Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice

Question Last used device (X360, XOne, PS4, Dualsense, etc)

Discussion in 'Input System' started by Bastienre4, Oct 18, 2021.

  1. Bastienre4

    Bastienre4

    Joined:
    Jul 8, 2014
    Posts:
    191
    Hello!

    I have a simple problem and I can't find any solutions.
    I need to display glyphs for input actions depending on the last used device. Kinda classical.
    BUT, I need to make the distinction between all kind of controllers. I won't display the same glyphs if it's a XBOX360 controller nor if it's a PS4 controller. For the sake of this thread, let's say we want to make different glyphs for : PS4/PS5/Stadia Controller/Joycon/Switch Pro/X360/XOne.

    The closest thread I found for my issue is this one https://forum.unity.com/threads/detect-most-recent-input-device-type.753206/ but it's not enough.

    In Rewired, there's those two super helpful methods:
    upload_2021-10-18_18-54-12.png

    I can then get the hardware GUID for the device

    upload_2021-10-18_19-2-4.png

    this id is unique per controller hardware (xbox 360, xbox one, ps3, ps4, ps5, stadia controller, switch joycons, switch pro controller, etc).

    Thanks and have a nice day.
     
    Last edited: Oct 18, 2021
  2. Bastienre4

    Bastienre4

    Joined:
    Jul 8, 2014
    Posts:
    191
  3. Bastienre4

    Bastienre4

    Joined:
    Jul 8, 2014
    Posts:
    191
  4. MousePods

    MousePods

    Joined:
    Jul 19, 2012
    Posts:
    811
    I use the PlayerInput script provided by Unity for this and then subscribe to the OnControlsChanged event.

    Note: Dualsense support has not been released yet: https://github.com/Unity-Technologies/InputSystem/pull/1404

    Screen Shot 2021-10-25 at 10.19.47 AM.png

    Code (CSharp):
    1.     private void OnEnable()
    2.     {
    3.         playerInput.onControlsChanged += OnControlsChanged;
    4.     }
    5.  
    6.     private void OnDisable()
    7.     {
    8.         playerInput.onControlsChanged -= OnControlsChanged;
    9.     }
    Code (CSharp):
    1.     private ActiveInputType SetActiveInputType()
    2.     {
    3.         if(playerInput.devices[0] is Mouse || playerInput.devices[0] is Keyboard)
    4.         {
    5.             return ActiveInputType.keyboardAndMouse;
    6.         }
    7.         else if(playerInput.devices[0] is XInputController)
    8.         {
    9.             return ActiveInputType.xbox;
    10.         }
    11.         else if(playerInput.devices[0] is DualShockGamepad)
    12.         {
    13.             return ActiveInputType.playstation;
    14.         }
    15.         else if(playerInput.devices[0] is Touchscreen)
    16.         {
    17.             return ActiveInputType.touch;
    18.         }
    19.         else
    20.         {
    21.             // If you are using a generic controller, it should default to xbox icons.
    22.             return ActiveInputType.xbox;
    23.         }
    24.     }
    25.  
    26.     private void OnControlsChanged(PlayerInput playerInput)
    27.     {
    28.         previousActiveInputType = activeInputType;
    29.         activeInputType = SetActiveInputType();
    30.  
    31.         if(previousActiveInputType != activeInputType)
    32.         {
    33.             EventManager.InvokeOnActiveInputChanged(previousActiveInputType, activeInputType);
    34.         }
    35.     }
    Hope it helps!
     
    Bastienre4 likes this.
  5. Bastienre4

    Bastienre4

    Joined:
    Jul 8, 2014
    Posts:
    191
    Thanks for your answer!

    However:
    - I would like to avoid using PlayerInput (but if it's the only drawback, I think I can live with it)
    - It does not give me the level of precision I need (for instance, making the distinction between a 360 and a One controller). I can't know if it's a Stadia controller neither for instance. Relying on the type is not enough, especially when they can change depending on the platform you're building your game on.

    But again, thanks for the help! :)
     
  6. MousePods

    MousePods

    Joined:
    Jul 19, 2012
    Posts:
    811
    No problem! If you ever find an answer would love to know :)
     
    Bastienre4 likes this.
  7. dmytro_at_unity

    dmytro_at_unity

    Unity Technologies

    Joined:
    Feb 12, 2021
    Posts:
    212
    Depending on what exactly you want to do,
    Gamepad.current
    might suffice, if you want to get all state notifications ever then
    InputState.onChange
    will do, just don't forget to remove the callback after you're done, otherwise it will be called way too often.

    Usually things like "I need to do figure out what is the device of recently joined player" are done via listening to a button press, with gamepads connected over bluetooth it's often done as "press A to join".

    Then for identification purposes you could try using
    InputDeviceDescription.serial
    , but the current implementation is a bit spotty, partially because we rarely do have a serial, but also because we're not exposing port connection hierarchy right now. In this thread https://forum.unity.com/threads/2-a...nly-one-inputs-its-axis.1178620/#post-7564132 we covered some basis how it should work, hopefully will come around to make device identification more robust.
     
  8. Bastienre4

    Bastienre4

    Joined:
    Jul 8, 2014
    Posts:
    191
    Hello. Thanks for your answer.

    I want to be able to detect (at all time, not only in a "press A to join" menu) whenever the player change device.
    I can't use only Gamepad.current as the player might be using a Keyboard, or a Touchpad. I want him to be able to change device on the fly, and for the game to adapt the glyphs automatically.

    Furthermore, InputDeviceDescription.serial is empty (I use a xbox series controller, wireless, on a windows editor)
    upload_2021-10-28_15-29-9.png
     
  9. dmytro_at_unity

    dmytro_at_unity

    Unity Technologies

    Joined:
    Feb 12, 2021
    Posts:
    212
    @Bastienre4 as I mentioned we currently don't have a great platform independent implementation for this, sorry about it, in the future we plan to revisit device identification and make it as uniform as possible.

    In this particular case XInput itself doesn't provide any information about gamepads. Instead it reports user id, up to 4 in total, from 0 to 3. This user id is stored in device description -> capabilities -> user index, which you can see on your screenshot.
    More info https://docs.microsoft.com/en-us/windows/win32/xinput/getting-started-with-xinput

    For USB HID devices you should be able to get the serial in most cases, but not all devices report it.
    USB port topology is currently not exposed.

    If your case is only to get the latest _type_ of a controller, maybe you can achieve that by listening to all state events, checking device id on them, and then checking with input system what is the type for that device id.
     
  10. dmytro_at_unity

    dmytro_at_unity

    Unity Technologies

    Joined:
    Feb 12, 2021
    Posts:
    212
    @Bastienre4 reading a bit in our code, we have
    InputSystem.GetDevice(Type type)
    , try passing InputDevice type there and see if that does what you want.

    Because reading the code:
    Code (CSharp):
    1.         public static InputDevice GetDevice(Type type)
    2.         {
    3.             InputDevice result = null;
    4.             var lastUpdateTime = -1.0;
    5.             foreach (var device in devices)
    6.             {
    7.                 if (!type.IsInstanceOfType(device))
    8.                     continue;
    9.  
    10.                 if (result == null || device.m_LastUpdateTimeInternal > lastUpdateTime)
    11.                 {
    12.                     result = device;
    13.                     lastUpdateTime = result.m_LastUpdateTimeInternal;
    14.                 }
    15.             }
    16.  
    17.             return result;
    18.         }
    It returns the last updated for the type, so passing the most generic type to it should work.
     
    Bastienre4 likes this.
  11. Bastienre4

    Bastienre4

    Joined:
    Jul 8, 2014
    Posts:
    191
    That would be "ok", waiting for a better device identification (in order to display proper glyphs depending on the precise type of the controller).
    It at least would solve one of the issues, getting the last used device.
    One question though, does it take into account the "noisy" devices or not (I've heard that PS4 controller for instance is noisy due to the gyro sensors & all)?
     
  12. Bastienre4

    Bastienre4

    Joined:
    Jul 8, 2014
    Posts:
    191
    Any update?
     
  13. dmytro_at_unity

    dmytro_at_unity

    Unity Technologies

    Joined:
    Feb 12, 2021
    Posts:
    212
    Sorry m_LastUpdateTimeInternal is currently ignoring the noise flag. Device.MakeCurrent() is the only thing currently called when there is any non-noise activity on a device. The way how PlayerInput does it currently is hooking into InputSystem.OnEvent and for every event doing EnumerateChangedControls to see if anything has changed.

    I don't immediately see how would you solve this without writing almost exactly the same code as in InputUser, maybe you can leverage it to do what you need?

    Otherwise I would suggest filing a bug report.
     
    Bastienre4 likes this.
  14. Bastienre4

    Bastienre4

    Joined:
    Jul 8, 2014
    Posts:
    191
    I wonder if it shouldn't be added in the InputSystem. It seem kind of an mandatory feature to me, esp. on some platforms like Stadia who requires you to react to controller change. And having to rely on some complicated, heavy code copied from an other component doesn't seem very robust. I know I'm not the only Unity customer having (a lot of) issues with this subject, maybe there's something you guys can do on your side to help us?

    TBH, I really like the philosophy of the InputSystem, but the struggle to work around those features I need will probably make me go back to Rewired.
     
  15. dmytro_at_unity

    dmytro_at_unity

    Unity Technologies

    Joined:
    Feb 12, 2021
    Posts:
    212
    @Bastienre4 I understand that this use case is a bit of pain right now, sorry about it.

    Would you mind to explain a bit in more detail what exactly you're trying to do so I can better figure out what feature/fix we need to make? I get that is "show graphics for last used device", which implies you probably want to switch control schemes based on last used device? We have a somewhat conflicting feature requests here. As in this thread https://forum.unity.com/threads/2-a...tick-inputs-only-one-inputs-its-axis.1178620/ the solution is not to use last active device, but rather figure out the connection hierarchy.

    Thanks!
     
    Bastienre4 likes this.
  16. Bastienre4

    Bastienre4

    Joined:
    Jul 8, 2014
    Posts:
    191
    TBH, I just gave up and went back using Rewired.
    I encountered a 100% crash while I was trying to develop the rebind menu, it was too much for me :p (Case 1379126)

    I don't think it's conflicting, it may just be different approaches.
    In my case, as it's a single player game, I just want an easier way to detect the device the player is really using to display the exact glyphs to show (and depending on the actual device, it's not the same (X360, XOne, XSeries, PS4, PS5, etc).