diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m index 7a2654eb8..2efd52c3f 100644 --- a/glfw/cocoa_window.m +++ b/glfw/cocoa_window.m @@ -1863,6 +1863,16 @@ void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) [window->ns.object setAlphaValue:opacity]; } +void _glfwPlatformSetRawInput(_GLFWwindow *window, bool enabled) +{ + window->useRawInput = enabled; +} + +bool _glfwPlatformRawInputSupported(void) +{ + return false; +} + void _glfwDispatchRenderFrame(CGDirectDisplayID displayID) { _GLFWwindow *w = _glfw.windowListHead; diff --git a/glfw/glfw3.h b/glfw/glfw3.h index 8c0135b66..b6bc61c36 100644 --- a/glfw/glfw3.h +++ b/glfw/glfw3.h @@ -1076,6 +1076,7 @@ extern "C" { #define GLFW_STICKY_KEYS 0x00033002 #define GLFW_STICKY_MOUSE_BUTTONS 0x00033003 #define GLFW_LOCK_KEY_MODS 0x00033004 +#define GLFW_RAW_INPUT 0x00033005 #define GLFW_CURSOR_NORMAL 0x00034001 #define GLFW_CURSOR_HIDDEN 0x00034002 @@ -4076,11 +4077,12 @@ GLFWAPI void glfwPostEmptyEvent(void); * * This function returns the value of an input option for the specified window. * The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS, - * @ref GLFW_STICKY_MOUSE_BUTTONS or @ref GLFW_LOCK_KEY_MODS. + * @ref GLFW_STICKY_MOUSE_BUTTONS, @ref GLFW_LOCK_KEY_MODS or + * @ref GLFW_RAW_INPUT. * * @param[in] window The window to query. * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`, - * `GLFW_STICKY_MOUSE_BUTTONS` or `GLFW_LOCK_KEY_MODS`. + * `GLFW_STICKY_MOUSE_BUTTONS`, `GLFW_LOCK_KEY_MODS` or `GLFW_RAW_INPUT`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_INVALID_ENUM. @@ -4099,7 +4101,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); * * This function sets an input mode option for the specified window. The mode * must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS, - * @ref GLFW_STICKY_MOUSE_BUTTONS or @ref GLFW_LOCK_KEY_MODS. + * @ref GLFW_STICKY_MOUSE_BUTTONS, @ref GLFW_LOCK_KEY_MODS or + * @ref GLFW_RAW_INPUT. * * If the mode is `GLFW_CURSOR`, the value must be one of the following cursor * modes: @@ -4131,9 +4134,14 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); * GLFW_MOD_CAPS_LOCK bit set when the event was generated with Caps Lock on, * and the @ref GLFW_MOD_NUM_LOCK bit when Num Lock was on. * + * If the mode is `GLFW_RAW_INPUT`, the value must be either `true` to + * enable the use of raw input, or `false` to disable it. If enabled and + * supported by the machine, the program will retrieve high-definition mouse + * movement when cursor is grabbed. + * * @param[in] window The window whose input mode to set. * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`, - * `GLFW_STICKY_MOUSE_BUTTONS` or `GLFW_LOCK_KEY_MODS`. + * `GLFW_STICKY_MOUSE_BUTTONS`, `GLFW_LOCK_KEY_MODS` or `GLFW_RAW_INPUT`. * @param[in] value The new value of the specified input mode. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref @@ -4149,6 +4157,38 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); */ GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); +/*! @brief Returns whether the raw input is supported. + * + * This function returns whether the raw input is supported by the current + * machine. + * + * Raw input allow to retrieve high-definition movement from mouse. + * Input from a high-definition mouse is much more precise than that from a + * standard mouse. But often, they cannot be obtained through standard + * platforms API which transform mouse movement using their own improvements + * (like pointer acceleration). Platform's improvements are ideal for pointer + * control but it is not so good for moving a first-person camera. For this + * reason when the cursor of a window is grabbed by setting @ref GLFW_CURSOR + * to @ref GLFW_CURSOR_DISABLED, raw input is used. + * + * The use of raw input can be disabled using @ref glfwSetInputMode with + * @ref GLFW_RAW_INPUT mode. + * + * @return `true` if high-definition mouse movement is supported, or + * `false` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref glfwSetInputMode + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI int glfwRawInputSupported(void); + /*! @brief Returns the layout-specific name of the specified printable key. * * This function returns the name of the specified printable key, encoded as diff --git a/glfw/input.c b/glfw/input.c index 6b451aaff..f2da1de57 100644 --- a/glfw/input.c +++ b/glfw/input.c @@ -675,6 +675,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode) return window->stickyMouseButtons; case GLFW_LOCK_KEY_MODS: return window->lockKeyMods; + case GLFW_RAW_INPUT: + return window->useRawInput; } _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); @@ -754,10 +756,18 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) { window->lockKeyMods = value ? true : false; } + else if (mode == GLFW_RAW_INPUT) + _glfwPlatformSetRawInput(window, value ? true : false); else _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); } +GLFWAPI int glfwRawInputSupported(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(0); + return _glfwPlatformRawInputSupported(); +} + GLFWAPI const char* glfwGetKeyName(int key, int native_key) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); diff --git a/glfw/internal.h b/glfw/internal.h index fb7b402bc..f4ed3e877 100644 --- a/glfw/internal.h +++ b/glfw/internal.h @@ -429,6 +429,7 @@ struct _GLFWwindow char keys[GLFW_KEY_LAST + 1]; // Virtual cursor position when cursor is disabled double virtualCursorPosX, virtualCursorPosY; + bool useRawInput; _GLFWcontext context; @@ -631,6 +632,8 @@ const char* _glfwPlatformGetVersionString(void); void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos); void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos); void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode); +void _glfwPlatformSetRawInput(_GLFWwindow *window, bool enabled); +bool _glfwPlatformRawInputSupported(void); int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot, int count); int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, GLFWCursorShape shape); diff --git a/glfw/null_window.c b/glfw/null_window.c index ceed84cdc..ecef7fef4 100644 --- a/glfw/null_window.c +++ b/glfw/null_window.c @@ -208,6 +208,16 @@ void _glfwPlatformSetWindowOpacity(_GLFWwindow* window UNUSED, float opacity UNU { } +void _glfwPlatformSetRawInput(_GLFWwindow *window, bool enabled) +{ + window->useRawInput = enabled; +} + +bool _glfwPlatformRawInputSupported(void) +{ + return false; +} + void _glfwPlatformShowWindow(_GLFWwindow* window UNUSED) { } diff --git a/glfw/window.c b/glfw/window.c index 20d9926a2..a4539ea20 100644 --- a/glfw/window.c +++ b/glfw/window.c @@ -247,6 +247,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, window->floating = wndconfig.floating; window->focusOnShow = wndconfig.focusOnShow; window->cursorMode = GLFW_CURSOR_NORMAL; + window->useRawInput = true; window->minwidth = GLFW_DONT_CARE; window->minheight = GLFW_DONT_CARE; diff --git a/glfw/wl_window.c b/glfw/wl_window.c index 64e5799a0..f015cc48d 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -1237,6 +1237,16 @@ void _glfwPlatformSetWindowOpacity(_GLFWwindow* window UNUSED, float opacity UNU { } +void _glfwPlatformSetRawInput(_GLFWwindow *window, bool enabled) +{ + window->useRawInput = enabled; +} + +bool _glfwPlatformRawInputSupported(void) +{ + return false; +} + void _glfwPlatformPollEvents(void) { wl_display_dispatch_pending(_glfw.wl.display); diff --git a/glfw/x11_window.c b/glfw/x11_window.c index fd1c50d0f..009982370 100644 --- a/glfw/x11_window.c +++ b/glfw/x11_window.c @@ -459,7 +459,7 @@ static void updateCursorImage(_GLFWwindow* window) // static void disableCursor(_GLFWwindow* window) { - if (_glfw.x11.xi.available) + if (_glfw.x11.xi.available && window->useRawInput) { XIEventMask em; unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; @@ -490,7 +490,7 @@ static void disableCursor(_GLFWwindow* window) // static void enableCursor(_GLFWwindow* window) { - if (_glfw.x11.xi.available) + if (_glfw.x11.xi.available && window->useRawInput) { XIEventMask em; unsigned char mask[] = { 0 }; @@ -1122,6 +1122,7 @@ static void processEvent(XEvent *event) _GLFWwindow* window = _glfw.x11.disabledCursorWindow; if (window && + window->useRawInput && event->xcookie.extension == _glfw.x11.xi.majorOpcode && XGetEventData(_glfw.x11.display, &event->xcookie) && event->xcookie.evtype == XI_RawMotion) @@ -1363,7 +1364,7 @@ static void processEvent(XEvent *event) { if (_glfw.x11.disabledCursorWindow != window) return; - if (_glfw.x11.xi.available) + if (_glfw.x11.xi.available && window->useRawInput) return; const int dx = x - window->x11.lastCursorPosX; @@ -2629,6 +2630,24 @@ _glfwDispatchX11Events(void) { return dispatched; } +void _glfwPlatformSetRawInput(_GLFWwindow *window, bool enabled) +{ + if (window->useRawInput != enabled) + { + int update = (_glfw.x11.disabledCursorWindow == window && _glfw.x11.xi.available); + if (update) + enableCursor(window); + window->useRawInput = enabled; + if (update) + disableCursor(window); + } +} + +bool _glfwPlatformRawInputSupported(void) +{ + return _glfw.x11.xi.available; +} + void _glfwPlatformPollEvents(void) { _glfwDispatchX11Events(); diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index 156e2ecb0..d8a0c7c27 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -839,6 +839,7 @@ #define GLFW_STICKY_KEYS 0x00033002 #define GLFW_STICKY_MOUSE_BUTTONS 0x00033003 #define GLFW_LOCK_KEY_MODS 0x00033004 +#define GLFW_RAW_INPUT 0x00033005 #define GLFW_CURSOR_NORMAL 0x00034001 #define GLFW_CURSOR_HIDDEN 0x00034002