From 3620da42e4187d47421adcb93e29c7fe8d5f3195 Mon Sep 17 00:00:00 2001 From: myT Date: Fri, 7 Dec 2018 21:28:22 +0100 Subject: [PATCH] fixed mouse cursor clipping on Windows --- changelog.txt | 2 ++ code/win32/win_input.cpp | 51 +++++++++++++++++++++++++++++----------- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/changelog.txt b/changelog.txt index e8fda50..d37bac2 100644 --- a/changelog.txt +++ b/changelog.txt @@ -14,6 +14,8 @@ add: /toggle can now accept a value sequence (2 or more entries) to loop through if the cvar's current value is in the sequence and not in the last spot, the next one is used otherwise, the first value in the sequence is used +fix: on Windows, could sometimes click outside the engine's window in raw mouse input mode + fix: when r_msaa was in the range [2, 16], the requested sample count was always 4 fix: /video and /stopvideo fixes diff --git a/code/win32/win_input.cpp b/code/win32/win_input.cpp index 05f66e5..85cd712 100644 --- a/code/win32/win_input.cpp +++ b/code/win32/win_input.cpp @@ -30,6 +30,7 @@ static cvar_t* in_noGrab; struct Mouse { Mouse() : active(qfalse) {} + virtual ~Mouse() {} qbool IsActive() const { return active; } @@ -37,6 +38,7 @@ struct Mouse { virtual qbool Activate( qbool _active ) { return qfalse; } // qtrue if successful virtual void Shutdown() {} virtual qbool ProcessMessage( UINT msg, WPARAM wParam, LPARAM lParam ) { return qfalse; } // qtrue if the event was handled + virtual void GetClipRect( RECT* clip, const RECT* client ) = 0; protected: void UpdateWheel( int delta ); // queues mouse wheel events if needed @@ -74,6 +76,7 @@ struct rawmouse_t : public Mouse { virtual qbool Activate( qbool active ); virtual void Shutdown(); virtual qbool ProcessMessage( UINT msg, WPARAM wParam, LPARAM lParam ); + virtual void GetClipRect( RECT* clip, const RECT* client ); }; static rawmouse_t rawmouse; @@ -173,6 +176,16 @@ qbool rawmouse_t::ProcessMessage( UINT msg, WPARAM wParam, LPARAM lParam ) } +void rawmouse_t::GetClipRect( RECT* clip, const RECT* client ) +{ + // when passing the window's client area in desktop coordinates to ClipCursor, + // it is *still* possible to click outside the window (on Windows 7 at least) + POINT center = { ( client->left + client->right ) / 2, ( client->top + client->bottom ) / 2 }; + MapWindowPoints( g_wv.hWnd, HWND_DESKTOP, ¢er, 1 ); + *clip = { center.x - 1, center.y - 1, center.x + 1, center.y + 1 }; +} + + /////////////////////////////////////////////////////////////// @@ -180,6 +193,7 @@ struct winmouse_t : public Mouse { virtual qbool Init() { return qtrue; } virtual qbool Activate( qbool active ); virtual qbool ProcessMessage( UINT msg, WPARAM wParam, LPARAM lParam ); + virtual void GetClipRect( RECT* clip, const RECT* client ); private: void UpdateWindowCenter(); @@ -229,7 +243,7 @@ qbool winmouse_t::ProcessMessage( UINT msg, WPARAM wParam, LPARAM lParam ) UpdateWindowCenter(); #define QUEUE_WM_BUTTON( qbutton, mask ) \ - WIN_QueEvent( g_wv.sysMsgTime, SE_KEY, qbutton, (wParam & mask), 0, NULL ); + WIN_QueEvent( g_wv.sysMsgTime, SE_KEY, qbutton, (wParam & mask), 0, NULL ) POINT p; GetCursorPos( &p ); @@ -274,6 +288,15 @@ qbool winmouse_t::ProcessMessage( UINT msg, WPARAM wParam, LPARAM lParam ) } +void winmouse_t::GetClipRect( RECT* clip, const RECT* client ) +{ + const int border = 16; // a little safety nest since Windows doesn't handle cursor clip rectangles perfectly right + POINT endPoints[2] = { { client->left, client->top }, { client->right, client->bottom } }; + MapWindowPoints( g_wv.hWnd, HWND_DESKTOP, endPoints, 2 ); + *clip = { endPoints[0].x + border, endPoints[0].y + border, endPoints[1].x - 2 * border, endPoints[1].y - 2 * border }; +} + + /////////////////////////////////////////////////////////////// @@ -355,15 +378,15 @@ static void IN_Startup() void Sys_InitInput() -{ +{ if (g_wv.inputInitialized) return; - + in_midi = Cvar_Get( "in_midi", "0", CVAR_ARCHIVE ); Cvar_SetModule( "in_midi", MODULE_INPUT ); in_joystick = Cvar_Get( "in_joystick", "0", CVAR_ARCHIVE|CVAR_LATCH ); - Cvar_SetModule( "in_joystick", MODULE_INPUT ); + Cvar_SetModule( "in_joystick", MODULE_INPUT ); in_joystick->modified = qfalse; IN_Startup(); @@ -394,18 +417,15 @@ void Sys_ShutdownInput() static void IN_SetCursorSettings( qbool active ) { if (active) { - while (ShowCursor(FALSE) >= 0) - ; - RECT rect; + while (ShowCursor(FALSE) >= 0) {} SetCapture( g_wv.hWnd ); - GetClientRect( g_wv.hWnd, &rect ); - POINT points[2] = { { rect.left, rect.top }, { rect.right, rect.bottom } }; - MapWindowPoints( g_wv.hWnd, HWND_DESKTOP, points, 2 ); - rect = { points[0].x, points[0].y, points[1].x, points[1].y }; - ClipCursor( &rect ); + RECT clientRect; + GetClientRect( g_wv.hWnd, &clientRect ); + RECT clipRect; + mouse->GetClipRect( &clipRect, &clientRect ); + ClipCursor( &clipRect ); } else { - while (ShowCursor(TRUE) < 0) - ; + while (ShowCursor(TRUE) < 0) {} ClipCursor( NULL ); ReleaseCapture(); } @@ -436,6 +456,9 @@ static qbool IN_ShouldBeActive() if ( g_wv.monitorCount >= 2 && isConsoleDown ) return qfalse; + if ( GetFocus() != g_wv.hWnd ) + return qfalse; + return g_wv.activeApp && (!isConsoleDown || Cvar_VariableIntegerValue("r_fullscreen")); }