diff --git a/CMakeLists.txt b/CMakeLists.txt index 36dbf12c73..a6f2ea7c7e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -712,6 +712,10 @@ add_library(Common STATIC Common/Render/Text/draw_text_uwp.h Common/System/Display.cpp Common/System/Display.h + Common/System/System.h + Common/System/NativeApp.h + Common/System/Request.cpp + Common/System/Request.h Common/Thread/Channel.h Common/Thread/ParallelLoop.cpp Common/Thread/ParallelLoop.h diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index c066494c66..3fabaafa64 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -550,6 +550,7 @@ + @@ -1005,6 +1006,7 @@ + diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index cce4e7656a..879e3495b8 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -494,6 +494,9 @@ ext\basis_universal + + System + @@ -920,6 +923,9 @@ ext\basis_universal + + System + diff --git a/Common/System/NativeApp.h b/Common/System/NativeApp.h index 6788642eb4..bb0c7af962 100644 --- a/Common/System/NativeApp.h +++ b/Common/System/NativeApp.h @@ -23,9 +23,6 @@ void NativeGetAppInfo(std::string *app_dir_name, std::string *app_nice_name, boo // Generic host->C++ messaging, used for functionality like system-native popup input boxes. void NativeMessageReceived(const char *message, const char *value); -// This is used to communicate back and thread requested input box strings. -void NativeInputBoxReceived(std::function cb, bool result, const std::string &value); - // Easy way for the Java side to ask the C++ side for configuration options, such as // the rotation lock which must be controlled from Java on Android. // It is currently not called on non-Android platforms. diff --git a/Common/System/Request.cpp b/Common/System/Request.cpp new file mode 100644 index 0000000000..883514d8da --- /dev/null +++ b/Common/System/Request.cpp @@ -0,0 +1,72 @@ +#include "Common/System/Request.h" +#include "Common/System/System.h" +#include "Common/Log.h" + +RequestManager g_requestManager; + +const char *RequestTypeAsString(SystemRequestType type) { + switch (type) { + case SystemRequestType::INPUT_TEXT_MODAL: return "INPUT_TEXT_MODAL"; + default: return "N/A"; + } +} + +bool RequestManager::MakeSystemRequest(SystemRequestType type, RequestCallback callback, const std::string ¶m1, const std::string ¶m2) { + int requestId = idCounter_++; + if (!System_MakeRequest(type, requestId, param1, param2)) { + return false; + } + + if (!callback) { + // We don't expect a response, this is a one-directional request. We're thus done. + return true; + } + + std::lock_guard guard(callbackMutex_); + callbackMap_[requestId] = callback; + return true; +} + +void RequestManager::PostSystemSuccess(int requestId, const char *responseString, int responseValue) { + std::lock_guard guard(callbackMutex_); + auto iter = callbackMap_.find(requestId); + if (iter == callbackMap_.end()) { + ERROR_LOG(SYSTEM, "PostSystemSuccess: Unexpected request ID %d (responseString=%s)", requestId, responseString); + return; + } + + std::lock_guard responseGuard(responseMutex_); + PendingResponse response; + response.callback = iter->second; + response.responseString = responseString; + response.responseValue = responseValue; + pendingResponses_.push_back(response); +} + +void RequestManager::PostSystemFailure(int requestId) { + std::lock_guard guard(callbackMutex_); + auto iter = callbackMap_.find(requestId); + if (iter == callbackMap_.end()) { + ERROR_LOG(SYSTEM, "PostSystemFailure: Unexpected request ID %d", requestId); + return; + } + callbackMap_.erase(iter); +} + +void RequestManager::ProcessRequests() { + std::lock_guard guard(responseMutex_); + for (auto &iter : pendingResponses_) { + if (iter.callback) { + iter.callback(iter.responseString.c_str(), iter.responseValue); + } + } + pendingResponses_.clear(); +} + +void RequestManager::Clear() { + std::lock_guard guard(callbackMutex_); + std::lock_guard responseGuard(responseMutex_); + + pendingResponses_.clear(); + callbackMap_.clear(); +} diff --git a/Common/System/Request.h b/Common/System/Request.h new file mode 100644 index 0000000000..19afe99721 --- /dev/null +++ b/Common/System/Request.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include +#include + +#include "Common/System/System.h" + +typedef std::function RequestCallback; + +// Platforms often have to process requests asynchronously, on wildly different threads. +// (Especially Android...) +// This acts as bridge and buffer. +class RequestManager { +public: + // These requests are to be handled by platform implementations. + // The callback you pass in will be called on the main thread later. + bool MakeSystemRequest(SystemRequestType type, RequestCallback callback, const std::string ¶m1, const std::string ¶m2); + + // Called by the platform implementation, when it's finished with a request. + void PostSystemSuccess(int requestId, const char *responseString, int responseValue = 0); + void PostSystemFailure(int requestId); + + // This must be called every frame from the beginning of NativeUpdate(). + // This will call the callback of any finished requests. + void ProcessRequests(); + + // Unclear if we need this... + void Clear(); + +private: + struct PendingRequest { + SystemRequestType type; + RequestCallback callback; + }; + + std::map callbackMap_; + std::mutex callbackMutex_; + + struct PendingResponse { + std::string responseString; + int responseValue; + RequestCallback callback; + }; + + int idCounter_ = 0; + std::vector pendingResponses_; + std::mutex responseMutex_; +}; + +const char *RequestTypeAsString(SystemRequestType type); + +extern RequestManager g_requestManager; + +// Wrappers for easy requests. +// NOTE: Semantics have changed - this no longer calls the callback on cancellation. +inline void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, RequestCallback callback) { + g_requestManager.MakeSystemRequest(SystemRequestType::INPUT_TEXT_MODAL, callback, title, defaultValue); +} diff --git a/Common/System/System.h b/Common/System/System.h index 8d74f9c270..b0222aeea0 100644 --- a/Common/System/System.h +++ b/Common/System/System.h @@ -50,8 +50,20 @@ enum class LaunchUrlType { void System_Vibrate(int length_ms); void System_ShowFileInFolder(const char *path); void System_LaunchUrl(LaunchUrlType urlType, const char *url); -void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb); + +enum class SystemRequestType { + INPUT_TEXT_MODAL, +}; + +// Implementations are supposed to process the request, and post the response to the g_RequestManager (see Message.h). +// This is not to be used directly by applications, instead use the g_RequestManager to make the requests. +// This can return false if it's known that the platform doesn't support the request, the app is supposed to handle +// or ignore that cleanly. +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2); + +// TODO: To be separated into requests, see Request.h, and a way to post "UI messages". void System_SendMessage(const char *command, const char *parameter); + PermissionStatus System_GetPermissionStatus(SystemPermission permission); void System_AskForPermission(SystemPermission permission); diff --git a/Core/Dialog/PSPOskDialog.cpp b/Core/Dialog/PSPOskDialog.cpp index e6e1ccafc4..bfbc545f67 100755 --- a/Core/Dialog/PSPOskDialog.cpp +++ b/Core/Dialog/PSPOskDialog.cpp @@ -22,7 +22,7 @@ #include "Common/Math/math_util.h" #include "Common/Data/Encoding/Utf8.h" #include "Common/Serialize/SerializeFuncs.h" -#include "Common/System/System.h" +#include "Common/System/Request.h" #include "Common/Serialize/Serializer.h" #include "Core/Dialog/PSPOskDialog.h" @@ -892,14 +892,14 @@ int PSPOskDialog::NativeKeyboard() { defaultText.assign(u"VALUE"); // There's already ConvertUCS2ToUTF8 in this file. Should we use that instead of the global ones? - System_InputBoxGetString(::ConvertUCS2ToUTF8(titleText), ::ConvertUCS2ToUTF8(defaultText), [&](bool result, const std::string &value) { + System_InputBoxGetString(::ConvertUCS2ToUTF8(titleText), ::ConvertUCS2ToUTF8(defaultText), [&](const std::string &value, int iValue) { std::lock_guard guard(nativeMutex_); if (nativeStatus_ != PSPOskNativeStatus::WAITING) { return; } nativeValue_ = value; - nativeStatus_ = result ? PSPOskNativeStatus::SUCCESS : PSPOskNativeStatus::FAILURE; + nativeStatus_ = iValue ? PSPOskNativeStatus::SUCCESS : PSPOskNativeStatus::FAILURE; }); } else if (nativeStatus_ == PSPOskNativeStatus::SUCCESS) { inputChars = ConvertUTF8ToUCS2(nativeValue_); diff --git a/Qt/QtMain.cpp b/Qt/QtMain.cpp index 3571c615ca..ba475e5141 100644 --- a/Qt/QtMain.cpp +++ b/Qt/QtMain.cpp @@ -34,7 +34,7 @@ #endif #include "Common/System/NativeApp.h" -#include "Common/System/System.h" +#include "Common/System/Request.h" #include "Common/GPU/OpenGL/GLFeatures.h" #include "Common/Math/math_util.h" #include "Common/Profiler/Profiler.h" @@ -58,6 +58,8 @@ MainUI *emugl = nullptr; static float refreshRate = 60.f; static int browseFileEvent = -1; static int browseFolderEvent = -1; +static int inputBoxEvent = -1; + QTCamera *qtcamera = nullptr; MainWindow *g_mainWindow; @@ -273,6 +275,57 @@ void System_Notify(SystemNotification notification) { } } +// TODO: Find a better version to pass parameters to HandleCustomEvent. +static std::string g_param1; +static std::string g_param2; +static int g_requestId; + +bool MainUI::HandleCustomEvent(QEvent *e) { + if (e->type() == browseFileEvent) { + QString fileName = QFileDialog::getOpenFileName(nullptr, "Load ROM", g_Config.currentDirectory.c_str(), "PSP ROMs (*.iso *.cso *.pbp *.elf *.zip *.ppdmp)"); + if (QFile::exists(fileName)) { + QDir newPath; + g_Config.currentDirectory = Path(newPath.filePath(fileName).toStdString()); + g_Config.Save("browseFileEvent"); + + NativeMessageReceived("boot", fileName.toStdString().c_str()); + } + } else if (e->type() == browseFolderEvent) { + auto mm = GetI18NCategory("MainMenu"); + QString fileName = QFileDialog::getExistingDirectory(nullptr, mm->T("Choose folder"), g_Config.currentDirectory.c_str()); + if (QDir(fileName).exists()) { + NativeMessageReceived("browse_folderSelect", fileName.toStdString().c_str()); + } + } else if (e->type() == inputBoxEvent) { + QString title = QString::fromStdString(g_param1); + QString defaultValue = QString::fromStdString(g_param2); + QString text = emugl->InputBoxGetQString(title, defaultValue); + if (text.isEmpty()) { + g_requestManager.PostSystemFailure(g_requestId); + } else { + g_requestManager.PostSystemSuccess(g_requestId, text.toStdString().c_str()); + } + } else { + return false; + } + return true; +} + +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2) { + switch (type) { + case SystemRequestType::INPUT_TEXT_MODAL: + { + g_requestId = requestId; + g_param1 = param1; + g_param2 = param2; + QCoreApplication::postEvent(emugl, new QEvent((QEvent::Type)inputBoxEvent)); + return true; + } + default: + return false; + } +} + void System_SendMessage(const char *command, const char *parameter) { if (!strcmp(command, "finish")) { qApp->exit(0); @@ -305,15 +358,6 @@ void System_Toast(const char *text) {} void System_AskForPermission(SystemPermission permission) {} PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; } -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()) { - NativeInputBoxReceived(cb, false, ""); - } else { - NativeInputBoxReceived(cb, true, text.toStdString()); - } -} - void System_Vibrate(int length_ms) { if (length_ms == -1 || length_ms == -3) length_ms = 50; @@ -355,6 +399,7 @@ static int mainInternal(QApplication &a) { browseFileEvent = QEvent::registerEventType(); browseFolderEvent = QEvent::registerEventType(); + inputBoxEvent = QEvent::registerEventType(); int retval = a.exec(); delete emugl; @@ -566,23 +611,8 @@ bool MainUI::event(QEvent *e) { break; default: - if (e->type() == browseFileEvent) { - QString fileName = QFileDialog::getOpenFileName(nullptr, "Load ROM", g_Config.currentDirectory.c_str(), "PSP ROMs (*.iso *.cso *.pbp *.elf *.zip *.ppdmp)"); - if (QFile::exists(fileName)) { - QDir newPath; - g_Config.currentDirectory = Path(newPath.filePath(fileName).toStdString()); - g_Config.Save("browseFileEvent"); - - NativeMessageReceived("boot", fileName.toStdString().c_str()); - } - break; - } else if (e->type() == browseFolderEvent) { - auto mm = GetI18NCategory("MainMenu"); - QString fileName = QFileDialog::getExistingDirectory(nullptr, mm->T("Choose folder"), g_Config.currentDirectory.c_str()); - if (QDir(fileName).exists()) { - NativeMessageReceived("browse_folderSelect", fileName.toStdString().c_str()); - } - } else { + // Can't switch on dynamic event types. + if (!HandleCustomEvent(e)) { return QWidget::event(e); } } diff --git a/Qt/QtMain.h b/Qt/QtMain.h index 639806bcf5..39cce11f77 100644 --- a/Qt/QtMain.h +++ b/Qt/QtMain.h @@ -140,6 +140,7 @@ protected: void EmuThreadJoin(); private: + bool HandleCustomEvent(QEvent *e); QtGLGraphicsContext *graphicsContext; float xscale, yscale; diff --git a/README.md b/README.md index 0aaed77a12..5c0e51a5b1 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,9 @@ Additional code by many contributors, see the Credits screen Originally released under the GPL 2.0 (and later) in November 2012 -Official website: -https://www.ppsspp.org/ +Official website: https://www.ppsspp.org/ -Discord: -https://discord.gg/5NJB6dD +Discord: https://discord.gg/5NJB6dD No BIOS file required to play, PPSSPP is an "HLE" emulator. Default settings balance good compatibility and speed. @@ -19,9 +17,11 @@ To contribute, see [the development page](https://www.ppsspp.org/development.htm For the latest source code, see [our GitHub page](https://github.com/hrydgard/ppsspp). +For documentation of all kinds (usage, reference, development), see the [documentation on the main website](https://www.ppsspp.org/docs) + For build instructions and other development tutorials, see [the wiki](https://github.com/hrydgard/ppsspp/wiki). -If you want to download regularly updated builds for Android, Windows x86 and x64, proceed to this [page](https://buildbot.orphis.net/ppsspp/) +If you want to download regularly updated builds for Android, Windows x86 and x64, [visit Orphis' buildbot](https://buildbot.orphis.net/ppsspp/) For game compatibility, see [community compatibility feedback](https://report.ppsspp.org/games). @@ -412,4 +412,4 @@ Credit goes to: [#16709]: https://github.com/hrydgard/ppsspp/issues/16709 "Correct some shader errors in reporting" [#16708]: https://github.com/hrydgard/ppsspp/issues/16708 "Additional fixes from both our reports and Play reports" [#16703]: https://github.com/hrydgard/ppsspp/issues/16703 "Minor fixes based on the latest Google Play report" -[#16706]: https://github.com/hrydgard/ppsspp/issues/16706 "softgpu: Fix lighting with 0 exp" \ No newline at end of file +[#16706]: https://github.com/hrydgard/ppsspp/issues/16706 "softgpu: Fix lighting with 0 exp" diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index f59a2dd22a..3bda836e98 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -166,6 +166,8 @@ void System_Vibrate(int length_ms) { // Ignore on PC } +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2) { return false; } + void System_SendMessage(const char *command, const char *parameter) { if (!strcmp(command, "toggle_fullscreen")) { g_ToggleFullScreenNextFrame = true; diff --git a/UI/ChatScreen.cpp b/UI/ChatScreen.cpp index 277185b3e5..d62470666e 100644 --- a/UI/ChatScreen.cpp +++ b/UI/ChatScreen.cpp @@ -10,7 +10,7 @@ #include "Common/Data/Text/I18n.h" #include "Common/Data/Encoding/Utf8.h" -#include "Common/System/System.h" +#include "Common/System/Request.h" #include "Core/Config.h" #include "Core/System.h" #include "Core/HLE/proAdhoc.h" @@ -97,7 +97,7 @@ UI::EventReturn ChatMenu::OnSubmit(UI::EventParams &e) { sendChat(chat); #elif PPSSPP_PLATFORM(ANDROID) auto n = GetI18NCategory("Networking"); - System_InputBoxGetString(n->T("Chat"), "", [](bool result, const std::string &value) { + System_InputBoxGetString(n->T("Chat"), "", [](const std::string &value, int) { sendChat(value); }); #endif @@ -181,10 +181,8 @@ void ChatMenu::Update() { #if defined(USING_WIN_UI) // Could remove the fullscreen check here, it works now. if (promptInput_ && g_Config.bBypassOSKWithKeyboard && !g_Config.UseFullScreen()) { - System_InputBoxGetString(n->T("Chat"), n->T("Chat Here"), [](bool result, const std::string &value) { - if (result) { - sendChat(value); - } + System_InputBoxGetString(n->T("Chat"), n->T("Chat Here"), [](const std::string &value, int) { + sendChat(value); }); promptInput_ = false; } diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index ded0d26d52..43f7ed44a5 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -30,7 +30,7 @@ #include "Common/VR/PPSSPPVR.h" #include "Common/System/Display.h" // Only to check screen aspect ratio with pixel_yres/pixel_xres -#include "Common/System/System.h" +#include "Common/System/Request.h" #include "Common/Battery/Battery.h" #include "Common/System/NativeApp.h" #include "Common/Data/Color/RGBAUtil.h" @@ -1564,10 +1564,8 @@ UI::EventReturn GameSettingsScreen::OnAudioDevice(UI::EventParams &e) { UI::EventReturn GameSettingsScreen::OnChangeQuickChat0(UI::EventParams &e) { #if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) auto n = GetI18NCategory("Networking"); - System_InputBoxGetString(n->T("Enter Quick Chat 1"), g_Config.sQuickChat0, [](bool result, const std::string &value) { - if (result) { - g_Config.sQuickChat0 = value; - } + System_InputBoxGetString(n->T("Enter Quick Chat 1"), g_Config.sQuickChat0, [](const std::string &value, int) { + g_Config.sQuickChat0 = value; }); #endif return UI::EVENT_DONE; @@ -1576,10 +1574,8 @@ UI::EventReturn GameSettingsScreen::OnChangeQuickChat0(UI::EventParams &e) { UI::EventReturn GameSettingsScreen::OnChangeQuickChat1(UI::EventParams &e) { #if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) auto n = GetI18NCategory("Networking"); - System_InputBoxGetString(n->T("Enter Quick Chat 2"), g_Config.sQuickChat1, [](bool result, const std::string &value) { - if (result) { - g_Config.sQuickChat1 = value; - } + System_InputBoxGetString(n->T("Enter Quick Chat 2"), g_Config.sQuickChat1, [](const std::string &value, int) { + g_Config.sQuickChat1 = value; }); #endif return UI::EVENT_DONE; @@ -1588,10 +1584,8 @@ UI::EventReturn GameSettingsScreen::OnChangeQuickChat1(UI::EventParams &e) { UI::EventReturn GameSettingsScreen::OnChangeQuickChat2(UI::EventParams &e) { #if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) auto n = GetI18NCategory("Networking"); - System_InputBoxGetString(n->T("Enter Quick Chat 3"), g_Config.sQuickChat2, [](bool result, const std::string &value) { - if (result) { - g_Config.sQuickChat2 = value; - } + System_InputBoxGetString(n->T("Enter Quick Chat 3"), g_Config.sQuickChat2, [](const std::string &value, int) { + g_Config.sQuickChat2 = value; }); #endif return UI::EVENT_DONE; @@ -1600,10 +1594,8 @@ UI::EventReturn GameSettingsScreen::OnChangeQuickChat2(UI::EventParams &e) { UI::EventReturn GameSettingsScreen::OnChangeQuickChat3(UI::EventParams &e) { #if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) auto n = GetI18NCategory("Networking"); - System_InputBoxGetString(n->T("Enter Quick Chat 4"), g_Config.sQuickChat3, [](bool result, const std::string &value) { - if (result) { - g_Config.sQuickChat3 = value; - } + System_InputBoxGetString(n->T("Enter Quick Chat 4"), g_Config.sQuickChat3, [](const std::string &value, int) { + g_Config.sQuickChat3 = value; }); #endif return UI::EVENT_DONE; @@ -1612,10 +1604,8 @@ UI::EventReturn GameSettingsScreen::OnChangeQuickChat3(UI::EventParams &e) { UI::EventReturn GameSettingsScreen::OnChangeQuickChat4(UI::EventParams &e) { #if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) auto n = GetI18NCategory("Networking"); - System_InputBoxGetString(n->T("Enter Quick Chat 5"), g_Config.sQuickChat4, [](bool result, const std::string &value) { - if (result) { - g_Config.sQuickChat4 = value; - } + System_InputBoxGetString(n->T("Enter Quick Chat 5"), g_Config.sQuickChat4, [](const std::string &value, int) { + g_Config.sQuickChat4 = value; }); #endif return UI::EVENT_DONE; @@ -1624,10 +1614,8 @@ UI::EventReturn GameSettingsScreen::OnChangeQuickChat4(UI::EventParams &e) { UI::EventReturn GameSettingsScreen::OnChangeNickname(UI::EventParams &e) { #if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) auto n = GetI18NCategory("Networking"); - System_InputBoxGetString(n->T("Enter a new PSP nickname"), g_Config.sNickName, [](bool result, const std::string &value) { - if (result) { - g_Config.sNickName = StripSpaces(value); - } + System_InputBoxGetString(n->T("Enter a new PSP nickname"), g_Config.sNickName, [](const std::string &value, int) { + g_Config.sNickName = StripSpaces(value); }); #endif return UI::EVENT_DONE; @@ -1723,10 +1711,8 @@ UI::EventReturn GameSettingsScreen::OnSysInfo(UI::EventParams &e) { UI::EventReturn GameSettingsScreen::OnChangeSearchFilter(UI::EventParams &e) { #if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || defined(__ANDROID__) auto se = GetI18NCategory("Search"); - System_InputBoxGetString(se->T("Search term"), searchFilter_, [](bool result, const std::string &value) { - if (result) { - NativeMessageReceived("gameSettings_search", StripSpaces(value).c_str()); - } + System_InputBoxGetString(se->T("Search term"), searchFilter_, [](const std::string &value, int) { + NativeMessageReceived("gameSettings_search", StripSpaces(value).c_str()); }); #else if (!System_GetPropertyBool(SYSPROP_HAS_KEYBOARD)) @@ -2098,10 +2084,8 @@ UI::EventReturn HostnameSelectScreen::OnDeleteAllClick(UI::EventParams &e) { UI::EventReturn HostnameSelectScreen::OnEditClick(UI::EventParams& e) { auto n = GetI18NCategory("Networking"); #if PPSSPP_PLATFORM(ANDROID) - System_InputBoxGetString(n->T("proAdhocServer Address:"), addrView_->GetText(), [this](bool result, const std::string& value) { - if (result) { - addrView_->SetText(value); - } + System_InputBoxGetString(n->T("proAdhocServer Address:"), addrView_->GetText(), [this](const std::string& value, int) { + addrView_->SetText(value); }); #endif return UI::EVENT_DONE; diff --git a/UI/MemStickScreen.cpp b/UI/MemStickScreen.cpp index 265be6bf68..5bf8c83d6f 100644 --- a/UI/MemStickScreen.cpp +++ b/UI/MemStickScreen.cpp @@ -26,6 +26,7 @@ #include "Common/StringUtils.h" #include "Common/System/System.h" +#include "Common/System/Request.h" #include "Common/System/NativeApp.h" #include "Common/System/Display.h" #include "Common/Data/Text/I18n.h" @@ -336,64 +337,62 @@ UI::EventReturn MemStickScreen::SetFolderManually(UI::EventParams ¶ms) { // The old way, from before scoped storage. #if PPSSPP_PLATFORM(ANDROID) auto sy = GetI18NCategory("System"); - System_InputBoxGetString(sy->T("Memory Stick Folder"), g_Config.memStickDirectory.ToString(), [&](bool result, const std::string &value) { + System_InputBoxGetString(sy->T("Memory Stick Folder"), g_Config.memStickDirectory.ToString(), [&](const std::string &value, int) { auto sy = GetI18NCategory("System"); auto di = GetI18NCategory("Dialog"); - if (result) { - std::string newPath = value; - size_t pos = newPath.find_last_not_of("/"); - // Gotta have at least something but a /, and also needs to start with a /. - if (newPath.empty() || pos == newPath.npos || newPath[0] != '/') { - settingInfo_->Show(sy->T("ChangingMemstickPathInvalid", "That path couldn't be used to save Memory Stick files."), nullptr); - return; - } - if (pos != newPath.size() - 1) { - newPath = newPath.substr(0, pos + 1); - } + std::string newPath = value; + size_t pos = newPath.find_last_not_of("/"); + // Gotta have at least something but a /, and also needs to start with a /. + if (newPath.empty() || pos == newPath.npos || newPath[0] != '/') { + settingInfo_->Show(sy->T("ChangingMemstickPathInvalid", "That path couldn't be used to save Memory Stick files."), nullptr); + return; + } + if (pos != newPath.size() - 1) { + newPath = newPath.substr(0, pos + 1); + } - if (newPath.empty()) { - // Reuse below message instead of adding yet another string. - System_Toast(sy->T("Path does not exist!")); - return; - } + if (newPath.empty()) { + // Reuse below message instead of adding yet another string. + System_Toast(sy->T("Path does not exist!")); + return; + } - Path pendingMemStickFolder(newPath); + Path pendingMemStickFolder(newPath); - if (!File::Exists(pendingMemStickFolder)) { - // Try to fix the path string, apparently some users got used to leaving out the /. - if (newPath[0] != '/') { - newPath = "/" + newPath; - } + if (!File::Exists(pendingMemStickFolder)) { + // Try to fix the path string, apparently some users got used to leaving out the /. + if (newPath[0] != '/') { + newPath = "/" + newPath; + } - pendingMemStickFolder = Path(newPath); - } + pendingMemStickFolder = Path(newPath); + } - if (!File::Exists(pendingMemStickFolder) && pendingMemStickFolder.Type() == PathType::NATIVE) { - // Still no path? Try to automatically fix the case. - std::string oldNewPath = newPath; - FixPathCase(Path(""), newPath, FixPathCaseBehavior::FPC_FILE_MUST_EXIST); - if (oldNewPath != newPath) { - NOTICE_LOG(IO, "Fixed path case: %s -> %s", oldNewPath.c_str(), newPath.c_str()); - pendingMemStickFolder = Path(newPath); - } else { - NOTICE_LOG(IO, "Failed to fix case of path %s (result: %s)", newPath.c_str(), oldNewPath.c_str()); - } - } + if (!File::Exists(pendingMemStickFolder) && pendingMemStickFolder.Type() == PathType::NATIVE) { + // Still no path? Try to automatically fix the case. + std::string oldNewPath = newPath; + FixPathCase(Path(""), newPath, FixPathCaseBehavior::FPC_FILE_MUST_EXIST); + if (oldNewPath != newPath) { + NOTICE_LOG(IO, "Fixed path case: %s -> %s", oldNewPath.c_str(), newPath.c_str()); + pendingMemStickFolder = Path(newPath); + } else { + NOTICE_LOG(IO, "Failed to fix case of path %s (result: %s)", newPath.c_str(), oldNewPath.c_str()); + } + } - if (pendingMemStickFolder == g_Config.memStickDirectory) { - // Same directory as before - all good. Nothing to do. - TriggerFinish(DialogResult::DR_OK); - return; - } + if (pendingMemStickFolder == g_Config.memStickDirectory) { + // Same directory as before - all good. Nothing to do. + TriggerFinish(DialogResult::DR_OK); + return; + } - if (!File::Exists(pendingMemStickFolder)) { - System_Toast(sy->T("Path does not exist!")); - return; - } + if (!File::Exists(pendingMemStickFolder)) { + System_Toast(sy->T("Path does not exist!")); + return; + } - screenManager()->push(new ConfirmMemstickMoveScreen(pendingMemStickFolder, false)); - } + screenManager()->push(new ConfirmMemstickMoveScreen(pendingMemStickFolder, false)); }); #endif return UI::EVENT_DONE; diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index e2c05d2b31..35503efce0 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -58,8 +58,10 @@ #include "android/jni/app-android.h" #include "Common/System/Display.h" +#include "Common/System/Request.h" #include "Common/System/System.h" #include "Common/System/NativeApp.h" + #include "Common/Data/Text/I18n.h" #include "Common/Input/InputState.h" #include "Common/Math/math_util.h" @@ -148,7 +150,7 @@ #include -ScreenManager *screenManager; +ScreenManager *g_screenManager; std::string config_filename; // Really need to clean this mess of globals up... but instead I add more :P @@ -164,15 +166,8 @@ struct PendingMessage { std::string value; }; -struct PendingInputBox { - std::function cb; - bool result; - std::string value; -}; - static std::mutex pendingMutex; static std::vector pendingMessages; -static std::vector pendingInputBoxes; static Draw::DrawContext *g_draw; static Draw::Pipeline *colorPipeline; static Draw::Pipeline *texColorPipeline; @@ -443,7 +438,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch setlocale( LC_ALL, "C" ); std::string user_data_path = savegame_dir; pendingMessages.clear(); - pendingInputBoxes.clear(); + g_requestManager.Clear(); // external_dir has all kinds of meanings depending on platform. // on iOS it's even the path to bundled app assets. It's a mess. @@ -789,19 +784,19 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch } DEBUG_LOG(SYSTEM, "ScreenManager!"); - screenManager = new ScreenManager(); + g_screenManager = new ScreenManager(); if (g_Config.memStickDirectory.empty()) { INFO_LOG(SYSTEM, "No memstick directory! Asking for one to be configured."); - screenManager->switchScreen(new LogoScreen(AfterLogoScreen::MEMSTICK_SCREEN_INITIAL_SETUP)); + g_screenManager->switchScreen(new LogoScreen(AfterLogoScreen::MEMSTICK_SCREEN_INITIAL_SETUP)); } else if (gotoGameSettings) { - screenManager->switchScreen(new LogoScreen(AfterLogoScreen::TO_GAME_SETTINGS)); + g_screenManager->switchScreen(new LogoScreen(AfterLogoScreen::TO_GAME_SETTINGS)); } else if (gotoTouchScreenTest) { - screenManager->switchScreen(new MainScreen()); - screenManager->push(new TouchTestScreen(Path())); + g_screenManager->switchScreen(new MainScreen()); + g_screenManager->push(new TouchTestScreen(Path())); } else if (skipLogo) { - screenManager->switchScreen(new EmuScreen(boot_filename)); + g_screenManager->switchScreen(new EmuScreen(boot_filename)); } else { - screenManager->switchScreen(new LogoScreen(AfterLogoScreen::DEFAULT)); + g_screenManager->switchScreen(new LogoScreen(AfterLogoScreen::DEFAULT)); } // Easy testing @@ -833,7 +828,7 @@ bool CreateGlobalPipelines(); bool NativeInitGraphics(GraphicsContext *graphicsContext) { INFO_LOG(SYSTEM, "NativeInitGraphics"); - _assert_(screenManager); + _assert_(g_screenManager); // We set this now so any resize during init is processed later. resized = false; @@ -864,10 +859,10 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) { if (uiContext->Text()) uiContext->Text()->SetFont("Tahoma", 20, 0); - screenManager->setUIContext(uiContext); - screenManager->setDrawContext(g_draw); - screenManager->setPostRenderCallback(&RenderOverlays, nullptr); - screenManager->deviceRestored(); + g_screenManager->setUIContext(uiContext); + g_screenManager->setDrawContext(g_draw); + g_screenManager->setPostRenderCallback(&RenderOverlays, nullptr); + g_screenManager->deviceRestored(); #ifdef _WIN32 winAudioBackend = CreateAudioBackend((AudioBackendType)g_Config.iAudioBackend); @@ -951,8 +946,8 @@ bool CreateGlobalPipelines() { void NativeShutdownGraphics() { INFO_LOG(SYSTEM, "NativeShutdownGraphics"); - if (screenManager) { - screenManager->deviceLost(); + if (g_screenManager) { + g_screenManager->deviceLost(); } if (gpu) @@ -1062,7 +1057,7 @@ void RenderOverlays(UIContext *dc, void *userdata) { void NativeRender(GraphicsContext *graphicsContext) { _dbg_assert_(graphicsContext != nullptr); - _dbg_assert_(screenManager != nullptr); + _dbg_assert_(g_screenManager != nullptr); g_GameManager.Update(); @@ -1108,19 +1103,19 @@ void NativeRender(GraphicsContext *graphicsContext) { ui_draw2d.PushDrawMatrix(ortho); ui_draw2d_front.PushDrawMatrix(ortho); - screenManager->getUIContext()->SetTintSaturation(g_Config.fUITint, g_Config.fUISaturation); + g_screenManager->getUIContext()->SetTintSaturation(g_Config.fUITint, g_Config.fUISaturation); Draw::DebugFlags debugFlags = Draw::DebugFlags::NONE; if (g_Config.bShowGpuProfile) debugFlags |= Draw::DebugFlags::PROFILE_TIMESTAMPS; if (g_Config.bGpuLogProfiler) debugFlags |= Draw::DebugFlags::PROFILE_SCOPES; - screenManager->getDrawContext()->SetDebugFlags(debugFlags); + g_screenManager->getDrawContext()->SetDebugFlags(debugFlags); // All actual rendering happen in here. - screenManager->render(); - if (screenManager->getUIContext()->Text()) { - screenManager->getUIContext()->Text()->OncePerFrame(); + g_screenManager->render(); + if (g_screenManager->getUIContext()->Text()) { + g_screenManager->getUIContext()->Text()->OncePerFrame(); } if (resized) { @@ -1142,7 +1137,7 @@ void NativeRender(GraphicsContext *graphicsContext) { } graphicsContext->Resize(); - screenManager->resized(); + g_screenManager->resized(); // TODO: Move this to the GraphicsContext objects for each backend. #if !PPSSPP_PLATFORM(WINDOWS) && !defined(ANDROID) @@ -1248,25 +1243,21 @@ void NativeUpdate() { PROFILE_END_FRAME(); std::vector toProcess; - std::vector inputToProcess; { std::lock_guard lock(pendingMutex); toProcess = std::move(pendingMessages); - inputToProcess = std::move(pendingInputBoxes); pendingMessages.clear(); - pendingInputBoxes.clear(); } for (const auto &item : toProcess) { HandleGlobalMessage(item.msg, item.value); - screenManager->sendMessage(item.msg.c_str(), item.value.c_str()); - } - for (const auto &item : inputToProcess) { - item.cb(item.result, item.value); + g_screenManager->sendMessage(item.msg.c_str(), item.value.c_str()); } + g_requestManager.ProcessRequests(); + g_DownloadManager.Update(); - screenManager->update(); + g_screenManager->update(); g_Discord.Update(); @@ -1275,11 +1266,11 @@ void NativeUpdate() { bool NativeIsAtTopLevel() { // This might need some synchronization? - if (!screenManager) { + if (!g_screenManager) { ERROR_LOG(SYSTEM, "No screen manager active"); return false; } - Screen *currentScreen = screenManager->topScreen(); + Screen *currentScreen = g_screenManager->topScreen(); if (currentScreen) { bool top = currentScreen->isTopLevel(); INFO_LOG(SYSTEM, "Screen toplevel: %i", (int)top); @@ -1291,7 +1282,7 @@ bool NativeIsAtTopLevel() { } void NativeTouch(const TouchInput &touch) { - if (!screenManager) { + if (!g_screenManager) { return; } @@ -1300,7 +1291,7 @@ void NativeTouch(const TouchInput &touch) { if (my_isnan(touch.x) || my_isnan(touch.y)) { return; } - screenManager->touch(touch); + g_screenManager->touch(touch); } bool NativeKey(const KeyInput &key) { @@ -1323,10 +1314,10 @@ bool NativeKey(const KeyInput &key) { } #endif bool retval = false; - if (screenManager) + if (g_screenManager) { HLEPlugins::PluginDataKeys[key.keyCode] = (key.flags & KEY_DOWN) ? 1 : 0; - retval = screenManager->key(key); + retval = g_screenManager->key(key); } return retval; } @@ -1337,7 +1328,7 @@ void NativeAxis(const AxisInput &axis) { return; } - if (!screenManager) { + if (!g_screenManager) { // Too early. return; } @@ -1346,7 +1337,7 @@ void NativeAxis(const AxisInput &axis) { // only do special handling of tilt events if tilt is enabled. HLEPlugins::PluginDataAxis[axis.axisId] = axis.value; - screenManager->axis(axis); + g_screenManager->axis(axis); if (g_Config.iTiltInputType == TILT_NULL) { // if tilt events are disabled, don't do anything special. @@ -1396,15 +1387,6 @@ void NativeMessageReceived(const char *message, const char *value) { pendingMessages.push_back(pendingMessage); } -void NativeInputBoxReceived(std::function cb, bool result, const std::string &value) { - std::lock_guard lock(pendingMutex); - PendingInputBox pendingMessage; - pendingMessage.cb = cb; - pendingMessage.result = result; - pendingMessage.value = value; - pendingInputBoxes.push_back(pendingMessage); -} - void NativeResized() { // NativeResized can come from any thread so we just set a flag, then process it later. VERBOSE_LOG(G3D, "NativeResized - setting flag"); @@ -1420,10 +1402,10 @@ bool NativeIsRestarting() { } void NativeShutdown() { - if (screenManager) { - screenManager->shutdown(); - delete screenManager; - screenManager = nullptr; + if (g_screenManager) { + g_screenManager->shutdown(); + delete g_screenManager; + g_screenManager = nullptr; } #if !PPSSPP_PLATFORM(UWP) diff --git a/UI/RemoteISOScreen.cpp b/UI/RemoteISOScreen.cpp index 98cea5ea85..d14c9999d4 100644 --- a/UI/RemoteISOScreen.cpp +++ b/UI/RemoteISOScreen.cpp @@ -31,6 +31,7 @@ #include "Common/Net/Resolve.h" #include "Common/Net/URL.h" #include "Common/Thread/ThreadUtil.h" +#include "Common/System/Request.h" #include "Common/File/PathBrowser.h" #include "Common/Data/Format/JSONReader.h" @@ -38,7 +39,6 @@ #include "Common/Common.h" #include "Common/Log.h" #include "Common/StringUtils.h" -#include "Common/System/System.h" #include "Common/TimeUtil.h" #include "Core/Config.h" #include "Core/System.h" @@ -643,7 +643,7 @@ void RemoteISOSettingsScreen::CreateViews() { UI::EventReturn RemoteISOSettingsScreen::OnClickRemoteServer(UI::EventParams &e) { #if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || defined(__ANDROID__) auto ri = GetI18NCategory("RemoteISO"); - System_InputBoxGetString(ri->T("Remote Server"), g_Config.sLastRemoteISOServer, [](bool result, const std::string &value) { + System_InputBoxGetString(ri->T("Remote Server"), g_Config.sLastRemoteISOServer, [](const std::string &value, int) { g_Config.sLastRemoteISOServer = value; }); #endif @@ -663,7 +663,7 @@ static void CleanupRemoteISOSubdir() { UI::EventReturn RemoteISOSettingsScreen::OnClickRemoteISOSubdir(UI::EventParams &e) { #if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || defined(__ANDROID__) auto ri = GetI18NCategory("RemoteISO"); - System_InputBoxGetString(ri->T("Remote Subdirectory"), g_Config.sRemoteISOSubdir, [](bool result, const std::string &value) { + System_InputBoxGetString(ri->T("Remote Subdirectory"), g_Config.sRemoteISOSubdir, [](const std::string &value, int) { g_Config.sRemoteISOSubdir = value; // Apply the cleanup logic, too. CleanupRemoteISOSubdir(); diff --git a/UI/SavedataScreen.cpp b/UI/SavedataScreen.cpp index 0d04ac02b9..c7ab4b7136 100644 --- a/UI/SavedataScreen.cpp +++ b/UI/SavedataScreen.cpp @@ -24,7 +24,7 @@ #include "Common/Data/Text/I18n.h" #include "Common/Math/curves.h" #include "Common/System/NativeApp.h" -#include "Common/System/System.h" +#include "Common/System/Request.h" #include "Common/Data/Encoding/Utf8.h" #include "Common/UI/Context.h" #include "Common/UI/View.h" @@ -674,8 +674,8 @@ UI::EventReturn SavedataScreen::OnSortClick(UI::EventParams &e) { UI::EventReturn SavedataScreen::OnSearch(UI::EventParams &e) { auto di = GetI18NCategory("Dialog"); #if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || defined(__ANDROID__) - System_InputBoxGetString(di->T("Filter"), searchFilter_, [](bool result, const std::string &value) { - if (result) { + System_InputBoxGetString(di->T("Filter"), searchFilter_, [](const std::string &value, int ivalue) { + if (ivalue) { NativeMessageReceived("savedatascreen_search", value.c_str()); } }); diff --git a/UWP/CommonUWP/CommonUWP.vcxproj b/UWP/CommonUWP/CommonUWP.vcxproj index a76a85ef67..f997600744 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj +++ b/UWP/CommonUWP/CommonUWP.vcxproj @@ -376,6 +376,7 @@ + @@ -510,6 +511,7 @@ + diff --git a/UWP/CommonUWP/CommonUWP.vcxproj.filters b/UWP/CommonUWP/CommonUWP.vcxproj.filters index 03f9424dfe..67e141a43f 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj.filters +++ b/UWP/CommonUWP/CommonUWP.vcxproj.filters @@ -429,6 +429,9 @@ ext\basis_universal + + System + @@ -811,6 +814,9 @@ ext\basis_universal + + System + diff --git a/UWP/PPSSPP_UWPMain.cpp b/UWP/PPSSPP_UWPMain.cpp index 1529a18887..39e27cbf56 100644 --- a/UWP/PPSSPP_UWPMain.cpp +++ b/UWP/PPSSPP_UWPMain.cpp @@ -443,6 +443,8 @@ void System_Notify(SystemNotification notification) { } } +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2) { return false; } + void System_SendMessage(const char *command, const char *parameter) { using namespace concurrency; diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp index f02d1e4f79..d81d20b121 100644 --- a/Windows/MainWindow.cpp +++ b/Windows/MainWindow.cpp @@ -107,7 +107,6 @@ struct VerySleepy_AddrInfo { }; static std::wstring windowTitle; -extern ScreenManager *screenManager; #define TIMER_CURSORUPDATE 1 #define TIMER_CURSORMOVEUPDATE 2 @@ -473,7 +472,6 @@ namespace MainWindow } void UpdateWindowTitle() { - // Seems to be fine to call now since we use a UNICODE build... std::wstring title = windowTitle; if (PPSSPP_ID >= 1 && GetInstancePeerCount() > 1) { title.append(ConvertUTF8ToWString(StringFromFormat(" (instance: %d)", (int)PPSSPP_ID))); diff --git a/Windows/main.cpp b/Windows/main.cpp index 4bf24d4d34..15fd6891d0 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -34,6 +34,7 @@ #include "Common/System/Display.h" #include "Common/System/NativeApp.h" #include "Common/System/System.h" +#include "Common/System/Request.h" #include "Common/File/FileUtil.h" #include "Common/File/VFS/VFS.h" #include "Common/File/VFS/DirectoryReader.h" @@ -109,8 +110,8 @@ static std::string restartArgs; int g_activeWindow = 0; -static std::thread inputBoxThread; -static bool inputBoxRunning = false; +static std::thread g_inputBoxThread; +static bool g_inputBoxRunning = false; int g_lastNumInstances = 0; void System_ShowFileInFolder(const char *path) { @@ -376,12 +377,13 @@ static BOOL PostDialogMessage(Dialog *dialog, UINT message, WPARAM wParam = 0, L return PostMessage(dialog->GetDlgHandle(), message, wParam, lParam); } +// This can come from any thread, so this mostly uses PostMessage. Can't access most data directly. void System_Notify(SystemNotification notification) { switch (notification) { case SystemNotification::BOOT_DONE: { if (g_symbolMap) - g_symbolMap->SortSymbols(); + g_symbolMap->SortSymbols(); // internal locking is performed here PostMessage(MainWindow::GetHWND(), WM_USER + 1, 0, 0); if (disasmWindow) @@ -413,7 +415,7 @@ void System_Notify(SystemNotification notification) { case SystemNotification::SYMBOL_MAP_UPDATED: if (g_symbolMap) - g_symbolMap->SortSymbols(); + g_symbolMap->SortSymbols(); // internal locking is performed here PostMessage(MainWindow::GetHWND(), WM_USER + 1, 0, 0); break; @@ -428,6 +430,28 @@ void System_Notify(SystemNotification notification) { } } +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2) { + switch (type) { + case SystemRequestType::INPUT_TEXT_MODAL: + if (g_inputBoxRunning) { + g_inputBoxThread.join(); + } + + g_inputBoxRunning = true; + g_inputBoxThread = std::thread([=] { + std::string out; + if (InputBox_GetString(MainWindow::GetHInstance(), MainWindow::GetHWND(), ConvertUTF8ToWString(param1).c_str(), param2, out)) { + g_requestManager.PostSystemSuccess(requestId, out.c_str()); + } else { + g_requestManager.PostSystemFailure(requestId); + } + }); + return true; + default: + return false; + } +} + void System_SendMessage(const char *command, const char *parameter) { if (!strcmp(command, "finish")) { if (!NativeIsRestarting()) { @@ -497,22 +521,6 @@ void EnableCrashingOnCrashes() { FreeLibrary(kernel32); } -void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb) { - if (inputBoxRunning) { - inputBoxThread.join(); - } - - inputBoxRunning = true; - inputBoxThread = std::thread([=] { - std::string out; - if (InputBox_GetString(MainWindow::GetHInstance(), MainWindow::GetHWND(), ConvertUTF8ToWString(title).c_str(), defaultValue, out)) { - NativeInputBoxReceived(cb, true, out); - } else { - NativeInputBoxReceived(cb, false, ""); - } - }); -} - void System_Toast(const char *text) { // Not-very-good implementation. Will normally not be used on Windows anyway. std::wstring str = ConvertUTF8ToWString(text); @@ -619,9 +627,9 @@ static void WinMainInit() { } static void WinMainCleanup() { - if (inputBoxRunning) { - inputBoxThread.join(); - inputBoxRunning = false; + if (g_inputBoxRunning) { + g_inputBoxThread.join(); + g_inputBoxRunning = false; } net::Shutdown(); CoUninitialize(); diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 61aaefc181..28775b9b2f 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -214,6 +214,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Common/Net/WebsocketServer.cpp \ $(SRC)/Common/Profiler/Profiler.cpp \ $(SRC)/Common/System/Display.cpp \ + $(SRC)/Common/System/Request.cpp \ $(SRC)/Common/Thread/ThreadUtil.cpp \ $(SRC)/Common/Thread/ThreadManager.cpp \ $(SRC)/Common/Thread/ParallelLoop.cpp \ diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 65a483e519..6a9e42a829 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -61,6 +61,7 @@ struct JNIEnv {}; #include "Common/System/Display.h" #include "Common/System/NativeApp.h" #include "Common/System/System.h" +#include "Common/System/Request.h" #include "Common/Thread/ThreadUtil.h" #include "Common/File/Path.h" #include "Common/File/DirListing.h" @@ -175,9 +176,6 @@ static std::atomic renderLoopRunning; static bool renderer_inited = false; static std::mutex renderLock; -static int inputBoxSequence = 1; -static std::map> inputBoxCallbacks; - static bool sustainedPerfSupported = false; static std::map permissions; @@ -909,7 +907,6 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) { { std::lock_guard guard(renderLock); - inputBoxCallbacks.clear(); NativeShutdown(); g_VFS.Clear(); } @@ -1032,12 +1029,17 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv } } -void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb) { - int seq = inputBoxSequence++; - inputBoxCallbacks[seq] = cb; - - std::string serialized = StringFromFormat("%d:@:%s:@:%s", seq, title.c_str(), defaultValue.c_str()); - System_SendMessage("inputbox", serialized.c_str()); +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2) { + switch (type) { + case SystemRequestType::INPUT_TEXT_MODAL: + { + std::string serialized = StringFromFormat("%d:@:%s:@:%s", requestId, param1.c_str(), param2.c_str()); + PushCommand("inputbox", serialized.c_str()); + return true; + } + default: + return false; + } } extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendInputBox(JNIEnv *env, jclass, jstring jseqID, jboolean result, jstring jvalue) { @@ -1058,13 +1060,11 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendInputBox(JNIEnv *en return; } - auto entry = inputBoxCallbacks.find(seq); - if (entry == inputBoxCallbacks.end()) { - ERROR_LOG(SYSTEM, "Did not find inputbox callback for %s, shutdown?", seqID.c_str()); - return; + if (result) { + g_requestManager.PostSystemSuccess(seq, value.c_str()); + } else { + g_requestManager.PostSystemFailure(seq); } - - NativeInputBoxReceived(entry->second, result, value); } void LockedNativeUpdateRender() { diff --git a/headless/Headless.cpp b/headless/Headless.cpp index 27e0508e64..8d6ae20519 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -116,6 +116,7 @@ bool System_GetPropertyBool(SystemProperty prop) { } void System_Notify(SystemNotification notification) {} void System_SendMessage(const char *command, const char *parameter) {} +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2) { return false; } void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb) { cb(false, ""); } void System_AskForPermission(SystemPermission permission) {} PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; } diff --git a/ios/main.mm b/ios/main.mm index 155bf79995..3caaf93e26 100644 --- a/ios/main.mm +++ b/ios/main.mm @@ -219,6 +219,10 @@ void System_SendMessage(const char *command, const char *parameter) { } } +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2) { + return false; +} + void System_Toast(const char *text) {} void System_AskForPermission(SystemPermission permission) {} diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 3beb711568..83e477f941 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -341,6 +341,7 @@ SOURCES_CXX += \ $(COMMONDIR)/UI/ScrollView.cpp \ $(COMMONDIR)/UI/PopupScreens.cpp \ $(COMMONDIR)/System/Display.cpp \ + $(COMMONDIR)/System/Request.cpp \ $(COMMONDIR)/ArmCPUDetect.cpp \ $(COMMONDIR)/CPUDetect.cpp \ $(COMMONDIR)/Buffer.cpp \ diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index 05b13dcdbf..cdb699bb56 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -1874,7 +1874,7 @@ void System_Notify(SystemNotification notification) { break; } } - +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2) { return false; } void System_SendMessage(const char *command, const char *parameter) {} void NativeUpdate() {} void NativeRender(GraphicsContext *graphicsContext) {} diff --git a/unittest/JitHarness.cpp b/unittest/JitHarness.cpp index ebbcdefa39..f730cc44d6 100644 --- a/unittest/JitHarness.cpp +++ b/unittest/JitHarness.cpp @@ -42,6 +42,7 @@ void NativeRender(GraphicsContext *graphicsContext) { } void NativeResized() { } void System_SendMessage(const char *command, const char *parameter) {} +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2) { return false; } void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb) { cb(false, ""); } void System_AskForPermission(SystemPermission permission) {} PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }