Unlimited mouse button input mode

This adds the GLFW_UNLIMITED_MOUSE_BUTTONS input mode which permits
mouse buttons over GLFW_MOUSE_BUTTON_LAST to be reported to the mouse
button callback.

Closes #2423
This commit is contained in:
Grzesiek11 2024-02-29 15:50:50 +00:00 committed by Doug Binks
parent dc557ecf38
commit bf945f1213
8 changed files with 81 additions and 21 deletions

View File

@ -121,6 +121,9 @@ information on what to include when reporting a bug.
## Changelog since 3.4 ## Changelog since 3.4
- Added `GLFW_UNLIMITED_MOUSE_BUTTONS` input mode that allows mouse buttons beyond
the limit of the mouse button tokens to be reported (#2423)
## Contact ## Contact

View File

@ -492,6 +492,20 @@ a mouse button callback.
glfwSetMouseButtonCallback(window, mouse_button_callback); glfwSetMouseButtonCallback(window, mouse_button_callback);
``` ```
@anchor GLFW_UNLIMITED_MOUSE_BUTTONS
To handle all mouse buttons in the callback, instead of only ones with associated
[button tokens](@ref buttons), set the @ref GLFW_UNLIMITED_MOUSE_BUTTONS
input mode.
```c
glfwSetInputMode(window, GLFW_UNLIMITED_MOUSE_BUTTONS, GLFW_TRUE);
```
When this input mode is enabled, GLFW doesn't limit the reported mouse buttons
to only those that have an associated button token, for compatibility with
earlier versions of GLFW, which never reported any buttons over
@ref GLFW_MOUSE_BUTTON_LAST, on which users could have relied on.
The callback function receives the [mouse button](@ref buttons), button action The callback function receives the [mouse button](@ref buttons), button action
and [modifier bits](@ref mods). and [modifier bits](@ref mods).
@ -503,11 +517,16 @@ void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
} }
``` ```
The mouse button is an integer that can be one of the
[mouse button tokens](@ref buttons) or, if the
@ref GLFW_UNLIMITED_MOUSE_BUTTONS input mode is set, any other positive value.
The action is one of `GLFW_PRESS` or `GLFW_RELEASE`. The action is one of `GLFW_PRESS` or `GLFW_RELEASE`.
The last reported state for every [supported mouse button](@ref buttons) is also The last reported state for every [mouse button token](@ref buttons) is also
saved in per-window state arrays that can be polled with @ref saved in per-window state arrays that can be polled with @ref
glfwGetMouseButton. glfwGetMouseButton. This is not effected by the @ref GLFW_UNLIMITED_MOUSE_BUTTONS
input mode.
```c ```c
int state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT); int state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT);
@ -540,7 +559,7 @@ had been processed in the meantime, the state will reset to `GLFW_RELEASE`,
otherwise it will remain `GLFW_PRESS`. otherwise it will remain `GLFW_PRESS`.
The `GLFW_MOUSE_BUTTON_LAST` constant holds the highest value of any The `GLFW_MOUSE_BUTTON_LAST` constant holds the highest value of any
[supported mouse button](@ref buttons). [mouse button token](@ref buttons).
### Scroll input {#scrolling} ### Scroll input {#scrolling}

View File

