diff --git a/Common/UI/ScreenManager.cpp b/Common/UI/ScreenManager.cpp index d7bbbd3b80..75857fb711 100644 --- a/Common/UI/ScreenManager.cpp +++ b/Common/UI/ScreenManager.cpp @@ -61,7 +61,7 @@ void ScreenManager::cancelScreensAbove(Screen *screen) { } } -void ScreenManager::update() { +void ScreenManager::update(const std::vector &events) { if (cancelScreensAbove_) { bool found = false; for (int i = (int)stack_.size() - 1; i >= 0; i--) { @@ -84,14 +84,6 @@ void ScreenManager::update() { overlayScreen_->update(); } - // Process queued events. - std::deque events; - { - std::lock_guard eventGuard(eventQueueLock_); - events = std::move(eventQueue_); - eventQueue_.clear(); - } - for (const QueuedEvent &ev : events) { switch (ev.type) { case QueuedEventType::TOUCH: @@ -174,32 +166,6 @@ void ScreenManager::switchToNext() { nextStack_.clear(); } -void ScreenManager::touch(const TouchInput &touch) { - QueuedEvent ev{}; - ev.type = QueuedEventType::TOUCH; - ev.touch = touch; - std::lock_guard guard(eventQueueLock_); - eventQueue_.push_back(ev); -} - -void ScreenManager::key(const KeyInput &key) { - QueuedEvent ev{}; - ev.type = QueuedEventType::KEY; - ev.key = key; - std::lock_guard guard(eventQueueLock_); - eventQueue_.push_back(ev); -} - -void ScreenManager::axis(const AxisInput *axes, size_t count) { - QueuedEvent ev{}; - ev.type = QueuedEventType::AXIS; - std::lock_guard guard(eventQueueLock_); - for (size_t i = 0; i < count; i++) { - ev.axis = axes[i]; - eventQueue_.push_back(ev); - } -} - void ScreenManager::deviceLost() { for (auto &iter : stack_) iter.screen->deviceLost(); @@ -331,16 +297,7 @@ void ScreenManager::getFocusPosition(float &x, float &y, float &z) { void ScreenManager::sendMessage(UIMessage message, const char *value) { if (message == UIMessage::RECREATE_VIEWS) { RecreateAllViews(); - } else if (message == UIMessage::LOST_FOCUS) { - TouchInput input{}; - input.x = -50000.0f; - input.y = -50000.0f; - input.flags = TouchInputFlags::RELEASE_ALL; - input.timestamp = time_now_d(); - input.id = 0; - touch(input); } - if (backgroundScreen_) { backgroundScreen_->sendMessage(message, value); } @@ -380,13 +337,6 @@ void ScreenManager::push(Screen *screen, int layerFlags) { // Release touches and unfocus. UI::SetFocusedView(nullptr, UI::FocusFlags::CAUSE_SCREEN_CHANGE); - TouchInput input{}; - input.x = -50000.0f; - input.y = -50000.0f; - input.flags = TouchInputFlags::RELEASE_ALL; - input.timestamp = time_now_d(); - input.id = 0; - touch(input); Layer layer = {screen, layerFlags}; diff --git a/Common/UI/ScreenManager.h b/Common/UI/ScreenManager.h index c88c6f775d..d18474a2b2 100644 --- a/Common/UI/ScreenManager.h +++ b/Common/UI/ScreenManager.h @@ -34,7 +34,7 @@ public: virtual ~ScreenManager(); void switchScreen(Screen *screen); - void update(); + void update(const std::vector &events); void setUIContext(UIContext *context) { uiContext_ = context; } UIContext *getUIContext() { return uiContext_; } @@ -62,11 +62,6 @@ public: void finishDialog(Screen *dialog, DialogResult result = DR_OK); Screen *dialogParent(const Screen *dialog) const; - // Instant touch, separate from the update() mechanism. - void touch(const TouchInput &touch); - void key(const KeyInput &key); - void axis(const AxisInput *axes, size_t count); - void sendMessage(UIMessage message, const char *value); const Screen *topScreen() const { @@ -119,8 +114,5 @@ private: std::unordered_map lastAxis_; - std::mutex eventQueueLock_; - std::deque eventQueue_; - InputMode passInputToMapper_ = InputMode::None; }; diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 62c07447da..070c9998a5 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -199,6 +199,9 @@ static bool g_savedAchievementsHardcoreMode = false; static bool g_hasSavedAchievementsSettings = false; static bool g_nativeMainThreadReady = false; +static std::mutex g_inputEventQueueLock; +static std::vector g_inputEventQueue; + static void ApplyAchievementsRuntimeSettings() { auto *client = Achievements::GetClient(); if (!client) { @@ -1024,7 +1027,14 @@ void NativeFrame(GraphicsContext *graphicsContext) { debugFlags |= Draw::DebugFlags::PROFILE_SCOPES; g_draw->BeginFrame(debugFlags); - g_screenManager->update(); + // Process queued events. + std::vector inputEvents; + { + std::lock_guard eventGuard(g_inputEventQueueLock); + inputEvents = std::move(g_inputEventQueue); + g_inputEventQueue.clear(); + } + g_screenManager->update(inputEvents); // Do this after g_screenManager.update() so we can receive setting changes before rendering. { @@ -1052,6 +1062,22 @@ void NativeFrame(GraphicsContext *graphicsContext) { // TODO: Add a to-string thingy. VERBOSE_LOG(Log::System, "Handled global message: %d / %s", (int)item.message, item.value.c_str()); } + + if (item.message == UIMessage::LOST_FOCUS) { + // This is a bit of a hack, but we need to do this here so that the graphics context is valid. + TouchInput input{}; + input.x = -50000.0f; + input.y = -50000.0f; + input.flags = TouchInputFlags::RELEASE_ALL; + input.timestamp = time_now_d(); + input.id = 0; + std::lock_guard eventGuard(g_inputEventQueueLock); + QueuedEvent q{}; + q.type = QueuedEventType::TOUCH; + q.touch = input; + g_inputEventQueue.push_back(q); + } + g_screenManager->sendMessage(item.message, item.value.c_str()); } } @@ -1248,7 +1274,12 @@ void NativeTouch(const TouchInput &touch) { if (my_isnan(touch.x) || my_isnan(touch.y)) { return; } - g_screenManager->touch(touch); + + QueuedEvent ev{}; + ev.type = QueuedEventType::TOUCH; + ev.touch = touch; + std::lock_guard guard(g_inputEventQueueLock); + g_inputEventQueue.push_back(ev); } // up, down @@ -1458,8 +1489,14 @@ bool NativeKey(const KeyInput &key) { return false; } - // Dispatch the key event. - g_screenManager->key(modKey); + // Queue up the key event for synchronous processing in the UI. + QueuedEvent ev{}; + ev.type = QueuedEventType::KEY; + ev.key = key; + { + std::lock_guard guard(g_inputEventQueueLock); + g_inputEventQueue.push_back(ev); + } // The Mode key can have weird consequences on some devices, see #17245. if (key.keyCode == NKCODE_BUTTON_MODE) { @@ -1487,7 +1524,15 @@ void NativeAxis(const AxisInput *axes, size_t count) { g_controlMapper.Axis(axes, count); } - g_screenManager->axis(axes, count); + QueuedEvent ev{}; + ev.type = QueuedEventType::AXIS; + { + std::lock_guard guard(g_inputEventQueueLock); + for (size_t i = 0; i < count; i++) { + ev.axis = axes[i]; + g_inputEventQueue.push_back(ev); + } + } for (size_t i = 0; i < count; i++) { const AxisInput &axis = axes[i];