From ee4132b5cfb278b9660eedff55f283f0aaab4645 Mon Sep 17 00:00:00 2001 From: Beoran Date: Thu, 7 Nov 2019 01:01:31 +0100 Subject: [PATCH] Test and fix joystick and game pad callbacks on Linux. --- include/GLFW/glfw3.h | 22 ++++++---------- src/input.c | 27 ++++++++++++++++---- src/internal.h | 1 + src/window.c | 2 ++ src/x11_window.c | 60 +++++++++++++++++++++++++++++++------------- tests/events.c | 50 ++++++++++++++++++++++++++++++++++++ 6 files changed, 125 insertions(+), 37 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 34713091..21ae6ce3 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1168,17 +1168,6 @@ 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 @@ -1711,7 +1700,11 @@ typedef void (* GLFWjoystickhatfun)(int,int,int); * @endcode * * @param[in] jid The ID of the game pad that changed state. - * @param[in] state The updated state of the game pad. + * @param[in] buttons The states of each + * [gamepad button](@ref gamepad_buttons), + * `GLFW_PRESS` or `GLFW_RELEASE`. + * @param[in] axes The states of each [gamepad axis](@ref gamepad_axes), + * in the range -1.0 to 1.0 inclusive. * * @sa @ref input_gamepad * @sa @ref glfwSetGamepadStateCallback @@ -1719,7 +1712,8 @@ typedef void (* GLFWjoystickhatfun)(int,int,int); * @since Added in version 3.4. * @ingroup input */ -typedef void (* GLFWgamepadstatefun)(int,GLFWgamepadstate*); +typedef void (* GLFWgamepadstatefun)(int, unsigned char buttons[15], + float axes[6]); /*! @brief The function pointer type for Unicode character callbacks. @@ -5385,7 +5379,7 @@ GLFWAPI GLFWjoystickhatfun glfwSetJoystickHatCallback(GLFWjoystickhatfun callbac * * @callback_signature * @code - * void function_name(int jid, GLFWgamepadstate* state) + * 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). diff --git a/src/input.c b/src/input.c index 6d07ce73..3664379b 100644 --- a/src/input.c +++ b/src/input.c @@ -370,10 +370,15 @@ void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths) void _glfwInputGamepad(_GLFWjoystick* js) { const int jid = (int) (js - _glfw.joysticks); - if (glfwJoystickIsGamepad(jid) && (_glfw.callbacks.gamepad_state)) { + + if (!_glfw.initialized) { + return; + } + + if ((js->mapping != NULL) && (_glfw.callbacks.gamepad_state)) { GLFWgamepadstate state; - if (0 == glfwGetGamepadState(jid, &state)) { - _glfw.callbacks.gamepad_state(jid, &state); + if (glfwGetGamepadState(jid, &state)) { + _glfw.callbacks.gamepad_state(jid, state.buttons, state.axes); } } } @@ -394,10 +399,11 @@ void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value) { const int jid = (int) (js - _glfw.joysticks); + if ((_glfw.callbacks.joystick_axis) && (js->axes[axis] != value)) + _glfw.callbacks.joystick_axis(jid, axis, value); + js->axes[axis] = value; - if (_glfw.callbacks.joystick_axis) - _glfw.callbacks.joystick_axis(jid, axis, value); _glfwInputGamepad(js); } @@ -495,6 +501,17 @@ void _glfwCenterCursorInContentArea(_GLFWwindow* window) _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); } +void _glfwPollAllJoysticks() { + int jid; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + if (_glfw.joysticks[jid].present == GLFW_TRUE) { + _glfwPlatformPollJoystick(_glfw.joysticks + jid, _GLFW_POLL_ALL); + } + } +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW public API ////// diff --git a/src/internal.h b/src/internal.h index c135083f..4fdd4780 100644 --- a/src/internal.h +++ b/src/internal.h @@ -769,6 +769,7 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name, int hatCount); void _glfwFreeJoystick(_GLFWjoystick* js); void _glfwCenterCursorInContentArea(_GLFWwindow* window); +void _glfwPollAllJoysticks(); GLFWbool _glfwInitVulkan(int mode); void _glfwTerminateVulkan(void); diff --git a/src/window.c b/src/window.c index fa604d01..a8a00c3e 100644 --- a/src/window.c +++ b/src/window.c @@ -1069,12 +1069,14 @@ GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow* GLFWAPI void glfwPollEvents(void) { _GLFW_REQUIRE_INIT(); + _glfwPollAllJoysticks(); _glfwPlatformPollEvents(); } GLFWAPI void glfwWaitEvents(void) { _GLFW_REQUIRE_INIT(); + _glfwPollAllJoysticks(); _glfwPlatformWaitEvents(); } diff --git a/src/x11_window.c b/src/x11_window.c index 56379a3c..b1182735 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -65,21 +65,32 @@ static GLFWbool waitForEvent(double* timeout) { fd_set fds; const int fd = ConnectionNumber(_glfw.x11.display); - int count = fd + 1; - -#if defined(__linux__) - if (_glfw.linjs.inotify > fd) - count = _glfw.linjs.inotify + 1; -#endif for (;;) { + int count = fd + 1; FD_ZERO(&fds); FD_SET(fd, &fds); + #if defined(__linux__) if (_glfw.linjs.inotify > 0) - FD_SET(_glfw.linjs.inotify, &fds); -#endif + { + if (_glfw.linjs.inotify >= count ) + count = _glfw.linjs.inotify + 1; + FD_SET(_glfw.linjs.inotify, &fds); + } + + for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + if (_glfw.joysticks[jid].present) { + if (_glfw.joysticks[jid].linjs.fd >= count) + count = _glfw.joysticks[jid].linjs.fd + 1; + + FD_SET(_glfw.joysticks[jid].linjs.fd, &fds); + } + } + +#endif if (timeout) { const long seconds = (long) *timeout; @@ -2681,6 +2692,7 @@ void _glfwPlatformPollEvents(void) #if defined(__linux__) _glfwDetectJoystickConnectionLinux(); + _glfwPollAllJoysticks(); #endif XPending(_glfw.x11.display); @@ -2709,23 +2721,35 @@ void _glfwPlatformPollEvents(void) XFlush(_glfw.x11.display); } -void _glfwPlatformWaitEvents(void) +static GLFWbool waitForAndPollEvents(double * timeout) { - while (!XPending(_glfw.x11.display)) - waitForEvent(NULL); + GLFWbool result = GLFW_FALSE; + for (;;) + { + int xpending = XPending(_glfw.x11.display); + GLFWbool event = waitForEvent(timeout); + // We cannot use the boolean shortcut here, since + // waiting for events might have a side effect. + if (event || xpending ) + { + result = GLFW_TRUE; + break; + } + } _glfwPlatformPollEvents(); + return result; +} + + +void _glfwPlatformWaitEvents(void) +{ + waitForAndPollEvents(NULL); } void _glfwPlatformWaitEventsTimeout(double timeout) { - while (!XPending(_glfw.x11.display)) - { - if (!waitForEvent(&timeout)) - break; - } - - _glfwPlatformPollEvents(); + waitForAndPollEvents(&timeout); } void _glfwPlatformPostEmptyEvent(void) diff --git a/tests/events.c b/tests/events.c index 251e15d9..043436f4 100644 --- a/tests/events.c +++ b/tests/events.c @@ -494,6 +494,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, unsigned char buttons[15], float axes[6]) { + 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, buttons[i]); + } + printf("Axes: "); + for (i= 0 ; i < 6; i++) { + printf(" %d:%0.4f", i, axes[i]); + } + printf("\n"); + +} + + int main(int argc, char** argv) { Slot* slots; @@ -511,6 +557,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) {