From 9be18f3009330ec3580d2e032e07abeef46ef015 Mon Sep 17 00:00:00 2001 From: Hiroaki Yamamoto Date: Fri, 19 Apr 2024 05:57:03 +0900 Subject: [PATCH] IME: prevent virtual keyboard from unintentionally releasing modifiers (#1721) When Fcitx5 is activated, it creates a virtual keyboard to send keycodes to applications, then creates a keyboard grab to capture keycodes the user typed. Before this commit, we set keyboard grab's modifiers to that of currently active keyboard, which is the virtual keyboard created in the case described above. However, since the modifiers of the virtual keyboard is empty at first, we actually set empty modifiers, even when the user is pressing modifiers. Then, Fcitx5 assumes no modifiers is pressed and redirect the modifier state back to the compositor via the virtual keyboard. As a result, when the focus is switched between windows by workspace-switcher, the workspace-switcher is immediately terminated. To fix this issue, with this commit, the modifier state of the currently active keyboard is not set to the keyboard grab if the keyboard is a virtual keyboard created by the same input-method client. Fcitx5's commit below is also required to fix the issue. https://github.com/fcitx/fcitx5/commit/b2924bd361680c493463d240a375b3f0948ae48d --- src/input/ime.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/input/ime.c b/src/input/ime.c index bb08f6d5..b3d6410d 100644 --- a/src/input/ime.c +++ b/src/input/ime.c @@ -11,6 +11,20 @@ (wl_resource_get_client((wlr_obj1)->resource) \ == wl_resource_get_client((wlr_obj2)->resource)) +static bool +is_keyboard_emulated_by_input_method(struct wlr_keyboard *keyboard, + struct wlr_input_method_v2 *input_method) +{ + if (!keyboard || !input_method) { + return false; + } + + struct wlr_virtual_keyboard_v1 *virtual_keyboard = + wlr_input_device_get_virtual_keyboard(&keyboard->base); + + return virtual_keyboard && SAME_CLIENT(virtual_keyboard, input_method); +} + /* * Get keyboard grab of the seat from keyboard if we should forward events * to it. @@ -31,11 +45,8 @@ get_keyboard_grab(struct keyboard *keyboard) * input-method so key events don't loop between the compositor and * the input-method. */ - struct wlr_virtual_keyboard_v1 *virtual_keyboard = - wlr_input_device_get_virtual_keyboard( - keyboard->base.wlr_input_device); - if (virtual_keyboard && SAME_CLIENT(virtual_keyboard, - input_method->keyboard_grab)) { + if (is_keyboard_emulated_by_input_method( + keyboard->wlr_keyboard, input_method)) { return NULL; } @@ -298,11 +309,15 @@ handle_input_method_grab_keyboard(struct wl_listener *listener, void *data) input_method_grab_keyboard); struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; - /* Send modifier state to grab */ struct wlr_keyboard *active_keyboard = wlr_seat_get_keyboard(relay->seat->seat); - wlr_input_method_keyboard_grab_v2_set_keyboard( - keyboard_grab, active_keyboard); + + if (!is_keyboard_emulated_by_input_method( + active_keyboard, relay->input_method)) { + /* Send modifier state to grab */ + wlr_input_method_keyboard_grab_v2_set_keyboard( + keyboard_grab, active_keyboard); + } relay->keyboard_grab_destroy.notify = handle_keyboard_grab_destroy; wl_signal_add(&keyboard_grab->events.destroy,