From 998f95786ada324838729117dc852ed690eaa63a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 9 Mar 2020 17:36:52 -0700 Subject: [PATCH] Android: Enable native keyboard for OSK. And make Windows/Qt follow the same async behavior for input boxes. --- Core/Config.cpp | 2 +- Core/Config.h | 1 - Core/Dialog/PSPOskDialog.cpp | 73 +++++++++++++++++++++++------------- Core/Dialog/PSPOskDialog.h | 15 +++++++- Qt/QtMain.cpp | 4 +- UI/GameSettingsScreen.cpp | 4 +- Windows/main.cpp | 4 +- 7 files changed, 67 insertions(+), 36 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 9a4e54743a..9d04db3ba5 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -968,7 +968,7 @@ static ConfigSetting systemParamSettings[] = { ReportedConfigSetting("ButtonPreference", &g_Config.iButtonPreference, PSP_SYSTEMPARAM_BUTTON_CROSS, true, true), ConfigSetting("LockParentalLevel", &g_Config.iLockParentalLevel, 0, true, true), ConfigSetting("WlanAdhocChannel", &g_Config.iWlanAdhocChannel, PSP_SYSTEMPARAM_ADHOC_CHANNEL_AUTOMATIC, true, true), -#if defined(USING_WIN_UI) +#if defined(USING_WIN_UI) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) ConfigSetting("BypassOSKWithKeyboard", &g_Config.bBypassOSKWithKeyboard, false, true, true), #endif ConfigSetting("WlanPowerSave", &g_Config.bWlanPowerSave, (bool) PSP_SYSTEMPARAM_WLAN_POWERSAVE_OFF, true, true), diff --git a/Core/Config.h b/Core/Config.h index 4e354639bc..67a07597f4 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -410,7 +410,6 @@ public: int iPSPModel; int iFirmwareVersion; - // TODO: Make this work with your platform, too! bool bBypassOSKWithKeyboard; // Debugger diff --git a/Core/Dialog/PSPOskDialog.cpp b/Core/Dialog/PSPOskDialog.cpp index 85b2ad3342..b97eae0eb7 100755 --- a/Core/Dialog/PSPOskDialog.cpp +++ b/Core/Dialog/PSPOskDialog.cpp @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include +#include "base/NativeApp.h" #include "i18n/i18n.h" #include "math/math_util.h" #include "util/text/utf8.h" @@ -30,10 +31,6 @@ #include "Common/ChunkFile.h" #include "GPU/GPUState.h" -#if defined(USING_WIN_UI) -#include "base/NativeApp.h" -#endif - #ifndef _WIN32 #include #include @@ -332,6 +329,9 @@ int PSPOskDialog::Init(u32 oskPtr) { // Eat any keys pressed before the dialog inited. UpdateButtons(); + std::lock_guard guard(nativeMutex_); + nativeStatus_ = PSPOskNativeStatus::IDLE; + StartFade(true); return 0; } @@ -837,7 +837,6 @@ void PSPOskDialog::RenderKeyboard() } } -#if defined(USING_WIN_UI) // TODO: Why does this have a 2 button press lag/delay when // re-opening the dialog box? I don't get it. int PSPOskDialog::NativeKeyboard() { @@ -845,28 +844,51 @@ int PSPOskDialog::NativeKeyboard() { return SCE_ERROR_UTILITY_INVALID_STATUS; } - std::wstring titleText; - GetWideStringFromPSPPointer(titleText, oskParams->fields[0].desc); +#if defined(USING_WIN_UI) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) + bool beginInputBox = false; + if (nativeStatus_ == PSPOskNativeStatus::IDLE) { + std::lock_guard guard(nativeMutex_); + if (nativeStatus_ == PSPOskNativeStatus::IDLE) { + nativeStatus_ = PSPOskNativeStatus::WAITING; + beginInputBox = true; + } + } - std::wstring defaultText; - GetWideStringFromPSPPointer(defaultText, oskParams->fields[0].intext); + if (beginInputBox) { + std::wstring titleText; + GetWideStringFromPSPPointer(titleText, oskParams->fields[0].desc); - if (defaultText.empty()) - defaultText.assign(L"VALUE"); + std::wstring defaultText; + GetWideStringFromPSPPointer(defaultText, oskParams->fields[0].intext); - // TODO: This is USING_WIN_UI only, so we rely on it being synchronous... - // But we should really have this set some state that is checked each time NativeKeyboard is called. - System_InputBoxGetString(ConvertWStringToUTF8(titleText), ConvertWStringToUTF8(defaultText), [&](bool result, const std::string &value) { - if (result) { - inputChars = ConvertUTF8ToWString(value); - u32 maxLength = FieldMaxLength(); - if (inputChars.length() > maxLength) { - ERROR_LOG(SCEUTILITY, "NativeKeyboard: input text too long(%d characters/glyphs max), truncating to game-requested length.", maxLength); - inputChars.erase(maxLength, std::string::npos); + if (defaultText.empty()) + defaultText.assign(L"VALUE"); + + System_InputBoxGetString(ConvertWStringToUTF8(titleText), ConvertWStringToUTF8(defaultText), [&](bool result, const std::string &value) { + std::lock_guard guard(nativeMutex_); + if (nativeStatus_ != PSPOskNativeStatus::WAITING) { + return; } + + nativeValue_ = value; + nativeStatus_ = result ? PSPOskNativeStatus::SUCCESS : PSPOskNativeStatus::FAILURE; + }); + } else if (nativeStatus_ == PSPOskNativeStatus::SUCCESS) { + inputChars = ConvertUTF8ToWString(nativeValue_); + nativeValue_.clear(); + + u32 maxLength = FieldMaxLength(); + if (inputChars.length() > maxLength) { + ERROR_LOG(SCEUTILITY, "NativeKeyboard: input text too long(%d characters/glyphs max), truncating to game-requested length.", maxLength); + inputChars.erase(maxLength, std::string::npos); } ChangeStatus(SCE_UTILITY_STATUS_FINISHED, 0); - }); + nativeStatus_ = PSPOskNativeStatus::DONE; + } else if (nativeStatus_ == PSPOskNativeStatus::FAILURE) { + ChangeStatus(SCE_UTILITY_STATUS_FINISHED, 0); + nativeStatus_ = PSPOskNativeStatus::DONE; + } +#endif u16_le *outText = oskParams->fields[0].outtext; @@ -886,7 +908,6 @@ int PSPOskDialog::NativeKeyboard() { return 0; } -#endif int PSPOskDialog::Update(int animSpeed) { if (GetStatus() != SCE_UTILITY_STATUS_RUNNING) { @@ -908,12 +929,10 @@ int PSPOskDialog::Update(int animSpeed) { int selectedRow = selectedChar / numKeyCols[currentKeyboard]; int selectedExtra = selectedChar % numKeyCols[currentKeyboard]; - // TODO: Add your platforms here when you have a NativeKeyboard func. - -#if defined(USING_WIN_UI) +#if defined(USING_WIN_UI) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) // Windows: Fall back to the OSK/continue normally if we're in fullscreen. // The dialog box doesn't work right if in fullscreen. - if(g_Config.bBypassOSKWithKeyboard && !g_Config.bFullScreen) + if (g_Config.bBypassOSKWithKeyboard && !g_Config.bFullScreen) return NativeKeyboard(); #endif @@ -1095,6 +1114,7 @@ int PSPOskDialog::Shutdown(bool force) if (!force) { ChangeStatusShutdown(OSK_SHUTDOWN_DELAY_US); } + nativeStatus_ = PSPOskNativeStatus::IDLE; return 0; } @@ -1113,6 +1133,7 @@ void PSPOskDialog::DoState(PointerWrap &p) p.Do(oskOuttext); p.Do(selectedChar); p.Do(inputChars); + // Don't need to save state native status or value. } pspUtilityDialogCommon *PSPOskDialog::GetCommonParam() diff --git a/Core/Dialog/PSPOskDialog.h b/Core/Dialog/PSPOskDialog.h index cac1358f71..fc57bcf2e4 100644 --- a/Core/Dialog/PSPOskDialog.h +++ b/Core/Dialog/PSPOskDialog.h @@ -17,6 +17,7 @@ #pragma once +#include #include #include "Core/Dialog/PSPDialog.h" @@ -202,6 +203,14 @@ static const std::string OskKeyboardNames[] = "English Full-width", }; +enum class PSPOskNativeStatus { + IDLE, + DONE, + WAITING, + SUCCESS, + FAILURE, +}; + class PSPOskDialog: public PSPDialog { public: PSPOskDialog(); @@ -222,9 +231,7 @@ private: void ConvertUCS2ToUTF8(std::string& _string, const PSPPointer& em_address); void ConvertUCS2ToUTF8(std::string& _string, const wchar_t *input); void RenderKeyboard(); -#if defined(USING_WIN_UI) int NativeKeyboard(); -#endif std::wstring CombinationString(bool isInput); // for Japanese, Korean std::wstring CombinationKorean(bool isInput); // for Korea @@ -244,6 +251,10 @@ private: OskKeyboardLanguage currentKeyboardLanguage; bool isCombinated; + std::mutex nativeMutex_; + PSPOskNativeStatus nativeStatus_ = PSPOskNativeStatus::IDLE; + std::string nativeValue_; + int i_level; // for Korean Keyboard support int i_value[3]; // for Korean Keyboard support }; diff --git a/Qt/QtMain.cpp b/Qt/QtMain.cpp index 9b3345678a..e60cfaf257 100644 --- a/Qt/QtMain.cpp +++ b/Qt/QtMain.cpp @@ -230,9 +230,9 @@ PermissionStatus System_GetPermissionStatus(SystemPermission permission) { retur void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb) { QString text = emugl->InputBoxGetQString(QString::fromStdString(title), QString::fromStdString(defaultValue)); if (text.isEmpty()) { - cb(false, ""); + NativeInputBoxReceived(cb, false, ""); } else { - cb(true, text.toStdString()); + NativeInputBoxReceived(cb, true, text.toStdString()); } } diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 8d9d143b23..ca2ff3a606 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -801,8 +801,8 @@ void GameSettingsScreen::CreateViews() { systemSettings->Add(new CheckBox(&g_Config.bEnableStateUndo, sy->T("Savestate slot backups"))); static const char *autoLoadSaveStateChoices[] = { "Off", "Oldest Save", "Newest Save", "Slot 1", "Slot 2", "Slot 3", "Slot 4", "Slot 5" }; systemSettings->Add(new PopupMultiChoice(&g_Config.iAutoLoadSaveState, sy->T("Auto Load Savestate"), autoLoadSaveStateChoices, 0, ARRAY_SIZE(autoLoadSaveStateChoices), sy->GetName(), screenManager())); -#if defined(USING_WIN_UI) - systemSettings->Add(new CheckBox(&g_Config.bBypassOSKWithKeyboard, sy->T("Enable Windows native keyboard", "Enable Windows native keyboard"))); +#if defined(USING_WIN_UI) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) + systemSettings->Add(new CheckBox(&g_Config.bBypassOSKWithKeyboard, sy->T("Use system native keyboard"))); #endif #if PPSSPP_PLATFORM(ANDROID) auto memstickPath = systemSettings->Add(new ChoiceWithValueDisplay(&g_Config.memStickDirectory, sy->T("Change Memory Stick folder"), (const char *)nullptr)); diff --git a/Windows/main.cpp b/Windows/main.cpp index 8a8d4e616a..85e63f6cf5 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -341,9 +341,9 @@ void EnableCrashingOnCrashes() { void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb) { std::string out; if (InputBox_GetString(MainWindow::GetHInstance(), MainWindow::GetHWND(), ConvertUTF8ToWString(title).c_str(), defaultValue, out)) { - cb(true, out); + NativeInputBoxReceived(cb, true, out); } else { - cb(false, ""); + NativeInputBoxReceived(cb, false, ""); } }