diff --git a/README.md b/README.md index 95b5493a..1a6a5644 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,7 @@ information on what to include when reporting a bug. - Bugfix: Invalid library paths were used in test and example CMake files (#930) - Bugfix: The scancode for synthetic key release events was always zero - [Win32] Added system error strings to relevant GLFW error descriptions (#733) +- [Win32] Moved to `WM_INPUT` for disabled cursor mode motion input (#125) - [Win32] Bugfix: Undecorated windows could not be iconified by the user (#861) - [Win32] Bugfix: Deadzone logic could underflow with some controllers (#910) - [Win32] Bugfix: Bitness test in `FindVulkan.cmake` was VS specific (#928) diff --git a/docs/news.dox b/docs/news.dox index 911c2954..f775f6a4 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -32,6 +32,12 @@ full screen windows with the [GLFW_CENTER_CURSOR](@ref GLFW_CENTER_CURSOR_hint) window hint. +@subsection news_33_rawmotion Support for raw mouse motion + +GLFW now supports raw mouse motion in disabled cursor mode on platforms where +this is available. + + @subsection news_33_moltenvk Support for Vulkan on macOS via MoltenVK GLFW now supports the `VK_MVK_macos_surface` window surface creation extension diff --git a/src/win32_init.c b/src/win32_init.c index c9978c24..b092d1c7 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -483,6 +483,7 @@ void _glfwPlatformTerminate(void) SPIF_SENDCHANGE); free(_glfw.win32.clipboardString); + free(_glfw.win32.rawInput); _glfwTerminateWGL(); _glfwTerminateEGL(); diff --git a/src/win32_platform.h b/src/win32_platform.h index 8b2af43f..cf01eb69 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -257,6 +257,8 @@ typedef struct _GLFWlibraryWin32 double restoreCursorPosX, restoreCursorPosY; // The window whose disabled cursor mode is active _GLFWwindow* disabledCursorWindow; + RAWINPUT* rawInput; + int rawInputSize; struct { HINSTANCE instance; diff --git a/src/win32_window.c b/src/win32_window.c index c54cf02d..d3bf2934 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -666,20 +666,11 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, const int x = GET_X_LPARAM(lParam); const int y = GET_Y_LPARAM(lParam); + // Disabled cursor motion input is provided by WM_INPUT if (window->cursorMode == GLFW_CURSOR_DISABLED) - { - const int dx = x - window->win32.lastCursorPosX; - const int dy = y - window->win32.lastCursorPosY; + break; - if (_glfw.win32.disabledCursorWindow != window) - break; - - _glfwInputCursorPos(window, - window->virtualCursorPosX + dx, - window->virtualCursorPosY + dy); - } - else - _glfwInputCursorPos(window, x, y); + _glfwInputCursorPos(window, x, y); window->win32.lastCursorPosX = x; window->win32.lastCursorPosY = y; @@ -700,6 +691,56 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, return 0; } + case WM_INPUT: + { + UINT size; + HRAWINPUT ri = (HRAWINPUT) lParam; + RAWINPUT* data; + int dx, dy; + + // Only process input when disabled cursor mode is applied + if (_glfw.win32.disabledCursorWindow != window) + break; + + GetRawInputData(ri, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); + if (size > _glfw.win32.rawInputSize) + { + free(_glfw.win32.rawInput); + _glfw.win32.rawInput = calloc(size, 1); + _glfw.win32.rawInputSize = size; + } + + size = _glfw.win32.rawInputSize; + if (GetRawInputData(ri, RID_INPUT, + _glfw.win32.rawInput, &size, + sizeof(RAWINPUTHEADER)) == (UINT) -1) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to retrieve raw input data"); + break; + } + + data = _glfw.win32.rawInput; + if (data->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) + { + dx = data->data.mouse.lLastX - window->win32.lastCursorPosX; + dy = data->data.mouse.lLastY - window->win32.lastCursorPosY; + } + else + { + dx = data->data.mouse.lLastX; + dy = data->data.mouse.lLastY; + } + + _glfwInputCursorPos(window, + window->virtualCursorPosX + dx, + window->virtualCursorPosY + dy); + + window->win32.lastCursorPosX += dx; + window->win32.lastCursorPosY += dy; + break; + } + case WM_MOUSELEAVE: { window->win32.cursorTracked = GLFW_FALSE; @@ -1527,20 +1568,36 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { if (mode == GLFW_CURSOR_DISABLED) { + const RAWINPUTDEVICE rid = { 0x01, 0x02, 0, window->win32.handle }; + _glfw.win32.disabledCursorWindow = window; _glfwPlatformGetCursorPos(window, &_glfw.win32.restoreCursorPosX, &_glfw.win32.restoreCursorPosY); centerCursor(window); updateClipRect(window); + + if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to register raw input device"); + } } else if (_glfw.win32.disabledCursorWindow == window) { + const RAWINPUTDEVICE rid = { 0x01, 0x02, RIDEV_REMOVE, NULL }; + _glfw.win32.disabledCursorWindow = NULL; updateClipRect(NULL); _glfwPlatformSetCursorPos(window, _glfw.win32.restoreCursorPosX, _glfw.win32.restoreCursorPosY); + + if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to remove raw input device"); + } } if (cursorInClientArea(window))