From 081bf51eacfc77623fbc7cac8438ac46e9d3243b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 25 May 2024 21:43:16 +0200 Subject: [PATCH 1/3] iOS: Fix issue with keyboard popping up after file picker. iOS kb APIs are crazy --- UI/DarwinFileSystemServices.mm | 32 ++++++++++++++++++++++---------- ios/ViewController.mm | 15 +++++++++------ 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/UI/DarwinFileSystemServices.mm b/UI/DarwinFileSystemServices.mm index 2afeabfa94a3..6b9ddce6442b 100644 --- a/UI/DarwinFileSystemServices.mm +++ b/UI/DarwinFileSystemServices.mm @@ -7,6 +7,7 @@ #include "ppsspp_config.h" #include "Core/Config.h" +#include "Common/Log.h" #include "DarwinFileSystemServices.h" #include #include @@ -16,6 +17,7 @@ #endif #if __has_include() +#include "../ios/ViewControllerCommon.h" #include @interface DocumentPickerDelegate : NSObject @@ -24,18 +26,27 @@ @interface DocumentPickerDelegate : NSObject @implementation DocumentPickerDelegate -(instancetype)initWithCallback: (DarwinDirectoryPanelCallback)callback { - if (self = [super init]) { - self.callback = callback; - } - - return self; + if (self = [super init]) { + self.callback = callback; + } + return self; } -- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray *)urls { - if (urls.count >= 1) +- (void)didPickDocumentsAtURLs:(NSArray *)urls { + if (urls.count >= 1) self.callback(true, Path(urls[0].path.UTF8String)); - else - self.callback(false, Path()); + else + self.callback(false, Path()); + + INFO_LOG(SYSTEM, "Callback processed, pre-emptively hide keyboard"); + [sharedViewController hideKeyboard]; +} + +- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller { + self.callback(false, Path()); + + INFO_LOG(SYSTEM, "Picker cancelled, pre-emptively hide keyboard"); + [sharedViewController hideKeyboard]; } @end @@ -77,6 +88,7 @@ - (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocum // panel.allowedFileTypes = @[(__bridge NSString *)kUTTypeFolder]; NSModalResponse modalResponse = [panel runModal]; + INFO_LOG(SYSTEM, "Mac: Received response from modal"); if (modalResponse == NSModalResponseOK && panel.URLs.firstObject) { callback(true, Path(panel.URLs.firstObject.path.UTF8String)); } else if (modalResponse == NSModalResponseCancel) { @@ -144,4 +156,4 @@ void RestartMacApp() { [task launch]; exit(0); #endif -} \ No newline at end of file +} diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 6c1d3e53d97e..48afd931e3c2 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -448,11 +448,6 @@ -(void) deleteBackward { INFO_LOG(SYSTEM, "Backspace"); } --(BOOL) hasText -{ - return YES; -} - -(void) insertText:(NSString *)text { std::string str = std::string([text UTF8String]); @@ -460,6 +455,7 @@ -(void) insertText:(NSString *)text UTF8 chars(str); while (!chars.end()) { uint32_t codePoint = chars.next(); + INFO_LOG(SYSTEM, "Codepoint#: %d", codePoint); KeyInput input{}; input.deviceId = DEVICE_ID_KEYBOARD; input.flags = KEY_CHAR; @@ -470,17 +466,24 @@ -(void) insertText:(NSString *)text -(BOOL) canBecomeFirstResponder { - return YES; + return true; +} + +-(BOOL) hasText +{ + return true; } -(void) showKeyboard { dispatch_async(dispatch_get_main_queue(), ^{ + INFO_LOG(SYSTEM, "becomeFirstResponder"); [self becomeFirstResponder]; }); } -(void) hideKeyboard { dispatch_async(dispatch_get_main_queue(), ^{ + INFO_LOG(SYSTEM, "resignFirstResponder"); [self resignFirstResponder]; }); } From f42f7ac9d1bce04db144dd1e90700df03b0f264f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 26 May 2024 09:39:44 +0200 Subject: [PATCH 2/3] Touch controls on iOS: Move the three center button up slightly by default to avoid the task switcher --- UI/GamepadEmu.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/UI/GamepadEmu.cpp b/UI/GamepadEmu.cpp index cdc7bf4a72f7..e176c222ca52 100644 --- a/UI/GamepadEmu.cpp +++ b/UI/GamepadEmu.cpp @@ -712,16 +712,23 @@ void InitPadLayout(float xres, float yres, float globalScale) { bottom_key_spacing *= 0.8f; } +// On IOS, nudge the bottom button up a little to avoid the task switcher. +#if PPSSPP_PLATFORM(IOS) + const float bottom_button_Y = 80.0f; +#else + const float bottom_button_Y = 60.0f; +#endif + int start_key_X = halfW + bottom_key_spacing * scale; - int start_key_Y = yres - 60 * scale; + int start_key_Y = yres - bottom_button_Y * scale; initTouchPos(g_Config.touchStartKey, start_key_X, start_key_Y); int select_key_X = halfW; - int select_key_Y = yres - 60 * scale; + int select_key_Y = yres - bottom_button_Y * scale; initTouchPos(g_Config.touchSelectKey, select_key_X, select_key_Y); int fast_forward_key_X = halfW - bottom_key_spacing * scale; - int fast_forward_key_Y = yres - 60 * scale; + int fast_forward_key_Y = yres - bottom_button_Y * scale; initTouchPos(g_Config.touchFastForwardKey, fast_forward_key_X, fast_forward_key_Y); // L and R------------------------------------------------------------ From c26de64d0f490ec53fca7c0087a709ccbe5a3848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 26 May 2024 09:55:50 +0200 Subject: [PATCH 3/3] iOS: Pass through touches near the task switcher only in-game. Makes the UI better behaved. --- Common/System/System.h | 1 + Core/System.cpp | 1 + ios/ViewController.mm | 17 ++++++++++++++++- ios/ViewControllerCommon.h | 2 ++ ios/ViewControllerMetal.mm | 17 ++++++++++++++++- ios/main.mm | 10 +++++++++- 6 files changed, 45 insertions(+), 3 deletions(-) diff --git a/Common/System/System.h b/Common/System/System.h index a5d87e479668..7c7b3c4c1b30 100644 --- a/Common/System/System.h +++ b/Common/System/System.h @@ -229,6 +229,7 @@ enum class SystemNotification { TEST_JAVA_EXCEPTION, KEEP_SCREEN_AWAKE, ACTIVITY, + UI_STATE_CHANGED, }; // I guess it's not super great architecturally to centralize this, since it's not general - but same with a lot of diff --git a/Core/System.cpp b/Core/System.cpp index 27e9006e7d58..01cd8fb06680 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -128,6 +128,7 @@ void UpdateUIState(GlobalUIState newState) { if (globalUIState != newState && globalUIState != UISTATE_EXIT) { globalUIState = newState; System_Notify(SystemNotification::DISASSEMBLY); + System_Notify(SystemNotification::UI_STATE_CHANGED); System_SetKeepScreenBright(globalUIState == UISTATE_INGAME); } } diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 48afd931e3c2..224b22cc6559 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -392,7 +392,22 @@ - (void)controllerDidDisconnect:(NSNotification *)note // Enables tapping for edge area. -(UIRectEdge)preferredScreenEdgesDeferringSystemGestures { - return UIRectEdgeAll; + if (GetUIState() == UISTATE_INGAME) { + // In-game, we need all the control we can get. Though, we could possibly + // allow the top edge? + INFO_LOG(SYSTEM, "Defer system gestures on all edges"); + return UIRectEdgeAll; + } else { + INFO_LOG(SYSTEM, "Allow system gestures on the bottom"); + // Allow task switching gestures to take precedence, without causing + // scroll events in the UI. + return UIRectEdgeTop | UIRectEdgeLeft | UIRectEdgeRight; + } +} + +- (void)uiStateChanged +{ + [self setNeedsUpdateOfScreenEdgesDeferringSystemGestures]; } - (UIView *)getView { diff --git a/ios/ViewControllerCommon.h b/ios/ViewControllerCommon.h index cfbe5e7daf99..1e955b66ce39 100644 --- a/ios/ViewControllerCommon.h +++ b/ios/ViewControllerCommon.h @@ -20,6 +20,8 @@ - (void)didBecomeActive; - (void)willResignActive; +- (void)uiStateChanged; + @end extern id sharedViewController; diff --git a/ios/ViewControllerMetal.mm b/ios/ViewControllerMetal.mm index 1fd177a8f36c..43038c8e6191 100644 --- a/ios/ViewControllerMetal.mm +++ b/ios/ViewControllerMetal.mm @@ -477,7 +477,22 @@ - (void)viewSafeAreaInsetsDidChange { // Enables tapping for edge area. -(UIRectEdge)preferredScreenEdgesDeferringSystemGestures { - return UIRectEdgeAll; + if (GetUIState() == UISTATE_INGAME) { + // In-game, we need all the control we can get. Though, we could possibly + // allow the top edge? + INFO_LOG(SYSTEM, "Defer system gestures on all edges"); + return UIRectEdgeAll; + } else { + INFO_LOG(SYSTEM, "Allow system gestures on the bottom"); + // Allow task switching gestures to take precedence, without causing + // scroll events in the UI. + return UIRectEdgeTop | UIRectEdgeLeft | UIRectEdgeRight; + } +} + +- (void)uiStateChanged +{ + [self setNeedsUpdateOfScreenEdgesDeferringSystemGestures]; } - (void)bindDefaultFBO diff --git a/ios/main.mm b/ios/main.mm index 48690865b21d..f0de32c9960e 100644 --- a/ios/main.mm +++ b/ios/main.mm @@ -386,7 +386,15 @@ bool System_GetPropertyBool(SystemProperty prop) { void System_Notify(SystemNotification notification) { switch (notification) { - default: break; + case SystemNotification::UI_STATE_CHANGED: + dispatch_async(dispatch_get_main_queue(), ^{ + if (sharedViewController) { + [sharedViewController uiStateChanged]; + } + }); + break; + default: + break; } }