From e77330bc3fe733412e92f4e90d797d31ee6c5652 Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Tue, 26 Sep 2023 17:51:54 +0100 Subject: [PATCH] keyboard: make keybind match stricter ...and avoid failing to send release events to clients for any keys that were not absorbed by a keybind. Do not match keybinds if there are other non-modifier keys (not part of any defined bind) pressed at the same time. Only store non-modifier keycodes in the key-state.c 'pressed' array. This makes the call to wlr_seat_keyboard_notify_enter() in seat_focus() consistent with the equivalent in sway (in seat_keyboard_notify_enter()). Fixes: issue #1091 --- include/key-state.h | 1 + src/key-state.c | 6 ++++++ src/keyboard.c | 51 +++++++++++++++++++++++++++++++++++++-------- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/include/key-state.h b/include/key-state.h index a45b3494..fd029881 100644 --- a/include/key-state.h +++ b/include/key-state.h @@ -21,5 +21,6 @@ void key_state_store_pressed_keys_as_bound(void); bool key_state_corresponding_press_event_was_bound(uint32_t keycode); void key_state_bound_key_remove(uint32_t keycode); int key_state_nr_keys(void); +int key_state_nr_pressed_keys(void); #endif /* LABWC_KEY_STATE_H */ diff --git a/src/key-state.c b/src/key-state.c index f95d480c..06e193a7 100644 --- a/src/key-state.c +++ b/src/key-state.c @@ -102,3 +102,9 @@ key_state_nr_keys(void) { return bound.nr_keys; } + +int +key_state_nr_pressed_keys(void) +{ + return pressed.nr_keys; +} diff --git a/src/keyboard.c b/src/keyboard.c index 0d5b4c2a..73b8c9fe 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -203,8 +203,34 @@ handle_compositor_keybindings(struct keyboard *keyboard, bool handled = false; - key_state_set_pressed(event->keycode, - event->state == WL_KEYBOARD_KEY_STATE_PRESSED); + /* + * keyboard_key_notify() is called before keyboard_key_modifier(), so + * 'modifiers' refers to modifiers that were pressed before the key + * event in hand. Consequently, we use is_modifier_key() to find out if + * the key event being processed is a modifier. + * + * Sway solves this differently by saving the 'modifiers' state and + * checking if it has changed each time we get to the equivalent of this + * function. If it has changed, it concludes that the last key was a + * modifier and then deletes it from the buffer of pressed keycodes. + * For us the equivalent would look something like this: + * + * static uint32_t last_modifiers; + * bool last_key_was_a_modifier = last_modifiers != modifiers; + * last_modifiers = modifiers; + * if (last_key_was_a_modifier) { + * key_state_remove_last_pressed_key(last_pressed_keycode); + * } + */ + + bool ismodifier = false; + for (int i = 0; i < translated.nr_syms; i++) { + ismodifier |= is_modifier_key(translated.syms[i]); + } + if (!ismodifier) { + key_state_set_pressed(event->keycode, + event->state == WL_KEYBOARD_KEY_STATE_PRESSED); + } /* * Ignore labwc keybindings if input is inhibited @@ -293,13 +319,7 @@ handle_compositor_keybindings(struct keyboard *keyboard, /* cycle to next */ bool backwards = modifiers & WLR_MODIFIER_SHIFT; - /* ignore if this is a modifier key being pressed */ - bool ignore = false; - for (int i = 0; i < translated.nr_syms; i++) { - ignore |= is_modifier_key(translated.syms[i]); - } - - if (!ignore) { + if (!ismodifier) { enum lab_cycle_dir dir = backwards ? LAB_CYCLE_DIR_BACKWARD : LAB_CYCLE_DIR_FORWARD; @@ -313,6 +333,19 @@ handle_compositor_keybindings(struct keyboard *keyboard, goto out; } + /* + * A keybind is not considered valid if other keys are pressed at the + * same time. + * + * In labwc, a keybind is defined by one/many modifier keys + _one_ + * non-modifier key. Returning early on >1 pressed non-modifier keys + * avoids false positive matches where 'other' keys were pressed at the + * same time. + */ + if (key_state_nr_pressed_keys() > 1) { + return false; + } + /* * Handle compositor keybinds *