SDL
SDL copied to clipboard
controller not properly supported after release-2.0.22 on macOS
Summary
I'm trying to get a USB dance mat to work with Project Outfox that uses a recent version of SDL2. When plugging in the controller, it is recognized as being present, but not button presses are seen. I could get it to work using the "SDL2 Gamepad Tool" using SDL version 2.0.7.
The original issue is filed as https://github.com/TeamRizu/OutFox/issues/716
Now, I've dug into it and could narrow it down to changes between release-2.0.22
and release-2.24.0
.
How to reproduce
I've written a small Python test script that will print events related to game pads and joysticks to stdout
that I named sdl_gamepad_test.py
:
#! /usr/bin/env python3
"""Simple test script for USB game pads and SDL2.
This script will run until the "arrow up" on the keyboard is pressed. It will print
messages for plugged and removed game pads and joysticks, and for button presses on those
game pads and joysticks.
2024-01-01, Mark Asbach
"""
import sdl2.ext
sdl2.ext.init(controller=True)
running=True
while running:
events = sdl2.ext.get_events()
for event in events:
if event.type == sdl2.SDL_QUIT:
running = False
break
elif event.type == sdl2.SDL_KEYDOWN:
if event.key.keysym.sym == sdl2.SDLK_UP:
running = False
elif event.type == sdl2.SDL_CONTROLLERDEVICEADDED:
print("Controller added")
controller = sdl2.SDL_GameControllerOpen(event.cdevice.which)
elif event.type == sdl2.SDL_JOYDEVICEADDED:
print("Joystick added")
elif event.type == sdl2.SDL_CONTROLLERDEVICEREMAPPED:
print("Controller remapped")
elif event.type == sdl2.SDL_CONTROLLERDEVICEREMOVED:
print("Controller removed")
elif event.type == sdl2.SDL_JOYDEVICEREMOVED:
print("Joystick removed")
elif event.type == sdl2.SDL_CONTROLLERBUTTONDOWN:
print("Controller button down: " + str(event.cbutton.button))
elif event.type == sdl2.SDL_CONTROLLERBUTTONUP:
print("Controller button up: " + str(event.cbutton.button))
elif event.type == sdl2.SDL_JOYBUTTONDOWN:
print("Joystick button down: " + str(event.cbutton.button))
elif event.type == sdl2.SDL_JOYBUTTONUP:
print("Joystick button up: " + str(event.cbutton.button))
else:
print(event.type)
sdl2.SDL_Delay(10)
These are the steps I do:
- Install a version of SDL2
- Start the script
sdl_gamepad_test.py
- Plug in the dance mat
- Press
start
andup
button on the dance mat - Unplug the dance mat
Expected result
This is the (expected) result when trying the procedure above with SDL version 2.0.22.post1
:
python3.10 -m pip install pysdl2 pysdl2-dll==2.0.22.post1 && python3.10 sdl_gamepad_test.py
UserWarning: Using SDL2 binaries from pysdl2-dll 2.0.22.post1
Controller added
Joystick added
Controller button down: 6
Joystick button down: 9
Controller button up: 6
Joystick button up: 9
Controller removed
Joystick removed
Actual result
This is the (buggy) result when trying the procedure above with SDL version 2.24.0
:
python3.10 -m pip install pysdl2 pysdl2-dll==2.24.0 && python3.10 sdl_gamepad_test.py
UserWarning: Using SDL2 binaries from pysdl2-dll 2.24.0
Joystick added
Joystick removed
Additional info
I've got the following versions of SDL2 that I could test:
2.0.10, 2.0.12, 2.0.14, 2.0.14.post1, 2.0.14.post2, 2.0.16, 2.0.18, 2.0.20, 2.0.22, 2.0.22.post1, 2.24.0, 2.24.1, 2.24.2, 2.26.0, 2.26.1, 2.26.2, 2.26.5, 2.28.0, 2.28.2, 2.28.4, 2.28.5
These are the findings for versions newer that 2.0.22.post1
:
-
2.24.1
,2.24.2
all behave as described for2.24.0
above -
2.26.0
,2.26.1',
2.26.2nearly behave as described for
2.24.0above, but additionally show
Controller removed`:UserWarning: Using SDL2 binaries from pysdl2-dll 2.26.2 Joystick added Controller removed Joystick removed Joystick added Controller removed Joystick removed
-
2.28.0
,2.28.2
,2.28.4
,2.28.5
nearly behave as described for2.26.x
above, but additionally crash with various strange errors when unplugging the dance mat:UserWarning: Using SDL2 binaries from pysdl2-dll 2.28.0 Joystick added Controller removed Joystick removed Joystick added Controller removed Joystick removed zsh: segmentation fault python3.10 sdl_gamepad_test.py
System information
The tests were run on an intel MacBook Pro 2017, using macOS Ventura 13.6.3 (22G436).
I don't have a dance mat for testing. Are you able to debug using lldb on SDL testjoystick to see what's happening?
I could do so in the coming days and will update this ticket.
I'm doing all experiments on 8c9beb0c8
.
Okay, so after getting to compile testjoystick.c
with Xcode, I could dig a bit. I don't understand it fully, but it seems that based on some random (timing?) effects, the dance mat is found by SDL_iokitjoystick
or not. Every time, though, the dance mat is found by SDL_mfijoystick
. That explains why it is sometimes found twice by OutFox and by Python test code.
SDL_mfijoystick
reports a device with nbuttons=0
and no other inputs - it is basically non-working. SDL_iokitjoystick
reports nbuttons=10
, axes=5
for my dance mat. That's the working device.
So, when I comment out the IOKit driver in SDL_joystick.c
as follows (lines 72++), sometimes a plugged in joypad is not recognised at all, but if it is recognised, it will work:
#ifdef SDL_JOYSTICK_IOKIT
&SDL_DARWIN_JoystickDriver,
#endif
//#if (defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__TVOS__)) && !defined(SDL_JOYSTICK_DISABLED)
// &SDL_IOS_JoystickDriver,
//#endif
Can someone here make any sense out of this and/or help me fix the issue?
An unrelated remark: The output on testjoystick.c
about event.jdevice.which
is strange. When SDL_JOYDEVICEADDED
gets reported, the number is typically 0 (after I commented out mfijoystick), but the numbers reported by SDL_JOYDEVICEREMOVED
and the SDL_JoystickInstanceID(joy)
are incrementing with every unplug/replug cycle.
SDL_mfijoystick
reports a device withnbuttons=0
and no other inputs - it is basically non-working.SDL_iokitjoystick
reportsnbuttons=10
,axes=5
for my dance mat. That's the working device.
I think in your case, you just need to disable the MFi joystick driver. What's happening is that GCController is reporting that the dance mat is handled by that driver but then doesn't actually know how to handle it.
You can disable it by setting the environment variable SDL_JOYSTICK_MFI=1
An unrelated remark: The output on
testjoystick.c
aboutevent.jdevice.which
is strange. WhenSDL_JOYDEVICEADDED
gets reported, the number is typically 0 (after I commented out mfijoystick), but the numbers reported bySDL_JOYDEVICEREMOVED
and theSDL_JoystickInstanceID(joy)
are incrementing with every unplug/replug cycle.
SDL_JOYDEVICEADDED reports indices, the other APIs report instance IDs. This is fixed in SDL3 where instance IDs are used in all cases.
I'll leave this open for now, but short of somebody from Apple stopping by and letting us know they have a fix, I don't think there's anything we can do.
Actually, I just double checked and we've done a bunch of MFi driver improvements since the version you're testing. Can you update to the latest SDL2 code and check that?
I've done so, but (please compare my tests from Python) there was little further insight I could gain:
As described above, tag 2.28.5
crashes randomly but frequently when plugging, unplugging, even when doing nothing while the device is plugged. There is something deeply broken in respect to Cocoa event handling in newer versions at it looks like. You can see that from my reports gathered using the Python module. Strangely, I've got a Logitech Gamepad F310 that will not trigger any crashes when plugged.
Regarding the actual issue here, support for my dance mat: in contrast to 8c9beb0c8
, no SDL_iokitjoystick
picks up the device, but the SDL_mfijoystick
always reports the device back, but with 0 buttons, 0 axes, etc.
I've looked at git diff -r 8c9beb0c8 src/joystick/darwin/SDL_iokitjoystick.c
and there are mostly formatting changes, just one functional change: GetDeviceInfo()
has been slightly modified. Maybe I'll have some time on the weekend to check if that change leads to SDL_iokitjoystick
not picking it up. That would still mean, I'd have to disable the MFi driver when trying to use this dance mat. The Logitech Gamepad F310, though, is picked up by exactly that MFi driver. So it seems the issue is routed somewhere deep in the code (that does not have too many lines ...).
Not sure what direction I could look into to take this further.
Can you post an Amazon link? Maybe I can pick up that dance mat and investigate further. I also haven't seen any crashes, so I'm not sure if it's specific to that device or a general problem.
Can you post an Amazon link? Maybe I can pick up that dance mat and investigate further.
It's this one: https://www.amazon.de/dp/B00FJ2KTXC/
Okay, I bought this mat, I should get it in a month or so and will take a look.