From 40e529f39385a4d202eb5869caa916d2e4858e49 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Tue, 15 Apr 2025 21:17:06 -0400 Subject: [PATCH] Use a different workaround (time-based) for GLFW Mac bug where setting GLFW_CURSOR_DISABLED creates a large mouse delta in a few frames. --- src/window/Window.cpp | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/src/window/Window.cpp b/src/window/Window.cpp index d4eeca06..59497645 100644 --- a/src/window/Window.cpp +++ b/src/window/Window.cpp @@ -98,7 +98,7 @@ struct Window::Internal { int lastWindowHeight = 0; int frame = 0; - bool ignoreNextMouseDelta = false; + double ignoreMouseDeltaUntil = -INFINITY; double monitorRefreshRate = 0.0; double frameTime = NAN; double lastFrameDuration = NAN; @@ -167,28 +167,15 @@ static void cursorPosCallback(GLFWwindow* win, double xpos, double ypos) { math::Vec mousePos = math::Vec(xpos, ypos).div(APP->window->pixelRatio / APP->window->windowRatio).round(); math::Vec mouseDelta = mousePos.minus(APP->window->internal->lastMousePos); + // if (glfwGetInputMode(win, GLFW_CURSOR) != GLFW_CURSOR_NORMAL && std::fabs(mouseDelta.y) > 20.0) { + // DEBUG("%d (%f, %f) (%f, %f)", APP->window->internal->frame, VEC_ARGS(mousePos), VEC_ARGS(mouseDelta)); + // } + // Workaround for GLFW warping mouse to a different position when the cursor is locked or unlocked. - if (APP->window->internal->ignoreNextMouseDelta) { - APP->window->internal->ignoreNextMouseDelta = false; + if (APP->window->internal->ignoreMouseDeltaUntil > APP->window->internal->frameTime) { mouseDelta = math::Vec(); } - int cursorMode = glfwGetInputMode(win, GLFW_CURSOR); - (void) cursorMode; - -#if defined ARCH_MAC - // Workaround for Mac. We can't use GLFW_CURSOR_DISABLED because it's buggy, so implement it on our own. - // This is not an ideal implementation. For example, if the user drags off the screen, the new mouse position will be clamped. - if (cursorMode == GLFW_CURSOR_HIDDEN) { - // CGSetLocalEventsSuppressionInterval(0.0); - glfwSetCursorPos(win, APP->window->internal->lastMousePos.x, APP->window->internal->lastMousePos.y); - CGAssociateMouseAndMouseCursorPosition(true); - mousePos = APP->window->internal->lastMousePos; - } - // Because sometimes the cursor turns into an arrow when its position is on the boundary of the window - glfwSetCursor(win, NULL); -#endif - APP->window->internal->lastMousePos = mousePos; APP->event->handleHover(mousePos, mouseDelta); @@ -647,12 +634,14 @@ void Window::cursorLock() { if (!settings::allowCursorLock) return; -#if defined ARCH_MAC - glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); -#else glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + + // Due to a bug in GLFW, setting GLFW_CURSOR_DISABLED causes a spurious mouse position delta after a few frames. + // https://github.com/glfw/glfw/issues/2523 + // Emperically, this seems to be up to 3-6 frames at 60 Hz but in fewer frames at lower framerates. +#if defined ARCH_MAC + internal->ignoreMouseDeltaUntil = internal->frameTime + 0.09; #endif - internal->ignoreNextMouseDelta = true; } @@ -661,7 +650,6 @@ void Window::cursorUnlock() { return; glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - internal->ignoreNextMouseDelta = true; }