Fixed bug 4704 - SDL_HINT_ANDROID_SEPERATE_MOUSE_AND_TOUCH on Windows?

superfury

I notice that, somehow, when locking the mouse into place(using SDL_SetRelativeMouseMode), somehow at least the movement information gets through to both mouse movement and touch movement events?

My app handles both, so when moving a touched finger accross the app(using RDP from an Android device) I see the mouse moving inside the app when it shouldn't(meaning that the touch movement is ignored properly by the app(press-location dependant) but the mouse movement is still performed due to the mouse movement events)?
This commit is contained in:
Sam Lantinga 2019-07-15 09:36:53 -07:00
parent 064d1223f0
commit e7c2cf107a
3 changed files with 64 additions and 10 deletions

View File

@ -156,6 +156,8 @@ SDL_MouseInit(void)
SDL_AddHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS, SDL_AddHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS,
SDL_MouseTouchEventsChanged, mouse); SDL_MouseTouchEventsChanged, mouse);
mouse->was_touch_mouse_events = SDL_FALSE; /* no touch to mouse movement event pending */
mouse->cursor_shown = SDL_TRUE; mouse->cursor_shown = SDL_TRUE;
return (0); return (0);
@ -244,7 +246,7 @@ SDL_SetMouseFocus(SDL_Window * window)
/* Check to see if we need to synthesize focus events */ /* Check to see if we need to synthesize focus events */
static SDL_bool static SDL_bool
SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate) SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate, SDL_bool send_mouse_motion)
{ {
SDL_Mouse *mouse = SDL_GetMouse(); SDL_Mouse *mouse = SDL_GetMouse();
SDL_bool inWindow = SDL_TRUE; SDL_bool inWindow = SDL_TRUE;
@ -275,7 +277,9 @@ SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate)
#ifdef DEBUG_MOUSE #ifdef DEBUG_MOUSE
printf("Mouse left window, synthesizing move & focus lost event\n"); printf("Mouse left window, synthesizing move & focus lost event\n");
#endif #endif
SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y); if (send_mouse_motion) {
SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
}
SDL_SetMouseFocus(NULL); SDL_SetMouseFocus(NULL);
} }
return SDL_FALSE; return SDL_FALSE;
@ -286,7 +290,9 @@ SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate)
printf("Mouse entered window, synthesizing focus gain & move event\n"); printf("Mouse entered window, synthesizing focus gain & move event\n");
#endif #endif
SDL_SetMouseFocus(window); SDL_SetMouseFocus(window);
SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y); if (send_mouse_motion) {
SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
}
} }
return SDL_TRUE; return SDL_TRUE;
} }
@ -296,7 +302,7 @@ SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int
{ {
if (window && !relative) { if (window && !relative) {
SDL_Mouse *mouse = SDL_GetMouse(); SDL_Mouse *mouse = SDL_GetMouse();
if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate)) { if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate, (mouseID == SDL_TOUCH_MOUSEID) ? SDL_FALSE : SDL_TRUE)) {
return 0; return 0;
} }
} }
@ -446,6 +452,8 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ
event.motion.type = SDL_MOUSEMOTION; event.motion.type = SDL_MOUSEMOTION;
event.motion.windowID = mouse->focus ? mouse->focus->id : 0; event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
event.motion.which = mouseID; event.motion.which = mouseID;
/* Set us pending (or clear during a normal mouse movement event) as having triggered */
mouse->was_touch_mouse_events = (mouseID == SDL_TOUCH_MOUSEID)? SDL_TRUE : SDL_FALSE;
event.motion.state = mouse->buttonstate; event.motion.state = mouse->buttonstate;
event.motion.x = mouse->x; event.motion.x = mouse->x;
event.motion.y = mouse->y; event.motion.y = mouse->y;
@ -530,7 +538,7 @@ SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state
/* We do this after calculating buttonstate so button presses gain focus */ /* We do this after calculating buttonstate so button presses gain focus */
if (window && state == SDL_PRESSED) { if (window && state == SDL_PRESSED) {
SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate); SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate, SDL_TRUE);
} }
if (buttonstate == mouse->buttonstate) { if (buttonstate == mouse->buttonstate) {
@ -580,7 +588,7 @@ SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state
/* We do this after dispatching event so button releases can lose focus */ /* We do this after dispatching event so button releases can lose focus */
if (window && state == SDL_RELEASED) { if (window && state == SDL_RELEASED) {
SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate); SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate, SDL_TRUE);
} }
return posted; return posted;

