Compare commits

...

17 Commits

Author SHA1 Message Date
Narrik Synthfox
78e034a7f7
Merge da7aa4130f into 506c11ba43 2025-07-05 14:09:06 -05:00
NarrikSynthfox
da7aa4130f Merge remote-tracking branch 'mainglfw/master' into pr/2 2024-12-20 09:47:56 -05:00
NarrikSynthfox
6cd8a73064 Update input.c 2024-04-10 13:44:49 -04:00
NarrikSynthfox
ed65906282 Merge branch 'pr/2' of https://github.com/NarrikSynthfox/glfw into pr/2 2024-04-10 13:39:43 -04:00
NarrikSynthfox
b9acd9d45f Update docs, readme, news, and contributors 2024-04-10 13:39:41 -04:00
NarrikSynthfox
a4c3492a03 Fix issue with merge 2024-04-10 13:39:35 -04:00
NarrikSynthfox
094db02c39 Update docs, readme, news, and contributors 2024-04-10 13:08:34 -04:00
NarrikSynthfox
a06c00215a Fixed issue with bad merge 2024-04-10 11:24:35 -04:00
NarrikSynthfox
39dec1415b Merge remote-tracking branch 'upstream' into pr/2 2024-04-10 06:06:04 -04:00
Enthuin
e65723069f change gamepad state callback to use the state. post empty event after joystick polling to make waitEvents return 2022-10-20 21:25:38 -05:00
Enthuin
712942e596 Merge remote-tracking branch 'upstream/master' into beoran-601-joystick-callbacks 2022-10-19 18:25:56 -05:00
Beoran
ccf7c931b0
Merge branch 'master' into beoran-601-joystick-callbacks 2021-09-22 19:38:40 +02:00
Beoran
ef269c0ae9 Only call the joystick event callback if the state actually changed.
Only calculate the joystick ID when the event callback is actually called.
2020-03-15 20:53:20 +01:00
Beoran
1ed4c69550 Remove accidentally duplicated function type definition. 2019-11-07 01:19:01 +01:00
Beoran
ee4132b5cf Test and fix joystick and game pad callbacks on Linux. 2019-11-07 01:01:31 +01:00
Beoran
f5536ccae0 Implement joystick and game pad callbacks.
This allows using GLFW joysticks in an event based manner.

For the joysticks, this was done by adding the callbacks
and then calling them in the shared code in input.c.
For the gamepads, a new shared function is called whenever the
joystick's state changes. However the gamepad state callback is
only called if the joystick is mapped to a gamepad.
2019-10-31 20:49:39 +01:00
Beoran
556cc61848 Added WIP types for the joystick callbacks. 2019-10-30 23:56:53 +01:00
9 changed files with 477 additions and 5 deletions

View File

@ -295,6 +295,9 @@ video tutorials.
- Jonas Ådahl
- Lasse Öörni
- Leonard König
- Beoran
- Enthuin
- Narrik Synthfox
- All the unmentioned and anonymous contributors in the GLFW community, for bug
reports, patches, feedback, testing and encouragement

View File

