Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Question Can't use button arrays for a custom device

Discussion in 'Input System' started by rz_0lento, Aug 19, 2020.

  1. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    I'm building a custom device to process DirectInput (input + ffb). I could get Input Debugger to show button arrays by following code:
    Code (CSharp):
    1. [InputControl(name = "dpad", layout = "Dpad", displayName = "D-Pad", sizeInBits = 4, bit = 0)]
    2. [InputControl(name = "button", layout = "Button", arraySize = 28, bit = 4)]
    3. public uint buttons;
    4.  
    While looking at Input Debugger I can tell this creates 28 buttons with increasing offset and bit 4 on all of the buttons in the array. It appears though that the input system doesn't actually map the buttons properly this way. When I press the button on my device, it DOES change the "buttons" variable properly (no issues there) but neither input system or input debugger detects these button presses beyond first button on the array.

    If I however do this:
    Code (CSharp):
    1. [InputControl(name = "dpad", layout = "Dpad", displayName = "D-Pad", sizeInBits = 4, bit = 0)]
    2. [InputControl(name = "button1", layout = "Button", bit = 4)]
    3. [InputControl(name = "button2", layout = "Button", bit = 5)]
    4. ..
    5. [InputControl(name = "button27", layout = "Button", bit = 30)]
    6. [InputControl(name = "button28", layout = "Button", bit = 31)]
    7. public uint buttons;
    it does let me set all buttons just fine.

    I'm using the following code to set the bits:
    Code (CSharp):
    1. void SetButton(int index, bool value, ref DirectInputControllerState state)
    2. {
    3.     var bit = (uint)1 << index;
    4.     if (value)
    5.     {
    6.         state.buttons |= bit;
    7.     }
    8.     else
    9.     {
    10.         state.buttons &= ~bit;
    11.     }
    12. }
    Is there any way to go with the array approach? Declaring each button separately (one extra LOC per button) is just ugly when you can have potentially 128 buttons + d-pad on a DirectInput device

    Additionally in ideal case, I could set the button amount per detected DirectInput device but current Custom Device structure doesn't seem to support this. I need to register the button amount ahead of time with IInputStateTypeInfo - well before the device gets detected.
     
  2. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    Yeah, unfortunately arrays of bit-addressed controls are not supported. Sounds like something the device builder should at least diagnose.

    Individual layouts indeed need to be more or less fixed (there's support for "variants" where a single layout can produce several different variations of the same structure but would generally recommend steering clear of that). However, there is a feature to allow custom-tailored layouts to be built for device that are fully known only at runtime. Whether that's worth the cost largely depends on the specific use case.

    The way this is usually set up is by hooking into InputSystem.onFindLayoutForDevice

    Code (CSharp):
    1. string MyOnFindLayoutForDevice(ref InputDeviceDescription description, string matchedLayout, InputDeviceExecuteCommandDelegate executeDeviceCommand)
    2. {
    3.     // Let's say you're reporting your devices with the "DirectInput" interface.
    4.     if (description.interfaceName != "DirectInput")
    5.         return null;
    6.  
    7.     // Check if we already generated a layout.
    8.     if (!string.IsNullOrEmpty(matchedLayout))
    9.         return null;
    10.  
    11.     // See how many buttons this device has. This kind of stuff is usually reported
    12.     // in JSON format in the InputDeviceDescription.capabilities string.
    13.     var caps = JsonUtility.FromJson<MyDeviceCaps>(description.capabilities);
    14.  
    15.     // Now register a layout builder that will generate a layout with the exact number
    16.     // of buttons.
    17.     var layoutName = "DirectInput:" + description.product;
    18.     InputSystem.RegisterLayoutBuilder(name: layoutName,
    19.         buildMethod: () =>
    20.         {
    21.             var builder = new InputControlLayout.Builder
    22.                 .WithName(layoutName)
    23.                 /* ... */;
    24.  
    25.             // Add buttons.
    26.             for (var i = 0; i < caps.numButtons; ++i)
    27.                 builder.AddControl("button" + i)
    28.                     .WithLayout("Button")
    29.                     /* ... */;
    30.  
    31.             return builder.Build();
    32.         },
    33.         matches: InputDeviceMatcher.FromDeviceDescription(description));
    34. }
    35.  
    36. [Serializable]
    37. struct MyDeviceCaps
    38. {
    39.     public int numButtons;
    40. }
    41.  
    42. InputSystem.onFindLayoutForDevice += MyOnFindLayoutForDevice;
     
    Last edited: Aug 19, 2020
    rz_0lento likes this.