SDL: Don't send fake key events while processing real ones on Android

From e19a56f4d5440f645c09666c3a315cc8dbd0e4a2 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 14 Jan 2025 18:53:36 -0800
Subject: [PATCH] Don't send fake key events while processing real ones on
 Android

Fixes https://github.com/libsdl-org/SDL/issues/11350
---
 .../main/java/org/libsdl/app/SDLActivity.java | 13 +++++++++--
 .../org/libsdl/app/SDLInputConnection.java    | 22 ++++++++++---------
 2 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
index 82f64dde46ba7..75a3df9c1565f 100644
--- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
+++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
@@ -231,6 +231,7 @@ public enum NativeState {
     protected static boolean mSDLMainFinished = false;
     protected static boolean mActivityCreated = false;
     private static SDLFileDialogState mFileDialogState = null;
+    protected static boolean mDispatchingKeyEvent = false;
 
     protected static SDLGenericMotionListener_API14 getMotionListener() {
         if (mMotionListener == null) {
@@ -807,7 +808,14 @@ public boolean dispatchKeyEvent(KeyEvent event) {
             ) {
             return false;
         }
-        return super.dispatchKeyEvent(event);
+        mDispatchingKeyEvent = true;
+        boolean result = super.dispatchKeyEvent(event);
+        mDispatchingKeyEvent = false;
+        return result;
+    }
+
+    public static boolean dispatchingKeyEvent() {
+        return mDispatchingKeyEvent;
     }
 
     /* Transition to next state */
@@ -1507,6 +1515,8 @@ public static boolean handleKeyEvent(View v, int keyCode, KeyEvent event, InputC
         }
 
         if (event.getAction() == KeyEvent.ACTION_DOWN) {
+            onNativeKeyDown(keyCode);
+
             if (isTextInputEvent(event)) {
                 if (ic != null) {
                     ic.commitText(String.valueOf((char) event.getUnicodeChar()), 1);
@@ -1514,7 +1524,6 @@ public static boolean handleKeyEvent(View v, int keyCode, KeyEvent event, InputC
                     SDLInputConnection.nativeCommitText(String.valueOf((char) event.getUnicodeChar()), 1);
                 }
             }
-            onNativeKeyDown(keyCode);
             return true;
         } else if (event.getAction() == KeyEvent.ACTION_UP) {
             onNativeKeyUp(keyCode);
diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLInputConnection.java b/android-project/app/src/main/java/org/libsdl/app/SDLInputConnection.java
index e1d29a8890e2d..accce4ba3f657 100644
--- a/android-project/app/src/main/java/org/libsdl/app/SDLInputConnection.java
+++ b/android-project/app/src/main/java/org/libsdl/app/SDLInputConnection.java
@@ -111,18 +111,20 @@ protected void updateText() {
 
         if (matchLength < text.length()) {
             String pendingText = text.subSequence(matchLength, text.length()).toString();
-            for (offset = 0; offset < pendingText.length(); ) {
-                int codePoint = pendingText.codePointAt(offset);
-                if (codePoint == '\n') {
-                    if (SDLActivity.onNativeSoftReturnKey()) {
-                        return;
+            if (!SDLActivity.dispatchingKeyEvent()) {
+                for (offset = 0; offset < pendingText.length(); ) {
+                    int codePoint = pendingText.codePointAt(offset);
+                    if (codePoint == '\n') {
+                        if (SDLActivity.onNativeSoftReturnKey()) {
+                            return;
+                        }
                     }
+                    /* Higher code points don't generate simulated scancodes */
+                    if (codePoint > 0 && codePoint < 128) {
+                        nativeGenerateScancodeForUnichar((char)codePoint);
+                    }
+                    offset += Character.charCount(codePoint);
                 }
-                /* Higher code points don't generate simulated scancodes */
-                if (codePoint < 128) {
-                    nativeGenerateScancodeForUnichar((char)codePoint);
-                }
-                offset += Character.charCount(codePoint);
             }
             SDLInputConnection.nativeCommitText(pendingText, 0);
         }