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)?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c
index 0ecb3cc..98b7298 100644
--- a/src/events/SDL_mouse.c
+++ b/src/events/SDL_mouse.c
@@ -156,6 +156,8 @@ SDL_MouseInit(void)
SDL_AddHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS,
SDL_MouseTouchEventsChanged, mouse);
+ mouse->was_touch_mouse_events = SDL_FALSE; /* no touch to mouse movement event pending */
+
mouse->cursor_shown = SDL_TRUE;
return (0);
@@ -244,7 +246,7 @@ SDL_SetMouseFocus(SDL_Window * window)
/* Check to see if we need to synthesize focus events */
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_bool inWindow = SDL_TRUE;
@@ -275,7 +277,9 @@ SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate)
#ifdef DEBUG_MOUSE
printf("Mouse left window, synthesizing move & focus lost event\n");
#endif
- SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
+ if (send_mouse_motion) {
+ SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
+ }
SDL_SetMouseFocus(NULL);
}
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");
#endif
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;
}
@@ -296,7 +302,7 @@ SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int
{
if (window && !relative) {
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;
}
}
@@ -446,6 +452,8 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ
event.motion.type = SDL_MOUSEMOTION;
event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
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.x = mouse->x;
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 */
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) {
@@ -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 */
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;
diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h
index 9f88d40..b44d40d 100644
--- a/src/events/SDL_mouse_c.h
+++ b/src/events/SDL_mouse_c.h
@@ -94,6 +94,7 @@ typedef struct
int double_click_radius;
SDL_bool touch_mouse_events;
SDL_bool mouse_touch_events;
+ SDL_bool was_touch_mouse_events; /* Was a touch-mouse event pending? */
/* Data for double-click tracking */
int num_clickstates;
diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index 2c9401b..9e95e33 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -359,14 +359,32 @@ ShouldGenerateWindowCloseOnAltF4(void)
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())
doesn't reliably generate WM_MOUSEMOVE events anymore (see #3931) which breaks relative mouse mode via warping.
This is used to implement a workaround.. */
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
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;
LRESULT returnCode = -1;
@@ -494,9 +512,10 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_MOUSEMOVE:
{
SDL_Mouse *mouse = SDL_GetMouse();
+ extrainfo = GetMessageExtraInfoAndCheckMousePacketTouch(&checkTouch); /* load */
if (!mouse->relative_mode || mouse->relative_mode_warp) {
/* 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));
if (isWin10FCUorNewer && mouse->relative_mode_warp) {
/* 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:
{
SDL_Mouse *mouse = SDL_GetMouse();
+ if (checkTouch < 0) {
+ extrainfo = GetMessageExtraInfoAndCheckMousePacketTouch(&checkTouch);
+ }
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);
}
}
@@ -553,7 +575,10 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
/* 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) {
RAWMOUSE* rawmouse = &inp.data.mouse;
@@ -616,10 +641,21 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_MOUSELEAVE:
if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode && !(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
if (!IsIconic(hwnd)) {
+ SDL_Mouse *mouse;
POINT cursorPos;
GetCursorPos(&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);
}
@@ -1125,6 +1161,14 @@ struct SDL_WIN_OSVERSIONINFOW {
};
static SDL_bool
+IsWinVistaOrNewer(void)
+{
+ DWORD version = GetVersion();
+ DWORD major = (DWORD)(LOBYTE(LOWORD(version)));
+ return (major >= 6)? SDL_TRUE : SDL_FALSE;
+}
+
+static SDL_bool
IsWin10FCUorNewer(void)
{
HMODULE handle = GetModuleHandleW(L"ntdll.dll");
@@ -1212,6 +1256,7 @@ SDL_RegisterApp(char *name, Uint32 style, void *hInst)
return SDL_SetError("Couldn't register application class");
}
+ isVistaOrNewer = IsWinVistaOrNewer();
isWin10FCUorNewer = IsWin10FCUorNewer();
app_registered = 1;