From 50eccd298a2bbc272b4977bd162d3e4b55f15394 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 17 Apr 2018 19:54:36 +0200 Subject: [PATCH] Fix cursor mode application for unfocused windows Fixes #1239. Fixes #1247. --- src/cocoa_window.m | 50 +++++++++-------- src/input.c | 4 +- src/win32_window.c | 130 +++++++++++++++++++++++++-------------------- src/x11_window.c | 110 ++++++++++++++++++++++---------------- 4 files changed, 165 insertions(+), 129 deletions(-) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index a54624cc..7cf4a593 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -128,6 +128,32 @@ static void updateCursorImage(_GLFWwindow* window) hideCursor(window); } +// Apply chosen cursor mode to a focused window +// +static void updateCursorMode(_GLFWwindow* window) +{ + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + _glfw.ns.disabledCursorWindow = window; + _glfwPlatformGetCursorPos(window, + &_glfw.ns.restoreCursorPosX, + &_glfw.ns.restoreCursorPosY); + centerCursor(window); + CGAssociateMouseAndMouseCursorPosition(false); + } + else if (_glfw.ns.disabledCursorWindow == window) + { + _glfw.ns.disabledCursorWindow = NULL; + CGAssociateMouseAndMouseCursorPosition(true); + _glfwPlatformSetCursorPos(window, + _glfw.ns.restoreCursorPosX, + _glfw.ns.restoreCursorPosY); + } + + if (cursorInClientArea(window)) + updateCursorImage(window); +} + // Transforms the specified y-coordinate between the CG display and NS screen // coordinate systems // @@ -321,7 +347,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; centerCursor(window); _glfwInputWindowFocus(window, GLFW_TRUE); - _glfwPlatformSetCursorMode(window, window->cursorMode); + updateCursorMode(window); } - (void)windowDidResignKey:(NSNotification *)notification @@ -1638,26 +1664,8 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { - if (mode == GLFW_CURSOR_DISABLED) - { - _glfw.ns.disabledCursorWindow = window; - _glfwPlatformGetCursorPos(window, - &_glfw.ns.restoreCursorPosX, - &_glfw.ns.restoreCursorPosY); - centerCursor(window); - CGAssociateMouseAndMouseCursorPosition(false); - } - else if (_glfw.ns.disabledCursorWindow == window) - { - _glfw.ns.disabledCursorWindow = NULL; - CGAssociateMouseAndMouseCursorPosition(true); - _glfwPlatformSetCursorPos(window, - _glfw.ns.restoreCursorPosX, - _glfw.ns.restoreCursorPosY); - } - - if (cursorInClientArea(window)) - updateCursorImage(window); + if (_glfwPlatformWindowFocused(window)) + updateCursorMode(window); } const char* _glfwPlatformGetScancodeName(int scancode) diff --git a/src/input.c b/src/input.c index c4f1e303..42975452 100644 --- a/src/input.c +++ b/src/input.c @@ -509,9 +509,7 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) _glfwPlatformGetCursorPos(window, &window->virtualCursorPosX, &window->virtualCursorPosY); - - if (_glfwPlatformWindowFocused(window)) - _glfwPlatformSetCursorMode(window, value); + _glfwPlatformSetCursorMode(window, value); } else if (mode == GLFW_STICKY_KEYS) { diff --git a/src/win32_window.c b/src/win32_window.c index 4506c8a7..d467f2ae 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -235,26 +235,6 @@ static void centerCursor(_GLFWwindow* window) _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); } -// Returns whether the cursor is in the client area of the specified window -// -static GLFWbool cursorInClientArea(_GLFWwindow* window) -{ - RECT area; - POINT pos; - - if (!GetCursorPos(&pos)) - return GLFW_FALSE; - - if (WindowFromPoint(pos) != window->win32.handle) - return GLFW_FALSE; - - GetClientRect(window->win32.handle, &area); - ClientToScreen(window->win32.handle, (POINT*) &area.left); - ClientToScreen(window->win32.handle, (POINT*) &area.right); - - return PtInRect(&area, pos); -} - // Updates the cursor image according to its cursor mode // static void updateCursorImage(_GLFWwindow* window) @@ -286,6 +266,67 @@ static void updateClipRect(_GLFWwindow* window) ClipCursor(NULL); } +// Apply disabled cursor mode to a focused window +// +static void disableCursor(_GLFWwindow* window) +{ + const RAWINPUTDEVICE rid = { 0x01, 0x02, 0, window->win32.handle }; + + _glfw.win32.disabledCursorWindow = window; + _glfwPlatformGetCursorPos(window, + &_glfw.win32.restoreCursorPosX, + &_glfw.win32.restoreCursorPosY); + updateCursorImage(window); + centerCursor(window); + updateClipRect(window); + + if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to register raw input device"); + } +} + +// Exit disabled cursor mode for the specified window +// +static void enableCursor(_GLFWwindow* window) +{ + const RAWINPUTDEVICE rid = { 0x01, 0x02, RIDEV_REMOVE, NULL }; + + _glfw.win32.disabledCursorWindow = NULL; + updateClipRect(NULL); + _glfwPlatformSetCursorPos(window, + _glfw.win32.restoreCursorPosX, + _glfw.win32.restoreCursorPosY); + updateCursorImage(window); + + if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to remove raw input device"); + } +} + +// Returns whether the cursor is in the client area of the specified window +// +static GLFWbool cursorInClientArea(_GLFWwindow* window) +{ + RECT area; + POINT pos; + + if (!GetCursorPos(&pos)) + return GLFW_FALSE; + + if (WindowFromPoint(pos) != window->win32.handle) + return GLFW_FALSE; + + GetClientRect(window->win32.handle, &area); + ClientToScreen(window->win32.handle, (POINT*) &area.left); + ClientToScreen(window->win32.handle, (POINT*) &area.right); + + return PtInRect(&area, pos); +} + // Update native window styles to match attributes // static void updateWindowStyles(const _GLFWwindow* window) @@ -575,7 +616,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, if (lParam == 0 && window->win32.frameAction) { if (window->cursorMode == GLFW_CURSOR_DISABLED) - _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); + disableCursor(window); window->win32.frameAction = GLFW_FALSE; } @@ -593,7 +634,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, break; if (window->cursorMode == GLFW_CURSOR_DISABLED) - _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); + disableCursor(window); return 0; } @@ -601,7 +642,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_KILLFOCUS: { if (window->cursorMode == GLFW_CURSOR_DISABLED) - _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); + enableCursor(window); if (window->monitor && window->autoIconify) _glfwPlatformIconifyWindow(window); @@ -857,10 +898,10 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_ENTERSIZEMOVE: case WM_ENTERMENULOOP: { - // HACK: Postpone cursor disabling while the user is moving or - // resizing the window or using the menu + // HACK: Enable the cursor while the user is moving or + // resizing the window or using the window menu if (window->cursorMode == GLFW_CURSOR_DISABLED) - _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); + enableCursor(window); break; } @@ -871,7 +912,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, // HACK: Disable the cursor once the user is done moving or // resizing the window or using the menu if (window->cursorMode == GLFW_CURSOR_DISABLED) - _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); + disableCursor(window); break; } @@ -1772,39 +1813,12 @@ 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"); - } + if (_glfwPlatformWindowFocused(window)) + disableCursor(window); } 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)) + enableCursor(window); + else if (cursorInClientArea(window)) updateCursorImage(window); } diff --git a/src/x11_window.c b/src/x11_window.c index f3014ec9..fc24f285 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -571,6 +571,61 @@ static void updateCursorImage(_GLFWwindow* window) } } +// Apply disabled cursor mode to a focused window +// +static void disableCursor(_GLFWwindow* window) +{ + if (_glfw.x11.xi.available) + { + XIEventMask em; + unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; + + em.deviceid = XIAllMasterDevices; + em.mask_len = sizeof(mask); + em.mask = mask; + XISetMask(mask, XI_RawMotion); + + XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1); + } + + _glfw.x11.disabledCursorWindow = window; + _glfwPlatformGetCursorPos(window, + &_glfw.x11.restoreCursorPosX, + &_glfw.x11.restoreCursorPosY); + updateCursorImage(window); + centerCursor(window); + XGrabPointer(_glfw.x11.display, window->x11.handle, True, + ButtonPressMask | ButtonReleaseMask | PointerMotionMask, + GrabModeAsync, GrabModeAsync, + window->x11.handle, + _glfw.x11.hiddenCursorHandle, + CurrentTime); +} + +// Exit disabled cursor mode for the specified window +// +static void enableCursor(_GLFWwindow* window) +{ + if (_glfw.x11.xi.available) + { + XIEventMask em; + unsigned char mask[] = { 0 }; + + em.deviceid = XIAllMasterDevices; + em.mask_len = sizeof(mask); + em.mask = mask; + + XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1); + } + + _glfw.x11.disabledCursorWindow = NULL; + XUngrabPointer(_glfw.x11.display, CurrentTime); + _glfwPlatformSetCursorPos(window, + _glfw.x11.restoreCursorPosX, + _glfw.x11.restoreCursorPosY); + updateCursorImage(window); +} + // Create the X11 window (and its colormap) // static GLFWbool createNativeWindow(_GLFWwindow* window, @@ -1432,7 +1487,7 @@ static void processEvent(XEvent *event) // HACK: This is a workaround for WMs (KWM, Fluxbox) that otherwise // ignore the defined cursor for hidden cursor mode if (window->cursorMode == GLFW_CURSOR_HIDDEN) - _glfwPlatformSetCursorMode(window, GLFW_CURSOR_HIDDEN); + updateCursorImage(window); _glfwInputCursorEnter(window, GLFW_TRUE); return; @@ -1725,7 +1780,7 @@ static void processEvent(XEvent *event) case FocusIn: { if (window->cursorMode == GLFW_CURSOR_DISABLED) - _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); + disableCursor(window); if (event->xfocus.mode == NotifyGrab || event->xfocus.mode == NotifyUngrab) @@ -1745,7 +1800,7 @@ static void processEvent(XEvent *event) case FocusOut: { if (window->cursorMode == GLFW_CURSOR_DISABLED) - _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); + enableCursor(window); if (event->xfocus.mode == NotifyGrab || event->xfocus.mode == NotifyUngrab) @@ -2708,53 +2763,14 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { if (mode == GLFW_CURSOR_DISABLED) { - if (_glfw.x11.xi.available) - { - XIEventMask em; - unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; - - em.deviceid = XIAllMasterDevices; - em.mask_len = sizeof(mask); - em.mask = mask; - XISetMask(mask, XI_RawMotion); - - XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1); - } - - _glfw.x11.disabledCursorWindow = window; - _glfwPlatformGetCursorPos(window, - &_glfw.x11.restoreCursorPosX, - &_glfw.x11.restoreCursorPosY); - centerCursor(window); - XGrabPointer(_glfw.x11.display, window->x11.handle, True, - ButtonPressMask | ButtonReleaseMask | PointerMotionMask, - GrabModeAsync, GrabModeAsync, - window->x11.handle, - _glfw.x11.hiddenCursorHandle, - CurrentTime); + if (_glfwPlatformWindowFocused(window)) + disableCursor(window); } else if (_glfw.x11.disabledCursorWindow == window) - { - if (_glfw.x11.xi.available) - { - XIEventMask em; - unsigned char mask[] = { 0 }; + enableCursor(window); + else + updateCursorImage(window); - em.deviceid = XIAllMasterDevices; - em.mask_len = sizeof(mask); - em.mask = mask; - - XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1); - } - - _glfw.x11.disabledCursorWindow = NULL; - XUngrabPointer(_glfw.x11.display, CurrentTime); - _glfwPlatformSetCursorPos(window, - _glfw.x11.restoreCursorPosX, - _glfw.x11.restoreCursorPosY); - } - - updateCursorImage(window); XFlush(_glfw.x11.display); }