Browse Source

Added the ability to query the keymap for keycodes based on modifier state

Sam Lantinga 10 months ago
parent
commit
679e4471ed

+ 2 - 0
VisualC-GDK/SDL/SDL.vcxproj

@@ -414,6 +414,7 @@
     <ClInclude Include="..\..\src\events\SDL_dropevents_c.h" />
     <ClInclude Include="..\..\src\events\SDL_events_c.h" />
     <ClInclude Include="..\..\src\events\SDL_keyboard_c.h" />
+    <ClInclude Include="..\..\src\events\SDL_keymap_c.h" />
     <ClInclude Include="..\..\src\events\SDL_mouse_c.h" />
     <ClInclude Include="..\..\src\events\SDL_touch_c.h" />
     <ClInclude Include="..\..\src\events\SDL_windowevents_c.h" />
@@ -634,6 +635,7 @@
     <ClCompile Include="..\..\src\events\SDL_dropevents.c" />
     <ClCompile Include="..\..\src\events\SDL_events.c" />
     <ClCompile Include="..\..\src\events\SDL_keyboard.c" />
+    <ClCompile Include="..\..\src\events\SDL_keymap.c" />
     <ClCompile Include="..\..\src\events\SDL_mouse.c" />
     <ClCompile Include="..\..\src\events\SDL_pen.c" />
     <ClCompile Include="..\..\src\events\SDL_quit.c" />

+ 2 - 0
VisualC-GDK/SDL/SDL.vcxproj.filters

@@ -47,6 +47,7 @@
     <ClCompile Include="..\..\src\events\SDL_dropevents.c" />
     <ClCompile Include="..\..\src\events\SDL_events.c" />
     <ClCompile Include="..\..\src\events\SDL_keyboard.c" />
+    <ClCompile Include="..\..\src\events\SDL_keymap.c" />
     <ClCompile Include="..\..\src\events\SDL_mouse.c" />
     <ClCompile Include="..\..\src\events\SDL_pen.c" />
     <ClCompile Include="..\..\src\events\SDL_quit.c" />
@@ -326,6 +327,7 @@
     <ClInclude Include="..\..\src\events\SDL_dropevents_c.h" />
     <ClInclude Include="..\..\src\events\SDL_events_c.h" />
     <ClInclude Include="..\..\src\events\SDL_keyboard_c.h" />
+    <ClInclude Include="..\..\src\events\SDL_keymap_c.h" />
     <ClInclude Include="..\..\src\events\SDL_mouse_c.h" />
     <ClInclude Include="..\..\src\events\SDL_touch_c.h" />
     <ClInclude Include="..\..\src\events\SDL_windowevents_c.h" />

+ 2 - 0
VisualC-WinRT/SDL-UWP.vcxproj

@@ -119,6 +119,7 @@
     <ClInclude Include="..\src\events\SDL_dropevents_c.h" />
     <ClInclude Include="..\src\events\SDL_events_c.h" />
     <ClInclude Include="..\src\events\SDL_keyboard_c.h" />
+    <ClInclude Include="..\src\events\SDL_keymap_c.h" />
     <ClInclude Include="..\src\events\SDL_mouse_c.h" />
     <ClInclude Include="..\src\events\SDL_touch_c.h" />
     <ClInclude Include="..\src\events\SDL_windowevents_c.h" />
@@ -320,6 +321,7 @@
     <ClCompile Include="..\src\events\SDL_dropevents.c" />
     <ClCompile Include="..\src\events\SDL_events.c" />
     <ClCompile Include="..\src\events\SDL_keyboard.c" />
+    <ClCompile Include="..\src\events\SDL_keymap.c" />
     <ClCompile Include="..\src\events\SDL_mouse.c" />
     <ClCompile Include="..\src\events\SDL_pen.c" />
     <ClCompile Include="..\src\events\SDL_quit.c" />

+ 6 - 0
VisualC-WinRT/SDL-UWP.vcxproj.filters

@@ -273,6 +273,9 @@
     <ClInclude Include="..\src\events\SDL_keyboard_c.h">
       <Filter>Source Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\src\events\SDL_keymap_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
     <ClInclude Include="..\src\events\SDL_mouse_c.h">
       <Filter>Source Files</Filter>
     </ClInclude>
@@ -585,6 +588,9 @@
     <ClCompile Include="..\src\events\SDL_keyboard.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\events\SDL_keymap.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
     <ClCompile Include="..\src\events\SDL_mouse.c">
       <Filter>Source Files</Filter>
     </ClCompile>

+ 2 - 0
VisualC/SDL/SDL.vcxproj

@@ -338,6 +338,7 @@
     <ClInclude Include="..\..\src\events\SDL_dropevents_c.h" />
     <ClInclude Include="..\..\src\events\SDL_events_c.h" />
     <ClInclude Include="..\..\src\events\SDL_keyboard_c.h" />
+    <ClInclude Include="..\..\src\events\SDL_keymap_c.h" />
     <ClInclude Include="..\..\src\events\SDL_mouse_c.h" />
     <ClInclude Include="..\..\src\events\SDL_touch_c.h" />
     <ClInclude Include="..\..\src\events\SDL_windowevents_c.h" />
@@ -524,6 +525,7 @@
     <ClCompile Include="..\..\src\events\SDL_dropevents.c" />
     <ClCompile Include="..\..\src\events\SDL_events.c" />
     <ClCompile Include="..\..\src\events\SDL_keyboard.c" />
+    <ClCompile Include="..\..\src\events\SDL_keymap.c" />
     <ClCompile Include="..\..\src\events\SDL_mouse.c" />
     <ClCompile Include="..\..\src\events\SDL_pen.c" />
     <ClCompile Include="..\..\src\events\SDL_quit.c" />

+ 6 - 0
VisualC/SDL/SDL.vcxproj.filters

@@ -507,6 +507,9 @@
     <ClInclude Include="..\..\src\events\SDL_keyboard_c.h">
       <Filter>events</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\events\SDL_keymap_c.h">
+      <Filter>events</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\events\SDL_mouse_c.h">
       <Filter>events</Filter>
     </ClInclude>
@@ -1000,6 +1003,9 @@
     <ClCompile Include="..\..\src\events\SDL_keyboard.c">
       <Filter>events</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\events\SDL_keymap.c">
+      <Filter>events</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\events\SDL_mouse.c">
       <Filter>events</Filter>
     </ClCompile>

+ 8 - 0
Xcode/SDL/SDL.xcodeproj/project.pbxproj

@@ -386,6 +386,8 @@
 		F310138D2C1F2CB700FBE946 /* SDL_getenv_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F310138A2C1F2CB700FBE946 /* SDL_getenv_c.h */; };
 		F310138E2C1F2CB700FBE946 /* SDL_random.c in Sources */ = {isa = PBXBuildFile; fileRef = F310138B2C1F2CB700FBE946 /* SDL_random.c */; };
 		F310138F2C1F2CB700FBE946 /* SDL_sysstdlib.h in Headers */ = {isa = PBXBuildFile; fileRef = F310138C2C1F2CB700FBE946 /* SDL_sysstdlib.h */; };
+		F31013C72C24E98200FBE946 /* SDL_keymap.c in Sources */ = {isa = PBXBuildFile; fileRef = F31013C52C24E98200FBE946 /* SDL_keymap.c */; };
+		F31013C82C24E98200FBE946 /* SDL_keymap_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F31013C62C24E98200FBE946 /* SDL_keymap_c.h */; };
 		F316ABD82B5C3185002EF551 /* SDL_memset.c in Sources */ = {isa = PBXBuildFile; fileRef = F316ABD62B5C3185002EF551 /* SDL_memset.c */; };
 		F316ABD92B5C3185002EF551 /* SDL_memcpy.c in Sources */ = {isa = PBXBuildFile; fileRef = F316ABD72B5C3185002EF551 /* SDL_memcpy.c */; };
 		F316ABDB2B5CA721002EF551 /* SDL_memmove.c in Sources */ = {isa = PBXBuildFile; fileRef = F316ABDA2B5CA721002EF551 /* SDL_memmove.c */; };
@@ -915,6 +917,8 @@
 		F310138A2C1F2CB700FBE946 /* SDL_getenv_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_getenv_c.h; sourceTree = "<group>"; };
 		F310138B2C1F2CB700FBE946 /* SDL_random.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_random.c; sourceTree = "<group>"; };
 		F310138C2C1F2CB700FBE946 /* SDL_sysstdlib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_sysstdlib.h; sourceTree = "<group>"; };
+		F31013C52C24E98200FBE946 /* SDL_keymap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_keymap.c; sourceTree = "<group>"; };
+		F31013C62C24E98200FBE946 /* SDL_keymap_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_keymap_c.h; sourceTree = "<group>"; };
 		F316ABD62B5C3185002EF551 /* SDL_memset.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_memset.c; sourceTree = "<group>"; };
 		F316ABD72B5C3185002EF551 /* SDL_memcpy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_memcpy.c; sourceTree = "<group>"; };
 		F316ABDA2B5CA721002EF551 /* SDL_memmove.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_memmove.c; sourceTree = "<group>"; };
@@ -2183,6 +2187,8 @@
 				A7D8A93523E2514000DCD162 /* SDL_events.c */,
 				A7D8A93D23E2514000DCD162 /* SDL_keyboard_c.h */,
 				A7D8A93823E2514000DCD162 /* SDL_keyboard.c */,
+				F31013C62C24E98200FBE946 /* SDL_keymap_c.h */,
+				F31013C52C24E98200FBE946 /* SDL_keymap.c */,
 				A7D8A92B23E2514000DCD162 /* SDL_mouse_c.h */,
 				A7D8A92A23E2514000DCD162 /* SDL_mouse.c */,
 				63134A232A7902FD0021E9A6 /* SDL_pen_c.h */,
@@ -2422,6 +2428,7 @@
 				F3F7D9392933074E00816151 /* SDL_opengles2_gl2ext.h in Headers */,
 				F3F7D9692933074E00816151 /* SDL_opengles2_gl2platform.h in Headers */,
 				F3F7D9092933074E00816151 /* SDL_opengles2_khrplatform.h in Headers */,
+				F31013C82C24E98200FBE946 /* SDL_keymap_c.h in Headers */,
 				63134A222A7902CF0021E9A6 /* SDL_pen.h in Headers */,
 				63134A252A7902FD0021E9A6 /* SDL_pen_c.h in Headers */,
 				F36C34312C0F876500991150 /* SDL_offscreenvulkan.h in Headers */,
@@ -2675,6 +2682,7 @@
 				A7D8BAC723E2514500DCD162 /* e_pow.c in Sources */,
 				A7D8B41C23E2514300DCD162 /* SDL_systls.c in Sources */,
 				9846B07C287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */,
+				F31013C72C24E98200FBE946 /* SDL_keymap.c in Sources */,
 				A7D8BBD923E2574800DCD162 /* SDL_uikitmessagebox.m in Sources */,
 				F32DDAD42AB795A30041EAA5 /* SDL_audioresample.c in Sources */,
 				F3FA5A212B59ACE000FEAD97 /* yuv_rgb_std.c in Sources */,

+ 2 - 0
docs/README-migration.md

@@ -890,6 +890,8 @@ The following symbols have been removed:
 
 Text input is no longer automatically enabled when initializing video, you should call SDL_StartTextInput() when you want to receive text input and call SDL_StopTextInput() when you are done. Starting text input may shown an input method editor (IME) and cause key up/down events to be skipped, so should only be enabled when the application wants text input.
 
+SDL_GetDefaultKeyFromScancode(), SDL_GetKeyFromScancode(), and SDL_GetScancodeFromKey() take an SDL_Keymod parameter and use that to provide the correct result based on keyboard modifier state.
+
 The following functions have been renamed:
 * SDL_IsScreenKeyboardShown() => SDL_ScreenKeyboardShown()
 * SDL_IsTextInputActive() => SDL_TextInputActive()

+ 3 - 5
include/SDL3/SDL_events.h

@@ -316,8 +316,7 @@ typedef struct SDL_KeyboardEvent
 /**
  * Keyboard text editing event structure (event.edit.*)
  *
- * The `text` is owned by SDL and should be copied if the application wants to
- * hold onto it beyond the scope of handling this event.
+ * The text string follows the SDL_GetStringRule.
  *
  * \since This struct is available since SDL 3.0.0.
  */
@@ -335,8 +334,7 @@ typedef struct SDL_TextEditingEvent
 /**
  * Keyboard text input event structure (event.text.*)
  *
- * The `text` is owned by SDL and should be copied if the application wants to
- * hold onto it beyond the scope of handling this event.
+ * The text string follows the SDL_GetStringRule.
  *
  * This event will never be delivered unless text input is enabled by calling
  * SDL_StartTextInput(). Text input is disabled by default!
@@ -733,7 +731,7 @@ typedef struct SDL_PenButtonEvent
  * An event used to drop text or request a file open by the system
  * (event.drop.*)
  *
- * The `source` and `data` are owned by SDL and should be copied if the application wants to hold onto them beyond the scope of handling this event.
+ * The source and data strings follow the SDL_GetStringRule.
  *
  * \since This struct is available since SDL 3.0.0.
  */

+ 40 - 8
include/SDL3/SDL_keyboard.h

@@ -211,6 +211,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetModState(SDL_Keymod modstate);
  * See SDL_Keycode for details.
  *
  * \param scancode the desired SDL_Scancode to query.
+ * \param modstate the modifier state to use when translating the scancode to a keycode.
  * \returns the SDL_Keycode that corresponds to the given SDL_Scancode.
  *
  * \since This function is available since SDL 3.0.0.
@@ -218,7 +219,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetModState(SDL_Keymod modstate);
  * \sa SDL_GetKeyName
  * \sa SDL_GetScancodeFromKey
  */
-extern SDL_DECLSPEC SDL_Keycode SDLCALL SDL_GetDefaultKeyFromScancode(SDL_Scancode scancode);
+extern SDL_DECLSPEC SDL_Keycode SDLCALL SDL_GetDefaultKeyFromScancode(SDL_Scancode scancode, SDL_Keymod modstate);
 
 /**
  * Get the key code corresponding to the given scancode according to the
@@ -227,35 +228,67 @@ extern SDL_DECLSPEC SDL_Keycode SDLCALL SDL_GetDefaultKeyFromScancode(SDL_Scanco
  * See SDL_Keycode for details.
  *
  * \param scancode the desired SDL_Scancode to query.
+ * \param modstate the modifier state to use when translating the scancode to a keycode.
  * \returns the SDL_Keycode that corresponds to the given SDL_Scancode.
  *
  * \since This function is available since SDL 3.0.0.
  *
+ * \sa SDL_GetDefaultKeyFromScancode
  * \sa SDL_GetKeyName
  * \sa SDL_GetScancodeFromKey
  */
-extern SDL_DECLSPEC SDL_Keycode SDLCALL SDL_GetKeyFromScancode(SDL_Scancode scancode);
+extern SDL_DECLSPEC SDL_Keycode SDLCALL SDL_GetKeyFromScancode(SDL_Scancode scancode, SDL_Keymod modstate);
+
+/**
+ * Get the scancode corresponding to the given key code according to a default en_US keyboard layout.
+ *
+ * Note that there may be multiple scancode+modifier states that can generate this keycode, this will just return the first one found.
+ *
+ * \param key the desired SDL_Keycode to query.
+ * \param modstate a pointer to the modifier state that would be used when the scancode generates this key, may be NULL.
+ * \returns the SDL_Scancode that corresponds to the given SDL_Keycode.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_GetScancodeFromKey
+ * \sa SDL_GetScancodeName
+ */
+extern SDL_DECLSPEC SDL_Scancode SDLCALL SDL_GetDefaultScancodeFromKey(SDL_Keycode key, SDL_Keymod *modstate);
 
 /**
  * Get the scancode corresponding to the given key code according to the
  * current keyboard layout.
  *
- * See SDL_Scancode for details.
+ * Note that there may be multiple scancode+modifier states that can generate this keycode, this will just return the first one found.
  *
  * \param key the desired SDL_Keycode to query.
+ * \param modstate a pointer to the modifier state that would be used when the scancode generates this key, may be NULL.
  * \returns the SDL_Scancode that corresponds to the given SDL_Keycode.
  *
  * \since This function is available since SDL 3.0.0.
  *
+ * \sa SDL_GetDefaultScancodeFromKey
  * \sa SDL_GetKeyFromScancode
  * \sa SDL_GetScancodeName
  */
-extern SDL_DECLSPEC SDL_Scancode SDLCALL SDL_GetScancodeFromKey(SDL_Keycode key);
+extern SDL_DECLSPEC SDL_Scancode SDLCALL SDL_GetScancodeFromKey(SDL_Keycode key, SDL_Keymod *modstate);
 
 /**
- * Get a human-readable name for a scancode.
+ * Set a human-readable name for a scancode.
+ *
+ * \param scancode the desired SDL_Scancode.
+ * \param name the name to use for the scancode, encoded as UTF-8. The string is not copied, so the pointer given to this function must stay valid while SDL is being used.
+ * \returns 0 on success or a negative error code on failure; call
+ *          SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 3.0.0.
  *
- * See SDL_Scancode for details.
+ * \sa SDL_GetScancodeName
+ */
+extern SDL_DECLSPEC int SDLCALL SDL_SetScancodeName(SDL_Scancode scancode, const char *name);
+
+/**
+ * Get a human-readable name for a scancode.
  *
  * The returned string follows the SDL_GetStringRule.
  *
@@ -276,6 +309,7 @@ extern SDL_DECLSPEC SDL_Scancode SDLCALL SDL_GetScancodeFromKey(SDL_Keycode key)
  *
  * \sa SDL_GetScancodeFromKey
  * \sa SDL_GetScancodeFromName
+ * \sa SDL_SetScancodeName
  */
 extern SDL_DECLSPEC const char *SDLCALL SDL_GetScancodeName(SDL_Scancode scancode);
 
