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.
This commit is contained in:
Beoran 2019-10-31 20:49:39 +01:00
parent 556cc61848
commit f5536ccae0
3 changed files with 231 additions and 2 deletions

View File

@ -1168,6 +1168,17 @@ typedef struct GLFWwindow GLFWwindow;
*/ */
typedef struct GLFWcursor GLFWcursor; typedef struct GLFWcursor GLFWcursor;
/*! @brief Gamepad state object.
*
* Gamepad state object, predeclared here.
*
* @since Added in version 3.4.
*
* @ingroup input
*/
typedef struct GLFWgamepadstate GLFWgamepadstate;
/*! @brief The function pointer type for error callbacks. /*! @brief The function pointer type for error callbacks.
* *
* This is the function pointer type for error callbacks. An error callback * This is the function pointer type for error callbacks. An error callback
@ -1691,6 +1702,26 @@ typedef void (* GLFWjoystickaxisfun)(int,int,float);
*/ */
typedef void (* GLFWjoystickhatfun)(int,int,int); 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 updated state of the game pad.
*
* @sa @ref input_gamepad
* @sa @ref glfwSetGamepadStateCallback
*
* @since Added in version 3.4.
* @ingroup input
*/
typedef void (* GLFWgamepadstatefun)(int,GLFWgamepadstate*);
/*! @brief The function pointer type for Unicode character callbacks. /*! @brief The function pointer type for Unicode character callbacks.
* *
* This is the function pointer type for Unicode character callbacks. * This is the function pointer type for Unicode character callbacks.
@ -1807,6 +1838,7 @@ typedef struct GLFWimage
* *
* @sa @ref gamepad * @sa @ref gamepad
* @sa @ref glfwGetGamepadState * @sa @ref glfwGetGamepadState
* @sa @ref glfwSetGamepadStateCallback
* *
* @since Added in version 3.3. * @since Added in version 3.3.
* *
@ -5237,6 +5269,140 @@ GLFWAPI int glfwJoystickIsGamepad(int jid);
*/ */
GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun callback); 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, GLFWgamepadstate* state)
* @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. /*! @brief Adds the specified SDL_GameControllerDB gamepad mappings.
* *
* This function parses the specified ASCII encoded string and updates the * This function parses the specified ASCII encoded string and updates the

View File

@ -365,6 +365,19 @@ void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths)
window->callbacks.drop((GLFWwindow*) window, count, 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 (glfwJoystickIsGamepad(jid) && (_glfw.callbacks.gamepad_state)) {
GLFWgamepadstate state;
if (0 == glfwGetGamepadState(jid, &state)) {
_glfw.callbacks.gamepad_state(jid, &state);
}
}
}
// Notifies shared code of a joystick connection or disconnection // Notifies shared code of a joystick connection or disconnection
// //
void _glfwInputJoystick(_GLFWjoystick* js, int event) void _glfwInputJoystick(_GLFWjoystick* js, int event)
@ -379,20 +392,33 @@ void _glfwInputJoystick(_GLFWjoystick* js, int event)
// //
void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value) void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value)
{ {
const int jid = (int) (js - _glfw.joysticks);
js->axes[axis] = value; js->axes[axis] = value;
if (_glfw.callbacks.joystick_axis)
_glfw.callbacks.joystick_axis(jid, axis, value);
_glfwInputGamepad(js);
} }
// Notifies shared code of the new value of a joystick button // Notifies shared code of the new value of a joystick button
// //
void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value) void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value)
{ {
const int jid = (int) (js - _glfw.joysticks);
js->buttons[button] = value; js->buttons[button] = value;
if (_glfw.callbacks.joystick_button)
_glfw.callbacks.joystick_button(jid, button, value);
_glfwInputGamepad(js);
} }
// Notifies shared code of the new value of a joystick hat // Notifies shared code of the new value of a joystick hat
// //
void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value) void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value)
{ {
const int jid = (int) (js - _glfw.joysticks);
const int base = js->buttonCount + hat * 4; const int base = js->buttonCount + hat * 4;
js->buttons[base + 0] = (value & 0x01) ? GLFW_PRESS : GLFW_RELEASE; js->buttons[base + 0] = (value & 0x01) ? GLFW_PRESS : GLFW_RELEASE;
@ -401,6 +427,10 @@ void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value)
js->buttons[base + 3] = (value & 0x08) ? GLFW_PRESS : GLFW_RELEASE; js->buttons[base + 3] = (value & 0x08) ? GLFW_PRESS : GLFW_RELEASE;
js->hats[hat] = value; js->hats[hat] = value;
if (_glfw.callbacks.joystick_hat)
_glfw.callbacks.joystick_hat(jid, hat, value);
_glfwInputGamepad(js);
} }
@ -1112,6 +1142,35 @@ GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun)
return cbfun; return cbfun;
} }
GLFWAPI GLFWgamepadstatefun glfwSetGamepadStateCallback(GLFWgamepadstatefun cbfun)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(_glfw.callbacks.gamepad_state, cbfun);
return cbfun;
}
GLFWAPI GLFWjoystickbuttonfun glfwSetJoystickButtonCallback(GLFWjoystickbuttonfun cbfun)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(_glfw.callbacks.joystick_button, cbfun);
return cbfun;
}
GLFWAPI GLFWjoystickaxisfun glfwSetJoystickAxisCallback(GLFWjoystickaxisfun cbfun)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(_glfw.callbacks.joystick_axis, cbfun);
return cbfun;
}
GLFWAPI GLFWjoystickhatfun glfwSetJoystickHatCallback(GLFWjoystickhatfun cbfun)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(_glfw.callbacks.joystick_hat, cbfun);
return cbfun;
}
GLFWAPI int glfwUpdateGamepadMappings(const char* string) GLFWAPI int glfwUpdateGamepadMappings(const char* string)
{ {
int jid; int jid;

View File

@ -567,6 +567,10 @@ struct _GLFWlibrary
struct { struct {
GLFWmonitorfun monitor; GLFWmonitorfun monitor;
GLFWjoystickfun joystick; GLFWjoystickfun joystick;
GLFWjoystickaxisfun joystick_axis;
GLFWjoystickbuttonfun joystick_button;
GLFWjoystickhatfun joystick_hat;
GLFWgamepadstatefun gamepad_state;
} callbacks; } callbacks;
// This is defined in the window API's platform.h // This is defined in the window API's platform.h