Patrick Baggett implemented relative mouse mode on Win32
authorSam Lantinga <slouken@libsdl.org>
Tue, 03 Jul 2012 23:52:02 -0400
changeset 635019545983ac76
parent 6349 bc8de0568373
child 6351 8f5535d05e34
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
src/video/windows/SDL_windowsevents.c
src/video/windows/SDL_windowsmouse.c
     1.1 --- a/src/core/windows/SDL_windows.h	Mon Jul 02 08:37:48 2012 -0400
     1.2 +++ b/src/core/windows/SDL_windows.h	Tue Jul 03 23:52:02 2012 -0400
     1.3 @@ -30,7 +30,7 @@
     1.4  #define UNICODE 1
     1.5  #endif
     1.6  #undef _WIN32_WINNT
     1.7 -#define _WIN32_WINNT  0x500   /* Need 0x410 for AlphaBlend() and 0x500 for EnumDisplayDevices() */
     1.8 +#define _WIN32_WINNT  0x501   /* Need 0x410 for AlphaBlend() and 0x500 for EnumDisplayDevices(), 0x501 for raw input */
     1.9  
    1.10  #include <windows.h>
    1.11  
     2.1 --- a/src/video/windows/SDL_windowsevents.c	Mon Jul 02 08:37:48 2012 -0400
     2.2 +++ b/src/video/windows/SDL_windowsevents.c	Tue Jul 03 23:52:02 2012 -0400
     2.3 @@ -173,6 +173,24 @@
     2.4                  if (SDL_GetKeyboardFocus() != data->window) {
     2.5                      SDL_SetKeyboardFocus(data->window);
     2.6                  }
     2.7 +
     2.8 +				if(SDL_GetMouse()->relative_mode) {
     2.9 +					LONG cx, cy;
    2.10 +					RECT rect;
    2.11 +					GetWindowRect(hwnd, &rect);
    2.12 +
    2.13 +					cx = (rect.left + rect.right) / 2;
    2.14 +					cy = (rect.top + rect.bottom) / 2;
    2.15 +
    2.16 +					/* Make an absurdly small clip rect */
    2.17 +					rect.left = cx-1;
    2.18 +					rect.right = cx+1;
    2.19 +					rect.top = cy-1;
    2.20 +					rect.bottom = cy+1;
    2.21 +
    2.22 +					ClipCursor(&rect);
    2.23 +				}
    2.24 +
    2.25                  /*
    2.26                   * FIXME: Update keyboard state
    2.27                   */
    2.28 @@ -191,6 +209,8 @@
    2.29          break;
    2.30  
    2.31  	case WM_MOUSEMOVE:
    2.32 +		if(SDL_GetMouse()->relative_mode)
    2.33 +			break;
    2.34  #ifdef _WIN32_WCE
    2.35          /* transform coords for VGA, WVGA... */
    2.36          {
    2.37 @@ -208,6 +228,25 @@
    2.38          SDL_SendMouseMotion(data->window, 0, LOWORD(lParam), HIWORD(lParam));
    2.39          break;
    2.40  
    2.41 +	case WM_INPUT:
    2.42 +	{
    2.43 +		HRAWINPUT hRawInput = (HRAWINPUT)lParam;
    2.44 +		RAWINPUT inp;
    2.45 +		UINT size = sizeof(inp);
    2.46 +		GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
    2.47 +
    2.48 +		/* Mouse data */
    2.49 +		if(inp.header.dwType == RIM_TYPEMOUSE)
    2.50 +		{
    2.51 +			RAWMOUSE* mouse = &inp.data.mouse;
    2.52 +
    2.53 +			if((mouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE)
    2.54 +				SDL_SendMouseMotion(data->window, 1, (int)mouse->lLastX, (int)mouse->lLastY);
    2.55 +
    2.56 +		}
    2.57 +		break;
    2.58 +	}
    2.59 +
    2.60      case WM_LBUTTONDOWN:
    2.61          SDL_SendMouseButton(data->window, SDL_PRESSED, SDL_BUTTON_LEFT);
    2.62          break;
     3.1 --- a/src/video/windows/SDL_windowsmouse.c	Mon Jul 02 08:37:48 2012 -0400
     3.2 +++ b/src/video/windows/SDL_windowsmouse.c	Tue Jul 03 23:52:02 2012 -0400
     3.3 @@ -140,8 +140,48 @@
     3.4  static int
     3.5  WIN_SetRelativeMouseMode(SDL_bool enabled)
     3.6  {
     3.7 -    SDL_Unsupported();
     3.8 -    return -1;
     3.9 +    RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */
    3.10 +	HWND hWnd;
    3.11 +	hWnd = GetActiveWindow();
    3.12 +
    3.13 +	rawMouse.hwndTarget = hWnd;
    3.14 +	if(!enabled) {
    3.15 +		rawMouse.dwFlags |= RIDEV_REMOVE;
    3.16 +		rawMouse.hwndTarget = NULL;
    3.17 +	}
    3.18 +
    3.19 +
    3.20 +	/* (Un)register raw input for mice */
    3.21 +	if(RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)) == FALSE) {
    3.22 +
    3.23 +		/* Only return an error when registering. If we unregister and fail, then
    3.24 +		it's probably that we unregistered twice. That's OK. */
    3.25 +		if(enabled) {
    3.26 +			SDL_Unsupported();
    3.27 +			return -1;
    3.28 +		}
    3.29 +	}
    3.30 +
    3.31 +	if(enabled) {
    3.32 +		LONG cx, cy;
    3.33 +		RECT rect;
    3.34 +		GetWindowRect(hWnd, &rect);
    3.35 +
    3.36 +		cx = (rect.left + rect.right) / 2;
    3.37 +		cy = (rect.top + rect.bottom) / 2;
    3.38 +
    3.39 +		/* Make an absurdly small clip rect */
    3.40 +		rect.left = cx-1;
    3.41 +		rect.right = cx+1;
    3.42 +		rect.top = cy-1;
    3.43 +		rect.bottom = cy+1;
    3.44 +
    3.45 +		ClipCursor(&rect);
    3.46 +	}
    3.47 +	else
    3.48 +		ClipCursor(NULL);
    3.49 +
    3.50 +    return 0;
    3.51  }
    3.52  
    3.53  void