diff options
-rw-r--r-- | include/sway/input/text_input.h | 3 | ||||
-rw-r--r-- | sway/input/keyboard.c | 74 | ||||
-rw-r--r-- | sway/input/text_input.c | 34 |
3 files changed, 102 insertions, 9 deletions
diff --git a/include/sway/input/text_input.h b/include/sway/input/text_input.h index 6cf9bdb3..37744266 100644 --- a/include/sway/input/text_input.h +++ b/include/sway/input/text_input.h | |||
@@ -28,7 +28,10 @@ struct sway_input_method_relay { | |||
28 | 28 | ||
29 | struct wl_listener input_method_new; | 29 | struct wl_listener input_method_new; |
30 | struct wl_listener input_method_commit; | 30 | struct wl_listener input_method_commit; |
31 | struct wl_listener input_method_grab_keyboard; | ||
31 | struct wl_listener input_method_destroy; | 32 | struct wl_listener input_method_destroy; |
33 | |||
34 | struct wl_listener input_method_keyboard_grab_destroy; | ||
32 | }; | 35 | }; |
33 | 36 | ||
34 | struct sway_text_input { | 37 | struct sway_text_input { |
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, | |||
378 | } | 378 | } |
379 | } | 379 | } |
380 | 380 | ||
381 | /** | ||
382 | * Get keyboard grab of the seat from sway_keyboard if we should forward events | ||
383 | * to it. | ||
384 | * | ||
385 | * Returns NULL if the keyboard is not grabbed by an input method, | ||
386 | * or if event is from virtual keyboard of the same client as grab. | ||
387 | * TODO: see swaywm/wlroots#2322 | ||
388 | */ | ||
389 | static struct wlr_input_method_keyboard_grab_v2 *keyboard_get_im_grab( | ||
390 | struct sway_keyboard *keyboard) { | ||
391 | struct wlr_input_method_v2 *input_method = keyboard->seat_device-> | ||
392 | sway_seat->im_relay.input_method; | ||
393 | struct wlr_virtual_keyboard_v1 *virtual_keyboard = | ||
394 | wlr_input_device_get_virtual_keyboard(keyboard->seat_device->input_device->wlr_device); | ||
395 | if (!input_method || !input_method->keyboard_grab || (virtual_keyboard && | ||
396 | wl_resource_get_client(virtual_keyboard->resource) == | ||
397 | wl_resource_get_client(input_method->keyboard_grab->resource))) { | ||
398 | return NULL; | ||
399 | } | ||
400 | return input_method->keyboard_grab; | ||
401 | } | ||
402 | |||
381 | static void handle_key_event(struct sway_keyboard *keyboard, | 403 | static void handle_key_event(struct sway_keyboard *keyboard, |
382 | struct wlr_event_keyboard_key *event) { | 404 | struct wlr_event_keyboard_key *event) { |
383 | struct sway_seat *seat = keyboard->seat_device->sway_seat; | 405 | struct sway_seat *seat = keyboard->seat_device->sway_seat; |
@@ -488,17 +510,42 @@ static void handle_key_event(struct sway_keyboard *keyboard, | |||
488 | keyinfo.raw_keysyms_len); | 510 | keyinfo.raw_keysyms_len); |
489 | } | 511 | } |
490 | 512 | ||
491 | if (!handled || event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { | 513 | if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { |
514 | // If the pressed event was sent to a client, also send the released | ||
515 | // event. In particular, don't send the released event to the IM grab. | ||
492 | bool pressed_sent = update_shortcut_state( | 516 | bool pressed_sent = update_shortcut_state( |
493 | &keyboard->state_pressed_sent, event->keycode, event->state, | 517 | &keyboard->state_pressed_sent, event->keycode, |
494 | keyinfo.keycode, 0); | 518 | event->state, keyinfo.keycode, 0); |
495 | if (pressed_sent || event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { | 519 | if (pressed_sent) { |
496 | wlr_seat_set_keyboard(wlr_seat, wlr_device); | 520 | wlr_seat_set_keyboard(wlr_seat, wlr_device); |
497 | wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, | 521 | wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, |
498 | event->keycode, event->state); | 522 | event->keycode, event->state); |
523 | handled = true; | ||
524 | } | ||
525 | } | ||
526 | |||
527 | if (!handled) { | ||
528 | struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(keyboard); | ||
529 | |||
530 | if (kb_grab) { | ||
531 | wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab, | ||
532 | wlr_device->keyboard); | ||
533 | wlr_input_method_keyboard_grab_v2_send_key(kb_grab, | ||
534 | event->time_msec, event->keycode, event->state); | ||
535 | handled = true; | ||
499 | } | 536 | } |
500 | } | 537 | } |
501 | 538 | ||
539 | if (!handled && event->state != WL_KEYBOARD_KEY_STATE_RELEASED) { | ||
540 | // If a released event failed pressed sent test, and not in sent to | ||
541 | // keyboard grab, it is still not handled. Don't handle released here. | ||
542 | update_shortcut_state( | ||
543 | &keyboard->state_pressed_sent, event->keycode, event->state, | ||
544 | keyinfo.keycode, 0); | ||
545 | wlr_seat_set_keyboard(wlr_seat, wlr_device); | ||
546 | wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, | ||
547 | event->keycode, event->state); | ||
548 | } | ||
502 | 549 | ||
503 | free(device_identifier); | 550 | free(device_identifier); |
504 | } | 551 | } |
@@ -614,10 +661,19 @@ static void handle_modifier_event(struct sway_keyboard *keyboard) { | |||
614 | struct wlr_input_device *wlr_device = | 661 | struct wlr_input_device *wlr_device = |
615 | keyboard->seat_device->input_device->wlr_device; | 662 | keyboard->seat_device->input_device->wlr_device; |
616 | if (!wlr_device->keyboard->group) { | 663 | if (!wlr_device->keyboard->group) { |
617 | struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat; | 664 | struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(keyboard); |
618 | wlr_seat_set_keyboard(wlr_seat, wlr_device); | 665 | |
619 | wlr_seat_keyboard_notify_modifiers(wlr_seat, | 666 | if (kb_grab) { |
620 | &wlr_device->keyboard->modifiers); | 667 | wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab, |
668 | wlr_device->keyboard); | ||
669 | wlr_input_method_keyboard_grab_v2_send_modifiers(kb_grab, | ||
670 | &wlr_device->keyboard->modifiers); | ||
671 | } else { | ||
672 | struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat; | ||
673 | wlr_seat_set_keyboard(wlr_seat, wlr_device); | ||
674 | wlr_seat_keyboard_notify_modifiers(wlr_seat, | ||
675 | &wlr_device->keyboard->modifiers); | ||
676 | } | ||
621 | 677 | ||
622 | uint32_t modifiers = wlr_keyboard_get_modifiers(wlr_device->keyboard); | 678 | uint32_t modifiers = wlr_keyboard_get_modifiers(wlr_device->keyboard); |
623 | determine_bar_visibility(modifiers); | 679 | determine_bar_visibility(modifiers); |
diff --git a/sway/input/text_input.c b/sway/input/text_input.c index 2a8f6222..b8c19c17 100644 --- a/sway/input/text_input.c +++ b/sway/input/text_input.c | |||
@@ -55,6 +55,37 @@ static void handle_im_commit(struct wl_listener *listener, void *data) { | |||
55 | wlr_text_input_v3_send_done(text_input->input); | 55 | wlr_text_input_v3_send_done(text_input->input); |
56 | } | 56 | } |
57 | 57 | ||
58 | static void handle_im_keyboard_grab_destroy(struct wl_listener *listener, void *data) { | ||
59 | struct sway_input_method_relay *relay = wl_container_of(listener, relay, | ||
60 | input_method_keyboard_grab_destroy); | ||
61 | struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; | ||
62 | wl_list_remove(&relay->input_method_keyboard_grab_destroy.link); | ||
63 | |||
64 | if (keyboard_grab->keyboard) { | ||
65 | // send modifier state to original client | ||
66 | wlr_seat_keyboard_notify_modifiers(keyboard_grab->input_method->seat, | ||
67 | &keyboard_grab->keyboard->modifiers); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | static void handle_im_grab_keyboard(struct wl_listener *listener, void *data) { | ||
72 | struct sway_input_method_relay *relay = wl_container_of(listener, relay, | ||
73 | input_method_grab_keyboard); | ||
74 | struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; | ||
75 | |||
76 | // send modifier state to grab | ||
77 | struct wlr_keyboard *active_keyboard = wlr_seat_get_keyboard(relay->seat->wlr_seat); | ||
78 | wlr_input_method_keyboard_grab_v2_set_keyboard(keyboard_grab, | ||
79 | active_keyboard); | ||
80 | wlr_input_method_keyboard_grab_v2_send_modifiers(keyboard_grab, | ||
81 | &active_keyboard->modifiers); | ||
82 | |||
83 | wl_signal_add(&keyboard_grab->events.destroy, | ||
84 | &relay->input_method_keyboard_grab_destroy); | ||
85 | relay->input_method_keyboard_grab_destroy.notify = | ||
86 | handle_im_keyboard_grab_destroy; | ||
87 | } | ||
88 | |||
58 | static void text_input_set_pending_focused_surface( | 89 | static void text_input_set_pending_focused_surface( |
59 | struct sway_text_input *text_input, struct wlr_surface *surface) { | 90 | struct sway_text_input *text_input, struct wlr_surface *surface) { |
60 | wl_list_remove(&text_input->pending_focused_surface_destroy.link); | 91 | wl_list_remove(&text_input->pending_focused_surface_destroy.link); |
@@ -245,6 +276,9 @@ static void relay_handle_input_method(struct wl_listener *listener, | |||
245 | wl_signal_add(&relay->input_method->events.commit, | 276 | wl_signal_add(&relay->input_method->events.commit, |
246 | &relay->input_method_commit); | 277 | &relay->input_method_commit); |
247 | relay->input_method_commit.notify = handle_im_commit; | 278 | relay->input_method_commit.notify = handle_im_commit; |
279 | wl_signal_add(&relay->input_method->events.grab_keyboard, | ||
280 | &relay->input_method_grab_keyboard); | ||
281 | relay->input_method_grab_keyboard.notify = handle_im_grab_keyboard; | ||
248 | wl_signal_add(&relay->input_method->events.destroy, | 282 | wl_signal_add(&relay->input_method->events.destroy, |
249 | &relay->input_method_destroy); | 283 | &relay->input_method_destroy); |
250 | relay->input_method_destroy.notify = handle_im_destroy; | 284 | relay->input_method_destroy.notify = handle_im_destroy; |