diff options
Diffstat (limited to 'sway/input/keyboard.c')
-rw-r--r-- | sway/input/keyboard.c | 74 |
1 files changed, 65 insertions, 9 deletions
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 95e53934..f258ac7d 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -378,6 +378,28 @@ static void update_keyboard_state(struct sway_keyboard *keyboard, } } +/** + * Get keyboard grab of the seat from sway_keyboard if we should forward events + * to it. + * + * Returns NULL if the keyboard is not grabbed by an input method, + * or if event is from virtual keyboard of the same client as grab. + * TODO: see swaywm/wlroots#2322 + */ +static struct wlr_input_method_keyboard_grab_v2 *keyboard_get_im_grab( + struct sway_keyboard *keyboard) { + struct wlr_input_method_v2 *input_method = keyboard->seat_device-> + sway_seat->im_relay.input_method; + struct wlr_virtual_keyboard_v1 *virtual_keyboard = + wlr_input_device_get_virtual_keyboard(keyboard->seat_device->input_device->wlr_device); + if (!input_method || !input_method->keyboard_grab || (virtual_keyboard && + wl_resource_get_client(virtual_keyboard->resource) == + wl_resource_get_client(input_method->keyboard_grab->resource))) { + return NULL; + } + return input_method->keyboard_grab; +} + static void handle_key_event(struct sway_keyboard *keyboard, struct wlr_event_keyboard_key *event) { struct sway_seat *seat = keyboard->seat_device->sway_seat; @@ -488,17 +510,42 @@ static void handle_key_event(struct sway_keyboard *keyboard, keyinfo.raw_keysyms_len); } - if (!handled || event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { + if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { + // If the pressed event was sent to a client, also send the released + // event. In particular, don't send the released event to the IM grab. bool pressed_sent = update_shortcut_state( - &keyboard->state_pressed_sent, event->keycode, event->state, - keyinfo.keycode, 0); - if (pressed_sent || event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { + &keyboard->state_pressed_sent, event->keycode, + event->state, keyinfo.keycode, 0); + if (pressed_sent) { wlr_seat_set_keyboard(wlr_seat, wlr_device); wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, - event->keycode, event->state); + event->keycode, event->state); + handled = true; + } + } + + if (!handled) { + struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(keyboard); + + if (kb_grab) { + wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab, + wlr_device->keyboard); + wlr_input_method_keyboard_grab_v2_send_key(kb_grab, + event->time_msec, event->keycode, event->state); + handled = true; } } + if (!handled && event->state != WL_KEYBOARD_KEY_STATE_RELEASED) { + // If a released event failed pressed sent test, and not in sent to + // keyboard grab, it is still not handled. Don't handle released here. + update_shortcut_state( + &keyboard->state_pressed_sent, event->keycode, event->state, + keyinfo.keycode, 0); + wlr_seat_set_keyboard(wlr_seat, wlr_device); + wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, + event->keycode, event->state); + } free(device_identifier); } @@ -614,10 +661,19 @@ static void handle_modifier_event(struct sway_keyboard *keyboard) { struct wlr_input_device *wlr_device = keyboard->seat_device->input_device->wlr_device; if (!wlr_device->keyboard->group) { - struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat; - wlr_seat_set_keyboard(wlr_seat, wlr_device); - wlr_seat_keyboard_notify_modifiers(wlr_seat, - &wlr_device->keyboard->modifiers); + struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(keyboard); + + if (kb_grab) { + wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab, + wlr_device->keyboard); + wlr_input_method_keyboard_grab_v2_send_modifiers(kb_grab, + &wlr_device->keyboard->modifiers); + } else { + struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat; + wlr_seat_set_keyboard(wlr_seat, wlr_device); + wlr_seat_keyboard_notify_modifiers(wlr_seat, + &wlr_device->keyboard->modifiers); + } uint32_t modifiers = wlr_keyboard_get_modifiers(wlr_device->keyboard); determine_bar_visibility(modifiers); |