@ -5,6 +5,15 @@
## New features {#features} ## New features {#features}
### Unlimited mouse buttons {#unlimited_mouse_buttons}
GLFW now has an input mode which allows an unlimited number of mouse buttons to
be reported by the mouse buttton callback, rather than just the associated
[mouse button tokens](@ref buttons). This allows using mouse buttons with
values over 8. For compatibility with older versions, the
@ref GLFW_UNLIMITED_MOUSE_BUTTONS input mode needs to be set to make use of
this.
## Caveats {#caveats} ## Caveats {#caveats}
## Deprecations {#deprecations} ## Deprecations {#deprecations}
@ -19,6 +28,8 @@
### New constants {#new_constants} ### New constants {#new_constants}
- @ref GLFW_UNLIMITED_MOUSE_BUTTONS
## Release notes for earlier versions {#news_archive} ## Release notes for earlier versions {#news_archive}
- [Release notes for 3.4](https://www.glfw.org/docs/3.4/news.html) - [Release notes for 3.4](https://www.glfw.org/docs/3.4/news.html)

View File

@ -1149,11 +1149,12 @@ extern "C" {
#define GLFW_OPENGL_CORE_PROFILE 0x00032001 #define GLFW_OPENGL_CORE_PROFILE 0x00032001
#define GLFW_OPENGL_COMPAT_PROFILE 0x00032002 #define GLFW_OPENGL_COMPAT_PROFILE 0x00032002
#define GLFW_CURSOR 0x00033001 #define GLFW_CURSOR 0x00033001
#define GLFW_STICKY_KEYS 0x00033002 #define GLFW_STICKY_KEYS 0x00033002
#define GLFW_STICKY_MOUSE_BUTTONS 0x00033003 #define GLFW_STICKY_MOUSE_BUTTONS 0x00033003
#define GLFW_LOCK_KEY_MODS 0x00033004 #define GLFW_LOCK_KEY_MODS 0x00033004
#define GLFW_RAW_MOUSE_MOTION 0x00033005 #define GLFW_RAW_MOUSE_MOTION 0x00033005
#define GLFW_UNLIMITED_MOUSE_BUTTONS 0x00033006
#define GLFW_CURSOR_NORMAL 0x00034001 #define GLFW_CURSOR_NORMAL 0x00034001
#define GLFW_CURSOR_HIDDEN 0x00034002 #define GLFW_CURSOR_HIDDEN 0x00034002
@ -4676,8 +4677,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode);
* *
* This function sets an input mode option for the specified window. The 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, * must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS,
* @ref GLFW_STICKY_MOUSE_BUTTONS, @ref GLFW_LOCK_KEY_MODS or * @ref GLFW_STICKY_MOUSE_BUTTONS, @ref GLFW_LOCK_KEY_MODS
* @ref GLFW_RAW_MOUSE_MOTION. * @ref GLFW_RAW_MOUSE_MOTION, or @ref GLFW_UNLIMITED_MOUSE_BUTTONS.
* *
* If the mode is `GLFW_CURSOR`, the value must be one of the following cursor * If the mode is `GLFW_CURSOR`, the value must be one of the following cursor
* modes: * modes:
@ -4717,6 +4718,11 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode);
* attempting to set this will emit @ref GLFW_FEATURE_UNAVAILABLE. Call @ref * attempting to set this will emit @ref GLFW_FEATURE_UNAVAILABLE. Call @ref
* glfwRawMouseMotionSupported to check for support. * glfwRawMouseMotionSupported to check for support.
* *
* If the mode is `GLFW_UNLIMITED_MOUSE_BUTTONS`, the value must be either
* `GLFW_TRUE` to disable the mouse button limit when calling the mouse button
* callback, or `GLFW_FALSE` to limit the mouse buttons sent to the callback
* to the mouse button token values up to `GLFW_MOUSE_BUTTON_LAST`.
*
* @param[in] window The window whose input mode to set. * @param[in] window The window whose input mode to set.
* @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`, * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`,
* `GLFW_STICKY_MOUSE_BUTTONS`, `GLFW_LOCK_KEY_MODS` or * `GLFW_STICKY_MOUSE_BUTTONS`, `GLFW_LOCK_KEY_MODS` or
@ -4911,8 +4917,11 @@ GLFWAPI int glfwGetKey(GLFWwindow* window, int key);
* returns `GLFW_PRESS` the first time you call it for a mouse button that was * returns `GLFW_PRESS` the first time you call it for a mouse button that was
* pressed, even if that mouse button has already been released. * pressed, even if that mouse button has already been released.
* *
* The @ref GLFW_UNLIMITED_MOUSE_BUTTONS input mode does not effect the
* limit on buttons which can be polled with this function.
*
* @param[in] window The desired window. * @param[in] window The desired window.
* @param[in] button The desired [mouse button](@ref buttons). * @param[in] button The desired [mouse button token](@ref buttons).
* @return One of `GLFW_PRESS` or `GLFW_RELEASE`. * @return One of `GLFW_PRESS` or `GLFW_RELEASE`.
* *
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
@ -5288,10 +5297,15 @@ GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmods
* is called when a mouse button is pressed or released. * is called when a mouse button is pressed or released.
* *
* When a window loses input focus, it will generate synthetic mouse button * When a window loses input focus, it will generate synthetic mouse button
* release events for all pressed mouse buttons. You can tell these events * release events for all pressed mouse buttons with associated button tokens.
* from user-generated events by the fact that the synthetic ones are generated * You can tell these events from user-generated events by the fact that the
* after the focus loss event has been processed, i.e. after the * synthetic ones are generated after the focus loss event has been processed,
* [window focus callback](@ref glfwSetWindowFocusCallback) has been called. * i.e. after the [window focus callback](@ref glfwSetWindowFocusCallback) has
* been called.
*
* The reported `button` value can be higher than `GLFW_MOUSE_BUTTON_LAST` if
* the button does not have an associated [button token](@ref buttons) and the
* @ref GLFW_UNLIMITED_MOUSE_BUTTONS input mode is set.
* *
* @param[in] window The window whose callback to set. * @param[in] window The window whose callback to set.
* @param[in] callback The new callback, or `NULL` to remove the currently set * @param[in] callback The new callback, or `NULL` to remove the currently set

