From 16f8122a0d481825cfd77dea02ec75d3e02ddce4 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 31 Jan 2025 12:07:08 -0800 Subject: [PATCH] Keep the simplest mapping of scancode + modifer for a given keycode Fixes https://github.com/libsdl-org/sdl2-compat/issues/259 --- src/events/SDL_keymap.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/events/SDL_keymap.c b/src/events/SDL_keymap.c index 5c3f784c6c..bc21c33103 100644 --- a/src/events/SDL_keymap.c +++ b/src/events/SDL_keymap.c @@ -72,20 +72,36 @@ void SDL_SetKeymapEntry(SDL_Keymap *keymap, SDL_Scancode scancode, SDL_Keymod mo return; } - if (keycode == SDL_GetKeymapKeycode(keymap, scancode, modstate)) { - return; - } - - Uint32 key = ((Uint32)NormalizeModifierStateForKeymap(modstate) << 16) | scancode; + modstate = NormalizeModifierStateForKeymap(modstate); + Uint32 key = ((Uint32)modstate << 16) | scancode; const void *value; if (SDL_FindInHashTable(keymap->scancode_to_keycode, (void *)(uintptr_t)key, &value)) { + SDL_Keycode existing_keycode = (SDL_Keycode)(uintptr_t)value; + if (existing_keycode == keycode) { + // We already have this mapping + return; + } + // Changing the mapping, need to remove the existing entry from the keymap SDL_RemoveFromHashTable(keymap->scancode_to_keycode, (void *)(uintptr_t)key); - SDL_RemoveFromHashTable(keymap->keycode_to_scancode, value); } - SDL_InsertIntoHashTable(keymap->scancode_to_keycode, (void *)(uintptr_t)key, (void *)(uintptr_t)keycode); - SDL_InsertIntoHashTable(keymap->keycode_to_scancode, (void *)(uintptr_t)keycode, (void *)(uintptr_t)key); + + bool update_keycode = true; + if (SDL_FindInHashTable(keymap->keycode_to_scancode, (void *)(uintptr_t)keycode, &value)) { + Uint32 existing_value = (Uint32)(uintptr_t)value; + SDL_Keymod existing_modstate = (SDL_Keymod)(existing_value >> 16); + + // Keep the simplest combination of scancode and modifiers to generate this keycode + if (existing_modstate <= modstate) { + update_keycode = false; + } else { + SDL_RemoveFromHashTable(keymap->keycode_to_scancode, (void *)(uintptr_t)keycode); + } + } + if (update_keycode) { + SDL_InsertIntoHashTable(keymap->keycode_to_scancode, (void *)(uintptr_t)keycode, (void *)(uintptr_t)key); + } } SDL_Keycode SDL_GetKeymapKeycode(SDL_Keymap *keymap, SDL_Scancode scancode, SDL_Keymod modstate)