Skip to content

Commit

Permalink
Unlimited mouse button input mode
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jedenastka authored and dougbinks committed Mar 12, 2024
1 parent dc557ec commit bf945f1
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 21 deletions.
3 changes: 3 additions & 0 deletions README.md
Expand Up @@ -121,6 +121,9 @@ information on what to include when reporting a bug.

## 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

Expand Down
25 changes: 22 additions & 3 deletions docs/input.md
Expand Up @@ -492,6 +492,20 @@ a 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
and [modifier bits](@ref mods).

Expand All @@ -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 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
glfwGetMouseButton.
glfwGetMouseButton. This is not effected by the @ref GLFW_UNLIMITED_MOUSE_BUTTONS
input mode.
```c
int state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT);
Expand Down Expand Up @@ -540,7 +559,7 @@ had been processed in the meantime, the state will reset to `GLFW_RELEASE`,
otherwise it will remain `GLFW_PRESS`.
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}
Expand Down
11 changes: 11 additions & 0 deletions docs/news.md
Expand Up @@ -5,6 +5,15 @@

## 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}

## Deprecations {#deprecations}
Expand All @@ -19,6 +28,8 @@

### New constants {#new_constants}

- @ref GLFW_UNLIMITED_MOUSE_BUTTONS

## Release notes for earlier versions {#news_archive}

- [Release notes for 3.4](https://www.glfw.org/docs/3.4/news.html)
Expand Down
38 changes: 26 additions & 12 deletions include/GLFW/glfw3.h
Expand Up @@ -1149,11 +1149,12 @@ extern "C" {
#define GLFW_OPENGL_CORE_PROFILE 0x00032001
#define GLFW_OPENGL_COMPAT_PROFILE 0x00032002

#define GLFW_CURSOR 0x00033001
#define GLFW_STICKY_KEYS 0x00033002
#define GLFW_STICKY_MOUSE_BUTTONS 0x00033003
#define GLFW_LOCK_KEY_MODS 0x00033004
#define GLFW_RAW_MOUSE_MOTION 0x00033005
#define GLFW_CURSOR 0x00033001
#define GLFW_STICKY_KEYS 0x00033002
#define GLFW_STICKY_MOUSE_BUTTONS 0x00033003
#define GLFW_LOCK_KEY_MODS 0x00033004
#define GLFW_RAW_MOUSE_MOTION 0x00033005
#define GLFW_UNLIMITED_MOUSE_BUTTONS 0x00033006

#define GLFW_CURSOR_NORMAL 0x00034001
#define GLFW_CURSOR_HIDDEN 0x00034002
Expand Down Expand Up @@ -4676,8 +4677,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, @ref GLFW_LOCK_KEY_MODS or
* @ref GLFW_RAW_MOUSE_MOTION.
* @ref GLFW_STICKY_MOUSE_BUTTONS, @ref GLFW_LOCK_KEY_MODS
* @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
* modes:
Expand Down Expand Up @@ -4717,6 +4718,11 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode);
* attempting to set this will emit @ref GLFW_FEATURE_UNAVAILABLE. Call @ref
* 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] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`,
* `GLFW_STICKY_MOUSE_BUTTONS`, `GLFW_LOCK_KEY_MODS` or
Expand Down Expand Up @@ -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
* 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] 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`.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
Expand Down Expand Up @@ -5288,10 +5297,15 @@ GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmods
* is called when a mouse button is pressed or released.
*
* When a window loses input focus, it will generate synthetic mouse button
* release events for all pressed mouse buttons. You can tell these events
* from user-generated events by the fact that the synthetic ones are generated
* after the focus loss event has been processed, i.e. after the
* [window focus callback](@ref glfwSetWindowFocusCallback) has been called.
* release events for all pressed mouse buttons with associated button tokens.
* You can tell these events from user-generated events by the fact that the
* synthetic ones are generated after the focus loss event has been processed,
* 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] callback The new callback, or `NULL` to remove the currently set
Expand Down
22 changes: 16 additions & 6 deletions src/input.c
Expand Up @@ -348,20 +348,22 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods)
{
assert(window != NULL);
assert(button >= 0);
assert(button <= GLFW_MOUSE_BUTTON_LAST);
assert(action == GLFW_PRESS || action == GLFW_RELEASE);
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;

if (!window->lockKeyMods)
mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);

if (action == GLFW_RELEASE && window->stickyMouseButtons)
window->mouseButtons[button] = _GLFW_STICK;
else
window->mouseButtons[button] = (char) action;
if (button <= GLFW_MOUSE_BUTTON_LAST)
{
if (action == GLFW_RELEASE && window->stickyMouseButtons)
window->mouseButtons[button] = _GLFW_STICK;
else
window->mouseButtons[button] = (char) action;
}

if (window->callbacks.mouseButton)
window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods);
Expand Down Expand Up @@ -576,6 +578,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode)
return window->lockKeyMods;
case GLFW_RAW_MOUSE_MOTION:
return window->rawMouseMotion;
case GLFW_UNLIMITED_MOUSE_BUTTONS:
return window->disableMouseButtonLimit;
}

_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
Expand Down Expand Up @@ -683,6 +687,12 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
_glfw.platform.setRawMouseMotion(window, value);
return;
}

case GLFW_UNLIMITED_MOUSE_BUTTONS:
{
window->disableMouseButtonLimit = value ? GLFW_TRUE : GLFW_FALSE;
return;
}
}

_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
Expand Down
1 change: 1 addition & 0 deletions src/internal.h
Expand Up @@ -544,6 +544,7 @@ struct _GLFWwindow
GLFWbool stickyKeys;
GLFWbool stickyMouseButtons;
GLFWbool lockKeyMods;
GLFWbool disableMouseButtonLimit;
int cursorMode;
char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1];
char keys[GLFW_KEY_LAST + 1];
Expand Down
1 change: 1 addition & 0 deletions tests/events.c
Expand Up @@ -630,6 +630,7 @@ int main(int argc, char** argv)
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwSetInputMode(slots[i].window, GLFW_UNLIMITED_MOUSE_BUTTONS, GLFW_TRUE);

glfwSetWindowUserPointer(slots[i].window, slots + i);

Expand Down
1 change: 1 addition & 0 deletions tests/window.c
Expand Up @@ -78,6 +78,7 @@ int main(int argc, char** argv)
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwSetInputMode(window, GLFW_UNLIMITED_MOUSE_BUTTONS, GLFW_TRUE);

glfwMakeContextCurrent(window);
gladLoadGL(glfwGetProcAddress);
Expand Down

0 comments on commit bf945f1

Please sign in to comment.