diff --git a/Common/UI/PopupScreens.cpp b/Common/UI/PopupScreens.cpp index 4e059df9fe..2195085816 100644 --- a/Common/UI/PopupScreens.cpp +++ b/Common/UI/PopupScreens.cpp @@ -51,11 +51,11 @@ PopupScreen::PopupScreen(std::string_view title, std::string_view button1, std:: alpha_ = 0.0f; // inherited } -void PopupScreen::touch(const TouchInput &touch) { +bool PopupScreen::touch(const TouchInput &touch) { if (!box_ || (touch.flags & TouchInputFlags::DOWN) == 0) { // Handle down-presses here. UIDialogScreen::touch(touch); - return; + return false; } // Extra bounds to avoid closing the dialog while trying to aim for something @@ -65,7 +65,7 @@ void PopupScreen::touch(const TouchInput &touch) { TriggerFinish(DR_CANCEL); } - UIDialogScreen::touch(touch); + return UIDialogScreen::touch(touch); } bool PopupScreen::key(const KeyInput &key) { diff --git a/Common/UI/PopupScreens.h b/Common/UI/PopupScreens.h index b0703acbbe..abd8ba39f1 100644 --- a/Common/UI/PopupScreens.h +++ b/Common/UI/PopupScreens.h @@ -25,7 +25,7 @@ public: virtual void CreatePopupContents(UI::ViewGroup *parent) = 0; void CreateViews() override; bool isTransparent() const override { return true; } - void touch(const TouchInput &touch) override; + bool touch(const TouchInput &touch) override; bool key(const KeyInput &key) override; void TriggerFinish(DialogResult result) override; diff --git a/Common/UI/Screen.cpp b/Common/UI/Screen.cpp index 48a664fea9..bba41c49b2 100644 --- a/Common/UI/Screen.cpp +++ b/Common/UI/Screen.cpp @@ -108,7 +108,6 @@ void ScreenManager::cancelScreensAbove(Screen *screen) { void ScreenManager::update() { std::lock_guard guard(inputLock_); - if (cancelScreensAbove_) { bool found = false; for (int i = (int)stack_.size() - 1; i >= 0; i--) { @@ -136,6 +135,67 @@ void ScreenManager::update() { stack_.back().screen->update(); passInputToMapper_ = stack_.back().screen->PassInputToMapper(); } + + // Process queued events. + + std::lock_guard eventGuard(eventQueueLock_); + + for (const QueuedEvent &ev : eventQueue_) { + switch (ev.type) { + case QueuedEventType::TOUCH: + { + const TouchInput &touch = ev.touch; + + // Send release all events to every screen layer. + if (touch.flags & TouchInputFlags::RELEASE_ALL) { + for (auto &layer : stack_) { + Screen *screen = layer.screen; + layer.screen->touch(screen->transformTouch(touch)); + } + } else if (!stack_.empty()) { + // Let the overlay know about touch-downs, to be able to dismiss popups. + bool skip = false; + if (overlayScreen_ && (touch.flags & TouchInputFlags::DOWN)) { + skip = overlayScreen_->touch(overlayScreen_->transformTouch(touch)); + } + if (!skip) { + Screen *screen = stack_.back().screen; + stack_.back().screen->touch(screen->transformTouch(touch)); + } + } + break; + } + case QueuedEventType::KEY: + { + const KeyInput &key = ev.key; + + std::lock_guard guard(inputLock_); + // Send key up to every screen layer, to avoid stuck keys. + if (key.flags & KeyInputFlags::UP) { + for (auto &layer : stack_) { + layer.screen->key(key); + } + } else if (!stack_.empty()) { + stack_.back().screen->key(key); + } + + break; + } + case QueuedEventType::AXIS: + { + const AxisInput &axis = ev.axis; + + std::lock_guard guard(inputLock_); + if (!stack_.empty()) { + stack_.back().screen->axis(axis); + } + break; + } + default: + ERROR_LOG(Log::UI, "Unknown queued event type: %d", (int)ev.type); + break; + } + } } void ScreenManager::switchToNext() { @@ -163,42 +223,28 @@ void ScreenManager::switchToNext() { } void ScreenManager::touch(const TouchInput &touch) { - std::lock_guard guard(inputLock_); - // Send release all events to every screen layer. - if (touch.flags & TouchInputFlags::RELEASE_ALL) { - for (auto &layer : stack_) { - Screen *screen = layer.screen; - layer.screen->UnsyncTouch(screen->transformTouch(touch)); - } - } else if (!stack_.empty()) { - // Let the overlay know about touch-downs, to be able to dismiss popups. - bool skip = false; - if (overlayScreen_ && (touch.flags & TouchInputFlags::DOWN)) { - skip = overlayScreen_->UnsyncTouch(overlayScreen_->transformTouch(touch)); - } - if (!skip) { - Screen *screen = stack_.back().screen; - stack_.back().screen->UnsyncTouch(screen->transformTouch(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) { - std::lock_guard guard(inputLock_); - // Send key up to every screen layer, to avoid stuck keys. - if (key.flags & KeyInputFlags::UP) { - for (auto &layer : stack_) { - layer.screen->UnsyncKey(key); - } - } else if (!stack_.empty()) { - stack_.back().screen->UnsyncKey(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) { - std::lock_guard guard(inputLock_); - if (!stack_.empty()) { - stack_.back().screen->UnsyncAxis(axes, 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); } } diff --git a/Common/UI/Screen.h b/Common/UI/Screen.h index 046da7b498..7d8f7d73c2 100644 --- a/Common/UI/Screen.h +++ b/Common/UI/Screen.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -84,6 +85,21 @@ enum class InputMode { }; ENUM_CLASS_BITOPS(InputMode); +enum class QueuedEventType : u8 { + KEY, + AXIS, + TOUCH, +}; + +struct QueuedEvent { + QueuedEventType type; + union { + TouchInput touch; + KeyInput key; + AxisInput axis; + }; +}; + class Screen { public: Screen() = default; @@ -103,11 +119,9 @@ public: virtual void focusChanged(ScreenFocusChange focusChange); - // Return value of UnsyncTouch is only used to let the overlay screen block touches. - virtual bool UnsyncTouch(const TouchInput &touch) = 0; - // Return value of UnsyncKey is used to not block certain system keys like volume when unhandled, on Android. - virtual void UnsyncKey(const KeyInput &touch) = 0; - virtual void UnsyncAxis(const AxisInput *axes, size_t count) = 0; + virtual bool touch(const TouchInput &touch) = 0; + virtual bool key(const KeyInput &key) = 0; + virtual void axis(const AxisInput &axis) = 0; virtual void RecreateViews() {} @@ -208,7 +222,6 @@ public: InputMode PassInputToMapper() const { return passInputToMapper_; } - std::recursive_mutex inputLock_; private: @@ -243,5 +256,8 @@ private: std::unordered_map lastAxis_; + std::mutex eventQueueLock_; + std::deque eventQueue_; + InputMode passInputToMapper_ = InputMode::None; }; diff --git a/Common/UI/UIScreen.cpp b/Common/UI/UIScreen.cpp index f6289ece88..ffe81312ff 100644 --- a/Common/UI/UIScreen.cpp +++ b/Common/UI/UIScreen.cpp @@ -66,7 +66,7 @@ void UIScreen::DoRecreateViews() { WipeRequesterToken(); } -void UIScreen::touch(const TouchInput &touch) { +bool UIScreen::touch(const TouchInput &touch) { if (ClickDebug && root_ && (touch.flags & TouchInputFlags::DOWN)) { INFO_LOG(Log::System, "Touch down!"); std::vector views; @@ -79,6 +79,7 @@ void UIScreen::touch(const TouchInput &touch) { if (!ignoreInput_ && root_) { UI::TouchEvent(touch, root_); } + return true; } void UIScreen::axis(const AxisInput &axis) { @@ -95,33 +96,6 @@ bool UIScreen::key(const KeyInput &key) { } } -bool UIScreen::UnsyncTouch(const TouchInput &touch) { - QueuedEvent ev{}; - ev.type = QueuedEventType::TOUCH; - ev.touch = touch; - std::lock_guard guard(eventQueueLock_); - eventQueue_.push_back(ev); - return false; -} - -void UIScreen::UnsyncAxis(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 UIScreen::UnsyncKey(const KeyInput &key) { - QueuedEvent ev{}; - ev.type = QueuedEventType::KEY; - ev.key = key; - std::lock_guard guard(eventQueueLock_); - eventQueue_.push_back(ev); -} - void UIScreen::update() { DeviceOrientation orientation = GetDeviceOrientation(); if (orientation != lastOrientation_) { @@ -131,41 +105,6 @@ void UIScreen::update() { DoRecreateViews(); - while (true) { - QueuedEvent ev{}; - { - std::lock_guard guard(eventQueueLock_); - if (!eventQueue_.empty()) { - ev = eventQueue_.front(); - eventQueue_.pop_front(); - } else { - break; - } - } - if (ignoreInput_) { - continue; - } - switch (ev.type) { - case QueuedEventType::KEY: - key(ev.key); - break; - case QueuedEventType::TOUCH: - if (ClickDebug && (ev.touch.flags & TouchInputFlags::DOWN)) { - INFO_LOG(Log::System, "Touch down!"); - std::vector views; - root_->Query(ev.touch.x, ev.touch.y, views); - for (auto view : views) { - INFO_LOG(Log::System, "%s", view->DescribeLog().c_str()); - } - } - touch(ev.touch); - break; - case QueuedEventType::AXIS: - axis(ev.axis); - break; - } - } - if (root_) { DialogResult result = UpdateViewHierarchy(root_); if (result != DR_NONE) { diff --git a/Common/UI/UIScreen.h b/Common/UI/UIScreen.h index f6124ccfe8..de162797d6 100644 --- a/Common/UI/UIScreen.h +++ b/Common/UI/UIScreen.h @@ -17,21 +17,6 @@ namespace Draw { class DrawContext; } -enum class QueuedEventType : u8 { - KEY, - AXIS, - TOUCH, -}; - -struct QueuedEvent { - QueuedEventType type; - union { - TouchInput touch; - KeyInput key; - AxisInput axis; - }; -}; - class UIScreen : public Screen { public: UIScreen(); @@ -42,13 +27,9 @@ public: void deviceLost() override; void deviceRestored(Draw::DrawContext *draw) override; - virtual void touch(const TouchInput &touch); - virtual bool key(const KeyInput &key); - virtual void axis(const AxisInput &axis); - - bool UnsyncTouch(const TouchInput &touch) override; - void UnsyncKey(const KeyInput &key) override; - void UnsyncAxis(const AxisInput *axes, size_t count) override; + bool touch(const TouchInput &touch) override; + bool key(const KeyInput &key) override; + void axis(const AxisInput &axis) override; TouchInput transformTouch(const TouchInput &touch) override; @@ -92,10 +73,6 @@ protected: bool recreateViews_ = true; DeviceOrientation lastOrientation_ = DeviceOrientation::Landscape; - -private: - std::mutex eventQueueLock_; - std::deque eventQueue_; }; class UIDialogScreen : public UIScreen { diff --git a/Core/RetroAchievements.cpp b/Core/RetroAchievements.cpp index 0b9f1125ba..4366d87359 100644 --- a/Core/RetroAchievements.cpp +++ b/Core/RetroAchievements.cpp @@ -615,7 +615,7 @@ static void load_integration_callback(int result, const char *error_message, rc_ } case RC_MISSING_VALUE: // This is fine, proceeding to login. - g_OSD.Show(OSDType::MESSAGE_WARNING, ac->T("RAIntegration is enabled, but %1 was not found.")); + g_OSD.Show(OSDType::MESSAGE_WARNING, ApplySafeSubstitutions(ac->T("RAIntegration is enabled, but %1 was not found."), RAINTEGRATION_FILENAME)); break; case RC_ABORTED: // This is fine(-ish), proceeding to login. diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 78ec366383..b9432c0dd2 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -629,7 +629,7 @@ void FrameDumpTestScreen::update() { } } -void TouchTestScreen::touch(const TouchInput &touch) { +bool TouchTestScreen::touch(const TouchInput &touch) { UIBaseDialogScreen::touch(touch); if (touch.flags & TouchInputFlags::DOWN) { bool found = false; @@ -678,6 +678,7 @@ void TouchTestScreen::touch(const TouchInput &touch) { WARN_LOG(Log::System, "Touch release without touch down"); } } + return true; } // TODO: Move this screen out into its own file. diff --git a/UI/DevScreens.h b/UI/DevScreens.h index ebe12887d3..3636eccf09 100644 --- a/UI/DevScreens.h +++ b/UI/DevScreens.h @@ -169,7 +169,7 @@ public: } } - void touch(const TouchInput &touch) override; + bool touch(const TouchInput &touch) override; void DrawForeground(UIContext &dc) override; bool key(const KeyInput &key) override; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 1a51683532..855c9723ed 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1212,7 +1212,7 @@ bool EmuScreen::key(const KeyInput &key) { return retval; } -void EmuScreen::touch(const TouchInput &touch) { +bool EmuScreen::touch(const TouchInput &touch) { System_Notify(SystemNotification::ACTIVITY); bool ignoreGamepad = false; @@ -1234,7 +1234,7 @@ void EmuScreen::touch(const TouchInput &touch) { if (g_Config.bShowImDebugger && imguiInited_) { ImGui_ImplPlatform_TouchEvent(touch); if (!ImGui::GetIO().WantCaptureMouse) { - UIScreen::touch(touch); + return UIScreen::touch(touch); } } else if (g_Config.bMouseControl && !(touch.flags & TouchInputFlags::UP) && (touch.flags & TouchInputFlags::MOUSE)) { // don't do anything as the mouse pointer is hidden in this case. @@ -1252,8 +1252,9 @@ void EmuScreen::touch(const TouchInput &touch) { } } } - UIScreen::touch(touch); + return UIScreen::touch(touch); } + return false; } // TODO: Shouldn't actually need bounds for this, Anchor can center too. diff --git a/UI/EmuScreen.h b/UI/EmuScreen.h index fb00911608..3fe396453e 100644 --- a/UI/EmuScreen.h +++ b/UI/EmuScreen.h @@ -56,7 +56,7 @@ public: // We also need to do some special handling of queued UI events to handle closing the chat window. bool key(const KeyInput &key) override; - void touch(const TouchInput &key) override; + bool touch(const TouchInput &key) override; void deviceLost() override; void deviceRestored(Draw::DrawContext *draw) override; diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index 8eadd8eed8..e1c0278b58 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -419,10 +419,12 @@ bool LogoScreen::key(const KeyInput &key) { return false; } -void LogoScreen::touch(const TouchInput &touch) { +bool LogoScreen::touch(const TouchInput &touch) { if (touch.flags & TouchInputFlags::DOWN) { Next(); + return true; } + return false; } void LogoScreen::DrawForeground(UIContext &dc) { diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index 14b8e4a3b1..9e9fc8cd0d 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -101,7 +101,7 @@ public: LogoScreen(AfterLogoScreen afterLogoScreen = AfterLogoScreen::DEFAULT); bool key(const KeyInput &key) override; - void touch(const TouchInput &touch) override; + bool touch(const TouchInput &touch) override; void update() override; void DrawForeground(UIContext &ui) override; void sendMessage(UIMessage message, const char *value) override; diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index eac30899f0..23eb404068 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1478,6 +1478,16 @@ bool NativeKey(const KeyInput &key) { g_controlMapper.Key(key); } + // Ignore volume keys and stuff here - though we do send them through to the control mapper, so they can be mapped to PSP buttons. + switch (key.keyCode) { + case NKCODE_VOLUME_DOWN: + case NKCODE_VOLUME_UP: + case NKCODE_VOLUME_MUTE: + return false; + default: + break; + } + // Track modifier keys. if (key.flags & KeyInputFlags::DOWN) { switch (key.keyCode) { @@ -1526,16 +1536,6 @@ bool NativeKey(const KeyInput &key) { KeyInput modKey = key; modKey.flags |= modifierFlags; - // Ignore volume keys and stuff here. Not elegant but need to propagate bools through the view hierarchy as well... - switch (key.keyCode) { - case NKCODE_VOLUME_DOWN: - case NKCODE_VOLUME_UP: - case NKCODE_VOLUME_MUTE: - return false; - default: - break; - } - bool retval = false; UI::KeyEventResult kev = UI::KeyEventToFocusMoves(key); diff --git a/UI/OnScreenDisplay.cpp b/UI/OnScreenDisplay.cpp index 271855fd7a..79ec0d3357 100644 --- a/UI/OnScreenDisplay.cpp +++ b/UI/OnScreenDisplay.cpp @@ -389,7 +389,7 @@ bool OnScreenMessagesView::Dismiss(float x, float y) { return dismissed; } -bool OSDOverlayScreen::UnsyncTouch(const TouchInput &touch) { +bool OSDOverlayScreen::touch(const TouchInput &touch) { // Don't really need to forward. // UIScreen::UnsyncTouch(touch); if ((touch.flags & TouchInputFlags::DOWN) && osmView_) { diff --git a/UI/OnScreenDisplay.h b/UI/OnScreenDisplay.h index 7ed2f78d91..7206a01651 100644 --- a/UI/OnScreenDisplay.h +++ b/UI/OnScreenDisplay.h @@ -38,7 +38,7 @@ class OSDOverlayScreen : public UIScreen { public: const char *tag() const override { return "OSDOverlayScreen"; } - bool UnsyncTouch(const TouchInput &touch) override; + bool touch(const TouchInput &touch) override; void CreateViews() override; void DrawForeground(UIContext &ui) override;