diff --git a/Generals/Code/GameEngine/Include/GameClient/HeaderTemplate.h b/Generals/Code/GameEngine/Include/GameClient/HeaderTemplate.h index 15f8816c37..edeec5a3c4 100644 --- a/Generals/Code/GameEngine/Include/GameClient/HeaderTemplate.h +++ b/Generals/Code/GameEngine/Include/GameClient/HeaderTemplate.h @@ -94,7 +94,7 @@ class HeaderTemplateManager HeaderTemplate *getFirstHeader( void ); HeaderTemplate *getNextHeader( HeaderTemplate *ht ); - void headerNotifyResolutionChange(void); + void onResolutionChanged(void); private: void populateGameFonts( void ); diff --git a/Generals/Code/GameEngine/Include/GameClient/Mouse.h b/Generals/Code/GameEngine/Include/GameClient/Mouse.h index 0b4b979c90..bdb94d9578 100644 --- a/Generals/Code/GameEngine/Include/GameClient/Mouse.h +++ b/Generals/Code/GameEngine/Include/GameClient/Mouse.h @@ -170,6 +170,7 @@ class Mouse : public SubsystemInterface CursorCaptureBlockReason_NoInit, CursorCaptureBlockReason_Paused, CursorCaptureBlockReason_Unfocused, + CursorCaptureBlockReadon_CursorIsOutside, CursorCaptureBlockReason_Count }; @@ -310,10 +311,14 @@ class Mouse : public SubsystemInterface Int getCursorIndex( const AsciiString& name ); void resetTooltipDelay( void ); - virtual void loseFocus(); - virtual void regainFocus(); + virtual void loseFocus(); ///< called when window has lost focus + virtual void regainFocus(); ///< called when window has regained focus - void mouseNotifyResolutionChange(void); + void onCursorMovedOutside(); ///< called when cursor has left game window + void onCursorMovedInside(); ///< called when cursor has entered game window + Bool isCursorInside() const; ///< true if the mouse is located inside the game window + + void onResolutionChanged(void); void onGameModeChanged(GameMode prev, GameMode next); void onGamePaused(Bool paused); diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp index 699352fe08..926627b084 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp @@ -708,8 +708,8 @@ void DeclineResolution() TheWritableGlobalData->m_xResolution = newDispSettings.xRes; TheWritableGlobalData->m_yResolution = newDispSettings.yRes; - TheHeaderTemplateManager->headerNotifyResolutionChange(); - TheMouse->mouseNotifyResolutionChange(); + TheHeaderTemplateManager->onResolutionChanged(); + TheMouse->onResolutionChanged(); AsciiString prefString; prefString.format("%d %d", newDispSettings.xRes, newDispSettings.yRes); diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp index 32bb9002f3..1b1d9c9172 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp @@ -1540,8 +1540,8 @@ static void saveOptions( void ) TheWritableGlobalData->m_xResolution = xres; TheWritableGlobalData->m_yResolution = yres; - TheHeaderTemplateManager->headerNotifyResolutionChange(); - TheMouse->mouseNotifyResolutionChange(); + TheHeaderTemplateManager->onResolutionChanged(); + TheMouse->onResolutionChanged(); //Save new settings for a dialog box confirmation after options are accepted newDispSettings.xRes = xres; diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/HeaderTemplate.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/HeaderTemplate.cpp index 2f07686158..c7288236ae 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/HeaderTemplate.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/HeaderTemplate.cpp @@ -206,7 +206,7 @@ HeaderTemplate *HeaderTemplateManager::getNextHeader( HeaderTemplate *ht ) } -void HeaderTemplateManager::headerNotifyResolutionChange( void ) +void HeaderTemplateManager::onResolutionChanged( void ) { populateGameFonts(); } diff --git a/Generals/Code/GameEngine/Source/GameClient/Input/Mouse.cpp b/Generals/Code/GameEngine/Source/GameClient/Input/Mouse.cpp index 7331faec6b..903a52b8a2 100644 --- a/Generals/Code/GameEngine/Source/GameClient/Input/Mouse.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/Input/Mouse.cpp @@ -64,6 +64,7 @@ const char *const Mouse::CursorCaptureBlockReasonNames[] = { "CursorCaptureBlockReason_NoInit", "CursorCaptureBlockReason_Paused", "CursorCaptureBlockReason_Unfocused", + "CursorCaptureBlockReason_CursorIsOutside", }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -575,7 +576,7 @@ void Mouse::init( void ) m_numButtons = 2; // by default just have 2 buttons m_numAxes = 2; // by default a normal mouse moves in a 2d plane m_forceFeedback = FALSE; - mouseNotifyResolutionChange(); + onResolutionChanged(); m_tooltipString.clear(); // redundant m_displayTooltip = FALSE; @@ -607,7 +608,7 @@ void Mouse::init( void ) //------------------------------------------------------------------------------------------------- /** Tell mouse system display resolution changed. */ //------------------------------------------------------------------------------------------------- -void Mouse::mouseNotifyResolutionChange( void ) +void Mouse::onResolutionChanged( void ) { if(m_tooltipDisplayString) TheDisplayStringManager->freeDisplayString(m_tooltipDisplayString); @@ -1034,6 +1035,24 @@ void Mouse::regainFocus() unblockCapture(CursorCaptureBlockReason_Unfocused); } +// ------------------------------------------------------------------------------------------------ +void Mouse::onCursorMovedOutside() +{ + blockCapture(CursorCaptureBlockReadon_CursorIsOutside); +} + +// ------------------------------------------------------------------------------------------------ +void Mouse::onCursorMovedInside() +{ + unblockCapture(CursorCaptureBlockReadon_CursorIsOutside); +} + +// ------------------------------------------------------------------------------------------------ +Bool Mouse::isCursorInside() const +{ + return (m_captureBlockReasonBits & (1 << CursorCaptureBlockReadon_CursorIsOutside)) == 0; +} + // ------------------------------------------------------------------------------------------------ void Mouse::initCapture() { diff --git a/Generals/Code/Main/WinMain.cpp b/Generals/Code/Main/WinMain.cpp index 303d6da1ce..9af234e3a5 100644 --- a/Generals/Code/Main/WinMain.cpp +++ b/Generals/Code/Main/WinMain.cpp @@ -69,7 +69,7 @@ // GLOBALS //////////////////////////////////////////////////////////////////// HINSTANCE ApplicationHInstance = NULL; ///< our application instance HWND ApplicationHWnd = NULL; ///< our application window handle -Win32Mouse *TheWin32Mouse= NULL; ///< for the WndProc() only +Win32Mouse *TheWin32Mouse = NULL; ///< for the WndProc() only DWORD TheMessageTime = 0; ///< For getting the time that a message was posted from Windows. const Char *g_strFile = "data\\Generals.str"; @@ -315,77 +315,59 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, { //------------------------------------------------------------------------- case WM_NCHITTEST: - // Prevent the user from selecting the menu in fullscreen mode - if( !TheGlobalData->m_windowed ) - return HTCLIENT; - break; + // Prevent the user from selecting the menu in fullscreen mode + if( !TheGlobalData->m_windowed ) + return HTCLIENT; + break; //------------------------------------------------------------------------- case WM_POWERBROADCAST: - switch( wParam ) - { - #ifndef PBT_APMQUERYSUSPEND - #define PBT_APMQUERYSUSPEND 0x0000 - #endif - case PBT_APMQUERYSUSPEND: - // At this point, the app should save any data for open - // network connections, files, etc., and prepare to go into - // a suspended mode. - return TRUE; - - #ifndef PBT_APMRESUMESUSPEND - #define PBT_APMRESUMESUSPEND 0x0007 - #endif - case PBT_APMRESUMESUSPEND: - // At this point, the app should recover any data, network - // connections, files, etc., and resume running from when - // the app was suspended. - return TRUE; - } - break; + switch( wParam ) + { + #ifndef PBT_APMQUERYSUSPEND + #define PBT_APMQUERYSUSPEND 0x0000 + #endif + case PBT_APMQUERYSUSPEND: + // At this point, the app should save any data for open + // network connections, files, etc., and prepare to go into + // a suspended mode. + return TRUE; + + #ifndef PBT_APMRESUMESUSPEND + #define PBT_APMRESUMESUSPEND 0x0007 + #endif + case PBT_APMRESUMESUSPEND: + // At this point, the app should recover any data, network + // connections, files, etc., and resume running from when + // the app was suspended. + return TRUE; + } + break; //------------------------------------------------------------------------- case WM_SYSCOMMAND: - // Prevent moving/sizing and power loss in fullscreen mode - switch( wParam ) - { - case SC_KEYMENU: - // TheSuperHackers @bugfix Mauller 10/05/2025 Always handle this command to prevent halting the game when left Alt is pressed. - return 1; - case SC_MOVE: - case SC_SIZE: - case SC_MAXIMIZE: - case SC_MONITORPOWER: - if( !TheGlobalData->m_windowed ) - return 1; - break; - } - break; + // Prevent moving/sizing and power loss in fullscreen mode + switch( wParam ) + { + case SC_KEYMENU: + // TheSuperHackers @bugfix Mauller 10/05/2025 Always handle this command to prevent halting the game when left Alt is pressed. + return 1; + case SC_MOVE: + case SC_SIZE: + case SC_MAXIMIZE: + case SC_MONITORPOWER: + if( !TheGlobalData->m_windowed ) + return 1; + break; + } + break; // ------------------------------------------------------------------------ case WM_CLOSE: - TheGameEngine->checkAbnormalQuitting(); - TheGameEngine->reset(); - TheGameEngine->setQuitting(TRUE); - _exit(EXIT_SUCCESS); - return 0; - - // ------------------------------------------------------------------------ - case WM_SETFOCUS: - { - - // - // reset the state of our keyboard cause we haven't been paying - // attention to the keys while focus was away - // - if( TheKeyboard ) - TheKeyboard->resetKeys(); - - if (TheMouse) - TheMouse->regainFocus(); - - break; - - } + TheGameEngine->checkAbnormalQuitting(); + TheGameEngine->reset(); + TheGameEngine->setQuitting(TRUE); + _exit(EXIT_SUCCESS); + return 0; //------------------------------------------------------------------------- case WM_MOVE: @@ -409,6 +391,22 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, break; } + // ------------------------------------------------------------------------ + case WM_SETFOCUS: + { + // + // reset the state of our keyboard cause we haven't been paying + // attention to the keys while focus was away + // + if( TheKeyboard ) + TheKeyboard->resetKeys(); + + if (TheMouse) + TheMouse->regainFocus(); + + break; + } + //------------------------------------------------------------------------- case WM_KILLFOCUS: { @@ -416,8 +414,15 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, TheKeyboard->resetKeys(); if (TheMouse) + { TheMouse->loseFocus(); + if (TheMouse->isCursorInside()) + { + TheMouse->onCursorMovedOutside(); + } + } + break; } @@ -439,13 +444,15 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, TheGameEngine->setIsActive(isWinMainActive); if (isWinMainActive) - { //restore mouse cursor to our custom version. + { + //restore mouse cursor to our custom version. if (TheWin32Mouse) TheWin32Mouse->setCursor(TheWin32Mouse->getMouseCursor()); } } return 0; } + //------------------------------------------------------------------------- case WM_ACTIVATE: { @@ -466,7 +473,6 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, TheMouse->refreshCursorCapture(); } break; - } //------------------------------------------------------------------------- @@ -476,21 +482,13 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, switch( key ) { - - //--------------------------------------------------------------------- case VK_ESCAPE: { - PostQuitMessage( 0 ); break; - } - - } - return 0; - } //------------------------------------------------------------------------- @@ -506,17 +504,18 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, case WM_RBUTTONUP: case WM_RBUTTONDBLCLK: { - if( TheWin32Mouse ) TheWin32Mouse->addWin32Event( message, wParam, lParam, TheMessageTime ); return 0; - } //------------------------------------------------------------------------- case 0x020A: // WM_MOUSEWHEEL { + if( TheWin32Mouse == NULL ) + return 0; + long x = (long) LOWORD(lParam); long y = (long) HIWORD(lParam); RECT rect; @@ -526,32 +525,42 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, if( x < rect.left || x > rect.right || y < rect.top || y > rect.bottom ) return 0; - if( TheWin32Mouse ) - TheWin32Mouse->addWin32Event( message, wParam, lParam, TheMessageTime ); - + TheWin32Mouse->addWin32Event( message, wParam, lParam, TheMessageTime ); return 0; - } - //------------------------------------------------------------------------- case WM_MOUSEMOVE: { + if( TheWin32Mouse == NULL ) + return 0; + + // ignore when window is not active + if( !isWinMainActive ) + return 0; + Int x = (Int)LOWORD( lParam ); Int y = (Int)HIWORD( lParam ); RECT rect; -// Int keys = wParam; // ignore when outside of client area GetClientRect( ApplicationHWnd, &rect ); if( x < rect.left || x > rect.right || y < rect.top || y > rect.bottom ) + { + if ( TheMouse->isCursorInside() ) + { + TheMouse->onCursorMovedOutside(); + } return 0; + } - if( TheWin32Mouse ) - TheWin32Mouse->addWin32Event( message, wParam, lParam, TheMessageTime ); + if( !TheMouse->isCursorInside() ) + { + TheMouse->onCursorMovedInside(); + } + TheWin32Mouse->addWin32Event( message, wParam, lParam, TheMessageTime ); return 0; - } //------------------------------------------------------------------------- diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/HeaderTemplate.h b/GeneralsMD/Code/GameEngine/Include/GameClient/HeaderTemplate.h index 4ee31cf727..d7683eeb8d 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/HeaderTemplate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/HeaderTemplate.h @@ -94,7 +94,7 @@ class HeaderTemplateManager HeaderTemplate *getFirstHeader( void ); HeaderTemplate *getNextHeader( HeaderTemplate *ht ); - void headerNotifyResolutionChange(void); + void onResolutionChanged(void); private: void populateGameFonts( void ); diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/Mouse.h b/GeneralsMD/Code/GameEngine/Include/GameClient/Mouse.h index d26d97317d..8d22891b39 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/Mouse.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/Mouse.h @@ -170,6 +170,7 @@ class Mouse : public SubsystemInterface CursorCaptureBlockReason_NoInit, CursorCaptureBlockReason_Paused, CursorCaptureBlockReason_Unfocused, + CursorCaptureBlockReadon_CursorIsOutside, CursorCaptureBlockReason_Count }; @@ -310,10 +311,14 @@ class Mouse : public SubsystemInterface Int getCursorIndex( const AsciiString& name ); void resetTooltipDelay( void ); - virtual void loseFocus(); - virtual void regainFocus(); + virtual void loseFocus(); ///< called when window has lost focus + virtual void regainFocus(); ///< called when window has regained focus - void mouseNotifyResolutionChange(void); + void onCursorMovedOutside(); ///< called when cursor has left game window + void onCursorMovedInside(); ///< called when cursor has entered game window + Bool isCursorInside() const; ///< true if the mouse is located inside the game window + + void onResolutionChanged(void); void onGameModeChanged(GameMode prev, GameMode next); void onGamePaused(Bool paused); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp index e2cb0193c1..23b5e9ea14 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp @@ -745,8 +745,8 @@ void DeclineResolution() TheWritableGlobalData->m_xResolution = newDispSettings.xRes; TheWritableGlobalData->m_yResolution = newDispSettings.yRes; - TheHeaderTemplateManager->headerNotifyResolutionChange(); - TheMouse->mouseNotifyResolutionChange(); + TheHeaderTemplateManager->onResolutionChanged(); + TheMouse->onResolutionChanged(); AsciiString prefString; prefString.format("%d %d", newDispSettings.xRes, newDispSettings.yRes); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp index 14d6063f8e..782cc525c8 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp @@ -1600,8 +1600,8 @@ static void saveOptions( void ) TheWritableGlobalData->m_xResolution = xres; TheWritableGlobalData->m_yResolution = yres; - TheHeaderTemplateManager->headerNotifyResolutionChange(); - TheMouse->mouseNotifyResolutionChange(); + TheHeaderTemplateManager->onResolutionChanged(); + TheMouse->onResolutionChanged(); //Save new settings for a dialog box confirmation after options are accepted newDispSettings.xRes = xres; diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/HeaderTemplate.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/HeaderTemplate.cpp index dfbd9e9c49..4b873a3a77 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/HeaderTemplate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/HeaderTemplate.cpp @@ -206,7 +206,7 @@ HeaderTemplate *HeaderTemplateManager::getNextHeader( HeaderTemplate *ht ) } -void HeaderTemplateManager::headerNotifyResolutionChange( void ) +void HeaderTemplateManager::onResolutionChanged( void ) { populateGameFonts(); } diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Input/Mouse.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Input/Mouse.cpp index b663e8d3b4..db0e9c745f 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Input/Mouse.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Input/Mouse.cpp @@ -64,6 +64,7 @@ const char *const Mouse::CursorCaptureBlockReasonNames[] = { "CursorCaptureBlockReason_NoInit", "CursorCaptureBlockReason_Paused", "CursorCaptureBlockReason_Unfocused", + "CursorCaptureBlockReason_CursorIsOutside", }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -575,7 +576,7 @@ void Mouse::init( void ) m_numButtons = 2; // by default just have 2 buttons m_numAxes = 2; // by default a normal mouse moves in a 2d plane m_forceFeedback = FALSE; - mouseNotifyResolutionChange(); + onResolutionChanged(); m_tooltipString.clear(); // redundant m_displayTooltip = FALSE; @@ -607,7 +608,7 @@ void Mouse::init( void ) //------------------------------------------------------------------------------------------------- /** Tell mouse system display resolution changed. */ //------------------------------------------------------------------------------------------------- -void Mouse::mouseNotifyResolutionChange( void ) +void Mouse::onResolutionChanged( void ) { if(m_tooltipDisplayString) TheDisplayStringManager->freeDisplayString(m_tooltipDisplayString); @@ -1034,6 +1035,24 @@ void Mouse::regainFocus() unblockCapture(CursorCaptureBlockReason_Unfocused); } +// ------------------------------------------------------------------------------------------------ +void Mouse::onCursorMovedOutside() +{ + blockCapture(CursorCaptureBlockReadon_CursorIsOutside); +} + +// ------------------------------------------------------------------------------------------------ +void Mouse::onCursorMovedInside() +{ + unblockCapture(CursorCaptureBlockReadon_CursorIsOutside); +} + +// ------------------------------------------------------------------------------------------------ +Bool Mouse::isCursorInside() const +{ + return (m_captureBlockReasonBits & (1 << CursorCaptureBlockReadon_CursorIsOutside)) == 0; +} + // ------------------------------------------------------------------------------------------------ void Mouse::initCapture() { diff --git a/GeneralsMD/Code/Main/WinMain.cpp b/GeneralsMD/Code/Main/WinMain.cpp index 6017276941..fb91c4fbea 100644 --- a/GeneralsMD/Code/Main/WinMain.cpp +++ b/GeneralsMD/Code/Main/WinMain.cpp @@ -72,7 +72,7 @@ // GLOBALS //////////////////////////////////////////////////////////////////// HINSTANCE ApplicationHInstance = NULL; ///< our application instance HWND ApplicationHWnd = NULL; ///< our application window handle -Win32Mouse *TheWin32Mouse= NULL; ///< for the WndProc() only +Win32Mouse *TheWin32Mouse = NULL; ///< for the WndProc() only DWORD TheMessageTime = 0; ///< For getting the time that a message was posted from Windows. const Char *g_strFile = "data\\Generals.str"; @@ -318,51 +318,51 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, { //------------------------------------------------------------------------- case WM_NCHITTEST: - // Prevent the user from selecting the menu in fullscreen mode - if( !TheGlobalData->m_windowed ) - return HTCLIENT; - break; + // Prevent the user from selecting the menu in fullscreen mode + if( !TheGlobalData->m_windowed ) + return HTCLIENT; + break; //------------------------------------------------------------------------- case WM_POWERBROADCAST: - switch( wParam ) - { - #ifndef PBT_APMQUERYSUSPEND - #define PBT_APMQUERYSUSPEND 0x0000 - #endif - case PBT_APMQUERYSUSPEND: - // At this point, the app should save any data for open - // network connections, files, etc., and prepare to go into - // a suspended mode. - return TRUE; - - #ifndef PBT_APMRESUMESUSPEND - #define PBT_APMRESUMESUSPEND 0x0007 - #endif - case PBT_APMRESUMESUSPEND: - // At this point, the app should recover any data, network - // connections, files, etc., and resume running from when - // the app was suspended. - return TRUE; - } - break; + switch( wParam ) + { + #ifndef PBT_APMQUERYSUSPEND + #define PBT_APMQUERYSUSPEND 0x0000 + #endif + case PBT_APMQUERYSUSPEND: + // At this point, the app should save any data for open + // network connections, files, etc., and prepare to go into + // a suspended mode. + return TRUE; + + #ifndef PBT_APMRESUMESUSPEND + #define PBT_APMRESUMESUSPEND 0x0007 + #endif + case PBT_APMRESUMESUSPEND: + // At this point, the app should recover any data, network + // connections, files, etc., and resume running from when + // the app was suspended. + return TRUE; + } + break; //------------------------------------------------------------------------- case WM_SYSCOMMAND: - // Prevent moving/sizing and power loss in fullscreen mode - switch( wParam ) - { - case SC_KEYMENU: - // TheSuperHackers @bugfix Mauller 10/05/2025 Always handle this command to prevent halting the game when left Alt is pressed. - return 1; - case SC_MOVE: - case SC_SIZE: - case SC_MAXIMIZE: - case SC_MONITORPOWER: - if( !TheGlobalData->m_windowed ) - return 1; - break; - } - break; + // Prevent moving/sizing and power loss in fullscreen mode + switch( wParam ) + { + case SC_KEYMENU: + // TheSuperHackers @bugfix Mauller 10/05/2025 Always handle this command to prevent halting the game when left Alt is pressed. + return 1; + case SC_MOVE: + case SC_SIZE: + case SC_MAXIMIZE: + case SC_MONITORPOWER: + if( !TheGlobalData->m_windowed ) + return 1; + break; + } + break; case WM_QUERYENDSESSION: { @@ -372,42 +372,24 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, // ------------------------------------------------------------------------ case WM_CLOSE: - if (!TheGameEngine->getQuitting()) - { - //user is exiting without using the menus + if (!TheGameEngine->getQuitting()) + { + //user is exiting without using the menus - //This method didn't work in cinematics because we don't process messages. - //But it's the cleanest way to exit that's similar to using menus. - TheMessageStream->appendMessage(GameMessage::MSG_META_DEMO_INSTANT_QUIT); + //This method didn't work in cinematics because we don't process messages. + //But it's the cleanest way to exit that's similar to using menus. + TheMessageStream->appendMessage(GameMessage::MSG_META_DEMO_INSTANT_QUIT); - //This method used to disable quitting. We just put up the options screen instead. - //TheMessageStream->appendMessage(GameMessage::MSG_META_OPTIONS); + //This method used to disable quitting. We just put up the options screen instead. + //TheMessageStream->appendMessage(GameMessage::MSG_META_OPTIONS); - //This method works everywhere but isn't as clean at shutting down. - //TheGameEngine->checkAbnormalQuitting(); //old way to log disconnections for ALT-F4 - //TheGameEngine->reset(); - //TheGameEngine->setQuitting(TRUE); - //_exit(EXIT_SUCCESS); + //This method works everywhere but isn't as clean at shutting down. + //TheGameEngine->checkAbnormalQuitting(); //old way to log disconnections for ALT-F4 + //TheGameEngine->reset(); + //TheGameEngine->setQuitting(TRUE); + //_exit(EXIT_SUCCESS); + } return 0; - } - - // ------------------------------------------------------------------------ - case WM_SETFOCUS: - { - - // - // reset the state of our keyboard cause we haven't been paying - // attention to the keys while focus was away - // - if( TheKeyboard ) - TheKeyboard->resetKeys(); - - if (TheMouse) - TheMouse->regainFocus(); - - break; - - } //------------------------------------------------------------------------- case WM_MOVE: @@ -431,6 +413,22 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, break; } + // ------------------------------------------------------------------------ + case WM_SETFOCUS: + { + // + // reset the state of our keyboard cause we haven't been paying + // attention to the keys while focus was away + // + if( TheKeyboard ) + TheKeyboard->resetKeys(); + + if (TheMouse) + TheMouse->regainFocus(); + + break; + } + //------------------------------------------------------------------------- case WM_KILLFOCUS: { @@ -438,8 +436,15 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, TheKeyboard->resetKeys(); if (TheMouse) + { TheMouse->loseFocus(); + if (TheMouse->isCursorInside()) + { + TheMouse->onCursorMovedOutside(); + } + } + break; } @@ -461,13 +466,15 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, TheGameEngine->setIsActive(isWinMainActive); if (isWinMainActive) - { //restore mouse cursor to our custom version. + { + //restore mouse cursor to our custom version. if (TheWin32Mouse) TheWin32Mouse->setCursor(TheWin32Mouse->getMouseCursor()); } } return 0; } + //------------------------------------------------------------------------- case WM_ACTIVATE: { @@ -488,7 +495,6 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, TheMouse->refreshCursorCapture(); } break; - } //------------------------------------------------------------------------- @@ -498,21 +504,13 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, switch( key ) { - - //--------------------------------------------------------------------- case VK_ESCAPE: { - PostQuitMessage( 0 ); break; - } - - } - return 0; - } //------------------------------------------------------------------------- @@ -528,17 +526,18 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, case WM_RBUTTONUP: case WM_RBUTTONDBLCLK: { - if( TheWin32Mouse ) TheWin32Mouse->addWin32Event( message, wParam, lParam, TheMessageTime ); return 0; - } //------------------------------------------------------------------------- case 0x020A: // WM_MOUSEWHEEL { + if( TheWin32Mouse == NULL ) + return 0; + long x = (long) LOWORD(lParam); long y = (long) HIWORD(lParam); RECT rect; @@ -548,32 +547,42 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, if( x < rect.left || x > rect.right || y < rect.top || y > rect.bottom ) return 0; - if( TheWin32Mouse ) - TheWin32Mouse->addWin32Event( message, wParam, lParam, TheMessageTime ); - + TheWin32Mouse->addWin32Event( message, wParam, lParam, TheMessageTime ); return 0; - } - //------------------------------------------------------------------------- case WM_MOUSEMOVE: { + if( TheWin32Mouse == NULL ) + return 0; + + // ignore when window is not active + if( !isWinMainActive ) + return 0; + Int x = (Int)LOWORD( lParam ); Int y = (Int)HIWORD( lParam ); RECT rect; -// Int keys = wParam; // ignore when outside of client area GetClientRect( ApplicationHWnd, &rect ); if( x < rect.left || x > rect.right || y < rect.top || y > rect.bottom ) + { + if ( TheMouse->isCursorInside() ) + { + TheMouse->onCursorMovedOutside(); + } return 0; + } - if( TheWin32Mouse ) - TheWin32Mouse->addWin32Event( message, wParam, lParam, TheMessageTime ); + if( !TheMouse->isCursorInside() ) + { + TheMouse->onCursorMovedInside(); + } + TheWin32Mouse->addWin32Event( message, wParam, lParam, TheMessageTime ); return 0; - } //-------------------------------------------------------------------------