From 7a7d7802892a34b0fff9d7da54761b2568db6100 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Sat, 8 Jun 2024 11:07:53 -0400 Subject: [PATCH] wayland: Fix broken dead key behavior This fixes numerous problems regarding dead keys on Wayland. Most notably, Wayland was enforcing dead keys on SDL_KEYDOWN and SDL_KEYUP events, which caused unresponsiveness on keys that were mapped to dead keys (tilde on US-Intl is most notable for this, commonly used as a console key). When starting text input, not all state was reset properly. The text input protocol requires to be re-enabled every time text input changes, which SDL did not do. Also, XKB compose state was not reset at all, causing composite and dead keys to carry over from when text input was disabled. Manual cherry-pick of 1c3090a1acee9c74bf8499d8c1ef0b0f317d3110 by Hanicef --- src/video/wayland/SDL_waylandevents.c | 8 +++---- src/video/wayland/SDL_waylandkeyboard.c | 29 ++++++++++--------------- src/video/wayland/SDL_waylandkeyboard.h | 1 - src/video/wayland/SDL_waylandsym.h | 1 + 4 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index fbb9b4de7b..378ab269cb 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -1622,11 +1622,9 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard, keyboard_input_get_text(text, input, key, SDL_RELEASED, &handled_by_ime); } - if (!handled_by_ime) { - scancode = Wayland_get_scancode_from_key(input, key + 8); - Wayland_HandleModifierKeys(input, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED); - SDL_SendKeyboardKeyIgnoreModifiers(Wayland_GetKeyboardTimestamp(input, time), input->keyboard_id, state == WL_KEYBOARD_KEY_STATE_PRESSED ? SDL_PRESSED : SDL_RELEASED, scancode); - } + scancode = Wayland_get_scancode_from_key(input, key + 8); + Wayland_HandleModifierKeys(input, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED); + SDL_SendKeyboardKeyIgnoreModifiers(Wayland_GetKeyboardTimestamp(input, time), input->keyboard_id, state == WL_KEYBOARD_KEY_STATE_PRESSED ? SDL_PRESSED : SDL_RELEASED, scancode); if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { if (has_text && !(SDL_GetModState() & SDL_KMOD_CTRL)) { diff --git a/src/video/wayland/SDL_waylandkeyboard.c b/src/video/wayland/SDL_waylandkeyboard.c index 0e903e2178..eac7e8219a 100644 --- a/src/video/wayland/SDL_waylandkeyboard.c +++ b/src/video/wayland/SDL_waylandkeyboard.c @@ -54,25 +54,13 @@ void Wayland_QuitKeyboard(SDL_VideoDevice *_this) void Wayland_StartTextInput(SDL_VideoDevice *_this) { SDL_VideoData *driverdata = _this->driverdata; + struct SDL_WaylandInput *input = driverdata->input; if (driverdata->text_input_manager) { - struct SDL_WaylandInput *input = driverdata->input; if (input && input->text_input) { const SDL_Rect *rect = &input->text_input->cursor_rect; - /* Don't re-enable if we're already enabled. */ - if (input->text_input->is_enabled) { - return; - } - - /* For some reason this has to be done twice, it appears to be a - * bug in mutter? Maybe? - * -flibit - */ zwp_text_input_v3_enable(input->text_input->text_input); - zwp_text_input_v3_commit(input->text_input->text_input); - zwp_text_input_v3_enable(input->text_input->text_input); - zwp_text_input_v3_commit(input->text_input->text_input); /* Now that it's enabled, set the input properties */ zwp_text_input_v3_set_content_type(input->text_input->text_input, @@ -87,29 +75,36 @@ void Wayland_StartTextInput(SDL_VideoDevice *_this) rect->h); } zwp_text_input_v3_commit(input->text_input->text_input); - input->text_input->is_enabled = SDL_TRUE; } } + + if (input && input->xkb.compose_state) { + /* Reset compose state so composite and dead keys don't carry over */ + WAYLAND_xkb_compose_state_reset(input->xkb.compose_state); + } } void Wayland_StopTextInput(SDL_VideoDevice *_this) { SDL_VideoData *driverdata = _this->driverdata; + struct SDL_WaylandInput *input = driverdata->input; if (driverdata->text_input_manager) { - struct SDL_WaylandInput *input = driverdata->input; if (input && input->text_input) { zwp_text_input_v3_disable(input->text_input->text_input); zwp_text_input_v3_commit(input->text_input->text_input); - input->text_input->is_enabled = SDL_FALSE; } } - #ifdef SDL_USE_IME else { SDL_IME_Reset(); } #endif + + if (input && input->xkb.compose_state) { + /* Reset compose state so composite and dead keys don't carry over */ + WAYLAND_xkb_compose_state_reset(input->xkb.compose_state); + } } int Wayland_SetTextInputRect(SDL_VideoDevice *_this, const SDL_Rect *rect) diff --git a/src/video/wayland/SDL_waylandkeyboard.h b/src/video/wayland/SDL_waylandkeyboard.h index 4a20ea26ab..62613cffff 100644 --- a/src/video/wayland/SDL_waylandkeyboard.h +++ b/src/video/wayland/SDL_waylandkeyboard.h @@ -28,7 +28,6 @@ typedef struct SDL_WaylandTextInput struct zwp_text_input_v3 *text_input; SDL_Rect cursor_rect; SDL_bool has_preedit; - SDL_bool is_enabled; } SDL_WaylandTextInput; extern int Wayland_InitKeyboard(SDL_VideoDevice *_this); diff --git a/src/video/wayland/SDL_waylandsym.h b/src/video/wayland/SDL_waylandsym.h index ac512a1458..25fec030ff 100644 --- a/src/video/wayland/SDL_waylandsym.h +++ b/src/video/wayland/SDL_waylandsym.h @@ -144,6 +144,7 @@ SDL_WAYLAND_SYM(enum xkb_state_component, xkb_state_update_mask, (struct xkb_sta xkb_layout_index_t locked_layout) ) SDL_WAYLAND_SYM(struct xkb_compose_table *, xkb_compose_table_new_from_locale, (struct xkb_context *,\ const char *locale, enum xkb_compose_compile_flags) ) +SDL_WAYLAND_SYM(void, xkb_compose_state_reset, (struct xkb_compose_state *) ) SDL_WAYLAND_SYM(void, xkb_compose_table_unref, (struct xkb_compose_table *) ) SDL_WAYLAND_SYM(struct xkb_compose_state *, xkb_compose_state_new, (struct xkb_compose_table *, enum xkb_compose_state_flags) ) SDL_WAYLAND_SYM(void, xkb_compose_state_unref, (struct xkb_compose_state *) )