SDL: Fixed mapping the non-US hash key on European keyboards

From 5ee88d43f96fda3cae706f5b610280fc81158594 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 10 Jul 2024 20:13:40 -0700
Subject: [PATCH] Fixed mapping the non-US hash key on European keyboards

---
 src/events/SDL_keymap.c                 | 356 +++++++++++++++++++++++-
 src/video/cocoa/SDL_cocoakeyboard.m     |   3 +-
 src/video/windows/SDL_windowskeyboard.c |   3 +-
 3 files changed, 356 insertions(+), 6 deletions(-)

diff --git a/src/events/SDL_keymap.c b/src/events/SDL_keymap.c
index 6336106816381..db2861865b99d 100644
--- a/src/events/SDL_keymap.c
+++ b/src/events/SDL_keymap.c
@@ -238,11 +238,359 @@ SDL_Keycode SDL_GetDefaultKeyFromScancode(SDL_Scancode scancode, SDL_Keymod mods
         }
     }
 
-    if (scancode == SDL_SCANCODE_DELETE) {
+    // These scancodes are not mapped to printable keycodes
+    switch (scancode) {
+    case SDL_SCANCODE_DELETE:
         return SDLK_DELETE;
+    case SDL_SCANCODE_CAPSLOCK:
+        return SDLK_CAPSLOCK;
+    case SDL_SCANCODE_F1:
+        return SDLK_F1;
+    case SDL_SCANCODE_F2:
+        return SDLK_F2;
+    case SDL_SCANCODE_F3:
+        return SDLK_F3;
+    case SDL_SCANCODE_F4:
+        return SDLK_F4;
+    case SDL_SCANCODE_F5:
+        return SDLK_F5;
+    case SDL_SCANCODE_F6:
+        return SDLK_F6;
+    case SDL_SCANCODE_F7:
+        return SDLK_F7;
+    case SDL_SCANCODE_F8:
+        return SDLK_F8;
+    case SDL_SCANCODE_F9:
+        return SDLK_F9;
+    case SDL_SCANCODE_F10:
+        return SDLK_F10;
+    case SDL_SCANCODE_F11:
+        return SDLK_F11;
+    case SDL_SCANCODE_F12:
+        return SDLK_F12;
+    case SDL_SCANCODE_PRINTSCREEN:
+        return SDLK_PRINTSCREEN;
+    case SDL_SCANCODE_SCROLLLOCK:
+        return SDLK_SCROLLLOCK;
+    case SDL_SCANCODE_PAUSE:
+        return SDLK_PAUSE;
+    case SDL_SCANCODE_INSERT:
+        return SDLK_INSERT;
+    case SDL_SCANCODE_HOME:
+        return SDLK_HOME;
+    case SDL_SCANCODE_PAGEUP:
+        return SDLK_PAGEUP;
+    case SDL_SCANCODE_END:
+        return SDLK_END;
+    case SDL_SCANCODE_PAGEDOWN:
+        return SDLK_PAGEDOWN;
+    case SDL_SCANCODE_RIGHT:
+        return SDLK_RIGHT;
+    case SDL_SCANCODE_LEFT:
+        return SDLK_LEFT;
+    case SDL_SCANCODE_DOWN:
+        return SDLK_DOWN;
+    case SDL_SCANCODE_UP:
+        return SDLK_UP;
+    case SDL_SCANCODE_NUMLOCKCLEAR:
+        return SDLK_NUMLOCKCLEAR;
+    case SDL_SCANCODE_KP_DIVIDE:
+        return SDLK_KP_DIVIDE;
+    case SDL_SCANCODE_KP_MULTIPLY:
+        return SDLK_KP_MULTIPLY;
+    case SDL_SCANCODE_KP_MINUS:
+        return SDLK_KP_MINUS;
+    case SDL_SCANCODE_KP_PLUS:
+        return SDLK_KP_PLUS;
+    case SDL_SCANCODE_KP_ENTER:
+        return SDLK_KP_ENTER;
+    case SDL_SCANCODE_KP_1:
+        return SDLK_KP_1;
+    case SDL_SCANCODE_KP_2:
+        return SDLK_KP_2;
+    case SDL_SCANCODE_KP_3:
+        return SDLK_KP_3;
+    case SDL_SCANCODE_KP_4:
+        return SDLK_KP_4;
+    case SDL_SCANCODE_KP_5:
+        return SDLK_KP_5;
+    case SDL_SCANCODE_KP_6:
+        return SDLK_KP_6;
+    case SDL_SCANCODE_KP_7:
+        return SDLK_KP_7;
+    case SDL_SCANCODE_KP_8:
+        return SDLK_KP_8;
+    case SDL_SCANCODE_KP_9:
+        return SDLK_KP_9;
+    case SDL_SCANCODE_KP_0:
+        return SDLK_KP_0;
+    case SDL_SCANCODE_KP_PERIOD:
+        return SDLK_KP_PERIOD;
+    case SDL_SCANCODE_APPLICATION:
+        return SDLK_APPLICATION;
+    case SDL_SCANCODE_POWER:
+        return SDLK_POWER;
+    case SDL_SCANCODE_KP_EQUALS:
+        return SDLK_KP_EQUALS;
+    case SDL_SCANCODE_F13:
+        return SDLK_F13;
+    case SDL_SCANCODE_F14:
+        return SDLK_F14;
+    case SDL_SCANCODE_F15:
+        return SDLK_F15;
+    case SDL_SCANCODE_F16:
+        return SDLK_F16;
+    case SDL_SCANCODE_F17:
+        return SDLK_F17;
+    case SDL_SCANCODE_F18:
+        return SDLK_F18;
+    case SDL_SCANCODE_F19:
+        return SDLK_F19;
+    case SDL_SCANCODE_F20:
+        return SDLK_F20;
+    case SDL_SCANCODE_F21:
+        return SDLK_F21;
+    case SDL_SCANCODE_F22:
+        return SDLK_F22;
+    case SDL_SCANCODE_F23:
+        return SDLK_F23;
+    case SDL_SCANCODE_F24:
+        return SDLK_F24;
+    case SDL_SCANCODE_EXECUTE:
+        return SDLK_EXECUTE;
+    case SDL_SCANCODE_HELP:
+        return SDLK_HELP;
+    case SDL_SCANCODE_MENU:
+        return SDLK_MENU;
+    case SDL_SCANCODE_SELECT:
+        return SDLK_SELECT;
+    case SDL_SCANCODE_STOP:
+        return SDLK_STOP;
+    case SDL_SCANCODE_AGAIN:
+        return SDLK_AGAIN;
+    case SDL_SCANCODE_UNDO:
+        return SDLK_UNDO;
+    case SDL_SCANCODE_CUT:
+        return SDLK_CUT;
+    case SDL_SCANCODE_COPY:
+        return SDLK_COPY;
+    case SDL_SCANCODE_PASTE:
+        return SDLK_PASTE;
+    case SDL_SCANCODE_FIND:
+        return SDLK_FIND;
+    case SDL_SCANCODE_MUTE:
+        return SDLK_MUTE;
+    case SDL_SCANCODE_VOLUMEUP:
+        return SDLK_VOLUMEUP;
+    case SDL_SCANCODE_VOLUMEDOWN:
+        return SDLK_VOLUMEDOWN;
+    case SDL_SCANCODE_KP_COMMA:
+        return SDLK_KP_COMMA;
+    case SDL_SCANCODE_KP_EQUALSAS400:
+        return SDLK_KP_EQUALSAS400;
+    case SDL_SCANCODE_ALTERASE:
+        return SDLK_ALTERASE;
+    case SDL_SCANCODE_SYSREQ:
+        return SDLK_SYSREQ;
+    case SDL_SCANCODE_CANCEL:
+        return SDLK_CANCEL;
+    case SDL_SCANCODE_CLEAR:
+        return SDLK_CLEAR;
+    case SDL_SCANCODE_PRIOR:
+        return SDLK_PRIOR;
+    case SDL_SCANCODE_RETURN2:
+        return SDLK_RETURN2;
+    case SDL_SCANCODE_SEPARATOR:
+        return SDLK_SEPARATOR;
+    case SDL_SCANCODE_OUT:
+        return SDLK_OUT;
+    case SDL_SCANCODE_OPER:
+        return SDLK_OPER;
+    case SDL_SCANCODE_CLEARAGAIN:
+        return SDLK_CLEARAGAIN;
+    case SDL_SCANCODE_CRSEL:
+        return SDLK_CRSEL;
+    case SDL_SCANCODE_EXSEL:
+        return SDLK_EXSEL;
+    case SDL_SCANCODE_KP_00:
+        return SDLK_KP_00;
+    case SDL_SCANCODE_KP_000:
+        return SDLK_KP_000;
+    case SDL_SCANCODE_THOUSANDSSEPARATOR:
+        return SDLK_THOUSANDSSEPARATOR;
+    case SDL_SCANCODE_DECIMALSEPARATOR:
+        return SDLK_DECIMALSEPARATOR;
+    case SDL_SCANCODE_CURRENCYUNIT:
+        return SDLK_CURRENCYUNIT;
+    case SDL_SCANCODE_CURRENCYSUBUNIT:
+        return SDLK_CURRENCYSUBUNIT;
+    case SDL_SCANCODE_KP_LEFTPAREN:
+        return SDLK_KP_LEFTPAREN;
+    case SDL_SCANCODE_KP_RIGHTPAREN:
+        return SDLK_KP_RIGHTPAREN;
+    case SDL_SCANCODE_KP_LEFTBRACE:
+        return SDLK_KP_LEFTBRACE;
+    case SDL_SCANCODE_KP_RIGHTBRACE:
+        return SDLK_KP_RIGHTBRACE;
+    case SDL_SCANCODE_KP_TAB:
+        return SDLK_KP_TAB;
+    case SDL_SCANCODE_KP_BACKSPACE:
+        return SDLK_KP_BACKSPACE;
+    case SDL_SCANCODE_KP_A:
+        return SDLK_KP_A;
+    case SDL_SCANCODE_KP_B:
+        return SDLK_KP_B;
+    case SDL_SCANCODE_KP_C:
+        return SDLK_KP_C;
+    case SDL_SCANCODE_KP_D:
+        return SDLK_KP_D;
+    case SDL_SCANCODE_KP_E:
+        return SDLK_KP_E;
+    case SDL_SCANCODE_KP_F:
+        return SDLK_KP_F;
+    case SDL_SCANCODE_KP_XOR:
+        return SDLK_KP_XOR;
+    case SDL_SCANCODE_KP_POWER:
+        return SDLK_KP_POWER;
+    case SDL_SCANCODE_KP_PERCENT:
+        return SDLK_KP_PERCENT;
+    case SDL_SCANCODE_KP_LESS:
+        return SDLK_KP_LESS;
+    case SDL_SCANCODE_KP_GREATER:
+        return SDLK_KP_GREATER;
+    case SDL_SCANCODE_KP_AMPERSAND:
+        return SDLK_KP_AMPERSAND;
+    case SDL_SCANCODE_KP_DBLAMPERSAND:
+        return SDLK_KP_DBLAMPERSAND;
+    case SDL_SCANCODE_KP_VERTICALBAR:
+        return SDLK_KP_VERTICALBAR;
+    case SDL_SCANCODE_KP_DBLVERTICALBAR:
+        return SDLK_KP_DBLVERTICALBAR;
+    case SDL_SCANCODE_KP_COLON:
+        return SDLK_KP_COLON;
+    case SDL_SCANCODE_KP_HASH:
+        return SDLK_KP_HASH;
+    case SDL_SCANCODE_KP_SPACE:
+        return SDLK_KP_SPACE;
+    case SDL_SCANCODE_KP_AT:
+        return SDLK_KP_AT;
+    case SDL_SCANCODE_KP_EXCLAM:
+        return SDLK_KP_EXCLAM;
+    case SDL_SCANCODE_KP_MEMSTORE:
+        return SDLK_KP_MEMSTORE;
+    case SDL_SCANCODE_KP_MEMRECALL:
+        return SDLK_KP_MEMRECALL;
+    case SDL_SCANCODE_KP_MEMCLEAR:
+        return SDLK_KP_MEMCLEAR;
+    case SDL_SCANCODE_KP_MEMADD:
+        return SDLK_KP_MEMADD;
+    case SDL_SCANCODE_KP_MEMSUBTRACT:
+        return SDLK_KP_MEMSUBTRACT;
+    case SDL_SCANCODE_KP_MEMMULTIPLY:
+        return SDLK_KP_MEMMULTIPLY;
+    case SDL_SCANCODE_KP_MEMDIVIDE:
+        return SDLK_KP_MEMDIVIDE;
+    case SDL_SCANCODE_KP_PLUSMINUS:
+        return SDLK_KP_PLUSMINUS;
+    case SDL_SCANCODE_KP_CLEAR:
+        return SDLK_KP_CLEAR;
+    case SDL_SCANCODE_KP_CLEARENTRY:
+        return SDLK_KP_CLEARENTRY;
+    case SDL_SCANCODE_KP_BINARY:
+        return SDLK_KP_BINARY;
+    case SDL_SCANCODE_KP_OCTAL:
+        return SDLK_KP_OCTAL;
+    case SDL_SCANCODE_KP_DECIMAL:
+        return SDLK_KP_DECIMAL;
+    case SDL_SCANCODE_KP_HEXADECIMAL:
+        return SDLK_KP_HEXADECIMAL;
+    case SDL_SCANCODE_LCTRL:
+        return SDLK_LCTRL;
+    case SDL_SCANCODE_LSHIFT:
+        return SDLK_LSHIFT;
+    case SDL_SCANCODE_LALT:
+        return SDLK_LALT;
+    case SDL_SCANCODE_LGUI:
+        return SDLK_LGUI;
+    case SDL_SCANCODE_RCTRL:
+        return SDLK_RCTRL;
+    case SDL_SCANCODE_RSHIFT:
+        return SDLK_RSHIFT;
+    case SDL_SCANCODE_RALT:
+        return SDLK_RALT;
+    case SDL_SCANCODE_RGUI:
+        return SDLK_RGUI;
+    case SDL_SCANCODE_MODE:
+        return SDLK_MODE;
+    case SDL_SCANCODE_SLEEP:
+        return SDLK_SLEEP;
+    case SDL_SCANCODE_WAKE:
+        return SDLK_WAKE;
+    case SDL_SCANCODE_CHANNEL_INCREMENT:
+        return SDLK_CHANNEL_INCREMENT;
+    case SDL_SCANCODE_CHANNEL_DECREMENT:
+        return SDLK_CHANNEL_DECREMENT;
+    case SDL_SCANCODE_MEDIA_PLAY:
+        return SDLK_MEDIA_PLAY;
+    case SDL_SCANCODE_MEDIA_PAUSE:
+        return SDLK_MEDIA_PAUSE;
+    case SDL_SCANCODE_MEDIA_RECORD:
+        return SDLK_MEDIA_RECORD;
+    case SDL_SCANCODE_MEDIA_FAST_FORWARD:
+        return SDLK_MEDIA_FAST_FORWARD;
+    case SDL_SCANCODE_MEDIA_REWIND:
+        return SDLK_MEDIA_REWIND;
+    case SDL_SCANCODE_MEDIA_NEXT_TRACK:
+        return SDLK_MEDIA_NEXT_TRACK;
+    case SDL_SCANCODE_MEDIA_PREVIOUS_TRACK:
+        return SDLK_MEDIA_PREVIOUS_TRACK;
+    case SDL_SCANCODE_MEDIA_STOP:
+        return SDLK_MEDIA_STOP;
+    case SDL_SCANCODE_MEDIA_EJECT:
+        return SDLK_MEDIA_EJECT;
+    case SDL_SCANCODE_MEDIA_PLAY_PAUSE:
+        return SDLK_MEDIA_PLAY_PAUSE;
+    case SDL_SCANCODE_MEDIA_SELECT:
+        return SDLK_MEDIA_SELECT;
+    case SDL_SCANCODE_AC_NEW:
+        return SDLK_AC_NEW;
+    case SDL_SCANCODE_AC_OPEN:
+        return SDLK_AC_OPEN;
+    case SDL_SCANCODE_AC_CLOSE:
+        return SDLK_AC_CLOSE;
+    case SDL_SCANCODE_AC_EXIT:
+        return SDLK_AC_EXIT;
+    case SDL_SCANCODE_AC_SAVE:
+        return SDLK_AC_SAVE;
+    case SDL_SCANCODE_AC_PRINT:
+        return SDLK_AC_PRINT;
+    case SDL_SCANCODE_AC_PROPERTIES:
+        return SDLK_AC_PROPERTIES;
+    case SDL_SCANCODE_AC_SEARCH:
+        return SDLK_AC_SEARCH;
+    case SDL_SCANCODE_AC_HOME:
+        return SDLK_AC_HOME;
+    case SDL_SCANCODE_AC_BACK:
+        return SDLK_AC_BACK;
+    case SDL_SCANCODE_AC_FORWARD:
+        return SDLK_AC_FORWARD;
+    case SDL_SCANCODE_AC_STOP:
+        return SDLK_AC_STOP;
+    case SDL_SCANCODE_AC_REFRESH:
+        return SDLK_AC_REFRESH;
+    case SDL_SCANCODE_AC_BOOKMARKS:
+        return SDLK_AC_BOOKMARKS;
+    case SDL_SCANCODE_SOFTLEFT:
+        return SDLK_SOFTLEFT;
+    case SDL_SCANCODE_SOFTRIGHT:
+        return SDLK_SOFTRIGHT;
+    case SDL_SCANCODE_CALL:
+        return SDLK_CALL;
+    case SDL_SCANCODE_ENDCALL:
+        return SDLK_ENDCALL;
+    default:
+        return SDLK_UNKNOWN;
     }
-
-    return SDL_SCANCODE_TO_KEYCODE(scancode);
 }
 
 SDL_Scancode SDL_GetDefaultScancodeFromKey(SDL_Keycode key, SDL_Keymod *modstate)
