From d2511d9ef9cd73efc9ddc37a248787875d3b5acf Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 27 Nov 2013 10:29:38 -0800 Subject: [PATCH] Fixed bug 2260 - SDL_SetCursorGrab() is buggy on Windows BurnSpamAddress Steps to reproduce: 1. Grab the cursor with SDL_SetCursorGrab() 2. Alt-tab away from the window 3. Click on the titlebar of the window This will cause the window to disappear underneath the taskbar! This appears to be a general issue with ClipCursor() on windows, i.e. I am getting the same behavior if I call ClipCursor() directly. It is caused by a feedback loop between the ClipCursor function and the modal resize/move event loop that handles mouse-based sizing on Windows. --- src/video/windows/SDL_windowsevents.c | 82 +++++++++++++++++++-------- src/video/windows/SDL_windowsmouse.c | 9 ++- 2 files changed, 62 insertions(+), 29 deletions(-) diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index eeb26c0a3f973..bbab2da2cb1a6 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -286,6 +286,45 @@ WIN_ConvertUTF32toUTF8(UINT32 codepoint, char * text) return SDL_TRUE; } +static void +WIN_UpdateClipCursor(SDL_Window *window) +{ + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + + /* Don't clip the cursor while we're in the modal resize or move loop */ + if (data->in_modal_loop) { + ClipCursor(NULL); + return; + } + + if (SDL_GetMouse()->relative_mode) { + LONG cx, cy; + RECT rect; + GetWindowRect(data->hwnd, &rect); + + cx = (rect.left + rect.right) / 2; + cy = (rect.top + rect.bottom) / 2; + + /* Make an absurdly small clip rect */ + rect.left = cx-1; + rect.right = cx+1; + rect.top = cy-1; + rect.bottom = cy+1; + + ClipCursor(&rect); + } else if ((window->flags & SDL_WINDOW_INPUT_GRABBED) && + (window->flags & SDL_WINDOW_INPUT_FOCUS)) { + RECT rect; + if (GetClientRect(data->hwnd, &rect) && !IsRectEmpty(&rect)) { + ClientToScreen(data->hwnd, (LPPOINT) & rect); + ClientToScreen(data->hwnd, (LPPOINT) & rect + 1); + ClipCursor(&rect); + } + } else { + ClipCursor(NULL); + } +} + LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -369,22 +408,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) WIN_CheckWParamMouseButton( ( keyState & 0x8000 ), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2 ); data->mouse_button_flags = 0; - if(SDL_GetMouse()->relative_mode) { - LONG cx, cy; - RECT rect; - GetWindowRect(hwnd, &rect); - - cx = (rect.left + rect.right) / 2; - cy = (rect.top + rect.bottom) / 2; - - /* Make an absurdly small clip rect */ - rect.left = cx-1; - rect.right = cx+1; - rect.top = cy-1; - rect.bottom = cy+1; - - ClipCursor(&rect); - } + WIN_UpdateClipCursor(data->window); /* * FIXME: Update keyboard state @@ -585,6 +609,22 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) break; #endif /* WM_INPUTLANGCHANGE */ + case WM_ENTERSIZEMOVE: + case WM_ENTERMENULOOP: + { + data->in_modal_loop = SDL_TRUE; + WIN_UpdateClipCursor(data->window); + } + break; + + case WM_EXITSIZEMOVE: + case WM_EXITMENULOOP: + { + data->in_modal_loop = SDL_FALSE; + WIN_UpdateClipCursor(data->window); + } + break; + #ifdef WM_GETMINMAXINFO case WM_GETMINMAXINFO: { @@ -673,20 +713,14 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) RECT rect; int x, y; int w, h; - Uint32 window_flags; - if (!GetClientRect(hwnd, &rect) || - (rect.right == rect.left && rect.bottom == rect.top)) { + if (!GetClientRect(hwnd, &rect) || IsRectEmpty(&rect)) { break; } ClientToScreen(hwnd, (LPPOINT) & rect); ClientToScreen(hwnd, (LPPOINT) & rect + 1); - window_flags = SDL_GetWindowFlags(data->window); - if ((window_flags & SDL_WINDOW_INPUT_GRABBED) && - (window_flags & SDL_WINDOW_INPUT_FOCUS)) { - ClipCursor(&rect); - } + WIN_UpdateClipCursor(data->window); x = rect.left; y = rect.top; diff --git a/src/video/windows/SDL_windowsmouse.c b/src/video/windows/SDL_windowsmouse.c index f50a8724bf5dd..f75b8dad335d9 100644 --- a/src/video/windows/SDL_windowsmouse.c +++ b/src/video/windows/SDL_windowsmouse.c @@ -207,7 +207,7 @@ WIN_SetRelativeMouseMode(SDL_bool enabled) /* (Un)register raw input for mice */ - if(RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)) == FALSE) { + if (RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)) == FALSE) { /* Only return an error when registering. If we unregister and fail, then it's probably that we unregistered twice. That's OK. */ @@ -216,7 +216,7 @@ WIN_SetRelativeMouseMode(SDL_bool enabled) } } - if(enabled) { + if (enabled) { LONG cx, cy; RECT rect; GetWindowRect(hWnd, &rect); @@ -231,10 +231,9 @@ WIN_SetRelativeMouseMode(SDL_bool enabled) rect.bottom = cy+1; ClipCursor(&rect); - } - else + } else { ClipCursor(NULL); - + } return 0; }