Reverted change for bug 4152 - restrict the win10 mouse bug workaround to win10 v1709 only

Daniel Gibson

Sorry, but it seems like Microsoft didn't fix the issue properly.

I just updated my Win10 machine, it now is Version 1803, Build 17134.1

I tested with SDL2 2.0.7 (my workaround was released with 2.0.8) and still got
lots of events that directly undid the prior "real" events - just like before.
(See simple testcase in attachement)
By default it sets SDL_HINT_MOUSE_RELATIVE_MODE_WARP - which triggered (and on my machine still triggers) the buggy behavior. You can start it with -raw, then it'll not set that hint and the events will be as expected.
The easiest way to see the difference is looking at the window title, which shows accumulated X and Y values: If you just move your mouse to the right, in -raw mode the number just increases. In non-raw mode (using mouse warping) it stays around 0.

I also had a WinAPI-only testcase: https://gist.github.com/DanielGibson/b5b033c67b9137f0280af9fc53352c68
It just calls SetCursorPos(320,240); on each WM_MOUSEMOVE event, and it also
logs all those events to a mouseevents.log textfile.
This log indeed looks a bit different since the latest Win10 update: It seems like all those events with x=320 y=240 do arrive - but only after I stopped moving the mouse - even though the cursor seems to be moved back every frame (or so).
So moving the mouse to the right gives X coordinates like
330, 325, 333, 340, 330, ...
and then when stopping movement I get lots of events with X coordinate 320
This commit is contained in:
Sam Lantinga 2018-05-07 20:10:12 -07:00
parent eb14b635cd
commit a4d0571e4a
1 changed files with 55 additions and 0 deletions

View File

@ -359,6 +359,11 @@ 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);
} }
/* 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;
LRESULT CALLBACK LRESULT CALLBACK
WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ {
@ -481,6 +486,17 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
if (!mouse->relative_mode || mouse->relative_mode_warp) { if (!mouse->relative_mode || mouse->relative_mode_warp) {
SDL_MouseID mouseID = (((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) ? SDL_TOUCH_MOUSEID : 0); SDL_MouseID mouseID = (((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) ? SDL_TOUCH_MOUSEID : 0);
SDL_SendMouseMotion(data->window, mouseID, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); SDL_SendMouseMotion(data->window, mouseID, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
if (isWin10FCUorNewer && mouseID != SDL_TOUCH_MOUSEID && mouse->relative_mode_warp) {
/* To work around #3931, Win10 bug introduced in Fall Creators Update, where
SetCursorPos() (SDL_WarpMouseInWindow()) doesn't reliably generate mouse events anymore,
after each windows mouse event generate a fake event for the middle of the window
if relative_mode_warp is used */
int center_x = 0, center_y = 0;
SDL_GetWindowSize(data->window, &center_x, &center_y);
center_x /= 2;
center_y /= 2;
SDL_SendMouseMotion(data->window, mouseID, 0, center_x, center_y);
}
} }
} }
/* don't break here, fall through to check the wParam like the button presses */ /* don't break here, fall through to check the wParam like the button presses */
@ -1058,6 +1074,43 @@ WIN_PumpEvents(_THIS)
} }
} }
/* to work around #3931, a bug introduced in Win10 Fall Creators Update (build nr. 16299)
we need to detect the windows version. this struct and the function below does that.
usually this struct and the corresponding function (RtlGetVersion) are in <Ntddk.h>
but here we just load it dynamically */
struct SDL_WIN_OSVERSIONINFOW {
ULONG dwOSVersionInfoSize;
ULONG dwMajorVersion;
ULONG dwMinorVersion;
ULONG dwBuildNumber;
ULONG dwPlatformId;
WCHAR szCSDVersion[128];
};
static SDL_bool
IsWin10FCUorNewer(void)
{
HMODULE handle = GetModuleHandleW(L"ntdll.dll");
if (handle) {
typedef LONG(WINAPI* RtlGetVersionPtr)(struct SDL_WIN_OSVERSIONINFOW*);
RtlGetVersionPtr getVersionPtr = (RtlGetVersionPtr)GetProcAddress(handle, "RtlGetVersion");
if (getVersionPtr != NULL) {
struct SDL_WIN_OSVERSIONINFOW info;
SDL_zero(info);
info.dwOSVersionInfoSize = sizeof(info);
if (getVersionPtr(&info) == 0) { /* STATUS_SUCCESS == 0 */
if ( (info.dwMajorVersion == 10 && info.dwMinorVersion == 0 && info.dwBuildNumber >= 16299)
|| (info.dwMajorVersion == 10 && info.dwMinorVersion > 0)
|| (info.dwMajorVersion > 10) )
{
return SDL_TRUE;
}
}
}
}
return SDL_FALSE;
}
static int app_registered = 0; static int app_registered = 0;
LPTSTR SDL_Appname = NULL; LPTSTR SDL_Appname = NULL;
Uint32 SDL_Appstyle = 0; Uint32 SDL_Appstyle = 0;
@ -1122,6 +1175,8 @@ SDL_RegisterApp(char *name, Uint32 style, void *hInst)
return SDL_SetError("Couldn't register application class"); return SDL_SetError("Couldn't register application class");
} }
isWin10FCUorNewer = IsWin10FCUorNewer();
app_registered = 1; app_registered = 1;
return 0; return 0;
} }