@@ -394,7 +742,7 @@ static const char *SDL_scancode_names[SDL_NUM_SCANCODES] =
     /* 97 */ "Keypad 9",
     /* 98 */ "Keypad 0",
     /* 99 */ "Keypad .",
-    /* 100 */ "\\",
+    /* 100 */ NULL,
     /* 101 */ "Application",
     /* 102 */ "Power",
     /* 103 */ "Keypad =",
diff --git a/src/video/cocoa/SDL_cocoakeyboard.m b/src/video/cocoa/SDL_cocoakeyboard.m
index c575346f80ff0..463f2c542a57d 100644
--- a/src/video/cocoa/SDL_cocoakeyboard.m
+++ b/src/video/cocoa/SDL_cocoakeyboard.m
@@ -288,7 +288,8 @@ static void UpdateKeymap(SDL_CocoaVideoData *data, SDL_bool send_event)
             /* Make sure this scancode is a valid character scancode */
             SDL_Scancode scancode = darwin_scancode_table[i];
             if (scancode == SDL_SCANCODE_UNKNOWN ||
-                scancode >= SDL_SCANCODE_CAPSLOCK) {
+                scancode == SDL_SCANCODE_DELETE ||
+                (SDL_GetDefaultKeyFromScancode(scancode, SDL_KMOD_NONE) & SDLK_SCANCODE_MASK)) {
                 continue;
             }
 
diff --git a/src/video/windows/SDL_windowskeyboard.c b/src/video/windows/SDL_windowskeyboard.c
index cbb7a40b99eb0..6da493e1b3ae6 100644
--- a/src/video/windows/SDL_windowskeyboard.c
+++ b/src/video/windows/SDL_windowskeyboard.c
@@ -106,7 +106,8 @@ void WIN_UpdateKeymap(SDL_bool send_event)
             /* Make sure this scancode is a valid character scancode */
             scancode = windows_scancode_table[i];
             if (scancode == SDL_SCANCODE_UNKNOWN ||
-                scancode >= SDL_SCANCODE_CAPSLOCK) {
+                scancode == SDL_SCANCODE_DELETE ||
+                (SDL_GetDefaultKeyFromScancode(scancode, SDL_KMOD_NONE) & SDLK_SCANCODE_MASK)) {
                 continue;
             }