Search Unity

How can I detect the gamepad model like XboxOne, PS4, etc?

Discussion in 'Input System' started by Peter77, Oct 1, 2019.

  1. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,620
    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.
    Code (CSharp):
    1. Gamepad.current.displayName
    2. XInputControllerWindows
    3.  
    4. Gamepad.current.description
    5. {
    6.     "interface": "XInput",
    7.     "type": "",
    8.     "product": "",
    9.     "serial": "",
    10.     "version": "",
    11.     "manufacturer": "",
    12.     "capabilities": "{\"userIndex\":0,\"type\":1,\"subType\":1,\"flags\":12,\"gamepad\":{\"buttons\":62463,\"leftTrigger\":255,\"rightTrigger\":255,\"leftStickX\":-64,\"leftStickY\":-64,\"rightStickX\":-64,\"rightStickY\":-64},\"vibration\":{\"leftMotor\":255,\"rightMotor\":255}}"
    13. }
    Before I was using Rewired. In Rewired, I used an hardware identifier (guid) that I could query to detect what gamepad is used.
     
  2. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    You can go by layout (InputDevice.layout) or simply by class.

    Code (CSharp):
    1. if (gamepad is XInputController)
    2.     /* Xbox gamepad */;
    3. else if (gamepad is DualShockGamepad)
    4.     /* PlayStation gamepad */;
     
    TractGames likes this.
  3. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,620
    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.
    Code (CSharp):
    1. Joystick disconnected ("Controller (Xbox One For Windows)").
    2. Joystick reconnected ("Controller (XBOX 360 For Windows)").
     
  4. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    5,633
    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.
     
    Last edited: Oct 4, 2019
    MihaPro, J_Sauve and JoNax97 like this.
  5. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    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).

    Code (CSharp):
    1.         // XInput device handling
    2.         // Note: we must read the Left/Right trigger data from XInput (HID doesn't report it properly) but we cannot
    3.         // definitively map the HID device to XInput's dwUserIndex; if multiple gamepads connected the UserIndex might not
    4.         // be properly mapped to this HIDDevice. Therefore, we must read the entire input state from XInput and skip HIDReport.
    5.         if (this->state->GetType() == JoystickState::T_XINPUT_DEVICE)
    6.         {
    7.             this->UpdateStateFromXInput();
    8.         }
    9.         else
    10.         {
    11.             // handle all data from the report
    12.             for (DataList::const_iterator data = this->dataList.begin(); data < (this->dataList.begin() + dataLength); ++data)
    13.             {
    14.                 DataMap::const_iterator dit = this->dataMap.find(data->DataIndex);
    15.  
    16.                 if (this->dataMap.end() != dit)
    17.                 {
    18.                     dit->second.Invoke(this, *data);
    19.                 }
    20.             }
    21.         }
    22.  
    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.
     
  6. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    5,633
    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.
     
    Last edited: Oct 9, 2019
  7. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    5,633
    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.
     
    Last edited: Oct 9, 2019
    AcidArrow likes this.
  8. darbotron

    darbotron

    Joined:
    Aug 9, 2010
    Posts:
    352
    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...)

    xboneController.png X360Controller.png
     
    Last edited: Jul 10, 2020
  9. HuntyBot

    HuntyBot

    Joined:
    Jun 14, 2020
    Posts:
    1
    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.)...
     
  10. TokyoWarfareProject

    TokyoWarfareProject

    Joined:
    Jun 20, 2018
    Posts:
    814
    Looks like 2 namespaces are needed to be added:

    Code (CSharp):
    1.         if(UnityEngine.InputSystem.Gamepad.current is UnityEngine.InputSystem.XInput.XInputController)
    and for Play Station looks like ther is this:
    Code (CSharp):
    1.         else if (UnityEngine.InputSystem.Gamepad.current is UnityEngine.InputSystem.DualShock.DualShockGamepad)
    2.  
    you can fine tune to dual shock 3/4 or generic as I put above
     
  11. Liderangel

    Liderangel

    Joined:
    Jul 8, 2018
    Posts:
    101

    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)
     
  12. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    5,633
    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.
     
  13. hyagogow

    hyagogow

    Joined:
    Apr 25, 2014
    Posts:
    26
    If your game is for WebGL, you can check the
    device.description.product 


    Xbox 360 gamepads will contain:
    Xbox 360 Controller (XInput STANDARD GAMEPAD)