Thanks for this @rdjadu - I think I’m following your explanation.
I came back to this issue after working on other things for a couple months, and I’m still having trouble. I can’t for the life of me figure out why, for example, a “Select” action bound to triggerPressed on my custom device is firing through all three phases (started, performed, cancelled) with every OnUpdate callback that the trigger is pressed. The value is not changing (as verified in the Input Debugger); but the action is refiring in its entirety with each update. Maybe, like you mention, I’m not setting up my memory regions correctly? If you have the chance, would you mind taking a look at the custom device and data class in question?
using UnityEngine;
public struct HandedXRControllerDeviceState : IInputStateTypeInfo
{
public FourCC format => new FourCC(a: 'P', b: 'L', c: 'A', d: 'Y');
[InputControl(layout = "Vector2")]
public Vector2 thumbstick;
[InputControl(layout = "Axis")]
public float trigger;
[InputControl(layout = "Axis")]
public float grip;
[InputControl(name = "triggerPressed", layout = "Button", bit = 0)]
[InputControl(name = "gripPressed", layout = "Button", bit = 1)]
[InputControl(name = "buttonSouth", layout = "Button", bit = 2)]
[InputControl(name = "buttonNorth", layout = "Button", bit = 3)]
[InputControl(name = "buttonSystem", layout = "Button", bit = 4)]
[InputControl(name = "thumbstickClicked", layout = "Button", bit = 5)]
[InputControl(name = "triggerTouched", layout = "Button", bit = 6)]
[InputControl(name = "buttonSouthTouched", layout = "Button", bit = 7)]
[InputControl(name = "buttonNorthTouched", layout = "Button", bit = 8)]
[InputControl(name = "thumbstickTouched", layout = "Button", bit = 9)]
public int buttons;
}
#if UNITY_EDITOR
[InitializeOnLoad]
#endif
[InputControlLayout(displayName = "HandedXRController", stateType = typeof(HandedXRControllerDeviceState), commonUsages = new string[] { "ActiveHand", "PassiveHand" })]
public class HandedXRControllerDevice : XRControllerWithRumble, IInputUpdateCallbackReceiver
{
public Vector2Control thumbstick { get; private set; }
public AxisControl trigger { get; private set; }
public AxisControl grip { get; private set; }
public ButtonControl triggerPressed { get; private set; }
public ButtonControl gripPressed { get; private set; }
public ButtonControl buttonSouth { get; private set; }
public ButtonControl buttonNorth { get; private set; }
public ButtonControl buttonSystem { get; private set; }
public ButtonControl thumbstickClicked { get; private set; }
public ButtonControl triggerTouched { get; private set; }
public ButtonControl buttonSouthTouched { get; private set; }
public ButtonControl buttonNorthTouched { get; private set; }
public ButtonControl thumbstickTouched { get; private set; }
protected override void FinishSetup()
{
base.FinishSetup();
thumbstick = GetChildControl<Vector2Control>("thumbstick");
trigger = GetChildControl<AxisControl>("trigger");
grip = GetChildControl<AxisControl>("grip");
triggerPressed = GetChildControl<ButtonControl>("triggerPressed");
gripPressed = GetChildControl<ButtonControl>("gripPressed");
buttonSouth = GetChildControl<ButtonControl>("buttonSouth");
buttonNorth = GetChildControl<ButtonControl>("buttonNorth");
buttonSystem = GetChildControl<ButtonControl>("buttonSystem");
thumbstickClicked = GetChildControl<ButtonControl>("thumbstickClicked");
triggerTouched = GetChildControl<ButtonControl>("triggerTouched");
buttonSouthTouched = GetChildControl<ButtonControl>("buttonSouthTouched");
buttonNorthTouched = GetChildControl<ButtonControl>("buttonNorthTouched");
thumbstickTouched = GetChildControl<ButtonControl>("thumbstickTouched");
}
#if UNITY_EDITOR
static HandedXRControllerDevice() => RegisterLayout();
#endif
[RuntimeInitializeOnLoadMethod]
public static void RegisterLayout()
{
InputSystem.RegisterLayout(
type: typeof(HandedXRControllerDevice),
name: "HandedXRController",
matches: new InputDeviceMatcher()
.WithDeviceClass("^HandedXRController", supportRegex: true)
);
}
public void OnUpdate()
{
// Copy state from generic XRController input device and queue this state for this custom device.
HandedXRControllerDeviceState state = GetXRControllerState();
InputSystem.QueueStateEvent(this, state);
}
private HandedXRControllerDeviceState GetXRControllerState()
{
HandedXRControllerDeviceState state = new HandedXRControllerDeviceState();
// Finds the appropriate XRController device by handedness.
InputDevice targetDevice = InputSystem.GetDevice<XRController>(
usages.Contains(InputDeviceManager.XRUsages.ActiveHand)
? InputDeviceManager.ActiveHand
: InputDeviceManager.PassiveHand
);
// If appropriate device was found, copy it's state to new state struct.
if (targetDevice != null)
{
state.thumbstick = targetDevice.GetChildControl<Vector2Control>("thumbstick").value;
state.trigger = targetDevice.GetChildControl<AxisControl>("trigger").value;
state.grip = targetDevice.GetChildControl<AxisControl>("grip").value;
if (targetDevice.GetChildControl<ButtonControl>("triggerPressed").isPressed)
state.buttons |= 1 << 0;
if (targetDevice.GetChildControl<ButtonControl>("gripPressed").isPressed)
state.buttons |= 1 << 1;
if (targetDevice.GetChildControl<ButtonControl>("primaryButton").isPressed)
state.buttons |= 1 << 2;
if (targetDevice.GetChildControl<ButtonControl>("secondaryButton").isPressed)
state.buttons |= 1 << 3;
if (targetDevice.GetChildControl<ButtonControl>("start").isPressed)
state.buttons |= 1 << 4;
if (targetDevice.GetChildControl<ButtonControl>("thumbstickClicked").isPressed)
state.buttons |= 1 << 5;
if (targetDevice.GetChildControl<ButtonControl>("triggerTouched").isPressed)
state.buttons |= 1 << 6;
if (targetDevice.GetChildControl<ButtonControl>("primaryTouched").isPressed)
state.buttons |= 1 << 7;
if (targetDevice.GetChildControl<ButtonControl>("secondaryTouched").isPressed)
state.buttons |= 1 << 8;
if (targetDevice.GetChildControl<ButtonControl>("thumbstickTouched").isPressed)
state.buttons |= 1 << 9;
}
return state;
}
}