Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question about making custom device.

Discussion in 'Input System' started by EliotVR, Jun 26, 2020.

  1. EliotVR

    EliotVR

    Joined:
    Jan 12, 2017
    Posts:
    14
    Hello.

    I want to create a custom device that receives the inputs I have defined.

    The following script is my CustomDevice.

    I am trying to create a custom device by calling CreateDevice which is a static function, but the following error occurs.

    ArgumentException: Cannot find layout matching device description '{"controllerIndex":0,"userId":0} (SteamVR)'
    Parameter name: description

    Code (CSharp):
    1. using UnityEngine.InputSystem.Controls;
    2. using UnityEngine.InputSystem.LowLevel;
    3. using UnityEngine.InputSystem.Utilities;
    4. using System;
    5. using System.Runtime.InteropServices;
    6. using UnityEngine.InputSystem.Haptics;
    7. using UnityEngine.InputSystem.Layouts;
    8.  
    9. using Valve.VR;
    10.  
    11. using System.Linq;
    12. using UnityEngine;
    13. using UnityEngine.InputSystem;
    14.  
    15. #if UNITY_EDITOR
    16. using UnityEditor;
    17. #endif
    18.  
    19. [StructLayout(LayoutKind.Explicit, Size = 4)]
    20. public struct SteamVRDeviceState : IInputStateTypeInfo
    21. {
    22.     public static FourCC kFormat => new FourCC('S', 'T', 'V', 'I');
    23.  
    24.     public enum Button
    25.     {
    26.         Grip = 0,
    27.         StickButton = 1,
    28.         Menu = 2
    29.     }
    30.  
    31.     [InputControl(name = "grip", layout = "Button", bit = (uint)Button.Grip, displayName = "Grip")]
    32.     [InputControl(name = "stickButton", layout = "Button", bit = (uint)Button.StickButton, displayName = "Stick Button")]
    33.     [InputControl(name = "menu", layout = "Button", bit = (uint)Button.Menu, displayName = "Menu")]
    34.     [FieldOffset(0)]
    35.     public ushort buttons; // 16 Bit
    36.  
    37.     [InputControl(name = "stick", format = "FLT", layout = "Vector2", displayName = "Stick")]
    38.     [InputControl(name = "stick/x", defaultState = 0.0f, format = "FLT", parameters = "normalize,normalizeMin=-1,normalizeMax=1,normalizeZero=0.0,clamp=2,clampMin=-1,clampMax=1")]
    39.     [InputControl(name = "stick/y", defaultState = 0.0f, format = "FLT", parameters = "normalize,normalizeMin=-1,normalizeMax=1,normalizeZero=0.0,clamp=2,clampMin=-1,clampMax=1")]
    40.     [FieldOffset(2)]
    41.     public Vector2 stick_value;
    42.  
    43.     [InputControl(name = "trigger", format = "FLT", layout = "Axis", parameters = "normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.0,clamp=2,clampMin=0,clampMax=1", displayName = "Trigger")]
    44.     [FieldOffset(10)]
    45.     public float trigger_Value;
    46.  
    47.     public FourCC format
    48.     {
    49.         get { return kFormat; }
    50.     }
    51.  
    52. }
    53.  
    54. ///// <summary>
    55. ///// PS4 output report sent as command to backend.
    56. ///// </summary>
    57. //// IMPORTANT: Struct must match the DualShockPS4OutputReport in native
    58. //[StructLayout(LayoutKind.Explicit, Size = kSize)]
    59. //internal struct MoveControllerPS4OuputCommand : IInputDeviceCommandInfo
    60. //{
    61. //    public static FourCC Type => new FourCC('S', 'T', 'V', 'O');
    62.  
    63. //    internal const int kSize = InputDeviceCommand.BaseCommandSize + 5;
    64.  
    65. //    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "Flags", Justification = "No better term for underlying data.")]
    66. //    [Flags]
    67. //    public enum Flags
    68. //    {
    69. //        Rumble = 0x1,
    70. //        Color = 0x2,
    71. //    }
    72.  
    73. //    [FieldOffset(0)] public InputDeviceCommand baseCommand;
    74.  
    75. //    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "flags", Justification = "No better term for underlying data.")]
    76. //    [FieldOffset(InputDeviceCommand.BaseCommandSize + 0)] public byte flags;
    77. //    [FieldOffset(InputDeviceCommand.BaseCommandSize + 1)] public byte motorSpeed;
    78. //    [FieldOffset(InputDeviceCommand.BaseCommandSize + 2)] public byte redColor;
    79. //    [FieldOffset(InputDeviceCommand.BaseCommandSize + 3)] public byte greenColor;
    80. //    [FieldOffset(InputDeviceCommand.BaseCommandSize + 4)] public byte blueColor;
    81.  
    82. //    public FourCC typeStatic
    83. //    {
    84. //        get { return Type; }
    85. //    }
    86.  
    87. //    public void SetMotorSpeed(float motor)
    88. //    {
    89. //        flags |= (byte)Flags.Rumble;
    90. //        motorSpeed = (byte)Mathf.Clamp(motor * 255, 0, 255);
    91. //    }
    92.  
    93. //    public void SetColor(Color color)
    94. //    {
    95. //        flags |= (byte)Flags.Color;
    96. //        redColor = (byte)Mathf.Clamp(color.r * 255, 0, 255);
    97. //        greenColor = (byte)Mathf.Clamp(color.g * 255, 0, 255);
    98. //        blueColor = (byte)Mathf.Clamp(color.b * 255, 0, 255);
    99. //    }
    100.  
    101. //    public static MoveControllerPS4OuputCommand Create()
    102. //    {
    103. //        return new MoveControllerPS4OuputCommand
    104. //        {
    105. //            baseCommand = new InputDeviceCommand(Type, kSize)
    106. //        };
    107. //    }
    108. //}
    109.  
    110.     //Sync to PS4MoveDeviceDefinition in sixaxis.cpp
    111.  
    112.     [Serializable]
    113.     class SteamVRDeviceDescriptor
    114.     {
    115.         public SteamVRDeviceDescriptor(uint userId, uint controllerIndex)
    116.         {
    117.             this.userId = userId;
    118.             this.controllerIndex = controllerIndex;
    119.         }
    120.  
    121.         public uint controllerIndex = 0;
    122.         public uint userId = 0;
    123.  
    124.         internal string ToJson()
    125.         {
    126.             return JsonUtility.ToJson(this);
    127.         }
    128.  
    129.         internal static SteamVRDeviceDescriptor FromJson(string json)
    130.         {
    131.             return JsonUtility.FromJson<SteamVRDeviceDescriptor>(json);
    132.         }
    133.     }
    134.  
    135. #if UNITY_EDITOR
    136. [InitializeOnLoad] // Call static class constructor in editor.
    137. #endif
    138. [InputControlLayout(displayName = "SteamVRController", stateType = typeof(SteamVRDeviceState))]
    139. public class SteamVRCustomDevice : InputDevice, IInputUpdateCallbackReceiver
    140. {
    141.     // [InitializeOnLoad] will ensure this gets called on every domain (re)load
    142.     // in the editor.
    143. #if UNITY_EDITOR
    144.     static SteamVRCustomDevice()
    145.     {
    146.         InitializeInPlayer();
    147.     }
    148. #endif
    149.  
    150.     // In the player, [RuntimeInitializeOnLoadMethod] will make sure our
    151.     // initialization code gets called during startup.
    152.     [RuntimeInitializeOnLoadMethod]
    153.     private static void InitializeInPlayer()
    154.     {
    155.         InputSystem.RegisterLayout<SteamVRCustomDevice>("SteamVRController",
    156.              matches: new InputDeviceMatcher()
    157.                  .WithInterface("SteamVR")
    158.                  .WithDeviceClass("SteamVRController"));
    159.  
    160.         InputSystem.RegisterLayoutOverride(@"
    161.                {
    162.                    ""name"" : ""SteamVRCustomDeviceWithUsageTags"",
    163.                    ""extend"" : ""SteamVRController"",
    164.                    ""commonUsages"" : [
    165.                        ""Right"", ""Left""
    166.                    ]
    167.                }
    168.            ");
    169.     }
    170.  
    171.     private int m_ControllerIndex = -1;
    172.     private int m_UserId = -1;
    173.     public int controllerIndex => m_ControllerIndex;
    174.     public int userId => m_UserId;
    175.  
    176.     public static SteamVRCustomDevice GetBySlotIndex(int userIndex, int controllerIndex)
    177.     {
    178.         if (userIndex < 0 || userIndex >= 4)
    179.             throw new ArgumentException("User index out of range: " + userIndex, "userId");
    180.  
    181.         if (controllerIndex < 0 || controllerIndex >= 2)
    182.             throw new ArgumentException("Controller index out of range: " + userIndex, "controllerIndex");
    183.  
    184.         int realIndex = (userIndex * 2) + controllerIndex;
    185.  
    186.         if (s_Devices[realIndex] != null && s_Devices[realIndex].userId == userIndex)
    187.         {
    188.             return s_Devices[realIndex];
    189.         }
    190.  
    191.         return null;
    192.     }
    193.  
    194.     private static SteamVRCustomDevice[] s_Devices = new SteamVRCustomDevice[8];
    195.     public new static ReadOnlyArray<SteamVRCustomDevice> all => new ReadOnlyArray<SteamVRCustomDevice>(s_Devices);
    196.  
    197.     public ButtonControl Grip { get; private set; }
    198.     public ButtonControl StickButton { get; private set; }
    199.     public ButtonControl Menu { get; private set; }
    200.     public Vector2Control Stick { get; private set; }
    201.     public AxisControl Trigger { get; private set; }
    202.  
    203.     protected override void FinishSetup()
    204.     {
    205.         Grip = GetChildControl<ButtonControl>("grip");
    206.         StickButton = GetChildControl<ButtonControl>("stickButton");
    207.         Menu = GetChildControl<ButtonControl>("menu");
    208.  
    209.         Stick = GetChildControl<Vector2Control>("stick");
    210.  
    211.         Trigger = GetChildControl<AxisControl>("trigger");
    212.  
    213.         base.FinishSetup();
    214.  
    215.         var capabilities = description.capabilities;
    216.         var deviceDescriptor = SteamVRDeviceDescriptor.FromJson(capabilities);
    217.  
    218.         if (deviceDescriptor != null)
    219.         {
    220.             m_ControllerIndex = (int)deviceDescriptor.controllerIndex;
    221.             m_UserId = (int)deviceDescriptor.userId;
    222.         }
    223.  
    224.     }
    225.  
    226.     public static SteamVRCustomDevice current { get; private set; }
    227.     public override void MakeCurrent()
    228.     {
    229.         base.MakeCurrent();
    230.         current = this;
    231.     }
    232.  
    233.     protected override void OnAdded()
    234.     {
    235.         base.OnAdded();
    236.  
    237.         AddDeviceToList();
    238.     }
    239.  
    240.     protected override void OnRemoved()
    241.     {
    242.         base.OnRemoved();
    243.         if (current == this)
    244.             current = null;
    245.  
    246.         RemoveDeviceFromList();
    247.     }
    248.  
    249.     private void AddDeviceToList()
    250.     {
    251.         int realIndex = (m_UserId * 2) + m_ControllerIndex;
    252.  
    253.         if (realIndex >= 0 && realIndex < s_Devices.Length)
    254.         {
    255. #if !UNITY_EDITOR
    256.                 Debug.Assert(s_Devices[realIndex] == null, "Controller with same UserId/ControllerIndex already added");
    257. #endif
    258.             s_Devices[realIndex] = this;
    259.         }
    260.     }
    261.  
    262.     private void RemoveDeviceFromList()
    263.     {
    264.         int realIndex = (m_UserId * 2) + m_ControllerIndex;
    265.  
    266.         if (realIndex >= 0 && realIndex < s_Devices.Length && s_Devices[realIndex] == this)
    267.             s_Devices[realIndex] = null;
    268.     }
    269.  
    270.     public static void CreateDevice(uint userId, uint controllerIndex)
    271.     {
    272.         SteamVRDeviceDescriptor newDeviceDescriptor = new SteamVRDeviceDescriptor(userId, controllerIndex);
    273.  
    274.         InputSystem.AddDevice(new InputDeviceDescription
    275.         {
    276.             interfaceName = "SteamVR",
    277.             capabilities = newDeviceDescriptor.ToJson(),
    278.         });
    279.     }
    280.  
    281.     private static void RemoveDevice()
    282.     {
    283.         var customDevice = InputSystem.devices.FirstOrDefault(x => x is SteamVRCustomDevice);
    284.         if (customDevice != null)
    285.             InputSystem.RemoveDevice(customDevice);
    286.     }
    287.  
    288.     public SteamVR_Action_Vector2 m_stick = SteamVR_Input.GetAction<SteamVR_Action_Vector2>("default", "stick");
    289.     public SteamVR_Action_Single m_trigger = SteamVR_Input.GetAction<SteamVR_Action_Single>("default", "trigger");
    290.  
    291.     public SteamVR_Action_Boolean m_grip = SteamVR_Input.GetAction<SteamVR_Action_Boolean>("default", "grip");
    292.     public SteamVR_Action_Boolean m_stickButton = SteamVR_Input.GetAction<SteamVR_Action_Boolean>("default", "stickButton");
    293.     public SteamVR_Action_Boolean m_menu = SteamVR_Input.GetAction<SteamVR_Action_Boolean>("default", "menu");
    294.  
    295.     public void OnUpdate()
    296.     {
    297.         var state = new SteamVRDeviceState();
    298.  
    299.         // Map buttons to 1, 2, and 3.
    300.         if (m_grip.GetStateDown(SteamVR_Input_Sources.Any))
    301.             state.buttons |= 1 << 0;
    302.         if (m_stickButton.GetStateDown(SteamVR_Input_Sources.Any))
    303.             state.buttons |= 1 << 1;
    304.         if (m_menu.GetStateDown(SteamVR_Input_Sources.Any))
    305.             state.buttons |= 1 << 2;
    306.  
    307.  
    308.         state.stick_value = m_stick.GetAxis(SteamVR_Input_Sources.Any);
    309.         state.trigger_Value = m_trigger.GetAxis(SteamVR_Input_Sources.Any);
    310.  
    311.         InputSystem.QueueStateEvent(this, state);
    312.     }
    313. }
    314.  
    Please help me to fix the error.
     

    Attached Files:

  2. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    The matcher you've set up for the layout is more specific than the information supplied here. Thus the failure.

    Here, you require "deviceClass" to be set as well. Thus the match fails.

    These you can put directly on SteamVRCustomDevice BTW.

    Code (CSharp):
    1. [InputControlLayout(..., commonUsages = new[] { "Right", "Left" })
    2. public class SteamVRCustomDevice : ...
     
  3. EliotVR

    EliotVR

    Joined:
    Jan 12, 2017
    Posts:
    14
    Thank you Rene-Damm.
    I fixed my code.
    It worked well
     

    Attached Files: