Skip to content

Commit 68d832f

Browse files
committed
bugfix(mouse): Prevent cursor capture when mouse is outside of app window (#1939)
1 parent aed42f0 commit 68d832f

File tree

6 files changed

+90
-0
lines changed

6 files changed

+90
-0
lines changed

Generals/Code/GameEngine/Include/GameClient/Mouse.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ class Mouse : public SubsystemInterface
170170
CursorCaptureBlockReason_NoInit,
171171
CursorCaptureBlockReason_Paused,
172172
CursorCaptureBlockReason_Unfocused,
173+
CursorCaptureBlockReadon_CursorIsOutside,
173174

174175
CursorCaptureBlockReason_Count
175176
};
@@ -313,6 +314,10 @@ class Mouse : public SubsystemInterface
313314
virtual void loseFocus(); ///< called when window has lost focus
314315
virtual void regainFocus(); ///< called when window has regained focus
315316

317+
void onCursorMovedOutside(); ///< called when cursor has left game window
318+
void onCursorMovedInside(); ///< called when cursor has entered game window
319+
Bool isCursorInside() const; ///< true if the mouse is located inside the game window
320+
316321
void onResolutionChanged(void);
317322
void onGameModeChanged(GameMode prev, GameMode next);
318323
void onGamePaused(Bool paused);

Generals/Code/GameEngine/Source/GameClient/Input/Mouse.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ const char *const Mouse::CursorCaptureBlockReasonNames[] = {
6464
"CursorCaptureBlockReason_NoInit",
6565
"CursorCaptureBlockReason_Paused",
6666
"CursorCaptureBlockReason_Unfocused",
67+
"CursorCaptureBlockReason_CursorIsOutside",
6768
};
6869

6970
///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1034,6 +1035,24 @@ void Mouse::regainFocus()
10341035
unblockCapture(CursorCaptureBlockReason_Unfocused);
10351036
}
10361037

1038+
// ------------------------------------------------------------------------------------------------
1039+
void Mouse::onCursorMovedOutside()
1040+
{
1041+
blockCapture(CursorCaptureBlockReadon_CursorIsOutside);
1042+
}
1043+
1044+
// ------------------------------------------------------------------------------------------------
1045+
void Mouse::onCursorMovedInside()
1046+
{
1047+
unblockCapture(CursorCaptureBlockReadon_CursorIsOutside);
1048+
}
1049+
1050+
// ------------------------------------------------------------------------------------------------
1051+
Bool Mouse::isCursorInside() const
1052+
{
1053+
return (m_captureBlockReasonBits & (1 << CursorCaptureBlockReadon_CursorIsOutside)) == 0;
1054+
}
1055+
10371056
// ------------------------------------------------------------------------------------------------
10381057
void Mouse::initCapture()
10391058
{

Generals/Code/Main/WinMain.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,8 +414,15 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message,
414414
TheKeyboard->resetKeys();
415415

416416
if (TheMouse)
417+
{
417418
TheMouse->loseFocus();
418419

420+
if (TheMouse->isCursorInside())
421+
{
422+
TheMouse->onCursorMovedOutside();
423+
}
424+
}
425+
419426
break;
420427
}
421428

@@ -528,15 +535,29 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message,
528535
if( TheWin32Mouse == NULL )
529536
return 0;
530537

538+
// ignore when window is not active
539+
if( !isWinMainActive )
540+
return 0;
541+
531542
Int x = (Int)LOWORD( lParam );
532543
Int y = (Int)HIWORD( lParam );
533544
RECT rect;
534545

535546
// ignore when outside of client area
536547
GetClientRect( ApplicationHWnd, &rect );
537548
if( x < rect.left || x > rect.right || y < rect.top || y > rect.bottom )
549+
{
550+
if ( TheMouse->isCursorInside() )
551+
{
552+
TheMouse->onCursorMovedOutside();
553+
}
538554
return 0;
555+
}
539556

557+
if( !TheMouse->isCursorInside() )
558+
{
559+
TheMouse->onCursorMovedInside();
560+
}
540561

