SDL: X11 scancode mapping cleanup

From 99f2a503941f69bc7ec15791fddf1dc42bc158a4 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 13 Oct 2022 22:40:24 -0700
Subject: [PATCH] X11 scancode mapping cleanup

* Consolidated scancode mapping tables into a single location for all backends
* Verified that the xfree86_scancode_table2 is largely identical to the Linux scancode table
* Updated the Linux scancode table with the latest kernel keycodes (still unmapped)
* Route X11 keysym -> scancode mapping through the linux scancode table (which a few hand-written exceptions), which will allow mappings to automatically get picked up as they are added in the Linux scancode table
* Disabled verbose reporting of missing keysym mappings, we have enough data for now
---
 include/SDL_scancode.h                   |    5 +
 src/core/linux/SDL_evdev.c               |   30 +-
 src/events/SDL_keyboard.c                | 1053 ++++++++++++----------
 src/events/SDL_scancode_tables.c         |   73 ++
 src/events/SDL_scancode_tables_c.h       |   37 +
 src/events/scancodes_darwin.h            |    2 +
 src/events/scancodes_linux.h             | 1033 ++++++++++++++++-----
 src/events/scancodes_windows.h           |    2 +
 src/events/scancodes_xfree86.h           |  491 +++++-----
 src/video/directfb/SDL_DirectFB_events.c |    9 +-
 src/video/wayland/SDL_waylandevents.c    |   72 +-
 src/video/x11/SDL_x11events.c            |   11 +-
 src/video/x11/SDL_x11keyboard.c          |  584 +++++++++---
 13 files changed, 2248 insertions(+), 1154 deletions(-)
 create mode 100644 src/events/SDL_scancode_tables.c
 create mode 100644 src/events/SDL_scancode_tables_c.h

diff --git a/include/SDL_scancode.h b/include/SDL_scancode.h
index aaa782f8da05..6f40884eede0 100644
--- a/include/SDL_scancode.h
+++ b/include/SDL_scancode.h
@@ -345,6 +345,11 @@ typedef enum
      *  \name Usage page 0x0C
      *
      *  These values are mapped from usage page 0x0C (USB consumer page).
+     *  See https://usb.org/sites/default/files/hut1_2.pdf
+     *
+     *  There are way more keys in the spec than we can represent in the
+     *  current scancode range, so pick the ones that commonly come up in
+     *  real world usage.
      */
     /* @{ */
 
diff --git a/src/core/linux/SDL_evdev.c b/src/core/linux/SDL_evdev.c
index 6355e139249a..f5ab06253e83 100644
--- a/src/core/linux/SDL_evdev.c
+++ b/src/core/linux/SDL_evdev.c
@@ -42,7 +42,7 @@
 #include "SDL_endian.h"
 #include "SDL_scancode.h"
 #include "../../events/SDL_events_c.h"
-#include "../../events/scancodes_linux.h" /* adds linux_scancode_table */
+#include "../../events/SDL_scancode_tables_c.h"
 #include "../../core/linux/SDL_evdev_capabilities.h"
 #include "../../core/linux/SDL_udev.h"
 
