After seeing threads about people disabling Steam’s self-updating and replacing Steam’s SDL2.dll with versions with that have XInput disabled, in order to fix games that get artificially capped at 4 controllers, I think it’s time to fix SDL to support more than 4 XInput-capable controllers by default.
Obviously, any game can just disable XInput and, for the most part, things will just be better (especially on low-end systems where, at low framerates, the evented DirectInput will miss fewer button presses than the polling XInput) - unless they want to use both triggers at once or rumble. But, I’ve got a lot of games in my Steam library that don’t do that, and have to be coerced into supporting more than 4 XInput-capable devices by disabling XInput via DLL patches or environment variables. These games usually use SDL directly, but apparently newer games (Super Bomberman R, for instance) are using SteamInput which is using SDL in XInput-mode, and not allowing more than 4 players by default (unless you use non-XInput-compatible controllers).
So, I propose a fix!
Fix #1: There’s a relatively simple, fool-proof solution - if, when iterating DirectInput controllers, more than 4 are found, disable XInput as if SDL_XINPUT_ENABLED=0 was set.
Fix #2: I’d rather get the best of both worlds though - XInput for the first 4 controllers, DirectInput for the rest. The way to do this is, when there are more than 4 devices, to correlate inputs between DirectInput and XInput devices to determine which DirectInput devices do not have a paired XInput device. In order to do this within SDL, I would need to make the following changes:
- When updating the list of devices, if there are more than 4 DirectInput-visible XInput-capable devices, add some virtual “XInput Controller #5”, etc, devices
- Open all XInput-capable DirectInput devices and XInput devices (either immediately, or when the user opens their first joystick), and keep them open (to keep a few bytes of state for correlation), though not emitting events unless they’ve been opened by the user
- If we still have some virtual devices, after each joystick update in which relevant state changed, do a correlation check to see if any of the 5+ open DirectInput devices are definitively not correlated to an XInput device, and if so, swap them into one of the virtual devices, and emit their current state (presumably an axis change or button press that was used for correlation) as events
Caveats I can see:
- When a player has 5 or more XInput devices plugged in and unplugs one, one of the extra DirectInput controllers will now be upgraded to XInput, and, I believe, there is no way for us to know which one, so we would need to do the correlation logic again whenever an XInput device is removed, and it will likely cause controllers to swap players. The simple “disable XInput if more than 4 controllers” solution would not have this problem (except, perhaps when adding a 5th controller at run-time). Maybe there’s something that could be done about this, but it may be complicated.
Fix #3: Or, to throw out a (possibly?) crazy idea, we go the other way around, and always primarily use DirectInput for all devices, and do the correlation the other way around - detect which XInput devices are correlated to DInput devices - and only ever use the data from the XInput APIs for overriding the trigger axis values (once correlated) and triggering rumble. This would probably be a much cleaner solution than #2, but perhaps there’s some other advantage of the XInput API I’m not aware of.
Would a patch to make this kind of change (probably fix #2) be acceptable? Would the “simple” (Fix #1) solution be preferred? Fix #2 or #3, but with a HINT to turn it off and behave like it does now? I’m just asking for feedback on the architectural changes, not on correlation methods, would be happy to discuss those after implementing some and having a room full of monkeys (err, my friends) bang on and power on and off 15 or so controllers repeatedly ;).
I’d love to work on fixing this, but it appears it’s complicated enough that it will be a lot of work, and involve some potentially contentious changes, so I’d love to get some feedback on the most likely to be accepted change to submit before starting making (potentially significant) architectural changes.
For those interested in Steam games “supporting” more than 4 local players (or reading about issues/workarounds people go through to get some of these to work when all you own is Xbox controllers), check out the More Than 4 Local Multiplayer group on Steam.