Fixed up SDL_CaptureMouse() on Windows to work like I expected.
This would have been a one-line patch to the documentation (specifying that captures only work as long as the left mouse button is pressed), but I didn't like that, so I got a little crazy about this instead.main
parent
bcc2cc8722
commit
bb7a27fadd
|
@ -30,6 +30,7 @@
|
|||
#include "../../events/SDL_events_c.h"
|
||||
#include "../../events/SDL_touch_c.h"
|
||||
#include "../../events/scancodes_windows.h"
|
||||
#include "SDL_assert.h"
|
||||
|
||||
/* Dropfile support */
|
||||
#include <shellapi.h>
|
||||
|
@ -428,33 +429,55 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
HRAWINPUT hRawInput = (HRAWINPUT)lParam;
|
||||
RAWINPUT inp;
|
||||
UINT size = sizeof(inp);
|
||||
const SDL_bool isRelative = mouse->relative_mode || mouse->relative_mode_warp;
|
||||
const SDL_bool isCapture = ((data->window->flags & SDL_WINDOW_MOUSE_CAPTURE) != 0);
|
||||
|
||||
if (!mouse->relative_mode || mouse->relative_mode_warp || mouse->focus != data->window) {
|
||||
break;
|
||||
if (!isRelative || mouse->focus != data->window) {
|
||||
if (!isCapture) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
|
||||
|
||||
/* Mouse data */
|
||||
if (inp.header.dwType == RIM_TYPEMOUSE) {
|
||||
RAWMOUSE* mouse = &inp.data.mouse;
|
||||
if (isRelative) {
|
||||
RAWMOUSE* mouse = &inp.data.mouse;
|
||||
|
||||
if ((mouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) {
|
||||
SDL_SendMouseMotion(data->window, 0, 1, (int)mouse->lLastX, (int)mouse->lLastY);
|
||||
} else {
|
||||
/* synthesize relative moves from the abs position */
|
||||
static SDL_Point initialMousePoint;
|
||||
if (initialMousePoint.x == 0 && initialMousePoint.y == 0) {
|
||||
initialMousePoint.x = mouse->lLastX;
|
||||
initialMousePoint.y = mouse->lLastY;
|
||||
}
|
||||
|
||||
SDL_SendMouseMotion(data->window, 0, 1, (int)(mouse->lLastX-initialMousePoint.x), (int)(mouse->lLastY-initialMousePoint.y) );
|
||||
|
||||
if ((mouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) {
|
||||
SDL_SendMouseMotion(data->window, 0, 1, (int)mouse->lLastX, (int)mouse->lLastY);
|
||||
} else {
|
||||
/* synthesize relative moves from the abs position */
|
||||
static SDL_Point initialMousePoint;
|
||||
if (initialMousePoint.x == 0 && initialMousePoint.y == 0) {
|
||||
initialMousePoint.x = mouse->lLastX;
|
||||
initialMousePoint.y = mouse->lLastY;
|
||||
}
|
||||
|
||||
SDL_SendMouseMotion(data->window, 0, 1, (int)(mouse->lLastX-initialMousePoint.x), (int)(mouse->lLastY-initialMousePoint.y) );
|
||||
|
||||
initialMousePoint.x = mouse->lLastX;
|
||||
initialMousePoint.y = mouse->lLastY;
|
||||
WIN_CheckRawMouseButtons( mouse->usButtonFlags, data );
|
||||
} else if (isCapture) {
|
||||
/* we check for where Windows thinks the system cursor lives in this case, so we don't really lose mouse accel, etc. */
|
||||
POINT pt;
|
||||
HWND hwnd = data->hwnd;
|
||||
GetCursorPos(&pt);
|
||||
if (WindowFromPoint(pt) != hwnd) { /* if in the window, WM_MOUSEMOVE, etc, will cover it. */
|
||||
ScreenToClient(data->hwnd, &pt);
|
||||
SDL_SendMouseMotion(data->window, 0, 0, (int) pt.x, (int) pt.y);
|
||||
SDL_SendMouseButton(data->window, 0, GetKeyState(VK_LBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_LEFT);
|
||||
SDL_SendMouseButton(data->window, 0, GetKeyState(VK_RBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_RIGHT);
|
||||
SDL_SendMouseButton(data->window, 0, GetKeyState(VK_MBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_MIDDLE);
|
||||
SDL_SendMouseButton(data->window, 0, GetKeyState(VK_XBUTTON1) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X1);
|
||||
SDL_SendMouseButton(data->window, 0, GetKeyState(VK_XBUTTON2) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X2);
|
||||
}
|
||||
} else {
|
||||
SDL_assert(0 && "Shouldn't happen");
|
||||
}
|
||||
WIN_CheckRawMouseButtons( mouse->usButtonFlags, data );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -499,7 +522,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
|
||||
#ifdef WM_MOUSELEAVE
|
||||
case WM_MOUSELEAVE:
|
||||
if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode) {
|
||||
if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode && !(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
|
||||
if (!IsIconic(hwnd)) {
|
||||
POINT cursorPos;
|
||||
GetCursorPos(&cursorPos);
|
||||
|
|
|
@ -30,6 +30,44 @@
|
|||
|
||||
HCURSOR SDL_cursor = NULL;
|
||||
|
||||
static int rawInputEnableCount = 0;
|
||||
|
||||
static int
|
||||
ToggleRawInput(SDL_bool enabled)
|
||||
{
|
||||
RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */
|
||||
|
||||
if (enabled) {
|
||||
rawInputEnableCount++;
|
||||
if (rawInputEnableCount > 1) {
|
||||
return 0; /* already done. */
|
||||
}
|
||||
} else {
|
||||
if (rawInputEnableCount == 0) {
|
||||
return 0; /* already done. */
|
||||
}
|
||||
rawInputEnableCount--;
|
||||
if (rawInputEnableCount > 0) {
|
||||
return 0; /* not time to disable yet */
|
||||
}
|
||||
}
|
||||
|
||||
if (!enabled) {
|
||||
rawMouse.dwFlags |= RIDEV_REMOVE;
|
||||
}
|
||||
|
||||
/* (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) {
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static SDL_Cursor *
|
||||
WIN_CreateDefaultCursor()
|
||||
|
@ -201,35 +239,25 @@ WIN_WarpMouse(SDL_Window * window, int x, int y)
|
|||
static int
|
||||
WIN_SetRelativeMouseMode(SDL_bool enabled)
|
||||
{
|
||||
RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */
|
||||
|
||||
if (!enabled) {
|
||||
rawMouse.dwFlags |= RIDEV_REMOVE;
|
||||
}
|
||||
|
||||
/* (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) {
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return ToggleRawInput(enabled);
|
||||
}
|
||||
|
||||
static int
|
||||
WIN_CaptureMouse(SDL_Window *window)
|
||||
{
|
||||
if (!window) {
|
||||
ReleaseCapture();
|
||||
} else {
|
||||
const SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
|
||||
SetCapture(data->hwnd);
|
||||
SDL_Window *focusWin = SDL_GetKeyboardFocus();
|
||||
if (focusWin) {
|
||||
SDL_WindowData *data = (SDL_WindowData *)focusWin->driverdata;
|
||||
WIN_OnWindowEnter(SDL_GetVideoDevice(), focusWin); /* make sure WM_MOUSELEAVE messages are (re)enabled. */
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* While we were thinking of SetCapture() when designing this API in SDL,
|
||||
we didn't count on the fact that SetCapture() only tracks while the
|
||||
left mouse button is held down! Instead, we listen for raw mouse input
|
||||
and manually query the mouse when it leaves the window. :/ */
|
||||
return ToggleRawInput(window != NULL);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -259,6 +287,11 @@ WIN_QuitMouse(_THIS)
|
|||
mouse->def_cursor = NULL;
|
||||
mouse->cur_cursor = NULL;
|
||||
}
|
||||
|
||||
if (rawInputEnableCount) { /* force RAWINPUT off here. */
|
||||
rawInputEnableCount = 1;
|
||||
ToggleRawInput(SDL_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_WINDOWS */
|
||||
|
|
Loading…
Reference in New Issue