Fix broken dead key behavior on Wayland

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.
This commit is contained in:
Hanicef 2024-06-06 13:18:22 +02:00 committed by Frank Praznik
parent 7fce9f3fd0
commit 1c3090a1ac
4 changed files with 15 additions and 22 deletions

View File

@ -1305,10 +1305,8 @@ 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);
SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ? SDL_PRESSED : SDL_RELEASED, scancode);
}
scancode = Wayland_get_scancode_from_key(input, key + 8);
SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ? SDL_PRESSED : SDL_RELEASED, scancode);
Wayland_data_device_set_serial(input->data_device, serial);
Wayland_primary_selection_device_set_serial(input->primary_selection_device, serial);

View File

@ -54,25 +54,13 @@ void Wayland_QuitKeyboard(_THIS)
void Wayland_StartTextInput(_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(_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(_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);
}
}
void Wayland_SetTextInputRect(_THIS, const SDL_Rect *rect)

View File

@ -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(_THIS);

View File

@ -146,6 +146,7 @@ SDL_WAYLAND_SYM(struct xkb_compose_table *, xkb_compose_table_new_from_locale, (
const char *locale, enum xkb_compose_compile_flags) )
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_reset, (struct xkb_compose_state *) )
SDL_WAYLAND_SYM(void, xkb_compose_state_unref, (struct xkb_compose_state *) )
SDL_WAYLAND_SYM(enum xkb_compose_feed_result, xkb_compose_state_feed, (struct xkb_compose_state *, xkb_keysym_t) )
SDL_WAYLAND_SYM(enum xkb_compose_status, xkb_compose_state_get_status, (struct xkb_compose_state *) )