From 091b87bfb89726bc13b4763d4f730f7d17cfc575 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Thu, 15 Aug 2019 00:59:39 -0400 Subject: input/keyboard: send released only if pressed sent This keeps track of whether surfaces received a key press event and will only send a key release event if the pressed event was sent. This also requires changing the keycodes that are sent via wl_keyboard_enter to only include those that were previously sent. This makes it so surfaces do not receive key release events for keys that they never received a key press for and makes it so switching focus doesn't leak keycodes that were consumed by bindings. --- include/sway/input/keyboard.h | 1 + sway/input/keyboard.c | 22 +++++++++++----- sway/input/seat.c | 58 +++++++++++++++++++++++++++---------------- 3 files changed, 54 insertions(+), 27 deletions(-) diff --git a/include/sway/input/keyboard.h b/include/sway/input/keyboard.h index 1ff63c94..4aa0d8f4 100644 --- a/include/sway/input/keyboard.h +++ b/include/sway/input/keyboard.h @@ -60,6 +60,7 @@ struct sway_keyboard { struct sway_shortcut_state state_keysyms_translated; struct sway_shortcut_state state_keysyms_raw; struct sway_shortcut_state state_keycodes; + struct sway_shortcut_state state_pressed_sent; struct sway_binding *held_binding; struct wl_event_source *key_repeat_source; diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 680d1f69..3e196ae1 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -69,8 +69,9 @@ int get_modifier_names(const char **names, uint32_t modifier_masks) { /** * Remove all key ids associated to a keycode from the list of pressed keys */ -static void state_erase_key(struct sway_shortcut_state *state, +static bool state_erase_key(struct sway_shortcut_state *state, uint32_t keycode) { + bool found = false; size_t j = 0; for (size_t i = 0; i < state->npressed; ++i) { if (i > j) { @@ -79,6 +80,8 @@ static void state_erase_key(struct sway_shortcut_state *state, } if (state->pressed_keycodes[i] != keycode) { ++j; + } else { + found = true; } } while(state->npressed > j) { @@ -87,6 +90,7 @@ static void state_erase_key(struct sway_shortcut_state *state, state->pressed_keycodes[state->npressed] = 0; } state->current_key = 0; + return found; } /** @@ -117,7 +121,7 @@ static void state_add_key(struct sway_shortcut_state *state, /** * Update the shortcut model state in response to new input */ -static void update_shortcut_state(struct sway_shortcut_state *state, +static bool update_shortcut_state(struct sway_shortcut_state *state, struct wlr_event_keyboard_key *event, uint32_t new_key, uint32_t raw_modifiers) { bool last_key_was_a_modifier = raw_modifiers != state->last_raw_modifiers; @@ -133,8 +137,10 @@ static void update_shortcut_state(struct sway_shortcut_state *state, state_add_key(state, event->keycode, new_key); state->last_keycode = event->keycode; } else { - state_erase_key(state, event->keycode); + return state_erase_key(state, event->keycode); } + + return false; } /** @@ -430,9 +436,13 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { } if (!handled || event->state == WLR_KEY_RELEASED) { - wlr_seat_set_keyboard(wlr_seat, wlr_device); - wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, - event->keycode, event->state); + bool pressed_sent = update_shortcut_state( + &keyboard->state_pressed_sent, event, (uint32_t)keycode, 0); + if (pressed_sent || event->state == WLR_KEY_PRESSED) { + wlr_seat_set_keyboard(wlr_seat, wlr_device); + wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, + event->keycode, event->state); + } } transaction_commit_dirty(); diff --git a/sway/input/seat.c b/sway/input/seat.c index f28c1cb9..a4118a18 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -1,4 +1,5 @@ #define _POSIX_C_SOURCE 200809L +#include #include #include #include @@ -85,6 +86,38 @@ static void seat_send_activate(struct sway_node *node, struct sway_seat *seat) { } } +static struct sway_keyboard *sway_keyboard_for_wlr_keyboard( + struct sway_seat *seat, struct wlr_keyboard *wlr_keyboard) { + struct sway_seat_device *seat_device; + wl_list_for_each(seat_device, &seat->devices, link) { + struct sway_input_device *input_device = seat_device->input_device; + if (input_device->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) { + continue; + } + if (input_device->wlr_device->keyboard == wlr_keyboard) { + return seat_device->keyboard; + } + } + return NULL; +} + +static void seat_keyboard_notify_enter(struct sway_seat *seat, + struct wlr_surface *surface) { + struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); + if (!keyboard) { + wlr_seat_keyboard_notify_enter(seat->wlr_seat, surface, NULL, 0, NULL); + return; + } + + struct sway_keyboard *sway_keyboard = + sway_keyboard_for_wlr_keyboard(seat, keyboard); + assert(sway_keyboard && "Cannot find sway_keyboard for seat keyboard"); + + struct sway_shortcut_state *state = &sway_keyboard->state_pressed_sent; + wlr_seat_keyboard_notify_enter(seat->wlr_seat, surface, + state->pressed_keycodes, state->npressed, &keyboard->modifiers); +} + /** * If con is a view, set it as active and enable keyboard input. * If con is a container, set all child views as active and don't enable @@ -103,15 +136,8 @@ static void seat_send_focus(struct sway_node *node, struct sway_seat *seat) { wlr_xwayland_set_seat(xwayland, seat->wlr_seat); } #endif - struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); - if (keyboard) { - wlr_seat_keyboard_notify_enter(seat->wlr_seat, - view->surface, keyboard->keycodes, - keyboard->num_keycodes, &keyboard->modifiers); - } else { - wlr_seat_keyboard_notify_enter( - seat->wlr_seat, view->surface, NULL, 0, NULL); - } + + seat_keyboard_notify_enter(seat, view->surface); struct wlr_pointer_constraint_v1 *constraint = wlr_pointer_constraints_v1_constraint_for_surface( @@ -578,8 +604,6 @@ static void seat_configure_keyboard(struct sway_seat *seat, if (!seat_device->keyboard) { sway_keyboard_create(seat, seat_device); } - struct wlr_keyboard *wlr_keyboard = - seat_device->input_device->wlr_device->keyboard; sway_keyboard_configure(seat_device->keyboard); wlr_seat_set_keyboard(seat->wlr_seat, seat_device->input_device->wlr_device); @@ -587,9 +611,7 @@ static void seat_configure_keyboard(struct sway_seat *seat, if (focus && node_is_view(focus)) { // force notify reenter to pick up the new configuration wlr_seat_keyboard_clear_focus(seat->wlr_seat); - wlr_seat_keyboard_notify_enter(seat->wlr_seat, - focus->sway_container->view->surface, wlr_keyboard->keycodes, - wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers); + seat_keyboard_notify_enter(seat, focus->sway_container->view->surface); } } @@ -1049,13 +1071,7 @@ void seat_set_focus_surface(struct sway_seat *seat, seat_send_unfocus(focus, seat); seat->has_focus = false; } - struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); - if (keyboard) { - wlr_seat_keyboard_notify_enter(seat->wlr_seat, surface, - keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers); - } else { - wlr_seat_keyboard_notify_enter(seat->wlr_seat, surface, NULL, 0, NULL); - } + seat_keyboard_notify_enter(seat, surface); } void seat_set_focus_layer(struct sway_seat *seat, -- cgit v1.2.3