@ -135,7 +135,7 @@ information on what to include when reporting a bug.
- [Null] Added EGL context creation on Mesa via `EGL_MESA_platform_surfaceless`
- [EGL] Allowed native access on Wayland with `GLFW_CONTEXT_CREATION_API` set to
`GLFW_NATIVE_CONTEXT_API` (#2518)
- Added `GLFWgamepadstatefun`, `glfwSetGamepadStateCallback`, `GLFWjoystickbuttonfun`,`glfwSetJoystickButtonCallback`, `GLFWjoystickaxisfun`, `glfwSetJoystickAxisCallback`, `GLFWjoystickhatfun`, and `glfwSetJoystickHatCallback` for event-based joystick/gamepad input.
## Contact

View File

@ -911,6 +911,85 @@ righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,
were recently added to SDL. The input modifiers `+`, `-` and `~` are supported
and described above.
### Event-based joystick and gamepad input {#joystick_input_event}
If you wish to be notified when a button on a joystick is pressed or released, set a joystick button callback.
```c
glfwSetJoystickButtonCallback(joystick_button_callback);
```
The callback function receives the joystick id, the [joystick button](@ref joystick_button) that was pressed or released, and action.
```c
void joystick_button_callback(int jid, int button, int action)
{
if (button == 0 && action == GLFW_PRESS)
jump();
}
```
The action is one of `GLFW_PRESS` or `GLFW_RELEASE`
If you wish to be notified when an axis on a joystick is moved, set a joystick axis callback.
```c
glfwSetJoystickAxisCallback(joystick_axis_callback);
```
The callback function receives the joystick id, [joystick axis](@ref joystick_axis) that was moved, and float value from -1.0 to 1.0 for the axis.
```c
void joystick_axis_callback(int jid, int axis, float value)
{
if (axis == 0){
if(value == -1.0f)
move_left();
else if(value == 1.0f)
move_right();
}
}
```
If you wish to be notified when a hat on a joystick is moved, set a joystick hat callback.
```c
glfwSetJoystickHatCallback(joystick_hat_callback);
```
The callback function receives the joystick id, hat, and the [hat states](@ref hat_state).
```c
void joystick_hat_callback(int jid, int hat, int position)
{
if(hat == 0 && position == GLFW_HAT_UP)
move_up();
}
```
If you wish to be notified when the state of a gamepad is updated, set a gamepad state callback. This callback will occur every time any button, axis, or hat updates, so with this, you will have to handle checks for if a value is changed.
```c
glfwSetGamepadStateCallback(gamepad_state_callback);
```
The callback function recieves the joystick id and the gamepad state.
```c
bool jumpButtonHeld = false;
gamepad_state_callback(int jid, GLFWgamepadstate state){
if (state.buttons[GLFW_GAMEPAD_BUTTON_A] && !jumpButtonHeld)
{
input_jump();
jumpButtonHeld = true;
}
else if (!state.buttons[GLFW_GAMEPAD_BUTTON_A] && jumpButtonHeld)
{
jumpButtonHeld = false;
}
}
```
## Time input {#time}

View File

@ -14,6 +14,11 @@ 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.
### Callback functions for gamepad state, joystick buttons, joystick axes, and joystick hat inputs {#joystick_input_callbacks}
GLFW now has callback functions for [gamepad state](@ref glfwSetGamepadStateCallback), [joystick buttons](@ref glfwSetJoystickButtonCallback), [joystick axes](@ref glfwSetJoystickAxisCallback), and [joystick hats](@ref glfwSetJoystickHatCallback), allowing for
event-based inputs for joysticks and gamepads.
## Caveats {#caveats}
## Deprecations {#deprecations}
@ -24,8 +29,18 @@ this.
### New functions {#new_functions}
- @ref glfwSetJoystickButtonCallback
- @ref glfwSetJoystickAxisCallback
- @ref glfwSetJoystickHatCallback
- @ref glfwSetGamepadStateCallback
### New types {#new_types}
- @ref GLFWjoystickbuttonfun
- @ref GLFWjoystickaxisfun
- @ref GLFWjoystickhatfun
- @ref GLFWgamepadstatefun
### New constants {#new_constants}
- @ref GLFW_UNLIMITED_MOUSE_BUTTONS

View File

@ -2106,6 +2106,7 @@ typedef struct GLFWimage
*
* @sa @ref gamepad
* @sa @ref glfwGetGamepadState
* @sa @ref glfwSetGamepadStateCallback
*
* @since Added in version 3.3.
*
@ -2155,6 +2156,103 @@ typedef struct GLFWallocator
void* user;
} GLFWallocator;
/*! @brief The function pointer type for joystick button callbacks.
*
* This is the function pointer type for joystick button callbacks. A joystick
* button callback function has the following signature:
* @code
* void function_name(int jid, int button, int action)
* @endcode
*
* @param[in] jid The joystick that had a button pressed or released.
* @param[in] button The [joystick button](@ref buttons) that was pressed or released.
* @param[in] action `GLFW_PRESS` or `GLFW_RELEASE`. Future
* releases may add more actions.
*
* @sa @ref input_joystick_button
* @sa @ref glfwSetJoystickButonCallback
*
* @since Added in version 3.4.
* @ingroup input
*/
typedef void (* GLFWjoystickbuttonfun)(int,int,int);
/*! @brief The function pointer type for joystick axis movement callbacks.
*
* This is the function pointer type for joystick axis movement callbacks. A joystick
* axis movement callback function has the following signature:
* @code
* void function_name(int jid, int axis, float position)
* @endcode
*
* @param[in] jid The joystick that had an axis moved.
* @param[in] axis The [joystick axis](@ref gamepad axes) that was moved.
* @param[in] position A value between -1.0 and 1.0 that indicates the position of the axis.
*
* @sa @ref input_gamepad_axis
* @sa @ref glfwSetJoystickAxisCallback
*
* @since Added in version 3.4.
* @ingroup input
*/
typedef void (* GLFWjoystickaxisfun)(int,int,float);
/*! @brief The function pointer type for joystick hat movement callbacks.
*
* This is the function pointer type for joystick hat movement callbacks. A joystick
* hat movement callback function has the following signature:
* @code
* void function_name(int jid, int hat, int position)
* @endcode
*
* @param[in] jid The joystick that had an axis moved.
* @param[in] hat The [joystick hat](@ref joystick hats) that was moved.
* @param[in] position A value that indicates the position of the hat.
* The position parameter is one of the following values:
*
* Name | Value
* ---- | -----
* `GLFW_HAT_CENTERED` | 0
* `GLFW_HAT_UP` | 1
* `GLFW_HAT_RIGHT` | 2
* `GLFW_HAT_DOWN` | 4
* `GLFW_HAT_LEFT` | 8
* `GLFW_HAT_RIGHT_UP` | `GLFW_HAT_RIGHT` \| `GLFW_HAT_UP`
* `GLFW_HAT_RIGHT_DOWN` | `GLFW_HAT_RIGHT` \| `GLFW_HAT_DOWN`
* `GLFW_HAT_LEFT_UP` | `GLFW_HAT_LEFT` \| `GLFW_HAT_UP`
* `GLFW_HAT_LEFT_DOWN` | `GLFW_HAT_LEFT` \| `GLFW_HAT_DOWN`
*
* The diagonal directions are bitwise combinations of the primary (up, right,
* down and left) directions and you can test for these individually by ANDing
* it with the corresponding direction.
*
* @sa @ref input_joystick_hat
* @sa @ref glfwSetJoystickHatCallback
*
* @since Added in version 3.4.
* @ingroup input
*/
typedef void (* GLFWjoystickhatfun)(int,int,int);
/*! @brief The function pointer type for game pad state changes.
*
* This is the function pointer type for game pad state change callbacks.
* A game pad state change callback function has the following signature:
* @code
* void function_name(int jid, GLFWgamepadstate* state)
* @endcode
*
* @param[in] jid The ID of the game pad that changed state.
* @param[in] state the state of the game pad
*
* @sa @ref input_gamepad
* @sa @ref glfwSetGamepadStateCallback
*
* @since Added in version 3.4.
* @ingroup input
*/
typedef void (* GLFWgamepadstatefun)(int jid, GLFWgamepadstate state);
/*************************************************************************
* GLFW API functions
@ -5806,6 +5904,140 @@ GLFWAPI int glfwJoystickIsGamepad(int jid);
*/
GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun callback);
/*! @brief Sets the joystick button callback.
*
* This function sets the joystick configuration callback, or removes the
* currently set callback. This is called when a joystick button is pressed
* or released.
*
* For joystick button events to be delivered on all platforms,
* you need to call one of the [event processing](@ref events)
* functions.
*
* @param[in] callback The new callback, or `NULL` to remove the currently set
* callback.
* @return The previously set callback, or `NULL` if no callback was set or the
* library had not been [initialized](@ref intro_init).
*
* @callback_signature
* @code
* void function_name(int jid, int button, int state)
* @endcode
* For more information about the callback parameters, see the
* [function pointer type](@ref GLFWjoystickbuttonfun).
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref joystick_event
*
* @since Added in version 3.2.
*
* @ingroup input
*/
GLFWAPI GLFWjoystickbuttonfun glfwSetJoystickButtonCallback(GLFWjoystickbuttonfun callback);
/*! @brief Sets the joystick axis callback.
*
* This function sets the joystick axis callback, or removes the
* currently set callback. This is called when a joystick axis moved.
*
* For joystick axis events to be delivered on all platforms,
* you need to call one of the [event processing](@ref events)
* functions.
*
* @param[in] callback The new callback, or `NULL` to remove the currently set
* callback.
* @return The previously set callback, or `NULL` if no callback was set or the
* library had not been [initialized](@ref intro_init).
*
* @callback_signature
* @code
* void function_name(int jid, int axis, float state)
* @endcode
* For more information about the callback parameters, see the
* [function pointer type](@ref GLFWjoystickaxisfun).
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref joystick_event
*
* @since Added in version 3.2.
*
* @ingroup input
*/
GLFWAPI GLFWjoystickaxisfun glfwSetJoystickAxisCallback(GLFWjoystickaxisfun callback);
/*! @brief Sets the joystick hat callback.
*
* This function sets the joystick hat callback, or removes the
* currently set callback. This is called when a joystick hat moved.
*
* For joystick hat events to be delivered on all platforms,
* you need to call one of the [event processing](@ref events)
* functions.
*
* @param[in] callback The new callback, or `NULL` to remove the currently set
* callback.
* @return The previously set callback, or `NULL` if no callback was set or the
* library had not been [initialized](@ref intro_init).
*
* @callback_signature
* @code
* void function_name(int jid, int hat, int state)
* @endcode
* For more information about the callback parameters, see the
* [function pointer type](@ref GLFWjoystickhatfun).
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref joystick_event
*
* @since Added in version 3.2.
*
* @ingroup input
*/
GLFWAPI GLFWjoystickhatfun glfwSetJoystickHatCallback(GLFWjoystickhatfun callback);
/*! @brief Sets the game pad state callback.
*
* This function sets the game pad state callback, or removes the
* currently set callback. This is called when a game pad state changes.
*
* For game pad events to be delivered on all platforms,
* you need to call one of the [event processing](@ref events)
* functions.
*
* @param[in] callback The new callback, or `NULL` to remove the currently set
* callback.
* @return The previously set callback, or `NULL` if no callback was set or the
* library had not been [initialized](@ref intro_init).
*
* @callback_signature
* @code
* void function_name(int jid, unsigned char buttons[15], float axes[6])
* @endcode
* For more information about the callback parameters, see the
* [function pointer type](@ref GLFWgamepadstatefun).
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref joystick_event
*
* @since Added in version 3.2.
*
* @ingroup input
*/
GLFWAPI GLFWgamepadstatefun glfwSetGamepadStateCallback(GLFWgamepadstatefun callback);
/*! @brief Adds the specified SDL_GameControllerDB gamepad mappings.
*
* This function parses the specified ASCII encoded string and updates the

View File

@ -413,6 +413,27 @@ void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths)
window->callbacks.drop((GLFWwindow*) window, count, paths);
}
// Notifies shared code of a change in the gamepad state.
// Automatically recalculates the state if the gamepad callback is installed.
void _glfwInputGamepad(_GLFWjoystick *js)
{
const int jid = (int)(js - _glfw.joysticks);
if (!_glfw.initialized)
{
return;
}
if ((js->mapping != NULL) && (_glfw.callbacks.gamepad_state))
{
GLFWgamepadstate state;
if (glfwGetGamepadState(jid, &state))
{
_glfw.callbacks.gamepad_state(jid, state);
}
}
}
// Notifies shared code of a joystick connection or disconnection
//
void _glfwInputJoystick(_GLFWjoystick* js, int event)
@ -437,7 +458,17 @@ void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value)
assert(axis >= 0);
assert(axis < js->axisCount);
if (js->axes[axis] != value)
{
const int jid = (int)(js - _glfw.joysticks);
js->axes[axis] = value;
if (_glfw.callbacks.joystick_axis)
_glfw.callbacks.joystick_axis(jid, axis, value);
_glfwInputGamepad(js);
} else {
js->axes[axis] = value;
}
}
// Notifies shared code of the new value of a joystick button
@ -449,7 +480,16 @@ void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value)
assert(button < js->buttonCount);
assert(value == GLFW_PRESS || value == GLFW_RELEASE);
if (js->buttons[button] != value) {
const int jid = (int)(js - _glfw.joysticks);
js->buttons[button] = value;
if (_glfw.callbacks.joystick_button)
_glfw.callbacks.joystick_button(jid, button, value);
_glfwInputGamepad(js);
} else {
js->buttons[button] = value;
}
}
// Notifies shared code of the new value of a joystick hat
@ -474,11 +514,17 @@ void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value)
js->buttons[base + 1] = (value & 0x02) ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[base + 2] = (value & 0x04) ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[base + 3] = (value & 0x08) ? GLFW_PRESS : GLFW_RELEASE;
if (js->hats[hat] != value)
{
const int jid = (int)(js - _glfw.joysticks);
js->hats[hat] = value;
if (_glfw.callbacks.joystick_hat)
_glfw.callbacks.joystick_hat(jid, hat, value);
_glfwInputGamepad(js);
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
@ -554,6 +600,19 @@ void _glfwCenterCursorInContentArea(_GLFWwindow* window)
_glfw.platform.setCursorPos(window, width / 2.0, height / 2.0);
}
void _glfwPollAllJoysticks()
{
int jid;
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (_glfw.joysticks[jid].connected == GLFW_TRUE)
{
_glfw.platform.pollJoystick(_glfw.joysticks + jid, _GLFW_POLL_ALL);
glfwPostEmptyEvent();
}
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW public API //////
@ -1269,6 +1328,34 @@ GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun)
return cbfun;
}
GLFWAPI GLFWgamepadstatefun glfwSetGamepadStateCallback(GLFWgamepadstatefun cbfun)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP(GLFWgamepadstatefun, _glfw.callbacks.gamepad_state, cbfun);
return cbfun;
}
GLFWAPI GLFWjoystickbuttonfun glfwSetJoystickButtonCallback(GLFWjoystickbuttonfun cbfun)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP(GLFWjoystickbuttonfun, _glfw.callbacks.joystick_button, cbfun);
return cbfun;
}
GLFWAPI GLFWjoystickaxisfun glfwSetJoystickAxisCallback(GLFWjoystickaxisfun cbfun)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP(GLFWjoystickaxisfun, _glfw.callbacks.joystick_axis, cbfun);
return cbfun;
}
GLFWAPI GLFWjoystickhatfun glfwSetJoystickHatCallback(GLFWjoystickhatfun cbfun)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP(GLFWjoystickhatfun, _glfw.callbacks.joystick_hat, cbfun);
return cbfun;
}
GLFWAPI int glfwUpdateGamepadMappings(const char* string)
{
int jid;
@ -1520,4 +1607,3 @@ GLFWAPI uint64_t glfwGetTimerFrequency(void)
_GLFW_REQUIRE_INIT_OR_RETURN(0);
return _glfwPlatformGetTimerFrequency();
}

View File

@ -876,8 +876,12 @@ struct _GLFWlibrary
} vk;
struct {
GLFWmonitorfun monitor;
GLFWjoystickfun joystick;
GLFWmonitorfun monitor;
GLFWjoystickfun joystick;
GLFWjoystickaxisfun joystick_axis;
GLFWjoystickbuttonfun joystick_button;
GLFWjoystickhatfun joystick_hat;
GLFWgamepadstatefun gamepad_state;
} callbacks;
// These are defined in platform.h
@ -986,6 +990,7 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name,
int hatCount);
void _glfwFreeJoystick(_GLFWjoystick* js);
void _glfwCenterCursorInContentArea(_GLFWwindow* window);
void _glfwPollAllJoysticks();
GLFWbool _glfwInitEGL(void);
void _glfwTerminateEGL(void);

View File

@ -1167,12 +1167,14 @@ GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow*
GLFWAPI void glfwPollEvents(void)
{
_GLFW_REQUIRE_INIT();
_glfwPollAllJoysticks();
_glfw.platform.pollEvents();
}
GLFWAPI void glfwWaitEvents(void)
{
_GLFW_REQUIRE_INIT();
_glfwPollAllJoysticks();
_glfw.platform.waitEvents();
}

View File

@ -542,6 +542,52 @@ static void joystick_callback(int jid, int event)
}
}
static void joystick_button_callback(int jid, int button, int state) {
printf("%08x at %0.3f: Joystick %i (%s) button %d state %d\n",
counter++, glfwGetTime(),
jid,
glfwGetJoystickName(jid),
button,
state);
}
static void joystick_axis_callback(int jid, int axis, float value) {
printf("%08x at %0.3f: Joystick %i (%s) axis %d value %0.4f\n",
counter++, glfwGetTime(), jid,
glfwGetJoystickName(jid),
axis,
value);
}
static void joystick_hat_callback(int jid, int hat, int value) {
printf("%08x at %0.3f: Joystick %i (%s) hat %d value %d\n",
counter++, glfwGetTime(),
jid,
glfwGetJoystickName(jid),
hat,
value);
}
static void gamepad_state_callback(int jid, GLFWgamepadstate state) {
int i = 0;
printf("%08x at %0.3f: Gamepad %i (%s) state:",
counter++, glfwGetTime(),
jid,
glfwGetJoystickName(jid));
printf("Buttons: ");
for (i= 0 ; i < 15; i++) {
printf(" %d:%d", i, state.buttons[i]);
}
printf("Axes: ");
for (i= 0 ; i < 6; i++) {
printf(" %d:%0.4f", i, state.axes[i]);
}
printf("\n");
}
int main(int argc, char** argv)
{
Slot* slots;
@ -557,6 +603,10 @@ int main(int argc, char** argv)
glfwSetMonitorCallback(monitor_callback);
glfwSetJoystickCallback(joystick_callback);
glfwSetJoystickAxisCallback(joystick_axis_callback);
glfwSetJoystickButtonCallback(joystick_button_callback);
glfwSetJoystickHatCallback(joystick_hat_callback);
glfwSetGamepadStateCallback(gamepad_state_callback);
while ((ch = getopt(argc, argv, "hfn:")) != -1)
{