Skip to content

Commit

Permalink
Fixed bug 2260 - SDL_SetCursorGrab() is buggy on Windows
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
slouken committed Nov 27, 2013
1 parent fa4e4a6 commit d2511d9
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 29 deletions.
82 changes: 58 additions & 24 deletions src/video/windows/SDL_windowsevents.c
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
{
Expand Down Expand Up @@ -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;
Expand Down
9 changes: 4 additions & 5 deletions src/video/windows/SDL_windowsmouse.c
Expand Up @@ -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. */
Expand All @@ -216,7 +216,7 @@ WIN_SetRelativeMouseMode(SDL_bool enabled)
}
}

if(enabled) {
if (enabled) {
LONG cx, cy;
RECT rect;
GetWindowRect(hWnd, &rect);
Expand All @@ -231,10 +231,9 @@ WIN_SetRelativeMouseMode(SDL_bool enabled)
rect.bottom = cy+1;

ClipCursor(&rect);
}
else
} else {
ClipCursor(NULL);

}
return 0;
}

Expand Down

0 comments on commit d2511d9

Please sign in to comment.