1 #include "util/array.h"
2 #include <assert.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <wayland-server-core.h>
6 #include <wlr/interfaces/wlr_keyboard.h>
7 #include <wlr/types/wlr_keyboard.h>
8 #include <wlr/util/log.h>
9 #include "types/wlr_keyboard.h"
10 #include "util/signal.h"
11
keyboard_led_update(struct wlr_keyboard * keyboard)12 void keyboard_led_update(struct wlr_keyboard *keyboard) {
13 if (keyboard->xkb_state == NULL) {
14 return;
15 }
16
17 uint32_t leds = 0;
18 for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) {
19 if (xkb_state_led_index_is_active(keyboard->xkb_state,
20 keyboard->led_indexes[i])) {
21 leds |= (1 << i);
22 }
23 }
24 wlr_keyboard_led_update(keyboard, leds);
25 }
26
27 /**
28 * Update the modifier state of the wlr-keyboard. Returns true if the modifier
29 * state changed.
30 */
keyboard_modifier_update(struct wlr_keyboard * keyboard)31 bool keyboard_modifier_update(struct wlr_keyboard *keyboard) {
32 if (keyboard->xkb_state == NULL) {
33 return false;
34 }
35
36 xkb_mod_mask_t depressed = xkb_state_serialize_mods(keyboard->xkb_state,
37 XKB_STATE_MODS_DEPRESSED);
38 xkb_mod_mask_t latched = xkb_state_serialize_mods(keyboard->xkb_state,
39 XKB_STATE_MODS_LATCHED);
40 xkb_mod_mask_t locked = xkb_state_serialize_mods(keyboard->xkb_state,
41 XKB_STATE_MODS_LOCKED);
42 xkb_mod_mask_t group = xkb_state_serialize_layout(keyboard->xkb_state,
43 XKB_STATE_LAYOUT_EFFECTIVE);
44 if (depressed == keyboard->modifiers.depressed &&
45 latched == keyboard->modifiers.latched &&
46 locked == keyboard->modifiers.locked &&
47 group == keyboard->modifiers.group) {
48 return false;
49 }
50
51 keyboard->modifiers.depressed = depressed;
52 keyboard->modifiers.latched = latched;
53 keyboard->modifiers.locked = locked;
54 keyboard->modifiers.group = group;
55
56 return true;
57 }
58
keyboard_key_update(struct wlr_keyboard * keyboard,struct wlr_event_keyboard_key * event)59 void keyboard_key_update(struct wlr_keyboard *keyboard,
60 struct wlr_event_keyboard_key *event) {
61 if (event->state == WLR_KEY_PRESSED) {
62 set_add(keyboard->keycodes, &keyboard->num_keycodes,
63 WLR_KEYBOARD_KEYS_CAP, event->keycode);
64 }
65 if (event->state == WLR_KEY_RELEASED) {
66 set_remove(keyboard->keycodes, &keyboard->num_keycodes,
67 WLR_KEYBOARD_KEYS_CAP, event->keycode);
68 }
69
70 assert(keyboard->num_keycodes <= WLR_KEYBOARD_KEYS_CAP);
71 }
72
wlr_keyboard_notify_modifiers(struct wlr_keyboard * keyboard,uint32_t mods_depressed,uint32_t mods_latched,uint32_t mods_locked,uint32_t group)73 void wlr_keyboard_notify_modifiers(struct wlr_keyboard *keyboard,
74 uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked,
75 uint32_t group) {
76 if (keyboard->xkb_state == NULL) {
77 return;
78 }
79 xkb_state_update_mask(keyboard->xkb_state, mods_depressed, mods_latched,
80 mods_locked, 0, 0, group);
81
82 bool updated = keyboard_modifier_update(keyboard);
83 if (updated) {
84 wlr_signal_emit_safe(&keyboard->events.modifiers, keyboard);
85 }
86
87 keyboard_led_update(keyboard);
88 }
89
wlr_keyboard_notify_key(struct wlr_keyboard * keyboard,struct wlr_event_keyboard_key * event)90 void wlr_keyboard_notify_key(struct wlr_keyboard *keyboard,
91 struct wlr_event_keyboard_key *event) {
92 keyboard_key_update(keyboard, event);
93 wlr_signal_emit_safe(&keyboard->events.key, event);
94
95 if (keyboard->xkb_state == NULL) {
96 return;
97 }
98
99 if (event->update_state) {
100 uint32_t keycode = event->keycode + 8;
101 xkb_state_update_key(keyboard->xkb_state, keycode,
102 event->state == WLR_KEY_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP);
103 }
104
105 bool updated = keyboard_modifier_update(keyboard);
106 if (updated) {
107 wlr_signal_emit_safe(&keyboard->events.modifiers, keyboard);
108 }
109
110 keyboard_led_update(keyboard);
111 }
112
wlr_keyboard_init(struct wlr_keyboard * kb,const struct wlr_keyboard_impl * impl)113 void wlr_keyboard_init(struct wlr_keyboard *kb,
114 const struct wlr_keyboard_impl *impl) {
115 kb->impl = impl;
116 wl_signal_init(&kb->events.key);
117 wl_signal_init(&kb->events.modifiers);
118 wl_signal_init(&kb->events.keymap);
119 wl_signal_init(&kb->events.repeat_info);
120 wl_signal_init(&kb->events.destroy);
121
122 // Sane defaults
123 kb->repeat_info.rate = 25;
124 kb->repeat_info.delay = 600;
125 }
126
wlr_keyboard_destroy(struct wlr_keyboard * kb)127 void wlr_keyboard_destroy(struct wlr_keyboard *kb) {
128 if (kb == NULL) {
129 return;
130 }
131 wlr_signal_emit_safe(&kb->events.destroy, kb);
132 xkb_state_unref(kb->xkb_state);
133 xkb_keymap_unref(kb->keymap);
134 free(kb->keymap_string);
135 if (kb->impl && kb->impl->destroy) {
136 kb->impl->destroy(kb);
137 } else {
138 wl_list_remove(&kb->events.key.listener_list);
139 free(kb);
140 }
141 }
142
wlr_keyboard_led_update(struct wlr_keyboard * kb,uint32_t leds)143 void wlr_keyboard_led_update(struct wlr_keyboard *kb, uint32_t leds) {
144 if (kb->impl && kb->impl->led_update) {
145 kb->impl->led_update(kb, leds);
146 }
147 }
148
wlr_keyboard_set_keymap(struct wlr_keyboard * kb,struct xkb_keymap * keymap)149 bool wlr_keyboard_set_keymap(struct wlr_keyboard *kb,
150 struct xkb_keymap *keymap) {
151 xkb_keymap_unref(kb->keymap);
152 kb->keymap = xkb_keymap_ref(keymap);
153
154 xkb_state_unref(kb->xkb_state);
155 kb->xkb_state = xkb_state_new(kb->keymap);
156 if (kb->xkb_state == NULL) {
157 wlr_log(WLR_ERROR, "Failed to create XKB state");
158 goto err;
159 }
160
161 const char *led_names[WLR_LED_COUNT] = {
162 XKB_LED_NAME_NUM,
163 XKB_LED_NAME_CAPS,
164 XKB_LED_NAME_SCROLL,
165 };
166 for (size_t i = 0; i < WLR_LED_COUNT; ++i) {
167 kb->led_indexes[i] = xkb_map_led_get_index(kb->keymap, led_names[i]);
168 }
169
170 const char *mod_names[WLR_MODIFIER_COUNT] = {
171 XKB_MOD_NAME_SHIFT,
172 XKB_MOD_NAME_CAPS,
173 XKB_MOD_NAME_CTRL, // "Control"
174 XKB_MOD_NAME_ALT, // "Mod1"
175 XKB_MOD_NAME_NUM, // "Mod2"
176 "Mod3",
177 XKB_MOD_NAME_LOGO, // "Mod4"
178 "Mod5",
179 };
180 // TODO: there's also "Ctrl", "Alt"?
181 for (size_t i = 0; i < WLR_MODIFIER_COUNT; ++i) {
182 kb->mod_indexes[i] = xkb_map_mod_get_index(kb->keymap, mod_names[i]);
183 }
184
185 char *tmp_keymap_string = xkb_keymap_get_as_string(kb->keymap,
186 XKB_KEYMAP_FORMAT_TEXT_V1);
187 if (tmp_keymap_string == NULL) {
188 wlr_log(WLR_ERROR, "Failed to get string version of keymap");
189 goto err;
190 }
191 free(kb->keymap_string);
192 kb->keymap_string = tmp_keymap_string;
193 kb->keymap_size = strlen(kb->keymap_string) + 1;
194
195 for (size_t i = 0; i < kb->num_keycodes; ++i) {
196 xkb_keycode_t keycode = kb->keycodes[i] + 8;
197 xkb_state_update_key(kb->xkb_state, keycode, XKB_KEY_DOWN);
198 }
199
200 keyboard_modifier_update(kb);
201
202 wlr_signal_emit_safe(&kb->events.keymap, kb);
203 return true;
204
205 err:
206 xkb_state_unref(kb->xkb_state);
207 kb->xkb_state = NULL;
208 xkb_keymap_unref(keymap);
209 kb->keymap = NULL;
210 free(kb->keymap_string);
211 kb->keymap_string = NULL;
212 return false;
213 }
214
wlr_keyboard_set_repeat_info(struct wlr_keyboard * kb,int32_t rate,int32_t delay)215 void wlr_keyboard_set_repeat_info(struct wlr_keyboard *kb, int32_t rate,
216 int32_t delay) {
217 if (kb->repeat_info.rate == rate && kb->repeat_info.delay == delay) {
218 return;
219 }
220 kb->repeat_info.rate = rate;
221 kb->repeat_info.delay = delay;
222 wlr_signal_emit_safe(&kb->events.repeat_info, kb);
223 }
224
wlr_keyboard_get_modifiers(struct wlr_keyboard * kb)225 uint32_t wlr_keyboard_get_modifiers(struct wlr_keyboard *kb) {
226 xkb_mod_mask_t mask = kb->modifiers.depressed | kb->modifiers.latched;
227 uint32_t modifiers = 0;
228 for (size_t i = 0; i < WLR_MODIFIER_COUNT; ++i) {
229 if (kb->mod_indexes[i] != XKB_MOD_INVALID &&
230 (mask & (1 << kb->mod_indexes[i]))) {
231 modifiers |= (1 << i);
232 }
233 }
234 return modifiers;
235 }
236
wlr_keyboard_keymaps_match(struct xkb_keymap * km1,struct xkb_keymap * km2)237 bool wlr_keyboard_keymaps_match(struct xkb_keymap *km1,
238 struct xkb_keymap *km2) {
239 if (!km1 && !km2) {
240 return true;
241 }
242 if (!km1 || !km2) {
243 return false;
244 }
245 char *km1_str = xkb_keymap_get_as_string(km1, XKB_KEYMAP_FORMAT_TEXT_V1);
246 char *km2_str = xkb_keymap_get_as_string(km2, XKB_KEYMAP_FORMAT_TEXT_V1);
247 bool result = strcmp(km1_str, km2_str) == 0;
248 free(km1_str);
249 free(km2_str);
250 return result;
251 }
252