From 20e8ac007551795754860f6c80ea3877fc184537 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Wed, 21 May 2025 11:21:39 -0400 Subject: [PATCH] wayland: Fix keymap changed event spam with non-latin keyboard layouts The function SDL_GetCurrentKeymap() would return null instead of the actual bound keymap for non-latin layouts if certain mapping options were set. Add a parameter to ignore the keymap options and always return the actual bound keymap, which is needed in the Wayland backend to avoid spamming keymap changed events on every keystroke with certain layouts. --- src/events/SDL_keyboard.c | 22 ++++++++++++---------- src/events/SDL_keymap.c | 4 ++-- src/events/SDL_keymap_c.h | 5 ++++- src/video/wayland/SDL_waylandevents.c | 12 ++++++------ 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c index 766a095257..fc06f07258 100644 --- a/src/events/SDL_keyboard.c +++ b/src/events/SDL_keyboard.c @@ -239,20 +239,22 @@ void SDL_ResetKeyboard(void) } } -SDL_Keymap *SDL_GetCurrentKeymap(void) +SDL_Keymap *SDL_GetCurrentKeymap(bool ignore_options) { SDL_Keyboard *keyboard = &SDL_keyboard; SDL_Keymap *keymap = SDL_keyboard.keymap; - if (keymap && keymap->thai_keyboard) { - // Thai keyboards are QWERTY plus Thai characters, use the default QWERTY keymap - return NULL; - } + if (!ignore_options) { + if (keymap && keymap->thai_keyboard) { + // Thai keyboards are QWERTY plus Thai characters, use the default QWERTY keymap + return NULL; + } - if ((keyboard->keycode_options & KEYCODE_OPTION_LATIN_LETTERS) && - keymap && !keymap->latin_letters) { - // We'll use the default QWERTY keymap - return NULL; + if ((keyboard->keycode_options & KEYCODE_OPTION_LATIN_LETTERS) && + keymap && !keymap->latin_letters) { + // We'll use the default QWERTY keymap + return NULL; + } } return keyboard->keymap; @@ -490,7 +492,7 @@ SDL_Keycode SDL_GetKeyFromScancode(SDL_Scancode scancode, SDL_Keymod modstate, b SDL_Keyboard *keyboard = &SDL_keyboard; if (key_event) { - SDL_Keymap *keymap = SDL_GetCurrentKeymap(); + SDL_Keymap *keymap = SDL_GetCurrentKeymap(false); bool numlock = (modstate & SDL_KMOD_NUM) != 0; SDL_Keycode keycode; diff --git a/src/events/SDL_keymap.c b/src/events/SDL_keymap.c index f99a7975dc..32e4975e7d 100644 --- a/src/events/SDL_keymap.c +++ b/src/events/SDL_keymap.c @@ -1059,7 +1059,7 @@ const char *SDL_GetKeyName(SDL_Keycode key) // but the key name is defined as the letter printed on that key, // which is usually the shifted capital letter. if (key > 0x7F || (key >= 'a' && key <= 'z')) { - SDL_Keymap *keymap = SDL_GetCurrentKeymap(); + SDL_Keymap *keymap = SDL_GetCurrentKeymap(false); SDL_Keymod modstate; SDL_Scancode scancode = SDL_GetKeymapScancode(keymap, key, &modstate); if (scancode != SDL_SCANCODE_UNKNOWN && !(modstate & SDL_KMOD_SHIFT)) { @@ -1127,7 +1127,7 @@ SDL_Keycode SDL_GetKeyFromName(const char *name) // SDL_Keycode is defined as the unshifted key on the keyboard, // but the key name is defined as the letter printed on that key, // which is usually the shifted capital letter. - SDL_Keymap *keymap = SDL_GetCurrentKeymap(); + SDL_Keymap *keymap = SDL_GetCurrentKeymap(false); SDL_Keymod modstate; SDL_Scancode scancode = SDL_GetKeymapScancode(keymap, key, &modstate); if (scancode != SDL_SCANCODE_UNKNOWN && (modstate & (SDL_KMOD_SHIFT | SDL_KMOD_CAPS))) { diff --git a/src/events/SDL_keymap_c.h b/src/events/SDL_keymap_c.h index a9c2c171fb..311e397e67 100644 --- a/src/events/SDL_keymap_c.h +++ b/src/events/SDL_keymap_c.h @@ -34,7 +34,10 @@ typedef struct SDL_Keymap bool thai_keyboard; } SDL_Keymap; -SDL_Keymap *SDL_GetCurrentKeymap(void); +/* This may return null even when a keymap is bound, depending on the current keyboard mapping options. + * Set 'ignore_options' to true to always return the keymap that is actually bound. + */ +SDL_Keymap *SDL_GetCurrentKeymap(bool ignore_options); SDL_Keymap *SDL_CreateKeymap(bool auto_release); void SDL_SetKeymapEntry(SDL_Keymap *keymap, SDL_Scancode scancode, SDL_Keymod modstate, SDL_Keycode keycode); SDL_Keycode SDL_GetKeymapKeycode(SDL_Keymap *keymap, SDL_Scancode scancode, SDL_Keymod modstate); diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 7198dd2cf8..89de867198 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -438,7 +438,7 @@ int Wayland_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS) // If key repeat is active, we'll need to cap our maximum wait time to handle repeats wl_list_for_each (seat, &d->seat_list, link) { if (keyboard_repeat_is_set(&seat->keyboard.repeat)) { - if (seat->keyboard.sdl_keymap != SDL_GetCurrentKeymap()) { + if (seat->keyboard.sdl_keymap != SDL_GetCurrentKeymap(true)) { SDL_SetKeymap(seat->keyboard.sdl_keymap, true); SDL_SetModState(seat->keyboard.pressed_modifiers | seat->keyboard.locked_modifiers); } @@ -477,7 +477,7 @@ int Wayland_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS) // If key repeat is active, we might have woken up to generate a key event if (key_repeat_active) { wl_list_for_each (seat, &d->seat_list, link) { - if (seat->keyboard.sdl_keymap != SDL_GetCurrentKeymap()) { + if (seat->keyboard.sdl_keymap != SDL_GetCurrentKeymap(true)) { SDL_SetKeymap(seat->keyboard.sdl_keymap, true); SDL_SetModState(seat->keyboard.pressed_modifiers | seat->keyboard.locked_modifiers); } @@ -548,7 +548,7 @@ void Wayland_PumpEvents(SDL_VideoDevice *_this) wl_list_for_each (seat, &d->seat_list, link) { if (keyboard_repeat_is_set(&seat->keyboard.repeat)) { - if (seat->keyboard.sdl_keymap != SDL_GetCurrentKeymap()) { + if (seat->keyboard.sdl_keymap != SDL_GetCurrentKeymap(true)) { SDL_SetKeymap(seat->keyboard.sdl_keymap, true); SDL_SetModState(seat->keyboard.pressed_modifiers | seat->keyboard.locked_modifiers); } @@ -1820,7 +1820,7 @@ static void keyboard_handle_enter(void *data, struct wl_keyboard *keyboard, Uint64 timestamp = SDL_GetTicksNS(); window->last_focus_event_time_ns = timestamp; - if (SDL_GetCurrentKeymap() != seat->keyboard.sdl_keymap) { + if (SDL_GetCurrentKeymap(true) != seat->keyboard.sdl_keymap) { SDL_SetKeymap(seat->keyboard.sdl_keymap, true); } @@ -1970,7 +1970,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard, Wayland_UpdateImplicitGrabSerial(seat, serial); - if (seat->keyboard.sdl_keymap != SDL_GetCurrentKeymap()) { + if (seat->keyboard.sdl_keymap != SDL_GetCurrentKeymap(true)) { SDL_SetKeymap(seat->keyboard.sdl_keymap, true); SDL_SetModState(seat->keyboard.pressed_modifiers | seat->keyboard.locked_modifiers); } @@ -2131,7 +2131,7 @@ static void Wayland_SeatDestroyKeyboard(SDL_WaylandSeat *seat, bool send_event) SDL_RemoveKeyboard(seat->keyboard.sdl_id, send_event); if (seat->keyboard.sdl_keymap) { - if (seat->keyboard.sdl_keymap == SDL_GetCurrentKeymap()) { + if (seat->keyboard.sdl_keymap == SDL_GetCurrentKeymap(true)) { SDL_SetKeymap(NULL, false); } SDL_DestroyKeymap(seat->keyboard.sdl_keymap);