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 ); }