Commit 8b438f7b51013a6494f385e26dd061e050a65f68

Cameron Gutman 2022-07-31T15:34:03

keyboard: Only send SDL_KEYMAPCHANGED when the keymap actually changes

diff --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c
index aa75f5d..9a8c403 100644
--- a/src/events/SDL_keyboard.c
+++ b/src/events/SDL_keyboard.c
@@ -590,24 +590,36 @@ SDL_GetDefaultKeymap(SDL_Keycode * keymap)
 }
 
 void
-SDL_SetKeymap(int start, SDL_Keycode * keys, int length)
+SDL_SetKeymap(int start, SDL_Keycode * keys, int length, SDL_bool send_event)
 {
     SDL_Keyboard *keyboard = &SDL_keyboard;
     SDL_Scancode scancode;
+    SDL_Keycode normalized_keymap[SDL_NUM_SCANCODES];
 
     if (start < 0 || start + length > SDL_NUM_SCANCODES) {
         return;
     }
 
-    SDL_memcpy(&keyboard->keymap[start], keys, sizeof(*keys) * length);
+    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.
      */
-    keyboard->keymap[SDL_SCANCODE_0] = SDLK_0;
+    normalized_keymap[SDL_SCANCODE_0] = SDLK_0;
     for (scancode = SDL_SCANCODE_1; scancode <= SDL_SCANCODE_9; ++scancode) {
-        keyboard->keymap[scancode] = SDLK_1 + (scancode - SDL_SCANCODE_1);
+        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);
+
+    if (send_event) {
+        SDL_SendKeymapChangedEvent();
     }
 }
 
diff --git a/src/events/SDL_keyboard_c.h b/src/events/SDL_keyboard_c.h
index beee827..e911312 100644
--- a/src/events/SDL_keyboard_c.h
+++ b/src/events/SDL_keyboard_c.h
@@ -33,7 +33,7 @@ extern int SDL_KeyboardInit(void);
 extern void SDL_GetDefaultKeymap(SDL_Keycode * keymap);
 
 /* Set the mapping of scancode to key codes */
-extern void SDL_SetKeymap(int start, SDL_Keycode * keys, int length);
+extern void SDL_SetKeymap(int start, 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
diff --git a/src/video/android/SDL_androidkeyboard.c b/src/video/android/SDL_androidkeyboard.c
index 7098d2e..e120360 100644
--- a/src/video/android/SDL_androidkeyboard.c
+++ b/src/video/android/SDL_androidkeyboard.c
@@ -36,7 +36,7 @@ void Android_InitKeyboard(void)
 
     /* Add default scancode to key mapping */
     SDL_GetDefaultKeymap(keymap);
-    SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES);
+    SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES, SDL_FALSE);
 }
 
 static SDL_Scancode Android_Keycodes[] = {
diff --git a/src/video/cocoa/SDL_cocoakeyboard.m b/src/video/cocoa/SDL_cocoakeyboard.m
index fd96ea3..02c99e8 100644
--- a/src/video/cocoa/SDL_cocoakeyboard.m
+++ b/src/video/cocoa/SDL_cocoakeyboard.m
@@ -439,10 +439,7 @@ UpdateKeymap(SDL_VideoData *data, SDL_bool send_event)
                 keymap[scancode] = s[0];
             }
         }
-        SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES);
-        if (send_event) {
-            SDL_SendKeymapChangedEvent();
-        }
+        SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES, send_event);
         return;
     }
 
diff --git a/src/video/directfb/SDL_DirectFB_events.c b/src/video/directfb/SDL_DirectFB_events.c
index e6ca47a..4e0ec4d 100644
--- a/src/video/directfb/SDL_DirectFB_events.c
+++ b/src/video/directfb/SDL_DirectFB_events.c
@@ -698,9 +698,9 @@ EnumKeyboards(DFBInputDeviceID device_id,
 
         SDL_GetDefaultKeymap(keymap);
 #if USE_MULTI_API
-        SDL_SetKeymap(devdata->num_keyboard, 0, keymap, SDL_NUM_SCANCODES);
+        SDL_SetKeymap(devdata->num_keyboard, 0, keymap, SDL_NUM_SCANCODES, SDL_FALSE);
 #else
-        SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES);
+        SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES, SDL_FALSE);
 #endif
         devdata->num_keyboard++;
 
diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index 08a7e1a..2b547fa 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -1111,8 +1111,7 @@ keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
     WAYLAND_xkb_keymap_key_for_each(input->xkb.keymap,
                                     Wayland_keymap_iter,
                                     &keymap);
-    SDL_SetKeymap(0, keymap.keymap, SDL_NUM_SCANCODES);
-    SDL_SendKeymapChangedEvent();
+    SDL_SetKeymap(0, keymap.keymap, SDL_NUM_SCANCODES, SDL_TRUE);
 }
 
 static void
diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index 60e80a8..4a1cfda 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -1044,8 +1044,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 #ifdef WM_INPUTLANGCHANGE
     case WM_INPUTLANGCHANGE:
         {
-            WIN_UpdateKeymap();
-            SDL_SendKeymapChangedEvent();
+            WIN_UpdateKeymap(SDL_TRUE);
         }
         returnCode = 1;
         break;
diff --git a/src/video/windows/SDL_windowskeyboard.c b/src/video/windows/SDL_windowskeyboard.c
index ac17fdf..9ff31d7 100644
--- a/src/video/windows/SDL_windowskeyboard.c
+++ b/src/video/windows/SDL_windowskeyboard.c
@@ -102,7 +102,7 @@ WIN_InitKeyboard(_THIS)
     data->ime_uielemsink = 0;
     data->ime_ippasink = 0;
 
-    WIN_UpdateKeymap();
+    WIN_UpdateKeymap(SDL_FALSE);
 
     SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
     SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Windows");
@@ -115,7 +115,7 @@ WIN_InitKeyboard(_THIS)
 }
 
 void
-WIN_UpdateKeymap()
+WIN_UpdateKeymap(SDL_bool send_event)
 {
     int i;
     SDL_Scancode scancode;
@@ -152,7 +152,7 @@ WIN_UpdateKeymap()
         }
     }
 
-    SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES);
+    SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES, send_event);
 }
 
 void
diff --git a/src/video/windows/SDL_windowskeyboard.h b/src/video/windows/SDL_windowskeyboard.h
index 57c4ffa..c9b5e10 100644
--- a/src/video/windows/SDL_windowskeyboard.h
+++ b/src/video/windows/SDL_windowskeyboard.h
@@ -24,7 +24,7 @@
 #define SDL_windowskeyboard_h_
 
 extern void WIN_InitKeyboard(_THIS);
-extern void WIN_UpdateKeymap(void);
+extern void WIN_UpdateKeymap(SDL_bool send_event);
 extern void WIN_QuitKeyboard(_THIS);
 
 extern void WIN_ResetDeadKeys(void);
diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c
index 6e3c067..b347b07 100644
--- a/src/video/x11/SDL_x11events.c
+++ b/src/video/x11/SDL_x11events.c
@@ -842,8 +842,7 @@ X11_DispatchEvent(_THIS, XEvent *xevent)
                 X11_XRefreshKeyboardMapping(&xevent->xmapping);
             }
 
-            X11_UpdateKeymap(_this);
-            SDL_SendKeymapChangedEvent();
+            X11_UpdateKeymap(_this, SDL_TRUE);
         } else if (xevent->type == PropertyNotify && videodata && videodata->windowlist) {
             char* name_of_atom = X11_XGetAtomName(display, xevent->xproperty.atom);
 
@@ -1470,8 +1469,7 @@ X11_DispatchEvent(_THIS, XEvent *xevent)
                    icon). Since it changes the XKLAVIER_STATE property, we
                    notice and reinit our keymap here. This might not be the
                    right approach, but it seems to work. */
-                X11_UpdateKeymap(_this);
-                SDL_SendKeymapChangedEvent();
+                X11_UpdateKeymap(_this, SDL_TRUE);
             } else if (xevent->xproperty.atom == videodata->_NET_FRAME_EXTENTS) {
                 Atom type;
                 int format;
diff --git a/src/video/x11/SDL_x11keyboard.c b/src/video/x11/SDL_x11keyboard.c
index 6da6c7d..c14e13d 100644
--- a/src/video/x11/SDL_x11keyboard.c
+++ b/src/video/x11/SDL_x11keyboard.c
@@ -394,7 +394,7 @@ X11_InitKeyboard(_THIS)
         }
     }
 
-    X11_UpdateKeymap(_this);
+    X11_UpdateKeymap(_this, SDL_FALSE);
 
     SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
 
@@ -408,7 +408,7 @@ X11_InitKeyboard(_THIS)
 }
 
 void
-X11_UpdateKeymap(_THIS)
+X11_UpdateKeymap(_THIS, SDL_bool send_event)
 {
     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
     int i;
@@ -468,7 +468,7 @@ X11_UpdateKeymap(_THIS)
             }
         }
     }
-    SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES);
+    SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES, send_event);
 }
 
 void
diff --git a/src/video/x11/SDL_x11keyboard.h b/src/video/x11/SDL_x11keyboard.h
index 9e20ae1..4ce4106 100644
--- a/src/video/x11/SDL_x11keyboard.h
+++ b/src/video/x11/SDL_x11keyboard.h
@@ -24,7 +24,7 @@
 #define SDL_x11keyboard_h_
 
 extern int X11_InitKeyboard(_THIS);
-extern void X11_UpdateKeymap(_THIS);
+extern void X11_UpdateKeymap(_THIS, SDL_bool send_event);
 extern void X11_QuitKeyboard(_THIS);
 extern void X11_StartTextInput(_THIS);
 extern void X11_StopTextInput(_THIS);