We used to store both `pressed` keys and `bound` keys and derive
`pressed_sent` keys from them, which are notified to the client when
switching focus. But I think this was overengineered and we can remove
`pressed` keys and `bound` keys. Instead we now directly modify
`pressed_sent` keys just before calling `wlr_seat_keyboard_notify_key()`.
Technically we could even remove `pressed_sent` keys as they are
duplicated in wlr_seat->keyboard_state.keyboard->keycodes, but we keep
`pressed_sent` keys as it is easier to access.
The only place which required `bound` keys was `handle_modifiers()`.
This function checked `bound` keys to keep widnow switcher alive when
Alt-Tab is pressed and only the Alt modifier is released. The window
switcher is then finished when Tab key is released. I replaced the check
with `(seat->keyboard_group->keyboard.num_keycodes > 0)`. This slightly
changes the behavior; when Alt-Tab and any other key e.g. X are pressed
and Tab key and Alt modifier are released, the window switcher is now
kept alive. But I don't think this breaks any workflows for users.
Add action `DebugToggleKeyStateIndicator` to show in the top-left corner
the pressed, bound, pressed-sent keys as well as modifiers.
This should help fault find issues like #2771 and #3238
Based-on: #3262
Co-authored-by: @tokyo4j
This prevents applications from seeing and handling the release event
for a modifier key that was part of a keybinding (e.g. Firefox displays
its menu bar for a lone Alt press + release).
Before commit e77330bc3f, there were issues with keys becoming "stuck"
if other keys were pressed at the time a keybinding was matched, because
those other keys were included in the "bound" set and the release events
were incorrectly eaten by labwc.
Commit e77330bc3f solved that issue with the "big hammer" approach of
preventing keybindings from working at all if other keys were pressed:
if (key_state_nr_pressed_keys() > 1) {
return false;
}
This is an alternate approach to solving the original problem, by (1)
not including those other keys in the "bound" set and (2) making sure we
always forward release events for un-bound keys to clients (even if a
menu or OSD is displayed).
Details:
- Since we only ever want to store the single matched keycode as bound,
key_state_store_pressed_keys_as_bound() doesn't really make sense in
the plural, so rename it to key_state_store_pressed_key_as_bound() and
pass in the keycode.
- The calls to key_state_store_pressed_keys_as_bound() within
handle_keybinding() appear to be redundant since it is also called
from the parent function (handle_compositor_keybindings()). So remove
these calls.
- Finally, rework the logic for handling key-release events so that we
always forward release events for keys not in the "bound" set.
This PR does not remove the "key_state_nr_pressed_keys() > 1" check, and
because of that should not result in any functional change. It should
however make it possible to relax or remove that check in future.