From cf51812a6f845f1305d77f040ce2665bcab2f9a6 Mon Sep 17 00:00:00 2001 From: bmdhacks Date: Thu, 4 Sep 2025 18:09:09 -0700 Subject: [PATCH] Controller cursor highlight fixes This resolves two issues: 1) Ensure that cursor tooltips stay displayed when buying spells or selling or consuming items and any other place where actions can highlight new items. 2) Ignore small mouse movements if we've just warped the mouse pointer a long distance. This resolves an issue where slight cursor wiggle will trigger after changing the dpad highlight. --- apps/openmw/mwbase/windowmanager.hpp | 8 +++--- apps/openmw/mwgui/itemview.cpp | 33 ++++++++++++++--------- apps/openmw/mwgui/spellbuyingwindow.cpp | 19 +++++++++---- apps/openmw/mwgui/spellcreationdialog.cpp | 10 +++---- apps/openmw/mwgui/spellview.cpp | 23 +++++++++++++--- apps/openmw/mwgui/spellwindow.cpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 15 ++++++----- apps/openmw/mwgui/windowmanagerimp.hpp | 16 +++++------ apps/openmw/mwinput/controllermanager.cpp | 6 ++--- apps/openmw/mwinput/mousemanager.cpp | 19 +++++++++++-- apps/openmw/mwinput/mousemanager.hpp | 2 ++ 12 files changed, 104 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 0197f490a0..440eb073d7 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -392,10 +392,10 @@ namespace MWBase /// Cycle to the next window to receive controller events virtual void cycleActiveControllerWindow(bool next) = 0; virtual void setActiveControllerWindow(MWGui::GuiMode mode, int activeIndex) = 0; - virtual bool getControllerTooltip() const = 0; - virtual void setControllerTooltip(bool enabled) = 0; - virtual bool getControllerTooltipUserPreference() const = 0; - virtual void setControllerTooltipUserPreference(bool enabled) = 0; + virtual bool getControllerTooltipVisible() const = 0; + virtual void setControllerTooltipVisible(bool visible) = 0; + virtual bool getControllerTooltipEnabled() const = 0; + virtual void setControllerTooltipEnabled(bool enabled) = 0; virtual void updateControllerButtonsOverlay() = 0; // Used in Lua bindings diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index 26cf54de00..3016d254ab 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -190,7 +190,7 @@ namespace MWGui { mControllerActiveWindow = active; - MWBase::Environment::get().getWindowManager()->setControllerTooltip( + MWBase::Environment::get().getWindowManager()->setControllerTooltipVisible( active && Settings::gui().mControllerTooltips); if (active) @@ -219,34 +219,38 @@ namespace MWGui break; case SDL_CONTROLLER_BUTTON_RIGHTSTICK: // Toggle info tooltip - winMgr->setControllerTooltipUserPreference(!winMgr->getControllerTooltip()); + winMgr->setControllerTooltipEnabled(!winMgr->getControllerTooltipEnabled()); updateControllerFocus(-1, mControllerFocus); break; case SDL_CONTROLLER_BUTTON_DPAD_UP: - if (winMgr->getControllerTooltipUserPreference() && !winMgr->getControllerTooltip()) - winMgr->setControllerTooltip(true); + // Restore tooltip visibility if user has them enabled but they were hidden by mouse + if (winMgr->getControllerTooltipEnabled() && !winMgr->getControllerTooltipVisible()) + winMgr->setControllerTooltipVisible(true); if (mControllerFocus % mRows == 0) mControllerFocus = std::min(mControllerFocus + mRows - 1, mItemCount - 1); else mControllerFocus--; break; case SDL_CONTROLLER_BUTTON_DPAD_DOWN: - if (winMgr->getControllerTooltipUserPreference() && !winMgr->getControllerTooltip()) - winMgr->setControllerTooltip(true); + // Restore tooltip visibility if user has them enabled but they were hidden by mouse + if (winMgr->getControllerTooltipEnabled() && !winMgr->getControllerTooltipVisible()) + winMgr->setControllerTooltipVisible(true); if (mControllerFocus % mRows == mRows - 1 || mControllerFocus == mItemCount - 1) mControllerFocus -= mControllerFocus % mRows; else mControllerFocus++; break; case SDL_CONTROLLER_BUTTON_DPAD_LEFT: - if (winMgr->getControllerTooltipUserPreference() && !winMgr->getControllerTooltip()) - winMgr->setControllerTooltip(true); + // Restore tooltip visibility if user has them enabled but they were hidden by mouse + if (winMgr->getControllerTooltipEnabled() && !winMgr->getControllerTooltipVisible()) + winMgr->setControllerTooltipVisible(true); if (mControllerFocus >= mRows) mControllerFocus -= mRows; break; case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: - if (winMgr->getControllerTooltipUserPreference() && !winMgr->getControllerTooltip()) - winMgr->setControllerTooltip(true); + // Restore tooltip visibility if user has them enabled but they were hidden by mouse + if (winMgr->getControllerTooltipEnabled() && !winMgr->getControllerTooltipVisible()) + winMgr->setControllerTooltipVisible(true); if (mControllerFocus + mRows < mItemCount) mControllerFocus += mRows; else if (mControllerFocus / mRows != (mItemCount - 1) / mRows) @@ -265,7 +269,7 @@ namespace MWGui void ItemView::updateControllerFocus(int prevFocus, int newFocus) { MWBase::Environment::get().getWindowManager()->setCursorVisible( - !MWBase::Environment::get().getWindowManager()->getControllerTooltip()); + !MWBase::Environment::get().getWindowManager()->getControllerTooltipVisible()); if (!mItemCount) return; @@ -293,7 +297,12 @@ namespace MWGui else mScrollView->setViewOffset(MyGUI::IntPoint(-42 * (column - 3), 0)); - if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) + // Restore tooltip visibility if user has them enabled but they were hidden by mouse movement + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + if (winMgr->getControllerTooltipEnabled() && !winMgr->getControllerTooltipVisible()) + winMgr->setControllerTooltipVisible(true); + + if (winMgr->getControllerTooltipVisible()) MWBase::Environment::get().getInputManager()->warpMouseToWidget(focused); } } diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 7ace160350..35a67b323a 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -151,8 +151,8 @@ namespace MWGui mSpellButtons[0].first->setStateSelected(true); MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); - winMgr->setControllerTooltip(Settings::gui().mControllerTooltips); - if (winMgr->getControllerTooltip()) + winMgr->setControllerTooltipVisible(Settings::gui().mControllerTooltips); + if (winMgr->getControllerTooltipVisible()) MWBase::Environment::get().getInputManager()->warpMouseToWidget(mSpellButtons[0].first); } } @@ -230,6 +230,8 @@ namespace MWGui bool SpellBuyingWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + if (arg.button == SDL_CONTROLLER_BUTTON_A) { if (mControllerFocus < mSpellButtons.size()) @@ -242,11 +244,14 @@ namespace MWGui else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) { // Toggle info tooltip - MWBase::Environment::get().getWindowManager()->setControllerTooltip( - !MWBase::Environment::get().getWindowManager()->getControllerTooltip()); + winMgr->setControllerTooltipEnabled(!winMgr->getControllerTooltipEnabled()); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { + // Restore tooltip visibility if user has them enabled but they were hidden by mouse + if (winMgr->getControllerTooltipEnabled() && !winMgr->getControllerTooltipVisible()) + winMgr->setControllerTooltipVisible(true); + if (mSpellButtons.size() <= 1) return true; @@ -256,6 +261,10 @@ namespace MWGui } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { + // Restore tooltip visibility if user has them enabled but they were hidden by mouse + if (winMgr->getControllerTooltipEnabled() && !winMgr->getControllerTooltipVisible()) + winMgr->setControllerTooltipVisible(true); + if (mSpellButtons.size() <= 1) return true; @@ -279,7 +288,7 @@ namespace MWGui } // Warp the mouse to the selected spell to show the tooltip - if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) + if (MWBase::Environment::get().getWindowManager()->getControllerTooltipVisible()) MWBase::Environment::get().getInputManager()->warpMouseToWidget(mSpellButtons[mControllerFocus].first); } diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 6d27b4e4d2..78246d4521 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -850,7 +850,7 @@ namespace MWGui if (mAvailableButtons.size() > 0) { mAvailableButtons[0]->setStateSelected(true); - if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) + if (MWBase::Environment::get().getWindowManager()->getControllerTooltipVisible()) MWBase::Environment::get().getInputManager()->warpMouseToWidget(mAvailableButtons[0]); } } @@ -1058,7 +1058,7 @@ namespace MWGui else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) { // Toggle info tooltip - winMgr->setControllerTooltip(!mRightColumn && !winMgr->getControllerTooltip()); + winMgr->setControllerTooltipVisible(!mRightColumn && !winMgr->getControllerTooltipVisible()); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { @@ -1102,7 +1102,7 @@ namespace MWGui if (mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) mAvailableButtons[mAvailableFocus]->setStateSelected(true); - winMgr->setControllerTooltip(Settings::gui().mControllerTooltips); + winMgr->setControllerTooltipVisible(Settings::gui().mControllerTooltips); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mRightColumn && mEffectButtons.size() > 0) { @@ -1112,7 +1112,7 @@ namespace MWGui if (mEffectFocus >= 0 && mEffectFocus < static_cast(mEffectButtons.size())) mEffectButtons[mEffectFocus].first->setStateSelected(true); - winMgr->setControllerTooltip(false); + winMgr->setControllerTooltipVisible(false); } else return true; @@ -1129,7 +1129,7 @@ namespace MWGui if (!mRightColumn && mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) { // Warp the mouse to the selected spell to show the tooltip - if (winMgr->getControllerTooltip()) + if (winMgr->getControllerTooltipVisible()) MWBase::Environment::get().getInputManager()->warpMouseToWidget(mAvailableButtons[mAvailableFocus]); } diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index ac923586dd..d79a90b0d6 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -350,6 +350,7 @@ namespace MWGui return; int prevFocus = mControllerFocus; + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); switch (button) { @@ -363,19 +364,30 @@ namespace MWGui break; case SDL_CONTROLLER_BUTTON_RIGHTSTICK: // Toggle info tooltip - MWBase::Environment::get().getWindowManager()->setControllerTooltip( - !MWBase::Environment::get().getWindowManager()->getControllerTooltip()); + winMgr->setControllerTooltipEnabled(!winMgr->getControllerTooltipEnabled()); break; case SDL_CONTROLLER_BUTTON_DPAD_UP: + // Restore tooltip visibility if user has them enabled but they were hidden by mouse + if (winMgr->getControllerTooltipEnabled() && !winMgr->getControllerTooltipVisible()) + winMgr->setControllerTooltipVisible(true); mControllerFocus--; break; case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + // Restore tooltip visibility if user has them enabled but they were hidden by mouse + if (winMgr->getControllerTooltipEnabled() && !winMgr->getControllerTooltipVisible()) + winMgr->setControllerTooltipVisible(true); mControllerFocus++; break; case SDL_CONTROLLER_BUTTON_DPAD_LEFT: + // Restore tooltip visibility if user has them enabled but they were hidden by mouse + if (winMgr->getControllerTooltipEnabled() && !winMgr->getControllerTooltipVisible()) + winMgr->setControllerTooltipVisible(true); mControllerFocus = std::max(0, mControllerFocus - 10); break; case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: + // Restore tooltip visibility if user has them enabled but they were hidden by mouse + if (winMgr->getControllerTooltipEnabled() && !winMgr->getControllerTooltipVisible()) + winMgr->setControllerTooltipVisible(true); mControllerFocus = std::min(mControllerFocus + 10, static_cast(mButtons.size()) - 1); break; case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: @@ -451,7 +463,12 @@ namespace MWGui mScrollView->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (line - 5))); } - if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) + // Restore tooltip visibility if user has them enabled but they were hidden by mouse movement + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + if (winMgr->getControllerTooltipEnabled() && !winMgr->getControllerTooltipVisible()) + winMgr->setControllerTooltipVisible(true); + + if (winMgr->getControllerTooltipVisible()) MWBase::Environment::get().getInputManager()->warpMouseToWidget(focused); } } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 3b088ae518..01b4a94e93 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -328,7 +328,7 @@ namespace MWGui MyGUI::Window* window = mMainWidget->castType(); window->setCoord(x, active ? y : viewSize.height + 1, width, height); - MWBase::Environment::get().getWindowManager()->setControllerTooltip( + MWBase::Environment::get().getWindowManager()->setControllerTooltipVisible( active && Settings::gui().mControllerTooltips); } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 7fd048a778..3abd238344 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -95,7 +95,7 @@ namespace MWGui if (guiMode) { - if (!winMgr->getCursorVisible() && !winMgr->getControllerTooltip()) + if (!winMgr->getCursorVisible() && !winMgr->getControllerTooltipVisible()) return; const MyGUI::IntPoint& mousePos = MyGUI::InputManager::getInstance().getMousePosition(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9e0acff7b4..682340533f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -520,7 +520,7 @@ namespace MWGui mInventoryTabsOverlay = inventoryTabsOverlay.get(); mWindows.push_back(std::move(inventoryTabsOverlay)); - mControllerTooltipUserPreference = Settings::gui().mControllerTooltips; + mControllerTooltipEnabled = Settings::gui().mControllerTooltips; mActiveControllerWindows[GM_Inventory] = 1; // Start on Inventory page mInputBlocker = MyGUI::Gui::getInstance().createWidget( @@ -1498,7 +1498,7 @@ namespace MWGui if (Settings::gui().mControllerMenus) { if (mGuiModes.empty()) - setControllerTooltip(false); + setControllerTooltipVisible(false); else reapplyActiveControllerWindow(); } @@ -2642,21 +2642,22 @@ namespace MWGui return height; } - void WindowManager::setControllerTooltip(bool enabled) + void WindowManager::setControllerTooltipVisible(bool visible) { if (!Settings::gui().mControllerMenus) return; - mControllerTooltip = enabled; + mControllerTooltipVisible = visible; } - void WindowManager::setControllerTooltipUserPreference(bool enabled) + void WindowManager::setControllerTooltipEnabled(bool enabled) { if (!Settings::gui().mControllerMenus) return; - mControllerTooltipUserPreference = enabled; - mControllerTooltip = enabled; + mControllerTooltipEnabled = enabled; + // When user toggles the setting, also update visibility + mControllerTooltipVisible = enabled; } void WindowManager::updateControllerButtonsOverlay() diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 8eaf171d0d..a79581ecac 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -395,10 +395,10 @@ namespace MWGui int getControllerMenuHeight() override; void cycleActiveControllerWindow(bool next) override; void setActiveControllerWindow(GuiMode mode, int activeIndex) override; - bool getControllerTooltip() const override { return mControllerTooltip; } - void setControllerTooltip(bool enabled) override; - bool getControllerTooltipUserPreference() const override { return mControllerTooltipUserPreference; } - void setControllerTooltipUserPreference(bool enabled) override; + bool getControllerTooltipVisible() const override { return mControllerTooltipVisible; } + void setControllerTooltipVisible(bool visible) override; + bool getControllerTooltipEnabled() const override { return mControllerTooltipEnabled; } + void setControllerTooltipEnabled(bool enabled) override; void updateControllerButtonsOverlay() override; // Used in Lua bindings @@ -513,10 +513,10 @@ namespace MWGui std::vector mGuiModes; // The active window for controller mode for each GUI mode. std::map mActiveControllerWindows; - // Current tooltip state (can be disabled by mouse movement) - bool mControllerTooltip = false; - // Toggleable preference. Restores tooltips on controller input after pointer movement - bool mControllerTooltipUserPreference = false; + // Current tooltip visibility state (can be disabled by mouse movement) + bool mControllerTooltipVisible = false; + // User preference for tooltips (persists across mouse/controller switches) + bool mControllerTooltipEnabled = false; void reapplyActiveControllerWindow(); diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index c0a7dbbae0..b88c17edda 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -259,7 +259,7 @@ namespace MWInput { // When the inventory tooltip is visible, we don't actually want the A button to // act like a mouse button; it should act normally. - if (treatAsMouse && arg.button == SDL_CONTROLLER_BUTTON_A && winMgr->getControllerTooltip()) + if (treatAsMouse && arg.button == SDL_CONTROLLER_BUTTON_A && winMgr->getControllerTooltipVisible()) treatAsMouse = false; mGamepadGuiCursorEnabled = topWin->isGamepadCursorAllowed(); @@ -368,9 +368,9 @@ namespace MWInput && (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY)) { // Treat the left stick like a cursor, which is the default behavior. - if (winMgr->getControllerTooltip()) + if (winMgr->getControllerTooltipVisible()) { - winMgr->setControllerTooltip(false); + winMgr->setControllerTooltipVisible(false); winMgr->setCursorVisible(true); } else if (mGamepadGuiCursorEnabled) diff --git a/apps/openmw/mwinput/mousemanager.cpp b/apps/openmw/mwinput/mousemanager.cpp index b17b92e118..366232a2ba 100644 --- a/apps/openmw/mwinput/mousemanager.cpp +++ b/apps/openmw/mwinput/mousemanager.cpp @@ -32,6 +32,8 @@ namespace MWInput , mMouseWheel(0) , mMouseLookEnabled(false) , mGuiCursorEnabled(true) + , mLastWarpX(-1) + , mLastWarpY(-1) , mMouseMoveX(0) , mMouseMoveY(0) { @@ -72,13 +74,23 @@ namespace MWInput static_cast(mGuiCursorX), static_cast(mGuiCursorY), mMouseWheel); winMgr->setCursorActive(true); + + // Check if this movement is from our recent mouse warp + bool isFromWarp = (mLastWarpX >= 0 && mLastWarpY >= 0 + && std::abs(mGuiCursorX - mLastWarpX) < 0.5f + && std::abs(mGuiCursorY - mLastWarpY) < 0.5f); + if (Settings::gui().mControllerMenus && !winMgr->getCursorVisible() - && (std::abs(arg.xrel) > 1 || std::abs(arg.yrel) > 1)) + && (std::abs(arg.xrel) > 1 || std::abs(arg.yrel) > 1) && !isFromWarp) { // Unhide the cursor if it was hidden to show a controller tooltip. - winMgr->setControllerTooltip(false); + winMgr->setControllerTooltipVisible(false); winMgr->setCursorVisible(true); } + + // Clear warp tracking after processing + mLastWarpX = -1; + mLastWarpY = -1; } if (mMouseLookEnabled && !input->controlsDisabled()) @@ -280,6 +292,9 @@ namespace MWInput { mGuiCursorX = widgetX; mGuiCursorY = widgetY; + // Remember where we warped to so we can ignore movement from this warp + mLastWarpX = widgetX; + mLastWarpY = widgetY; warpMouse(); } } diff --git a/apps/openmw/mwinput/mousemanager.hpp b/apps/openmw/mwinput/mousemanager.hpp index 0a9c4eccd7..323703b56f 100644 --- a/apps/openmw/mwinput/mousemanager.hpp +++ b/apps/openmw/mwinput/mousemanager.hpp @@ -49,6 +49,8 @@ namespace MWInput int mMouseWheel; bool mMouseLookEnabled; bool mGuiCursorEnabled; + float mLastWarpX; + float mLastWarpY; int mMouseMoveX; int mMouseMoveY;