From 3852d4f698ec35fafe012da06298d667ab101331 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 Mar 2023 11:34:48 +0100 Subject: [PATCH] Make a little system to replace the InputBox message queue with something more generic --- Common/Common.vcxproj | 2 ++ Common/Common.vcxproj.filters | 6 ++++ Common/System/Message.cpp | 55 +++++++++++++++++++++++++++++++++++ Common/System/Message.h | 50 +++++++++++++++++++++++++++++++ Common/System/System.h | 10 +++++++ Windows/main.cpp | 20 +++++++++++++ 6 files changed, 143 insertions(+) create mode 100644 Common/System/Message.cpp create mode 100644 Common/System/Message.h diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index c066494c66..a28696099b 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..23b138fb39 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/Message.cpp b/Common/System/Message.cpp new file mode 100644 index 0000000000..8a09fc3a04 --- /dev/null +++ b/Common/System/Message.cpp @@ -0,0 +1,55 @@ +#include "Common/System/Message.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 char *param1, const char *param2) { + 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::PostSystemResponse(int requestId, const char *responseString, int responseValue) { + std::lock_guard guard(callbackMutex_); + auto iter = callbackMap_.find(requestId); + if (iter == callbackMap_.end()) { + // Unexpected! + ERROR_LOG(SYSTEM, "PostSystemResponse: Unexpected request ID %d for %s (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::ProcessRequests() { + std::lock_guard guard(responseMutex_); + for (auto &iter : pendingResponses_) { + if (iter.callback) { + iter.callback(iter.responseString.c_str(), iter.responseValue); + } + } + pendingResponses_.clear(); +} diff --git a/Common/System/Message.h b/Common/System/Message.h new file mode 100644 index 0000000000..88cd58df41 --- /dev/null +++ b/Common/System/Message.h @@ -0,0 +1,50 @@ +#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 char *param1, const char *param2); + + // Called by the platform implementation, when it's finished with a request. + void PostSystemResponse(int requestId, const char *responseString, int responseValue); + + // This must be called every frame from the beginning of NativeUpdate(). + // This will call the callback of any finished requests. + void ProcessRequests(); + +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; diff --git a/Common/System/System.h b/Common/System/System.h index 8d74f9c270..c33bac6ed0 100644 --- a/Common/System/System.h +++ b/Common/System/System.h @@ -146,6 +146,16 @@ enum class SystemNotification { SWITCH_UMD_UPDATED, }; +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 char *param1, const char *param2); + std::string System_GetProperty(SystemProperty prop); std::vector System_GetPropertyStringVec(SystemProperty prop); int System_GetPropertyInt(SystemProperty prop); diff --git a/Windows/main.cpp b/Windows/main.cpp index 4bf24d4d34..7db15f7b81 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -513,6 +513,26 @@ void System_InputBoxGetString(const std::string &title, const std::string &defau }); } +bool System_PerformRequest(SystemRequestType type, int requestId, const char *param1, const char *param2) { + switch (type) { + case SystemRequestType::INPUT_TEXT_MODAL: + 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);