SDL: events: Add function to send keystrokes and not update the modifier state

From d2917918c099240e1610668f75b7c3d26f0b8819 Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Fri, 30 Dec 2022 10:06:00 -0500
Subject: [PATCH] events: Add function to send keystrokes and not update the
 modifier state

Add SDL_SendKeyboardKeyIgnoreModifiers() function and repurpose the source parameter for the SDL_SendKeyboardKeyInternal() function to use as a generic set of keyboard flags.
---
 src/events/SDL_keyboard.c   | 104 ++++++++++++++++++++----------------
 src/events/SDL_keyboard_c.h |   1 +
 2 files changed, 60 insertions(+), 45 deletions(-)

diff --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c
index 09486250e6fb..26c83a39427b 100644
--- a/src/events/SDL_keyboard.c
+++ b/src/events/SDL_keyboard.c
@@ -30,8 +30,14 @@
 
 /* Global keyboard information */
 
-#define KEYBOARD_HARDWARE    0x01
-#define KEYBOARD_AUTORELEASE 0x02
+typedef enum
+{
+    KEYBOARD_HARDWARE = 0x01,
+    KEYBOARD_AUTORELEASE = 0x02,
+    KEYBOARD_IGNOREMODIFIERS = 0x04
+} SDL_KeyboardFlags;
+
+#define KEYBOARD_SOURCE_MASK (KEYBOARD_HARDWARE | KEYBOARD_AUTORELEASE)
 
 typedef struct SDL_Keyboard SDL_Keyboard;
 
@@ -789,13 +795,14 @@ void SDL_SetKeyboardFocus(SDL_Window *window)
     }
 }
 
-static int SDL_SendKeyboardKeyInternal(Uint64 timestamp, Uint8 source, Uint8 state, SDL_Scancode scancode, SDL_Keycode keycode)
+static int SDL_SendKeyboardKeyInternal(Uint64 timestamp, SDL_KeyboardFlags flags, Uint8 state, SDL_Scancode scancode, SDL_Keycode keycode)
 {
     SDL_Keyboard *keyboard = &SDL_keyboard;
     int posted;
     SDL_Keymod modifier;
     Uint32 type;
     Uint8 repeat = SDL_FALSE;
+    const Uint8 source = flags & KEYBOARD_SOURCE_MASK;
 
     if (scancode == SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) {
         return 0;
@@ -848,55 +855,57 @@ static int SDL_SendKeyboardKeyInternal(Uint64 timestamp, Uint8 source, Uint8 sta
     }
 
     /* Update modifiers state if applicable */
-    switch (keycode) {
-    case SDLK_LCTRL:
-        modifier = SDL_KMOD_LCTRL;
-        break;
-    case SDLK_RCTRL:
-        modifier = SDL_KMOD_RCTRL;
-        break;
-    case SDLK_LSHIFT:
-        modifier = SDL_KMOD_LSHIFT;
-        break;
-    case SDLK_RSHIFT:
-        modifier = SDL_KMOD_RSHIFT;
-        break;
-    case SDLK_LALT:
-        modifier = SDL_KMOD_LALT;
-        break;
-    case SDLK_RALT:
-        modifier = SDL_KMOD_RALT;
-        break;
-    case SDLK_LGUI:
-        modifier = SDL_KMOD_LGUI;
-        break;
-    case SDLK_RGUI:
-        modifier = SDL_KMOD_RGUI;
-        break;
-    case SDLK_MODE:
-        modifier = SDL_KMOD_MODE;
-        break;
-    default:
-        modifier = SDL_KMOD_NONE;
-        break;
-    }
-    if (SDL_KEYDOWN == type) {
+    if (!(flags & KEYBOARD_IGNOREMODIFIERS)) {
         switch (keycode) {
-        case SDLK_NUMLOCKCLEAR:
-            keyboard->modstate ^= SDL_KMOD_NUM;
+        case SDLK_LCTRL:
+            modifier = SDL_KMOD_LCTRL;
+            break;
+        case SDLK_RCTRL:
+            modifier = SDL_KMOD_RCTRL;
+            break;
+        case SDLK_LSHIFT:
+            modifier = SDL_KMOD_LSHIFT;
             break;
-        case SDLK_CAPSLOCK:
-            keyboard->modstate ^= SDL_KMOD_CAPS;
+        case SDLK_RSHIFT:
+            modifier = SDL_KMOD_RSHIFT;
             break;
-        case SDLK_SCROLLLOCK:
-            keyboard->modstate ^= SDL_KMOD_SCROLL;
+        case SDLK_LALT:
+            modifier = SDL_KMOD_LALT;
+            break;
+        case SDLK_RALT:
+            modifier = SDL_KMOD_RALT;
+            break;
+        case SDLK_LGUI:
+            modifier = SDL_KMOD_LGUI;
+            break;
+        case SDLK_RGUI:
+            modifier = SDL_KMOD_RGUI;
+            break;
+        case SDLK_MODE:
+            modifier = SDL_KMOD_MODE;
             break;
         default:
-            keyboard->modstate |= modifier;
+            modifier = SDL_KMOD_NONE;
             break;
         }
-    } else {
-        keyboard->modstate &= ~modifier;
+        if (SDL_KEYDOWN == type) {
+            switch (keycode) {
+            case SDLK_NUMLOCKCLEAR:
+                keyboard->modstate ^= SDL_KMOD_NUM;
+                break;
+            case SDLK_CAPSLOCK:
+                keyboard->modstate ^= SDL_KMOD_CAPS;
+                break;
+            case SDLK_SCROLLLOCK:
+                keyboard->modstate ^= SDL_KMOD_SCROLL;
+                break;
+            default:
+                keyboard->modstate |= modifier;
+                break;
+            }
+        } else {
+            keyboard->modstate &= ~modifier;
+        }
     }
 
     /* Post the event, if desired */
@@ -973,6 +982,11 @@ int SDL_SendKeyboardKeyAutoRelease(Uint64 timestamp, SDL_Scancode scancode)
     return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_AUTORELEASE, SDL_PRESSED, scancode, SDLK_UNKNOWN);
 }
 
+int SDL_SendKeyboardKeyIgnoreModifiers(Uint64 timestamp, Uint8 state, SDL_Scancode scancode)
+{
+    return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE | KEYBOARD_IGNOREMODIFIERS, state, scancode, SDLK_UNKNOWN);
+}
+
 void SDL_ReleaseAutoReleaseKeys(void)
 {
     SDL_Keyboard *keyboard = &SDL_keyboard;
diff --git a/src/events/SDL_keyboard_c.h b/src/events/SDL_keyboard_c.h
index acf788be8e69..fe9a8cbc1eda 100644
--- a/src/events/SDL_keyboard_c.h
+++ b/src/events/SDL_keyboard_c.h
@@ -52,6 +52,7 @@ extern int SDL_SendKeyboardUnicodeKey(Uint64 timestamp, Uint32 ch);
 /* Send a keyboard key event */
 extern int SDL_SendKeyboardKey(Uint64 timestamp, Uint8 state, SDL_Scancode scancode);
 extern int SDL_SendKeyboardKeyAutoRelease(Uint64 timestamp, SDL_Scancode scancode);
+extern int SDL_SendKeyboardKeyIgnoreModifiers(Uint64 timestamp, Uint8 state, SDL_Scancode scancode);
 
 /* This is for platforms that don't know the keymap but can report scancode and keycode directly.
    Most platforms should prefer to optionally call SDL_SetKeymap and then use SDL_SendKeyboardKey. */