View File

@ -94,6 +94,7 @@ typedef struct
int double_click_radius; int double_click_radius;
SDL_bool touch_mouse_events; SDL_bool touch_mouse_events;
SDL_bool mouse_touch_events; SDL_bool mouse_touch_events;
SDL_bool was_touch_mouse_events; /* Was a touch-mouse event pending? */
/* Data for double-click tracking */ /* Data for double-click tracking */
int num_clickstates; int num_clickstates;

View File

@ -359,14 +359,32 @@ ShouldGenerateWindowCloseOnAltF4(void)
return !SDL_GetHintBoolean(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, SDL_FALSE); return !SDL_GetHintBoolean(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, SDL_FALSE);
} }
static SDL_bool isVistaOrNewer = SDL_FALSE;
/* Win10 "Fall Creators Update" introduced the bug that SetCursorPos() (as used by SDL_WarpMouseInWindow()) /* Win10 "Fall Creators Update" introduced the bug that SetCursorPos() (as used by SDL_WarpMouseInWindow())
doesn't reliably generate WM_MOUSEMOVE events anymore (see #3931) which breaks relative mouse mode via warping. doesn't reliably generate WM_MOUSEMOVE events anymore (see #3931) which breaks relative mouse mode via warping.
This is used to implement a workaround.. */ This is used to implement a workaround.. */
static SDL_bool isWin10FCUorNewer = SDL_FALSE; static SDL_bool isWin10FCUorNewer = SDL_FALSE;
/* Checks a mouse or raw packet for touch indication.
returns: 0 for not touch input, 1 for touch input.
*/
static LPARAM
GetMessageExtraInfoAndCheckMousePacketTouch(int *checkTouch) {
LPARAM extrainfo = GetMessageExtraInfo();
/* Mouse data (ignoring synthetic mouse events generated for touchscreens) */
/* Versions below Vista will set the low 7 bits to the Mouse ID and don't use bit 7:
Check bits 8-32 for the signature (which will indicate a Tablet PC Pen or Touch Device).
Only check bit 7 when Vista and up(Cleared=Pen, Set=Touch(which we need to filter out)),
when the signature is set. The Mouse ID will be zero for an actual mouse. */
*checkTouch = (!(((extrainfo & 0x7F) && (isVistaOrNewer ? (extrainfo & 0x80) : 1)) || ((extrainfo & 0xFFFFFF00) == 0xFF515700)));
return extrainfo;
}
LRESULT CALLBACK LRESULT CALLBACK
WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ {
int checkTouch = -1; /* Default to -1 for not yet loaded */
LPARAM extrainfo; /* The extra info when checkTouch >= 0. */
SDL_WindowData *data; SDL_WindowData *data;
LRESULT returnCode = -1; LRESULT returnCode = -1;
@ -494,9 +512,10 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_MOUSEMOVE: case WM_MOUSEMOVE:
{ {
SDL_Mouse *mouse = SDL_GetMouse(); SDL_Mouse *mouse = SDL_GetMouse();
extrainfo = GetMessageExtraInfoAndCheckMousePacketTouch(&checkTouch); /* load */
if (!mouse->relative_mode || mouse->relative_mode_warp) { if (!mouse->relative_mode || mouse->relative_mode_warp) {
/* Only generate mouse events for real mouse */ /* Only generate mouse events for real mouse */
if ((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) != MOUSEEVENTF_FROMTOUCH) { if (((extrainfo & MOUSEEVENTF_FROMTOUCH) != MOUSEEVENTF_FROMTOUCH) && checkTouch) {
SDL_SendMouseMotion(data->window, 0, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); SDL_SendMouseMotion(data->window, 0, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
if (isWin10FCUorNewer && mouse->relative_mode_warp) { if (isWin10FCUorNewer && mouse->relative_mode_warp) {
/* To work around #3931, Win10 bug introduced in Fall Creators Update, where /* To work around #3931, Win10 bug introduced in Fall Creators Update, where
@ -527,8 +546,11 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_XBUTTONDBLCLK: case WM_XBUTTONDBLCLK:
{ {
SDL_Mouse *mouse = SDL_GetMouse(); SDL_Mouse *mouse = SDL_GetMouse();
if (checkTouch < 0) {
extrainfo = GetMessageExtraInfoAndCheckMousePacketTouch(&checkTouch);
}
if (!mouse->relative_mode || mouse->relative_mode_warp) { if (!mouse->relative_mode || mouse->relative_mode_warp) {
if ((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) != MOUSEEVENTF_FROMTOUCH) { if (((extrainfo & MOUSEEVENTF_FROMTOUCH) != MOUSEEVENTF_FROMTOUCH) && checkTouch) {
WIN_CheckWParamMouseButtons(wParam, data, 0); WIN_CheckWParamMouseButtons(wParam, data, 0);
} }
} }
@ -553,7 +575,10 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER)); GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
/* Mouse data (ignoring synthetic mouse events generated for touchscreens) */ /* Mouse data (ignoring synthetic mouse events generated for touchscreens) */
if (inp.header.dwType == RIM_TYPEMOUSE && (GetMessageExtraInfo() & 0x80) == 0) { if (inp.header.dwType == RIM_TYPEMOUSE) {
extrainfo = GetMessageExtraInfoAndCheckMousePacketTouch(&checkTouch);
if (!checkTouch)
break;
if (isRelative) { if (isRelative) {
RAWMOUSE* rawmouse = &inp.data.mouse; RAWMOUSE* rawmouse = &inp.data.mouse;
@ -616,10 +641,21 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_MOUSELEAVE: case WM_MOUSELEAVE:
if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode && !(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) { if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode && !(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
if (!IsIconic(hwnd)) { if (!IsIconic(hwnd)) {
SDL_Mouse *mouse;
POINT cursorPos; POINT cursorPos;
GetCursorPos(&cursorPos); GetCursorPos(&cursorPos);
ScreenToClient(hwnd, &cursorPos); ScreenToClient(hwnd, &cursorPos);
SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y); mouse = SDL_GetMouse();
if (!mouse->was_touch_mouse_events) { /* we're not a touch handler causing a mouse leave? */
SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y);
} else { /* touch handling? */
mouse->was_touch_mouse_events = SDL_FALSE; /* not anymore */
if (mouse->touch_mouse_events) { /* convert touch to mouse events */
SDL_SendMouseMotion(data->window, SDL_TOUCH_MOUSEID, 0, cursorPos.x, cursorPos.y);
} else { /* normal handling */
SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y);
}
}
} }
SDL_SetMouseFocus(NULL); SDL_SetMouseFocus(NULL);
} }
@ -1124,6 +1160,14 @@ struct SDL_WIN_OSVERSIONINFOW {
WCHAR szCSDVersion[128]; WCHAR szCSDVersion[128];
}; };
static SDL_bool
IsWinVistaOrNewer(void)
{
DWORD version = GetVersion();
DWORD major = (DWORD)(LOBYTE(LOWORD(version)));
return (major >= 6)? SDL_TRUE : SDL_FALSE;
}
static SDL_bool static SDL_bool
IsWin10FCUorNewer(void) IsWin10FCUorNewer(void)
{ {
@ -1212,6 +1256,7 @@ SDL_RegisterApp(char *name, Uint32 style, void *hInst)
return SDL_SetError("Couldn't register application class"); return SDL_SetError("Couldn't register application class");
} }
isVistaOrNewer = IsWinVistaOrNewer();
isWin10FCUorNewer = IsWin10FCUorNewer(); isWin10FCUorNewer = IsWin10FCUorNewer();
app_registered = 1; app_registered = 1;