From 20e8ac007551795754860f6c80ea3877fc184537 Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
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 766a095257aa7..fc06f07258d43 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 f99a7975dc340..32e4975e7df22 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 a9c2c171fb184..311e397e677eb 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 7198dd2cf8ede..89de8671983e1 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);