Sending data to custom HID device

I managed to implement the custom HID device in Unity Input System and I can read from it easily. But how to send data back to the HID device?

This is the IInputDeviceCommandInfo implementation I have:

[StructLayout(LayoutKind.Explicit)]
internal struct MyControlCommand : IInputDeviceCommandInfo
{
    public static FourCC Type { get { return new FourCC("HIDO"); } }
 
    [FieldOffset(0)]
    public byte res;
 
    [FieldOffset(1)]
    public byte magic;
 
    [FieldOffset(2)]
    public byte DataType;
 
    [FieldOffset(3)]
    public short Data;
    public FourCC typeStatic
    {
        get { return Type; }
    }
 
    public static MyControlCommand Create(byte dataType, short data)
    {
        return new MyControlCommand
        {
            magic = 0x7e,
            DataType = dataType,
            Data = data
        };
    }
 }

I wanted to send these bytes:

0x00
0x7e
0x04
0xfff

So I use:

var c = MyControlCommand.Create(0x04, 0xfff);
var res = current.ExecuteCommand(ref c);

but the res variable is -1 (unsuccessful).

I managed to communicate with the device (above bytes worked fine) using HidSharp library and my own HID implementation, but Unity is stubborn…

Thanks for help!

Ok, that was not an easy problem to solve:

The problem was that IInputDeviceCommandInfo does not force user to implement Field(0) to be an InputDeviceCommand. InputDeviceCommand ** must be added at Field(0) offset** and other fields must be shifted respectively.

The second problem was that my device required different size of the output data. OS probably checks if the sizes matches (the one reported by the descriptor in capabilities.outputReportSize and the one actually to be sent).

So I have added missing fields in the struct and it works:

[StructLayout(LayoutKind.Explicit, Size = kSize)]
    internal struct Command2 : IInputDeviceCommandInfo
    {
        public static FourCC Type => new FourCC('H', 'I', 'D', 'O');
        public FourCC typeStatic => Type;

        internal const int kSize = InputDeviceCommand.BaseCommandSize + 31; //<---- calculate manually
          
        [FieldOffset(0)] public InputDeviceCommand baseCommand; // <--- required, overlaps the rest, that's the trick to avoid Marshalling struct to byte array, that I use 
        [FieldOffset(InputDeviceCommand.BaseCommandSize + 0)] public byte zero; // <--- don't know why
        [FieldOffset(InputDeviceCommand.BaseCommandSize + 1)] public byte magic;
        [FieldOffset(InputDeviceCommand.BaseCommandSize + 2)] public byte reportId;
        [FieldOffset(InputDeviceCommand.BaseCommandSize + 3)] public short payload; 
         
        public static Command2 Create(byte id, short payload)
        {
            return new Command2
            {
                baseCommand = new InputDeviceCommand(Type, kSize),
                magic = 0x7e,
                reportId = id,
                payload = payload
            };
        }
    }

I hope someone will benefit from this.