I’m trying to integrate the new input system in my game. The last piece of the puzzle is how I can detect what gamepad is actually used.
My game updates the UI with specific images depending on the used gamepad. For example, if you use an Xbox One gamepad, the UI displays Xbox One images. If you use a PlayStation gamepad, the game displays PlayStation images.
device.name and device.description do not seem to contain useful information.
Both, Xbox360 and XboxOne Controllers appear to be an “XInputControllerWindows” (InputDevice.layout) for Unity.
How can I distinguish whether an Xbox360 or XboxOne Controller has been connected?
I’d need to detect the same for PS3 and PS4 controllers. I guess that would be DualShock3GamepadHID and DualShock4GamepadHID.
What’s interesting is when I connect/disconnect the gamepads, it correctly outputs that one is an Xbox360 and the other one an XboxOne Controller to the Console window.
Joystick disconnected ("Controller (Xbox One For Windows)").
Joystick reconnected ("Controller (XBOX 360 For Windows)").
The console is not using XInput to display that information, it’s using information from the HID device. This is one of the most common questions I get from Rewired users. This is an XInput limitation and cannot be worked around reliably. See my documentation on this topic: https://guavaman.com/projects/rewired/docs/KnownIssues.html#xinput-device-name
Unity has been combining XInput and HID for XInput controllers for years on Windows using the L/R trigger values from XInput and the name and other elements from the HID device. However, read the forums and you will see many, many problems that come from this “fusion” because there simply is no reliable way to fuse these devices because Microsoft gives you no way to associate an XInput device id to a HID device. All attempts to do this fail at some point or another with multiple controllers attached. That’s why you will see many complaints on the forum about XInput gamepads triggers responding on the wrong device when multiple devices are attached in some scenarios. Rewired will never attempt this kind of “fusion” to work around Microsoft’s built-in limitation, and I certainly hope Unity doesn’t try to do this in their new input system. You must work within the limitations of the underlying input APIs. In this case, XInput tells you one thing – this is a gamepad. Nothing more.
Other limitations:
Only 4 XInput controllers can be used at once.
This is not the case. Neither for the old nor for the new input system.
For the old input system, I believe it was actually the case for the Windows code at some point but that’s been a long while. This is the respective code from the Unity runtime for the old input system (new input system uses an from-scratch implementation).
// XInput device handling
// Note: we must read the Left/Right trigger data from XInput (HID doesn't report it properly) but we cannot
// definitively map the HID device to XInput's dwUserIndex; if multiple gamepads connected the UserIndex might not
// be properly mapped to this HIDDevice. Therefore, we must read the entire input state from XInput and skip HIDReport.
if (this->state->GetType() == JoystickState::T_XINPUT_DEVICE)
{
this->UpdateStateFromXInput();
}
else
{
// handle all data from the report
for (DataList::const_iterator data = this->dataList.begin(); data < (this->dataList.begin() + dataLength); ++data)
{
DataMap::const_iterator dit = this->dataMap.find(data->DataIndex);
if (this->dataMap.end() != dit)
{
dit->second.Invoke(this, *data);
}
}
}
Unfortunately, I think you can’t. If it’s an XInput controller, that’s all you get to know. The XInput API does not come with any device-specific information other than just general device capabilities.
If that’s true then why does Unity, as of 2019.3 beta, still display the HID device name in Input.GetJoystickNames and yet also reports XInput-style independent triggers on Axis 8 and 9? XInput and Windows.Gaming.Input are the only systems that can retrieve independent trigger values from Xbox Controllers. And XInput cannot get the name “Controller (Xbox One for Windows)”, so Unity can only possibly be using HID information to get this. I also see that Axis 2 reports the HID-style 1-axis shared trigger that cancels each other out, so either this is coming from the HID device or it is being simulated from XInput for backwards compatibility. Regardless, displaying the HID name for the XInput device through this “fusion” is still happening even if the other elements aren’t anymore.
I’m glad to hear that the new input system won’t be attempting this fusion.
Actually, I just did testing on 2019.3.0b2 on the legacy input system. I can still reproduce issues related to the HID->XInput association which Unity is still doing, though not the exact same issues as before. The symptoms have changed, but the underlying cause is still the same from what I can tell. I see that Unity will support > 4 XInput controllers (not possible using XInput), and ones that are not associated with an XInput device will still function, except Axes 8 and 9 do not function, as expected because they’re HID devices. Unity is combining XInput devices and HID XInput devices into a single list, and is still attempting to make an association between HID devices and their XInput id’s. Doing some controller unplugging and replugging easily confuses the XInput-HID fusion and you’re left with physical controllers that control multiple Unity joysticks simultaneously – one being a HID device (no Axis 8, 9) and one being an XInput device (Axis 8, 9 work).
So it appears to me the Unity legacy code was changed at some point in the past to not read joystick values from HID combined with triggers from XInput like they used to, but it is switching between using the XInput or the HID device entirely for element values. It’s still fusing the HID device to the XInput device for the purposes of displaying the HID name and for determining whether to use XInput or HID for the element values. This would explain why things get mixed up and you can be controlling multiple devices with one controller while another controller is just dead and contributes no input.
I recently read that Steam/SDL2 are looking into combining HID and XInput devices to try to get past the 4-controller XInput limit because players are always asking for it. The code is visible in the SDL2 source. They’re going to face the same issues.
I’m also trying to work out how to get the InputSystem to distinguish between an X360 and an xbone controller.
I’ve had a good look at the Xinput documentation and it appears that there’s no way to distinguish an X360 pad from an xbone pad - however, I just tried a bit of free USB packet sniffing software and it shows that the information is in fact available (though there’s maybe no way to link it up with the information Xinput provides…)
I’ve pasted the images in below.
Would it be possible to override the InputSystem’s XInput device and read from the X360 / xbone controller as HID devices based on their product name? (this might make a good additional sample for the InputSystem package if it is…)
Heyy, this might not be the right place but could you expand on this answer? I’m trying to do exactly that (distinguish only Playstation and Xbox controllers), but I can’t seem to get it right. The script wont let me reference the names (“XInputController”, etc.)…
Hey, I’m coming from 3 years in the future! Is it possible to now differentiate same brand devices?
I would need to differentiate XBOX ONE from XBOX SERIES S/X and PlayStation 4 from PlayStation 5.
And well if it comes to it, XBOX 360 from the other 2 XBOX.
(this is just to put the most appropriate glyphs per device, since while they have minor differences between them we want to have it the best they can be)
It’s not possible if the underlying input source is XInput. Raw Input, Direct Input, and Windows.Gaming.Input could give you that information, but XInput cannot.