From 3a57725ea94454dddc5fe05366a76ec2b199f776 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 3 Jul 2012 23:52:02 -0400 Subject: [PATCH] Patrick Baggett implemented relative mouse mode on Win32 Here is my first rough attempt. "testrelative" feels right to me, but I'd like it someone else tested this, especially compared to Linux/OSX. The "Ctrl+r" to switch between relative and normal mouse movements seems to work flawlessly. With relative mouse movement, the only way to change focus is via keyboard. I'm not sure if that is the correct approach, but that would seem to be the most useful mode for games. Still, if my assumption is wrong, I can fix that no problem. --- src/core/windows/SDL_windows.h | 2 +- src/video/windows/SDL_windowsevents.c | 39 ++++++++++++++++++++++++ src/video/windows/SDL_windowsmouse.c | 44 +++++++++++++++++++++++++-- 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/src/core/windows/SDL_windows.h b/src/core/windows/SDL_windows.h index ab21627d6..0c0486673 100755 --- a/src/core/windows/SDL_windows.h +++ b/src/core/windows/SDL_windows.h @@ -30,7 +30,7 @@ #define UNICODE 1 #endif #undef _WIN32_WINNT -#define _WIN32_WINNT 0x500 /* Need 0x410 for AlphaBlend() and 0x500 for EnumDisplayDevices() */ +#define _WIN32_WINNT 0x501 /* Need 0x410 for AlphaBlend() and 0x500 for EnumDisplayDevices(), 0x501 for raw input */ #include diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index d844fba20..fa1c33474 100755 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -173,6 +173,24 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) if (SDL_GetKeyboardFocus() != data->window) { SDL_SetKeyboardFocus(data->window); } + + 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); + } + /* * FIXME: Update keyboard state */ @@ -191,6 +209,8 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) break; case WM_MOUSEMOVE: + if(SDL_GetMouse()->relative_mode) + break; #ifdef _WIN32_WCE /* transform coords for VGA, WVGA... */ { @@ -208,6 +228,25 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) SDL_SendMouseMotion(data->window, 0, LOWORD(lParam), HIWORD(lParam)); break; + case WM_INPUT: + { + HRAWINPUT hRawInput = (HRAWINPUT)lParam; + RAWINPUT inp; + UINT size = sizeof(inp); + GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER)); + + /* Mouse data */ + if(inp.header.dwType == RIM_TYPEMOUSE) + { + RAWMOUSE* mouse = &inp.data.mouse; + + if((mouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) + SDL_SendMouseMotion(data->window, 1, (int)mouse->lLastX, (int)mouse->lLastY); + + } + break; + } + case WM_LBUTTONDOWN: SDL_SendMouseButton(data->window, SDL_PRESSED, SDL_BUTTON_LEFT); break; diff --git a/src/video/windows/SDL_windowsmouse.c b/src/video/windows/SDL_windowsmouse.c index 73103c4c7..d0d30b945 100755 --- a/src/video/windows/SDL_windowsmouse.c +++ b/src/video/windows/SDL_windowsmouse.c @@ -140,8 +140,48 @@ WIN_WarpMouse(SDL_Window * window, int x, int y) static int WIN_SetRelativeMouseMode(SDL_bool enabled) { - SDL_Unsupported(); - return -1; + RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */ + HWND hWnd; + hWnd = GetActiveWindow(); + + rawMouse.hwndTarget = hWnd; + if(!enabled) { + rawMouse.dwFlags |= RIDEV_REMOVE; + rawMouse.hwndTarget = NULL; + } + + + /* (Un)register raw input for mice */ + 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. */ + if(enabled) { + SDL_Unsupported(); + return -1; + } + } + + if(enabled) { + 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); + } + else + ClipCursor(NULL); + + return 0; } void