From 970aba9766795584f9c7acc3c2c716674835590b Mon Sep 17 00:00:00 2001 From: JeffR Date: Mon, 11 Aug 2025 00:06:42 -0500 Subject: [PATCH 1/2] Fixes design oversight where the general game menu keybind was being overridden due to order of operations issues with an offscreen canvas demoing the options menu Fixed via several solutions to prevent issue from cropping up again. Firstly, Adjusted behavior script-side so game menu keybind is pushed with the PlayGUI since almost every single game will use the game menu Secondly, added logic so that the guiInputCtrl, when going to push an ActionMap(if it has one) will check if it's root canvas is active. Thirdly, to allow guiInputCtrls to respond to a canvas becoming active, such as a GUi-on-Material surface displaying a menu and it's activated, an offscreen canvas becoming active now trips a signal that guiInputCtrl listens for. --- Engine/source/T3D/fps/guiCrossHairHud.cpp | 4 +++ Engine/source/gui/core/guiCanvas.cpp | 16 +++++++++ Engine/source/gui/core/guiCanvas.h | 12 +++++-- Engine/source/gui/utility/guiInputCtrl.cpp | 34 +++++++++++++++++-- Engine/source/gui/utility/guiInputCtrl.h | 4 +++ .../game/data/Prototyping/Prototyping.tscript | 1 + 6 files changed, 67 insertions(+), 4 deletions(-) diff --git a/Engine/source/T3D/fps/guiCrossHairHud.cpp b/Engine/source/T3D/fps/guiCrossHairHud.cpp index 052350be1..8ad593aeb 100644 --- a/Engine/source/T3D/fps/guiCrossHairHud.cpp +++ b/Engine/source/T3D/fps/guiCrossHairHud.cpp @@ -161,6 +161,9 @@ void GuiCrossHairHud::onRender(Point2I offset, const RectI &updateRect) { if (mFrameTime->getElapsedMs() > 32) { + if (GuiOffscreenCanvas::sActiveOffscreenCanvas) + GuiOffscreenCanvas::sActiveOffscreenCanvas->setActive(false); + GuiOffscreenCanvas::sActiveOffscreenCanvas = NULL; mFrameTime->reset(); @@ -197,6 +200,7 @@ void GuiCrossHairHud::onRender(Point2I offset, const RectI &updateRect) canvas->setCursorPos(newCursorPos); canvas->markDirty(); GuiOffscreenCanvas::sActiveOffscreenCanvas = canvas; + GuiOffscreenCanvas::sActiveOffscreenCanvas->setActive(true); break; } } diff --git a/Engine/source/gui/core/guiCanvas.cpp b/Engine/source/gui/core/guiCanvas.cpp index c9f603d05..cb592cc63 100644 --- a/Engine/source/gui/core/guiCanvas.cpp +++ b/Engine/source/gui/core/guiCanvas.cpp @@ -393,6 +393,7 @@ void GuiCanvas::setWindowTitle(const char *newTitle) } CanvasSizeChangeSignal GuiCanvas::smCanvasSizeChangeSignal; +CanvasSetActiveSignal GuiCanvas::smCanvasSetActiveSignal; void GuiCanvas::handleResize( WindowId did, S32 width, S32 height ) { @@ -2202,6 +2203,13 @@ StringTableEntry GuiCanvas::getLastInputDeviceType() return StringTable->EmptyString(); } +void GuiCanvas::setActive(bool value) +{ + Parent::setActive(value); + + GuiCanvas::getCanvasSetActiveSignal().trigger(this, value); +} + DefineEngineMethod( GuiCanvas, getContent, S32, (),, "@brief Get the GuiControl which is being used as the content.\n\n" @@ -3027,3 +3035,11 @@ DefineEngineMethod(GuiCanvas, getLastInputDevice, const char*, (), , "Returns th { return object->getLastInputDeviceType(); } + +DefineEngineMethod(GuiCanvas, getActiveOffscreenCanvas, S32, (), , "Returns the SimID of the active offscreen canvas, if one exists. If not, returns 0") +{ + if (GuiOffscreenCanvas::sActiveOffscreenCanvas && GuiOffscreenCanvas::sActiveOffscreenCanvas->isActive()) + return GuiOffscreenCanvas::sActiveOffscreenCanvas->getId(); + + return 0; +} diff --git a/Engine/source/gui/core/guiCanvas.h b/Engine/source/gui/core/guiCanvas.h index 64493c7dd..9e66076af 100644 --- a/Engine/source/gui/core/guiCanvas.h +++ b/Engine/source/gui/core/guiCanvas.h @@ -86,6 +86,8 @@ class guiCanvas; class Point2I; typedef Signal CanvasSizeChangeSignal; +typedef Signal CanvasSetActiveSignal; + class GuiCanvas : public GuiControl, public IProcessInput { @@ -210,10 +212,13 @@ protected: void checkLockMouseMove( const GuiEvent& event ); //Signal used to let others know this canvas has changed size. static CanvasSizeChangeSignal smCanvasSizeChangeSignal; + static CanvasSetActiveSignal smCanvasSetActiveSignal; GuiControl *mMenuBarCtrl; GuiControl* mMenuBackground; bool mConstrainMouse; + + typedef Signal< void(SetModification modification, SimSet* set, SimObject* object) > SetModificationSignal; public: DECLARE_CONOBJECT(GuiCanvas); DECLARE_CATEGORY( "Gui Core" ); @@ -230,6 +235,7 @@ public: static void initPersistFields(); static CanvasSizeChangeSignal& getCanvasSizeChangeSignal() { return smCanvasSizeChangeSignal; } + static CanvasSetActiveSignal& getCanvasSetActiveSignal() { return smCanvasSetActiveSignal; } /// @name Rendering methods /// @@ -477,16 +483,18 @@ public: private: static const U32 MAX_GAMEPADS = 4; ///< The maximum number of supported gamepads - protected: +protected: bool mConsumeLastInputEvent; S32 mLastInputDeviceType; - public: +public: void clearMouseRightButtonDown(void) { mMouseRightButtonDown = false; } void clearMouseButtonDown(void) { mMouseButtonDown = false; } void setConsumeLastInputEvent(bool flag) { mConsumeLastInputEvent = flag; } bool getLastCursorPoint(Point2I& pt) const { pt = mLastCursorPt; return mLastCursorEnabled; } StringTableEntry getLastInputDeviceType(); + + void setActive(bool value) override; }; typedef GuiCanvas::KeyTranslationMode KeyboardTranslationMode; DefineEnumType(KeyboardTranslationMode); diff --git a/Engine/source/gui/utility/guiInputCtrl.cpp b/Engine/source/gui/utility/guiInputCtrl.cpp index 830e6746b..8a5d5c089 100644 --- a/Engine/source/gui/utility/guiInputCtrl.cpp +++ b/Engine/source/gui/utility/guiInputCtrl.cpp @@ -23,6 +23,7 @@ #include "gui/utility/guiInputCtrl.h" #include "sim/actionMap.h" #include "console/engineAPI.h" +#include "gui/core/guiCanvas.h" IMPLEMENT_CONOBJECT(GuiInputCtrl); @@ -88,6 +89,13 @@ void GuiInputCtrl::initPersistFields() } //------------------------------------------------------------------------------ +bool GuiInputCtrl::onAdd() +{ + if (!Parent::onAdd()) + return false; + + GuiCanvas::getCanvasSetActiveSignal().notify(this, &GuiInputCtrl::handleCanvasSetActive); +} bool GuiInputCtrl::onWake() { @@ -108,8 +116,11 @@ bool GuiInputCtrl::onWake() if(mActionmap != nullptr) { - SimSet* actionMapSet = Sim::getActiveActionMapSet(); - actionMapSet->pushObject(mActionmap); + if (getRoot()->isActive()) + { + SimSet* actionMapSet = Sim::getActiveActionMapSet(); + actionMapSet->pushObject(mActionmap); + } } setFirstResponder(); @@ -152,6 +163,25 @@ void GuiInputCtrl::setActive(bool value) } +void GuiInputCtrl::handleCanvasSetActive(GuiCanvas* canvas, bool isActive) +{ + if (mActionmap == nullptr) + return; + + if (getRoot() == canvas) + { + if (isActive) + { + SimSet* actionMapSet = Sim::getActiveActionMapSet(); + actionMapSet->pushObject(mActionmap); + } + else + { + SimSet* actionMapSet = Sim::getActiveActionMapSet(); + actionMapSet->removeObject(mActionmap); + } + } +} //------------------------------------------------------------------------------ static bool isModifierKey( U16 keyCode ) diff --git a/Engine/source/gui/utility/guiInputCtrl.h b/Engine/source/gui/utility/guiInputCtrl.h index 7ddedd780..b26248058 100644 --- a/Engine/source/gui/utility/guiInputCtrl.h +++ b/Engine/source/gui/utility/guiInputCtrl.h @@ -47,6 +47,8 @@ public: GuiInputCtrl(); + bool onAdd() override; + // GuiControl. bool onWake() override; void onSleep() override; @@ -57,6 +59,8 @@ public: static void initPersistFields(); + void handleCanvasSetActive(GuiCanvas* canvas, bool isActive); + DECLARE_CONOBJECT(GuiInputCtrl); DECLARE_CATEGORY( "Gui Other Script" ); DECLARE_DESCRIPTION( "A control that locks the mouse and reports all input events to script." ); diff --git a/Templates/BaseGame/game/data/Prototyping/Prototyping.tscript b/Templates/BaseGame/game/data/Prototyping/Prototyping.tscript index bd3841f9e..e2c8b407a 100644 --- a/Templates/BaseGame/game/data/Prototyping/Prototyping.tscript +++ b/Templates/BaseGame/game/data/Prototyping/Prototyping.tscript @@ -50,6 +50,7 @@ function Prototyping::onCreateClientConnection(%this) dynamicTarget = false; canInteract = true; maxInteractDistance = "3"; + active = false; }; } From c2a46e4b45ea8f04fbe2db51121ba8c09d216aaa Mon Sep 17 00:00:00 2001 From: JeffR Date: Mon, 11 Aug 2025 00:09:54 -0500 Subject: [PATCH 2/2] Make sure to actually remove the signal registration too --- Engine/source/gui/utility/guiInputCtrl.cpp | 9 +++++++++ Engine/source/gui/utility/guiInputCtrl.h | 1 + 2 files changed, 10 insertions(+) diff --git a/Engine/source/gui/utility/guiInputCtrl.cpp b/Engine/source/gui/utility/guiInputCtrl.cpp index 8a5d5c089..280a73f93 100644 --- a/Engine/source/gui/utility/guiInputCtrl.cpp +++ b/Engine/source/gui/utility/guiInputCtrl.cpp @@ -95,6 +95,15 @@ bool GuiInputCtrl::onAdd() return false; GuiCanvas::getCanvasSetActiveSignal().notify(this, &GuiInputCtrl::handleCanvasSetActive); + + return true; +} + +void GuiInputCtrl::onRemove() +{ + GuiCanvas::getCanvasSetActiveSignal().remove(this, &GuiInputCtrl::handleCanvasSetActive); + + Parent::onRemove(); } bool GuiInputCtrl::onWake() diff --git a/Engine/source/gui/utility/guiInputCtrl.h b/Engine/source/gui/utility/guiInputCtrl.h index b26248058..08fd9bfc5 100644 --- a/Engine/source/gui/utility/guiInputCtrl.h +++ b/Engine/source/gui/utility/guiInputCtrl.h @@ -48,6 +48,7 @@ public: GuiInputCtrl(); bool onAdd() override; + void onRemove() override; // GuiControl. bool onWake() override;