541562
TheWin32Mouse->addWin32Event( message, wParam, lParam, TheMessageTime );
542563
return 0;

GeneralsMD/Code/GameEngine/Include/GameClient/Mouse.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ class Mouse : public SubsystemInterface
170170
CursorCaptureBlockReason_NoInit,
171171
CursorCaptureBlockReason_Paused,
172172
CursorCaptureBlockReason_Unfocused,
173+
CursorCaptureBlockReadon_CursorIsOutside,
173174

174175
CursorCaptureBlockReason_Count
175176
};
@@ -313,6 +314,10 @@ class Mouse : public SubsystemInterface
313314
virtual void loseFocus(); ///< called when window has lost focus
314315
virtual void regainFocus(); ///< called when window has regained focus
315316

317+
void onCursorMovedOutside(); ///< called when cursor has left game window
318+
void onCursorMovedInside(); ///< called when cursor has entered game window
319+
Bool isCursorInside() const; ///< true if the mouse is located inside the game window
320+
316321
void onResolutionChanged(void);
317322
void onGameModeChanged(GameMode prev, GameMode next);
318323
void onGamePaused(Bool paused);

GeneralsMD/Code/GameEngine/Source/GameClient/Input/Mouse.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ const char *const Mouse::CursorCaptureBlockReasonNames[] = {
6464
"CursorCaptureBlockReason_NoInit",
6565
"CursorCaptureBlockReason_Paused",
6666
"CursorCaptureBlockReason_Unfocused",
67+
"CursorCaptureBlockReason_CursorIsOutside",
6768
};
6869

6970
///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1034,6 +1035,24 @@ void Mouse::regainFocus()
10341035
unblockCapture(CursorCaptureBlockReason_Unfocused);
10351036
}
10361037

1038+
// ------------------------------------------------------------------------------------------------
1039+
void Mouse::onCursorMovedOutside()
1040+
{
1041+
blockCapture(CursorCaptureBlockReadon_CursorIsOutside);
1042+
}
1043+
1044+
// ------------------------------------------------------------------------------------------------
1045+
void Mouse::onCursorMovedInside()
1046+
{
1047+
unblockCapture(CursorCaptureBlockReadon_CursorIsOutside);
1048+
}
1049+
1050+
// ------------------------------------------------------------------------------------------------
1051+
Bool Mouse::isCursorInside() const
1052+
{
1053+
return (m_captureBlockReasonBits & (1 << CursorCaptureBlockReadon_CursorIsOutside)) == 0;
1054+
}
1055+
10371056
// ------------------------------------------------------------------------------------------------
10381057
void Mouse::initCapture()
10391058
{

GeneralsMD/Code/Main/WinMain.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,8 +436,15 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message,
436436
TheKeyboard->resetKeys();
437437

438438
if (TheMouse)
439+
{
439440
TheMouse->loseFocus();
440441

442+
if (TheMouse->isCursorInside())
443+
{
444+
TheMouse->onCursorMovedOutside();
445+
}
446+
}
447+
441448
break;
442449
}
443450

@@ -550,15 +557,29 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message,
550557
if( TheWin32Mouse == NULL )
551558
return 0;
552559

560+
// ignore when window is not active
561+
if( !isWinMainActive )
562+
return 0;
563+
553564
Int x = (Int)LOWORD( lParam );
554565
Int y = (Int)HIWORD( lParam );
555566
RECT rect;
556567

557568
// ignore when outside of client area
558569
GetClientRect( ApplicationHWnd, &rect );
559570
if( x < rect.left || x > rect.right || y < rect.top || y > rect.bottom )
571+
{
572+
if ( TheMouse->isCursorInside() )
573+
{
574+
TheMouse->onCursorMovedOutside();
575+
}
560576
return 0;
577+
}
561578

579+
if( !TheMouse->isCursorInside() )
580+
{
581+
TheMouse->onCursorMovedInside();
582+
}
562583

563584
TheWin32Mouse->addWin32Event( message, wParam, lParam, TheMessageTime );
564585
return 0;

0 commit comments

Comments
 (0)