From e021032bcdb0a2c06ac3107cc035f76ab935cbe9 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Fri, 15 Aug 2025 23:06:47 +0200 Subject: [PATCH 1/2] tweak(scrolling): Disable edge scrolling when the mouse cursor is not captured --- .../GameEngine/Include/GameClient/Mouse.h | 13 ++++++++----- .../Source/GameClient/Input/Mouse.cpp | 13 +++++++++++++ .../GameClient/MessageStream/LookAtXlat.cpp | 19 +++++++++++-------- .../Win32Device/GameClient/Win32Mouse.cpp | 10 ++++++++-- 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/Mouse.h b/GeneralsMD/Code/GameEngine/Include/GameClient/Mouse.h index fd36f8f794..46f71a553b 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/Mouse.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/Mouse.h @@ -291,6 +291,7 @@ class Mouse : public SubsystemInterface void setCursorCaptureMode(CursorCaptureMode mode); ///< set the rules for the mouse capture void refreshCursorCapture(); ///< refresh the mouse capture + Bool isCursorCaptured(); ///< true if the mouse is captured in the game window // access methods for the mouse data const MouseIO *getMouseStatus( void ) { return &m_currMouse; } ///< get current mouse status @@ -349,12 +350,13 @@ class Mouse : public SubsystemInterface protected: void initCapture(); - Bool canCapture() const; - void unblockCapture(CursorCaptureBlockReason reason); - void blockCapture(CursorCaptureBlockReason reason); + Bool canCapture() const; ///< true if the mouse can be captured + void unblockCapture(CursorCaptureBlockReason reason); // unset a reason to block mouse capture + void blockCapture(CursorCaptureBlockReason reason); // set a reason to block mouse capture + void onCursorCaptured(Bool captured); ///< called when the mouse was successfully captured or released - virtual void capture( void ) = 0; ///< capture the mouse - virtual void releaseCapture( void ) = 0; ///< release mouse capture + virtual void capture( void ) = 0; ///< capture the mouse in the game window + virtual void releaseCapture( void ) = 0; ///< release the mouse capture /// you must implement getting a buffered mouse event from you device here virtual UnsignedByte getMouseEvent( MouseIO *result, Bool flush ) = 0; @@ -399,6 +401,7 @@ class Mouse : public SubsystemInterface relative coordinate changes */ Bool m_visible; // visibility status + Bool m_isCursorCaptured; MouseCursor m_currentCursor; ///< current mouse cursor diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Input/Mouse.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Input/Mouse.cpp index b3991e6fe5..9e7b8aeac7 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Input/Mouse.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Input/Mouse.cpp @@ -500,6 +500,7 @@ Mouse::Mouse( void ) else m_currentRedrawMode = RM_W3D;//RM_WINDOWS; m_visible = FALSE; + m_isCursorCaptured = FALSE; m_tooltipFontName = "Times New Roman"; m_tooltipFontSize = 12; m_tooltipFontIsBold = FALSE; @@ -1039,6 +1040,12 @@ void Mouse::refreshCursorCapture() } } +// ------------------------------------------------------------------------------------------------ +Bool Mouse::isCursorCaptured() +{ + return m_isCursorCaptured; +} + // ------------------------------------------------------------------------------------------------ void Mouse::loseFocus() { @@ -1118,6 +1125,12 @@ void Mouse::blockCapture(CursorCaptureBlockReason reason) CursorCaptureBlockReasonNames[reason], m_captureBlockReasonBits, (Int)canCapture())); } +// ------------------------------------------------------------------------------------------------ +void Mouse::onCursorCaptured( Bool captured ) +{ + m_isCursorCaptured = captured; +} + //------------------------------------------------------------------------------------------------- /** Draw the mouse */ //------------------------------------------------------------------------------------------------- diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp index e3e5aed2a0..4114c7373a 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp @@ -307,18 +307,21 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage } // TheSuperHackers @tweak Ayumi/xezon 26/07/2025 Enables edge scrolling in windowed mode. - if (m_isScrolling) + if (TheMouse->isCursorCaptured()) { - if ( m_scrollType == SCROLL_SCREENEDGE && (m_currentPos.x >= edgeScrollSize && m_currentPos.y >= edgeScrollSize && m_currentPos.y < height-edgeScrollSize && m_currentPos.x < width-edgeScrollSize) ) + if (m_isScrolling) { - stopScrolling(); + if ( m_scrollType == SCROLL_SCREENEDGE && (m_currentPos.x >= edgeScrollSize && m_currentPos.y >= edgeScrollSize && m_currentPos.y < height-edgeScrollSize && m_currentPos.x < width-edgeScrollSize) ) + { + stopScrolling(); + } } - } - else - { - if ( m_currentPos.x < edgeScrollSize || m_currentPos.y < edgeScrollSize || m_currentPos.y >= height-edgeScrollSize || m_currentPos.x >= width-edgeScrollSize ) + else { - setScrolling(SCROLL_SCREENEDGE); + if ( m_currentPos.x < edgeScrollSize || m_currentPos.y < edgeScrollSize || m_currentPos.y >= height-edgeScrollSize || m_currentPos.x >= width-edgeScrollSize ) + { + setScrolling(SCROLL_SCREENEDGE); + } } } diff --git a/GeneralsMD/Code/GameEngineDevice/Source/Win32Device/GameClient/Win32Mouse.cpp b/GeneralsMD/Code/GameEngineDevice/Source/Win32Device/GameClient/Win32Mouse.cpp index f7f5883ce2..97f7840770 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/Win32Device/GameClient/Win32Mouse.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/Win32Device/GameClient/Win32Mouse.cpp @@ -472,7 +472,10 @@ void Win32Mouse::capture( void ) rect.right = rightBottom.x; rect.bottom = rightBottom.y; - ::ClipCursor(&rect); + if (::ClipCursor(&rect)) + { + onCursorCaptured(true); + } } // end capture @@ -482,6 +485,9 @@ void Win32Mouse::capture( void ) void Win32Mouse::releaseCapture( void ) { - ::ClipCursor(NULL); + if (::ClipCursor(NULL)) + { + onCursorCaptured(false); + } } // end releaseCapture From bbc0c035243f4d4cbdea5b295d472a4886fff472 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 23 Aug 2025 19:29:54 +0200 Subject: [PATCH 2/2] Replicate in Generals --- .../GameEngine/Include/GameClient/Mouse.h | 13 ++++++++----- .../Source/GameClient/Input/Mouse.cpp | 13 +++++++++++++ .../GameClient/MessageStream/LookAtXlat.cpp | 19 +++++++++++-------- .../Win32Device/GameClient/Win32Mouse.cpp | 10 ++++++++-- 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/Generals/Code/GameEngine/Include/GameClient/Mouse.h b/Generals/Code/GameEngine/Include/GameClient/Mouse.h index 2541f6d504..b3e044bd1d 100644 --- a/Generals/Code/GameEngine/Include/GameClient/Mouse.h +++ b/Generals/Code/GameEngine/Include/GameClient/Mouse.h @@ -291,6 +291,7 @@ class Mouse : public SubsystemInterface void setCursorCaptureMode(CursorCaptureMode mode); ///< set the rules for the mouse capture void refreshCursorCapture(); ///< refresh the mouse capture + Bool isCursorCaptured(); ///< true if the mouse is captured in the game window // access methods for the mouse data const MouseIO *getMouseStatus( void ) { return &m_currMouse; } ///< get current mouse status @@ -348,12 +349,13 @@ class Mouse : public SubsystemInterface protected: void initCapture(); - Bool canCapture() const; - void unblockCapture(CursorCaptureBlockReason reason); - void blockCapture(CursorCaptureBlockReason reason); + Bool canCapture() const; ///< true if the mouse can be captured + void unblockCapture(CursorCaptureBlockReason reason); // unset a reason to block mouse capture + void blockCapture(CursorCaptureBlockReason reason); // set a reason to block mouse capture + void onCursorCaptured(Bool captured); ///< called when the mouse was successfully captured or released - virtual void capture( void ) = 0; ///< capture the mouse - virtual void releaseCapture( void ) = 0; ///< release mouse capture + virtual void capture( void ) = 0; ///< capture the mouse in the game window + virtual void releaseCapture( void ) = 0; ///< release the mouse capture /// you must implement getting a buffered mouse event from you device here virtual UnsignedByte getMouseEvent( MouseIO *result, Bool flush ) = 0; @@ -398,6 +400,7 @@ class Mouse : public SubsystemInterface relative coordinate changes */ Bool m_visible; // visibility status + Bool m_isCursorCaptured; MouseCursor m_currentCursor; ///< current mouse cursor diff --git a/Generals/Code/GameEngine/Source/GameClient/Input/Mouse.cpp b/Generals/Code/GameEngine/Source/GameClient/Input/Mouse.cpp index 21e35449b0..cf3e226d2d 100644 --- a/Generals/Code/GameEngine/Source/GameClient/Input/Mouse.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/Input/Mouse.cpp @@ -500,6 +500,7 @@ Mouse::Mouse( void ) else m_currentRedrawMode = RM_W3D;//RM_WINDOWS; m_visible = FALSE; + m_isCursorCaptured = FALSE; m_tooltipFontName = "Times New Roman"; m_tooltipFontSize = 12; m_tooltipFontIsBold = FALSE; @@ -1039,6 +1040,12 @@ void Mouse::refreshCursorCapture() } } +// ------------------------------------------------------------------------------------------------ +Bool Mouse::isCursorCaptured() +{ + return m_isCursorCaptured; +} + // ------------------------------------------------------------------------------------------------ void Mouse::loseFocus() { @@ -1118,6 +1125,12 @@ void Mouse::blockCapture(CursorCaptureBlockReason reason) CursorCaptureBlockReasonNames[reason], m_captureBlockReasonBits, (Int)canCapture())); } +// ------------------------------------------------------------------------------------------------ +void Mouse::onCursorCaptured( Bool captured ) +{ + m_isCursorCaptured = captured; +} + //------------------------------------------------------------------------------------------------- /** Draw the mouse */ //------------------------------------------------------------------------------------------------- diff --git a/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp b/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp index e0f4971e06..92984eec2c 100644 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp @@ -308,18 +308,21 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage } // TheSuperHackers @tweak Ayumi/xezon 26/07/2025 Enables edge scrolling in windowed mode. - if (m_isScrolling) + if (TheMouse->isCursorCaptured()) { - if ( m_scrollType == SCROLL_SCREENEDGE && (m_currentPos.x >= edgeScrollSize && m_currentPos.y >= edgeScrollSize && m_currentPos.y < height-edgeScrollSize && m_currentPos.x < width-edgeScrollSize) ) + if (m_isScrolling) { - stopScrolling(); + if ( m_scrollType == SCROLL_SCREENEDGE && (m_currentPos.x >= edgeScrollSize && m_currentPos.y >= edgeScrollSize && m_currentPos.y < height-edgeScrollSize && m_currentPos.x < width-edgeScrollSize) ) + { + stopScrolling(); + } } - } - else - { - if ( m_currentPos.x < edgeScrollSize || m_currentPos.y < edgeScrollSize || m_currentPos.y >= height-edgeScrollSize || m_currentPos.x >= width-edgeScrollSize ) + else { - setScrolling(SCROLL_SCREENEDGE); + if ( m_currentPos.x < edgeScrollSize || m_currentPos.y < edgeScrollSize || m_currentPos.y >= height-edgeScrollSize || m_currentPos.x >= width-edgeScrollSize ) + { + setScrolling(SCROLL_SCREENEDGE); + } } } diff --git a/Generals/Code/GameEngineDevice/Source/Win32Device/GameClient/Win32Mouse.cpp b/Generals/Code/GameEngineDevice/Source/Win32Device/GameClient/Win32Mouse.cpp index b4fb0fff08..c5f60c4c45 100644 --- a/Generals/Code/GameEngineDevice/Source/Win32Device/GameClient/Win32Mouse.cpp +++ b/Generals/Code/GameEngineDevice/Source/Win32Device/GameClient/Win32Mouse.cpp @@ -472,7 +472,10 @@ void Win32Mouse::capture( void ) rect.right = rightBottom.x; rect.bottom = rightBottom.y; - ::ClipCursor(&rect); + if (::ClipCursor(&rect)) + { + onCursorCaptured(true); + } } // end capture @@ -482,6 +485,9 @@ void Win32Mouse::capture( void ) void Win32Mouse::releaseCapture( void ) { - ::ClipCursor(NULL); + if (::ClipCursor(NULL)) + { + onCursorCaptured(false); + } } // end releaseCapture