From f8841b82640d7bae9edd10ebe3f5df8475d4e00f Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Thu, 16 Apr 2020 11:14:56 -0600 Subject: [PATCH] Add workaround for mouse handling bug in Win10 FCU (cherry picked from commit d15e58f3da33c77d015f1af248354b01ca237362) Author: Adam Johnson Date: Sun Mar 25 21:08:57 2018 -0400 Add workaround for mouse handling bug in Win10 FCU Windows 10 Fall Creators Update changed the behavior of SetCursorPos, which no longer sends the expected WM_MOUSEMOVE message when recentering the cursor. This adds a function to detect affected versions of Windows and flags the necessity to manually send our own message. This workaround currently only detects the known affected version of Win10, in the hope that it will be fixed and no further attention will be required. If this regression is not fixed, additional Win10 versions can be added. --- .../Sources/Plasma/CoreLib/hsUtils.cpp | 28 ++++++++++++ .../Sources/Plasma/CoreLib/hsWindows.h | 3 ++ .../PubUtilLib/plInputCore/plInputManager.cpp | 44 ++++++++++++++++++- 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/CoreLib/hsUtils.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/CoreLib/hsUtils.cpp index 3384a854..3dd0830f 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/CoreLib/hsUtils.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/CoreLib/hsUtils.cpp @@ -766,3 +766,31 @@ char** DisplaySystemVersion() return nil; #endif } + +#ifdef HS_BUILD_FOR_WIN32 +static RTL_OSVERSIONINFOW s_WinVer; + +const RTL_OSVERSIONINFOW& hsGetWindowsVersion() +{ + static bool done = false; + if (!done) { + memset(&s_WinVer, 0, sizeof(RTL_OSVERSIONINFOW)); + HMODULE ntdll = LoadLibraryW(L"ntdll.dll"); + hsAssert(ntdll, "Failed to LoadLibrary on ntdll???"); + + if (ntdll) { + s_WinVer.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW); + typedef LONG(WINAPI* RtlGetVersionPtr)(RTL_OSVERSIONINFOW*); + RtlGetVersionPtr getVersion = (RtlGetVersionPtr)GetProcAddress(ntdll, "RtlGetVersion"); + hsAssert(getVersion, "Could not find RtlGetVersion in ntdll"); + if (getVersion) { + getVersion(&s_WinVer); + done = true; + } + } + FreeLibrary(ntdll); + } + return s_WinVer; +} +#endif + diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/CoreLib/hsWindows.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/CoreLib/hsWindows.h index d8c34c6a..dec1a5b6 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/CoreLib/hsWindows.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/CoreLib/hsWindows.h @@ -55,4 +55,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include #endif // __AFX_H__ + + const RTL_OSVERSIONINFOW& hsGetWindowsVersion(); + #endif // HS_BUILD_FOR_WIN32 diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plInputCore/plInputManager.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plInputCore/plInputManager.cpp index a6ce26d2..e15ec590 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plInputCore/plInputManager.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plInputCore/plInputManager.cpp @@ -262,7 +262,25 @@ plKeyDef plInputManager::UntranslateKey(plKeyDef key, hsBool extended) return key; } - +#if HS_BUILD_FOR_WIN32 +/** Determines if we need to hackily flush cursor updates + * \remarks Normally, we would just call SetCursorPos directly. However, in Windows 10's + * 2017 Fall Creator's Update, SetCursorPos, GetCursorPos, and WM_MOUSEMOVE are buggy. + * Research done by Deledrius matches my independent observations and failed fixes: + * https://discourse.libsdl.org/t/win10-fall-creators-update-breaks-mouse-warping/23526 + * Many thanks to these fine folks who work on libsdl! + */ +static bool INeedsWin10CursorHack() +{ + // According to Chromium, Microsoft will be fixing the cursor bug in the next build + // of Windows 10, so we only need to test for the dreaded 2017 FCU... + // Reference: https://bugs.chromium.org/p/chromium/issues/detail?id=781182#c15 + const RTL_OSVERSIONINFOW& version = hsGetWindowsVersion(); + return version.dwMajorVersion == 10 && version.dwBuildNumber == 16299; +} + +#endif // HS_BUILD_FOR_WIN32 + void plInputManager::HandleWin32ControlEvent(UINT message, WPARAM Wparam, LPARAM Lparam, HWND hWnd) { if( !fhWnd ) @@ -378,6 +396,12 @@ void plInputManager::HandleWin32ControlEvent(UINT message, WPARAM Wparam, LPARAM { pt.x = (rect.right - rect.left) / 2; pt.y = HIWORD(Lparam); + if (INeedsWin10CursorHack()) { + pXMsg->fWx = pt.x; + pXMsg->fX = pt.x / (float)rect.right; + for (int i = 0; i < fInputDevices.Count(); i++) + fInputDevices[i]->MsgReceive(pXMsg); + } ClientToScreen(hWnd, &pt); SetCursorPos( pt.x, pt.y ); } @@ -386,6 +410,13 @@ void plInputManager::HandleWin32ControlEvent(UINT message, WPARAM Wparam, LPARAM { pt.y = (rect.bottom - rect.top) / 2; pt.x = LOWORD(Lparam); + if (INeedsWin10CursorHack()) { + pYMsg->fWy = pt.y; + pYMsg->fY = pYMsg->fWy / (float)rect.bottom; + for (int i = 0; i < fInputDevices.Count(); i++) + fInputDevices[i]->MsgReceive(pYMsg); + } + ClientToScreen(hWnd, &pt); SetCursorPos( pt.x, pt.y ); } @@ -393,6 +424,17 @@ void plInputManager::HandleWin32ControlEvent(UINT message, WPARAM Wparam, LPARAM { pt.y = (rect.bottom - rect.top) / 2; pt.x = (rect.right - rect.left) / 2; + if (INeedsWin10CursorHack()) { + pXMsg->fWx = pt.x; + pXMsg->fX = pXMsg->fWx / (float)rect.right; + pYMsg->fWy = pt.y; + pYMsg->fY = pYMsg->fWy / (float)rect.bottom; + + for (int i = 0; i < fInputDevices.Count(); i++) { + fInputDevices[i]->MsgReceive(pXMsg); + fInputDevices[i]->MsgReceive(pYMsg); + } + } ClientToScreen(hWnd, &pt); SetCursorPos( pt.x, pt.y ); }