From 39f1aea42ce4ab22469b2a663c559617c58802fe Mon Sep 17 00:00:00 2001 From: IntellectualKitty Date: Fri, 25 Nov 2016 20:55:24 -0700 Subject: [PATCH 01/11] Update cocoa_joystick.h --- src/cocoa_joystick.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cocoa_joystick.h b/src/cocoa_joystick.h index 9a5910153..fb46f9071 100644 --- a/src/cocoa_joystick.h +++ b/src/cocoa_joystick.h @@ -51,6 +51,7 @@ typedef struct _GLFWjoystickNS float* axes; unsigned char* buttons; + unsigned char* hats; } _GLFWjoystickNS; From a185cbe9b41a1d3f2a88ac0845950d09363c2fe7 Mon Sep 17 00:00:00 2001 From: IntellectualKitty Date: Fri, 25 Nov 2016 20:56:01 -0700 Subject: [PATCH 02/11] Update cocoa_joystick.m --- src/cocoa_joystick.m | 45 ++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/src/cocoa_joystick.m b/src/cocoa_joystick.m index 72cebcfcd..66896a8a2 100644 --- a/src/cocoa_joystick.m +++ b/src/cocoa_joystick.m @@ -187,6 +187,7 @@ static void removeJoystick(_GLFWjoystickNS* js) free(js->axes); free(js->buttons); + free(js->hats); memset(js, 0, sizeof(_GLFWjoystickNS)); @@ -224,7 +225,6 @@ static GLFWbool pollJoystickAxisEvents(_GLFWjoystickNS* js) static GLFWbool pollJoystickButtonEvents(_GLFWjoystickNS* js) { CFIndex i; - int buttonIndex = 0; if (!js->present) return GLFW_FALSE; @@ -235,29 +235,41 @@ static GLFWbool pollJoystickButtonEvents(_GLFWjoystickNS* js) CFArrayGetValueAtIndex(js->buttonElements, i); if (getElementValue(js, button)) - js->buttons[buttonIndex++] = GLFW_PRESS; + js->buttons[i] = GLFW_PRESS; else - js->buttons[buttonIndex++] = GLFW_RELEASE; + js->buttons[i] = GLFW_RELEASE; } + return GLFW_TRUE; +} + +// Polls for joystick hat events and updates GLFW state +// +static GLFWbool pollJoystickHatEvents(_GLFWjoystickNS* js) +{ + CFIndex i; + + if (!js->present) + return GLFW_FALSE; + for (i = 0; i < CFArrayGetCount(js->hatElements); i++) { _GLFWjoyelementNS* hat = (_GLFWjoyelementNS*) CFArrayGetValueAtIndex(js->hatElements, i); // Bit fields of button presses for each direction, including nil - const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 }; + const unsigned char directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 }; long j, value = getElementValue(js, hat); if (value < 0 || value > 8) value = 8; + js->hats[i] = 0; for (j = 0; j < 4; j++) { - if (directions[value] & (1 << j)) - js->buttons[buttonIndex++] = GLFW_PRESS; - else - js->buttons[buttonIndex++] = GLFW_RELEASE; + unsigned char bit_value = 1 << j; + if (directions[value] & bit_value) + js->hats[i] |= bit_value; } } @@ -321,8 +333,8 @@ static void matchCallback(void* context, CFRelease(arrayRef); js->axes = calloc(CFArrayGetCount(js->axisElements), sizeof(float)); - js->buttons = calloc(CFArrayGetCount(js->buttonElements) + - CFArrayGetCount(js->hatElements) * 4, 1); + js->buttons = calloc(CFArrayGetCount(js->buttonElements), 1); + js->hats = calloc(CFArrayGetCount(js->hatElements), 1); _glfwInputJoystickChange(jid, GLFW_CONNECTED); } @@ -495,11 +507,20 @@ const unsigned char* _glfwPlatformGetJoystickButtons(int jid, int* count) if (!pollJoystickButtonEvents(js)) return NULL; - *count = (int) CFArrayGetCount(js->buttonElements) + - (int) CFArrayGetCount(js->hatElements) * 4; + *count = (int) CFArrayGetCount(js->buttonElements); return js->buttons; } +const unsigned char* _glfwPlatformGetJoystickHats(int jid, int* count) +{ + _GLFWjoystickNS* js = _glfw.ns_js + jid; + if (!pollJoystickHatEvents(js)) + return NULL; + + *count = (int) CFArrayGetCount(js->hatElements); + return js->hats; +} + const char* _glfwPlatformGetJoystickName(int jid) { _GLFWjoystickNS* js = _glfw.ns_js + jid; From 7c2f18b725693ce212b160510f16f6f8a9a351c5 Mon Sep 17 00:00:00 2001 From: IntellectualKitty Date: Fri, 25 Nov 2016 20:56:24 -0700 Subject: [PATCH 03/11] Update input.c --- src/input.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/input.c b/src/input.c index cceae35da..eb70ceaef 100644 --- a/src/input.c +++ b/src/input.c @@ -598,6 +598,22 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count) return _glfwPlatformGetJoystickButtons(jid, count); } +GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count) +{ + assert(count != NULL); + *count = 0; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", jid); + return NULL; + } + + return _glfwPlatformGetJoystickHats(jid, count); +} + GLFWAPI const char* glfwGetJoystickName(int jid) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); From e42c2a4df4471bf1bd01e4f49fda08a241222f6c Mon Sep 17 00:00:00 2001 From: IntellectualKitty Date: Fri, 25 Nov 2016 20:57:32 -0700 Subject: [PATCH 04/11] Update internal.h --- src/internal.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/internal.h b/src/internal.h index 7aea807b5..4c1166eed 100644 --- a/src/internal.h +++ b/src/internal.h @@ -626,6 +626,11 @@ const float* _glfwPlatformGetJoystickAxes(int jid, int* count); */ const unsigned char* _glfwPlatformGetJoystickButtons(int jid, int* count); +/*! @copydoc glfwGetJoystickHats + * @ingroup platform + */ +const unsigned char* _glfwPlatformGetJoystickHats(int jid, int* count); + /*! @copydoc glfwGetJoystickName * @ingroup platform */ From 081f8004ef160ba223e24dced2e7bedea4b424ad Mon Sep 17 00:00:00 2001 From: IntellectualKitty Date: Fri, 25 Nov 2016 20:58:00 -0700 Subject: [PATCH 05/11] Update linux_joystick.c --- src/linux_joystick.c | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/linux_joystick.c b/src/linux_joystick.c index d5b9a28ef..3dd98052d 100644 --- a/src/linux_joystick.c +++ b/src/linux_joystick.c @@ -43,12 +43,17 @@ #endif // __linux__ +// Since Linux does not seem to provide support for hat or POV switches in +// currently, future support for hat events has been stubbed +// in using the #defines JSIOCGHATS and JS_EVENT_HAT to follow the existing +// paradigm. + // Attempt to open the specified joystick device // #if defined(__linux__) static GLFWbool openJoystickDevice(const char* path) { - char axisCount, buttonCount; + char axisCount, buttonCount, hatCount; char name[256] = ""; int jid, fd, version; _GLFWjoystickLinux* js; @@ -101,6 +106,14 @@ static GLFWbool openJoystickDevice(const char* path) js->buttonCount = (int) buttonCount; js->buttons = calloc(buttonCount, 1); +#if defined(JSIOCGHATS) + ioctl(fd, JSIOCGHATS, &hatCount); +#else + hatCount = 0; +#endif + js->hatCount = (int) hatCount; + js->hats = calloc(hatCount, 1); + _glfwInputJoystickChange(jid, GLFW_CONNECTED); return GLFW_TRUE; } @@ -129,6 +142,7 @@ static GLFWbool pollJoystickEvents(_GLFWjoystickLinux* js) { free(js->axes); free(js->buttons); + free(js->hats); free(js->name); free(js->path); @@ -148,6 +162,24 @@ static GLFWbool pollJoystickEvents(_GLFWjoystickLinux* js) js->axes[e.number] = (float) e.value / 32767.0f; else if (e.type == JS_EVENT_BUTTON) js->buttons[e.number] = e.value ? GLFW_PRESS : GLFW_RELEASE; +#if defined(JS_EVENT_HAT) + else if (e.type == JS_EVENT_HAT) + { + const unsigned char directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 }; + int j; + short value = e.value; + if (value < 0 || value > 8) + value = 8; + + js->hats[e.number] = 0; + for (j = 0; j < 4; j++) + { + unsigned char bit_value = 1 << j; + if (directions[value] & bit_value) + js->hats[e.number] |= bit_value; + } + } +#endif } #endif // __linux__ return js->present; @@ -330,6 +362,16 @@ const unsigned char* _glfwPlatformGetJoystickButtons(int jid, int* count) return js->buttons; } +const unsigned char* _glfwPlatformGetJoystickHats(int jid, int* count) +{ + _GLFWjoystickLinux* js = _glfw.linux_js.js + jid; + if (!pollJoystickEvents(js)) + return NULL; + + *count = js->hatCount; + return js->hats; +} + const char* _glfwPlatformGetJoystickName(int jid) { _GLFWjoystickLinux* js = _glfw.linux_js.js + jid; From 049f43a06c82f39e74de49407bb03a1bbb460adc Mon Sep 17 00:00:00 2001 From: IntellectualKitty Date: Fri, 25 Nov 2016 20:58:27 -0700 Subject: [PATCH 06/11] Update linux_joystick.h --- src/linux_joystick.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/linux_joystick.h b/src/linux_joystick.h index 4187b1370..a8ee429df 100644 --- a/src/linux_joystick.h +++ b/src/linux_joystick.h @@ -42,6 +42,8 @@ typedef struct _GLFWjoystickLinux int axisCount; unsigned char* buttons; int buttonCount; + unsigned char* hats; + int hatCount; char* name; char* path; } _GLFWjoystickLinux; From 9343492a7da3151196315602174e8fc4a15b0189 Mon Sep 17 00:00:00 2001 From: IntellectualKitty Date: Fri, 25 Nov 2016 20:58:57 -0700 Subject: [PATCH 07/11] Update win32_joystick.c --- src/win32_joystick.c | 46 +++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/src/win32_joystick.c b/src/win32_joystick.c index e3e9ec6d0..7f2efb75e 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -249,6 +249,7 @@ static void closeJoystick(_GLFWjoystickWin32* js) free(js->name); free(js->axes); free(js->buttons); + free(js->hats); free(js->objects); memset(js, 0, sizeof(_GLFWjoystickWin32)); @@ -431,8 +432,10 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) js->guid = di->guidInstance; js->axisCount = data.axisCount + data.sliderCount; js->axes = calloc(js->axisCount, sizeof(float)); - js->buttonCount += data.buttonCount + data.povCount * 4; + js->buttonCount = data.buttonCount; js->buttons = calloc(js->buttonCount, 1); + js->hatCount = data.povCount; + js->hats = calloc(js->hatCount, 1); js->objects = data.objects; js->objectCount = data.objectCount; js->name = _glfwCreateUTF8FromWideStringWin32(di->tszInstanceName); @@ -476,8 +479,10 @@ static GLFWbool openXinputDevice(DWORD index) js = _glfw.win32_js + jid; js->axisCount = 6; js->axes = calloc(js->axisCount, sizeof(float)); - js->buttonCount = 14; + js->buttonCount = 10; js->buttons = calloc(js->buttonCount, 1); + js->hatCount = 1; + js->hats = calloc(js->hatCount, 1); js->present = GLFW_TRUE; js->name = strdup(getDeviceDescription(&xic)); js->index = index; @@ -496,7 +501,7 @@ static GLFWbool pollJoystickState(_GLFWjoystickWin32* js, int mode) if (js->device) { - int i, j, ai = 0, bi = 0; + int i, j, ai = 0, bi = 0, hi = 0; HRESULT result; DIJOYSTATE state; @@ -547,19 +552,20 @@ static GLFWbool pollJoystickState(_GLFWjoystickWin32* js, int mode) case _GLFW_TYPE_POV: { - const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 }; + const unsigned char directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 }; // Screams of horror are appropriate at this point int value = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES); if (value < 0 || value > 8) value = 8; + js->hats[hi] = 0; for (j = 0; j < 4; j++) { - if (directions[value] & (1 << j)) - js->buttons[bi++] = GLFW_PRESS; - else - js->buttons[bi++] = GLFW_RELEASE; + unsigned char bit_value = 1 << j; + if (directions[value] & bit_value) + js->hats[hi] |= bit_value; } + hi++; break; } @@ -573,7 +579,7 @@ static GLFWbool pollJoystickState(_GLFWjoystickWin32* js, int mode) int i; DWORD result; XINPUT_STATE xis; - const WORD buttons[14] = + const WORD buttons[10] = { XINPUT_GAMEPAD_A, XINPUT_GAMEPAD_B, @@ -584,7 +590,10 @@ static GLFWbool pollJoystickState(_GLFWjoystickWin32* js, int mode) XINPUT_GAMEPAD_BACK, XINPUT_GAMEPAD_START, XINPUT_GAMEPAD_LEFT_THUMB, - XINPUT_GAMEPAD_RIGHT_THUMB, + XINPUT_GAMEPAD_RIGHT_THUMB + }; + const WORD hat_buttons[4] = + { XINPUT_GAMEPAD_DPAD_UP, XINPUT_GAMEPAD_DPAD_RIGHT, XINPUT_GAMEPAD_DPAD_DOWN, @@ -639,9 +648,14 @@ static GLFWbool pollJoystickState(_GLFWjoystickWin32* js, int mode) else js->axes[5] = -1.f; - for (i = 0; i < 14; i++) + for (i = 0; i < 10; i++) js->buttons[i] = (xis.Gamepad.wButtons & buttons[i]) ? 1 : 0; + js->hats[0] = 0; + for (i = 0; i < 4; i++) + if (xis.Gamepad.wButtons & hat_buttons[i]) + js->hats[0] |= 1 << i; + return GLFW_TRUE; } } @@ -752,6 +766,16 @@ const unsigned char* _glfwPlatformGetJoystickButtons(int jid, int* count) return js->buttons; } +const unsigned char* _glfwPlatformGetJoystickHats(int jid, int* count) +{ + _GLFWjoystickWin32* js = _glfw.win32_js + jid; + if (!pollJoystickState(js, _GLFW_UPDATE_STATE)) + return NULL; + + *count = js->hatCount; + return js->hats; +} + const char* _glfwPlatformGetJoystickName(int jid) { _GLFWjoystickWin32* js = _glfw.win32_js + jid; From 882eed59a5a03111d2e80190289a853a487848b1 Mon Sep 17 00:00:00 2001 From: IntellectualKitty Date: Fri, 25 Nov 2016 20:59:31 -0700 Subject: [PATCH 08/11] Update win32_joystick.h --- src/win32_joystick.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/win32_joystick.h b/src/win32_joystick.h index 44ce9531b..9d3041295 100644 --- a/src/win32_joystick.h +++ b/src/win32_joystick.h @@ -47,6 +47,8 @@ typedef struct _GLFWjoystickWin32 int axisCount; unsigned char* buttons; int buttonCount; + unsigned char* hats; + int hatCount; _GLFWjoyobjectWin32* objects; int objectCount; char* name; From 7627c53d625cc87fb5bae9345466fd64419ca737 Mon Sep 17 00:00:00 2001 From: IntellectualKitty Date: Fri, 25 Nov 2016 21:00:05 -0700 Subject: [PATCH 09/11] Update glfw3.h --- include/GLFW/glfw3.h | 71 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 385a04728..4841b7b7d 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -286,6 +286,23 @@ extern "C" { #define GLFW_REPEAT 2 /*! @} */ +/*! @defgroup hat_directions Joystick hat directions + * + * See [joystick hat input](@ref joystick_hat) for how these are used. + * + * @ingroup input + * @{ */ +#define GLFW_HAT_CENTERED 0 +#define GLFW_HAT_UP 1 +#define GLFW_HAT_RIGHT 2 +#define GLFW_HAT_DOWN 4 +#define GLFW_HAT_LEFT 8 +#define GLFW_HAT_RIGHT_UP (GLFW_HAT_RIGHT | GLFW_HAT_UP) +#define GLFW_HAT_RIGHT_DOWN (GLFW_HAT_RIGHT | GLFW_HAT_DOWN) +#define GLFW_HAT_LEFT_UP (GLFW_HAT_LEFT | GLFW_HAT_UP) +#define GLFW_HAT_LEFT_DOWN (GLFW_HAT_LEFT | GLFW_HAT_DOWN) +/*! @} */ + /*! @defgroup keys Keyboard keys * * See [key input](@ref input_key) for how these are used. @@ -3754,6 +3771,60 @@ GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count); */ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count); +/*! @brief Returns the state of all hats of the specified joystick. + * + * This function returns the state of all hats of the specified joystick. + * Each element in the array is one of the following: + * + * GLFW_HAT_CENTERED + * GLFW_HAT_UP + * GLFW_HAT_RIGHT + * GLFW_HAT_DOWN + * GLFW_HAT_LEFT + * GLFW_HAT_RIGHT_UP + * GLFW_HAT_RIGHT_DOWN + * GLFW_HAT_LEFT_UP + * GLFW_HAT_LEFT_DOWN + * + * For masking purposes, the hat state may be ANDed with the following primary + * directions: + * + * GLFW_HAT_UP + * GLFW_HAT_RIGHT + * GLFW_HAT_DOWN + * GLFW_HAT_LEFT + * + * Querying a joystick slot with no device present is not an error, but will + * cause this function to return `NULL`. Call @ref glfwJoystickPresent to + * check device presence. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @param[out] count Where to store the number of hat states in the returned + * array. This is set to zero if the joystick is not present or an error + * occurred. + * @return An array of hat states, or `NULL` if the joystick is not present + * or an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @remark @linux Linux does not currently support hats. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, this function is called again for that joystick or the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_hat + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count); + /*! @brief Returns the name of the specified joystick. * * This function returns the name, encoded as UTF-8, of the specified joystick. From 90a3c7765b684d109f48fec4723ffb11fa16b965 Mon Sep 17 00:00:00 2001 From: IntellectualKitty Date: Fri, 25 Nov 2016 21:00:37 -0700 Subject: [PATCH 10/11] Update events.c --- tests/events.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/events.c b/tests/events.c index fa14ae11b..db405499d 100644 --- a/tests/events.c +++ b/tests/events.c @@ -463,17 +463,19 @@ static void joystick_callback(int jid, int event) { if (event == GLFW_CONNECTED) { - int axisCount, buttonCount; + int axisCount, buttonCount, hatCount; glfwGetJoystickAxes(jid, &axisCount); glfwGetJoystickButtons(jid, &buttonCount); + glfwGetJoystickHats(jid, &hatCount); - printf("%08x at %0.3f: Joystick %i (%s) was connected with %i axes and %i buttons\n", + printf("%08x at %0.3f: Joystick %i (%s) was connected with %i axes, %i buttons, and %i hats\n", counter++, glfwGetTime(), jid, glfwGetJoystickName(jid), axisCount, - buttonCount); + buttonCount, + hatCount); } else { From 1bb5c9250ad158aaaa0713dbf45bca176640a927 Mon Sep 17 00:00:00 2001 From: IntellectualKitty Date: Fri, 25 Nov 2016 21:01:11 -0700 Subject: [PATCH 11/11] Update joysticks.c --- tests/joysticks.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/tests/joysticks.c b/tests/joysticks.c index ca51511fd..b2f45e953 100644 --- a/tests/joysticks.c +++ b/tests/joysticks.c @@ -171,9 +171,10 @@ int main(void) NK_WINDOW_MINIMIZABLE | NK_WINDOW_TITLE)) { - int j, axis_count, button_count; + int j, axis_count, button_count, hat_count; const float* axes; const unsigned char* buttons; + const unsigned char* hats; nk_layout_row_dynamic(nk, 30, 1); @@ -197,6 +198,46 @@ int main(void) } } + nk_layout_row_dynamic(nk, 60, 4); + + hats = glfwGetJoystickHats(joysticks[i], &hat_count); + if (hat_count) + { + for (j = 0; j < hat_count; j++) + { + switch(hats[j]) + { + case GLFW_HAT_CENTERED: + nk_select_label(nk, "centered", NK_TEXT_CENTERED, 0); + break; + case GLFW_HAT_UP: + nk_select_label(nk, "up", NK_TEXT_CENTERED, 1); + break; + case GLFW_HAT_RIGHT: + nk_select_label(nk, "right", NK_TEXT_CENTERED, 1); + break; + case GLFW_HAT_DOWN: + nk_select_label(nk, "down", NK_TEXT_CENTERED, 1); + break; + case GLFW_HAT_LEFT: + nk_select_label(nk, "left", NK_TEXT_CENTERED, 1); + break; + case GLFW_HAT_RIGHT_UP: + nk_select_label(nk, "right_up", NK_TEXT_CENTERED, 1); + break; + case GLFW_HAT_RIGHT_DOWN: + nk_select_label(nk, "right_down", NK_TEXT_CENTERED, 1); + break; + case GLFW_HAT_LEFT_UP: + nk_select_label(nk, "left_up", NK_TEXT_CENTERED, 1); + break; + case GLFW_HAT_LEFT_DOWN: + nk_select_label(nk, "left_down", NK_TEXT_CENTERED, 1); + break; + } + } + } + nk_layout_row_end(nk); }