SDL: Only do work to process text events if text input is active

From fa236f169baa1faa2a8dad4ce4e0b2d11cc589f5 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 25 Mar 2024 12:49:09 -0700
Subject: [PATCH] Only do work to process text events if text input is active

Fixes https://github.com/libsdl-org/SDL/issues/9353
---
 src/events/SDL_keyboard.c                   |  8 +++
 src/video/emscripten/SDL_emscriptenevents.c | 11 +--
 src/video/wayland/SDL_waylandevents.c       |  4 +-
 src/video/windows/SDL_windowsevents.c       | 43 ++++++-----
 src/video/winrt/SDL_winrtkeyboard.cpp       | 40 ++++++-----
 src/video/x11/SDL_x11events.c               | 80 +++++++++++----------
 6 files changed, 106 insertions(+), 80 deletions(-)

diff --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c
index 871d45a737b49..2f1ea4f1d8782 100644
--- a/src/events/SDL_keyboard.c
+++ b/src/events/SDL_keyboard.c
@@ -1180,6 +1180,10 @@ int SDL_SendKeyboardText(const char *text)
     SDL_Keyboard *keyboard = &SDL_keyboard;
     int posted;
 
+    if (!SDL_TextInputActive()) {
+        return 0;
+    }
+
     /* Don't post text events for unprintable characters */
     if (SDL_iscntrl((unsigned char)*text)) {
         return 0;
@@ -1210,6 +1214,10 @@ int SDL_SendEditingText(const char *text, int start, int length)
     SDL_Keyboard *keyboard = &SDL_keyboard;
     int posted;
 
+    if (!SDL_TextInputActive()) {
+        return 0;
+    }
+
     /* Post the event, if desired */
     posted = 0;
     if (SDL_EventEnabled(SDL_EVENT_TEXT_EDITING)) {
diff --git a/src/video/emscripten/SDL_emscriptenevents.c b/src/video/emscripten/SDL_emscriptenevents.c
index c67a8f3c5155b..5eef448516c55 100644
--- a/src/video/emscripten/SDL_emscriptenevents.c
+++ b/src/video/emscripten/SDL_emscriptenevents.c
@@ -837,11 +837,14 @@ static EM_BOOL Emscripten_HandleKey(int eventType, const EmscriptenKeyboardEvent
 
 static EM_BOOL Emscripten_HandleKeyPress(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
 {
-    char text[5];
-    if (Emscripten_ConvertUTF32toUTF8(keyEvent->charCode, text)) {
-        SDL_SendKeyboardText(text);
+    if (SDL_TextInputActive()) {
+        char text[5];
+        if (Emscripten_ConvertUTF32toUTF8(keyEvent->charCode, text)) {
+            SDL_SendKeyboardText(text);
+        }
+        return EM_TRUE;
     }
-    return SDL_EventEnabled(SDL_EVENT_TEXT_INPUT);
+    return EM_FALSE;
 }
 
 static EM_BOOL Emscripten_HandleFullscreenChange(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent, void *userData)
diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index 3b284f5ef214e..c73197bd8edef 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -1605,7 +1605,9 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
     Wayland_UpdateImplicitGrabSerial(input, serial);
 
     if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
-        has_text = keyboard_input_get_text(text, input, key, SDL_PRESSED, &handled_by_ime);
+        if (SDL_TextInputActive()) {
+            has_text = keyboard_input_get_text(text, input, key, SDL_PRESSED, &handled_by_ime);
+        }
     } else {
         if (keyboard_repeat_key_is_set(&input->keyboard_repeat, key)) {
             /* Send any due key repeat events before stopping the repeat and generating the key up event.
diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index 96dfcb07ca4cb..b7c8af6743657 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -1164,33 +1164,40 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
         if (wParam == UNICODE_NOCHAR) {
             returnCode = 1;
         } else {
-            char text[5];
-            if (SDL_UCS4ToUTF8((Uint32)wParam, text) != text) {
-                SDL_SendKeyboardText(text);
+            if (SDL_TextInputActive()) {
+                char text[5];
+                if (SDL_UCS4ToUTF8((Uint32)wParam, text) != text) {
+                    SDL_SendKeyboardText(text);
+                }
             }
             returnCode = 0;
         }
         break;
 
     case WM_CHAR:
-        /* Characters outside Unicode Basic Multilingual Plane (BMP)
-         * are coded as so called "surrogate pair" in two separate UTF-16 character events.
-         * Cache high surrogate until next character event. */
-        if (IS_HIGH_SURROGATE(wParam)) {
-            data->high_surrogate = (WCHAR)wParam;
-        } else {
-            WCHAR utf16[3];
+        if (SDL_TextInputActive()) {
+            /* Characters outside Unicode Basic Multilingual Plane (BMP)
+             * are coded as so called "surrogate pair" in two separate UTF-16 character events.
+             * Cache high surrogate until next character event. */
+            if (IS_HIGH_SURROGATE(wParam)) {
+                data->high_surrogate = (WCHAR)wParam;
+            } else {
+                if (SDL_TextInputActive()) {
+                    WCHAR utf16[3];
 
-            utf16[0] = data->high_surrogate ? data->high_surrogate : (WCHAR)wParam;
-            utf16[1] = data->high_surrogate ? (WCHAR)wParam : L'\0';
-            utf16[2] = L'\0';
+                    utf16[0] = data->high_surrogate ? data->high_surrogate : (WCHAR)wParam;
+                    utf16[1] = data->high_surrogate ? (WCHAR)wParam : L'\0';
+                    utf16[2] = L'\0';
 
-            char utf8[5];
-            int result = WIN_WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, utf16, -1, utf8, sizeof(utf8), NULL, NULL);
-            if (result > 0) {
-                SDL_SendKeyboardText(utf8);
+                    char utf8[5];
+                    int result = WIN_WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, utf16, -1, utf8, sizeof(utf8), NULL, NULL);
+                    if (result > 0) {
+                        SDL_SendKeyboardText(utf8);
+                    }
+                }
+                data->high_surrogate = L'\0';
             }
-
+        } else {
             data->high_surrogate = L'\0';
         }
 
diff --git a/src/video/winrt/SDL_winrtkeyboard.cpp b/src/video/winrt/SDL_winrtkeyboard.cpp
index 6f088ec172c18..28013413a1b32 100644
--- a/src/video/winrt/SDL_winrtkeyboard.cpp
+++ b/src/video/winrt/SDL_winrtkeyboard.cpp
@@ -88,25 +88,29 @@ void WINRT_ProcessCharacterReceivedEvent(SDL_Window *window, Windows::UI::Core::
 
     SDL_WindowData *data = window->driverdata;
 
-    /* Characters outside Unicode Basic Multilingual Plane (BMP)
-     * are coded as so called "surrogate pair" in two separate UTF-16 character events.
-     * Cache high surrogate until next character event. */
-    if (IS_HIGH_SURROGATE(args->KeyCode)) {
-        data->high_surrogate = (WCHAR)args->KeyCode;
-    } else {
-        WCHAR utf16[] = {
-            data->high_surrogate ? data->high_surrogate : (WCHAR)args->KeyCode,
-            data->high_surrogate ? (WCHAR)args->KeyCode : L'\0',
-            L'\0'
-        };
-
-        char utf8[5];
-        // doesn't need to be WIN_WideCharToMultiByte, since we don't care about WinXP support in WinRT.
-        int result = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, utf16, -1, utf8, sizeof(utf8), NULL, NULL);
-        if (result > 0) {
-            SDL_SendKeyboardText(utf8);
-        }
+    if (SDL_TextInputActive()) {
+        /* Characters outside Unicode Basic Multilingual Plane (BMP)
+         * are coded as so called "surrogate pair" in two separate UTF-16 character events.
+         * Cache high surrogate until next character event. */
+        if (IS_HIGH_SURROGATE(args->KeyCode)) {
+            data->high_surrogate = (WCHAR)args->KeyCode;
+        } else {
+            WCHAR utf16[] = {
+                data->high_surrogate ? data->high_surrogate : (WCHAR)args->KeyCode,
+                data->high_surrogate ? (WCHAR)args->KeyCode : L'\0',
+                L'\0'
+            };
+
+            char utf8[5];
+            // doesn't need to be WIN_WideCharToMultiByte, since we don't care about WinXP support in WinRT.
+            int result = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, utf16, -1, utf8, sizeof(utf8), NULL, NULL);
+            if (result > 0) {
+                SDL_SendKeyboardText(utf8);
+            }
 
+            data->high_surrogate = L'\0';
+        }
+    } else {
         data->high_surrogate = L'\0';
     }
 }
diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c
index 6d568a90db43e..2d24a2d9eb276 100644
--- a/src/video/x11/SDL_x11events.c
+++ b/src/video/x11/SDL_x11events.c
@@ -842,35 +842,6 @@ void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_
     Status status = 0;
     SDL_bool handled_by_ime = SDL_FALSE;
 
-    /* Save the original keycode for dead keys, which are filtered out by
-       the XFilterEvent() call below.
-    */
-    int orig_event_type = xevent->type;
-    KeyCode orig_keycode = xevent->xkey.keycode;
-
-    /* filter events catches XIM events and sends them to the correct handler */
-    if (X11_XFilterEvent(xevent, None)) {
-#if 0
-        printf("Filtered event type = %d display = %d window = %d\n",
-               xevent->type, xevent->xany.display, xevent->xany.window);
-#endif
-        /* Make sure dead key press/release events are sent */
-        /* But only if we're using one of the DBus IMEs, otherwise
-           some XIM IMEs will generate duplicate events */
-#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX)
-        SDL_Scancode scancode = videodata->key_layout[orig_keycode];
-        videodata->filter_code = orig_keycode;
-        videodata->filter_time = xevent->xkey.time;
-
-        if (orig_event_type == KeyPress) {
-            SDL_SendKeyboardKey(0, keyboardID, SDL_PRESSED, scancode);
-        } else {
-            SDL_SendKeyboardKey(0, keyboardID, SDL_RELEASED, scancode);
-        }
-#endif
-        return;
-    }
-
 #ifdef DEBUG_XEVENTS
     printf("window %p: %s (X11 keycode = 0x%X)\n", data, (xevent->type == KeyPress ? "KeyPress" : "KeyRelease"), xevent->xkey.keycode);
 #endif
@@ -885,23 +856,54 @@ void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_
     }
 #endif /* DEBUG SCANCODES */
 
-    SDL_zeroa(text);
+    text[0] = '\0';
+
+    if (SDL_TextInputActive()) {
+        /* Save the original keycode for dead keys, which are filtered out by
+           the XFilterEvent() call below.
+        */
+        int orig_event_type = xevent->type;
+        KeyCode orig_keycode = xevent->xkey.keycode;
+
+        /* filter events catches XIM events and sends them to the correct handler */
+        if (X11_XFilterEvent(xevent, None)) {
+#if 0
+            printf("Filtered event type = %d display = %d window = %d\n",
+                   xevent->type, xevent->xany.display, xevent->xany.window);
+#endif
+            /* Make sure dead key press/release events are sent */
+            /* But only if we're using one of the DBus IMEs, otherwise
+               some XIM IMEs will generate duplicate events */
+#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX)
+            SDL_Scancode scancode = videodata->key_layout[orig_keycode];
+            videodata->filter_code = orig_keycode;
+            videodata->filter_time = xevent->xkey.time;
+
+            if (orig_event_type == KeyPress) {
+                SDL_SendKeyboardKey(0, keyboardID, SDL_PRESSED, scancode);
+            } else {
+                SDL_SendKeyboardKey(0, keyboardID, SDL_RELEASED, scancode);
+            }
+#endif
+            return;
+        }
+
 #ifdef X_HAVE_UTF8_STRING
-    if (windowdata->ic && xevent->type == KeyPress) {
-        X11_Xutf8LookupString(windowdata->ic, &xevent->xkey, text, sizeof(text),
-                              &keysym, &status);
-    } else {
-        XLookupStringAsUTF8(&xevent->xkey, text, sizeof(text), &keysym, NULL);
-    }
+        if (windowdata->ic && xevent->type == KeyPress) {
+            X11_Xutf8LookupString(windowdata->ic, &xevent->xkey, text, sizeof(text),
+                                  &keysym, &status);
+        } else {
+            XLookupStringAsUTF8(&xevent->xkey, text, sizeof(text), &keysym, NULL);
+        }
 #else
-    XLookupStringAsUTF8(&xevent->xkey, text, sizeof(text), &keysym, NULL);
+        XLookupStringAsUTF8(&xevent->xkey, text, sizeof(text), &keysym, NULL);
 #endif
 
 #ifdef SDL_USE_IME
-    if (SDL_TextInputActive()) {
         handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode, (xevent->type == KeyPress ? SDL_PRESSED : SDL_RELEASED));
-    }
 #endif
+    }
+
     if (!handled_by_ime) {
         if (xevent->type == KeyPress) {
             /* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */