SDL: Add `SetTextInputProperties` to video device API and fix iOS handling

From 972c6d0b8275e9f000b7a7fa461becc109ec1e40 Mon Sep 17 00:00:00 2001
From: Salman Alshamrani <[EMAIL REDACTED]>
Date: Sat, 9 Nov 2024 08:17:43 -0500
Subject: [PATCH] Add `SetTextInputProperties` to video device API and fix iOS
 handling

---
 src/video/SDL_sysvideo.h                  |  1 +
 src/video/SDL_video.c                     |  4 ++++
 src/video/uikit/SDL_uikitvideo.m          |  1 +
 src/video/uikit/SDL_uikitviewcontroller.h |  1 +
 src/video/uikit/SDL_uikitviewcontroller.m | 24 ++++++++++++++++++++++-
 5 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index 12c4213d766fd..38b27a7a37578 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -352,6 +352,7 @@ struct SDL_VideoDevice
     bool (*HasScreenKeyboardSupport)(SDL_VideoDevice *_this);
     void (*ShowScreenKeyboard)(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
     void (*HideScreenKeyboard)(SDL_VideoDevice *_this, SDL_Window *window);
+    void (*SetTextInputProperties)(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
     bool (*IsScreenKeyboardShown)(SDL_VideoDevice *_this, SDL_Window *window);
 
     // Clipboard
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 819bd13fc1427..89c7294fbc157 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -5299,6 +5299,10 @@ bool SDL_StartTextInputWithProperties(SDL_Window *window, SDL_PropertiesID props
         }
     }
 
+    if (_this->SetTextInputProperties) {
+        _this->SetTextInputProperties(_this, window, props);
+    }
+
     // Show the on-screen keyboard, if desired
     if (AutoShowingScreenKeyboard() && !SDL_ScreenKeyboardShown(window)) {
         if (_this->ShowScreenKeyboard) {
diff --git a/src/video/uikit/SDL_uikitvideo.m b/src/video/uikit/SDL_uikitvideo.m
index d492178b8151f..de134147f0007 100644
--- a/src/video/uikit/SDL_uikitvideo.m
+++ b/src/video/uikit/SDL_uikitvideo.m
@@ -99,6 +99,7 @@ static void UIKit_DeleteDevice(SDL_VideoDevice *device)
         device->HasScreenKeyboardSupport = UIKit_HasScreenKeyboardSupport;
         device->StartTextInput = UIKit_StartTextInput;
         device->StopTextInput = UIKit_StopTextInput;
+        device->SetTextInputProperties = UIKit_SetTextInputProperties;
         device->IsScreenKeyboardShown = UIKit_IsScreenKeyboardShown;
         device->UpdateTextInputArea = UIKit_UpdateTextInputArea;
 #endif
diff --git a/src/video/uikit/SDL_uikitviewcontroller.h b/src/video/uikit/SDL_uikitviewcontroller.h
index dd22e780c7a54..997dc977c5c75 100644
--- a/src/video/uikit/SDL_uikitviewcontroller.h
+++ b/src/video/uikit/SDL_uikitviewcontroller.h
@@ -90,6 +90,7 @@
 bool UIKit_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
 bool UIKit_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
 bool UIKit_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window);
+void UIKit_SetTextInputProperties(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
 bool UIKit_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);
 bool UIKit_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window);
 #endif
diff --git a/src/video/uikit/SDL_uikitviewcontroller.m b/src/video/uikit/SDL_uikitviewcontroller.m
index 832ee33ecbdcb..c7628e13d575e 100644
--- a/src/video/uikit/SDL_uikitviewcontroller.m
+++ b/src/video/uikit/SDL_uikitviewcontroller.m
@@ -470,6 +470,21 @@ - (void)setTextFieldProperties:(SDL_PropertiesID) props
     } else {
         textField.enablesReturnKeyAutomatically = NO;
     }
+
+    if (!textField.window) {
+        /* textField has not been added to the view yet,
+         we don't have to do anything. */
+        return;
+    }
+
+    // the text field needs to be re-added to the view in order to update correctly.
+    UIView *superview = textField.superview;
+    [textField removeFromSuperview];
+    [superview addSubview:textField];
+
+    if (SDL_TextInputActive(window)) {
+        [textField becomeFirstResponder];
+    }
 }
 
 /* requests the SDL text field to become focused and accept text input.
@@ -672,7 +687,6 @@ bool UIKit_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_Proper
 {
     @autoreleasepool {
         SDL_uikitviewcontroller *vc = GetWindowViewController(window);
-        [vc setTextFieldProperties:props];
         return [vc startTextInput];
     }
 }
@@ -685,6 +699,14 @@ bool UIKit_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window)
     }
 }
 
+void UIKit_SetTextInputProperties(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
+{
+    @autoreleasepool {
+        SDL_uikitviewcontroller *vc = GetWindowViewController(window);
+        [vc setTextFieldProperties:props];
+    }
+}
+
 bool UIKit_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window)
 {
     @autoreleasepool {