Summary
Many perfectly ordinary gamepads report nothing at all through the current IsGamepadButtonDown / GetGamepadAxisMovement intrinsics — no buttons, no D-pad, no sticks — even though IsGamepadAvailable returns true and GetGamepadName returns the right name. This is a limitation of raylib's GLFW backend, not of our bindings, but it means raylib-miniscript currently can't use hardware that works fine in Mini Micro.
I'd like to propose exposing raw joystick access to work around it.
What happens
Found while adding key.axis and joystick button support to Soda. With a USB gamepad connected on macOS:
slot 0: available = 1, name = USB,2-axis 8-button gamepad , axisCount = 6
...and then nothing. Mashing every button and the D-pad produces no change in any button or axis, forever. The only non-zero readings are axis4 = -1 and axis5 = -1, constant.
The same gamepad works correctly in Mini Micro, which reports the D-pad as JoyAxis1/JoyAxis2 and buttons 0-5.
Why
raylib reads gamepad state exclusively through glfwGetGamepadState() (rcore_desktop_glfw.c:1325). That function returns GLFW_FALSE unless GLFW holds a valid SDL-style mapping for the device:
// glfw/src/input.c:1401
if (!js->mapping)
return GLFW_FALSE;
When it fails, raylib zeroes every button and axis and parks the two triggers at -1.0f — exactly the readings above. So the constant -1s are raylib's "no data" sentinel, not hardware.
Two independent things then conspire to deny this device a mapping:
-
Platform filtering. GLFW rejects any mapping whose platform: field doesn't match the host (Mac OS X via _glfwGetMappingNameCocoa, cocoa_joystick.m:469). The only bundled entry for this device (03000000830500006020000000000000,Retro Controller,...) is tagged platform:Windows.
-
All-or-nothing element validation. findValidMapping (input.c:100) discards the entire mapping if it references any element the device lacks. The bundled entry reaches for rightshoulder:b8 and righttrigger:b9, but this pad's HID descriptor reports only 2 axes and 8 buttons (b0-b7). One out-of-range index kills the whole pad.
I confirmed the diagnosis by supplying a corrected mapping via SetGamepadMappings — retagged platform:Mac OS X and restricted to a0-a1/b0-b7. The gamepad then works fully.
Worth noting: SetGamepadMappings returns 1 even when every line it was given is rejected — glfwUpdateGamepadMappings returns GLFW_TRUE unconditionally. So the current API gives a caller no way to tell whether a mapping was actually accepted.
Also, GetGamepadAxisCount is misleading: raylib hardcodes it to GLFW_GAMEPAD_AXIS_LAST + 1 (always 6, rcore_desktop_glfw.c:1396), so it never reflects the real device.
Why mappings alone aren't a fix
Shipping gamecontrollerdb.txt and feeding it to SetGamepadMappings is the usual advice, and it would help many devices. It does not help this one: the community entry is not merely wrong-platform, it's written for a 10-button variant sharing the same vendor/product ID. Cheap generic pads are both the most likely to have sloppy database entries and the most likely to be plugged into a hobbyist game engine.
Fundamentally, the gamepad mapping layer is designed to normalize devices into an Xbox-shaped abstraction. When it can't, raylib's API offers no fallback — the device becomes invisible even though GLFW is still perfectly happy to report its raw axes and buttons.
Proposal: raw joystick intrinsics
Expose the raw side of GLFW's joystick API, which needs no mapping:
| Intrinsic |
Wraps |
Returns |
IsJoystickPresent(joystick=0) |
glfwJoystickPresent |
0/1 |
GetJoystickName(joystick=0) |
glfwGetJoystickName |
string |
GetJoystickAxes(joystick=0) |
glfwGetJoystickAxes |
list of numbers, -1..1 |
GetJoystickButtons(joystick=0) |
glfwGetJoystickButtons |
list of 0/1 |
GetJoystickHats(joystick=0) |
glfwGetJoystickHats |
list of bitmasks |
GetJoystickGUID(joystick=0) |
glfwGetJoystickGUID |
string |
This matches how Unity (and therefore Mini Micro) reads controllers, and it makes any device usable without database entries. GetJoystickGUID is valuable on its own — right now there's no way for a script to discover the GUID it would need in order to write a mapping.
The tradeoffs are real and worth discussing before anyone writes code:
- It reaches past raylib to GLFW directly. raylib deliberately doesn't expose these. It means including
GLFW/glfw3.h and depending on the desktop GLFW backend specifically.
- It won't work on the web build. Emscripten uses a different input path; these would need stubbing or a separate implementation.
- Raw axis/button indices are device-specific, which is exactly what the mapping layer exists to avoid. This is a fallback for when mapping fails, not a replacement — the existing gamepad API should stay the recommended path.
If reaching into GLFW is unappealing, a narrower alternative would be to expose GetGamepadGUID plus a SetGamepadMappings that reports how many mappings were actually accepted. That would at least let a script detect the failure and supply its own mapping, rather than silently seeing a dead controller.
Happy to take a run at whichever direction you prefer.
Summary
Many perfectly ordinary gamepads report nothing at all through the current
IsGamepadButtonDown/GetGamepadAxisMovementintrinsics — no buttons, no D-pad, no sticks — even thoughIsGamepadAvailablereturns true andGetGamepadNamereturns the right name. This is a limitation of raylib's GLFW backend, not of our bindings, but it means raylib-miniscript currently can't use hardware that works fine in Mini Micro.I'd like to propose exposing raw joystick access to work around it.
What happens
Found while adding
key.axisand joystick button support to Soda. With a USB gamepad connected on macOS:...and then nothing. Mashing every button and the D-pad produces no change in any button or axis, forever. The only non-zero readings are
axis4 = -1andaxis5 = -1, constant.The same gamepad works correctly in Mini Micro, which reports the D-pad as
JoyAxis1/JoyAxis2and buttons 0-5.Why
raylib reads gamepad state exclusively through
glfwGetGamepadState()(rcore_desktop_glfw.c:1325). That function returnsGLFW_FALSEunless GLFW holds a valid SDL-style mapping for the device:When it fails, raylib zeroes every button and axis and parks the two triggers at
-1.0f— exactly the readings above. So the constant-1s are raylib's "no data" sentinel, not hardware.Two independent things then conspire to deny this device a mapping:
Platform filtering. GLFW rejects any mapping whose
platform:field doesn't match the host (Mac OS Xvia_glfwGetMappingNameCocoa,cocoa_joystick.m:469). The only bundled entry for this device (03000000830500006020000000000000,Retro Controller,...) is taggedplatform:Windows.All-or-nothing element validation.
findValidMapping(input.c:100) discards the entire mapping if it references any element the device lacks. The bundled entry reaches forrightshoulder:b8andrighttrigger:b9, but this pad's HID descriptor reports only 2 axes and 8 buttons (b0-b7). One out-of-range index kills the whole pad.I confirmed the diagnosis by supplying a corrected mapping via
SetGamepadMappings— retaggedplatform:Mac OS Xand restricted toa0-a1/b0-b7. The gamepad then works fully.Worth noting:
SetGamepadMappingsreturns 1 even when every line it was given is rejected —glfwUpdateGamepadMappingsreturnsGLFW_TRUEunconditionally. So the current API gives a caller no way to tell whether a mapping was actually accepted.Also,
GetGamepadAxisCountis misleading: raylib hardcodes it toGLFW_GAMEPAD_AXIS_LAST + 1(always 6,rcore_desktop_glfw.c:1396), so it never reflects the real device.Why mappings alone aren't a fix
Shipping
gamecontrollerdb.txtand feeding it toSetGamepadMappingsis the usual advice, and it would help many devices. It does not help this one: the community entry is not merely wrong-platform, it's written for a 10-button variant sharing the same vendor/product ID. Cheap generic pads are both the most likely to have sloppy database entries and the most likely to be plugged into a hobbyist game engine.Fundamentally, the gamepad mapping layer is designed to normalize devices into an Xbox-shaped abstraction. When it can't, raylib's API offers no fallback — the device becomes invisible even though GLFW is still perfectly happy to report its raw axes and buttons.
Proposal: raw joystick intrinsics
Expose the raw side of GLFW's joystick API, which needs no mapping:
IsJoystickPresent(joystick=0)glfwJoystickPresentGetJoystickName(joystick=0)glfwGetJoystickNameGetJoystickAxes(joystick=0)glfwGetJoystickAxesGetJoystickButtons(joystick=0)glfwGetJoystickButtonsGetJoystickHats(joystick=0)glfwGetJoystickHatsGetJoystickGUID(joystick=0)glfwGetJoystickGUIDThis matches how Unity (and therefore Mini Micro) reads controllers, and it makes any device usable without database entries.
GetJoystickGUIDis valuable on its own — right now there's no way for a script to discover the GUID it would need in order to write a mapping.The tradeoffs are real and worth discussing before anyone writes code:
GLFW/glfw3.hand depending on the desktop GLFW backend specifically.If reaching into GLFW is unappealing, a narrower alternative would be to expose
GetGamepadGUIDplus aSetGamepadMappingsthat reports how many mappings were actually accepted. That would at least let a script detect the failure and supply its own mapping, rather than silently seeing a dead controller.Happy to take a run at whichever direction you prefer.