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