@@ -297,8 +331,6 @@ extern SDL_DECLSPEC SDL_Scancode SDLCALL SDL_GetScancodeFromName(const char *nam
 /**
  * Get a human-readable name for a key.
  *
- * See SDL_Scancode and SDL_Keycode for details.
- *
  * The returned string follows the SDL_GetStringRule.
  *
  * \param key the desired SDL_Keycode to query.

+ 31 - 1
include/SDL3/SDL_keycode.h

@@ -88,6 +88,32 @@ typedef Uint32 SDL_Keycode;
 #define SDLK_GREATER    '>'
 #define SDLK_QUESTION   '?'
 #define SDLK_AT '@'
+#define SDLK_A  'A'
+#define SDLK_B  'B'
+#define SDLK_C  'C'
+#define SDLK_D  'D'
+#define SDLK_E  'E'
+#define SDLK_F  'F'
+#define SDLK_G  'G'
+#define SDLK_H  'H'
+#define SDLK_I  'I'
+#define SDLK_J  'J'
+#define SDLK_K  'K'
+#define SDLK_L  'L'
+#define SDLK_M  'M'
+#define SDLK_N  'N'
+#define SDLK_O  'O'
+#define SDLK_P  'P'
+#define SDLK_Q  'Q'
+#define SDLK_R  'R'
+#define SDLK_S  'S'
+#define SDLK_T  'T'
+#define SDLK_U  'U'
+#define SDLK_V  'V'
+#define SDLK_W  'W'
+#define SDLK_X  'X'
+#define SDLK_Y  'Y'
+#define SDLK_Z  'Z'
 #define SDLK_LEFTBRACKET    '['
 #define SDLK_BACKSLASH  '\\'
 #define SDLK_RIGHTBRACKET   ']'
@@ -120,6 +146,11 @@ typedef Uint32 SDL_Keycode;
 #define SDLK_x  'x'
 #define SDLK_y  'y'
 #define SDLK_z  'z'
+#define SDLK_LEFTBRACE  '{'
+#define SDLK_PIPE   '|'
+#define SDLK_RIGHTBRACE '}'
+#define SDLK_TILDE  '~'
+#define SDLK_DELETE '\x7F'
 #define SDLK_CAPSLOCK   SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CAPSLOCK)
 #define SDLK_F1 SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F1)
 #define SDLK_F2 SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F2)
@@ -139,7 +170,6 @@ typedef Uint32 SDL_Keycode;
 #define SDLK_INSERT SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_INSERT)
 #define SDLK_HOME   SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_HOME)
 #define SDLK_PAGEUP SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PAGEUP)
-#define SDLK_DELETE '\x7F'
 #define SDLK_END    SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_END)
 #define SDLK_PAGEDOWN   SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PAGEDOWN)
 #define SDLK_RIGHT  SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RIGHT)

+ 8 - 1
src/SDL_hashtable.c

@@ -241,7 +241,7 @@ SDL_bool SDL_HashTableEmpty(SDL_HashTable *table)
     return SDL_TRUE;
 }
 
-void SDL_DestroyHashTable(SDL_HashTable *table)
+void SDL_EmptyHashTable(SDL_HashTable *table)
 {
     if (table) {
         void *data = table->data;
@@ -257,8 +257,15 @@ void SDL_DestroyHashTable(SDL_HashTable *table)
                 SDL_free(item);
                 item = next;
             }
+            table->table[i] = NULL;
         }
+    }
+}
 
+void SDL_DestroyHashTable(SDL_HashTable *table)
+{
+    if (table) {
+        SDL_EmptyHashTable(table);
         SDL_free(table->table);
         SDL_free(table);
     }

+ 1 - 0
src/SDL_hashtable.h

@@ -36,6 +36,7 @@ SDL_HashTable *SDL_CreateHashTable(void *data,
                                    const SDL_HashTable_NukeFn nukefn,
                                    const SDL_bool stackable);
 
+void SDL_EmptyHashTable(SDL_HashTable *table);
 void SDL_DestroyHashTable(SDL_HashTable *table);
 SDL_bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value);
 SDL_bool SDL_RemoveFromHashTable(SDL_HashTable *table, const void *key);

+ 25 - 0
src/SDL_utils.c

@@ -101,6 +101,31 @@ SDL_bool SDL_endswith(const char *string, const char *suffix)
     return SDL_FALSE;
 }
 
+char *SDL_UCS4ToUTF8(Uint32 ch, char *dst)
+{
+    Uint8 *p = (Uint8 *)dst;
+    if (ch <= 0x7F) {
+        *p = (Uint8)ch;
+        ++dst;
+    } else if (ch <= 0x7FF) {
+        p[0] = 0xC0 | (Uint8)((ch >> 6) & 0x1F);
+        p[1] = 0x80 | (Uint8)(ch & 0x3F);
+        dst += 2;
+    } else if (ch <= 0xFFFF) {
+        p[0] = 0xE0 | (Uint8)((ch >> 12) & 0x0F);
+        p[1] = 0x80 | (Uint8)((ch >> 6) & 0x3F);
+        p[2] = 0x80 | (Uint8)(ch & 0x3F);
+        dst += 3;
+    } else {
+        p[0] = 0xF0 | (Uint8)((ch >> 18) & 0x07);
+        p[1] = 0x80 | (Uint8)((ch >> 12) & 0x3F);
+        p[2] = 0x80 | (Uint8)((ch >> 6) & 0x3F);
+        p[3] = 0x80 | (Uint8)(ch & 0x3F);
+        dst += 4;
+    }
+    return dst;
+}
+
 /* Assume we can wrap SDL_AtomicInt values and cast to Uint32 */
 SDL_COMPILE_TIME_ASSERT(sizeof_object_id, sizeof(int) == sizeof(Uint32));
 

+ 2 - 0
src/SDL_utils_c.h

@@ -32,6 +32,8 @@ extern void SDL_CalculateFraction(float x, int *numerator, int *denominator);
 
 extern SDL_bool SDL_endswith(const char *string, const char *suffix);
 
+extern char *SDL_UCS4ToUTF8(Uint32 ch, char *dst);
+
 typedef enum
 {
     SDL_OBJECT_TYPE_UNKNOWN,

+ 2 - 0
src/dynapi/SDL_dynapi.sym

@@ -210,6 +210,7 @@ SDL3_0.0.0 {
     SDL_GetDefaultAssertionHandler;
     SDL_GetDefaultCursor;
     SDL_GetDefaultKeyFromScancode;
+    SDL_GetDefaultScancodeFromKey;
     SDL_GetDesktopDisplayMode;
     SDL_GetDisplayBounds;
     SDL_GetDisplayContentScale;
@@ -732,6 +733,7 @@ SDL3_0.0.0 {
     SDL_SetRenderTarget;
     SDL_SetRenderVSync;
     SDL_SetRenderViewport;
+    SDL_SetScancodeName;
     SDL_SetStringProperty;
     SDL_SetSurfaceAlphaMod;
     SDL_SetSurfaceBlendMode;

+ 2 - 0
src/dynapi/SDL_dynapi_overrides.h

@@ -235,6 +235,7 @@
 #define SDL_GetDefaultAssertionHandler SDL_GetDefaultAssertionHandler_REAL
 #define SDL_GetDefaultCursor SDL_GetDefaultCursor_REAL
 #define SDL_GetDefaultKeyFromScancode SDL_GetDefaultKeyFromScancode_REAL
+#define SDL_GetDefaultScancodeFromKey SDL_GetDefaultScancodeFromKey_REAL
 #define SDL_GetDesktopDisplayMode SDL_GetDesktopDisplayMode_REAL
 #define SDL_GetDisplayBounds SDL_GetDisplayBounds_REAL
 #define SDL_GetDisplayContentScale SDL_GetDisplayContentScale_REAL
@@ -757,6 +758,7 @@
 #define SDL_SetRenderTarget SDL_SetRenderTarget_REAL
 #define SDL_SetRenderVSync SDL_SetRenderVSync_REAL
 #define SDL_SetRenderViewport SDL_SetRenderViewport_REAL
+#define SDL_SetScancodeName SDL_SetScancodeName_REAL
 #define SDL_SetStringProperty SDL_SetStringProperty_REAL
 #define SDL_SetSurfaceAlphaMod SDL_SetSurfaceAlphaMod_REAL
 #define SDL_SetSurfaceBlendMode SDL_SetSurfaceBlendMode_REAL

+ 5 - 3
src/dynapi/SDL_dynapi_procs.h

@@ -254,7 +254,8 @@ SDL_DYNAPI_PROC(int,SDL_GetDayOfYear,(int a, int b, int c),(a,b,c),return)
 SDL_DYNAPI_PROC(int,SDL_GetDaysInMonth,(int a, int b),(a,b),return)
 SDL_DYNAPI_PROC(SDL_AssertionHandler,SDL_GetDefaultAssertionHandler,(void),(),return)
 SDL_DYNAPI_PROC(SDL_Cursor*,SDL_GetDefaultCursor,(void),(),return)
-SDL_DYNAPI_PROC(SDL_Keycode,SDL_GetDefaultKeyFromScancode,(SDL_Scancode a),(a),return)
+SDL_DYNAPI_PROC(SDL_Keycode,SDL_GetDefaultKeyFromScancode,(SDL_Scancode a, SDL_Keymod b),(a,b),return)
+SDL_DYNAPI_PROC(SDL_Scancode,SDL_GetDefaultScancodeFromKey,(SDL_Keycode a, SDL_Keymod *b),(a,b),return)
 SDL_DYNAPI_PROC(const SDL_DisplayMode*,SDL_GetDesktopDisplayMode,(SDL_DisplayID a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetDisplayBounds,(SDL_DisplayID a, SDL_Rect *b),(a,b),return)
 SDL_DYNAPI_PROC(float,SDL_GetDisplayContentScale,(SDL_DisplayID a),(a),return)
@@ -364,7 +365,7 @@ SDL_DYNAPI_PROC(SDL_JoystickType,SDL_GetJoystickType,(SDL_Joystick *a),(a),retur
 SDL_DYNAPI_PROC(Uint16,SDL_GetJoystickVendor,(SDL_Joystick *a),(a),return)
 SDL_DYNAPI_PROC(SDL_JoystickID*,SDL_GetJoysticks,(int *a),(a),return)
 SDL_DYNAPI_PROC(SDL_Keycode,SDL_GetKeyFromName,(const char *a),(a),return)
-SDL_DYNAPI_PROC(SDL_Keycode,SDL_GetKeyFromScancode,(SDL_Scancode a),(a),return)
+SDL_DYNAPI_PROC(SDL_Keycode,SDL_GetKeyFromScancode,(SDL_Scancode a, SDL_Keymod b),(a,b),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetKeyName,(SDL_Keycode a),(a),return)
 SDL_DYNAPI_PROC(SDL_Window*,SDL_GetKeyboardFocus,(void),(),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetKeyboardInstanceName,(SDL_KeyboardID a),(a),return)
@@ -451,7 +452,7 @@ SDL_DYNAPI_PROC(const char *,SDL_GetRendererName,(SDL_Renderer *a),(a),return)
 SDL_DYNAPI_PROC(SDL_PropertiesID,SDL_GetRendererProperties,(SDL_Renderer *a),(a),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetRevision,(void),(),return)
 SDL_DYNAPI_PROC(size_t,SDL_GetSIMDAlignment,(void),(),return)
-SDL_DYNAPI_PROC(SDL_Scancode,SDL_GetScancodeFromKey,(SDL_Keycode a),(a),return)
+SDL_DYNAPI_PROC(SDL_Scancode,SDL_GetScancodeFromKey,(SDL_Keycode a, SDL_Keymod *b),(a,b),return)
 SDL_DYNAPI_PROC(SDL_Scancode,SDL_GetScancodeFromName,(const char *a),(a),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetScancodeName,(SDL_Scancode a),(a),return)
 SDL_DYNAPI_PROC(Uint32,SDL_GetSemaphoreValue,(SDL_Semaphore *a),(a),return)
@@ -767,6 +768,7 @@ SDL_DYNAPI_PROC(int,SDL_SetRenderScale,(SDL_Renderer *a, float b, float c),(a,b,
 SDL_DYNAPI_PROC(int,SDL_SetRenderTarget,(SDL_Renderer *a, SDL_Texture *b),(a,b),return)
 SDL_DYNAPI_PROC(int,SDL_SetRenderVSync,(SDL_Renderer *a, int b),(a,b),return)
 SDL_DYNAPI_PROC(int,SDL_SetRenderViewport,(SDL_Renderer *a, const SDL_Rect *b),(a,b),return)
+SDL_DYNAPI_PROC(int,SDL_SetScancodeName,(SDL_Scancode a, const char *b),(a,b),return)
 SDL_DYNAPI_PROC(int,SDL_SetStringProperty,(SDL_PropertiesID a, const char *b, const char *c),(a,b,c),return)
 SDL_DYNAPI_PROC(int,SDL_SetSurfaceAlphaMod,(SDL_Surface *a, Uint8 b),(a,b),return)
 SDL_DYNAPI_PROC(int,SDL_SetSurfaceBlendMode,(SDL_Surface *a, SDL_BlendMode b),(a,b),return)

+ 24 - 843
src/events/SDL_keyboard.c

@@ -23,8 +23,8 @@
 /* General keyboard handling code for SDL */
 
 #include "SDL_events_c.h"
+#include "SDL_keymap_c.h"
 #include "../video/SDL_sysvideo.h"
-#include "scancodes_ascii.h"
 
 /* #define DEBUG_KEYBOARD */
 
@@ -53,7 +53,7 @@ typedef struct SDL_Keyboard
     SDL_Keymod modstate;
     Uint8 keysource[SDL_NUM_SCANCODES];
     Uint8 keystate[SDL_NUM_SCANCODES];
-    SDL_Keycode keymap[SDL_NUM_SCANCODES];
+    SDL_Keymap *keymap;
     SDL_bool autorelease_pending;
     Uint64 hardware_timestamp;
 } SDL_Keyboard;
@@ -62,625 +62,9 @@ static SDL_Keyboard SDL_keyboard;
 static int SDL_keyboard_count;
 static SDL_KeyboardInstance *SDL_keyboards;
 
-static const SDL_Keycode SDL_default_keymap[SDL_NUM_SCANCODES] = {
-    /* 0 */ SDLK_UNKNOWN,
-    /* 1 */ SDLK_UNKNOWN,
-    /* 2 */ SDLK_UNKNOWN,
-    /* 3 */ SDLK_UNKNOWN,
-    /* 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 */ SDLK_UNKNOWN,
-    /* 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 */ SDLK_UNKNOWN,
-    /* 131 */ SDLK_UNKNOWN,
-    /* 132 */ SDLK_UNKNOWN,
-    /* 133 */ SDLK_KP_COMMA,
-    /* 134 */ SDLK_KP_EQUALSAS400,
-    /* 135 */ SDLK_UNKNOWN,
-    /* 136 */ SDLK_UNKNOWN,
-    /* 137 */ SDLK_UNKNOWN,
-    /* 138 */ SDLK_UNKNOWN,
-    /* 139 */ SDLK_UNKNOWN,
-    /* 140 */ SDLK_UNKNOWN,
-    /* 141 */ SDLK_UNKNOWN,
-    /* 142 */ SDLK_UNKNOWN,
-    /* 143 */ SDLK_UNKNOWN,
-    /* 144 */ SDLK_UNKNOWN,
-    /* 145 */ SDLK_UNKNOWN,
-    /* 146 */ SDLK_UNKNOWN,
-    /* 147 */ SDLK_UNKNOWN,
-    /* 148 */ SDLK_UNKNOWN,
-    /* 149 */ SDLK_UNKNOWN,
-    /* 150 */ SDLK_UNKNOWN,
-    /* 151 */ SDLK_UNKNOWN,
-    /* 152 */ SDLK_UNKNOWN,
-    /* 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 */ SDLK_UNKNOWN,
-    /* 166 */ SDLK_UNKNOWN,
-    /* 167 */ SDLK_UNKNOWN,
-    /* 168 */ SDLK_UNKNOWN,
-    /* 169 */ SDLK_UNKNOWN,
-    /* 170 */ SDLK_UNKNOWN,
-    /* 171 */ SDLK_UNKNOWN,
-    /* 172 */ SDLK_UNKNOWN,
-    /* 173 */ SDLK_UNKNOWN,
-    /* 174 */ SDLK_UNKNOWN,
-    /* 175 */ SDLK_UNKNOWN,
-    /* 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 */ SDLK_UNKNOWN,
-    /* 223 */ SDLK_UNKNOWN,
-    /* 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 */ SDLK_UNKNOWN,
-    /* 233 */ SDLK_UNKNOWN,
-    /* 234 */ SDLK_UNKNOWN,
-    /* 235 */ SDLK_UNKNOWN,
-    /* 236 */ SDLK_UNKNOWN,
-    /* 237 */ SDLK_UNKNOWN,
-    /* 238 */ SDLK_UNKNOWN,
-    /* 239 */ SDLK_UNKNOWN,
-    /* 240 */ SDLK_UNKNOWN,
-    /* 241 */ SDLK_UNKNOWN,
-    /* 242 */ SDLK_UNKNOWN,
-    /* 243 */ SDLK_UNKNOWN,
-    /* 244 */ SDLK_UNKNOWN,
-    /* 245 */ SDLK_UNKNOWN,
-    /* 246 */ SDLK_UNKNOWN,
-    /* 247 */ SDLK_UNKNOWN,
-    /* 248 */ SDLK_UNKNOWN,
-    /* 249 */ SDLK_UNKNOWN,
-    /* 250 */ SDLK_UNKNOWN,
-    /* 251 */ SDLK_UNKNOWN,
-    /* 252 */ SDLK_UNKNOWN,
-    /* 253 */ SDLK_UNKNOWN,
-    /* 254 */ SDLK_UNKNOWN,
-    /* 255 */ SDLK_UNKNOWN,
-    /* 256 */ SDLK_UNKNOWN,
-    /* 257 */ SDLK_MODE,
-    /* 258 */ SDLK_SLEEP,
-    /* 258 */ SDLK_WAKE,
-    /* 260 */ SDLK_CHANNEL_INCREMENT,
-    /* 261 */ SDLK_CHANNEL_DECREMENT,
-    /* 262 */ SDLK_MEDIA_PLAY,
-    /* 263 */ SDLK_MEDIA_PAUSE,
-    /* 264 */ SDLK_MEDIA_RECORD,
-    /* 265 */ SDLK_MEDIA_FAST_FORWARD,
-    /* 266 */ SDLK_MEDIA_REWIND,
-    /* 267 */ SDLK_MEDIA_NEXT_TRACK,
-    /* 268 */ SDLK_MEDIA_PREVIOUS_TRACK,
-    /* 269 */ SDLK_MEDIA_STOP,
-    /* 270 */ SDLK_MEDIA_EJECT,
-    /* 271 */ SDLK_MEDIA_PLAY_PAUSE,
-    /* 272 */ SDLK_MEDIA_SELECT,
-    /* 273 */ SDLK_AC_NEW,
-    /* 274 */ SDLK_AC_OPEN,
-    /* 275 */ SDLK_AC_CLOSE,
-    /* 276 */ SDLK_AC_EXIT,
-    /* 277 */ SDLK_AC_SAVE,
-    /* 278 */ SDLK_AC_PRINT,
-    /* 279 */ SDLK_AC_PROPERTIES,
-    /* 280 */ SDLK_AC_SEARCH,
-    /* 281 */ SDLK_AC_HOME,
-    /* 282 */ SDLK_AC_BACK,
-    /* 283 */ SDLK_AC_FORWARD,
-    /* 284 */ SDLK_AC_STOP,
-    /* 285 */ SDLK_AC_REFRESH,
-    /* 286 */ SDLK_AC_BOOKMARKS,
-    /* 287 */ SDLK_SOFTLEFT,
-    /* 288 */ SDLK_SOFTRIGHT,
-    /* 289 */ SDLK_CALL,
-    /* 290 */ SDLK_ENDCALL,
-};
-
-static const char *SDL_scancode_names[SDL_NUM_SCANCODES] = {
-    /* 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 */ "Sleep",
-    /* 259 */ "Wake",
-    /* 260 */ "ChannelUp",
-    /* 261 */ "ChannelDown",
-    /* 262 */ "MediaPlay",
-    /* 263 */ "MediaPause",
-    /* 264 */ "MediaRecord",
-    /* 265 */ "MediaFastForward",
-    /* 266 */ "MediaRewind",
-    /* 267 */ "MediaTrackNext",
-    /* 268 */ "MediaTrackPrevious",
-    /* 269 */ "MediaStop",
-    /* 270 */ "Eject",
-    /* 271 */ "MediaPlayPause",
-    /* 272 */ "MediaSelect",
-    /* 273 */ "AC New",
-    /* 274 */ "AC Open",
-    /* 275 */ "AC Close",
-    /* 276 */ "AC Exit",
-    /* 277 */ "AC Save",
-    /* 278 */ "AC Print",
-    /* 279 */ "AC Properties",
-    /* 280 */ "AC Search",
-    /* 281 */ "AC Home",
-    /* 282 */ "AC Back",
-    /* 283 */ "AC Forward",
-    /* 284 */ "AC Stop",
-    /* 285 */ "AC Refresh",
-    /* 286 */ "AC Bookmarks",
-    /* 287 */ "SoftLeft",
-    /* 288 */ "SoftRight",
-    /* 289 */ "Call",
-    /* 290 */ "EndCall",
-};
-
-/* Taken from SDL_iconv() */
-char *SDL_UCS4ToUTF8(Uint32 ch, char *dst)
-{
-    Uint8 *p = (Uint8 *)dst;
-    if (ch <= 0x7F) {
-        *p = (Uint8)ch;
-        ++dst;
-    } else if (ch <= 0x7FF) {
-        p[0] = 0xC0 | (Uint8)((ch >> 6) & 0x1F);
-        p[1] = 0x80 | (Uint8)(ch & 0x3F);
-        dst += 2;
-    } else if (ch <= 0xFFFF) {
-        p[0] = 0xE0 | (Uint8)((ch >> 12) & 0x0F);
-        p[1] = 0x80 | (Uint8)((ch >> 6) & 0x3F);
-        p[2] = 0x80 | (Uint8)(ch & 0x3F);
-        dst += 3;
-    } else {
-        p[0] = 0xF0 | (Uint8)((ch >> 18) & 0x07);
-        p[1] = 0x80 | (Uint8)((ch >> 12) & 0x3F);
-        p[2] = 0x80 | (Uint8)((ch >> 6) & 0x3F);
-        p[3] = 0x80 | (Uint8)(ch & 0x3F);
-        dst += 4;
-    }
-    return dst;
-}
-
 /* Public functions */
 int SDL_InitKeyboard(void)
 {
-    /* Set the default keymap */
-    SDL_SetKeymap(0, SDL_default_keymap, SDL_NUM_SCANCODES, SDL_FALSE);
     return 0;
 }
 
@@ -811,73 +195,21 @@ void SDL_ResetKeyboard(void)
     }
 }
 
-void SDL_GetDefaultKeymap(SDL_Keycode *keymap)
-{
-    SDL_memcpy(keymap, SDL_default_keymap, sizeof(SDL_default_keymap));
-}
-
-void SDL_SetKeymap(int start, const SDL_Keycode *keys, int length, SDL_bool send_event)
+void SDL_SetKeymap(SDL_Keymap *keymap, SDL_bool send_event)
 {
     SDL_Keyboard *keyboard = &SDL_keyboard;
-    SDL_Scancode scancode;
-    SDL_Keycode normalized_keymap[SDL_NUM_SCANCODES];
-    SDL_bool is_azerty = SDL_FALSE;
-
-    if (start < 0 || start + length > SDL_NUM_SCANCODES) {
-        return;
-    }
 
-    if (start > 0) {
-        SDL_memcpy(&normalized_keymap[0], &keyboard->keymap[0], sizeof(*keys) * start);
+    if (keyboard->keymap) {
+        SDL_DestroyKeymap(keyboard->keymap);
     }
 
-    SDL_memcpy(&normalized_keymap[start], keys, sizeof(*keys) * length);
-
-    if (start + length < SDL_NUM_SCANCODES) {
-        int offset = start + length;
-        SDL_memcpy(&normalized_keymap[offset], &keyboard->keymap[offset], sizeof(*keys) * (SDL_NUM_SCANCODES - offset));
-    }
-
-    /* On AZERTY layouts the number keys are technically symbols, but users (and games)
-     * always think of them and view them in UI as number keys, so remap them here.
-     */
-    if (normalized_keymap[SDL_SCANCODE_0] < SDLK_0 || normalized_keymap[SDL_SCANCODE_0] > SDLK_9) {
-        is_azerty = SDL_TRUE;
-        for (scancode = SDL_SCANCODE_1; scancode <= SDL_SCANCODE_9; ++scancode) {
-            if (normalized_keymap[scancode] >= SDLK_0 && normalized_keymap[scancode] <= SDLK_9) {
-                /* There's a number on this row, it's not AZERTY */
-                is_azerty = SDL_FALSE;
-                break;
-            }
-        }
-    }
-    if (is_azerty) {
-        normalized_keymap[SDL_SCANCODE_0] = SDLK_0;
-        for (scancode = SDL_SCANCODE_1; scancode <= SDL_SCANCODE_9; ++scancode) {
-            normalized_keymap[scancode] = SDLK_1 + (scancode - SDL_SCANCODE_1);
-        }
-    }
-
-    /* If the mapping didn't really change, we're done here */
-    if (!SDL_memcmp(&keyboard->keymap[start], &normalized_keymap[start], sizeof(*keys) * length)) {
-        return;
-    }
-
-    SDL_memcpy(&keyboard->keymap[start], &normalized_keymap[start], sizeof(*keys) * length);
+    keyboard->keymap = keymap;
 
     if (send_event) {
         SDL_SendKeymapChangedEvent();
     }
 }
 
-void SDL_SetScancodeName(SDL_Scancode scancode, const char *name)
-{
-    if (scancode >= SDL_NUM_SCANCODES) {
-        return;
-    }
-    SDL_scancode_names[scancode] = name;
-}
-
 SDL_Window *SDL_GetKeyboardFocus(void)
 {
     SDL_Keyboard *keyboard = &SDL_keyboard;
@@ -993,7 +325,7 @@ static int SDL_SendKeyboardKeyInternal(Uint64 timestamp, Uint32 flags, SDL_Keybo
         keyboard->keystate[scancode] = state;
 
         if (keycode == SDLK_UNKNOWN) {
-            keycode = keyboard->keymap[scancode];
+            keycode = SDL_GetKeyFromScancode(scancode, SDL_KMOD_NONE);
         }
 
     } else if (keycode == SDLK_UNKNOWN && rawcode == 0) {
@@ -1098,26 +430,22 @@ static int SDL_SendKeyboardKeyInternal(Uint64 timestamp, Uint32 flags, SDL_Keybo
 
 int SDL_SendKeyboardUnicodeKey(Uint64 timestamp, Uint32 ch)
 {
-    SDL_Scancode code = SDL_SCANCODE_UNKNOWN;
-    uint16_t mod = 0;
+    SDL_Keymod modstate = SDL_KMOD_NONE;
+    SDL_Scancode scancode = SDL_GetDefaultScancodeFromKey(ch, &modstate);
 
-    if (ch < SDL_arraysize(SDL_ASCIIKeyInfoTable)) {
-        code = SDL_ASCIIKeyInfoTable[ch].code;
-        mod = SDL_ASCIIKeyInfoTable[ch].mod;
-    }
 
-    if (mod & SDL_KMOD_SHIFT) {
+    if (modstate & SDL_KMOD_SHIFT) {
         /* If the character uses shift, press shift down */
-        SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, SDL_SCANCODE_LSHIFT, SDLK_UNKNOWN, SDL_PRESSED);
+        SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, SDL_SCANCODE_LSHIFT, SDLK_LSHIFT, SDL_PRESSED);
     }
 
     /* Send a keydown and keyup for the character */
-    SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, code, SDLK_UNKNOWN, SDL_PRESSED);
-    SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, code, SDLK_UNKNOWN, SDL_RELEASED);
+    SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, scancode, ch, SDL_PRESSED);
+    SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, scancode, ch, SDL_RELEASED);
 
-    if (mod & SDL_KMOD_SHIFT) {
+    if (modstate & SDL_KMOD_SHIFT) {
         /* If the character uses shift, release shift */
-        SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, SDL_SCANCODE_LSHIFT, SDLK_UNKNOWN, SDL_RELEASED);
+        SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, SDL_SCANCODE_LSHIFT, SDLK_LSHIFT, SDL_RELEASED);
     }
     return 0;
 }
@@ -1256,6 +584,11 @@ void SDL_QuitKeyboard(void)
     }
     SDL_free(SDL_keyboards);
     SDL_keyboards = NULL;
+
+    if (SDL_keyboard.keymap) {
+        SDL_DestroyKeymap(SDL_keyboard.keymap);
+        SDL_keyboard.keymap = NULL;
+    }
 }
 
 const Uint8 *SDL_GetKeyboardState(int *numkeys)
@@ -1293,165 +626,13 @@ void SDL_ToggleModState(const SDL_Keymod modstate, const SDL_bool toggle)
     }
 }
 
