Search Unity

Question Getting an 8 way DPad to read in the new Input System with a custom HID gamepad

Discussion in 'Input System' started by MrTroyD, Jan 28, 2023.

  1. MrTroyD

    MrTroyD

    Joined:
    Mar 5, 2015
    Posts:
    7
    Hello,

    I'm trying my best to work through this and I think I'm misunderstanding how things work. I have a custom build HID gamepad and I wanted to make it work with Unity. The dPad works fine in other games that I've tried, the Point of view hat shows up just fine in the Windows 10 gamepad screen, so I figure there has to be a way to do it properly within the Unity Input System. Unfortunately the way the input system is reading the DPad doesn't give me proper axis numbers.

    I realize I will have to write my own function to make it work. I have my custom C# file and it recognizes my gamepad. I see the raw bytes and know the order. Using the Dual Shock example I landed here...

    Code (CSharp):
    1.         public FourCC format => new FourCC('H', 'I', 'D');
    2.         [FieldOffset(0)] public byte reportId;
    3.         [InputControl(name = "dPad", format = "BIT", layout = "Dpad", sizeInBits = 4, defaultState = 0)]
    4.         [InputControl(name = "dpad/up", format = "BIT", layout = "DiscreteButton", parameters = "minValue=7,maxValue=1,nullValue=8,wrapAtValue=7", bit = 0, sizeInBits = 4)]
    5.         [InputControl(name = "dpad/right", format = "BIT", layout = "DiscreteButton", parameters = "minValue=1,maxValue=3", bit = 0, sizeInBits = 4)]
    6.         [InputControl(name = "dpad/down", format = "BIT", layout = "DiscreteButton", parameters = "minValue=3,maxValue=5", bit = 0, sizeInBits = 4)]
    7.         [InputControl(name = "dpad/left", format = "BIT", layout = "DiscreteButton", parameters = "minValue=5, maxValue=7", bit = 0, sizeInBits = 4)]
    8.  
    9.         [FieldOffset(7)] public byte dPad;
    My actual question is, when I know that starting with up being 1, up right being 2, and right being 3; I understand that the entire hat should go clockwise to eight. But, I can't seem to figure out how to change my InputControl to read the bits properly. Is there another example outside of the Dual Shock that may be closer to what I'm trying to do that someone can recommend?

    Thank you.
     
  2. rdjadu

    rdjadu

    Joined:
    May 9, 2022
    Posts:
    116
    Is it actually using an enum? Hatswitches are unfortunately represented in different ways on HIDs. If yours is simply a bitfield with 4 on/off bits for the 4 directions, you don't need any of the DiscreteButton and complicated minValue/maxValue/wrapAtValue stuff.

    If it is indeed done as an enum, then if the enum conceptually is

    Code (CSharp):
    1. enum
    2. {
    3.     Up = 0, // Note how this starts at 0.
    4.     UpRight = 1,
    5.     Right = 2,
    6.     RightDown = 3,
    7.     Down = 4,
    8.     DownLeft = 5,
    9.     Left = 6,
    10.     LeftUp = 7,
    11.     Neutral = 8 // All bits set means *no* button pressed.
    12. }
    Normally a DiscreteButton is simply a range of values. This works for right, down, and left. For example, right is simply minValue=1 (UpRight) and maxValue=3 (RightDown). All three values mean the right button is pressed.

    The tricky ones are up. Its range wraps around in the 4-bit integer space. So, up is 0, 1, and 7, but not 8. Which makes for the confusing arrangement in the snippet you posted above. Starts at minValue=7, goes to maxValue=1, wraps around at wrapAtValue=7. Why nullValue needs to be configured explicitly in this case I don't even know :)

    Note that the enumeration of values can be done in a different way. For example, Neutral can be at 0. Shifts the whole thing around accordingly.
     
    MrTroyD likes this.
  3. MrTroyD

    MrTroyD

    Joined:
    Mar 5, 2015
    Posts:
    7
    Thank you rdjadu,

    I ended up hacking together a c# script and doing everything manually.
    Code (CSharp):
    1.  
    2.         [InputControl(name = "dPad", format = "BIT", layout = "Axis",  sizeInBits = 4, defaultState = 0)]
    3.         [FieldOffset(7)] public byte dPad;
    4.  
    In my Input Actions...


    And then, in my player movement.
    Code (CSharp):
    1.  
    2.         float angle = value.Get<float>() * 15;
    3.         int index = (int)(angle - 1);
    4.  
    5.         Vector2 direction = new Vector2();
    6.         if (angle > 0)
    7.         {
    8.             angle = ((angle + 13) % 8) * 45 * Mathf.Deg2Rad;
    9.             direction.x = Mathf.RoundToInt(Mathf.Cos(angle));
    10.             direction.y = Mathf.RoundToInt(Mathf.Sin(angle));
    11.         }
    12.  
    I have a ton of magic numbers going on here, and this is the WRONG way to do it... even if it works. I wanted to respond to your reply so that you know I've read it, and will be attempting to fix it in the future once I figure out how to code the enums properly.