@@ -509,23 +509,21 @@ SDL_EVDEV_Poll(void)
 static SDL_Scancode
 SDL_EVDEV_translate_keycode(int keycode)
 {
-    SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
-
-    if (keycode < SDL_arraysize(linux_scancode_table)) {
-        scancode = linux_scancode_table[keycode];
-
-        if (scancode == SDL_SCANCODE_UNKNOWN) {
-            /* BTN_TOUCH is handled elsewhere, but we might still end up here if
-               you get an unexpected BTN_TOUCH from something SDL believes is not
-               a touch device. In this case, we'd rather not get a misleading
-               SDL_Log message about an unknown key. */
-            if (keycode != BTN_TOUCH) {
-                SDL_Log("The key you just pressed is not recognized by SDL. To help "
-                    "get this fixed, please report this to the SDL forums/mailing list "
-                    "<https://discourse.libsdl.org/> EVDEV KeyCode %d", keycode);
-            }
+    SDL_Scancode scancode = SDL_GetScancodeFromTable(SDL_SCANCODE_TABLE_LINUX, keycode);
+
+#ifdef DEBUG_SCANCODES
+    if (scancode == SDL_SCANCODE_UNKNOWN) {
+        /* BTN_TOUCH is handled elsewhere, but we might still end up here if
+           you get an unexpected BTN_TOUCH from something SDL believes is not
+           a touch device. In this case, we'd rather not get a misleading
+           SDL_Log message about an unknown key. */
+        if (keycode != BTN_TOUCH) {
+            SDL_Log("The key you just pressed is not recognized by SDL. To help "
+                "get this fixed, please report this to the SDL forums/mailing list "
+                "<https://discourse.libsdl.org/> EVDEV KeyCode %d", keycode);
         }
     }
+#endif /* DEBUG_SCANCODES */
 
     return scancode;
 }
diff --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c
index f83191251c86..b1e27e1ae934 100644
--- a/src/events/SDL_keyboard.c
+++ b/src/events/SDL_keyboard.c
@@ -53,480 +53,591 @@ struct SDL_Keyboard
 static SDL_Keyboard SDL_keyboard;
 
 static const SDL_Keycode SDL_default_keymap[SDL_NUM_SCANCODES] = {
-    0, 0, 0, 0,
-    'a',
-    'b',
-    'c',
-    'd',
-    'e',
-    'f',
-    'g',
-    'h',
-    'i',
-    'j',
-    'k',
-    'l',
-    'm',
-    'n',
-    'o',
-    'p',
-    'q',
-    'r',
-    's',
-    't',
-    'u',
-    'v',
-    'w',
-    'x',
-    'y',
-    'z',
-    '1',
-    '2',
-    '3',
-    '4',
-    '5',
-    '6',
-    '7',
-    '8',
-    '9',
-    '0',
-    SDLK_RETURN,
-    SDLK_ESCAPE,
-    SDLK_BACKSPACE,
-    SDLK_TAB,
-    SDLK_SPACE,
-    '-',
-    '=',
-    '[',
-    ']',
-    '\\',
-    '#',
-    ';',
-    '\'',
-    '`',
-    ',',
-    '.',
-    '/',
-    SDLK_CAPSLOCK,
-    SDLK_F1,
-    SDLK_F2,
-    SDLK_F3,
-    SDLK_F4,
-    SDLK_F5,
-    SDLK_F6,
-    SDLK_F7,
-    SDLK_F8,
-    SDLK_F9,
-    SDLK_F10,
-    SDLK_F11,
-    SDLK_F12,
-    SDLK_PRINTSCREEN,
-    SDLK_SCROLLLOCK,
-    SDLK_PAUSE,
-    SDLK_INSERT,
-    SDLK_HOME,
-    SDLK_PAGEUP,
-    SDLK_DELETE,
-    SDLK_END,
-    SDLK_PAGEDOWN,
-    SDLK_RIGHT,
-    SDLK_LEFT,
-    SDLK_DOWN,
-    SDLK_UP,
-    SDLK_NUMLOCKCLEAR,
-    SDLK_KP_DIVIDE,
-    SDLK_KP_MULTIPLY,
-    SDLK_KP_MINUS,
-    SDLK_KP_PLUS,
-    SDLK_KP_ENTER,
-    SDLK_KP_1,
-    SDLK_KP_2,
-    SDLK_KP_3,
-    SDLK_KP_4,
-    SDLK_KP_5,
-    SDLK_KP_6,
-    SDLK_KP_7,
-    SDLK_KP_8,
-    SDLK_KP_9,
-    SDLK_KP_0,
-    SDLK_KP_PERIOD,
-    0,
-    SDLK_APPLICATION,
-    SDLK_POWER,
-    SDLK_KP_EQUALS,
-    SDLK_F13,
-    SDLK_F14,
-    SDLK_F15,
-    SDLK_F16,
-    SDLK_F17,
-    SDLK_F18,
-    SDLK_F19,
-    SDLK_F20,
-    SDLK_F21,
-    SDLK_F22,
-    SDLK_F23,
-    SDLK_F24,
-    SDLK_EXECUTE,
-    SDLK_HELP,
-    SDLK_MENU,
-    SDLK_SELECT,
-    SDLK_STOP,
-    SDLK_AGAIN,
-    SDLK_UNDO,
-    SDLK_CUT,
-    SDLK_COPY,
-    SDLK_PASTE,
-    SDLK_FIND,
-    SDLK_MUTE,
-    SDLK_VOLUMEUP,
-    SDLK_VOLUMEDOWN,
-    0, 0, 0,
-    SDLK_KP_COMMA,
-    SDLK_KP_EQUALSAS400,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    SDLK_ALTERASE,
-    SDLK_SYSREQ,
-    SDLK_CANCEL,
-    SDLK_CLEAR,
-    SDLK_PRIOR,
-    SDLK_RETURN2,
-    SDLK_SEPARATOR,
-    SDLK_OUT,
-    SDLK_OPER,
-    SDLK_CLEARAGAIN,
-    SDLK_CRSEL,
-    SDLK_EXSEL,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    SDLK_KP_00,
-    SDLK_KP_000,
-    SDLK_THOUSANDSSEPARATOR,
-    SDLK_DECIMALSEPARATOR,
-    SDLK_CURRENCYUNIT,
-    SDLK_CURRENCYSUBUNIT,
-    SDLK_KP_LEFTPAREN,
-    SDLK_KP_RIGHTPAREN,
-    SDLK_KP_LEFTBRACE,
-    SDLK_KP_RIGHTBRACE,
-    SDLK_KP_TAB,
-    SDLK_KP_BACKSPACE,
-    SDLK_KP_A,
-    SDLK_KP_B,
-    SDLK_KP_C,
-    SDLK_KP_D,
-    SDLK_KP_E,
-    SDLK_KP_F,
-    SDLK_KP_XOR,
-    SDLK_KP_POWER,
-    SDLK_KP_PERCENT,
-    SDLK_KP_LESS,
-    SDLK_KP_GREATER,
-    SDLK_KP_AMPERSAND,
-    SDLK_KP_DBLAMPERSAND,
-    SDLK_KP_VERTICALBAR,
-    SDLK_KP_DBLVERTICALBAR,
-    SDLK_KP_COLON,
-    SDLK_KP_HASH,
-    SDLK_KP_SPACE,
-    SDLK_KP_AT,
-    SDLK_KP_EXCLAM,
-    SDLK_KP_MEMSTORE,
-    SDLK_KP_MEMRECALL,
-    SDLK_KP_MEMCLEAR,
-    SDLK_KP_MEMADD,
-    SDLK_KP_MEMSUBTRACT,
-    SDLK_KP_MEMMULTIPLY,
-    SDLK_KP_MEMDIVIDE,
-    SDLK_KP_PLUSMINUS,
-    SDLK_KP_CLEAR,
-    SDLK_KP_CLEARENTRY,
-    SDLK_KP_BINARY,
-    SDLK_KP_OCTAL,
-    SDLK_KP_DECIMAL,
-    SDLK_KP_HEXADECIMAL,
-    0, 0,
-    SDLK_LCTRL,
-    SDLK_LSHIFT,
-    SDLK_LALT,
-    SDLK_LGUI,
-    SDLK_RCTRL,
-    SDLK_RSHIFT,
-    SDLK_RALT,
-    SDLK_RGUI,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    SDLK_MODE,
-    SDLK_AUDIONEXT,
-    SDLK_AUDIOPREV,
-    SDLK_AUDIOSTOP,
-    SDLK_AUDIOPLAY,
-    SDLK_AUDIOMUTE,
-    SDLK_MEDIASELECT,
-    SDLK_WWW,
-    SDLK_MAIL,
-    SDLK_CALCULATOR,
-    SDLK_COMPUTER,
-    SDLK_AC_SEARCH,
-    SDLK_AC_HOME,
-    SDLK_AC_BACK,
-    SDLK_AC_FORWARD,
-    SDLK_AC_STOP,
-    SDLK_AC_REFRESH,
-    SDLK_AC_BOOKMARKS,
-    SDLK_BRIGHTNESSDOWN,
-    SDLK_BRIGHTNESSUP,
-    SDLK_DISPLAYSWITCH,
-    SDLK_KBDILLUMTOGGLE,
-    SDLK_KBDILLUMDOWN,
-    SDLK_KBDILLUMUP,
-    SDLK_EJECT,
-    SDLK_SLEEP,
-    SDLK_APP1,
-    SDLK_APP2,
-    SDLK_AUDIOREWIND,
-    SDLK_AUDIOFASTFORWARD,
-    SDLK_SOFTLEFT,
-    SDLK_SOFTRIGHT,
-    SDLK_CALL,
-    SDLK_ENDCALL,
+    /* 0 */ 0,
+    /* 1 */ 0,
+    /* 2 */ 0,
+    /* 3 */ 0,
+    /* 4 */ 'a',
+    /* 5 */ 'b',
+    /* 6 */ 'c',
+    /* 7 */ 'd',
+    /* 8 */ 'e',
+    /* 9 */ 'f',
+    /* 10 */ 'g',
+    /* 11 */ 'h',
+    /* 12 */ 'i',
+    /* 13 */ 'j',
+    /* 14 */ 'k',
+    /* 15 */ 'l',
+    /* 16 */ 'm',
+    /* 17 */ 'n',
+    /* 18 */ 'o',
+    /* 19 */ 'p',
+    /* 20 */ 'q',
+    /* 21 */ 'r',
+    /* 22 */ 's',
+    /* 23 */ 't',
+    /* 24 */ 'u',
+    /* 25 */ 'v',
+    /* 26 */ 'w',
+    /* 27 */ 'x',
+    /* 28 */ 'y',
+    /* 29 */ 'z',
+    /* 30 */ '1',
+    /* 31 */ '2',
+    /* 32 */ '3',
+    /* 33 */ '4',
+    /* 34 */ '5',
+    /* 35 */ '6',
+    /* 36 */ '7',
+    /* 37 */ '8',
+    /* 38 */ '9',
+    /* 39 */ '0',
+    /* 40 */ SDLK_RETURN,
+    /* 41 */ SDLK_ESCAPE,
+    /* 42 */ SDLK_BACKSPACE,
+    /* 43 */ SDLK_TAB,
+    /* 44 */ SDLK_SPACE,
+    /* 45 */ '-',
+    /* 46 */ '=',
+    /* 47 */ '[',
+    /* 48 */ ']',
+    /* 49 */ '\\',
+    /* 50 */ '#',
+    /* 51 */ ';',
+    /* 52 */ '\'',
+    /* 53 */ '`',
+    /* 54 */ ',',
+    /* 55 */ '.',
+    /* 56 */ '/',
+    /* 57 */ SDLK_CAPSLOCK,
+    /* 58 */ SDLK_F1,
+    /* 59 */ SDLK_F2,
+    /* 60 */ SDLK_F3,
+    /* 61 */ SDLK_F4,
+    /* 62 */ SDLK_F5,
+    /* 63 */ SDLK_F6,
+    /* 64 */ SDLK_F7,
+    /* 65 */ SDLK_F8,
+    /* 66 */ SDLK_F9,
+    /* 67 */ SDLK_F10,
+    /* 68 */ SDLK_F11,
+    /* 69 */ SDLK_F12,
+    /* 70 */ SDLK_PRINTSCREEN,
+    /* 71 */ SDLK_SCROLLLOCK,
+    /* 72 */ SDLK_PAUSE,
+    /* 73 */ SDLK_INSERT,
+    /* 74 */ SDLK_HOME,
+    /* 75 */ SDLK_PAGEUP,
+    /* 76 */ SDLK_DELETE,
+    /* 77 */ SDLK_END,
+    /* 78 */ SDLK_PAGEDOWN,
+    /* 79 */ SDLK_RIGHT,
+    /* 80 */ SDLK_LEFT,
+    /* 81 */ SDLK_DOWN,
+    /* 82 */ SDLK_UP,
+    /* 83 */ SDLK_NUMLOCKCLEAR,
+    /* 84 */ SDLK_KP_DIVIDE,
+    /* 85 */ SDLK_KP_MULTIPLY,
+    /* 86 */ SDLK_KP_MINUS,
+    /* 87 */ SDLK_KP_PLUS,
+    /* 88 */ SDLK_KP_ENTER,
+    /* 89 */ SDLK_KP_1,
+    /* 90 */ SDLK_KP_2,
+    /* 91 */ SDLK_KP_3,
+    /* 92 */ SDLK_KP_4,
+    /* 93 */ SDLK_KP_5,
+    /* 94 */ SDLK_KP_6,
+    /* 95 */ SDLK_KP_7,
+    /* 96 */ SDLK_KP_8,
+    /* 97 */ SDLK_KP_9,
+    /* 98 */ SDLK_KP_0,
+    /* 99 */ SDLK_KP_PERIOD,
+    /* 100 */ 0,
+    /* 101 */ SDLK_APPLICATION,
+    /* 102 */ SDLK_POWER,
+    /* 103 */ SDLK_KP_EQUALS,
+    /* 104 */ SDLK_F13,
+    /* 105 */ SDLK_F14,
+    /* 106 */ SDLK_F15,
+    /* 107 */ SDLK_F16,
+    /* 108 */ SDLK_F17,
+    /* 109 */ SDLK_F18,
+    /* 110 */ SDLK_F19,
+    /* 111 */ SDLK_F20,
+    /* 112 */ SDLK_F21,
+    /* 113 */ SDLK_F22,
+    /* 114 */ SDLK_F23,
+    /* 115 */ SDLK_F24,
+    /* 116 */ SDLK_EXECUTE,
+    /* 117 */ SDLK_HELP,
+    /* 118 */ SDLK_MENU,
+    /* 119 */ SDLK_SELECT,
+    /* 120 */ SDLK_STOP,
+    /* 121 */ SDLK_AGAIN,
+    /* 122 */ SDLK_UNDO,
+    /* 123 */ SDLK_CUT,
+    /* 124 */ SDLK_COPY,
+    /* 125 */ SDLK_PASTE,
+    /* 126 */ SDLK_FIND,
+    /* 127 */ SDLK_MUTE,
+    /* 128 */ SDLK_VOLUMEUP,
+    /* 129 */ SDLK_VOLUMEDOWN,
+    /* 130 */ 0,
+    /* 131 */ 0,
+    /* 132 */ 0,
+    /* 133 */ SDLK_KP_COMMA,
+    /* 134 */ SDLK_KP_EQUALSAS400,
+    /* 135 */ 0,
+    /* 136 */ 0,
+    /* 137 */ 0,
+    /* 138 */ 0,
+    /* 139 */ 0,
+    /* 140 */ 0,
+    /* 141 */ 0,
+    /* 142 */ 0,
+    /* 143 */ 0,
+    /* 144 */ 0,
+    /* 145 */ 0,
+    /* 146 */ 0,
+    /* 147 */ 0,
+    /* 148 */ 0,
+    /* 149 */ 0,
+    /* 150 */ 0,
+    /* 151 */ 0,
+    /* 152 */ 0,
+    /* 153 */ SDLK_ALTERASE,
+    /* 154 */ SDLK_SYSREQ,
+    /* 155 */ SDLK_CANCEL,
+    /* 156 */ SDLK_CLEAR,
+    /* 157 */ SDLK_PRIOR,
+    /* 158 */ SDLK_RETURN2,
+    /* 159 */ SDLK_SEPARATOR,
+    /* 160 */ SDLK_OUT,
+    /* 161 */ SDLK_OPER,
+    /* 162 */ SDLK_CLEARAGAIN,
+    /* 163 */ SDLK_CRSEL,
+    /* 164 */ SDLK_EXSEL,
+    /* 165 */ 0,
+    /* 166 */ 0,
+    /* 167 */ 0,
+    /* 168 */ 0,
+    /* 169 */ 0,
+    /* 170 */ 0,
+    /* 171 */ 0,
+    /* 172 */ 0,
+    /* 173 */ 0,
+    /* 174 */ 0,
+    /* 175 */ 0,
+    /* 176 */ SDLK_KP_00,
+    /* 177 */ SDLK_KP_000,
+    /* 178 */ SDLK_THOUSANDSSEPARATOR,
+    /* 179 */ SDLK_DECIMALSEPARATOR,
+    /* 180 */ SDLK_CURRENCYUNIT,
+    /* 181 */ SDLK_CURRENCYSUBUNIT,
+    /* 182 */ SDLK_KP_LEFTPAREN,
+    /* 183 */ SDLK_KP_RIGHTPAREN,
+    /* 184 */ SDLK_KP_LEFTBRACE,
+    /* 185 */ SDLK_KP_RIGHTBRACE,
+    /* 186 */ SDLK_KP_TAB,
+    /* 187 */ SDLK_KP_BACKSPACE,
+    /* 188 */ SDLK_KP_A,
+    /* 189 */ SDLK_KP_B,
+    /* 190 */ SDLK_KP_C,
+    /* 191 */ SDLK_KP_D,
+    /* 192 */ SDLK_KP_E,
+    /* 193 */ SDLK_KP_F,
+    /* 194 */ SDLK_KP_XOR,
+    /* 195 */ SDLK_KP_POWER,
+    /* 196 */ SDLK_KP_PERCENT,
+    /* 197 */ SDLK_KP_LESS,
+    /* 198 */ SDLK_KP_GREATER,
+    /* 199 */ SDLK_KP_AMPERSAND,
+    /* 200 */ SDLK_KP_DBLAMPERSAND,
+    /* 201 */ SDLK_KP_VERTICALBAR,
+    /* 202 */ SDLK_KP_DBLVERTICALBAR,
+    /* 203 */ SDLK_KP_COLON,
+    /* 204 */ SDLK_KP_HASH,
+    /* 205 */ SDLK_KP_SPACE,
+    /* 206 */ SDLK_KP_AT,
+    /* 207 */ SDLK_KP_EXCLAM,
+    /* 208 */ SDLK_KP_MEMSTORE,
+    /* 209 */ SDLK_KP_MEMRECALL,
+    /* 210 */ SDLK_KP_MEMCLEAR,
+    /* 211 */ SDLK_KP_MEMADD,
+    /* 212 */ SDLK_KP_MEMSUBTRACT,
+    /* 213 */ SDLK_KP_MEMMULTIPLY,
+    /* 214 */ SDLK_KP_MEMDIVIDE,
+    /* 215 */ SDLK_KP_PLUSMINUS,
+    /* 216 */ SDLK_KP_CLEAR,
+    /* 217 */ SDLK_KP_CLEARENTRY,
+    /* 218 */ SDLK_KP_BINARY,
+    /* 219 */ SDLK_KP_OCTAL,
+    /* 220 */ SDLK_KP_DECIMAL,
+    /* 221 */ SDLK_KP_HEXADECIMAL,
+    /* 222 */ 0,
+    /* 223 */ 0,
+    /* 224 */ SDLK_LCTRL,
+    /* 225 */ SDLK_LSHIFT,
+    /* 226 */ SDLK_LALT,
+    /* 227 */ SDLK_LGUI,
+    /* 228 */ SDLK_RCTRL,
+    /* 229 */ SDLK_RSHIFT,
+    /* 230 */ SDLK_RALT,
+    /* 231 */ SDLK_RGUI,
+    /* 232 */ 0,
+    /* 233 */ 0,
+    /* 234 */ 0,
+    /* 235 */ 0,
+    /* 236 */ 0,
+    /* 237 */ 0,
+    /* 238 */ 0,
+    /* 239 */ 0,
+    /* 240 */ 0,
+    /* 241 */ 0,
+    /* 242 */ 0,
+    /* 243 */ 0,
+    /* 244 */ 0,
+    /* 245 */ 0,
+    /* 246 */ 0,
+    /* 247 */ 0,
+    /* 248 */ 0,
+    /* 249 */ 0,
+    /* 250 */ 0,
+    /* 251 */ 0,
+    /* 252 */ 0,
+    /* 253 */ 0,
+    /* 254 */ 0,
+    /* 255 */ 0,
+    /* 256 */ 0,
+    /* 257 */ SDLK_MODE,
+    /* 258 */ SDLK_AUDIONEXT,
+    /* 259 */ SDLK_AUDIOPREV,
+    /* 260 */ SDLK_AUDIOSTOP,
+    /* 261 */ SDLK_AUDIOPLAY,
+    /* 262 */ SDLK_AUDIOMUTE,
+    /* 263 */ SDLK_MEDIASELECT,
+    /* 264 */ SDLK_WWW,
+    /* 265 */ SDLK_MAIL,
+    /* 266 */ SDLK_CALCULATOR,
+    /* 267 */ SDLK_COMPUTER,
+    /* 268 */ SDLK_AC_SEARCH,
+    /* 269 */ SDLK_AC_HOME,
+    /* 270 */ SDLK_AC_BACK,
+    /* 271 */ SDLK_AC_FORWARD,
+    /* 272 */ SDLK_AC_STOP,
+    /* 273 */ SDLK_AC_REFRESH,
+    /* 274 */ SDLK_AC_BOOKMARKS,
+    /* 275 */ SDLK_BRIGHTNESSDOWN,
+    /* 276 */ SDLK_BRIGHTNESSUP,
+    /* 277 */ SDLK_DISPLAYSWITCH,
+    /* 278 */ SDLK_KBDILLUMTOGGLE,
+    /* 279 */ SDLK_KBDILLUMDOWN,
+    /* 280 */ SDLK_KBDILLUMUP,
+    /* 281 */ SDLK_EJECT,
+    /* 282 */ SDLK_SLEEP,
+    /* 283 */ SDLK_APP1,
+    /* 284 */ SDLK_APP2,
+    /* 285 */ SDLK_AUDIOREWIND,
+    /* 286 */ SDLK_AUDIOFASTFORWARD,
+    /* 287 */ SDLK_SOFTLEFT,
+    /* 288 */ SDLK_SOFTRIGHT,
+    /* 289 */ SDLK_CALL,
+    /* 290 */ SDLK_ENDCALL,
 };
 
 static const char *SDL_scancode_names[SDL_NUM_SCANCODES] = {
-    NULL, NULL, NULL, NULL,
-    "A",
-    "B",
-    "C",
-    "D",
-    "E",
-    "F",
-    "G",
-    "H",
-    "I",
-    "J",
-    "K",
-    "L",
-    "M",
-    "N",
-    "O",
-    "P",
-    "Q",
-    "R",
-    "S",
-    "T",
-    "U",
-    "V",
-    "W",
-    "X",
-    "Y",
-    "Z",
-    "1",
-    "2",
-    "3",
-    "4",
-    "5",
-    "6",
-    "7",
-    "8",
-    "9",
-    "0",
-    "Return",
-    "Escape",
-    "Backspace",
-    "Tab",
-    "Space",
-    "-",
-    "=",
-    "[",
-    "]",
-    "\\",
-    "#",
-    ";",
-    "'",
-    "`",
-    ",",
-    ".",
-    "/",
-    "CapsLock",
-    "F1",
-    "F2",
-    "F3",
-    "F4",
-    "F5",
-    "F6",
-    "F7",
-    "F8",
-    "F9",
-    "F10",
-    "F11",
-    "F12",
-    "PrintScreen",
-    "ScrollLock",
-    "Pause",
-    "Insert",
-    "Home",
-    "PageUp",
-    "Delete",
-    "End",
-    "PageDown",
-    "Right",
-    "Left",
-    "Down",
-    "Up",
-    "Numlock",
-    "Keypad /",
-    "Keypad *",
-    "Keypad -",
-    "Keypad +",
-    "Keypad Enter",
-    "Keypad 1",
-    "Keypad 2",
-    "Keypad 3",
-    "Keypad 4",
-    "Keypad 5",
-    "Keypad 6",
-    "Keypad 7",
-    "Keypad 8",
-    "Keypad 9",
-    "Keypad 0",
-    "Keypad .",
-    NULL,
-    "Application",
-    "Power",
-    "Keypad =",
-    "F13",
-    "F14",
-    "F15",
-    "F16",
-    "F17",
-    "F18",
-    "F19",
-    "F20",
-    "F21",
-    "F22",
-    "F23",
-    "F24",
-    "Execute",
-    "Help",
-    "Menu",
-    "Select",
-    "Stop",
-    "Again",
-    "Undo",
-    "Cut",
-    "Copy",
-    "Paste",
-    "Find",
-    "Mute",
-    "VolumeUp",
-    "VolumeDown",
-    NULL, NULL, NULL,
-    "Keypad ,",
-    "Keypad = (AS400)",
-    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-    NULL, NULL, NULL, NULL, NULL, NULL,
-    "AltErase",
-    "SysReq",
-    "Cancel",
-    "Clear",
-    "Prior",
-    "Return",
-    "Separator",
-    "Out",
-    "Oper",
-    "Clear / Again",
-    "CrSel",
-    "ExSel",
-    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-    "Keypad 00",
-    "Keypad 000",
-    "ThousandsSeparator",
-    "DecimalSeparator",
-    "CurrencyUnit",
-    "CurrencySubUnit",
-    "Keypad (",
-    "Keypad )",
-    "Keypad {",
-    "Keypad }",
-    "Keypad Tab",
-    "Keypad Backspace",
-    "Keypad A",
-    "Keypad B",
-    "Keypad C",
-    "Keypad D",
-    "Keypad E",
-    "Keypad F",
-    "Keypad XOR",
-    "Keypad ^",
-    "Keypad %",
-    "Keypad <",
-    "Keypad >",
-    "Keypad &",
-    "Keypad &&",
-    "Keypad |",
-    "Keypad ||",
-    "Keypad :",
-    "Keypad #",
-    "Keypad Space",
-    "Keypad @",
-    "Keypad !",
-    "Keypad MemStore",
-    "Keypad MemRecall",
-    "Keypad MemClear",
-    "Keypad MemAdd",
-    "Keypad MemSubtract",
-    "Keypad MemMultiply",
-    "Keypad MemDivide",
-    "Keypad +/-",
-    "Keypad Clear",
-    "Keypad ClearEntry",
-    "Keypad Binary",
-    "Keypad Octal",
-    "Keypad Decimal",
-    "Keypad Hexadecimal",
-    NULL, NULL,
-    "Left Ctrl",
-    "Left Shift",
-    "Left Alt",
-    "Left GUI",
-    "Right Ctrl",
-    "Right Shift",
-    "Right Alt",
-    "Right GUI",
-    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-    NULL,
-    "ModeSwitch",
-    "AudioNext",
-    "AudioPrev",
-    "AudioStop",
-    "AudioPlay",
-    "AudioMute",
-    "MediaSelect",
-    "WWW",
-    "Mail",
-    "Calculator",
-    "Computer",
-    "AC Search",
-    "AC Home",
-    "AC Back",
-    "AC Forward",
-    "AC Stop",
-    "AC Refresh",
-    "AC Bookmarks",
-    "BrightnessDown",
-    "BrightnessUp",
-    "DisplaySwitch",
-    "KBDIllumToggle",
-    "KBDIllumDown",
-    "KBDIllumUp",
-    "Eject",
-    "Sleep",
-    "App1",
-    "App2",
-    "AudioRewind",
-    "AudioFastForward",
-    "SoftLeft",
-    "SoftRight",
-    "Call",
-    "EndCall",
+    /* 0 */ NULL,
+    /* 1 */ NULL,
+    /* 2 */ NULL,
+    /* 3 */ NULL,
+    /* 4 */ "A",
+    /* 5 */ "B",
+    /* 6 */ "C",
+    /* 7 */ "D",
+    /* 8 */ "E",
+    /* 9 */ "F",
+    /* 10 */ "G",
+    /* 11 */ "H",
+    /* 12 */ "I",
+    /* 13 */ "J",
+    /* 14 */ "K",
+    /* 15 */ "L",
+    /* 16 */ "M",
+    /* 17 */ "N",
+    /* 18 */ "O",
+    /* 19 */ "P",
+    /* 20 */ "Q",
+    /* 21 */ "R",
+    /* 22 */ "S",
+    /* 23 */ "T",
+    /* 24 */ "U",
+    /* 25 */ "V",
+    /* 26 */ "W",
+    /* 27 */ "X",
+    /* 28 */ "Y",
+    /* 29 */ "Z",
+    /* 30 */ "1",
+    /* 31 */ "2",
+    /* 32 */ "3",
+    /* 33 */ "4",
+    /* 34 */ "5",
+    /* 35 */ "6",
+    /* 36 */ "7",
+    /* 37 */ "8",
+    /* 38 */ "9",
+    /* 39 */ "0",
+    /* 40 */ "Return",
+    /* 41 */ "Escape",
+    /* 42 */ "Backspace",
+    /* 43 */ "Tab",
+    /* 44 */ "Space",
+    /* 45 */ "-",
+    /* 46 */ "=",
+    /* 47 */ "[",
+    /* 48 */ "]",
+    /* 49 */ "\\",
+    /* 50 */ "#",
+    /* 51 */ ";",
+    /* 52 */ "'",
+    /* 53 */ "`",
+    /* 54 */ ",",
+    /* 55 */ ".",
+    /* 56 */ "/",
+    /* 57 */ "CapsLock",
+    /* 58 */ "F1",
+    /* 59 */ "F2",
+    /* 60 */ "F3",
+    /* 61 */ "F4",
+    /* 62 */ "F5",
+    /* 63 */ "F6",
+    /* 64 */ "F7",
+    /* 65 */ "F8",
+    /* 66 */ "F9",
+    /* 67 */ "F10",
+    /* 68 */ "F11",
+    /* 69 */ "F12",
+    /* 70 */ "PrintScreen",
+    /* 71 */ "ScrollLock",
+    /* 72 */ "Pause",
+    /* 73 */ "Insert",
+    /* 74 */ "Home",
+    /* 75 */ "PageUp",
+    /* 76 */ "Delete",
+    /* 77 */ "End",
+    /* 78 */ "PageDown",
+    /* 79 */ "Right",
+    /* 80 */ "Left",
+    /* 81 */ "Down",
+    /* 82 */ "Up",
+    /* 83 */ "Numlock",
+    /* 84 */ "Keypad /",
+    /* 85 */ "Keypad *",
+    /* 86 */ "Keypad -",
+    /* 87 */ "Keypad +",
+    /* 88 */ "Keypad Enter",
+    /* 89 */ "Keypad 1",
+    /* 90 */ "Keypad 2",
+    /* 91 */ "Keypad 3",
+    /* 92 */ "Keypad 4",
+    /* 93 */ "Keypad 5",
+    /* 94 */ "Keypad 6",
+    /* 95 */ "Keypad 7",
+    /* 96 */ "Keypad 8",
+    /* 97 */ "Keypad 9",
+    /* 98 */ "Keypad 0",
+    /* 99 */ "Keypad .",
+    /* 100 */ NULL,
+    /* 101 */ "Application",
+    /* 102 */ "Power",
+    /* 103 */ "Keypad =",
+    /* 104 */ "F13",
+    /* 105 */ "F14",
+    /* 106 */ "F15",
+    /* 107 */ "F16",
+    /* 108 */ "F17",
+    /* 109 */ "F18",
+    /* 110 */ "F19",
+    /* 111 */ "F20",
+    /* 112 */ "F21",
+    /* 113 */ "F22",
+    /* 114 */ "F23",
+    /* 115 */ "F24",
+    /* 116 */ "Execute",
+    /* 117 */ "Help",
+    /* 118 */ "Menu",
+    /* 119 */ "Select",
+    /* 120 */ "Stop",
+    /* 121 */ "Again",
+    /* 122 */ "Undo",
+    /* 123 */ "Cut",
+    /* 124 */ "Copy",
+    /* 125 */ "Paste",
+    /* 126 */ "Find",
+    /* 127 */ "Mute",
+    /* 128 */ "VolumeUp",
+    /* 129 */ "VolumeDown",
+    /* 130 */ NULL,
+    /* 131 */ NULL,
+    /* 132 */ NULL,
+    /* 133 */ "Keypad ,",
+    /* 134 */ "Keypad = (AS400)",
+    /* 135 */ NULL,
+    /* 136 */ NULL,
+    /* 137 */ NULL,
+    /* 138 */ NULL,
+    /* 139 */ NULL,
+    /* 140 */ NULL,
+    /* 141 */ NULL,
+    /* 142 */ NULL,
+    /* 143 */ NULL,
+    /* 144 */ NULL,
+    /* 145 */ NULL,
+    /* 146 */ NULL,
+    /* 147 */ NULL,
+    /* 148 */ NULL,
+    /* 149 */ NULL,
+    /* 150 */ NULL,
+    /* 151 */ NULL,
+    /* 152 */ NULL,
+    /* 153 */ "AltErase",
+    /* 154 */ "SysReq",
+    /* 155 */ "Cancel",
+    /* 156 */ "Clear",
+    /* 157 */ "Prior",
+    /* 158 */ "Return",
+    /* 159 */ "Separator",
+    /* 160 */ "Out",
+    /* 161 */ "Oper",
+    /* 162 */ "Clear / Again",
+    /* 163 */ "CrSel",
+    /* 164 */ "ExSel",
+    /* 165 */ NULL,
+    /* 166 */ NULL,
+    /* 167 */ NULL,
+    /* 168 */ NULL,
+    /* 169 */ NULL,
+    /* 170 */ NULL,
+    /* 171 */ NULL,
+    /* 172 */ NULL,
+    /* 173 */ NULL,
+    /* 174 */ NULL,
+    /* 175 */ NULL,
+    /* 176 */ "Keypad 00",
+    /* 177 */ "Keypad 000",
+    /* 178 */ "ThousandsSeparator",
+    /* 179 */ "DecimalSeparator",
+    /* 180 */ "CurrencyUnit",
+    /* 181 */ "CurrencySubUnit",
+    /* 182 */ "Keypad (",
+    /* 183 */ "Keypad )",
+    /* 184 */ "Keypad {",
+    /* 185 */ "Keypad }",
+    /* 186 */ "Keypad Tab",
+    /* 187 */ "Keypad Backspace",
+    /* 188 */ "Keypad A",
+    /* 189 */ "Keypad B",
+    /* 190 */ "Keypad C",
+    /* 191 */ "Keypad D",
+    /* 192 */ "Keypad E",
+    /* 193 */ "Keypad F",
+    /* 194 */ "Keypad XOR",
+    /* 195 */ "Keypad ^",
+    /* 196 */ "Keypad %",
+    /* 197 */ "Keypad <",
+    /* 198 */ "Keypad >",
+    /* 199 */ "Keypad &",
+    /* 200 */ "Keypad &&",
+    /* 201 */ "Keypad |",
+    /* 202 */ "Keypad ||",
+    /* 203 */ "Keypad :",
+    /* 204 */ "Keypad #",
+    /* 205 */ "Keypad Space",
+    /* 206 */ "Keypad @",
+    /* 207 */ "Keypad !",
+    /* 208 */ "Keypad MemStore",
+    /* 209 */ "Keypad MemRecall",
+    /* 210 */ "Keypad MemClear",
+    /* 211 */ "Keypad MemAdd",
+    /* 212 */ "Keypad MemSubtract",
+    /* 213 */ "Keypad MemMultiply",
+    /* 214 */ "Keypad MemDivide",
+    /* 215 */ "Keypad +/-",
+    /* 216 */ "Keypad Clear",
+    /* 217 */ "Keypad ClearEntry",
+    /* 218 */ "Keypad Binary",
+    /* 219 */ "Keypad Octal",
+    /* 220 */ "Keypad Decimal",
+    /* 221 */ "Keypad Hexadecimal",
+    /* 222 */ NULL,
+    /* 223 */ NULL,
+    /* 224 */ "Left Ctrl",
+    /* 225 */ "Left Shift",
+    /* 226 */ "Left Alt",
+    /* 227 */ "Left GUI",
+    /* 228 */ "Right Ctrl",
+    /* 229 */ "Right Shift",
+    /* 230 */ "Right Alt",
+    /* 231 */ "Right GUI",
+    /* 232 */ NULL,
+    /* 233 */ NULL,
+    /* 234 */ NULL,
+    /* 235 */ NULL,
+    /* 236 */ NULL,
+    /* 237 */ NULL,
+    /* 238 */ NULL,
+    /* 239 */ NULL,
+    /* 240 */ NULL,
+    /* 241 */ NULL,
+    /* 242 */ NULL,
+    /* 243 */ NULL,
+    /* 244 */ NULL,
+    /* 245 */ NULL,
+    /* 246 */ NULL,
+    /* 247 */ NULL,
+    /* 248 */ NULL,
+    /* 249 */ NULL,
+    /* 250 */ NULL,
+    /* 251 */ NULL,
+    /* 252 */ NULL,
+    /* 253 */ NULL,
+    /* 254 */ NULL,
+    /* 255 */ NULL,
+    /* 256 */ NULL,
+    /* 257 */ "ModeSwitch",
+    /* 258 */ "AudioNext",
+    /* 259 */ "AudioPrev",
+    /* 260 */ "AudioStop",
+    /* 261 */ "AudioPlay",
+    /* 262 */ "AudioMute",
+    /* 263 */ "MediaSelect",
+    /* 264 */ "WWW",
+    /* 265 */ "Mail",
+    /* 266 */ "Calculator",
+    /* 267 */ "Computer",
+    /* 268 */ "AC Search",
+    /* 269 */ "AC Home",
+    /* 270 */ "AC Back",
+    /* 271 */ "AC Forward",
+    /* 272 */ "AC Stop",
+    /* 273 */ "AC Refresh",
+    /* 274 */ "AC Bookmarks",
+    /* 275 */ "BrightnessDown",
+    /* 276 */ "BrightnessUp",
+    /* 277 */ "DisplaySwitch",
+    /* 278 */ "KBDIllumToggle",
+    /* 279 */ "KBDIllumDown",
+    /* 280 */ "KBDIllumUp",
+    /* 281 */ "Eject",
+    /* 282 */ "Sleep",
+    /* 283 */ "App1",
+    /* 284 */ "App2",
+    /* 285 */ "AudioRewind",
+    /* 286 */ "AudioFastForward",
+    /* 287 */ "SoftLeft",
+    /* 288 */ "SoftRight",
+    /* 289 */ "Call",
+    /* 290 */ "EndCall",
 };
 
 /* Taken from SDL_iconv() */
diff --git a/src/events/SDL_scancode_tables.c b/src/events/SDL_scancode_tables.c
new file mode 100644
index 000000000000..9c9a55fe8968
--- /dev/null
+++ b/src/events/SDL_scancode_tables.c
@@ -0,0 +1,73 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../SDL_internal.h"
+
+#if SDL_INPUT_LINUXEV || SDL_VIDEO_DRIVER_DIRECTFB || SDL_VIDEO_DRIVER_WAYLAND || SDL_VIDEO_DRIVER_X11
+
+#include "SDL_scancode_tables_c.h"
+
+#include "scancodes_darwin.h"
+#include "scancodes_linux.h"
+#include "scancodes_xfree86.h"
+
+static const struct
+{
+    SDL_ScancodeTable table;
+    SDL_Scancode const *scancodes;
+    int num_entries;
+} SDL_scancode_tables[] = {
+    { SDL_SCANCODE_TABLE_DARWIN, darwin_scancode_table, SDL_arraysize(darwin_scancode_table) },
+    { SDL_SCANCODE_TABLE_LINUX, linux_scancode_table, SDL_arraysize(linux_scancode_table) },
+    { SDL_SCANCODE_TABLE_XFREE86_1, xfree86_scancode_table, SDL_arraysize(xfree86_scancode_table) },
+    { SDL_SCANCODE_TABLE_XFREE86_2, xfree86_scancode_table2, SDL_arraysize(xfree86_scancode_table2) },
+    { SDL_SCANCODE_TABLE_XVNC, xvnc_scancode_table, SDL_arraysize(xvnc_scancode_table) },
+};
+
+const SDL_Scancode *SDL_GetScancodeTable(SDL_ScancodeTable table, int *num_entries)
+{
+    int i;
+
+    for (i = 0; i < SDL_arraysize(SDL_scancode_tables); ++i) {
+        if (table == SDL_scancode_tables[i].table) {
+            *num_entries = SDL_scancode_tables[i].num_entries;
+            return SDL_scancode_tables[i].scancodes;
+        }
+    }
+
+    *num_entries = 0;
+    return NULL;
+}
+
+SDL_Scancode SDL_GetScancodeFromTable(SDL_ScancodeTable table, int keycode)
+{
+    SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
+    int num_entries;
+    const SDL_Scancode *scancodes = SDL_GetScancodeTable(table, &num_entries);
+
+    if (keycode >= 0 && keycode < num_entries) {
+        scancode = scancodes[keycode];
+    }
+    return scancode;
+}
+
+#endif /* SDL_INPUT_LINUXEV || SDL_VIDEO_DRIVER_DIRECTFB || SDL_VIDEO_DRIVER_WAYLAND || SDL_VIDEO_DRIVER_X11 */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/events/SDL_scancode_tables_c.h b/src/events/SDL_scancode_tables_c.h
new file mode 100644
index 000000000000..c85b8ddcac40
--- /dev/null
+++ b/src/events/SDL_scancode_tables_c.h
@@ -0,0 +1,37 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../SDL_internal.h"
+
+#include "../../include/SDL_scancode.h"
+
+typedef enum
+{
+    SDL_SCANCODE_TABLE_DARWIN,
+    SDL_SCANCODE_TABLE_LINUX,
+    SDL_SCANCODE_TABLE_XFREE86_1,
+    SDL_SCANCODE_TABLE_XFREE86_2,
+    SDL_SCANCODE_TABLE_XVNC,
+} SDL_ScancodeTable;
+
+extern const SDL_Scancode *SDL_GetScancodeTable(SDL_ScancodeTable table, int *num_entries);
+extern SDL_Scancode SDL_GetScancodeFromTable(SDL_ScancodeTable table, int keycode);
+

(Patch may be truncated, please check the link at the top of this post.)