Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Bug DualShock 4 (ps4 gamepad) acts as 2 seperate devices at the same time

Discussion in 'Input System' started by bagelbaker, Feb 13, 2023.

  1. bagelbaker

    bagelbaker

    Joined:
    Jun 5, 2017
    Posts:
    66
    Hello,

    I have a ps4 gamepad (dualshock 4) attached to a USB port and the game detects 2 gamepads. One as DualShock4GamepadHID and one as XInputControllerWindows. This can be confirmed also by looking at the input debugger's device list (see attached screenshot). Both devices will react the same way when I press buttons on my gamepad.

    When testing with a ps5 or a xbox one gamepad, only 1 device (DualSenseGamepadHID and XInputControllerWindows respectively) shoes up as it should be.

    This bug occurs on Unity 2022.2.6f1 and input system 1.3.0 through 1.5.0. The bug is NOT there on Unity 2021.3.4f1 with input system 1.3.0 through 1.5.0. So it seems to be a regression on a Unity version upgrade.

    I filed bug report IN-32056
     

    Attached Files:

  2. SnowConures

    SnowConures

    Joined:
    Jun 15, 2017
    Posts:
    1
    The exact same thing happens for me on 2022.2.4f1
     
  3. SwingWren

    SwingWren

    Joined:
    Mar 1, 2014
    Posts:
    30
    Still happening in 2022.2.11f1

    I could not find a reliable identify the wrong xbox controller so for now I just added a manual way for the user to solve this in settings. (If you disable or remove that xbox controller the controller works as expected)
     
    Last edited: Mar 21, 2023
    MikeGDev likes this.
  4. bagelbaker

    bagelbaker

    Joined:
    Jun 5, 2017
    Posts:
    66
    So this is the latest reply to the bug report I did
    So it might be related to the pc system/driver configurations that is causing this issue with Unity but I haven't been able to figure out what it is exactly. Both my ps4 and xbox controllers where plug and play without any 3rd party drivers or software.
     
  5. unormal

    unormal

    Joined:
    Jan 10, 2012
    Posts:
    65
    Is this perhaps steams gamepad support getting in the middle of things?
     
  6. Josh707

    Josh707

    Joined:
    Jul 12, 2012
    Posts:
    68
    For anyone encountering this going forward, here's a relevant link and some info I've picked up:

    - Relevant issue tracker link: https://issuetracker.unity3d.com/is...tools-is-installed-and-xinput-support-enabled

    - Are you using DS4Windows? If so, it's configuration may be the culprit - make sure you properly set up HidHide to hide the real controller's hardware device so that only the 'fake' controller device created by DS4Windows is visible to your system.

    - Are you using a DS3 controller with DsHidMini, configured to work with DS4Windows? This seems to present 2 controller devices to the new input system even if HidHide is set up. The only workaround I've found so far is stopping & closing DS4Windows and opening DsHidMini configuration tool (DSHMC.exe) and temporarily changing your DS3 controller's HID device mode from DS4Windows to XInput, then it only shows up as one XInput device. This means whatever you set up in terms of deadzones, remapping, etc. in DS4Windows is not in use anymore however.

    - Lastly, that info doesn't actually solve the problem for a random user playing your game with this problematic setup. If you're handling InputUser.onUnpairedDeviceUsed yourself, it will still detect a new unpaired gamepad device was used every input system update (so default every frame). If your game, like mine, simply pairs to the latest used device it will ping pong between the 2 gamepad devices while it's in use. My solution (for now) is to not performing pairing to a gamepad device if we're already paired to a device that falls into the gamepad control scheme:
    Code (CSharp):
    1. // These correspond to the 2 control schemes defined in my game's InputActions assets
    2. private const string ControlSchemeNameKeyboard = "Keyboard";
    3. private const string ControlSchemeNameGamepad = "Gamepad";
    4.  
    5. private InputUser inputUser;
    6. private ReadOnlyArray<InputControlScheme> inputControlSchemes;
    7.  
    8. private void Awake()
    9. {
    10.     // Detect the best control scheme with what devices are plugged in
    11.     if (inputUser.valid)
    12.         inputUser.UnpairDevices();
    13.     else
    14.         inputUser = InputUser.CreateUserWithoutPairedDevices();
    15.  
    16.     // SystemInputs is one of my InputActions, with "Keyboard" & "Gamepad" control schemes
    17.     inputControlSchemes = SystemInputs.asset.controlSchemes;
    18.     using (var availableDevices = InputUser.GetUnpairedInputDevices())
    19.     {
    20.         if (InputControlScheme.FindControlSchemeForDevices(availableDevices, inputControlSchemes, out var controlScheme, out var matchResult))
    21.         {
    22.             var newDevices = matchResult.devices;
    23.             for (int i = 0; i < newDevices.Count; i++)
    24.                 inputUser = InputUser.PerformPairingWithDevice(newDevices[i], inputUser);
    25.  
    26.             switch (controlScheme.name)
    27.             {
    28.                 case ControlSchemeNameKeyboard:
    29.                     CurrentUserControlScheme = ControlScheme.Keyboard;
    30.                     break;
    31.                 case ControlSchemeNameGamepad:
    32.                     CurrentUserControlScheme = ControlScheme.Gamepad;
    33.                     break;
    34.                 default:
    35.                     Debug.LogError($"Unknown control scheme encountered: {controlScheme.name}");
    36.                     break;
    37.             }
    38.  
    39.             inputUser.ActivateControlScheme(controlScheme);
    40.         }
    41.     }
    42.     InputUser.listenForUnpairedDeviceActivity = 1;
    43.     InputUser.onUnpairedDeviceUsed += OnUnpairedDeviceUsed;
    44. }
    45.  
    46. private void OnUnpairedDeviceUsed(InputControl control, InputEventPtr eventPtr)
    47. {
    48.     var device = control.device;
    49.     using (var availableDevices = InputUser.GetUnpairedInputDevices())
    50.     {
    51.         // Put new device first in the list to make sure it's the first one picked for a match
    52.         if (availableDevices.Count > 1)
    53.         {
    54.             var indexOfDevice = availableDevices.IndexOf(device);
    55.             Debug.Assert(indexOfDevice != -1, "Did not find unpaired device in list of unpaired devices");
    56.             availableDevices.SwapElements(0, indexOfDevice);
    57.         }
    58.  
    59.         // Add all devices currently already paired to us in case something is unusable
    60.         var currentDevices = inputUser.pairedDevices;
    61.         for (var i = 0; i < currentDevices.Count; ++i)
    62.             availableDevices.Add(currentDevices[i]);
    63.  
    64.         // Find the best control scheme to use
    65.         if (InputControlScheme.FindControlSchemeForDevices(availableDevices, inputControlSchemes,
    66.             out var controlScheme, out var matchResult, mustIncludeDevice: device))
    67.         {
    68.             // Hacky fix for DS3/DS4 and DS4Windows showing 2 devices (DualShock4GamepadHID & XInputControllerWindows) for one gamepad
    69.             // Input system still detects an unpaired device, this just suppresses our code from spamming control scheme changed events or un-pairing & re-pairing
    70.             if (CurrentUserControlScheme == ControlScheme.Gamepad && controlScheme.name == ControlSchemeNameGamepad)
    71.                 return;
    72.  
    73.             inputUser.UnpairDevices();
    74.  
    75.             var newDevices = matchResult.devices;
    76.             for (int i = 0; i < newDevices.Count; i++)
    77.                 inputUser = InputUser.PerformPairingWithDevice(newDevices[i], inputUser);
    78.  
    79.             switch (controlScheme.name)
    80.             {
    81.                 case ControlSchemeNameKeyboard:
    82.                     CurrentUserControlScheme = ControlScheme.Keyboard;
    83.                     break;
    84.                 case ControlSchemeNameGamepad:
    85.                     CurrentUserControlScheme = ControlScheme.Gamepad;
    86.                     break;
    87.                 default:
    88.                     Debug.LogError($"Unknown control scheme encountered: {controlScheme.name}");
    89.                     break;
    90.             }
    91.  
    92.             inputUser.ActivateControlScheme(controlScheme);
    93.         }
    94.     }
    95. #if UNITY_EDITOR
    96.     Debug.Log($"InputManager: Switched control scheme to {CurrentUserControlScheme}");
    97. #endif
    98. }
    This doesn't completely solve the problem - under the hood, Unity is still detecting a new device was used, signalling the OnUnpairedDeviceUsed event - if you check the profiler it generates ~300b of garbage per frame from InputControlScheme.FindControlSchemeForDevices(). However, on the gameplay side, our CurrentUserControlScheme property signals a control scheme changed event when it's value is set - this code change makes us stay paired to the first gamepad device detected and not signal the event, nor pair to other gamepad devices until it switches back to mouse and keyboard which is still a functional improvement and a performance improvement from it being spammed.
     
  7. webik150

    webik150

    Joined:
    Mar 23, 2013
    Posts:
    59
    This is absolute bullshit issue that's been going on for forever. It's sad it's still around. I don't even have DS4Windows installed and it still happens (I used to have it ages ago but I went through the DS4Windows guide for removal)