SDL: #6433 Fix WINRT_IsScreenKeyboardShown on Xbox

From 8db3a33872cfbefcdfb059beea92338a7873f89e Mon Sep 17 00:00:00 2001
From: Thomas Cashman <[EMAIL REDACTED]>
Date: Sun, 23 Oct 2022 15:45:20 +0100
Subject: [PATCH] #6433 Fix WINRT_IsScreenKeyboardShown on Xbox

---
 src/video/winrt/SDL_winrtevents_c.h   |  1 +
 src/video/winrt/SDL_winrtkeyboard.cpp | 50 +++++++++++++++++++++++----
 src/video/winrt/SDL_winrtvideo.cpp    |  2 ++
 3 files changed, 46 insertions(+), 7 deletions(-)

diff --git a/src/video/winrt/SDL_winrtevents_c.h b/src/video/winrt/SDL_winrtevents_c.h
index 112318024f8f..67c18b86569a 100644
--- a/src/video/winrt/SDL_winrtevents_c.h
+++ b/src/video/winrt/SDL_winrtevents_c.h
@@ -68,6 +68,7 @@ extern void WINRT_ProcessKeyUpEvent(Windows::UI::Core::KeyEventArgs ^args);
 extern void WINRT_ProcessCharacterReceivedEvent(Windows::UI::Core::CharacterReceivedEventArgs ^args);
 
 #if NTDDI_VERSION >= NTDDI_WIN10
+extern void WINTRT_InitialiseInputPaneEvents(_THIS);
 extern SDL_bool WINRT_HasScreenKeyboardSupport(_THIS);
 extern void WINRT_ShowScreenKeyboard(_THIS, SDL_Window *window);
 extern void WINRT_HideScreenKeyboard(_THIS, SDL_Window *window);
diff --git a/src/video/winrt/SDL_winrtkeyboard.cpp b/src/video/winrt/SDL_winrtkeyboard.cpp
index 40681cb8a398..f6ff0a409b46 100644
--- a/src/video/winrt/SDL_winrtkeyboard.cpp
+++ b/src/video/winrt/SDL_winrtkeyboard.cpp
@@ -386,6 +386,30 @@ WINRT_ProcessCharacterReceivedEvent(Windows::UI::Core::CharacterReceivedEventArg
 
 #if NTDDI_VERSION >= NTDDI_WIN10
 
+static bool WINRT_InputPaneVisible = false;
+
+void WINTRT_OnInputPaneShowing(Windows::UI::ViewManagement::InputPane ^ sender, Windows::UI::ViewManagement::InputPaneVisibilityEventArgs ^ args)
+{
+    WINRT_InputPaneVisible = true;
+}
+
+void WINTRT_OnInputPaneHiding(Windows::UI::ViewManagement::InputPane ^ sender, Windows::UI::ViewManagement::InputPaneVisibilityEventArgs ^ args)
+{
+    WINRT_InputPaneVisible = false;
+}
+
+void WINTRT_InitialiseInputPaneEvents(_THIS)
+{
+    using namespace Windows::UI::ViewManagement;
+    InputPane ^ inputPane = InputPane::GetForCurrentView();
+    if (inputPane) {
+        inputPane->Showing += ref new Windows::Foundation::TypedEventHandler<Windows::UI::ViewManagement::InputPane ^, 
+            Windows::UI::ViewManagement::InputPaneVisibilityEventArgs ^>(&WINTRT_OnInputPaneShowing);
+        inputPane->Hiding += ref new Windows::Foundation::TypedEventHandler<Windows::UI::ViewManagement::InputPane ^, 
+            Windows::UI::ViewManagement::InputPaneVisibilityEventArgs ^>(&WINTRT_OnInputPaneHiding);
+    }
+}
+
 SDL_bool WINRT_HasScreenKeyboardSupport(_THIS)
 {
     return SDL_TRUE;
@@ -414,12 +438,24 @@ SDL_bool WINRT_IsScreenKeyboardShown(_THIS, SDL_Window *window)
     using namespace Windows::UI::ViewManagement;
     InputPane ^ inputPane = InputPane::GetForCurrentView();
     if (inputPane) {
-        // dludwig@pobox.com: checking inputPane->Visible doesn't seem to detect visibility,
-        //   at least not on the Windows Phone 10.0.10240.0 emulator.  Checking
-        //   the size of inputPane->OccludedRect, however, does seem to work.
-        Windows::Foundation::Rect rect = inputPane->OccludedRect;
-        if (rect.Width > 0 && rect.Height > 0) {
-            return SDL_TRUE;
+        switch (SDL_WinRTGetDeviceFamily()) {
+        case SDL_WINRT_DEVICEFAMILY_XBOX:
+            //Documentation recommends using inputPane->Visible 
+            //https://learn.microsoft.com/en-us/uwp/api/windows.ui.viewmanagement.inputpane.visible?view=winrt-22621
+            //This does not seem to work on latest UWP/Xbox.
+            //Workaround: Listen to Showing/Hiding events
+            if (WINRT_InputPaneVisible) {
+                return SDL_TRUE;
+            }
+            break;
+        default:
+            //OccludedRect is recommend on universal apps per docs
+            //https://learn.microsoft.com/en-us/uwp/api/windows.ui.viewmanagement.inputpane.visible?view=winrt-22621
+            Windows::Foundation::Rect rect = inputPane->OccludedRect;
+            if (rect.Width > 0 && rect.Height > 0) {
+                return SDL_TRUE;
+            }
+            break;
         }
     }
     return SDL_FALSE;
@@ -427,4 +463,4 @@ SDL_bool WINRT_IsScreenKeyboardShown(_THIS, SDL_Window *window)
 
 #endif  // NTDDI_VERSION >= ...
 
-#endif // SDL_VIDEO_DRIVER_WINRT
+#endif // SDL_VIDEO_DRIVER_WINRT
\ No newline at end of file
diff --git a/src/video/winrt/SDL_winrtvideo.cpp b/src/video/winrt/SDL_winrtvideo.cpp
index a71ba9b07978..3a7b220b9e82 100644
--- a/src/video/winrt/SDL_winrtvideo.cpp
+++ b/src/video/winrt/SDL_winrtvideo.cpp
@@ -154,6 +154,8 @@ WINRT_CreateDevice(void)
     device->ShowScreenKeyboard = WINRT_ShowScreenKeyboard;
     device->HideScreenKeyboard = WINRT_HideScreenKeyboard;
     device->IsScreenKeyboardShown = WINRT_IsScreenKeyboardShown;
+
+    WINTRT_InitialiseInputPaneEvents(device);
 #endif
 
 #ifdef SDL_VIDEO_OPENGL_EGL