From 416f7828ffe1cb23406ca7223dc06a5d150e3e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 5 May 2022 22:23:12 +0200 Subject: [PATCH] Fix joystick user pointer NULL during disconnect The joystick code did not distinguish between the allocation status of the GLFW joystick object and whether it is connection to an OS level joystick object. These are now tracked separately. Fixes #2092 This is adapted to 3.3-stable from 2c204ab52ecaa51bfd32b777aef715dae937f009 and fd7e737216dfdcecd4522b7d8c8dd2439d3dac3b. --- CONTRIBUTORS.md | 1 + README.md | 1 + src/cocoa_joystick.m | 15 ++++++++------- src/input.c | 35 ++++++++++++++++++++--------------- src/internal.h | 3 ++- src/linux_joystick.c | 8 ++++---- src/win32_joystick.c | 10 +++++----- 7 files changed, 41 insertions(+), 32 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 36a040e2..41efe310 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -136,6 +136,7 @@ video tutorials. - Kenneth Miller - Bruce Mitchener - Jack Moffitt + - Ravi Mohan - Jeff Molofee - Alexander Monakov - Pierre Morel diff --git a/README.md b/README.md index 61b20c71..26a6092a 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,7 @@ information on what to include when reporting a bug. - Bugfix: `glfwMakeContextCurrent` would access TLS slot before initialization - Bugfix: `glfwSetGammaRamp` could emit `GLFW_INVALID_VALUE` before initialization + - Bugfix: `glfwGetJoystickUserPointer` returned `NULL` during disconnection (#2092) - [Win32] Bugfix: `Alt+PrtSc` would emit `GLFW_KEY_UNKNOWN` and a different scancode than `PrtSc` (#1993) - [Win32] Bugfix: `GLFW_KEY_PAUSE` scancode from `glfwGetKeyScancode` did not diff --git a/src/cocoa_joystick.m b/src/cocoa_joystick.m index 2c8d82d9..3d306777 100644 --- a/src/cocoa_joystick.m +++ b/src/cocoa_joystick.m @@ -98,8 +98,7 @@ static void closeJoystick(_GLFWjoystick* js) { int i; - if (!js->present) - return; + _glfwInputJoystick(js, GLFW_DISCONNECTED); for (i = 0; i < CFArrayGetCount(js->ns.axes); i++) free((void*) CFArrayGetValueAtIndex(js->ns.axes, i)); @@ -114,7 +113,6 @@ static void closeJoystick(_GLFWjoystick* js) CFRelease(js->ns.hats); _glfwFreeJoystick(js); - _glfwInputJoystick(js, GLFW_DISCONNECTED); } // Callback for user-initiated joystick addition @@ -294,9 +292,9 @@ static void removeCallback(void* context, for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { - if (_glfw.joysticks[jid].ns.device == device) + if (_glfw.joysticks[jid].connected && _glfw.joysticks[jid].ns.device == device) { - closeJoystick(_glfw.joysticks + jid); + closeJoystick(&_glfw.joysticks[jid]); break; } } @@ -392,7 +390,10 @@ void _glfwTerminateJoysticksNS(void) int jid; for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) - closeJoystick(_glfw.joysticks + jid); + { + if (_glfw.joysticks[jid].connected) + closeJoystick(&_glfw.joysticks[jid]); + } CFRelease(_glfw.ns.hidManager); _glfw.ns.hidManager = NULL; @@ -470,7 +471,7 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) } } - return js->present; + return js->connected; } void _glfwPlatformUpdateGamepadGUID(char* guid) diff --git a/src/input.c b/src/input.c index f6c1ed79..7ea1222c 100644 --- a/src/input.c +++ b/src/input.c @@ -360,6 +360,11 @@ void _glfwInputJoystick(_GLFWjoystick* js, int event) { const int jid = (int) (js - _glfw.joysticks); + if (event == GLFW_CONNECTED) + js->connected = GLFW_TRUE; + else if (event == GLFW_DISCONNECTED) + js->connected = GLFW_FALSE; + if (_glfw.callbacks.joystick) _glfw.callbacks.joystick(jid, event); } @@ -415,7 +420,7 @@ void _glfwInitGamepadMappings(void) for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { _GLFWjoystick* js = _glfw.joysticks + jid; - if (js->present) + if (js->connected) js->mapping = findValidMapping(js); } } @@ -433,7 +438,7 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name, for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { - if (!_glfw.joysticks[jid].present) + if (!_glfw.joysticks[jid].allocated) break; } @@ -441,7 +446,7 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name, return NULL; js = _glfw.joysticks + jid; - js->present = GLFW_TRUE; + js->allocated = GLFW_TRUE; js->axes = calloc(axisCount, sizeof(float)); js->buttons = calloc(buttonCount + (size_t) hatCount * 4, 1); js->hats = calloc(hatCount, 1); @@ -944,7 +949,7 @@ GLFWAPI int glfwJoystickPresent(int jid) } js = _glfw.joysticks + jid; - if (!js->present) + if (!js->connected) return GLFW_FALSE; return _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); @@ -969,7 +974,7 @@ GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count) } js = _glfw.joysticks + jid; - if (!js->present) + if (!js->connected) return NULL; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_AXES)) @@ -998,7 +1003,7 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count) } js = _glfw.joysticks + jid; - if (!js->present) + if (!js->connected) return NULL; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS)) @@ -1031,7 +1036,7 @@ GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count) } js = _glfw.joysticks + jid; - if (!js->present) + if (!js->connected) return NULL; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS)) @@ -1057,7 +1062,7 @@ GLFWAPI const char* glfwGetJoystickName(int jid) } js = _glfw.joysticks + jid; - if (!js->present) + if (!js->connected) return NULL; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) @@ -1082,7 +1087,7 @@ GLFWAPI const char* glfwGetJoystickGUID(int jid) } js = _glfw.joysticks + jid; - if (!js->present) + if (!js->connected) return NULL; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) @@ -1101,7 +1106,7 @@ GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer) _GLFW_REQUIRE_INIT(); js = _glfw.joysticks + jid; - if (!js->present) + if (!js->allocated) return; js->userPointer = pointer; @@ -1117,7 +1122,7 @@ GLFWAPI void* glfwGetJoystickUserPointer(int jid) _GLFW_REQUIRE_INIT_OR_RETURN(NULL); js = _glfw.joysticks + jid; - if (!js->present) + if (!js->allocated) return NULL; return js->userPointer; @@ -1183,7 +1188,7 @@ GLFWAPI int glfwUpdateGamepadMappings(const char* string) for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { _GLFWjoystick* js = _glfw.joysticks + jid; - if (js->present) + if (js->connected) js->mapping = findValidMapping(js); } @@ -1206,7 +1211,7 @@ GLFWAPI int glfwJoystickIsGamepad(int jid) } js = _glfw.joysticks + jid; - if (!js->present) + if (!js->connected) return GLFW_FALSE; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) @@ -1231,7 +1236,7 @@ GLFWAPI const char* glfwGetGamepadName(int jid) } js = _glfw.joysticks + jid; - if (!js->present) + if (!js->connected) return NULL; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) @@ -1263,7 +1268,7 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) } js = _glfw.joysticks + jid; - if (!js->present) + if (!js->connected) return GLFW_FALSE; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_ALL)) diff --git a/src/internal.h b/src/internal.h index 3e9283a3..7734caa3 100644 --- a/src/internal.h +++ b/src/internal.h @@ -478,7 +478,8 @@ struct _GLFWmapping // struct _GLFWjoystick { - GLFWbool present; + GLFWbool allocated; + GLFWbool connected; float* axes; int axisCount; unsigned char* buttons; diff --git a/src/linux_joystick.c b/src/linux_joystick.c index 5a3b806c..0894a726 100644 --- a/src/linux_joystick.c +++ b/src/linux_joystick.c @@ -128,7 +128,7 @@ static GLFWbool openJoystickDevice(const char* path) { for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { - if (!_glfw.joysticks[jid].present) + if (!_glfw.joysticks[jid].connected) continue; if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0) return GLFW_FALSE; @@ -245,9 +245,9 @@ static GLFWbool openJoystickDevice(const char* path) // static void closeJoystick(_GLFWjoystick* js) { + _glfwInputJoystick(js, GLFW_DISCONNECTED); close(js->linjs.fd); _glfwFreeJoystick(js); - _glfwInputJoystick(js, GLFW_DISCONNECTED); } // Lexically compare joysticks by name; used by qsort @@ -329,7 +329,7 @@ void _glfwTerminateJoysticksLinux(void) for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { _GLFWjoystick* js = _glfw.joysticks + jid; - if (js->present) + if (js->connected) closeJoystick(js); } @@ -424,7 +424,7 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) handleAbsEvent(js, e.code, e.value); } - return js->present; + return js->connected; } void _glfwPlatformUpdateGamepadGUID(char* guid) diff --git a/src/win32_joystick.c b/src/win32_joystick.c index 67e3465c..f471f0a9 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -256,6 +256,8 @@ static GLFWbool supportsXInput(const GUID* guid) // static void closeJoystick(_GLFWjoystick* js) { + _glfwInputJoystick(js, GLFW_DISCONNECTED); + if (js->win32.device) { IDirectInputDevice8_Unacquire(js->win32.device); @@ -263,9 +265,7 @@ static void closeJoystick(_GLFWjoystick* js) } free(js->win32.objects); - _glfwFreeJoystick(js); - _glfwInputJoystick(js, GLFW_DISCONNECTED); } // DirectInput device object enumeration callback @@ -357,7 +357,7 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { js = _glfw.joysticks + jid; - if (js->present) + if (js->connected) { if (memcmp(&js->win32.guid, &di->guidInstance, sizeof(GUID)) == 0) return DIENUM_CONTINUE; @@ -541,7 +541,7 @@ void _glfwDetectJoystickConnectionWin32(void) for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { - if (_glfw.joysticks[jid].present && + if (_glfw.joysticks[jid].connected && _glfw.joysticks[jid].win32.device == NULL && _glfw.joysticks[jid].win32.index == index) { @@ -593,7 +593,7 @@ void _glfwDetectJoystickDisconnectionWin32(void) for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { _GLFWjoystick* js = _glfw.joysticks + jid; - if (js->present) + if (js->connected) _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); } }