From f5536ccae0a751994a0cfdf6541a841a2198482f Mon Sep 17 00:00:00 2001 From: Beoran Date: Thu, 31 Oct 2019 20:49:39 +0100 Subject: [PATCH] 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. --- include/GLFW/glfw3.h | 166 +++++++++++++++++++++++++++++++++++++++++++ src/input.c | 59 +++++++++++++++ src/internal.h | 8 ++- 3 files changed, 231 insertions(+), 2 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 4460d94c..34713091 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1168,6 +1168,17 @@ typedef struct GLFWwindow GLFWwindow; */ 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. * * 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); +/*! @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. * * This is the function pointer type for Unicode character callbacks. @@ -1807,6 +1838,7 @@ typedef struct GLFWimage * * @sa @ref gamepad * @sa @ref glfwGetGamepadState + * @sa @ref glfwSetGamepadStateCallback * * @since Added in version 3.3. * @@ -5237,6 +5269,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, 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. * * This function parses the specified ASCII encoded string and updates the diff --git a/src/input.c b/src/input.c index 28291750..6d07ce73 100644 --- a/src/input.c +++ b/src/input.c @@ -365,6 +365,19 @@ 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 (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 // void _glfwInputJoystick(_GLFWjoystick* js, int event) @@ -379,20 +392,33 @@ void _glfwInputJoystick(_GLFWjoystick* js, int event) // void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float 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); } // Notifies shared code of the new value of a joystick button // void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char 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); } // Notifies shared code of the new value of a joystick hat // void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value) { + const int jid = (int) (js - _glfw.joysticks); const int base = js->buttonCount + hat * 4; 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->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; } +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) { int jid; diff --git a/src/internal.h b/src/internal.h index acdae22d..c135083f 100644 --- a/src/internal.h +++ b/src/internal.h @@ -565,8 +565,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; // This is defined in the window API's platform.h