From: Johan Malm Date: Tue, 20 Sep 2022 19:46:39 +0000 (+0100) Subject: seat: only pass on sent keys on surface-focus X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=de99a8ba33c36139d7fa62deb0925ccbfab2bd2e;p=proto%2Flabwc.git seat: only pass on sent keys on surface-focus Key events associated with keybindings (both pressed and released) are not sent to clients. When using wlr_seat_keyboard_notify_enter() it it therefore important not to send the keycodes of _all_ pressed keys, but only those that were actually _sent_ to clients (that is, those that were not bound). This approach is consistent with sway's implementation in input/seat.c https://github.com/swaywm/sway/blob/cffb006feba52c318e66f73c3463032fa76782dc/sway/input/seat.c#L173-L175 Fixes issue #510 --- diff --git a/include/key-state.h b/include/key-state.h index cfe9df9c..00767258 100644 --- a/include/key-state.h +++ b/include/key-state.h @@ -2,6 +2,20 @@ #ifndef __LABWC_KEY_STATE_H #define __LABWC_KEY_STATE_H +/* + * All keycodes in these functions are (Linux) libinput evdev scancodes which is + * what 'wlr_keyboard' uses (e.g. 'seat->keyboard_group->keyboard->keycodes'). + * Note: These keycodes are different to XKB scancodes by a value of 8. + */ + +/** + * key_state_pressed_sent_keycodes - generate array of pressed+sent keys + * Note: The array is generated by subtracting any bound keys from _all_ pressed + * keys (because bound keys were not forwarded to clients). + */ +uint32_t *key_state_pressed_sent_keycodes(void); +int key_state_nr_pressed_sent_keycodes(void); + void key_state_set_pressed(uint32_t keycode, bool ispressed); void key_state_store_pressed_keys_as_bound(void); bool key_state_corresponding_press_event_was_bound(uint32_t keycode); diff --git a/src/key-state.c b/src/key-state.c index 0c53cf9f..775b2e9b 100644 --- a/src/key-state.c +++ b/src/key-state.c @@ -10,7 +10,7 @@ struct key_array { int nr_keys; }; -static struct key_array pressed, bound; +static struct key_array pressed, bound, pressed_sent; static void remove_key(struct key_array *array, uint32_t keycode) @@ -35,6 +35,25 @@ add_key(struct key_array *array, uint32_t keycode) array->keys[array->nr_keys++] = keycode; } +uint32_t * +key_state_pressed_sent_keycodes(void) +{ + /* pressed_sent = pressed - bound */ + memcpy(pressed_sent.keys, pressed.keys, + MAX_PRESSED_KEYS * sizeof(uint32_t)); + pressed_sent.nr_keys = pressed.nr_keys; + for (int i = 0; i < bound.nr_keys; ++i) { + remove_key(&pressed_sent, bound.keys[i]); + } + return pressed_sent.keys; +} + +int +key_state_nr_pressed_sent_keycodes(void) +{ + return pressed_sent.nr_keys; +} + void key_state_set_pressed(uint32_t keycode, bool ispressed) { diff --git a/src/keyboard.c b/src/keyboard.c index 4849a2f4..63e46a68 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -85,6 +85,7 @@ handle_keybinding(struct server *server, uint32_t modifiers, xkb_keysym_t sym) } for (size_t i = 0; i < keybind->keysyms_len; i++) { if (xkb_keysym_to_lower(sym) == keybind->keysyms[i]) { + key_state_store_pressed_keys_as_bound(); actions_run(NULL, server, &keybind->actions, 0); return true; } @@ -121,7 +122,7 @@ handle_compositor_keybindings(struct wl_listener *listener, bool handled = false; - key_state_set_pressed(keycode, + key_state_set_pressed(event->keycode, event->state == WL_KEYBOARD_KEY_STATE_PRESSED); /* @@ -152,9 +153,9 @@ handle_compositor_keybindings(struct wl_listener *listener, * If a press event was handled by a compositor binding, then do not * forward the corresponding release event to clients */ - if (key_state_corresponding_press_event_was_bound(keycode) + if (key_state_corresponding_press_event_was_bound(event->keycode) && event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { - key_state_bound_key_remove(keycode); + key_state_bound_key_remove(event->keycode); return true; } @@ -247,7 +248,7 @@ keyboard_key_notify(struct wl_listener *listener, void *data) if (!handled) { wlr_seat_set_keyboard(wlr_seat, keyboard); wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, - event->keycode, event->state); + event->keycode, event->state); } } diff --git a/src/seat.c b/src/seat.c index ddc723ed..b775cf4c 100644 --- a/src/seat.c +++ b/src/seat.c @@ -9,6 +9,7 @@ #include #include #include "common/mem.h" +#include "key-state.h" #include "labwc.h" static void @@ -347,8 +348,19 @@ seat_focus_surface(struct seat *seat, struct wlr_surface *surface) return; } struct wlr_keyboard *kb = &seat->keyboard_group->keyboard; - wlr_seat_keyboard_notify_enter(seat->seat, surface, kb->keycodes, - kb->num_keycodes, &kb->modifiers); + + /* + * Key events associated with keybindings (both pressed and released) + * are not sent to clients. When changing surface-focus it is therefore + * important not to send the keycodes of _all_ pressed keys, but only + * those that were actually _sent_ to clients (that is, those that were + * not bound). + */ + uint32_t *pressed_sent_keycodes = key_state_pressed_sent_keycodes(); + int nr_pressed_sent_keycodes = key_state_nr_pressed_sent_keycodes(); + + wlr_seat_keyboard_notify_enter(seat->seat, surface, + pressed_sent_keycodes, nr_pressed_sent_keycodes, &kb->modifiers); struct server *server = seat->server; struct wlr_pointer_constraint_v1 *constraint =