diff --git a/Common/System/System.h b/Common/System/System.h index 5ad89373a3..a5d87e4796 100644 --- a/Common/System/System.h +++ b/Common/System/System.h @@ -142,6 +142,7 @@ enum SystemProperty { SYSPROP_HAS_IMAGE_BROWSER, SYSPROP_HAS_BACK_BUTTON, SYSPROP_HAS_KEYBOARD, + SYSPROP_KEYBOARD_IS_SOFT, SYSPROP_HAS_ACCELEROMETER, // Used to enable/disable tilt input settings SYSPROP_HAS_OPEN_DIRECTORY, SYSPROP_HAS_LOGIN_DIALOG, diff --git a/Common/UI/PopupScreens.cpp b/Common/UI/PopupScreens.cpp index 5f0094caff..d3d8cf04f5 100644 --- a/Common/UI/PopupScreens.cpp +++ b/Common/UI/PopupScreens.cpp @@ -537,6 +537,9 @@ EventReturn PopupTextInputChoice::HandleClick(EventParams &e) { } TextEditPopupScreen *popupScreen = new TextEditPopupScreen(value_, placeHolder_, ChopTitle(text_), maxLen_); + if (System_GetPropertyBool(SYSPROP_KEYBOARD_IS_SOFT)) { + popupScreen->SetAlignTop(true); + } popupScreen->OnChange.Handle(this, &PopupTextInputChoice::HandleChange); if (e.v) popupScreen->SetPopupOrigin(e.v); diff --git a/Common/UI/UIScreen.cpp b/Common/UI/UIScreen.cpp index f9a750a557..c0af58bfb4 100644 --- a/Common/UI/UIScreen.cpp +++ b/Common/UI/UIScreen.cpp @@ -385,10 +385,6 @@ void PopupScreen::SetPopupOrigin(const UI::View *view) { popupOrigin_ = view->GetBounds().Center(); } -void PopupScreen::SetPopupOffset(float y) { - offsetY_ = y; -} - void PopupScreen::TriggerFinish(DialogResult result) { if (CanComplete(result)) { ignoreInput_ = true; @@ -411,8 +407,18 @@ void PopupScreen::CreateViews() { float yres = screenManager()->getUIContext()->GetBounds().h; - box_ = new LinearLayout(ORIENT_VERTICAL, - new AnchorLayoutParams(PopupWidth(), FillVertical() ? yres - 30 : WRAP_CONTENT, dc.GetBounds().centerX(), dc.GetBounds().centerY() + offsetY_, NONE, NONE, true)); + AnchorLayoutParams *anchorParams; + if (!alignTop_) { + // Standard centering etc. + anchorParams = new AnchorLayoutParams(PopupWidth(), FillVertical() ? yres - 30 : WRAP_CONTENT, + dc.GetBounds().centerX(), dc.GetBounds().centerY() + offsetY_, NONE, NONE, true); + } else { + // Top-aligned, for dialogs where we need to pop a keyboard below. + anchorParams = new AnchorLayoutParams(PopupWidth(), FillVertical() ? yres - 30 : WRAP_CONTENT, + NONE, 0, NONE, NONE, false); + } + + box_ = new LinearLayout(ORIENT_VERTICAL, anchorParams); root_->Add(box_); box_->SetBG(dc.theme->popupStyle.background); diff --git a/Common/UI/UIScreen.h b/Common/UI/UIScreen.h index 12c71cb831..701fe4e42d 100644 --- a/Common/UI/UIScreen.h +++ b/Common/UI/UIScreen.h @@ -108,7 +108,9 @@ public: void TriggerFinish(DialogResult result) override; void SetPopupOrigin(const UI::View *view); - void SetPopupOffset(float y); + void SetPopupOffset(float y) { offsetY_ = y; } + + void SetAlignTop(bool alignTop) { alignTop_ = alignTop; } void SetHasDropShadow(bool has) { hasDropShadow_ = has; } @@ -144,6 +146,7 @@ private: bool hasPopupOrigin_ = false; Point popupOrigin_; float offsetY_ = 0.0f; + bool alignTop_ = false; bool hasDropShadow_ = true; }; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 19600bdb03..283775dc57 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -970,14 +970,7 @@ void GameSettingsScreen::CreateToolsSettings(UI::ViewGroup *tools) { tools->Add(new ItemHeader(ms->T("Tools"))); - bool showRetroAchievements = true; -#if PPSSPP_PLATFORM(IOS_APP_STORE) - // Hide RetroAchievements login (unless the user has specified a login via the ini file). - // A non-working login won't pass App Store review. - if (g_Config.sAchievementsUserName.empty()) { - showRetroAchievements = false; - } -#endif + const bool showRetroAchievements = true; if (showRetroAchievements) { auto retro = tools->Add(new Choice(sy->T("RetroAchievements"))); retro->OnClick.Add([=](UI::EventParams &) -> UI::EventReturn { @@ -1231,9 +1224,7 @@ void GameSettingsScreen::CreateSystemSettings(UI::ViewGroup *systemSettings) { systemSettings->Add(new PopupMultiChoice(&g_Config.iLanguage, psps->T("Game language"), defaultLanguages, -1, ARRAY_SIZE(defaultLanguages), I18NCat::PSPSETTINGS, screenManager())); static const char *models[] = { "PSP-1000", "PSP-2000/3000" }; systemSettings->Add(new PopupMultiChoice(&g_Config.iPSPModel, sy->T("PSP Model"), models, 0, ARRAY_SIZE(models), I18NCat::SYSTEM, screenManager()))->SetEnabled(!PSP_IsInited()); -#if !PPSSPP_PLATFORM(IOS_APP_STORE) systemSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &g_Config.sNickName, sy->T("Change Nickname"), "", 32, screenManager())); -#endif systemSettings->Add(new CheckBox(&g_Config.bDayLightSavings, sy->T("Day Light Saving"))); static const char *dateFormat[] = { "YYYYMMDD", "MMDDYYYY", "DDMMYYYY" }; systemSettings->Add(new PopupMultiChoice(&g_Config.iDateFormat, sy->T("Date Format"), dateFormat, 0, ARRAY_SIZE(dateFormat), I18NCat::SYSTEM, screenManager())); diff --git a/UI/RetroAchievementScreens.cpp b/UI/RetroAchievementScreens.cpp index 5a9e1ff4a7..8fc80fc8d8 100644 --- a/UI/RetroAchievementScreens.cpp +++ b/UI/RetroAchievementScreens.cpp @@ -308,8 +308,6 @@ void RetroAchievementsSettingsScreen::CreateAccountTab(UI::ViewGroup *viewGroup) return UI::EVENT_DONE; }); } else { - // TODO: For text input on iOS, look into https://stackoverflow.com/questions/7253477/how-to-display-the-iphone-ipad-keyboard-over-a-full-screen-opengl-es-app - // Hack up a temporary quick login-form-ish-thing viewGroup->Add(new PopupTextInputChoice(GetRequesterToken(), &username_, di->T("Username"), "", 128, screenManager())); viewGroup->Add(new PopupTextInputChoice(GetRequesterToken(), &password_, di->T("Password"), "", 128, screenManager()))->SetPasswordDisplay(); diff --git a/ios/ViewController.h b/ios/ViewController.h index d17de68c1c..36c1db7f8b 100644 --- a/ios/ViewController.h +++ b/ios/ViewController.h @@ -10,10 +10,12 @@ #import "LocationHelper.h" @interface ViewController : GLKViewController + LocationHandlerDelegate, CameraFrameDelegate, UIGestureRecognizerDelegate, UIKeyInput> - (void)shareText:(NSString *)text; - (void)shutdown; +- (void)hideKeyboard; +- (void)showKeyboard; @end diff --git a/ios/ViewController.mm b/ios/ViewController.mm index b25b5cb83e..8bbaaa85e3 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -19,7 +19,7 @@ #include "Common/GPU/thin3d_create.h" #include "Common/GPU/OpenGL/GLRenderManager.h" #include "Common/GPU/OpenGL/GLFeatures.h" - +#include "Common/Data/Encoding/Utf8.h" #include "Common/System/Display.h" #include "Common/System/System.h" #include "Common/System/OSD.h" @@ -179,6 +179,11 @@ extern float g_safeInsetBottom; } } +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + [self hideKeyboard]; +} + - (void)viewDidLoad { [super viewDidLoad]; [[DisplayManager shared] setupDisplayListener]; @@ -763,6 +768,55 @@ void stopLocation() { 0 /* bearing */); } +// The below is inspired by https://stackoverflow.com/questions/7253477/how-to-display-the-iphone-ipad-keyboard-over-a-full-screen-opengl-es-app +// It's a bit limited but good enough. + +-(void) deleteBackward { + KeyInput input{}; + input.deviceId = DEVICE_ID_KEYBOARD; + input.flags = KEY_DOWN | KEY_UP; + input.keyCode = NKCODE_DEL; + NativeKey(input); + INFO_LOG(SYSTEM, "Backspace"); +} + +-(BOOL) hasText +{ + return YES; +} + +-(void) insertText:(NSString *)text +{ + std::string str = std::string([text UTF8String]); + INFO_LOG(SYSTEM, "Chars: %s", str.c_str()); + UTF8 chars(str); + while (!chars.end()) { + uint32_t codePoint = chars.next(); + KeyInput input{}; + input.deviceId = DEVICE_ID_KEYBOARD; + input.flags = KEY_CHAR; + input.unicodeChar = codePoint; + NativeKey(input); + } +} + +-(BOOL) canBecomeFirstResponder +{ + return YES; +} + +-(void) showKeyboard { + dispatch_async(dispatch_get_main_queue(), ^{ + [self becomeFirstResponder]; + }); +} + +-(void) hideKeyboard { + dispatch_async(dispatch_get_main_queue(), ^{ + [self resignFirstResponder]; + }); +} + @end void System_LaunchUrl(LaunchUrlType urlType, char const* url) diff --git a/ios/main.mm b/ios/main.mm index 28d1bdf6aa..999accc5c8 100644 --- a/ios/main.mm +++ b/ios/main.mm @@ -349,6 +349,11 @@ bool System_GetPropertyBool(SystemProperty prop) { return false; case SYSPROP_HAS_ACCELEROMETER: return true; + case SYSPROP_HAS_KEYBOARD: + return true; + case SYSPROP_KEYBOARD_IS_SOFT: + // If a hardware keyboard is connected, and we add support, we could return false here. + return true; case SYSPROP_APP_GOLD: #ifdef GOLD return true; @@ -437,6 +442,23 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string [sharedViewController shareText:text]; return true; } + case SystemRequestType::NOTIFY_UI_EVENT: + { + switch ((UIEventNotification)param3) { + case UIEventNotification::POPUP_CLOSED: + [sharedViewController hideKeyboard]; + break; + case UIEventNotification::TEXT_GOTFOCUS: + [sharedViewController showKeyboard]; + break; + case UIEventNotification::TEXT_LOSTFOCUS: + [sharedViewController hideKeyboard]; + break; + default: + break; + } + return true; + } /* // Not 100% sure the threading is right case SystemRequestType::COPY_TO_CLIPBOARD: