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.
This commit is contained in:
Brian Ashworth 2019-08-15 00:59:39 -04:00 committed by Drew DeVault
parent 7488d33d42
commit 384afc5cb5
3 changed files with 54 additions and 27 deletions

View file

@ -60,6 +60,7 @@ struct sway_keyboard {
struct sway_shortcut_state state_keysyms_translated; struct sway_shortcut_state state_keysyms_translated;
struct sway_shortcut_state state_keysyms_raw; struct sway_shortcut_state state_keysyms_raw;
struct sway_shortcut_state state_keycodes; struct sway_shortcut_state state_keycodes;
struct sway_shortcut_state state_pressed_sent;
struct sway_binding *held_binding; struct sway_binding *held_binding;
struct wl_event_source *key_repeat_source; struct wl_event_source *key_repeat_source;

View file

@ -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 * 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) { uint32_t keycode) {
bool found = false;
size_t j = 0; size_t j = 0;
for (size_t i = 0; i < state->npressed; ++i) { for (size_t i = 0; i < state->npressed; ++i) {
if (i > j) { if (i > j) {
@ -79,6 +80,8 @@ static void state_erase_key(struct sway_shortcut_state *state,
} }
if (state->pressed_keycodes[i] != keycode) { if (state->pressed_keycodes[i] != keycode) {
++j; ++j;
} else {
found = true;
} }
} }
while(state->npressed > j) { 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->pressed_keycodes[state->npressed] = 0;
} }
state->current_key = 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 * 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, struct wlr_event_keyboard_key *event, uint32_t new_key,
uint32_t raw_modifiers) { uint32_t raw_modifiers) {
bool last_key_was_a_modifier = raw_modifiers != state->last_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_add_key(state, event->keycode, new_key);
state->last_keycode = event->keycode; state->last_keycode = event->keycode;
} else { } 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) { if (!handled || event->state == WLR_KEY_RELEASED) {
wlr_seat_set_keyboard(wlr_seat, wlr_device); bool pressed_sent = update_shortcut_state(
wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, &keyboard->state_pressed_sent, event, (uint32_t)keycode, 0);
event->keycode, event->state); 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(); transaction_commit_dirty();

View file

@ -1,4 +1,5 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <linux/input-event-codes.h> #include <linux/input-event-codes.h>
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
@ -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 view, set it as active and enable keyboard input.
* If con is a container, set all child views as active and don't enable * 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); wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
} }
#endif #endif
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
if (keyboard) { seat_keyboard_notify_enter(seat, view->surface);
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);
}
struct wlr_pointer_constraint_v1 *constraint = struct wlr_pointer_constraint_v1 *constraint =
wlr_pointer_constraints_v1_constraint_for_surface( wlr_pointer_constraints_v1_constraint_for_surface(
@ -578,8 +604,6 @@ static void seat_configure_keyboard(struct sway_seat *seat,
if (!seat_device->keyboard) { if (!seat_device->keyboard) {
sway_keyboard_create(seat, seat_device); sway_keyboard_create(seat, seat_device);
} }
struct wlr_keyboard *wlr_keyboard =
seat_device->input_device->wlr_device->keyboard;
sway_keyboard_configure(seat_device->keyboard); sway_keyboard_configure(seat_device->keyboard);
wlr_seat_set_keyboard(seat->wlr_seat, wlr_seat_set_keyboard(seat->wlr_seat,
seat_device->input_device->wlr_device); 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)) { if (focus && node_is_view(focus)) {
// force notify reenter to pick up the new configuration // force notify reenter to pick up the new configuration
wlr_seat_keyboard_clear_focus(seat->wlr_seat); wlr_seat_keyboard_clear_focus(seat->wlr_seat);
wlr_seat_keyboard_notify_enter(seat->wlr_seat, seat_keyboard_notify_enter(seat, focus->sway_container->view->surface);
focus->sway_container->view->surface, wlr_keyboard->keycodes,
wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers);
} }
} }
@ -1049,13 +1071,7 @@ void seat_set_focus_surface(struct sway_seat *seat,
seat_send_unfocus(focus, seat); seat_send_unfocus(focus, seat);
seat->has_focus = false; seat->has_focus = false;
} }
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); seat_keyboard_notify_enter(seat, surface);
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);
}
} }
void seat_set_focus_layer(struct sway_seat *seat, void seat_set_focus_layer(struct sway_seat *seat,