View File

@ -348,20 +348,22 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods)
{ {
assert(window != NULL); assert(window != NULL);
assert(button >= 0); assert(button >= 0);
assert(button <= GLFW_MOUSE_BUTTON_LAST);
assert(action == GLFW_PRESS || action == GLFW_RELEASE); assert(action == GLFW_PRESS || action == GLFW_RELEASE);
assert(mods == (mods & GLFW_MOD_MASK)); assert(mods == (mods & GLFW_MOD_MASK));
if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST) if (button < 0 || (!window->disableMouseButtonLimit && button > GLFW_MOUSE_BUTTON_LAST))
return; return;
if (!window->lockKeyMods) if (!window->lockKeyMods)
mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
if (action == GLFW_RELEASE && window->stickyMouseButtons) if (button <= GLFW_MOUSE_BUTTON_LAST)
window->mouseButtons[button] = _GLFW_STICK; {
else if (action == GLFW_RELEASE && window->stickyMouseButtons)
window->mouseButtons[button] = (char) action; window->mouseButtons[button] = _GLFW_STICK;
else
window->mouseButtons[button] = (char) action;
}
if (window->callbacks.mouseButton) if (window->callbacks.mouseButton)
window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods); window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods);
@ -576,6 +578,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode)
return window->lockKeyMods; return window->lockKeyMods;
case GLFW_RAW_MOUSE_MOTION: case GLFW_RAW_MOUSE_MOTION:
return window->rawMouseMotion; return window->rawMouseMotion;
case GLFW_UNLIMITED_MOUSE_BUTTONS:
return window->disableMouseButtonLimit;
} }
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
@ -683,6 +687,12 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
_glfw.platform.setRawMouseMotion(window, value); _glfw.platform.setRawMouseMotion(window, value);
return; return;
} }
case GLFW_UNLIMITED_MOUSE_BUTTONS:
{
window->disableMouseButtonLimit = value ? GLFW_TRUE : GLFW_FALSE;
return;
}
} }
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);

View File

@ -544,6 +544,7 @@ struct _GLFWwindow
GLFWbool stickyKeys; GLFWbool stickyKeys;
GLFWbool stickyMouseButtons; GLFWbool stickyMouseButtons;
GLFWbool lockKeyMods; GLFWbool lockKeyMods;
GLFWbool disableMouseButtonLimit;
int cursorMode; int cursorMode;
char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1]; char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1];
char keys[GLFW_KEY_LAST + 1]; char keys[GLFW_KEY_LAST + 1];

View File

@ -630,6 +630,7 @@ int main(int argc, char** argv)
glfwTerminate(); glfwTerminate();
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
glfwSetInputMode(slots[i].window, GLFW_UNLIMITED_MOUSE_BUTTONS, GLFW_TRUE);
glfwSetWindowUserPointer(slots[i].window, slots + i); glfwSetWindowUserPointer(slots[i].window, slots + i);

View File

@ -78,6 +78,7 @@ int main(int argc, char** argv)
glfwTerminate(); glfwTerminate();
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
glfwSetInputMode(window, GLFW_UNLIMITED_MOUSE_BUTTONS, GLFW_TRUE);
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
gladLoadGL(glfwGetProcAddress); gladLoadGL(glfwGetProcAddress);