]> git.mdlowis.com Git - proto/labwc.git/commitdiff
keyboard: fix key repeat bug on surface focus change
authorJohan Malm <jgm323@gmail.com>
Tue, 14 Nov 2023 18:57:40 +0000 (18:57 +0000)
committerJohan Malm <johanmalm@users.noreply.github.com>
Sat, 18 Nov 2023 14:17:25 +0000 (14:17 +0000)
The bug can be reproduced by using the following keybinds and then taking
the steps below with an XWayland client, for example xterm:

    <keybind key="C-S-h">
      <action name="GoToDesktop" to="left" wrap="yes"/>
    </keybind>
    <keybind key="C-S-l">
      <action name="GoToDesktop" to="right" wrap="yes"/>
    </keybind>

1. Press C-S-h
2. Press C-S-l
3. Observe llllllll.... in xterm

Store the key-state in `handle_keybind()` before any call to
`action_run()` as this may lead to `seat_focus()` which passes
'pressed-sent' keys to the new surface.

This partially reverts 7571c4b, which as a standalone commit was fine, but
when 'pressed_mods' were then included in 'bound' in 98bf316,
`key_state_store_pressed_keys_as_bound()` was again required in
`handle_keybind()` to ensure modifers are not passed as non-modifiers in
`wlr_seat_keyboard_notify_enter()` in `seat_focus()`

src/input/keyboard.c

index 078209a6b15e4a6619ede344cc80586be0630b61..14b6864cfdcaf9665f58bdbf8c1a7492863e160c 100644 (file)
@@ -90,6 +90,8 @@ keyboard_modifiers_notify(struct wl_listener *listener, void *data)
 static bool
 handle_keybinding(struct server *server, uint32_t modifiers, xkb_keysym_t sym, xkb_keycode_t code)
 {
+       uint32_t evdev_scancode = code - 8;
+
        struct keybind *keybind;
        wl_list_for_each(keybind, &rc.keybinds, link) {
                if (modifiers ^ keybind->modifiers) {
@@ -104,7 +106,14 @@ handle_keybinding(struct server *server, uint32_t modifiers, xkb_keysym_t sym, x
                if (sym == XKB_KEY_NoSymbol) {
                        /* Use keycodes */
                        for (size_t i = 0; i < keybind->keycodes_len; i++) {
+                               /*
+                                * Update key-state before action_run() because
+                                * the action might lead to seat_focus() in
+                                * which case we pass the 'pressed-sent' keys to
+                                * the new surface.
+                                */
                                if (keybind->keycodes[i] == code) {
+                                       key_state_store_pressed_key_as_bound(evdev_scancode);
                                        actions_run(NULL, server, &keybind->actions, 0);
                                        return true;
                                }
@@ -113,6 +122,7 @@ handle_keybinding(struct server *server, uint32_t modifiers, xkb_keysym_t sym, x
                        /* Use syms */
                        for (size_t i = 0; i < keybind->keysyms_len; i++) {
                                if (xkb_keysym_to_lower(sym) == keybind->keysyms[i]) {
+                                       key_state_store_pressed_key_as_bound(evdev_scancode);
                                        actions_run(NULL, server, &keybind->actions, 0);
                                        return true;
                                }
@@ -308,10 +318,10 @@ handle_compositor_keybindings(struct keyboard *keyboard,
 
        if (server->input_mode == LAB_INPUT_STATE_MENU) {
                if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+                       key_state_store_pressed_key_as_bound(event->keycode);
                        handle_menu_keys(server, &translated);
                }
-               handled = true;
-               goto out;
+               return true;
        }
 
        if (server->osd_state.cycle_view) {
@@ -381,7 +391,7 @@ handle_compositor_keybindings(struct keyboard *keyboard,
                handled |= handle_keybinding(server, modifiers, XKB_KEY_NoSymbol, keycode);
                if (handled) {
                        wlr_log(WLR_DEBUG, "keycodes matched");
-                       goto out;
+                       return true;
                }
 
                /* Then fall back to keysyms */
@@ -391,7 +401,7 @@ handle_compositor_keybindings(struct keyboard *keyboard,
                }
                if (handled) {
                        wlr_log(WLR_DEBUG, "translated keysyms matched");
-                       goto out;
+                       return true;
                }
 
                /* And finally test for keysyms without modifier */
@@ -400,6 +410,7 @@ handle_compositor_keybindings(struct keyboard *keyboard,
                }
                if (handled) {
                        wlr_log(WLR_DEBUG, "raw keysyms matched");
+                       return true;
                }
        }