SDL: Don't map the top keyboard row to numbers when using the one-handed DVORAK layouts (thanks @tormol!) (4dd9f)

From 4dd9f61bfda155bbdd153d40d4a7be0805050afa Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 22 May 2023 11:30:42 -0700
Subject: [PATCH] Don't map the top keyboard row to numbers when using the
 one-handed DVORAK layouts (thanks @tormol!)

Fixes https://github.com/libsdl-org/SDL/pull/5127

(cherry picked from commit a2f4783e753e499c7f6660bf34e337618239a72f)
---
 include/SDL3/SDL_keycode.h              |  2 +-
 src/events/SDL_keyboard.c               | 33 ++++++++++++++++++++-----
 src/video/windows/SDL_windowskeyboard.c |  6 ++---
 3 files changed, 30 insertions(+), 11 deletions(-)

diff --git a/include/SDL3/SDL_keycode.h b/include/SDL3/SDL_keycode.h
index 1e11a2e4da95..9f4953c01b7d 100644
--- a/include/SDL3/SDL_keycode.h
+++ b/include/SDL3/SDL_keycode.h
@@ -40,7 +40,7 @@
  *  an SDLK_* constant for those keys that do not generate characters.
  *
  *  A special exception is the number keys at the top of the keyboard which
- *  always map to SDLK_0...SDLK_9, regardless of layout.
+ *  map to SDLK_0...SDLK_9 on AZERTY layouts.
  */
 typedef Sint32 SDL_Keycode;
 
diff --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c
index de07c168d19c..005812b7c18f 100644
--- a/src/events/SDL_keyboard.c
+++ b/src/events/SDL_keyboard.c
@@ -702,20 +702,41 @@ void SDL_SetKeymap(int start, const SDL_Keycode *keys, int length, SDL_bool send
     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);
+    }
+
     SDL_memcpy(&normalized_keymap[start], keys, sizeof(*keys) * length);
 
-    /* The number key scancodes always map to the number key keycodes.
-     * On AZERTY layouts these technically are symbols, but users (and games)
-     * always think of them and view them in UI as number keys.
+    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.
      */
-    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 (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 */
diff --git a/src/video/windows/SDL_windowskeyboard.c b/src/video/windows/SDL_windowskeyboard.c
index 18547f313048..45c488790a6d 100644
--- a/src/video/windows/SDL_windowskeyboard.c
+++ b/src/video/windows/SDL_windowskeyboard.c
@@ -130,10 +130,8 @@ void WIN_UpdateKeymap(SDL_bool send_event)
         }
 
         /* If this key is one of the non-mappable keys, ignore it */
-        /* Not mapping numbers fixes the French layout, giving numeric keycodes for the number keys, which is the expected behavior */
-        if ((keymap[scancode] & SDLK_SCANCODE_MASK) ||
-            /*  scancode == SDL_SCANCODE_GRAVE || */ /* Uncomment this line to re-enable the behavior of not mapping the "`"(grave) key to the users actual keyboard layout */
-            (scancode >= SDL_SCANCODE_1 && scancode <= SDL_SCANCODE_0)) {
+        /* Uncomment the second part 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_GRAVE*/) {
             continue;
         }