diff --git a/src/joystick/apple/SDL_mfijoystick.m b/src/joystick/apple/SDL_mfijoystick.m index a7ab051ebe..484891bb1b 100644 --- a/src/joystick/apple/SDL_mfijoystick.m +++ b/src/joystick/apple/SDL_mfijoystick.m @@ -26,6 +26,7 @@ #include "../hidapi/SDL_hidapijoystick_c.h" #include "../usb_ids.h" #include "../../events/SDL_events_c.h" +#include "../../video/uikit/SDL_uikitvideo.h" #include "SDL_mfijoystick_c.h" @@ -790,6 +791,10 @@ static bool IOS_JoystickInit(void) SDL_UnlockJoysticks(); }]; #endif // SDL_JOYSTICK_MFI + +#ifdef SDL_VIDEO_DRIVER_UIKIT + UIKit_SetGameControllerInteraction(true); +#endif } return true; @@ -1581,6 +1586,10 @@ static void IOS_JoystickQuit(void) while (deviceList != NULL) { IOS_RemoveJoystickDevice(deviceList); } + +#ifdef SDL_VIDEO_DRIVER_UIKIT + UIKit_SetGameControllerInteraction(false); +#endif } numjoysticks = 0; diff --git a/src/video/uikit/SDL_uikitvideo.h b/src/video/uikit/SDL_uikitvideo.h index 0f69503b2c..38d41037ce 100644 --- a/src/video/uikit/SDL_uikitvideo.h +++ b/src/video/uikit/SDL_uikitvideo.h @@ -36,19 +36,24 @@ @end #ifdef SDL_PLATFORM_VISIONOS -CGRect UIKit_ComputeViewFrame(SDL_Window *window); +extern CGRect UIKit_ComputeViewFrame(SDL_Window *window); #else -CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen); +extern CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen); #endif +extern API_AVAILABLE(ios(13.0)) UIWindowScene *UIKit_GetActiveWindowScene(void); + +extern void UIKit_SetGameControllerInteraction(bool enabled); +extern void UIKit_SetViewGameControllerInteraction(UIView *view, bool enabled); + #endif // __OBJC__ -bool UIKit_SuspendScreenSaver(SDL_VideoDevice *_this); +extern bool UIKit_SuspendScreenSaver(SDL_VideoDevice *_this); -void UIKit_ForceUpdateHomeIndicator(void); +extern void UIKit_ForceUpdateHomeIndicator(void); -bool UIKit_IsSystemVersionAtLeast(double version); +extern bool UIKit_IsSystemVersionAtLeast(double version); -SDL_SystemTheme UIKit_GetSystemTheme(void); +extern SDL_SystemTheme UIKit_GetSystemTheme(void); #endif // SDL_uikitvideo_h_ diff --git a/src/video/uikit/SDL_uikitvideo.m b/src/video/uikit/SDL_uikitvideo.m index aaa1d5076a..2cca9bc0c2 100644 --- a/src/video/uikit/SDL_uikitvideo.m +++ b/src/video/uikit/SDL_uikitvideo.m @@ -23,6 +23,7 @@ #ifdef SDL_VIDEO_DRIVER_UIKIT #import +#import #include "../SDL_sysvideo.h" #include "../SDL_pixels_c.h" @@ -210,7 +211,8 @@ SDL_SystemTheme UIKit_GetSystemTheme(void) } #ifdef SDL_PLATFORM_VISIONOS -CGRect UIKit_ComputeViewFrame(SDL_Window *window){ +CGRect UIKit_ComputeViewFrame(SDL_Window *window) +{ return CGRectMake(window->x, window->y, window->w, window->h); } #else @@ -251,8 +253,80 @@ CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen) return frame; } +#endif // SDL_PLATFORM_VISIONOS -#endif +UIWindowScene *UIKit_GetActiveWindowScene(void) +{ + if (@available(iOS 13.0, tvOS 13.0, *)) { + NSSet *connectedScenes = [UIApplication sharedApplication].connectedScenes; + + // First, try to find an active foreground scene + for (UIScene *scene in connectedScenes) { + if ([scene isKindOfClass:[UIWindowScene class]]) { + UIWindowScene *windowScene = (UIWindowScene *)scene; + if (windowScene.activationState == UISceneActivationStateForegroundActive) { + return windowScene; + } + } + } + + // If no active scene, return any foreground scene + for (UIScene *scene in connectedScenes) { + if ([scene isKindOfClass:[UIWindowScene class]]) { + UIWindowScene *windowScene = (UIWindowScene *)scene; + if (windowScene.activationState == UISceneActivationStateForegroundInactive) { + return windowScene; + } + } + } + + // Last resort: return first window scene + for (UIScene *scene in connectedScenes) { + if ([scene isKindOfClass:[UIWindowScene class]]) { + return (UIWindowScene *)scene; + } + } + } + + return nil; +} + +void UIKit_SetGameControllerInteraction(bool enabled) +{ + if (@available(iOS 13.0, tvOS 13.0, *)) { + UIWindowScene *scene = UIKit_GetActiveWindowScene(); + if (scene == nil) { + return; + } + + for (UIWindow *window in scene.windows) { + UIKit_SetViewGameControllerInteraction(window, enabled); + } + } +} + +void UIKit_SetViewGameControllerInteraction(UIView *view, bool enabled) +{ +#ifndef SDL_PLATFORM_TVOS + if (@available(iOS 18.0, visionOS 2.0, *)) { + if (enabled) { + GCEventInteraction *interaction = [[GCEventInteraction alloc] init]; + interaction.handledEventTypes = GCUIEventTypeGamepad; + [view addInteraction:interaction]; + } else { + for (id entry in view.interactions) { + if ([entry isKindOfClass:[GCEventInteraction class]]) { + GCEventInteraction *interaction = (GCEventInteraction *)entry; + if (interaction.handledEventTypes == GCUIEventTypeGamepad) { + [view removeInteraction:interaction]; + break; + } + } + } + } + } +#endif // !SDL_PLATFORM_TVOS +} void UIKit_ForceUpdateHomeIndicator(void) { diff --git a/src/video/uikit/SDL_uikitviewcontroller.m b/src/video/uikit/SDL_uikitviewcontroller.m index 6bdefae955..845c0d3686 100644 --- a/src/video/uikit/SDL_uikitviewcontroller.m +++ b/src/video/uikit/SDL_uikitviewcontroller.m @@ -341,6 +341,10 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char { [super setView:view]; + if (SDL_WasInit(SDL_INIT_JOYSTICK)) { + UIKit_SetViewGameControllerInteraction(view, true); + } + [view addSubview:textField]; if (textFieldFocused) { diff --git a/src/video/uikit/SDL_uikitwindow.m b/src/video/uikit/SDL_uikitwindow.m index 22a863e61f..b16319ef84 100644 --- a/src/video/uikit/SDL_uikitwindow.m +++ b/src/video/uikit/SDL_uikitwindow.m @@ -126,43 +126,6 @@ static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, UIWindow return true; } -API_AVAILABLE(ios(13.0)) -static UIWindowScene *GetActiveWindowScene(void) -{ - if (@available(iOS 13.0, tvOS 13.0, *)) { - NSSet *connectedScenes = [UIApplication sharedApplication].connectedScenes; - - // First, try to find an active foreground scene - for (UIScene *scene in connectedScenes) { - if ([scene isKindOfClass:[UIWindowScene class]]) { - UIWindowScene *windowScene = (UIWindowScene *)scene; - if (windowScene.activationState == UISceneActivationStateForegroundActive) { - return windowScene; - } - } - } - - // If no active scene, return any foreground scene - for (UIScene *scene in connectedScenes) { - if ([scene isKindOfClass:[UIWindowScene class]]) { - UIWindowScene *windowScene = (UIWindowScene *)scene; - if (windowScene.activationState == UISceneActivationStateForegroundInactive) { - return windowScene; - } - } - } - - // Last resort: return first window scene - for (UIScene *scene in connectedScenes) { - if ([scene isKindOfClass:[UIWindowScene class]]) { - return (UIWindowScene *)scene; - } - } - } - - return nil; -} - bool UIKit_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props) { @autoreleasepool { @@ -210,7 +173,7 @@ bool UIKit_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properti UIWindow *uiwindow = nil; if (@available(iOS 13.0, tvOS 13.0, *)) { - UIWindowScene *scene = GetActiveWindowScene(); + UIWindowScene *scene = UIKit_GetActiveWindowScene(); if (scene) { uiwindow = [[UIWindow alloc] initWithWindowScene:scene]; }