Hello,
I’ve beem trying to add support for my SteamController, since I couldn’t hook it up out of the box.
I’ve done some research and found this:
https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/HID.html
Then I’ve found some references for Hid Inputs for Steam Controller here:
I’ve followed along creating InputDevice/Gamepad and HID Input Report as follows:
SteamControllerHID.cs
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Layouts;
namespace CFG.Runtime.Input
{
// Using InputControlLayoutAttribute, we tell the system about the state
// struct we created, which includes where to find all the InputControl
// attributes that we placed on there. This is how the Input System knows
// what controls to create and how to configure them.
[InputControlLayout(stateType = typeof(SteamControllerHIDInputReport2))]
#if UNITY_EDITOR
[InitializeOnLoad] // Make sure static constructor is called during startup.
#endif
public class SteamControllerHID :
//Gamepad
InputDevice
{
static SteamControllerHID()
{
// This is one way to match the Device.
//InputSystem.RegisterLayout<SteamControllerHID>(name:null,
// new InputDeviceMatcher()
// .WithInterface("HID")
// .WithManufacturer("Valve Software")
// .WithProduct("Steam Controller"));//Wireless Steam Controller
//InputSystem.RegisterLayout<SteamControllerHID>(name: null,
// new InputDeviceMatcher()
// .WithInterface("HID")
// .WithManufacturer("Valve Software")
// .WithProduct("Valve"));//Wired Controller
// Alternatively, you can also match by PID and VID, which is generally
// more reliable for HIDs.
InputSystem.RegisterLayout<SteamControllerHID>(name: "Wireless Steam Controller",
matches: new InputDeviceMatcher()
.WithInterface("HID")
.WithCapability("vendorId", 0x28de) // Valve Software
.WithCapability("productId", 0x1142)); // Wireless Steam Controller
InputSystem.RegisterLayout<SteamControllerHID>(name: "Wired Steam Controller",
matches: new InputDeviceMatcher()
.WithInterface("HID")
.WithCapability("vendorId", 0x28de) // Valve Software
.WithCapability("productId", 0x1102)); // Wired Controller
}
// In the Player, to trigger the calling of the static constructor,
// create an empty method annotated with RuntimeInitializeOnLoadMethod.
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
static void Init() { }
}
}
SteamControllerHIDInputReport2.cs
using System.Runtime.InteropServices;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.InputSystem.Utilities;
namespace CFG.Runtime.Input
{
// We receive data as raw HID input reports. This struct
// describes the raw binary format of such a report.
[StructLayout(LayoutKind.Explicit, Size = 60)]
public struct SteamControllerHIDInputReport2 : IInputStateTypeInfo
{
// Because all HID input reports are tagged with the 'HID ' FourCC,
// this is the format we need to use for this state struct.
public FourCC format => new FourCC('H', 'I', 'D');
//FieldOffset 5-8 sequence number
[InputControl(name = "rightTriggerButton", layout = "Button", bit = 0)]
[InputControl(name = "leftTriggerButton", layout = "Button", bit = 1)]
[InputControl(name = "rightShoulder", layout = "Button", bit = 2)]
[InputControl(name = "leftShoulder", layout = "Button", bit = 3)]
[InputControl(name = "buttonNorth", displayName = "Y", layout = "Button", bit = 4)]
[InputControl(name = "buttonEast", displayName = "B", layout = "Button", bit = 5)]
[InputControl(name = "buttonWest", displayName = "X", layout = "Button", bit = 6)]
[InputControl(name = "buttonSouth", displayName = "A", layout = "Button", bit = 7)]
[FieldOffset(9)] public byte buttonsSet1;
[InputControl(name = "leftPad", layout = "Stick", format = "BYTE")]
[InputControl(name = "leftPad/Up", layout = "Button", bit = 0)]
[InputControl(name = "leftPad/Right", layout = "Button", bit = 1)]
[InputControl(name = "leftPad/Left", layout = "Button", bit = 2)]
[InputControl(name = "leftPad/Down", layout = "Button", bit = 3)]
[InputControl(name = "select", displayName = "Back", layout = "Button", bit = 4)]
[InputControl(name = "systemButton", displayName = "Steam Home Button", layout = "Button", bit = 5)]
[InputControl(name = "start", displayName = "Start", layout = "Button", bit = 6)]
[InputControl(name = "leftGrip", layout = "Button", bit = 7)]
[FieldOffset(10)] public byte buttonsSet2;
[InputControl(name = "righPad", layout = "Stick", format = "BYTE")]
[InputControl(name = "rightGrip", layout = "Button", bit = 0)]
[InputControl(name = "leftPad/Clicked", layout = "Button", bit = 1)]
[InputControl(name = "righPad/Clicked", layout = "Button", bit = 2)]
[InputControl(name = "leftDpadTouched", displayName = "Left Dpad Touched", layout = "Button", bit = 3)]
[InputControl(name = "rightDpadTouched", displayName = "Right Dpad Touched", layout = "Button", bit = 4)]
//offset 5 unknown
[InputControl(name = "joystick_clicked", layout = "Button", bit = 6)]
[InputControl(name = "lpad_and_joy", layout = "Button", bit = 7)]
[FieldOffset(11)] public byte buttonsSet3;
[InputControl(name = "leftTrigger", layout = "Button", format = "BYTE")]
[FieldOffset(12)] public byte leftTrigger;
[InputControl(name = "rightTrigger", layout = "Button", format = "BYTE")]
[FieldOffset(13)] public byte q1;
//FieldOffset 14-16 always 0
[InputControl(name = "leftStickX0", layout = "Button", format = "BYTE")]
[FieldOffset(17)] public byte leftStickX0;
[InputControl(name = "leftStickX1", layout = "Button", format = "BYTE")]
[FieldOffset(18)] public byte leftStickX1;
[InputControl(name = "leftStickY0", layout = "Button", format = "BYTE")]
[FieldOffset(19)] public byte leftStickY0;
[InputControl(name = "leftStickY1", layout = "Button", format = "BYTE")]
[FieldOffset(20)] public byte leftStickY1;
}
}
I was able to get most of the inputs right but the stick and touch pads are more tricky.
I wanted at least to add joystick support for basic movement but I have a problem with getting correct values. Because it looks like X and Y axis data are returned in signed16 type.
So I need to merge/aggregate two bytes into one layout entry but I tried different things with InputControlAttribute without any success.
Here are values that I’ve managed to retrieve:
Pressing down on the joytick x=0, y=-1 :
Pressing left on the joystick x=-1, y = 0 :
Pressing up on the joystick x=0, y=1 :
Pressing right on the joystick x=1, y=0 :
When joystick is in default position X0, X1, Y0, Y1 values are set to 0
So i see that values respond to joystick but I think I need to somehow aggregate two bytes for X and two bytes for Y, and then normalize it in attribute with parameters = "normalize,normalizeMin…
Maybe someone knows how to aggregate those values?



