From 8008d21f5b81c705bb14d168aeda508c975125c9 Mon Sep 17 00:00:00 2001 From: Yuya Nishihara Date: Thu, 6 May 2021 17:33:39 +0900 Subject: [PATCH] virtual_keyboard: Emulate key release events on destroy According to libinput, release events are generated when device is unplugged, and libinput copies this behavior for device removal. Let's do the same for our virtual keyboard. https://github.com/wayland-project/libinput/commit/8f846a41fa0566fbd72ece676656e20e56ce43e6 This is another attempt to fix #2034 and the following sway issue: https://github.com/swaywm/sway/issues/6254 Note that we have other key repeating issues in sway, which aren't addressed by this patch. Since the virtual keyboard itself isn't destroyed when the keyboard grab is destroyed, we'll probably need some trick to reset the state of the corresponding virtual keyboard when the grab is released. https://github.com/swaywm/sway/issues/6095 https://github.com/swaywm/sway/issues/6193 --- types/wlr_virtual_keyboard_v1.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/types/wlr_virtual_keyboard_v1.c b/types/wlr_virtual_keyboard_v1.c index 25c94545..db643ef3 100644 --- a/types/wlr_virtual_keyboard_v1.c +++ b/types/wlr_virtual_keyboard_v1.c @@ -8,6 +8,7 @@ #include #include #include "util/signal.h" +#include "util/time.h" #include "virtual-keyboard-unstable-v1-protocol.h" @@ -118,9 +119,31 @@ static void virtual_keyboard_modifiers(struct wl_client *client, mods_depressed, mods_latched, mods_locked, group); } +/** + * Send release event for each pressed key to bring the keyboard back to + * neutral state. + * + * This may be needed for virtual keyboards. For physical devices, kernel + * or libinput will deal with the removal of devices. + */ +static void keyboard_release_pressed_keys(struct wlr_keyboard *keyboard) { + size_t orig_num_keycodes = keyboard->num_keycodes; + for (size_t i = 0; i < orig_num_keycodes; ++i) { + assert(keyboard->num_keycodes == orig_num_keycodes - i); + struct wlr_event_keyboard_key event = { + .time_msec = get_current_time_msec(), + .keycode = keyboard->keycodes[orig_num_keycodes - i - 1], + .update_state = false, + .state = WL_KEYBOARD_KEY_STATE_RELEASED, + }; + wlr_keyboard_notify_key(keyboard, &event); // updates num_keycodes + } +} + static void virtual_keyboard_destroy_resource(struct wl_resource *resource) { struct wlr_virtual_keyboard_v1 *keyboard = virtual_keyboard_from_resource(resource); + keyboard_release_pressed_keys(keyboard->input_device.keyboard); wlr_signal_emit_safe(&keyboard->events.destroy, keyboard); wl_list_remove(&keyboard->link); wlr_input_device_destroy(&keyboard->input_device);