-SDL_Keycode SDL_GetKeyFromScancode(SDL_Scancode scancode)
-{
-    SDL_Keyboard *keyboard = &SDL_keyboard;
-
-    if (((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) {
-        SDL_InvalidParamError("scancode");
-        return 0;
-    }
-
-    return keyboard->keymap[scancode];
-}
-
-SDL_Keycode SDL_GetDefaultKeyFromScancode(SDL_Scancode scancode)
-{
-    if (((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) {
-        SDL_InvalidParamError("scancode");
-        return 0;
-    }
-
-    return SDL_default_keymap[scancode];
-}
-
-SDL_Scancode SDL_GetScancodeFromKey(SDL_Keycode key)
+SDL_Keycode SDL_GetKeyFromScancode(SDL_Scancode scancode, SDL_Keymod modstate)
 {
-    SDL_Keyboard *keyboard = &SDL_keyboard;
-    SDL_Scancode scancode;
-
-    for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_NUM_SCANCODES;
-         ++scancode) {
-        if (keyboard->keymap[scancode] == key) {
-            return scancode;
-        }
-    }
-    return SDL_SCANCODE_UNKNOWN;
+    return SDL_GetKeymapKeycode(SDL_keyboard.keymap, scancode, modstate);
 }
 
-// these are static memory, so we don't use SDL_FreeLater on them.
-const char *SDL_GetScancodeName(SDL_Scancode scancode)
+SDL_Scancode SDL_GetScancodeFromKey(SDL_Keycode key, SDL_Keymod *modstate)
 {
-    const char *name;
-    if (((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) {
-        SDL_InvalidParamError("scancode");
-        return "";
-    }
-
-    name = SDL_scancode_names[scancode];
-    if (name) {
-        return name;
-    }
-
-    return "";
+    return SDL_GetKeymapScancode(SDL_keyboard.keymap, key, modstate);
 }
 
-SDL_Scancode SDL_GetScancodeFromName(const char *name)
-{
-    int i;
-
-    if (!name || !*name) {
-        SDL_InvalidParamError("name");
-        return SDL_SCANCODE_UNKNOWN;
-    }
-
-    for (i = 0; i < SDL_arraysize(SDL_scancode_names); ++i) {
-        if (!SDL_scancode_names[i]) {
-            continue;
-        }
-        if (SDL_strcasecmp(name, SDL_scancode_names[i]) == 0) {
-            return (SDL_Scancode)i;
-        }
-    }
-
-    SDL_InvalidParamError("name");
-    return SDL_SCANCODE_UNKNOWN;
-}
-
-const char *SDL_GetKeyName(SDL_Keycode key)
-{
-    char name[8];
-    char *end;
-
-    if (key & SDLK_SCANCODE_MASK) {
-        return SDL_GetScancodeName((SDL_Scancode)(key & ~SDLK_SCANCODE_MASK));
-    }
-
-    switch (key) {
-    case SDLK_RETURN:
-        return SDL_GetScancodeName(SDL_SCANCODE_RETURN);
-    case SDLK_ESCAPE:
-        return SDL_GetScancodeName(SDL_SCANCODE_ESCAPE);
-    case SDLK_BACKSPACE:
-        return SDL_GetScancodeName(SDL_SCANCODE_BACKSPACE);
-    case SDLK_TAB:
-        return SDL_GetScancodeName(SDL_SCANCODE_TAB);
-    case SDLK_SPACE:
-        return SDL_GetScancodeName(SDL_SCANCODE_SPACE);
-    case SDLK_DELETE:
-        return SDL_GetScancodeName(SDL_SCANCODE_DELETE);
-    default:
-        /* Unaccented letter keys on latin keyboards are normally
-           labeled in upper case (and probably on others like Greek or
-           Cyrillic too, so if you happen to know for sure, please
-           adapt this). */
-        if (key >= 'a' && key <= 'z') {
-            key -= 32;
-        }
-
-        end = SDL_UCS4ToUTF8((Uint32)key, name);
-        *end = '\0';
-        return SDL_FreeLater(SDL_strdup(name));
-    }
-}
-
-SDL_Keycode SDL_GetKeyFromName(const char *name)
-{
-    SDL_Keycode key;
-
-    /* Check input */
-    if (!name) {
-        return SDLK_UNKNOWN;
-    }
-
-    /* If it's a single UTF-8 character, then that's the keycode itself */
-    key = *(const unsigned char *)name;
-    if (key >= 0xF0) {
-        if (SDL_strlen(name) == 4) {
-            int i = 0;
-            key = (Uint16)(name[i] & 0x07) << 18;
-            key |= (Uint16)(name[++i] & 0x3F) << 12;
-            key |= (Uint16)(name[++i] & 0x3F) << 6;
-            key |= (Uint16)(name[++i] & 0x3F);
-            return key;
-        }
-        return SDLK_UNKNOWN;
-    } else if (key >= 0xE0) {
-        if (SDL_strlen(name) == 3) {
-            int i = 0;
-            key = (Uint16)(name[i] & 0x0F) << 12;
-            key |= (Uint16)(name[++i] & 0x3F) << 6;
-            key |= (Uint16)(name[++i] & 0x3F);
-            return key;
-        }
-        return SDLK_UNKNOWN;
-    } else if (key >= 0xC0) {
-        if (SDL_strlen(name) == 2) {
-            int i = 0;
-            key = (Uint16)(name[i] & 0x1F) << 6;
-            key |= (Uint16)(name[++i] & 0x3F);
-            return key;
-        }
-        return SDLK_UNKNOWN;
-    } else {
-        if (SDL_strlen(name) == 1) {
-            if (key >= 'A' && key <= 'Z') {
-                key += 32;
-            }
-            return key;
-        }
-
-        /* Get the scancode for this name, and the associated keycode */
-        return SDL_default_keymap[SDL_GetScancodeFromName(name)];
-    }
-}

+ 3 - 16
src/events/SDL_keyboard_c.h

@@ -23,6 +23,8 @@
 #ifndef SDL_keyboard_c_h_
 #define SDL_keyboard_c_h_
 
+#include "SDL_keymap_c.h"
+
 /* Keyboard events not associated with a specific input device */
 #define SDL_GLOBAL_KEYBOARD_ID     0
 
@@ -41,20 +43,8 @@ extern void SDL_AddKeyboard(SDL_KeyboardID keyboardID, const char *name, SDL_boo
 /* A keyboard has been removed from the system */
 extern void SDL_RemoveKeyboard(SDL_KeyboardID keyboardID, SDL_bool send_event);
 
-/* Get the default keymap */
-extern void SDL_GetDefaultKeymap(SDL_Keycode *keymap);
-
-/* Get the default key code for a scancode */
-extern SDL_Keycode SDL_GetDefaultKeyFromScancode(SDL_Scancode scancode);
-
 /* Set the mapping of scancode to key codes */
-extern void SDL_SetKeymap(int start, const SDL_Keycode *keys, int length, SDL_bool send_event);
-
-/* Set a platform-dependent key name, overriding the default platform-agnostic
-   name. Encoded as UTF-8. The string is not copied, thus the pointer given to
-   this function must stay valid forever (or at least until the call to
-   VideoQuit()). */
-extern void SDL_SetScancodeName(SDL_Scancode scancode, const char *name);
+extern void SDL_SetKeymap(SDL_Keymap *keymap, SDL_bool send_event);
 
 /* Set the keyboard focus window */
 extern int SDL_SetKeyboardFocus(SDL_Window *window);
@@ -91,9 +81,6 @@ extern int SDL_SendEditingText(const char *text, int start, int length);
 /* Shutdown the keyboard subsystem */
 extern void SDL_QuitKeyboard(void);
 
-/* Convert to UTF-8 */
-extern char *SDL_UCS4ToUTF8(Uint32 ch, char *dst);
-
 /* Toggle on or off pieces of the keyboard mod state. */
 extern void SDL_ToggleModState(const SDL_Keymod modstate, const SDL_bool toggle);
 

+ 716 - 0
src/events/SDL_keymap.c

@@ -0,0 +1,716 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2024 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 "SDL_keymap_c.h"
+#include "../SDL_hashtable.h"
+
+struct SDL_Keymap
+{
+    SDL_HashTable *scancode_to_keycode;
+    SDL_HashTable *keycode_to_scancode;
+};
+
+SDL_Keymap *SDL_CreateKeymap(void)
+{
+    SDL_Keymap *keymap = (SDL_Keymap *)SDL_malloc(sizeof(*keymap));
+    if (!keymap) {
+        return NULL;
+    }
+
+    keymap->scancode_to_keycode = SDL_CreateHashTable(NULL, 64, SDL_HashID, SDL_KeyMatchID, NULL, SDL_FALSE);
+    keymap->keycode_to_scancode = SDL_CreateHashTable(NULL, 64, SDL_HashID, SDL_KeyMatchID, NULL, SDL_FALSE);
+    if (!keymap->scancode_to_keycode || !keymap->keycode_to_scancode) {
+        SDL_DestroyKeymap(keymap);
+        return NULL;
+    }
+    return keymap;
+}
+
+static SDL_Keymod NormalizeModifierStateForKeymap(SDL_Keymod modstate)
+{
+    // The modifiers that affect the keymap are: SHIFT, CAPS, ALT, and MODE
+    modstate &= (SDL_KMOD_SHIFT | SDL_KMOD_CAPS | SDL_KMOD_ALT | SDL_KMOD_MODE);
+
+    // If either right or left Shift are set, set both in the output
+    if (modstate & SDL_KMOD_SHIFT) {
+        modstate |= SDL_KMOD_SHIFT;
+    }
+
+    // If either right or left Alt are set, set both in the output
+    if (modstate & SDL_KMOD_ALT) {
+        modstate |= SDL_KMOD_ALT;
+    }
+
+    return modstate;
+}
+
+void SDL_SetKeymapEntry(SDL_Keymap *keymap, SDL_Scancode scancode, SDL_Keymod modstate, SDL_Keycode keycode)
+{
+    if (!keymap) {
+        return;
+    }
+
+    if (keycode == SDL_GetDefaultKeyFromScancode(scancode, modstate)) {
+        return;
+    }
+
+    Uint32 key = ((Uint32)NormalizeModifierStateForKeymap(modstate) << 16) | scancode;
+    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);
+}
+
+SDL_Keycode SDL_GetKeymapKeycode(SDL_Keymap *keymap, SDL_Scancode scancode, SDL_Keymod modstate)
+{
+    SDL_Keycode keycode;
+
+    Uint32 key = ((Uint32)NormalizeModifierStateForKeymap(modstate) << 16) | scancode;
+    const void *value;
+    if (keymap && SDL_FindInHashTable(keymap->scancode_to_keycode, (void *)(uintptr_t)key, &value)) {
+        keycode = (SDL_Keycode)(uintptr_t)value;
+    } else {
+        keycode = SDL_GetDefaultKeyFromScancode(scancode, modstate);
+    }
+    return keycode;
+}
+
+SDL_Scancode SDL_GetKeymapScancode(SDL_Keymap *keymap, SDL_Keycode keycode, SDL_Keymod *modstate)
+{
+    SDL_Scancode scancode;
+
+    const void *value;
+    if (keymap && SDL_FindInHashTable(keymap->keycode_to_scancode, (void *)(uintptr_t)keycode, &value)) {
+        scancode = (SDL_Scancode)((uintptr_t)value & 0xFFFF);
+        if (modstate) {
+            *modstate = (SDL_Keymod)((uintptr_t)value >> 16);
+        }
+    } else {
+        scancode = SDL_GetDefaultScancodeFromKey(keycode, modstate);
+    }
+    return scancode;
+}
+
+void SDL_ResetKeymap(SDL_Keymap *keymap)
+{
+    if (keymap) {
+        SDL_EmptyHashTable(keymap->scancode_to_keycode);
+        SDL_EmptyHashTable(keymap->keycode_to_scancode);
+    }
+}
+
+void SDL_DestroyKeymap(SDL_Keymap *keymap)
+{
+    if (keymap) {
+        SDL_DestroyHashTable(keymap->scancode_to_keycode);
+        SDL_DestroyHashTable(keymap->keycode_to_scancode);
+        SDL_free(keymap);
+    }
+}
+
+static const SDL_Keycode normal_default_symbols[] = {
+    SDLK_1,
+    SDLK_2,
+    SDLK_3,
+    SDLK_4,
+    SDLK_5,
+    SDLK_6,
+    SDLK_7,
+    SDLK_8,
+    SDLK_9,
+    SDLK_0,
+    SDLK_RETURN,
+    SDLK_ESCAPE,
+    SDLK_BACKSPACE,
+    SDLK_TAB,
+    SDLK_SPACE,
+    SDLK_MINUS,
+    SDLK_EQUALS,
+    SDLK_LEFTBRACKET,
+    SDLK_RIGHTBRACKET,
+    SDLK_BACKSLASH,
+    SDLK_HASH,
+    SDLK_SEMICOLON,
+    SDLK_APOSTROPHE,
+    SDLK_GRAVE,
+    SDLK_COMMA,
+    SDLK_PERIOD,
+    SDLK_SLASH,
+};
+
+static const SDL_Keycode shifted_default_symbols[] = {
+    SDLK_EXCLAIM,
+    SDLK_AT,
+    SDLK_HASH,
+    SDLK_DOLLAR,
+    SDLK_PERCENT,
+    SDLK_CARET,
+    SDLK_AMPERSAND,
+    SDLK_ASTERISK,
+    SDLK_LEFTPAREN,
+    SDLK_RIGHTPAREN,
+    SDLK_RETURN,
+    SDLK_ESCAPE,
+    SDLK_BACKSPACE,
+    SDLK_TAB,
+    SDLK_SPACE,
+    SDLK_UNDERSCORE,
+    SDLK_PLUS,
+    SDLK_LEFTBRACE,
+    SDLK_RIGHTBRACE,
+    SDLK_PIPE,
+    SDLK_HASH,
+    SDLK_COLON,
+    SDLK_DBLAPOSTROPHE,
+    SDLK_TILDE,
+    SDLK_LESS,
+    SDLK_GREATER,
+    SDLK_QUESTION
+};
+
+SDL_Keycode SDL_GetDefaultKeyFromScancode(SDL_Scancode scancode, SDL_Keymod modstate)
+{
+    if (((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) {
+        SDL_InvalidParamError("scancode");
+        return SDLK_UNKNOWN;
+    }
+
+    if (modstate & SDL_KMOD_MODE) {
+        return SDLK_UNKNOWN;
+    }
+
+    if (scancode < SDL_SCANCODE_A) {
+        return SDLK_UNKNOWN;
+    }
+
+    if (scancode < SDL_SCANCODE_1) {
+        SDL_bool shifted = (modstate & SDL_KMOD_SHIFT) ? SDL_TRUE : SDL_FALSE;
+#ifdef SDL_PLATFORM_APPLE
+        // Apple maps to upper case for either shift or capslock inclusive
+        if (modstate & SDL_KMOD_CAPS) {
+            shifted = SDL_TRUE;
+        }
+#else
+        if (modstate & SDL_KMOD_CAPS) {
+            shifted = !shifted;
+        }
+#endif
+        if (!shifted) {
+            return (SDL_Keycode)('a' + scancode - SDL_SCANCODE_A);
+        } else {
+            return (SDL_Keycode)('A' + scancode - SDL_SCANCODE_A);
+        }
+    }
+
+    if (scancode < SDL_SCANCODE_CAPSLOCK) {
+        SDL_bool shifted = (modstate & SDL_KMOD_SHIFT) ? SDL_TRUE : SDL_FALSE;
+
+        if (!shifted) {
+            return normal_default_symbols[scancode - SDL_SCANCODE_1];
+        } else {
+            return shifted_default_symbols[scancode - SDL_SCANCODE_1];
+        }
+    }
+
+    if (scancode == SDL_SCANCODE_DELETE) {
+        return SDLK_DELETE;
+    }
+
+    return SDL_SCANCODE_TO_KEYCODE(scancode);
+}
+
+SDL_Scancode SDL_GetDefaultScancodeFromKey(SDL_Keycode key, SDL_Keymod *modstate)
+{
+    if (modstate) {
+        *modstate = SDL_KMOD_NONE;
+    }
+
+    if (key == SDLK_UNKNOWN) {
+        return SDL_SCANCODE_UNKNOWN;
+    }
+
+    if (key & SDLK_SCANCODE_MASK) {
+        return (SDL_Scancode)(key & ~SDLK_SCANCODE_MASK);
+    }
+
+    if (key >= SDLK_a && key <= SDLK_z) {
+        return (SDL_Scancode)(SDL_SCANCODE_A + key - SDLK_a);
+    }
+
+    if (key >= SDLK_Z && key <= SDLK_Z) {
+        if (modstate) {
+            *modstate = SDL_KMOD_SHIFT;
+        }
+        return (SDL_Scancode)(SDL_SCANCODE_A + key - SDLK_Z);
+    }
+
+    for (int i = 0; i < SDL_arraysize(normal_default_symbols); ++i) {
+        if (key == normal_default_symbols[i]) {
+            return(SDL_Scancode)(SDL_SCANCODE_1 + i);
+        }
+    }
+
+    for (int i = 0; i < SDL_arraysize(shifted_default_symbols); ++i) {
+        if (key == shifted_default_symbols[i]) {
+            if (modstate) {
+                *modstate = SDL_KMOD_SHIFT;
+            }
+            return(SDL_Scancode)(SDL_SCANCODE_1 + i);
+        }
+    }
+
+    if (key == SDLK_DELETE) {
+        return SDL_SCANCODE_DELETE;
+    }
+
+    return SDL_SCANCODE_UNKNOWN;
+}
+
+static const char *SDL_scancode_names[SDL_NUM_SCANCODES] =
+{
+    /* 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 */ "Sleep",
+    /* 259 */ "Wake",
+    /* 260 */ "ChannelUp",
+    /* 261 */ "ChannelDown",
+    /* 262 */ "MediaPlay",
+    /* 263 */ "MediaPause",
+    /* 264 */ "MediaRecord",
+    /* 265 */ "MediaFastForward",
+    /* 266 */ "MediaRewind",
+    /* 267 */ "MediaTrackNext",
+    /* 268 */ "MediaTrackPrevious",
+    /* 269 */ "MediaStop",
+    /* 270 */ "Eject",
+    /* 271 */ "MediaPlayPause",
+    /* 272 */ "MediaSelect",
+    /* 273 */ "AC New",
+    /* 274 */ "AC Open",
+    /* 275 */ "AC Close",
+    /* 276 */ "AC Exit",
+    /* 277 */ "AC Save",
+    /* 278 */ "AC Print",
+    /* 279 */ "AC Properties",
+    /* 280 */ "AC Search",
+    /* 281 */ "AC Home",
+    /* 282 */ "AC Back",
+    /* 283 */ "AC Forward",
+    /* 284 */ "AC Stop",
+    /* 285 */ "AC Refresh",
+    /* 286 */ "AC Bookmarks",
+    /* 287 */ "SoftLeft",
+    /* 288 */ "SoftRight",
+    /* 289 */ "Call",
+    /* 290 */ "EndCall",
+};
+
+int SDL_SetScancodeName(SDL_Scancode scancode, const char *name)
+{
+    if (((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) {
+        return SDL_InvalidParamError("scancode");
+    }
+
+    SDL_scancode_names[scancode] = name;
+    return 0;
+}
+
+// these are static memory, so we don't use SDL_FreeLater on them.
+const char *SDL_GetScancodeName(SDL_Scancode scancode)
+{
+    const char *name;
+    if (((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) {
+        SDL_InvalidParamError("scancode");
+        return "";
+    }
+
+    name = SDL_scancode_names[scancode];
+    if (name) {
+        return name;
+    }
+
+    return "";
+}
+
+SDL_Scancode SDL_GetScancodeFromName(const char *name)
+{
+    int i;
+
+    if (!name || !*name) {
+        SDL_InvalidParamError("name");
+        return SDL_SCANCODE_UNKNOWN;
+    }
+
+    for (i = 0; i < SDL_arraysize(SDL_scancode_names); ++i) {
+        if (!SDL_scancode_names[i]) {
+            continue;
+        }
+        if (SDL_strcasecmp(name, SDL_scancode_names[i]) == 0) {
+            return (SDL_Scancode)i;
+        }
+    }
+
+    SDL_InvalidParamError("name");
+    return SDL_SCANCODE_UNKNOWN;
+}
+
+const char *SDL_GetKeyName(SDL_Keycode key)
+{
+    char name[8];
+    char *end;
+
+    if (key & SDLK_SCANCODE_MASK) {
+        return SDL_GetScancodeName((SDL_Scancode)(key & ~SDLK_SCANCODE_MASK));
+    }
+
+    switch (key) {
+    case SDLK_RETURN:
+        return SDL_GetScancodeName(SDL_SCANCODE_RETURN);
+    case SDLK_ESCAPE:
+        return SDL_GetScancodeName(SDL_SCANCODE_ESCAPE);
+    case SDLK_BACKSPACE:
+        return SDL_GetScancodeName(SDL_SCANCODE_BACKSPACE);
+    case SDLK_TAB:
+        return SDL_GetScancodeName(SDL_SCANCODE_TAB);
+    case SDLK_SPACE:
+        return SDL_GetScancodeName(SDL_SCANCODE_SPACE);
+    case SDLK_DELETE:
+        return SDL_GetScancodeName(SDL_SCANCODE_DELETE);
+    default:
+        /* Unaccented letter keys on latin keyboards are normally
+           labeled in upper case (and probably on others like Greek or
+           Cyrillic too, so if you happen to know for sure, please
+           adapt this). */
+        if (key >= 'a' && key <= 'z') {
+            key -= 32;
+        }
+
+        end = SDL_UCS4ToUTF8(key, name);
+        *end = '\0';
+        return SDL_FreeLater(SDL_strdup(name));
+    }
+}
+
+SDL_Keycode SDL_GetKeyFromName(const char *name)
+{
+    SDL_Keycode key;
+
+    /* Check input */
+    if (!name) {
+        return SDLK_UNKNOWN;
+    }
+
+    /* If it's a single UTF-8 character, then that's the keycode itself */
+    key = *(const unsigned char *)name;
+    if (key >= 0xF0) {
+        if (SDL_strlen(name) == 4) {
+            int i = 0;
+            key = (Uint16)(name[i] & 0x07) << 18;
+            key |= (Uint16)(name[++i] & 0x3F) << 12;
+            key |= (Uint16)(name[++i] & 0x3F) << 6;
+            key |= (Uint16)(name[++i] & 0x3F);
+            return key;
+        }
+        return SDLK_UNKNOWN;
+    } else if (key >= 0xE0) {
+        if (SDL_strlen(name) == 3) {
+            int i = 0;
+            key = (Uint16)(name[i] & 0x0F) << 12;
+            key |= (Uint16)(name[++i] & 0x3F) << 6;
+            key |= (Uint16)(name[++i] & 0x3F);
+            return key;
+        }
+        return SDLK_UNKNOWN;
+    } else if (key >= 0xC0) {
+        if (SDL_strlen(name) == 2) {
+            int i = 0;
+            key = (Uint16)(name[i] & 0x1F) << 6;
+            key |= (Uint16)(name[++i] & 0x3F);
+            return key;
+        }
+        return SDLK_UNKNOWN;
+    } else {
+        if (SDL_strlen(name) == 1) {
+            if (key >= 'A' && key <= 'Z') {
+                key += 32;
+            }
+            return key;
+        }
+
+        /* Get the scancode for this name, and the associated keycode */
+        return SDL_GetKeyFromScancode(SDL_GetScancodeFromName(name), SDL_KMOD_NONE);
+    }
+}

+ 37 - 0
src/events/SDL_keymap_c.h

@@ -0,0 +1,37 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2024 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"
+
+#ifndef SDL_keymap_c_h_
+#define SDL_keymap_c_h_
+
+#include "../SDL_hashtable.h"
+
+typedef struct SDL_Keymap SDL_Keymap;
+
+SDL_Keymap *SDL_CreateKeymap(void);
+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);
+SDL_Scancode SDL_GetKeymapScancode(SDL_Keymap *keymap, SDL_Keycode keycode, SDL_Keymod *modstate);
+void SDL_ResetKeymap(SDL_Keymap *keymap);
+void SDL_DestroyKeymap(SDL_Keymap *keymap);
+
+#endif /* SDL_keymap_c_h_ */

+ 0 - 165
src/events/scancodes_ascii.h

@@ -1,165 +0,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 1997-2024 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.
-*/
-
-/*
-    This file is used to convert between characters passed in from an ASCII
-    virtual keyboard in US layout and tuples of SDL_Scancode and SDL_keymods.
-
-    For example ASCIIKeyInfoTable['a'] would give you the scan code and keymod
-    for lower case a.
-*/
-
-typedef struct
-{
-    SDL_Scancode code;
-    uint16_t mod;
-} ASCIIKeyInfo;
-
-static ASCIIKeyInfo SDL_ASCIIKeyInfoTable[] = {
-    /*   0 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*   1 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*   2 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*   3 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*   4 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*   5 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*   6 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*   7 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*   8 */ { SDL_SCANCODE_BACKSPACE, 0 },
-    /*   9 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  10 */ { SDL_SCANCODE_RETURN, 0 },
-    /*  11 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  12 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  13 */ { SDL_SCANCODE_RETURN, 0 },
-    /*  14 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  15 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  16 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  17 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  18 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  19 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  20 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  21 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  22 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  23 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  24 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  25 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  26 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  27 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  28 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  29 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  30 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  31 */ { SDL_SCANCODE_UNKNOWN, 0 },
-    /*  32 */ { SDL_SCANCODE_SPACE, 0 },
-    /*  33 */ { SDL_SCANCODE_1, SDL_KMOD_SHIFT },          /* plus shift modifier '!' */
-    /*  34 */ { SDL_SCANCODE_APOSTROPHE, SDL_KMOD_SHIFT }, /* plus shift modifier '"' */
-    /*  35 */ { SDL_SCANCODE_3, SDL_KMOD_SHIFT },          /* plus shift modifier '#' */
-    /*  36 */ { SDL_SCANCODE_4, SDL_KMOD_SHIFT },          /* plus shift modifier '$' */
-    /*  37 */ { SDL_SCANCODE_5, SDL_KMOD_SHIFT },          /* plus shift modifier '%' */
-    /*  38 */ { SDL_SCANCODE_7, SDL_KMOD_SHIFT },          /* plus shift modifier '&' */
-    /*  39 */ { SDL_SCANCODE_APOSTROPHE, 0 },          /* '''                     */
-    /*  40 */ { SDL_SCANCODE_9, SDL_KMOD_SHIFT },          /* plus shift modifier '(' */
-    /*  41 */ { SDL_SCANCODE_0, SDL_KMOD_SHIFT },          /* plus shift modifier ')' */
-    /*  42 */ { SDL_SCANCODE_8, SDL_KMOD_SHIFT },          /* '*'                     */
-    /*  43 */ { SDL_SCANCODE_EQUALS, SDL_KMOD_SHIFT },     /* plus shift modifier '+' */
-    /*  44 */ { SDL_SCANCODE_COMMA, 0 },               /* ','                     */
-    /*  45 */ { SDL_SCANCODE_MINUS, 0 },               /* '-'                     */
-    /*  46 */ { SDL_SCANCODE_PERIOD, 0 },              /* '.'                     */
-    /*  47 */ { SDL_SCANCODE_SLASH, 0 },               /* '/'                     */
-    /*  48 */ { SDL_SCANCODE_0, 0 },
-    /*  49 */ { SDL_SCANCODE_1, 0 },
-    /*  50 */ { SDL_SCANCODE_2, 0 },
-    /*  51 */ { SDL_SCANCODE_3, 0 },
-    /*  52 */ { SDL_SCANCODE_4, 0 },
-    /*  53 */ { SDL_SCANCODE_5, 0 },
-    /*  54 */ { SDL_SCANCODE_6, 0 },
-    /*  55 */ { SDL_SCANCODE_7, 0 },
-    /*  56 */ { SDL_SCANCODE_8, 0 },
-    /*  57 */ { SDL_SCANCODE_9, 0 },
-    /*  58 */ { SDL_SCANCODE_SEMICOLON, SDL_KMOD_SHIFT }, /* plus shift modifier ';' */
-    /*  59 */ { SDL_SCANCODE_SEMICOLON, 0 },
-    /*  60 */ { SDL_SCANCODE_COMMA, SDL_KMOD_SHIFT }, /* plus shift modifier '<' */
-    /*  61 */ { SDL_SCANCODE_EQUALS, 0 },
-    /*  62 */ { SDL_SCANCODE_PERIOD, SDL_KMOD_SHIFT }, /* plus shift modifier '>' */
-    /*  63 */ { SDL_SCANCODE_SLASH, SDL_KMOD_SHIFT },  /* plus shift modifier '?' */
-    /*  64 */ { SDL_SCANCODE_2, SDL_KMOD_SHIFT },      /* plus shift modifier '@' */
-    /*  65 */ { SDL_SCANCODE_A, SDL_KMOD_SHIFT },      /* all the following need shift modifiers */
-    /*  66 */ { SDL_SCANCODE_B, SDL_KMOD_SHIFT },
-    /*  67 */ { SDL_SCANCODE_C, SDL_KMOD_SHIFT },
-    /*  68 */ { SDL_SCANCODE_D, SDL_KMOD_SHIFT },
-    /*  69 */ { SDL_SCANCODE_E, SDL_KMOD_SHIFT },
-    /*  70 */ { SDL_SCANCODE_F, SDL_KMOD_SHIFT },
-    /*  71 */ { SDL_SCANCODE_G, SDL_KMOD_SHIFT },
-    /*  72 */ { SDL_SCANCODE_H, SDL_KMOD_SHIFT },
-    /*  73 */ { SDL_SCANCODE_I, SDL_KMOD_SHIFT },
-    /*  74 */ { SDL_SCANCODE_J, SDL_KMOD_SHIFT },
-    /*  75 */ { SDL_SCANCODE_K, SDL_KMOD_SHIFT },
-    /*  76 */ { SDL_SCANCODE_L, SDL_KMOD_SHIFT },
-    /*  77 */ { SDL_SCANCODE_M, SDL_KMOD_SHIFT },
-    /*  78 */ { SDL_SCANCODE_N, SDL_KMOD_SHIFT },
-    /*  79 */ { SDL_SCANCODE_O, SDL_KMOD_SHIFT },
-    /*  80 */ { SDL_SCANCODE_P, SDL_KMOD_SHIFT },
-    /*  81 */ { SDL_SCANCODE_Q, SDL_KMOD_SHIFT },
-    /*  82 */ { SDL_SCANCODE_R, SDL_KMOD_SHIFT },
-    /*  83 */ { SDL_SCANCODE_S, SDL_KMOD_SHIFT },
-    /*  84 */ { SDL_SCANCODE_T, SDL_KMOD_SHIFT },
-    /*  85 */ { SDL_SCANCODE_U, SDL_KMOD_SHIFT },
-    /*  86 */ { SDL_SCANCODE_V, SDL_KMOD_SHIFT },
-    /*  87 */ { SDL_SCANCODE_W, SDL_KMOD_SHIFT },
-    /*  88 */ { SDL_SCANCODE_X, SDL_KMOD_SHIFT },
-    /*  89 */ { SDL_SCANCODE_Y, SDL_KMOD_SHIFT },
-    /*  90 */ { SDL_SCANCODE_Z, SDL_KMOD_SHIFT },
-    /*  91 */ { SDL_SCANCODE_LEFTBRACKET, 0 },
-    /*  92 */ { SDL_SCANCODE_BACKSLASH, 0 },
-    /*  93 */ { SDL_SCANCODE_RIGHTBRACKET, 0 },
-    /*  94 */ { SDL_SCANCODE_6, SDL_KMOD_SHIFT },     /* plus shift modifier '^' */
-    /*  95 */ { SDL_SCANCODE_MINUS, SDL_KMOD_SHIFT }, /* plus shift modifier '_' */
-    /*  96 */ { SDL_SCANCODE_GRAVE, SDL_KMOD_SHIFT }, /* '`'                     */
-    /*  97 */ { SDL_SCANCODE_A, 0 },
-    /*  98 */ { SDL_SCANCODE_B, 0 },
-    /*  99 */ { SDL_SCANCODE_C, 0 },
-    /* 100 */ { SDL_SCANCODE_D, 0 },
-    /* 101 */ { SDL_SCANCODE_E, 0 },
-    /* 102 */ { SDL_SCANCODE_F, 0 },
-    /* 103 */ { SDL_SCANCODE_G, 0 },
-    /* 104 */ { SDL_SCANCODE_H, 0 },
-    /* 105 */ { SDL_SCANCODE_I, 0 },
-    /* 106 */ { SDL_SCANCODE_J, 0 },
-    /* 107 */ { SDL_SCANCODE_K, 0 },
-    /* 108 */ { SDL_SCANCODE_L, 0 },
-    /* 109 */ { SDL_SCANCODE_M, 0 },
-    /* 110 */ { SDL_SCANCODE_N, 0 },
-    /* 111 */ { SDL_SCANCODE_O, 0 },
-    /* 112 */ { SDL_SCANCODE_P, 0 },
-    /* 113 */ { SDL_SCANCODE_Q, 0 },
-    /* 114 */ { SDL_SCANCODE_R, 0 },
-    /* 115 */ { SDL_SCANCODE_S, 0 },
-    /* 116 */ { SDL_SCANCODE_T, 0 },
-    /* 117 */ { SDL_SCANCODE_U, 0 },
-    /* 118 */ { SDL_SCANCODE_V, 0 },
-    /* 119 */ { SDL_SCANCODE_W, 0 },
-    /* 120 */ { SDL_SCANCODE_X, 0 },
-    /* 121 */ { SDL_SCANCODE_Y, 0 },
-    /* 122 */ { SDL_SCANCODE_Z, 0 },
-    /* 123 */ { SDL_SCANCODE_LEFTBRACKET, SDL_KMOD_SHIFT },  /* plus shift modifier '{' */
-    /* 124 */ { SDL_SCANCODE_BACKSLASH, SDL_KMOD_SHIFT },    /* plus shift modifier '|' */
-    /* 125 */ { SDL_SCANCODE_RIGHTBRACKET, SDL_KMOD_SHIFT }, /* plus shift modifier '}' */
-    /* 126 */ { SDL_SCANCODE_GRAVE, SDL_KMOD_SHIFT },        /* plus shift modifier '~' */
-    /* 127 */ { SDL_SCANCODE_BACKSPACE, SDL_KMOD_SHIFT }
-};

+ 37 - 24
src/video/cocoa/SDL_cocoakeyboard.m

@@ -240,10 +240,7 @@ static void HandleModifiers(SDL_VideoDevice *_this, SDL_Scancode code, unsigned
 static void UpdateKeymap(SDL_CocoaVideoData *data, SDL_bool send_event)
 {
     TISInputSourceRef key_layout;
-    const void *chr_data;
-    int i;
-    SDL_Scancode scancode;
-    SDL_Keycode keymap[SDL_NUM_SCANCODES];
+    UCKeyboardLayout *keyLayoutPtr = NULL;
     CFDataRef uchrDataRef;
 
     /* See if the keymap needs to be updated */
@@ -253,29 +250,45 @@ static void UpdateKeymap(SDL_CocoaVideoData *data, SDL_bool send_event)
     }
     data.key_layout = key_layout;
 
-    SDL_GetDefaultKeymap(keymap);
-
     /* Try Unicode data first */
     uchrDataRef = TISGetInputSourceProperty(key_layout, kTISPropertyUnicodeKeyLayoutData);
     if (uchrDataRef) {
-        chr_data = CFDataGetBytePtr(uchrDataRef);
-    } else {
-        goto cleanup;
+        keyLayoutPtr = (UCKeyboardLayout *)CFDataGetBytePtr(uchrDataRef);
     }
 
-    if (chr_data) {
-        UInt32 keyboard_type = LMGetKbdType();
-        OSStatus err;
+    if (!keyLayoutPtr) {
+        CFRelease(key_layout);
+        return;
+    }
 
-        for (i = 0; i < SDL_arraysize(darwin_scancode_table); i++) {
+    static struct {
+        int flags;
+        SDL_Keymod modstate;
+    } mods[] = {
+        { 0, SDL_KMOD_NONE },
+        { shiftKey, SDL_KMOD_SHIFT },
+        { alphaLock, SDL_KMOD_CAPS },
+        { (shiftKey | alphaLock), (SDL_KMOD_SHIFT | SDL_KMOD_CAPS) },
+        { optionKey, SDL_KMOD_ALT },
+        { (optionKey | shiftKey), (SDL_KMOD_ALT | SDL_KMOD_SHIFT) },
+        { (optionKey | alphaLock), (SDL_KMOD_ALT | SDL_KMOD_CAPS) },
+        { (optionKey | shiftKey | alphaLock), (SDL_KMOD_ALT | SDL_KMOD_SHIFT | SDL_KMOD_CAPS) }
+    };
+
+    UInt32 keyboard_type = LMGetKbdType();
+
+    SDL_Keymap *keymap = SDL_CreateKeymap();
+    for (int m = 0; m < SDL_arraysize(mods); ++m) {
+        for (int i = 0; i < SDL_arraysize(darwin_scancode_table); i++) {
+            OSStatus err;
             UniChar s[8];
             UniCharCount len;
             UInt32 dead_key_state;
 
             /* Make sure this scancode is a valid character scancode */
-            scancode = darwin_scancode_table[i];
+            SDL_Scancode scancode = darwin_scancode_table[i];
             if (scancode == SDL_SCANCODE_UNKNOWN ||
-                (keymap[scancode] & SDLK_SCANCODE_MASK)) {
+                (SDL_GetDefaultKeyFromScancode(scancode, SDL_KMOD_NONE) & SDLK_SCANCODE_MASK)) {
                 continue;
             }
 
@@ -291,9 +304,8 @@ static void UpdateKeymap(SDL_CocoaVideoData *data, SDL_bool send_event)
             }
 
             dead_key_state = 0;
-            err = UCKeyTranslate((UCKeyboardLayout *)chr_data,
-                                 i, kUCKeyActionDown,
-                                 0, keyboard_type,
+            err = UCKeyTranslate(keyLayoutPtr, i, kUCKeyActionDown,
+                                 ((mods[m].flags >> 8) & 0xFF), keyboard_type,
                                  kUCKeyTranslateNoDeadKeysMask,
                                  &dead_key_state, 8, &len, s);
             if (err != noErr) {
@@ -301,15 +313,16 @@ static void UpdateKeymap(SDL_CocoaVideoData *data, SDL_bool send_event)
             }
 
             if (len > 0 && s[0] != 0x10) {
-                keymap[scancode] = s[0];
+                SDL_SetKeymapEntry(keymap, scancode, mods[m].modstate, s[0]);
+            } else {
+                // The default keymap doesn't have any SDL_KMOD_ALT entries, so we don't need to override them
+                if (!(mods[m].modstate & SDL_KMOD_ALT)) {
+                    SDL_SetKeymapEntry(keymap, scancode, mods[m].modstate, SDLK_UNKNOWN);
+                }
             }
         }
-        SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES, send_event);
-        return;
     }
-
-cleanup:
-    CFRelease(key_layout);
+    SDL_SetKeymap(keymap, send_event);
 }
 
 void Cocoa_InitKeyboard(SDL_VideoDevice *_this)

+ 109 - 108
src/video/haiku/SDL_bkeyboard.cc

@@ -39,7 +39,8 @@ extern "C" {
 static SDL_Scancode keymap[KEYMAP_SIZE];
 static int8 keystate[KEYMAP_SIZE];
 
-void HAIKU_InitOSKeymap(void) {
+void HAIKU_InitOSKeymap(void)
+{
         for ( uint i = 0; i < SDL_arraysize(keymap); ++i ) {
             keymap[i] = SDL_SCANCODE_UNKNOWN;
         }
@@ -48,113 +49,113 @@ void HAIKU_InitOSKeymap(void) {
             keystate[i] = SDL_RELEASED;
         }
 
-        keymap[0x01]        = SDL_GetScancodeFromKey(SDLK_ESCAPE);
-        keymap[B_F1_KEY]    = SDL_GetScancodeFromKey(SDLK_F1);
-        keymap[B_F2_KEY]    = SDL_GetScancodeFromKey(SDLK_F2);
-        keymap[B_F3_KEY]    = SDL_GetScancodeFromKey(SDLK_F3);
-        keymap[B_F4_KEY]    = SDL_GetScancodeFromKey(SDLK_F4);
-        keymap[B_F5_KEY]    = SDL_GetScancodeFromKey(SDLK_F5);
-        keymap[B_F6_KEY]    = SDL_GetScancodeFromKey(SDLK_F6);
-        keymap[B_F7_KEY]    = SDL_GetScancodeFromKey(SDLK_F7);
-        keymap[B_F8_KEY]    = SDL_GetScancodeFromKey(SDLK_F8);
-        keymap[B_F9_KEY]    = SDL_GetScancodeFromKey(SDLK_F9);
-        keymap[B_F10_KEY]    = SDL_GetScancodeFromKey(SDLK_F10);
-        keymap[B_F11_KEY]    = SDL_GetScancodeFromKey(SDLK_F11);
-        keymap[B_F12_KEY]    = SDL_GetScancodeFromKey(SDLK_F12);
-        keymap[B_PRINT_KEY]    = SDL_GetScancodeFromKey(SDLK_PRINTSCREEN);
-        keymap[B_SCROLL_KEY]    = SDL_GetScancodeFromKey(SDLK_SCROLLLOCK);
-        keymap[B_PAUSE_KEY]    = SDL_GetScancodeFromKey(SDLK_PAUSE);
-        keymap[0x11]        = SDL_GetScancodeFromKey(SDLK_GRAVE);
-        keymap[0x12]        = SDL_GetScancodeFromKey(SDLK_1);
-        keymap[0x13]        = SDL_GetScancodeFromKey(SDLK_2);
-        keymap[0x14]        = SDL_GetScancodeFromKey(SDLK_3);
-        keymap[0x15]        = SDL_GetScancodeFromKey(SDLK_4);
-        keymap[0x16]        = SDL_GetScancodeFromKey(SDLK_5);
-        keymap[0x17]        = SDL_GetScancodeFromKey(SDLK_6);
-        keymap[0x18]        = SDL_GetScancodeFromKey(SDLK_7);
-        keymap[0x19]        = SDL_GetScancodeFromKey(SDLK_8);
-        keymap[0x1a]        = SDL_GetScancodeFromKey(SDLK_9);
-        keymap[0x1b]        = SDL_GetScancodeFromKey(SDLK_0);
-        keymap[0x1c]        = SDL_GetScancodeFromKey(SDLK_MINUS);
-        keymap[0x1d]        = SDL_GetScancodeFromKey(SDLK_EQUALS);
-        keymap[0x1e]        = SDL_GetScancodeFromKey(SDLK_BACKSPACE);
-        keymap[0x1f]        = SDL_GetScancodeFromKey(SDLK_INSERT);
-        keymap[0x20]        = SDL_GetScancodeFromKey(SDLK_HOME);
-        keymap[0x21]        = SDL_GetScancodeFromKey(SDLK_PAGEUP);
-        keymap[0x22]        = SDL_GetScancodeFromKey(SDLK_NUMLOCKCLEAR);
-        keymap[0x23]        = SDL_GetScancodeFromKey(SDLK_KP_DIVIDE);
-        keymap[0x24]        = SDL_GetScancodeFromKey(SDLK_KP_MULTIPLY);
-        keymap[0x25]        = SDL_GetScancodeFromKey(SDLK_KP_MINUS);
-        keymap[0x26]        = SDL_GetScancodeFromKey(SDLK_TAB);
-        keymap[0x27]        = SDL_GetScancodeFromKey(SDLK_q);
-        keymap[0x28]        = SDL_GetScancodeFromKey(SDLK_w);
-        keymap[0x29]        = SDL_GetScancodeFromKey(SDLK_e);
-        keymap[0x2a]        = SDL_GetScancodeFromKey(SDLK_r);
-        keymap[0x2b]        = SDL_GetScancodeFromKey(SDLK_t);
-        keymap[0x2c]        = SDL_GetScancodeFromKey(SDLK_y);
-        keymap[0x2d]        = SDL_GetScancodeFromKey(SDLK_u);
-        keymap[0x2e]        = SDL_GetScancodeFromKey(SDLK_i);
-        keymap[0x2f]        = SDL_GetScancodeFromKey(SDLK_o);
-        keymap[0x30]        = SDL_GetScancodeFromKey(SDLK_p);
-        keymap[0x31]        = SDL_GetScancodeFromKey(SDLK_LEFTBRACKET);
-        keymap[0x32]        = SDL_GetScancodeFromKey(SDLK_RIGHTBRACKET);
-        keymap[0x33]        = SDL_GetScancodeFromKey(SDLK_BACKSLASH);
-        keymap[0x34]        = SDL_GetScancodeFromKey(SDLK_DELETE);
-        keymap[0x35]        = SDL_GetScancodeFromKey(SDLK_END);
-        keymap[0x36]        = SDL_GetScancodeFromKey(SDLK_PAGEDOWN);
-        keymap[0x37]        = SDL_GetScancodeFromKey(SDLK_KP_7);
-        keymap[0x38]        = SDL_GetScancodeFromKey(SDLK_KP_8);
-        keymap[0x39]        = SDL_GetScancodeFromKey(SDLK_KP_9);
-        keymap[0x3a]        = SDL_GetScancodeFromKey(SDLK_KP_PLUS);
-        keymap[0x3b]        = SDL_GetScancodeFromKey(SDLK_CAPSLOCK);
-        keymap[0x3c]        = SDL_GetScancodeFromKey(SDLK_a);
-        keymap[0x3d]        = SDL_GetScancodeFromKey(SDLK_s);
-        keymap[0x3e]        = SDL_GetScancodeFromKey(SDLK_d);
-        keymap[0x3f]        = SDL_GetScancodeFromKey(SDLK_f);
-        keymap[0x40]        = SDL_GetScancodeFromKey(SDLK_g);
-        keymap[0x41]        = SDL_GetScancodeFromKey(SDLK_h);
-        keymap[0x42]        = SDL_GetScancodeFromKey(SDLK_j);
-        keymap[0x43]        = SDL_GetScancodeFromKey(SDLK_k);
-        keymap[0x44]        = SDL_GetScancodeFromKey(SDLK_l);
-        keymap[0x45]        = SDL_GetScancodeFromKey(SDLK_SEMICOLON);
-        keymap[0x46]        = SDL_GetScancodeFromKey(SDLK_APOSTROPHE);
-        keymap[0x47]        = SDL_GetScancodeFromKey(SDLK_RETURN);
-        keymap[0x48]        = SDL_GetScancodeFromKey(SDLK_KP_4);
-        keymap[0x49]        = SDL_GetScancodeFromKey(SDLK_KP_5);
-        keymap[0x4a]        = SDL_GetScancodeFromKey(SDLK_KP_6);
-        keymap[0x4b]        = SDL_GetScancodeFromKey(SDLK_LSHIFT);
-        keymap[0x4c]        = SDL_GetScancodeFromKey(SDLK_z);
-        keymap[0x4d]        = SDL_GetScancodeFromKey(SDLK_x);
-        keymap[0x4e]        = SDL_GetScancodeFromKey(SDLK_c);
-        keymap[0x4f]        = SDL_GetScancodeFromKey(SDLK_v);
-        keymap[0x50]        = SDL_GetScancodeFromKey(SDLK_b);
-        keymap[0x51]        = SDL_GetScancodeFromKey(SDLK_n);
-        keymap[0x52]        = SDL_GetScancodeFromKey(SDLK_m);
-        keymap[0x53]        = SDL_GetScancodeFromKey(SDLK_COMMA);
-        keymap[0x54]        = SDL_GetScancodeFromKey(SDLK_PERIOD);
-        keymap[0x55]        = SDL_GetScancodeFromKey(SDLK_SLASH);
-        keymap[0x56]        = SDL_GetScancodeFromKey(SDLK_RSHIFT);
-        keymap[0x57]        = SDL_GetScancodeFromKey(SDLK_UP);
-        keymap[0x58]        = SDL_GetScancodeFromKey(SDLK_KP_1);
-        keymap[0x59]        = SDL_GetScancodeFromKey(SDLK_KP_2);
-        keymap[0x5a]        = SDL_GetScancodeFromKey(SDLK_KP_3);
-        keymap[0x5b]        = SDL_GetScancodeFromKey(SDLK_KP_ENTER);
-        keymap[0x5c]        = SDL_GetScancodeFromKey(SDLK_LCTRL);
-        keymap[0x5d]        = SDL_GetScancodeFromKey(SDLK_LALT);
-        keymap[0x5e]        = SDL_GetScancodeFromKey(SDLK_SPACE);
-        keymap[0x5f]        = SDL_GetScancodeFromKey(SDLK_RALT);
-        keymap[0x60]        = SDL_GetScancodeFromKey(SDLK_RCTRL);
-        keymap[0x61]        = SDL_GetScancodeFromKey(SDLK_LEFT);
-        keymap[0x62]        = SDL_GetScancodeFromKey(SDLK_DOWN);
-        keymap[0x63]        = SDL_GetScancodeFromKey(SDLK_RIGHT);
-        keymap[0x64]        = SDL_GetScancodeFromKey(SDLK_KP_0);
-        keymap[0x65]        = SDL_GetScancodeFromKey(SDLK_KP_PERIOD);
-        keymap[0x66]        = SDL_GetScancodeFromKey(SDLK_LGUI);
-        keymap[0x67]        = SDL_GetScancodeFromKey(SDLK_RGUI);
-        keymap[0x68]        = SDL_GetScancodeFromKey(SDLK_MENU);
-        keymap[0x69]        = SDL_GetScancodeFromKey(SDLK_2); /* SDLK_EURO */
-        keymap[0x6a]        = SDL_GetScancodeFromKey(SDLK_KP_EQUALS);
-        keymap[0x6b]        = SDL_GetScancodeFromKey(SDLK_POWER);
+        keymap[0x01]        = SDL_SCANCODE_ESCAPE;
+        keymap[B_F1_KEY]    = SDL_SCANCODE_F1;
+        keymap[B_F2_KEY]    = SDL_SCANCODE_F2;
+        keymap[B_F3_KEY]    = SDL_SCANCODE_F3;
+        keymap[B_F4_KEY]    = SDL_SCANCODE_F4;
+        keymap[B_F5_KEY]    = SDL_SCANCODE_F5;
+        keymap[B_F6_KEY]    = SDL_SCANCODE_F6;
+        keymap[B_F7_KEY]    = SDL_SCANCODE_F7;
+        keymap[B_F8_KEY]    = SDL_SCANCODE_F8;
+        keymap[B_F9_KEY]    = SDL_SCANCODE_F9;
+        keymap[B_F10_KEY]   = SDL_SCANCODE_F10;
+        keymap[B_F11_KEY]   = SDL_SCANCODE_F11;
+        keymap[B_F12_KEY]   = SDL_SCANCODE_F12;
+        keymap[B_PRINT_KEY] = SDL_SCANCODE_PRINTSCREEN;
+        keymap[B_SCROLL_KEY]= SDL_SCANCODE_SCROLLLOCK;
+        keymap[B_PAUSE_KEY] = SDL_SCANCODE_PAUSE;
+        keymap[0x11]        = SDL_SCANCODE_GRAVE;
+        keymap[0x12]        = SDL_SCANCODE_1;
+        keymap[0x13]        = SDL_SCANCODE_2;
+        keymap[0x14]        = SDL_SCANCODE_3;
+        keymap[0x15]        = SDL_SCANCODE_4;
+        keymap[0x16]        = SDL_SCANCODE_5;
+        keymap[0x17]        = SDL_SCANCODE_6;
+        keymap[0x18]        = SDL_SCANCODE_7;
+        keymap[0x19]        = SDL_SCANCODE_8;
+        keymap[0x1a]        = SDL_SCANCODE_9;
+        keymap[0x1b]        = SDL_SCANCODE_0;
+        keymap[0x1c]        = SDL_SCANCODE_MINUS;
+        keymap[0x1d]        = SDL_SCANCODE_EQUALS;
+        keymap[0x1e]        = SDL_SCANCODE_BACKSPACE;
+        keymap[0x1f]        = SDL_SCANCODE_INSERT;
+        keymap[0x20]        = SDL_SCANCODE_HOME;
+        keymap[0x21]        = SDL_SCANCODE_PAGEUP;
+        keymap[0x22]        = SDL_SCANCODE_NUMLOCKCLEAR;
+        keymap[0x23]        = SDL_SCANCODE_KP_DIVIDE;
+        keymap[0x24]        = SDL_SCANCODE_KP_MULTIPLY;
+        keymap[0x25]        = SDL_SCANCODE_KP_MINUS;
+        keymap[0x26]        = SDL_SCANCODE_TAB;
+        keymap[0x27]        = SDL_SCANCODE_Q;
+        keymap[0x28]        = SDL_SCANCODE_W;
+        keymap[0x29]        = SDL_SCANCODE_E;
+        keymap[0x2a]        = SDL_SCANCODE_R;
+        keymap[0x2b]        = SDL_SCANCODE_T;
+        keymap[0x2c]        = SDL_SCANCODE_Y;
+        keymap[0x2d]        = SDL_SCANCODE_U;
+        keymap[0x2e]        = SDL_SCANCODE_I;
+        keymap[0x2f]        = SDL_SCANCODE_O;
+        keymap[0x30]        = SDL_SCANCODE_P;
+        keymap[0x31]        = SDL_SCANCODE_LEFTBRACKET;
+        keymap[0x32]        = SDL_SCANCODE_RIGHTBRACKET;
+        keymap[0x33]        = SDL_SCANCODE_BACKSLASH;
+        keymap[0x34]        = SDL_SCANCODE_DELETE;
+        keymap[0x35]        = SDL_SCANCODE_END;
+        keymap[0x36]        = SDL_SCANCODE_PAGEDOWN;
+        keymap[0x37]        = SDL_SCANCODE_KP_7;
+        keymap[0x38]        = SDL_SCANCODE_KP_8;
+        keymap[0x39]        = SDL_SCANCODE_KP_9;
+        keymap[0x3a]        = SDL_SCANCODE_KP_PLUS;
+        keymap[0x3b]        = SDL_SCANCODE_CAPSLOCK;
+        keymap[0x3c]        = SDL_SCANCODE_A;
+        keymap[0x3d]        = SDL_SCANCODE_S;
+        keymap[0x3e]        = SDL_SCANCODE_D;
+        keymap[0x3f]        = SDL_SCANCODE_F;
+        keymap[0x40]        = SDL_SCANCODE_G;
+        keymap[0x41]        = SDL_SCANCODE_H;
+        keymap[0x42]        = SDL_SCANCODE_J;
+        keymap[0x43]        = SDL_SCANCODE_K;
+        keymap[0x44]        = SDL_SCANCODE_L;
+        keymap[0x45]        = SDL_SCANCODE_SEMICOLON;
+        keymap[0x46]        = SDL_SCANCODE_APOSTROPHE;
+        keymap[0x47]        = SDL_SCANCODE_RETURN;
+        keymap[0x48]        = SDL_SCANCODE_KP_4;
+        keymap[0x49]        = SDL_SCANCODE_KP_5;
+        keymap[0x4a]        = SDL_SCANCODE_KP_6;
+        keymap[0x4b]        = SDL_SCANCODE_LSHIFT;
+        keymap[0x4c]        = SDL_SCANCODE_Z;
+        keymap[0x4d]        = SDL_SCANCODE_X;
+        keymap[0x4e]        = SDL_SCANCODE_C;
+        keymap[0x4f]        = SDL_SCANCODE_V;
+        keymap[0x50]        = SDL_SCANCODE_B;
+        keymap[0x51]        = SDL_SCANCODE_N;
+        keymap[0x52]        = SDL_SCANCODE_M;
+        keymap[0x53]        = SDL_SCANCODE_COMMA;
+        keymap[0x54]        = SDL_SCANCODE_PERIOD;
+        keymap[0x55]        = SDL_SCANCODE_SLASH;
+        keymap[0x56]        = SDL_SCANCODE_RSHIFT;
+        keymap[0x57]        = SDL_SCANCODE_UP;
+        keymap[0x58]        = SDL_SCANCODE_KP_1;
+        keymap[0x59]        = SDL_SCANCODE_KP_2;
+        keymap[0x5a]        = SDL_SCANCODE_KP_3;
+        keymap[0x5b]        = SDL_SCANCODE_KP_ENTER;
+        keymap[0x5c]        = SDL_SCANCODE_LCTRL;
+        keymap[0x5d]        = SDL_SCANCODE_LALT;
+        keymap[0x5e]        = SDL_SCANCODE_SPACE;
+        keymap[0x5f]        = SDL_SCANCODE_RALT;
+        keymap[0x60]        = SDL_SCANCODE_RCTRL;
+        keymap[0x61]        = SDL_SCANCODE_LEFT;
+        keymap[0x62]        = SDL_SCANCODE_DOWN;
+        keymap[0x63]        = SDL_SCANCODE_RIGHT;
+        keymap[0x64]        = SDL_SCANCODE_KP_0;
+        keymap[0x65]        = SDL_SCANCODE_KP_PERIOD;
+        keymap[0x66]        = SDL_SCANCODE_LGUI;
+        keymap[0x67]        = SDL_SCANCODE_RGUI;
+        keymap[0x68]        = SDL_SCANCODE_MENU;
+        keymap[0x69]        = SDL_SCANCODE_2; /* SDLK_EURO */
+        keymap[0x6a]        = SDL_SCANCODE_KP_EQUALS;
+        keymap[0x6b]        = SDL_SCANCODE_POWER;
 }
 
 SDL_Scancode HAIKU_GetScancodeFromBeKey(int32 bkey) {

+ 25 - 25
src/video/ngage/SDL_ngageevents.cpp

@@ -70,81 +70,81 @@ TBool isCursorVisible = EFalse;
 
 static SDL_Scancode ConvertScancode(SDL_VideoDevice *_this, int key)
 {
-    SDL_Keycode keycode;
+    SDL_Keycode scancode;
 
     switch (key) {
     case EStdKeyBackspace: // Clear key
-        keycode = SDLK_BACKSPACE;
+        scancode = SDL_SCANCODE_BACKSPACE;
         break;
     case 0x31: // 1
-        keycode = SDLK_1;
+        scancode = SDL_SCANCODE_1;
         break;
     case 0x32: // 2
-        keycode = SDLK_2;
+        scancode = SDL_SCANCODE_2;
         break;
     case 0x33: // 3
-        keycode = SDLK_3;
+        scancode = SDL_SCANCODE_3;
         break;
     case 0x34: // 4
-        keycode = SDLK_4;
+        scancode = SDL_SCANCODE_4;
         break;
     case 0x35: // 5
-        keycode = SDLK_5;
+        scancode = SDL_SCANCODE_5;
         break;
     case 0x36: // 6
-        keycode = SDLK_6;
+        scancode = SDL_SCANCODE_6;
         break;
     case 0x37: // 7
-        keycode = SDLK_7;
+        scancode = SDL_SCANCODE_7;
         break;
     case 0x38: // 8
-        keycode = SDLK_8;
+        scancode = SDL_SCANCODE_8;
         break;
     case 0x39: // 9
-        keycode = SDLK_9;
+        scancode = SDL_SCANCODE_9;
         break;
     case 0x30: // 0
-        keycode = SDLK_0;
+        scancode = SDL_SCANCODE_0;
         break;
     case 0x2a: // Asterisk
-        keycode = SDLK_ASTERISK;
+        scancode = SDL_SCANCODE_ASTERISK;
         break;
     case EStdKeyHash: // Hash
-        keycode = SDLK_HASH;
+        scancode = SDL_SCANCODE_HASH;
         break;
     case EStdKeyDevice0: // Left softkey
-        keycode = SDLK_SOFTLEFT;
+        scancode = SDL_SCANCODE_SOFTLEFT;
         break;
     case EStdKeyDevice1: // Right softkey
-        keycode = SDLK_SOFTRIGHT;
+        scancode = SDL_SCANCODE_SOFTRIGHT;
         break;
     case EStdKeyApplication0: // Call softkey
-        keycode = SDLK_CALL;
+        scancode = SDL_SCANCODE_CALL;
         break;
     case EStdKeyApplication1: // End call softkey
-        keycode = SDLK_ENDCALL;
+        scancode = SDL_SCANCODE_ENDCALL;
         break;
     case EStdKeyDevice3: // Middle softkey
-        keycode = SDLK_SELECT;
+        scancode = SDL_SCANCODE_SELECT;
         break;
     case EStdKeyUpArrow: // Up arrow
-        keycode = SDLK_UP;
+        scancode = SDL_SCANCODE_UP;
         break;
     case EStdKeyDownArrow: // Down arrow
-        keycode = SDLK_DOWN;
+        scancode = SDL_SCANCODE_DOWN;
         break;
     case EStdKeyLeftArrow: // Left arrow
-        keycode = SDLK_LEFT;
+        scancode = SDL_SCANCODE_LEFT;
         break;
     case EStdKeyRightArrow: // Right arrow
-        keycode = SDLK_RIGHT;
+        scancode = SDL_SCANCODE_RIGHT;
         break;
     default:
-        keycode = SDLK_UNKNOWN;
+        scancode = SDL_SCANCODE_UNKNOWN;
         break;
     }
 
-    return SDL_GetScancodeFromKey(keycode);
+    return scancode;
 }
 
 int HandleWsEvent(SDL_VideoDevice *_this, const TWsEvent &aWsEvent)

+ 111 - 115
src/video/psp/SDL_pspevents.c

@@ -41,7 +41,7 @@
 #define IRKBD_CONFIG_FILE NULL /* this will take ms0:/seplugins/pspirkeyb.ini */
 
 static int irkbd_ready = 0;
-static SDL_Keycode keymap[256];
+static SDL_Scancode keymap[256];
 #endif
 
 static enum PspHprmKeys hprm = 0;
@@ -51,14 +51,14 @@ static int running = 0;
 static struct
 {
     enum PspHprmKeys id;
-    SDL_Keycode sym;
+    SDL_Scancode scancode;
 } keymap_psp[] = {
-    { PSP_HPRM_PLAYPAUSE, SDLK_F10 },
-    { PSP_HPRM_FORWARD, SDLK_F11 },
-    { PSP_HPRM_BACK, SDLK_F12 },
-    { PSP_HPRM_VOL_UP, SDLK_F13 },
-    { PSP_HPRM_VOL_DOWN, SDLK_F14 },
-    { PSP_HPRM_HOLD, SDLK_F15 }
+    { PSP_HPRM_PLAYPAUSE, SDL_SCANCODE_F10 },
+    { PSP_HPRM_FORWARD, SDL_SCANCODE_F11 },
+    { PSP_HPRM_BACK, SDL_SCANCODE_F12 },
+    { PSP_HPRM_VOL_UP, SDL_SCANCODE_F13 },
+    { PSP_HPRM_VOL_DOWN, SDL_SCANCODE_F14 },
+    { PSP_HPRM_HOLD, SDL_SCANCODE_F15 }
 };
 
 int EventUpdate(void *data)
@@ -90,7 +90,7 @@ void PSP_PumpEvents(SDL_VideoDevice *_this)
     if (changed) {
         for (i = 0; i < sizeof(keymap_psp) / sizeof(keymap_psp[0]); i++) {
             if (changed & keymap_psp[i].id) {
-                SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, keymap_psp[i].id, SDL_GetScancodeFromKey(keymap_psp[i].sym), (keys & keymap_psp[i].id) ? SDL_PRESSED : SDL_RELEASED);
+                SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, keymap_psp[i].id, keymap_psp[i].scancode, (keys & keymap_psp[i].id) ? SDL_PRESSED : SDL_RELEASED);
             }
         }
     }
@@ -109,11 +109,7 @@ void PSP_PumpEvents(SDL_VideoDevice *_this)
                     scanData = (SIrKeybScanCodeData *)buffer + i;
                     raw = scanData->raw;
                     pressed = scanData->pressed;
-                    sym.scancode = raw;
-                    sym.sym = keymap[raw];
-                    /* not tested */
-                    /* SDL_PrivateKeyboard(pressed?SDL_PRESSED:SDL_RELEASED, &sym); */
-                    SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, raw, SDL_GetScancodeFromKey(keymap[raw]), (keys & keymap_psp[i].id) ? SDL_PRESSED : SDL_RELEASED);
+                    SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, raw, keymap[raw], pressed ? SDL_PRESSED : SDL_RELEASED);
                 }
             }
         }
@@ -129,109 +125,109 @@ void PSP_InitOSKeymap(SDL_VideoDevice *_this)
 #ifdef PSPIRKEYB
     int i;
     for (i = 0; i < SDL_arraysize(keymap); ++i) {
-        keymap[i] = SDLK_UNKNOWN;
+        keymap[i] = SDL_SCANCODE_UNKNOWN;
     }
 
-    keymap[KEY_ESC] = SDLK_ESCAPE;
-
-    keymap[KEY_F1] = SDLK_F1;
-    keymap[KEY_F2] = SDLK_F2;
-    keymap[KEY_F3] = SDLK_F3;
-    keymap[KEY_F4] = SDLK_F4;
-    keymap[KEY_F5] = SDLK_F5;
-    keymap[KEY_F6] = SDLK_F6;
-    keymap[KEY_F7] = SDLK_F7;
-    keymap[KEY_F8] = SDLK_F8;
-    keymap[KEY_F9] = SDLK_F9;
-    keymap[KEY_F10] = SDLK_F10;
-    keymap[KEY_F11] = SDLK_F11;
-    keymap[KEY_F12] = SDLK_F12;
-    keymap[KEY_F13] = SDLK_PRINT;
-    keymap[KEY_F14] = SDLK_PAUSE;
-
-    keymap[KEY_GRAVE] = SDLK_GRAVE;
-    keymap[KEY_1] = SDLK_1;
-    keymap[KEY_2] = SDLK_2;
-    keymap[KEY_3] = SDLK_3;
-    keymap[KEY_4] = SDLK_4;
-    keymap[KEY_5] = SDLK_5;
-    keymap[KEY_6] = SDLK_6;
-    keymap[KEY_7] = SDLK_7;
-    keymap[KEY_8] = SDLK_8;
-    keymap[KEY_9] = SDLK_9;
-    keymap[KEY_0] = SDLK_0;
-    keymap[KEY_MINUS] = SDLK_MINUS;
-    keymap[KEY_EQUAL] = SDLK_EQUALS;
-    keymap[KEY_BACKSPACE] = SDLK_BACKSPACE;
-
-    keymap[KEY_TAB] = SDLK_TAB;
-    keymap[KEY_Q] = SDLK_q;
-    keymap[KEY_W] = SDLK_w;
-    keymap[KEY_E] = SDLK_e;
-    keymap[KEY_R] = SDLK_r;
-    keymap[KEY_T] = SDLK_t;
-    keymap[KEY_Y] = SDLK_y;
-    keymap[KEY_U] = SDLK_u;
-    keymap[KEY_I] = SDLK_i;
-    keymap[KEY_O] = SDLK_o;
-    keymap[KEY_P] = SDLK_p;
-    keymap[KEY_LEFTBRACE] = SDLK_LEFTBRACKET;
-    keymap[KEY_RIGHTBRACE] = SDLK_RIGHTBRACKET;
-    keymap[KEY_ENTER] = SDLK_RETURN;
-
-    keymap[KEY_CAPSLOCK] = SDLK_CAPSLOCK;
-    keymap[KEY_A] = SDLK_a;
-    keymap[KEY_S] = SDLK_s;
-    keymap[KEY_D] = SDLK_d;
-    keymap[KEY_F] = SDLK_f;
-    keymap[KEY_G] = SDLK_g;
-    keymap[KEY_H] = SDLK_h;
-    keymap[KEY_J] = SDLK_j;
-    keymap[KEY_K] = SDLK_k;
-    keymap[KEY_L] = SDLK_l;
-    keymap[KEY_SEMICOLON] = SDLK_SEMICOLON;
-    keymap[KEY_APOSTROPHE] = SDLK_APOSTROPHE;
-    keymap[KEY_BACKSLASH] = SDLK_BACKSLASH;
-
-    keymap[KEY_Z] = SDLK_z;
-    keymap[KEY_X] = SDLK_x;
-    keymap[KEY_C] = SDLK_c;
-    keymap[KEY_V] = SDLK_v;
-    keymap[KEY_B] = SDLK_b;
-    keymap[KEY_N] = SDLK_n;
-    keymap[KEY_M] = SDLK_m;
-    keymap[KEY_COMMA] = SDLK_COMMA;
-    keymap[KEY_DOT] = SDLK_PERIOD;
-    keymap[KEY_SLASH] = SDLK_SLASH;
-
-    keymap[KEY_SPACE] = SDLK_SPACE;
-
-    keymap[KEY_UP] = SDLK_UP;
-    keymap[KEY_DOWN] = SDLK_DOWN;
-    keymap[KEY_LEFT] = SDLK_LEFT;
-    keymap[KEY_RIGHT] = SDLK_RIGHT;
-
-    keymap[KEY_HOME] = SDLK_HOME;
-    keymap[KEY_END] = SDLK_END;
-    keymap[KEY_INSERT] = SDLK_INSERT;
-    keymap[KEY_DELETE] = SDLK_DELETE;
-
-    keymap[KEY_NUMLOCK] = SDLK_NUMLOCK;
-    keymap[KEY_LEFTMETA] = SDLK_LSUPER;
-
-    keymap[KEY_KPSLASH] = SDLK_KP_DIVIDE;
-    keymap[KEY_KPASTERISK] = SDLK_KP_MULTIPLY;
-    keymap[KEY_KPMINUS] = SDLK_KP_MINUS;
-    keymap[KEY_KPPLUS] = SDLK_KP_PLUS;
-    keymap[KEY_KPDOT] = SDLK_KP_PERIOD;
-    keymap[KEY_KPEQUAL] = SDLK_KP_EQUALS;
-
-    keymap[KEY_LEFTCTRL] = SDLK_LCTRL;
-    keymap[KEY_RIGHTCTRL] = SDLK_RCTRL;
-    keymap[KEY_LEFTALT] = SDLK_LALT;
-    keymap[KEY_RIGHTALT] = SDLK_RALT;
-    keymap[KEY_LEFTSHIFT] = SDLK_LSHIFT;
-    keymap[KEY_RIGHTSHIFT] = SDLK_RSHIFT;
+    keymap[KEY_ESC] = SDL_SCANCODE_ESCAPE;
+
+    keymap[KEY_F1] = SDL_SCANCODE_F1;
+    keymap[KEY_F2] = SDL_SCANCODE_F2;
+    keymap[KEY_F3] = SDL_SCANCODE_F3;
+    keymap[KEY_F4] = SDL_SCANCODE_F4;
+    keymap[KEY_F5] = SDL_SCANCODE_F5;
+    keymap[KEY_F6] = SDL_SCANCODE_F6;
+    keymap[KEY_F7] = SDL_SCANCODE_F7;
+    keymap[KEY_F8] = SDL_SCANCODE_F8;
+    keymap[KEY_F9] = SDL_SCANCODE_F9;
+    keymap[KEY_F10] = SDL_SCANCODE_F10;
+    keymap[KEY_F11] = SDL_SCANCODE_F11;
+    keymap[KEY_F12] = SDL_SCANCODE_F12;
+    keymap[KEY_F13] = SDL_SCANCODE_PRINT;
+    keymap[KEY_F14] = SDL_SCANCODE_PAUSE;
+
+    keymap[KEY_GRAVE] = SDL_SCANCODE_GRAVE;
+    keymap[KEY_1] = SDL_SCANCODE_1;
+    keymap[KEY_2] = SDL_SCANCODE_2;
+    keymap[KEY_3] = SDL_SCANCODE_3;
+    keymap[KEY_4] = SDL_SCANCODE_4;
+    keymap[KEY_5] = SDL_SCANCODE_5;
+    keymap[KEY_6] = SDL_SCANCODE_6;
+    keymap[KEY_7] = SDL_SCANCODE_7;
+    keymap[KEY_8] = SDL_SCANCODE_8;
+    keymap[KEY_9] = SDL_SCANCODE_9;
+    keymap[KEY_0] = SDL_SCANCODE_0;
+    keymap[KEY_MINUS] = SDL_SCANCODE_MINUS;
+    keymap[KEY_EQUAL] = SDL_SCANCODE_EQUALS;
+    keymap[KEY_BACKSPACE] = SDL_SCANCODE_BACKSPACE;
+
+    keymap[KEY_TAB] = SDL_SCANCODE_TAB;
+    keymap[KEY_Q] = SDL_SCANCODE_q;
+    keymap[KEY_W] = SDL_SCANCODE_w;
+    keymap[KEY_E] = SDL_SCANCODE_e;
+    keymap[KEY_R] = SDL_SCANCODE_r;
+    keymap[KEY_T] = SDL_SCANCODE_t;
+    keymap[KEY_Y] = SDL_SCANCODE_y;
+    keymap[KEY_U] = SDL_SCANCODE_u;
+    keymap[KEY_I] = SDL_SCANCODE_i;
+    keymap[KEY_O] = SDL_SCANCODE_o;
+    keymap[KEY_P] = SDL_SCANCODE_p;
+    keymap[KEY_LEFTBRACE] = SDL_SCANCODE_LEFTBRACKET;
+    keymap[KEY_RIGHTBRACE] = SDL_SCANCODE_RIGHTBRACKET;
+    keymap[KEY_ENTER] = SDL_SCANCODE_RETURN;
+
+    keymap[KEY_CAPSLOCK] = SDL_SCANCODE_CAPSLOCK;
+    keymap[KEY_A] = SDL_SCANCODE_a;
+    keymap[KEY_S] = SDL_SCANCODE_s;
+    keymap[KEY_D] = SDL_SCANCODE_d;
+    keymap[KEY_F] = SDL_SCANCODE_f;
+    keymap[KEY_G] = SDL_SCANCODE_g;
+    keymap[KEY_H] = SDL_SCANCODE_h;
+    keymap[KEY_J] = SDL_SCANCODE_j;
+    keymap[KEY_K] = SDL_SCANCODE_k;
+    keymap[KEY_L] = SDL_SCANCODE_l;
+    keymap[KEY_SEMICOLON] = SDL_SCANCODE_SEMICOLON;
+    keymap[KEY_APOSTROPHE] = SDL_SCANCODE_APOSTROPHE;
+    keymap[KEY_BACKSLASH] = SDL_SCANCODE_BACKSLASH;
+
+    keymap[KEY_Z] = SDL_SCANCODE_z;
+    keymap[KEY_X] = SDL_SCANCODE_x;
+    keymap[KEY_C] = SDL_SCANCODE_c;
+    keymap[KEY_V] = SDL_SCANCODE_v;
+    keymap[KEY_B] = SDL_SCANCODE_b;
+    keymap[KEY_N] = SDL_SCANCODE_n;
+    keymap[KEY_M] = SDL_SCANCODE_m;
+    keymap[KEY_COMMA] = SDL_SCANCODE_COMMA;
+    keymap[KEY_DOT] = SDL_SCANCODE_PERIOD;
+    keymap[KEY_SLASH] = SDL_SCANCODE_SLASH;
+
+    keymap[KEY_SPACE] = SDL_SCANCODE_SPACE;
+
+    keymap[KEY_UP] = SDL_SCANCODE_UP;
+    keymap[KEY_DOWN] = SDL_SCANCODE_DOWN;
+    keymap[KEY_LEFT] = SDL_SCANCODE_LEFT;
+    keymap[KEY_RIGHT] = SDL_SCANCODE_RIGHT;
+
+    keymap[KEY_HOME] = SDL_SCANCODE_HOME;
+    keymap[KEY_END] = SDL_SCANCODE_END;
+    keymap[KEY_INSERT] = SDL_SCANCODE_INSERT;
+    keymap[KEY_DELETE] = SDL_SCANCODE_DELETE;
+
+    keymap[KEY_NUMLOCK] = SDL_SCANCODE_NUMLOCK;
+    keymap[KEY_LEFTMETA] = SDL_SCANCODE_LSUPER;
+
+    keymap[KEY_KPSLASH] = SDL_SCANCODE_KP_DIVIDE;
+    keymap[KEY_KPASTERISK] = SDL_SCANCODE_KP_MULTIPLY;
+    keymap[KEY_KPMINUS] = SDL_SCANCODE_KP_MINUS;
+    keymap[KEY_KPPLUS] = SDL_SCANCODE_KP_PLUS;
+    keymap[KEY_KPDOT] = SDL_SCANCODE_KP_PERIOD;
+    keymap[KEY_KPEQUAL] = SDL_SCANCODE_KP_EQUALS;
+
+    keymap[KEY_LEFTCTRL] = SDL_SCANCODE_LCTRL;
+    keymap[KEY_RIGHTCTRL] = SDL_SCANCODE_RCTRL;
+    keymap[KEY_LEFTALT] = SDL_SCANCODE_LALT;
+    keymap[KEY_RIGHTALT] = SDL_SCANCODE_RALT;
+    keymap[KEY_LEFTSHIFT] = SDL_SCANCODE_LSHIFT;
+    keymap[KEY_RIGHTSHIFT] = SDL_SCANCODE_RSHIFT;
 #endif
 }
 

+ 2 - 4
src/video/vita/SDL_vitavideo.c

@@ -380,7 +380,6 @@ SceImeCaret caret_rev;
 void VITA_ImeEventHandler(void *arg, const SceImeEventData *e)
 {
     SDL_VideoData *videodata = (SDL_VideoData *)arg;
-    SDL_Scancode scancode;
     uint8_t utf8_buffer[SCE_IME_MAX_TEXT_LENGTH];
     switch (e->id) {
     case SCE_IME_EVENT_UPDATE_TEXT:
@@ -388,11 +387,10 @@ void VITA_ImeEventHandler(void *arg, const SceImeEventData *e)
             SDL_SendKeyboardKeyAutoRelease(0, SDL_SCANCODE_BACKSPACE);
             sceImeSetText((SceWChar16 *)libime_initval, 4);
         } else {
-            scancode = SDL_GetScancodeFromKey(*(SceWChar16 *)&libime_out[1]);
-            if (scancode == SDL_SCANCODE_SPACE) {
+            utf16_to_utf8((SceWChar16 *)&libime_out[1], utf8_buffer);
+            if (utf8_buffer[0] == ' ') {
                 SDL_SendKeyboardKeyAutoRelease(0, SDL_SCANCODE_SPACE);
             } else {
-                utf16_to_utf8((SceWChar16 *)&libime_out[1], utf8_buffer);
                 SDL_SendKeyboardText((const char *)utf8_buffer);
             }
             SDL_memset(&caret_rev, 0, sizeof(SceImeCaret));

+ 7 - 7
src/video/wayland/SDL_waylandevents.c

@@ -1107,7 +1107,7 @@ static void Wayland_keymap_iter(struct xkb_keymap *keymap, xkb_keycode_t key, vo
 
             /* Note: The default SDL keymap always sets this to right alt instead of AltGr/Mode, so handle it separately. */
             if (syms[0] != XKB_KEY_ISO_Level3_Shift) {
-                keycode = SDL_GetDefaultKeyFromScancode(sc);
+                keycode = SDL_GetDefaultKeyFromScancode(sc, SDL_KMOD_NONE);
             } else {
                 keycode = SDLK_MODE;
             }
@@ -1218,13 +1218,13 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
     if (input->xkb.current_group != XKB_GROUP_INVALID) {
         Wayland_Keymap keymap;
         keymap.layout = input->xkb.current_group;
-        SDL_GetDefaultKeymap(keymap.keymap);
+        //SDL_GetDefaultKeymap(keymap.keymap);
         if (!input->keyboard_is_virtual) {
             WAYLAND_xkb_keymap_key_for_each(input->xkb.keymap,
                                             Wayland_keymap_iter,
                                             &keymap);
         }
-        SDL_SetKeymap(0, keymap.keymap, SDL_NUM_SCANCODES, SDL_TRUE);
+        //SDL_SetKeymap(0, keymap.keymap, SDL_NUM_SCANCODES, SDL_TRUE);
     }
 
     /*
@@ -1398,7 +1398,7 @@ static void Wayland_ReconcileModifiers(struct SDL_WaylandInput *input)
 
 static void Wayland_HandleModifierKeys(struct SDL_WaylandInput *input, SDL_Scancode scancode, SDL_bool pressed)
 {
-    const SDL_Keycode keycode = SDL_GetKeyFromScancode(scancode);
+    const SDL_Keycode keycode = SDL_GetKeyFromScancode(scancode, SDL_KMOD_NONE);
     SDL_Keymod mod;
 
     switch (keycode) {
@@ -1475,7 +1475,7 @@ static void keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
 
     wl_array_for_each (key, keys) {
         const SDL_Scancode scancode = Wayland_get_scancode_from_key(input, *key + 8);
-        const SDL_Keycode keycode = SDL_GetKeyFromScancode(scancode);
+        const SDL_Keycode keycode = SDL_GetKeyFromScancode(scancode, SDL_KMOD_NONE);
 
         switch (keycode) {
         case SDLK_LSHIFT:
@@ -1677,13 +1677,13 @@ static void keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
     /* The layout changed, remap and fire an event. Virtual keyboards use the default keymap. */
     input->xkb.current_group = group;
     keymap.layout = group;
-    SDL_GetDefaultKeymap(keymap.keymap);
+    //SDL_GetDefaultKeymap(keymap.keymap);
     if (!input->keyboard_is_virtual) {
         WAYLAND_xkb_keymap_key_for_each(input->xkb.keymap,
                                         Wayland_keymap_iter,
                                         &keymap);
     }
-    SDL_SetKeymap(0, keymap.keymap, SDL_NUM_SCANCODES, SDL_TRUE);
+    //SDL_SetKeymap(0, keymap.keymap, SDL_NUM_SCANCODES, SDL_TRUE);
 }
 
 static void keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard,

+ 61 - 37
src/video/windows/SDL_windowskeyboard.c

@@ -111,57 +111,81 @@ void WIN_InitKeyboard(SDL_VideoDevice *_this)
 
 void WIN_UpdateKeymap(SDL_bool send_event)
 {
-    int i;
     SDL_Scancode scancode;
-    SDL_Keycode keymap[SDL_NUM_SCANCODES];
+    SDL_Keymap *keymap;
     BYTE keyboardState[256] = { 0 };
     WCHAR buffer[16];
+    SDL_Keymod mods[] = {
+        SDL_KMOD_NONE,
+        SDL_KMOD_SHIFT,
+        SDL_KMOD_CAPS,
+        (SDL_KMOD_SHIFT | SDL_KMOD_CAPS),
+        SDL_KMOD_MODE,
+        (SDL_KMOD_MODE | SDL_KMOD_SHIFT),
+        (SDL_KMOD_MODE | SDL_KMOD_CAPS),
+        (SDL_KMOD_MODE | SDL_KMOD_SHIFT | SDL_KMOD_CAPS)
+    };
 
-    SDL_GetDefaultKeymap(keymap);
     WIN_ResetDeadKeys();
 
-    for (i = 0; i < SDL_arraysize(windows_scancode_table); i++) {
-        int vk, sc, result;
-        Uint32 *ch = 0;
+    keymap = SDL_CreateKeymap();
 
-        /* Make sure this scancode is a valid character scancode */
-        scancode = windows_scancode_table[i];
-        if (scancode == SDL_SCANCODE_UNKNOWN) {
-            continue;
-        }
+    for (int m = 0; m < SDL_arraysize(mods); ++m) {
+        for (int i = 0; i < SDL_arraysize(windows_scancode_table); i++) {
+            int vk, sc, result;
+            Uint32 *ch = 0;
 
-        /* If this key is one of the non-mappable keys, ignore it */
-        /* Uncomment the third part to re-enable the behavior of not mapping the "`"(grave) key to the users actual keyboard layout */
-        if ((keymap[scancode] & SDLK_SCANCODE_MASK) || scancode == SDL_SCANCODE_DELETE /*|| scancode == SDL_SCANCODE_GRAVE*/) {
-            continue;
-        }
+            /* Make sure this scancode is a valid character scancode */
+            scancode = windows_scancode_table[i];
+            if (scancode == SDL_SCANCODE_UNKNOWN ||
+                (SDL_GetDefaultKeyFromScancode(scancode, SDL_KMOD_NONE) & SDLK_SCANCODE_MASK)) {
+                continue;
+            }
 
-        /* Unpack the single byte index to make the scan code. */
-        sc = MAKEWORD(i & 0x7f, (i & 0x80) ? 0xe0 : 0x00);
-        vk = LOBYTE(MapVirtualKey(sc, MAPVK_VSC_TO_VK));
-        if (!vk) {
-            continue;
-        }
+            /* If this key is one of the non-mappable keys, ignore it */
+            /* Uncomment the second part to re-enable the behavior of not mapping the "`"(grave) key to the users actual keyboard layout */
+            if (scancode == SDL_SCANCODE_DELETE /*|| scancode == SDL_SCANCODE_GRAVE*/) {
+                continue;
+            }
 
-        result = ToUnicode(vk, sc, keyboardState, buffer, 16, 0);
-        buffer[SDL_abs(result)] = 0;
-
-        /* Convert UTF-16 to UTF-32 code points */
-        ch = (Uint32 *)SDL_iconv_string("UTF-32LE", "UTF-16LE", (const char *)buffer, (SDL_abs(result) + 1) * sizeof(WCHAR));
-        if (ch) {
-            /* Windows keyboard layouts can emit several UTF-32 code points on a single key press.
-             * Use <U+FFFD REPLACEMENT CHARACTER> since we cannot fit into single SDL_Keycode value in SDL keymap.
-             * See https://kbdlayout.info/features/ligatures for a list of such keys. */
-            keymap[scancode] = ch[1] == 0 ? ch[0] : 0xfffd;
-            SDL_free(ch);
-        }
+            /* Unpack the single byte index to make the scan code. */
+            sc = MAKEWORD(i & 0x7f, (i & 0x80) ? 0xe0 : 0x00);
+            vk = LOBYTE(MapVirtualKey(sc, MAPVK_VSC_TO_VK));
+            if (!vk) {
+                continue;
+            }
+
+            // Update the keyboard state for the modifiers
+            keyboardState[VK_SHIFT] = (mods[m] & SDL_KMOD_SHIFT) ? 0x80 : 0x00;
+            keyboardState[VK_CAPITAL] = (mods[m] & SDL_KMOD_CAPS) ? 0x01 : 0x00;
+            keyboardState[VK_CONTROL] = (mods[m] & SDL_KMOD_MODE) ? 0x80 : 0x00;
+            keyboardState[VK_MENU] = (mods[m] & SDL_KMOD_MODE) ? 0x80 : 0x00;
+
+            result = ToUnicode(vk, sc, keyboardState, buffer, 16, 0);
+            buffer[SDL_abs(result)] = 0;
+
+            /* Convert UTF-16 to UTF-32 code points */
+            ch = (Uint32 *)SDL_iconv_string("UTF-32LE", "UTF-16LE", (const char *)buffer, (SDL_abs(result) + 1) * sizeof(WCHAR));
+            if (ch) {
+                /* Windows keyboard layouts can emit several UTF-32 code points on a single key press.
+                 * Use <U+FFFD REPLACEMENT CHARACTER> since we cannot fit into single SDL_Keycode value in SDL keymap.
+                 * See https://kbdlayout.info/features/ligatures for a list of such keys. */
+                SDL_SetKeymapEntry(keymap, scancode, mods[m], ch[1] == 0 ? ch[0] : 0xfffd);
+                SDL_free(ch);
+            } else {
+                // The default keymap doesn't have any SDL_KMOD_MODE entries, so we don't need to override them
+                if (!(mods[m] & SDL_KMOD_MODE)) {
+                    SDL_SetKeymapEntry(keymap, scancode, mods[m], SDLK_UNKNOWN);
+                }
+            }
 
-        if (result < 0) {
-            WIN_ResetDeadKeys();
+            if (result < 0) {
+                WIN_ResetDeadKeys();
+            }
         }
     }
 
-    SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES, send_event);
+    SDL_SetKeymap(keymap, send_event);
 }
 
 void WIN_QuitKeyboard(SDL_VideoDevice *_this)

+ 1 - 1
src/video/x11/SDL_x11events.c

@@ -428,7 +428,7 @@ void X11_ReconcileKeyboardState(SDL_VideoDevice *_this)
 
         if (x11KeyPressed && !sdlKeyPressed) {
             /* Only update modifier state for keys that are pressed in another application */
-            switch (SDL_GetKeyFromScancode(scancode)) {
+            switch (SDL_GetKeyFromScancode(scancode, SDL_KMOD_NONE)) {
             case SDLK_LCTRL:
             case SDLK_RCTRL:
             case SDLK_LSHIFT:

+ 17 - 14
src/video/x11/SDL_x11keyboard.c

@@ -257,7 +257,6 @@ int X11_InitKeyboard(SDL_VideoDevice *_this)
         }
     }
     if (best_index >= 0 && best_distance <= 2) {
-        SDL_Keycode default_keymap[SDL_NUM_SCANCODES];
         int table_size;
         const SDL_Scancode *table = SDL_GetScancodeTable(scancode_set[best_index], &table_size);
 
@@ -274,8 +273,6 @@ int X11_InitKeyboard(SDL_VideoDevice *_this)
            However, there are a number of extended scancodes that have no standard location, so use
            the X11 mapping for all non-character keys.
          */
-        SDL_GetDefaultKeymap(default_keymap);
-
         for (i = min_keycode; i <= max_keycode; ++i) {
             SDL_Scancode scancode = X11_KeyCodeToSDLScancode(_this, i);
 #ifdef DEBUG_KEYBOARD
@@ -289,7 +286,7 @@ int X11_InitKeyboard(SDL_VideoDevice *_this)
             if (scancode == data->key_layout[i]) {
                 continue;
             }
-            if (default_keymap[scancode] >= SDLK_SCANCODE_MASK && X11_ScancodeIsRemappable(scancode)) {
+            if ((SDL_GetDefaultKeyFromScancode(scancode, SDL_KMOD_NONE) & SDLK_SCANCODE_MASK) && X11_ScancodeIsRemappable(scancode)) {
                 /* Not a character key and the scancode is safe to remap */
 #ifdef DEBUG_KEYBOARD
                 SDL_Log("Changing scancode, was %d (%s), now %d (%s)\n", data->key_layout[i], SDL_GetScancodeName(data->key_layout[i]), scancode, SDL_GetScancodeName(scancode));
@@ -340,10 +337,10 @@ void X11_UpdateKeymap(SDL_VideoDevice *_this, SDL_bool send_event)
     SDL_VideoData *data = _this->driverdata;
     int i;
     SDL_Scancode scancode;
-    SDL_Keycode keymap[SDL_NUM_SCANCODES];
+    SDL_Keymap *keymap;
     unsigned char group = 0;
 
-    SDL_GetDefaultKeymap(keymap);
+    keymap = SDL_CreateKeymap();
 
 #ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
     if (data->xkb) {
@@ -356,8 +353,10 @@ void X11_UpdateKeymap(SDL_VideoDevice *_this, SDL_bool send_event)
     }
 #endif
 
+    // FIXME: Need to get the mapping for all modifiers, not just the first one
     for (i = 0; i < SDL_arraysize(data->key_layout); i++) {
         Uint32 key;
+        SDL_Keycode keycode;
 
         /* Make sure this is a valid scancode */
         scancode = data->key_layout[i];
@@ -368,33 +367,37 @@ void X11_UpdateKeymap(SDL_VideoDevice *_this, SDL_bool send_event)
         /* See if there is a UCS keycode for this scancode */
         key = X11_KeyCodeToUcs4(_this, (KeyCode)i, group);
         if (key) {
-            keymap[scancode] = key;
+            keycode = (SDL_Keycode)key;
         } else {
             SDL_Scancode keyScancode = X11_KeyCodeToSDLScancode(_this, (KeyCode)i);
 
             switch (keyScancode) {
+            case SDL_SCANCODE_UNKNOWN:
+                keycode = SDLK_UNKNOWN;
+                break;
             case SDL_SCANCODE_RETURN:
-                keymap[scancode] = SDLK_RETURN;
+                keycode = SDLK_RETURN;
                 break;
             case SDL_SCANCODE_ESCAPE:
-                keymap[scancode] = SDLK_ESCAPE;
+                keycode = SDLK_ESCAPE;
                 break;
             case SDL_SCANCODE_BACKSPACE:
-                keymap[scancode] = SDLK_BACKSPACE;
+                keycode = SDLK_BACKSPACE;
                 break;
             case SDL_SCANCODE_TAB:
-                keymap[scancode] = SDLK_TAB;
+                keycode = SDLK_TAB;
                 break;
             case SDL_SCANCODE_DELETE:
-                keymap[scancode] = SDLK_DELETE;
+                keycode = SDLK_DELETE;
                 break;
             default:
-                keymap[scancode] = SDL_SCANCODE_TO_KEYCODE(keyScancode);
+                keycode = SDL_SCANCODE_TO_KEYCODE(keyScancode);
                 break;
             }
         }
+        SDL_SetKeymapEntry(keymap, scancode, SDL_KMOD_NONE, keycode);
     }
-    SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES, send_event);
+    SDL_SetKeymap(keymap, send_event);
 }
 
 void X11_QuitKeyboard(SDL_VideoDevice *_this)

+ 90 - 36
test/checkkeys.c

@@ -27,8 +27,7 @@ static SDLTest_CommonState *state;
 static SDLTest_TextWindow *textwin;
 static int done;
 
-static void
-print_string(char **text, size_t *maxlen, const char *fmt, ...)
+static void print_string(char **text, size_t *maxlen, const char *fmt, ...)
 {
     int len;
     va_list ap;
@@ -46,39 +45,52 @@ print_string(char **text, size_t *maxlen, const char *fmt, ...)
     va_end(ap);
 }
 
-static void
-print_modifiers(char **text, size_t *maxlen)
+static void print_modifiers(char **text, size_t *maxlen, SDL_Keymod mod)
 {
-    int mod;
     print_string(text, maxlen, " modifiers:");
-    mod = SDL_GetModState();
-    if (!mod) {
+    if (mod == SDL_KMOD_NONE) {
         print_string(text, maxlen, " (none)");
         return;
     }
-    if (mod & SDL_KMOD_LSHIFT) {
-        print_string(text, maxlen, " LSHIFT");
-    }
-    if (mod & SDL_KMOD_RSHIFT) {
-        print_string(text, maxlen, " RSHIFT");
-    }
-    if (mod & SDL_KMOD_LCTRL) {
-        print_string(text, maxlen, " LCTRL");
-    }
-    if (mod & SDL_KMOD_RCTRL) {
-        print_string(text, maxlen, " RCTRL");
-    }
-    if (mod & SDL_KMOD_LALT) {
-        print_string(text, maxlen, " LALT");
+    if ((mod & SDL_KMOD_SHIFT) == SDL_KMOD_SHIFT) {
+        print_string(text, maxlen, " SHIFT");
+    } else {
+        if (mod & SDL_KMOD_LSHIFT) {
+            print_string(text, maxlen, " LSHIFT");
+        }
+        if (mod & SDL_KMOD_RSHIFT) {
+            print_string(text, maxlen, " RSHIFT");
+        }
     }
-    if (mod & SDL_KMOD_RALT) {
-        print_string(text, maxlen, " RALT");
+    if ((mod & SDL_KMOD_CTRL) == SDL_KMOD_CTRL) {
+        print_string(text, maxlen, " CTRL");
+    } else {
+        if (mod & SDL_KMOD_LCTRL) {
+            print_string(text, maxlen, " LCTRL");
+        }
+        if (mod & SDL_KMOD_RCTRL) {
+            print_string(text, maxlen, " RCTRL");
+        }
     }
-    if (mod & SDL_KMOD_LGUI) {
-        print_string(text, maxlen, " LGUI");
+    if ((mod & SDL_KMOD_ALT) == SDL_KMOD_ALT) {
+        print_string(text, maxlen, " ALT");
+    } else {
+        if (mod & SDL_KMOD_LALT) {
+            print_string(text, maxlen, " LALT");
+        }
+        if (mod & SDL_KMOD_RALT) {
+            print_string(text, maxlen, " RALT");
+        }
     }
-    if (mod & SDL_KMOD_RGUI) {
-        print_string(text, maxlen, " RGUI");
+    if ((mod & SDL_KMOD_GUI) == SDL_KMOD_GUI) {
+        print_string(text, maxlen, " GUI");
+    } else {
+        if (mod & SDL_KMOD_LGUI) {
+            print_string(text, maxlen, " LGUI");
+        }
+        if (mod & SDL_KMOD_RGUI) {
+            print_string(text, maxlen, " RGUI");
+        }
     }
     if (mod & SDL_KMOD_NUM) {
         print_string(text, maxlen, " NUM");
@@ -94,8 +106,47 @@ print_modifiers(char **text, size_t *maxlen)
     }
 }
 
-static void
-PrintModifierState(void)
+static void PrintKeymap(void)
+{
+    SDL_Keymod mods[] = {
+        SDL_KMOD_NONE,
+        SDL_KMOD_SHIFT,
+        SDL_KMOD_CAPS,
+        (SDL_KMOD_SHIFT | SDL_KMOD_CAPS),
+        SDL_KMOD_ALT,
+        (SDL_KMOD_ALT | SDL_KMOD_SHIFT),
+        (SDL_KMOD_ALT | SDL_KMOD_CAPS),
+        (SDL_KMOD_ALT | SDL_KMOD_SHIFT | SDL_KMOD_CAPS),
+        SDL_KMOD_MODE,
+        (SDL_KMOD_MODE | SDL_KMOD_SHIFT),
+        (SDL_KMOD_MODE | SDL_KMOD_CAPS),
+        (SDL_KMOD_MODE | SDL_KMOD_SHIFT | SDL_KMOD_CAPS)
+    };
+    int i, m;
+
+    SDL_Log("Differences from the default keymap:\n");
+    for (m = 0; m < SDL_arraysize(mods); ++m) {
+        for (i = 0; i < SDL_NUM_SCANCODES; ++i) {
+            SDL_Keycode key = SDL_GetKeyFromScancode((SDL_Scancode)i, mods[m]);
+			SDL_Keycode default_key = SDL_GetDefaultKeyFromScancode((SDL_Scancode)i, mods[m]);
+            if (key != default_key) {
+                char message[512];
+                char *spot;
+                size_t left;
+
+                spot = message;
+                left = sizeof(message);
+
+                print_string(&spot, &left, "Scancode %s", SDL_GetScancodeName((SDL_Scancode)i));
+                print_modifiers(&spot, &left, mods[m]);
+                print_string(&spot, &left, ": %s 0x%x (default: %s 0x%x)", SDL_GetKeyName(key), key, SDL_GetKeyName(default_key), default_key);
+                SDL_Log("%s", message);
+            }
+        }
+    }
+}
+
+static void PrintModifierState(void)
 {
     char message[512];
     char *spot;
@@ -104,12 +155,11 @@ PrintModifierState(void)
     spot = message;
     left = sizeof(message);
 
-    print_modifiers(&spot, &left);
+    print_modifiers(&spot, &left, SDL_GetModState());
     SDL_Log("Initial state:%s\n", message);
 }
 
-static void
-PrintKey(SDL_Keysym *sym, SDL_bool pressed, SDL_bool repeat)
+static void PrintKey(SDL_Keysym *sym, SDL_bool pressed, SDL_bool repeat)
 {
     char message[512];
     char *spot;
@@ -135,15 +185,14 @@ PrintKey(SDL_Keysym *sym, SDL_bool pressed, SDL_bool repeat)
                      sym->scancode == SDL_SCANCODE_UNKNOWN ? "UNKNOWN" : SDL_GetScancodeName(sym->scancode),
                      pressed ? "pressed " : "released");
     }
-    print_modifiers(&spot, &left);
+    print_modifiers(&spot, &left, sym->mod);
     if (repeat) {
         print_string(&spot, &left, " (repeat)");
     }
     SDL_Log("%s\n", message);
 }
 
-static void
-PrintText(const char *eventtype, const char *text)
+static void PrintText(const char *eventtype, const char *text)
 {
     const char *spot;
     char expanded[1024];
@@ -225,6 +274,10 @@ static void loop(void)
                 }
             }
             break;
+        case SDL_EVENT_KEYMAP_CHANGED:
+            SDL_Log("Keymap changed!\n");
+            PrintKeymap();
+            break;
         case SDL_EVENT_QUIT:
             done = 1;
             break;
@@ -296,8 +349,9 @@ int main(int argc, char *argv[])
 
     SDL_StartTextInput();
 
-    /* Print initial modifier state */
+    /* Print initial state */
     SDL_PumpEvents();
+    PrintKeymap();
     PrintModifierState();
 
     /* Watch keystrokes */

+ 11 - 8
test/testautomation_keyboard.c

@@ -124,12 +124,12 @@ static int keyboard_getKeyFromScancode(void *arg)
     SDL_Keycode result;
 
     /* Case where input is valid */
-    result = SDL_GetKeyFromScancode(SDL_SCANCODE_A);
+    result = SDL_GetKeyFromScancode(SDL_SCANCODE_A, SDL_KMOD_NONE);
     SDLTest_AssertPass("Call to SDL_GetKeyFromScancode(valid)");
     SDLTest_AssertCheck(result == SDLK_a, "Verify result from call, expected: %d, got: %" SDL_PRIs32, SDLK_a, result);
 
     /* Case where input is zero */
-    result = SDL_GetKeyFromScancode(0);
+    result = SDL_GetKeyFromScancode(SDL_SCANCODE_UNKNOWN, SDL_KMOD_NONE);
     SDLTest_AssertPass("Call to SDL_GetKeyFromScancode(0)");
     SDLTest_AssertCheck(result == SDLK_UNKNOWN, "Verify result from call is UNKNOWN, expected: %d, got: %" SDL_PRIs32, SDLK_UNKNOWN, result);
 
@@ -138,13 +138,13 @@ static int keyboard_getKeyFromScancode(void *arg)
     SDLTest_AssertPass("Call to SDL_ClearError()");
 
     /* Case where input is invalid (too small) */
-    result = SDL_GetKeyFromScancode(-999);
+    result = SDL_GetKeyFromScancode((SDL_Scancode)-999, SDL_KMOD_NONE);
     SDLTest_AssertPass("Call to SDL_GetKeyFromScancode(-999)");
     SDLTest_AssertCheck(result == SDLK_UNKNOWN, "Verify result from call is UNKNOWN, expected: %d, got: %" SDL_PRIs32, SDLK_UNKNOWN, result);
     checkInvalidScancodeError();
 
     /* Case where input is invalid (too big) */
-    result = SDL_GetKeyFromScancode(999);
+    result = SDL_GetKeyFromScancode((SDL_Scancode)999, SDL_KMOD_NONE);
     SDLTest_AssertPass("Call to SDL_GetKeyFromScancode(999)");
     SDLTest_AssertCheck(result == SDLK_UNKNOWN, "Verify result from call is UNKNOWN, expected: %d, got: %" SDL_PRIs32, SDLK_UNKNOWN, result);
     checkInvalidScancodeError();
@@ -499,16 +499,19 @@ static int keyboard_setTextInputRectNegative(void *arg)
 static int keyboard_getScancodeFromKey(void *arg)
 {
     SDL_Scancode scancode;
+    SDL_Keymod modstate;
 
     /* Regular key */
-    scancode = SDL_GetScancodeFromKey(SDLK_4);
+    scancode = SDL_GetDefaultScancodeFromKey(SDLK_4, &modstate);
     SDLTest_AssertPass("Call to SDL_GetScancodeFromKey(SDLK_4)");
-    SDLTest_AssertCheck(scancode == SDL_SCANCODE_4, "Validate return value from SDL_GetScancodeFromKey, expected: %d, got: %d", SDL_SCANCODE_4, scancode);
+    SDLTest_AssertCheck(scancode == SDL_SCANCODE_4, "Validate return value from SDL_GetDefaultScancodeFromKey, expected: %d, got: %d", SDL_SCANCODE_4, scancode);
+    SDLTest_AssertCheck(modstate == SDL_KMOD_NONE, "Validate modstate from SDL_GetDefaultScancodeFromKey, expected: %d, got: %d", SDL_KMOD_NONE, modstate);
 
     /* Virtual key */
-    scancode = SDL_GetScancodeFromKey(SDLK_PLUS);
+    scancode = SDL_GetDefaultScancodeFromKey(SDLK_PLUS, &modstate);
     SDLTest_AssertPass("Call to SDL_GetScancodeFromKey(SDLK_PLUS)");
-    SDLTest_AssertCheck(scancode == 0, "Validate return value from SDL_GetScancodeFromKey, expected: 0, got: %d", scancode);
+    SDLTest_AssertCheck(scancode == SDL_SCANCODE_EQUALS, "Validate return value from SDL_GetDefaultScancodeFromKey, expected: %d, got: %d", SDL_SCANCODE_EQUALS, scancode);
+    SDLTest_AssertCheck(modstate == SDL_KMOD_SHIFT, "Validate modstate from SDL_GetDefaultScancodeFromKey, expected: %d, got: %d", SDL_KMOD_SHIFT, modstate);
 
     return TEST_COMPLETED;
 }