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
This commit is contained in:
Johan Malm 2023-09-26 17:51:54 +01:00 committed by Johan Malm
parent 3022985ba7
commit e77330bc3f
3 changed files with 49 additions and 9 deletions

View file

@ -21,5 +21,6 @@ void key_state_store_pressed_keys_as_bound(void);
bool key_state_corresponding_press_event_was_bound(uint32_t keycode); bool key_state_corresponding_press_event_was_bound(uint32_t keycode);
void key_state_bound_key_remove(uint32_t keycode); void key_state_bound_key_remove(uint32_t keycode);
int key_state_nr_keys(void); int key_state_nr_keys(void);
int key_state_nr_pressed_keys(void);
#endif /* LABWC_KEY_STATE_H */ #endif /* LABWC_KEY_STATE_H */

View file

@ -102,3 +102,9 @@ key_state_nr_keys(void)
{ {
return bound.nr_keys; return bound.nr_keys;
} }
int
key_state_nr_pressed_keys(void)
{
return pressed.nr_keys;
}

View file

@ -203,8 +203,34 @@ handle_compositor_keybindings(struct keyboard *keyboard,
bool handled = false; bool handled = false;
/*
* 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, key_state_set_pressed(event->keycode,
event->state == WL_KEYBOARD_KEY_STATE_PRESSED); event->state == WL_KEYBOARD_KEY_STATE_PRESSED);
}
/* /*
* Ignore labwc keybindings if input is inhibited * Ignore labwc keybindings if input is inhibited
@ -293,13 +319,7 @@ handle_compositor_keybindings(struct keyboard *keyboard,
/* cycle to next */ /* cycle to next */
bool backwards = modifiers & WLR_MODIFIER_SHIFT; bool backwards = modifiers & WLR_MODIFIER_SHIFT;
/* ignore if this is a modifier key being pressed */ if (!ismodifier) {
bool ignore = false;
for (int i = 0; i < translated.nr_syms; i++) {
ignore |= is_modifier_key(translated.syms[i]);
}
if (!ignore) {
enum lab_cycle_dir dir = backwards enum lab_cycle_dir dir = backwards
? LAB_CYCLE_DIR_BACKWARD ? LAB_CYCLE_DIR_BACKWARD
: LAB_CYCLE_DIR_FORWARD; : LAB_CYCLE_DIR_FORWARD;
@ -313,6 +333,19 @@ handle_compositor_keybindings(struct keyboard *keyboard,
goto out; 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 * Handle compositor keybinds
* *