diff options
Diffstat (limited to 'sway/input/keyboard.c')
-rw-r--r-- | sway/input/keyboard.c | 96 |
1 files changed, 75 insertions, 21 deletions
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 3090d32f..7b90dacf 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c | |||
@@ -1,3 +1,4 @@ | |||
1 | #include <assert.h> | ||
1 | #include <wlr/backend/multi.h> | 2 | #include <wlr/backend/multi.h> |
2 | #include <wlr/backend/session.h> | 3 | #include <wlr/backend/session.h> |
3 | #include "sway/input/seat.h" | 4 | #include "sway/input/seat.h" |
@@ -54,6 +55,18 @@ static bool keyboard_execute_compositor_binding(struct sway_keyboard *keyboard, | |||
54 | return false; | 55 | return false; |
55 | } | 56 | } |
56 | 57 | ||
58 | static bool binding_matches_keystate(struct sway_binding *binding, | ||
59 | enum wlr_key_state key_state) { | ||
60 | if (key_state == WLR_KEY_PRESSED && !binding->release) { | ||
61 | return true; | ||
62 | } | ||
63 | if (key_state == WLR_KEY_RELEASED && binding->release) { | ||
64 | return true; | ||
65 | } | ||
66 | |||
67 | return false; | ||
68 | } | ||
69 | |||
57 | /** | 70 | /** |
58 | * Execute keyboard bindings bound with `bindysm`. | 71 | * Execute keyboard bindings bound with `bindysm`. |
59 | * | 72 | * |
@@ -61,13 +74,15 @@ static bool keyboard_execute_compositor_binding(struct sway_keyboard *keyboard, | |||
61 | * should be propagated to clients. | 74 | * should be propagated to clients. |
62 | */ | 75 | */ |
63 | static bool keyboard_execute_bindsym(struct sway_keyboard *keyboard, | 76 | static bool keyboard_execute_bindsym(struct sway_keyboard *keyboard, |
64 | xkb_keysym_t *pressed_keysyms, uint32_t modifiers, size_t keysyms_len) { | 77 | xkb_keysym_t *pressed_keysyms, uint32_t modifiers, enum wlr_key_state key_state) { |
65 | // configured bindings | 78 | // configured bindings |
66 | int n = pressed_keysyms_length(pressed_keysyms); | 79 | int n = pressed_keysyms_length(pressed_keysyms); |
67 | list_t *keysym_bindings = config->current_mode->keysym_bindings; | 80 | list_t *keysym_bindings = config->current_mode->keysym_bindings; |
68 | for (int i = 0; i < keysym_bindings->length; ++i) { | 81 | for (int i = 0; i < keysym_bindings->length; ++i) { |
69 | struct sway_binding *binding = keysym_bindings->items[i]; | 82 | struct sway_binding *binding = keysym_bindings->items[i]; |
70 | if (modifiers ^ binding->modifiers || n != binding->keys->length) { | 83 | if (!binding_matches_keystate(binding, key_state) || |
84 | modifiers ^ binding->modifiers || | ||
85 | n != binding->keys->length) { | ||
71 | continue; | 86 | continue; |
72 | } | 87 | } |
73 | 88 | ||
@@ -115,16 +130,43 @@ static bool keysym_is_modifier(xkb_keysym_t keysym) { | |||
115 | } | 130 | } |
116 | 131 | ||
117 | static bool binding_matches_keycodes(struct wlr_keyboard *keyboard, | 132 | static bool binding_matches_keycodes(struct wlr_keyboard *keyboard, |
118 | struct sway_binding *binding) { | 133 | struct sway_binding *binding, struct wlr_event_keyboard_key *event) { |
134 | assert(binding->bindcode); | ||
135 | |||
136 | uint32_t keycode = event->keycode + 8; | ||
137 | |||
138 | if (!binding_matches_keystate(binding, event->state)) { | ||
139 | return false; | ||
140 | } | ||
141 | |||
119 | uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard); | 142 | uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard); |
120 | if (modifiers ^ binding->modifiers) { | 143 | if (modifiers ^ binding->modifiers) { |
121 | return false; | 144 | return false; |
122 | } | 145 | } |
123 | 146 | ||
147 | // on release, the released key must be in the binding | ||
148 | if (event->state == WLR_KEY_RELEASED) { | ||
149 | bool found = false; | ||
150 | for (int i = 0; i < binding->keys->length; ++i) { | ||
151 | uint32_t binding_keycode = *(uint32_t*)binding->keys->items[i] + 8; | ||
152 | if (binding_keycode == keycode) { | ||
153 | found = true; | ||
154 | break; | ||
155 | } | ||
156 | } | ||
157 | if (!found) { | ||
158 | return false; | ||
159 | } | ||
160 | } | ||
161 | |||
124 | // every keycode in the binding must be present in the pressed keys on the | 162 | // every keycode in the binding must be present in the pressed keys on the |
125 | // keyboard | 163 | // keyboard |
126 | for (int i = 0; i < binding->keys->length; ++i) { | 164 | for (int i = 0; i < binding->keys->length; ++i) { |
127 | uint32_t binding_keycode = *(uint32_t*)binding->keys->items[i] + 8; | 165 | uint32_t binding_keycode = *(uint32_t*)binding->keys->items[i] + 8; |
166 | if (event->state == WLR_KEY_RELEASED && keycode == binding_keycode) { | ||
167 | continue; | ||
168 | } | ||
169 | |||
128 | bool found = false; | 170 | bool found = false; |
129 | for (size_t j = 0; j < keyboard->num_keycodes; ++j) { | 171 | for (size_t j = 0; j < keyboard->num_keycodes; ++j) { |
130 | xkb_keycode_t keycode = keyboard->keycodes[j] + 8; | 172 | xkb_keycode_t keycode = keyboard->keycodes[j] + 8; |
@@ -178,13 +220,14 @@ static bool binding_matches_keycodes(struct wlr_keyboard *keyboard, | |||
178 | * Returns true if the keysym was handled by a binding and false if the event | 220 | * Returns true if the keysym was handled by a binding and false if the event |
179 | * should be propagated to clients. | 221 | * should be propagated to clients. |
180 | */ | 222 | */ |
181 | static bool keyboard_execute_bindcode(struct sway_keyboard *keyboard) { | 223 | static bool keyboard_execute_bindcode(struct sway_keyboard *keyboard, |
224 | struct wlr_event_keyboard_key *event) { | ||
182 | struct wlr_keyboard *wlr_keyboard = | 225 | struct wlr_keyboard *wlr_keyboard = |
183 | keyboard->seat_device->input_device->wlr_device->keyboard; | 226 | keyboard->seat_device->input_device->wlr_device->keyboard; |
184 | list_t *keycode_bindings = config->current_mode->keycode_bindings; | 227 | list_t *keycode_bindings = config->current_mode->keycode_bindings; |
185 | for (int i = 0; i < keycode_bindings->length; ++i) { | 228 | for (int i = 0; i < keycode_bindings->length; ++i) { |
186 | struct sway_binding *binding = keycode_bindings->items[i]; | 229 | struct sway_binding *binding = keycode_bindings->items[i]; |
187 | if (binding_matches_keycodes(wlr_keyboard, binding)) { | 230 | if (binding_matches_keycodes(wlr_keyboard, binding, event)) { |
188 | struct cmd_results *results = handle_command(binding->command); | 231 | struct cmd_results *results = handle_command(binding->command); |
189 | if (results->status != CMD_SUCCESS) { | 232 | if (results->status != CMD_SUCCESS) { |
190 | sway_log(L_DEBUG, "could not run command for binding: %s", | 233 | sway_log(L_DEBUG, "could not run command for binding: %s", |
@@ -289,50 +332,61 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { | |||
289 | bool handled = false; | 332 | bool handled = false; |
290 | 333 | ||
291 | // handle keycodes | 334 | // handle keycodes |
292 | handled = keyboard_execute_bindcode(keyboard); | 335 | handled = keyboard_execute_bindcode(keyboard, event); |
293 | 336 | ||
294 | // handle translated keysyms | 337 | // handle translated keysyms |
338 | if (!handled && event->state == WLR_KEY_RELEASED) { | ||
339 | handled = keyboard_execute_bindsym(keyboard, | ||
340 | keyboard->pressed_keysyms_translated, | ||
341 | keyboard->modifiers_translated, | ||
342 | event->state); | ||
343 | } | ||
295 | const xkb_keysym_t *translated_keysyms; | 344 | const xkb_keysym_t *translated_keysyms; |
296 | uint32_t translated_modifiers; | ||
297 | size_t translated_keysyms_len = | 345 | size_t translated_keysyms_len = |
298 | keyboard_keysyms_translated(keyboard, keycode, &translated_keysyms, | 346 | keyboard_keysyms_translated(keyboard, keycode, &translated_keysyms, |
299 | &translated_modifiers); | 347 | &keyboard->modifiers_translated); |
300 | pressed_keysyms_update(keyboard->pressed_keysyms_translated, | 348 | pressed_keysyms_update(keyboard->pressed_keysyms_translated, |
301 | translated_keysyms, translated_keysyms_len, event->state); | 349 | translated_keysyms, translated_keysyms_len, event->state); |
302 | if (event->state == WLR_KEY_PRESSED && !handled) { | 350 | if (!handled && event->state == WLR_KEY_PRESSED) { |
303 | handled = keyboard_execute_bindsym(keyboard, | 351 | handled = keyboard_execute_bindsym(keyboard, |
304 | keyboard->pressed_keysyms_translated, translated_modifiers, | 352 | keyboard->pressed_keysyms_translated, |
305 | translated_keysyms_len); | 353 | keyboard->modifiers_translated, |
354 | event->state); | ||
306 | } | 355 | } |
307 | 356 | ||
308 | // Handle raw keysyms | 357 | // Handle raw keysyms |
358 | if (!handled && event->state == WLR_KEY_RELEASED) { | ||
359 | handled = keyboard_execute_bindsym(keyboard, | ||
360 | keyboard->pressed_keysyms_raw, keyboard->modifiers_raw, | ||
361 | event->state); | ||
362 | } | ||
309 | const xkb_keysym_t *raw_keysyms; | 363 | const xkb_keysym_t *raw_keysyms; |
310 | uint32_t raw_modifiers; | ||
311 | size_t raw_keysyms_len = | 364 | size_t raw_keysyms_len = |
312 | keyboard_keysyms_raw(keyboard, keycode, &raw_keysyms, &raw_modifiers); | 365 | keyboard_keysyms_raw(keyboard, keycode, &raw_keysyms, &keyboard->modifiers_raw); |
313 | pressed_keysyms_update(keyboard->pressed_keysyms_raw, raw_keysyms, | 366 | pressed_keysyms_update(keyboard->pressed_keysyms_raw, raw_keysyms, |
314 | raw_keysyms_len, event->state); | 367 | raw_keysyms_len, event->state); |
315 | if (event->state == WLR_KEY_PRESSED && !handled) { | 368 | if (!handled && event->state == WLR_KEY_PRESSED) { |
316 | handled = keyboard_execute_bindsym(keyboard, | 369 | handled = keyboard_execute_bindsym(keyboard, |
317 | keyboard->pressed_keysyms_raw, raw_modifiers, | 370 | keyboard->pressed_keysyms_raw, keyboard->modifiers_raw, |
318 | raw_keysyms_len); | 371 | event->state); |
319 | } | 372 | } |
320 | 373 | ||
321 | // Compositor bindings | 374 | // Compositor bindings |
322 | if (event->state == WLR_KEY_PRESSED && !handled) { | 375 | if (!handled && event->state == WLR_KEY_PRESSED) { |
323 | handled = | 376 | handled = |
324 | keyboard_execute_compositor_binding(keyboard, | 377 | keyboard_execute_compositor_binding(keyboard, |
325 | keyboard->pressed_keysyms_translated, translated_modifiers, | 378 | keyboard->pressed_keysyms_translated, |
379 | keyboard->modifiers_translated, | ||
326 | translated_keysyms_len); | 380 | translated_keysyms_len); |
327 | } | 381 | } |
328 | if (event->state == WLR_KEY_PRESSED && !handled) { | 382 | if (!handled && event->state == WLR_KEY_PRESSED) { |
329 | handled = | 383 | handled = |
330 | keyboard_execute_compositor_binding(keyboard, | 384 | keyboard_execute_compositor_binding(keyboard, |
331 | keyboard->pressed_keysyms_raw, raw_modifiers, | 385 | keyboard->pressed_keysyms_raw, keyboard->modifiers_raw, |
332 | raw_keysyms_len); | 386 | raw_keysyms_len); |
333 | } | 387 | } |
334 | 388 | ||
335 | if (!handled) { | 389 | if (!handled || event->state == WLR_KEY_RELEASED) { |
336 | wlr_seat_set_keyboard(wlr_seat, wlr_device); | 390 | wlr_seat_set_keyboard(wlr_seat, wlr_device); |
337 | wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, | 391 | wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, |
338 | event->keycode, event->state); | 392 | event->keycode, event->state); |