From 797ee8d8e347061b1bdb79fa33c2ca39e21145e1 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 25 May 2016 14:06:02 +0200 Subject: [PATCH] Move all cursor positioning to platform code Due to Wayland, shared code cannot rely on cursor positioning being supported by the underlying platform. This implicitly fixes #617 as it moves cursor centering into _glfwPlatformSetCursorMode, thus separating it from the stale value of _glfw.cursorWindow. Fixes #617. --- src/cocoa_platform.h | 2 + src/cocoa_window.m | 63 +++++++++++------ src/input.c | 63 +++++------------ src/internal.h | 5 +- src/mir_window.c | 3 +- src/win32_platform.h | 2 + src/win32_window.c | 159 +++++++++++++++++++++++++------------------ src/window.c | 14 +--- src/wl_init.c | 6 +- src/wl_window.c | 6 +- src/x11_platform.h | 4 +- src/x11_window.c | 60 +++++++++------- 12 files changed, 205 insertions(+), 182 deletions(-) diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index 1355758a..d6fbffe3 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -99,6 +99,8 @@ typedef struct _GLFWlibraryNS short int publicKeys[256]; short int nativeKeys[GLFW_KEY_LAST + 1]; char* clipboardString; + // Where to place the cursor when re-enabled + double restoreCursorPosX, restoreCursorPosY; struct { CFBundleRef bundle; diff --git a/src/cocoa_window.m b/src/cocoa_window.m index cd7fd871..76c17a2d 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -85,6 +85,21 @@ static void centerCursor(_GLFWwindow *window) _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); } +// Updates the cursor image according to the specified cursor mode +// +static void updateCursorImage(_GLFWwindow* window, int mode) +{ + if (mode == GLFW_CURSOR_NORMAL) + { + if (window->cursor) + [(NSCursor*) window->cursor->ns.object set]; + else + [[NSCursor arrowCursor] set]; + } + else + [(NSCursor*) _glfw.ns.cursor set]; +} + // Transforms the specified y-coordinate between the CG display and NS screen // coordinate systems // @@ -394,7 +409,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)cursorUpdate:(NSEvent *)event { - _glfwPlatformSetCursorMode(window, window->cursorMode); + updateCursorImage(window, window->cursorMode); } - (void)mouseDown:(NSEvent *)event @@ -422,16 +437,19 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; { if (window->cursorMode == GLFW_CURSOR_DISABLED) { - _glfwInputCursorMotion(window, - [event deltaX] - window->ns.cursorWarpDeltaX, - [event deltaY] - window->ns.cursorWarpDeltaY); + const double dx = [event deltaX] - window->ns.cursorWarpDeltaX; + const double dy = [event deltaY] - window->ns.cursorWarpDeltaY; + + _glfwInputCursorPos(window, + window->virtualCursorPosX + dx, + window->virtualCursorPosY + dy); } else { const NSRect contentRect = [window->ns.view frame]; const NSPoint pos = [event locationInWindow]; - _glfwInputCursorMotion(window, pos.x, contentRect.size.height - pos.y); + _glfwInputCursorPos(window, pos.x, contentRect.size.height - pos.y); } window->ns.cursorWarpDeltaX = 0; @@ -607,9 +625,9 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; NSArray* files = [pasteboard propertyListForType:NSFilenamesPboardType]; const NSRect contentRect = [window->ns.view frame]; - _glfwInputCursorMotion(window, - [sender draggingLocation].x, - contentRect.size.height - [sender draggingLocation].y); + _glfwInputCursorPos(window, + [sender draggingLocation].x, + contentRect.size.height - [sender draggingLocation].y); const int count = [files count]; if (count) @@ -1033,6 +1051,8 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, _glfwPlatformFocusWindow(window); if (!acquireMonitor(window)) return GLFW_FALSE; + + centerCursor(window); } return GLFW_TRUE; @@ -1397,7 +1417,7 @@ void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) { - _glfwPlatformSetCursorMode(window, window->cursorMode); + updateCursorImage(window, window->cursorMode); const NSRect contentRect = [window->ns.view frame]; const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream]; @@ -1423,20 +1443,23 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { - if (mode == GLFW_CURSOR_NORMAL) - { - if (window->cursor) - [(NSCursor*) window->cursor->ns.object set]; - else - [[NSCursor arrowCursor] set]; - } - else - [(NSCursor*) _glfw.ns.cursor set]; - if (mode == GLFW_CURSOR_DISABLED) + { + _glfwPlatformGetCursorPos(window, + &_glfw.ns.restoreCursorPosX, + &_glfw.ns.restoreCursorPosY); + centerCursor(window); CGAssociateMouseAndMouseCursorPosition(false); - else + } + else if (window->cursorMode == GLFW_CURSOR_DISABLED) + { CGAssociateMouseAndMouseCursorPosition(true); + _glfwPlatformSetCursorPos(window, + _glfw.ns.restoreCursorPosX, + _glfw.ns.restoreCursorPosY); + } + + updateCursorImage(window, mode); } const char* _glfwPlatformGetKeyName(int key, int scancode) diff --git a/src/input.c b/src/input.c index 8f7148a5..7109ee26 100644 --- a/src/input.c +++ b/src/input.c @@ -37,48 +37,27 @@ // Sets the cursor mode for the specified window // -static void setCursorMode(_GLFWwindow* window, int newMode) +static void setCursorMode(_GLFWwindow* window, int mode) { - const int oldMode = window->cursorMode; - - if (newMode != GLFW_CURSOR_NORMAL && - newMode != GLFW_CURSOR_HIDDEN && - newMode != GLFW_CURSOR_DISABLED) + if (mode != GLFW_CURSOR_NORMAL && + mode != GLFW_CURSOR_HIDDEN && + mode != GLFW_CURSOR_DISABLED) { - _glfwInputError(GLFW_INVALID_ENUM, "Invalid cursor mode %i", newMode); + _glfwInputError(GLFW_INVALID_ENUM, "Invalid cursor mode %i", mode); return; } - if (oldMode == newMode) + if (window->cursorMode == mode) return; - window->cursorMode = newMode; + _glfwPlatformGetCursorPos(window, + &window->virtualCursorPosX, + &window->virtualCursorPosY); if (_glfw.cursorWindow == window) - { - if (oldMode == GLFW_CURSOR_DISABLED) - { - _glfwPlatformSetCursorPos(window, - _glfw.restoreCursorPosX, - _glfw.restoreCursorPosY); - } - else if (newMode == GLFW_CURSOR_DISABLED) - { - int width, height; + _glfwPlatformSetCursorMode(window, mode); - _glfwPlatformGetCursorPos(window, - &_glfw.restoreCursorPosX, - &_glfw.restoreCursorPosY); - - window->virtualCursorPosX = _glfw.restoreCursorPosX; - window->virtualCursorPosY = _glfw.restoreCursorPosY; - - _glfwPlatformGetWindowSize(window, &width, &height); - _glfwPlatformSetCursorPos(window, width / 2, height / 2); - } - - _glfwPlatformSetCursorMode(window, window->cursorMode); - } + window->cursorMode = mode; } // Set sticky keys mode for the specified window @@ -191,19 +170,13 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods); } -void _glfwInputCursorMotion(_GLFWwindow* window, double x, double y) +void _glfwInputCursorPos(_GLFWwindow* window, double x, double y) { - if (window->cursorMode == GLFW_CURSOR_DISABLED) - { - if (x == 0.0 && y == 0.0) - return; + if (window->virtualCursorPosX == x && window->virtualCursorPosY == y) + return; - window->virtualCursorPosX += x; - window->virtualCursorPosY += y; - - x = window->virtualCursorPosX; - y = window->virtualCursorPosY; - } + window->virtualCursorPosX = x; + window->virtualCursorPosY = y; if (window->callbacks.cursorPos) window->callbacks.cursorPos((GLFWwindow*) window, x, y); @@ -490,9 +463,9 @@ GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle) _GLFW_REQUIRE_INIT(); - _glfwPlatformSetCursor(window, cursor); - window->cursor = cursor; + + _glfwPlatformSetCursor(window, cursor); } GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun) diff --git a/src/internal.h b/src/internal.h index 01c34957..32418649 100644 --- a/src/internal.h +++ b/src/internal.h @@ -437,9 +437,6 @@ struct _GLFWlibrary int refreshRate; } hints; - // Where to place the cursor when re-enabled - double restoreCursorPosX, restoreCursorPosY; - _GLFWcursor* cursorListHead; _GLFWwindow* windowListHead; @@ -906,7 +903,7 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) * of the client area of the window. * @ingroup event */ -void _glfwInputCursorMotion(_GLFWwindow* window, double x, double y); +void _glfwInputCursorPos(_GLFWwindow* window, double x, double y); /*! @brief Notifies shared code of a cursor enter/leave event. * @param[in] window The window that received the event. diff --git a/src/mir_window.c b/src/mir_window.c index b303d331..57b13865 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -208,8 +208,7 @@ static void handlePointerMotion(_GLFWwindow* window, int dx = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll); int dy = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll); - if (current_x != x || current_y != y) - _glfwInputCursorMotion(window, x, y); + _glfwInputCursorPos(window, x, y); if (dx != 0 || dy != 0) _glfwInputScroll(window, dx, dy); } diff --git a/src/win32_platform.h b/src/win32_platform.h index 59a1dcc1..30549dfb 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -252,6 +252,8 @@ typedef struct _GLFWlibraryWin32 char keyName[64]; short int publicKeys[512]; short int nativeKeys[GLFW_KEY_LAST + 1]; + // Where to place the cursor when re-enabled + double restoreCursorPosX, restoreCursorPosY; struct { HINSTANCE instance; diff --git a/src/win32_window.c b/src/win32_window.c index 7fd4474b..43c793d5 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -218,15 +218,69 @@ static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area) } } +// Centers the cursor over the window client area +// +static void centerCursor(_GLFWwindow* window) +{ + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); +} + +// +// +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 the specified cursor mode +// +static void updateCursorImage(_GLFWwindow* window, int mode) +{ + if (mode == GLFW_CURSOR_NORMAL) + { + if (window->cursor) + SetCursor(window->cursor->win32.handle); + else + SetCursor(LoadCursorW(NULL, IDC_ARROW)); + } + else + { + if (mode == GLFW_CURSOR_DISABLED && _glfw.cursorWindow != window) + SetCursor(LoadCursorW(NULL, IDC_ARROW)); + else + SetCursor(NULL); + } +} + // Updates the cursor clip rect // static void updateClipRect(_GLFWwindow* window) { - RECT clipRect; - GetClientRect(window->win32.handle, &clipRect); - ClientToScreen(window->win32.handle, (POINT*) &clipRect.left); - ClientToScreen(window->win32.handle, (POINT*) &clipRect.right); - ClipCursor(&clipRect); + if (window) + { + RECT clipRect; + GetClientRect(window->win32.handle, &clipRect); + ClientToScreen(window->win32.handle, (POINT*) &clipRect.left); + ClientToScreen(window->win32.handle, (POINT*) &clipRect.right); + ClipCursor(&clipRect); + } + else + ClipCursor(NULL); } // Translates a GLFW standard cursor to a resource ID @@ -420,10 +474,11 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, { case WM_SETFOCUS: { + _glfwInputWindowFocus(window, GLFW_TRUE); + if (window->cursorMode == GLFW_CURSOR_DISABLED) _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); - _glfwInputWindowFocus(window, GLFW_TRUE); return 0; } @@ -571,12 +626,15 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, if (_glfw.cursorWindow != window) break; - _glfwInputCursorMotion(window, - x - window->win32.lastCursorPosX, - y - window->win32.lastCursorPosY); + const int dx = x - window->win32.lastCursorPosX; + const int dy = y - window->win32.lastCursorPosY; + + _glfwInputCursorPos(window, + window->virtualCursorPosX + dx, + window->virtualCursorPosY + dy); } else - _glfwInputCursorMotion(window, x, y); + _glfwInputCursorPos(window, x, y); window->win32.lastCursorPosX = x; window->win32.lastCursorPosY = y; @@ -725,19 +783,10 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_SETCURSOR: { - if (_glfw.cursorWindow == window && LOWORD(lParam) == HTCLIENT) + if (LOWORD(lParam) == HTCLIENT) { - if (window->cursorMode == GLFW_CURSOR_HIDDEN || - window->cursorMode == GLFW_CURSOR_DISABLED) - { - SetCursor(NULL); - return TRUE; - } - else if (window->cursor) - { - SetCursor(window->cursor->win32.handle); - return TRUE; - } + updateCursorImage(window, window->cursorMode); + return TRUE; } break; @@ -767,7 +816,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, // Move the mouse to the position of the drop DragQueryPoint(drop, &pt); - _glfwInputCursorMotion(window, pt.x, pt.y); + _glfwInputCursorPos(window, pt.x, pt.y); for (i = 0; i < count; i++) { @@ -1007,6 +1056,8 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, _glfwPlatformFocusWindow(window); if (!acquireMonitor(window)) return GLFW_FALSE; + + centerCursor(window); } return GLFW_TRUE; @@ -1444,28 +1495,24 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { - POINT pos; - if (mode == GLFW_CURSOR_DISABLED) - updateClipRect(window); - else - ClipCursor(NULL); - - if (!GetCursorPos(&pos)) - return; - - if (WindowFromPoint(pos) != window->win32.handle) - return; - - if (mode == GLFW_CURSOR_NORMAL) { - if (window->cursor) - SetCursor(window->cursor->win32.handle); - else - SetCursor(LoadCursorW(NULL, IDC_ARROW)); + _glfwPlatformGetCursorPos(window, + &_glfw.win32.restoreCursorPosX, + &_glfw.win32.restoreCursorPosY); + centerCursor(window); + updateClipRect(window); } - else - SetCursor(NULL); + else if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + updateClipRect(NULL); + _glfwPlatformSetCursorPos(window, + _glfw.win32.restoreCursorPosX, + _glfw.win32.restoreCursorPosY); + } + + if (cursorInClientArea(window)) + updateCursorImage(window, mode); } const char* _glfwPlatformGetKeyName(int key, int scancode) @@ -1525,32 +1572,8 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { - RECT area; - POINT pos; - - if (_glfw.cursorWindow != window) - return; - - if (window->cursorMode != GLFW_CURSOR_NORMAL) - return; - - if (!GetCursorPos(&pos)) - return; - - if (WindowFromPoint(pos) != window->win32.handle) - return; - - GetClientRect(window->win32.handle, &area); - ClientToScreen(window->win32.handle, (POINT*) &area.left); - ClientToScreen(window->win32.handle, (POINT*) &area.right); - - if (!PtInRect(&area, pos)) - return; - - if (cursor) - SetCursor(cursor->win32.handle); - else - SetCursor(LoadCursorW(NULL, IDC_ARROW)); + if (cursorInClientArea(window)) + updateCursorImage(window, window->cursorMode); } void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) diff --git a/src/window.c b/src/window.c index 503436ae..f6dc2c78 100644 --- a/src/window.c +++ b/src/window.c @@ -219,19 +219,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, glfwMakeContextCurrent((GLFWwindow*) previous); } - if (window->monitor) - { - int width, height; - _glfwPlatformGetWindowSize(window, &width, &height); - - window->virtualCursorPosX = width / 2; - window->virtualCursorPosY = height / 2; - - _glfwPlatformSetCursorPos(window, - window->virtualCursorPosX, - window->virtualCursorPosY); - } - else + if (!window->monitor) { if (wndconfig.visible) { diff --git a/src/wl_init.c b/src/wl_init.c index 29509ae9..5f6a2e99 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -91,9 +91,9 @@ static void pointerHandleMotion(void* data, window->wl.cursorPosY = wl_fixed_to_double(sy); } - _glfwInputCursorMotion(window, - wl_fixed_to_double(sx), - wl_fixed_to_double(sy)); + _glfwInputCursorPos(window, + wl_fixed_to_double(sx), + wl_fixed_to_double(sy)); } static void pointerHandleButton(void* data, diff --git a/src/wl_window.c b/src/wl_window.c index 58a721fd..b889f927 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -784,9 +784,9 @@ static void handleRelativeMotion(void* data, if (window->cursorMode != GLFW_CURSOR_DISABLED) return; - _glfwInputCursorMotion(window, - wl_fixed_to_double(dxUnaccel), - wl_fixed_to_double(dyUnaccel)); + _glfwInputCursorPos(window, + window->virtualCursorPosX + wl_fixed_to_double(dxUnaccel), + window->virtualCursorPosY + wl_fixed_to_double(dyUnaccel)); } static const struct zwp_relative_pointer_v1_listener relativePointerListener = { diff --git a/src/x11_platform.h b/src/x11_platform.h index 48070cf2..cdcfa96d 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -118,7 +118,7 @@ typedef struct _GLFWwindowX11 int xpos, ypos; // The last received cursor position, regardless of source - double lastCursorPosX, lastCursorPosY; + int lastCursorPosX, lastCursorPosY; // The last position the cursor was warped to by GLFW int warpCursorPosX, warpCursorPosY; @@ -155,6 +155,8 @@ typedef struct _GLFWlibraryX11 short int publicKeys[256]; // GLFW key to X11 keycode LUT short int nativeKeys[GLFW_KEY_LAST + 1]; + // Where to place the cursor when re-enabled + double restoreCursorPosX, restoreCursorPosY; // Window manager atoms Atom WM_PROTOCOLS; diff --git a/src/x11_window.c b/src/x11_window.c index 071b5117..36e16730 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -387,6 +387,15 @@ static char** parseUriList(char* text, int* count) return paths; } +// Centers the cursor over the window client area +// +static void centerCursor(_GLFWwindow* window) +{ + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); +} + // Create the X11 window (and its colormap) // static GLFWbool createWindow(_GLFWwindow* window, @@ -1158,12 +1167,15 @@ static void processEvent(XEvent *event) if (_glfw.cursorWindow != window) return; - _glfwInputCursorMotion(window, - x - window->x11.lastCursorPosX, - y - window->x11.lastCursorPosY); + const int dx = x - window->x11.lastCursorPosX; + const int dy = y - window->x11.lastCursorPosY; + + _glfwInputCursorPos(window, + window->virtualCursorPosX + dx, + window->virtualCursorPosY + dy); } else - _glfwInputCursorMotion(window, x, y); + _glfwInputCursorPos(window, x, y); } window->x11.lastCursorPosX = x; @@ -1265,7 +1277,7 @@ static void processEvent(XEvent *event) int x, y; _glfwPlatformGetWindowPos(window, &x, &y); - _glfwInputCursorMotion(window, absX - x, absY - y); + _glfwInputCursorPos(window, absX - x, absY - y); // Reply that we are ready to copy the dragged data XEvent reply; @@ -1517,6 +1529,8 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, updateWindowMode(window); if (!acquireMonitor(window)) return GLFW_FALSE; + + centerCursor(window); } return GLFW_TRUE; @@ -1999,11 +2013,7 @@ void _glfwPlatformPollEvents(void) _GLFWwindow* window = _glfw.cursorWindow; if (window && window->cursorMode == GLFW_CURSOR_DISABLED) - { - int width, height; - _glfwPlatformGetWindowSize(window, &width, &height); - _glfwPlatformSetCursorPos(window, width / 2, height / 2); - } + centerCursor(window); } void _glfwPlatformWaitEvents(void) @@ -2082,31 +2092,35 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { if (mode == GLFW_CURSOR_DISABLED) { + _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.cursor, CurrentTime); } - else + else if (window->cursorMode == GLFW_CURSOR_DISABLED) { XUngrabPointer(_glfw.x11.display, CurrentTime); + _glfwPlatformSetCursorPos(window, + _glfw.x11.restoreCursorPosX, + _glfw.x11.restoreCursorPosY); + } - if (mode == GLFW_CURSOR_NORMAL) - { - if (window->cursor) - { - XDefineCursor(_glfw.x11.display, window->x11.handle, - window->cursor->x11.handle); - } - else - XUndefineCursor(_glfw.x11.display, window->x11.handle); - } - else + if (mode == GLFW_CURSOR_NORMAL) + { + if (window->cursor) { XDefineCursor(_glfw.x11.display, window->x11.handle, - _glfw.x11.cursor); + window->cursor->x11.handle); } + else + XUndefineCursor(_glfw.x11.display, window->x11.handle); } + else + XDefineCursor(_glfw.x11.display, window->x11.handle, _glfw.x11.cursor); } const char* _glfwPlatformGetKeyName(int key, int scancode)