using System.Collections.Generic;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.XR;
using UnityEngine.Scripting;
using UnityEngine.XR.OpenXR.Input;
#if UNITY_EDITOR
using UnityEditor;
#endif
#if USE_INPUT_SYSTEM_POSE_CONTROL
using PoseControl = UnityEngine.InputSystem.XR.PoseControl;
#else
using PoseControl = UnityEngine.XR.OpenXR.Input.PoseControl;
#endif
#if USE_STICK_CONTROL_THUMBSTICKS
using ThumbstickControl = UnityEngine.InputSystem.Controls.StickControl; // If replaced, make sure the control extends Vector2Control
#else
using ThumbstickControl = UnityEngine.InputSystem.Controls.Vector2Control;
#endif
namespace UnityEngine.XR.OpenXR.Features.Interactions
{
///
/// This enables the use of Valve Index Controllers interaction profiles in OpenXR.
///
#if UNITY_EDITOR
[UnityEditor.XR.OpenXR.Features.OpenXRFeature(UiName = "Valve Index Controller Profile",
BuildTargetGroups = new[] { BuildTargetGroup.Standalone, BuildTargetGroup.WSA },
Company = "Unity",
Desc = "Allows for mapping input to the Valve Index Controller interaction profile.",
DocumentationLink = Constants.k_DocumentationManualURL + "features/valveindexcontrollerprofile.html",
OpenxrExtensionStrings = "",
Version = "0.0.1",
Category = UnityEditor.XR.OpenXR.Features.FeatureCategory.Interaction,
FeatureId = featureId)]
#endif
public class ValveIndexControllerProfile : OpenXRInteractionFeature
{
///
/// The feature id string. This is used to give the feature a well known id for reference.
///
public const string featureId = "com.unity.openxr.feature.input.valveindex";
///
/// An Input System device based on the hand interaction profile in the Valve Index Controller.
///
[Preserve, InputControlLayout(displayName = "Index Controller (OpenXR)", commonUsages = new[] { "LeftHand", "RightHand" })]
public class ValveIndexController : XRControllerWithRumble
{
///
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR binding.
///
[Preserve, InputControl(alias = "systemButton", usage = "MenuButton")]
public ButtonControl system { get; private set; }
///
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR binding.
///
[Preserve, InputControl(usage = "MenuTouch")]
public ButtonControl systemTouched { get; private set; }
///
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR binding.
///
[Preserve, InputControl(usage = "PrimaryButton")]
public ButtonControl primaryButton { get; private set; }
///
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR binding.
///
[Preserve, InputControl(usage = "PrimaryTouch")]
public ButtonControl primaryTouched { get; private set; }
///
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR binding.
///
[Preserve, InputControl(usage = "SecondaryButton")]
public ButtonControl secondaryButton { get; private set; }
///
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR binding.
///
[Preserve, InputControl(usage = "SecondaryTouch")]
public ButtonControl secondaryTouched { get; private set; }
///
/// A [AxisControl](xref:UnityEngine.InputSystem.Controls.AxisControl) that represents the OpenXR binding.
///
[Preserve, InputControl(aliases = new[] { "GripAxis", "squeeze" }, usage = "Grip")]
public AxisControl grip { get; private set; }
///
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the Valve Index Controller Profile gripPressed OpenXR binding.
///
[Preserve, InputControl(aliases = new[] { "GripButton", "squeezeClicked" }, usage = "GripButton")]
public ButtonControl gripPressed { get; private set; }
///
/// A [AxisControl](xref:UnityEngine.InputSystem.Controls.AxisControl) that represents the OpenXR binding.
///
[Preserve, InputControl(alias = "squeezeForce", usage = "GripForce")]
public AxisControl gripForce { get; private set; }
///
/// A [AxisControl](xref:UnityEngine.InputSystem.Controls.AxisControl) that represents the OpenXR binding.
///
[Preserve, InputControl(usage = "Trigger")]
public AxisControl trigger { get; private set; }
///
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR binding.
///
[Preserve, InputControl(usage = "TriggerButton")]
public ButtonControl triggerPressed { get; private set; }
///
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR binding.
///
[Preserve, InputControl(usage = "TriggerTouch")]
public ButtonControl triggerTouched { get; private set; }
///
/// A [Vector2Control](xref:UnityEngine.InputSystem.Controls.Vector2Control)/[StickControl](xref:UnityEngine.InputSystem.Controls.StickControl) that represents the OpenXR binding.
///
[Preserve, InputControl(aliases = new[] { "joystick", "Primary2DAxis" }, usage = "Primary2DAxis")]
public ThumbstickControl thumbstick { get; private set; }
///
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR binding.
///
[Preserve, InputControl(alias = "joystickClicked", usage = "Primary2DAxisClick")]
public ButtonControl thumbstickClicked { get; private set; }
///
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR binding.
///
[Preserve, InputControl(alias = "joystickTouched", usage = "Primary2DAxisTouch")]
public ButtonControl thumbstickTouched { get; private set; }
///
/// A [Vector2Control](xref:UnityEngine.InputSystem.Controls.Vector2Control)/[StickControl](xref:UnityEngine.InputSystem.Controls.StickControl) that represents the OpenXR binding.
///
[Preserve, InputControl(aliases = new[] { "touchpad", "Secondary2DAxis" }, usage = "Secondary2DAxis")]
public ThumbstickControl trackpad { get; private set; }
///
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR binding.
///
[Preserve, InputControl(alias = "touchpadTouched", usage = "Secondary2DAxisTouch")]
public ButtonControl trackpadTouched { get; private set; }
///
/// A [AxisControl](xref:UnityEngine.InputSystem.Controls.AxisControl) that represents the OpenXR binding.
///
[Preserve, InputControl(alias = "touchpadForce", usage = "Secondary2DAxisForce")]
public AxisControl trackpadForce { get; private set; }
///
/// A that represents the OpenXR binding.
///
[Preserve, InputControl(offset = 0, aliases = new[] { "device", "gripPose" }, usage = "Device")]
public PoseControl devicePose { get; private set; }
///
/// A that represents the Valve Index Controller Profile pointer OpenXR binding.
///
[Preserve, InputControl(offset = 0, alias = "aimPose", usage = "Pointer")]
public PoseControl pointer { get; private set; }
///
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) required for backwards compatibility with the XRSDK layouts. This represents the overall tracking state of the device. This value is equivalent to mapping devicePose/isTracked.
///
[Preserve, InputControl(offset = 53)]
new public ButtonControl isTracked { get; private set; }
///
/// A [IntegerControl](xref:UnityEngine.InputSystem.Controls.IntegerControl) required for backwards compatibility with the XRSDK layouts. This represents the bit flag set indicating what data is valid. This value is equivalent to mapping devicePose/trackingState.
///
[Preserve, InputControl(offset = 56)]
new public IntegerControl trackingState { get; private set; }
///
/// A [Vector3Control](xref:UnityEngine.InputSystem.Controls.Vector3Control) required for backwards compatibility with the XRSDK layouts. This is the device position, or grip position. This value is equivalent to mapping devicePose/position.
///
[Preserve, InputControl(offset = 60, alias = "gripPosition")]
new public Vector3Control devicePosition { get; private set; }
///
/// A [QuaternionControl](xref:UnityEngine.InputSystem.Controls.QuaternionControl) required for backwards compatibility with the XRSDK layouts. This is the device orientation, or grip orientation. This value is equivalent to mapping devicePose/rotation.
///
[Preserve, InputControl(offset = 72, alias = "gripOrientation")]
new public QuaternionControl deviceRotation { get; private set; }
///
/// A [Vector3Control](xref:UnityEngine.InputSystem.Controls.Vector3Control) required for backwards compatibility with the XRSDK layouts. This is the pointer position. This value is equivalent to mapping pointerPose/position.
///
[Preserve, InputControl(offset = 120)]
public Vector3Control pointerPosition { get; private set; }
///
/// A [QuaternionControl](xref:UnityEngine.InputSystem.Controls.QuaternionControl) required for backwards compatibility with the XRSDK layouts. This is the pointer rotation. This value is equivalent to mapping pointerPose/rotation.
///
[Preserve, InputControl(offset = 132, alias = "pointerOrientation")]
public QuaternionControl pointerRotation { get; private set; }
///
/// A that represents the binding.
///
[Preserve, InputControl(usage = "Haptic")]
public HapticControl haptic { get; private set; }
///
protected override void FinishSetup()
{
base.FinishSetup();
system = GetChildControl("system");
systemTouched = GetChildControl("systemTouched");
primaryButton = GetChildControl("primaryButton");
primaryTouched = GetChildControl("primaryTouched");
secondaryButton = GetChildControl("secondaryButton");
secondaryTouched = GetChildControl("secondaryTouched");
grip = GetChildControl("grip");
gripPressed = GetChildControl("gripPressed");
gripForce = GetChildControl("gripForce");
trigger = GetChildControl("trigger");
triggerPressed = GetChildControl("triggerPressed");
triggerTouched = GetChildControl("triggerTouched");
thumbstick = GetChildControl("thumbstick");
thumbstickClicked = GetChildControl("thumbstickClicked");
thumbstickTouched = GetChildControl("thumbstickTouched");
trackpad = GetChildControl("trackpad");
trackpadTouched = GetChildControl("trackpadTouched");
trackpadForce = GetChildControl("trackpadForce");
devicePose = GetChildControl("devicePose");
pointer = GetChildControl("pointer");
isTracked = GetChildControl("isTracked");
trackingState = GetChildControl("trackingState");
devicePosition = GetChildControl("devicePosition");
deviceRotation = GetChildControl("deviceRotation");
pointerPosition = GetChildControl("pointerPosition");
pointerRotation = GetChildControl("pointerRotation");
haptic = GetChildControl("haptic");
}
}
///
/// The interaction profile string used to reference the Valve Index Controller.
///
public const string profile = "/interaction_profiles/valve/index_controller";
///
/// Constant for a boolean interaction binding '.../input/system/click' OpenXR Input Binding.
///
public const string system = "/input/system/click";
///
/// Constant for a boolean interaction binding '.../input/system/touch' OpenXR Input Binding.
///
public const string systemTouch = "/input/system/touch";
///
/// Constant for a boolean interaction binding '.../input/a/click' OpenXR Input Binding.
///
public const string buttonA = "/input/a/click";
///
/// Constant for a boolean interaction binding '.../input/a/touch' OpenXR Input Binding.
///
public const string buttonATouch = "/input/a/touch";
///
/// Constant for a boolean interaction binding '.../input/b/click' OpenXR Input Binding.
///
public const string buttonB = "/input/b/click";
///
/// Constant for a boolean interaction binding '.../input/b/touch' OpenXR Input Binding.
///
public const string buttonBTouch = "/input/b/touch";
///
/// Constant for a float interaction binding '.../input/squeeze/value' OpenXR Input Binding.
///
public const string squeeze = "/input/squeeze/value";
///
/// Constant for a float interaction binding '.../input/squeeze/force' OpenXR Input Binding.
///
public const string squeezeForce = "/input/squeeze/force";
///
/// Constant for a boolean interaction binding '.../input/trigger/click' OpenXR Input Binding.
///
public const string triggerClick = "/input/trigger/click";
///
/// Constant for a float interaction binding '.../input/trigger/value' OpenXR Input Binding.
///
public const string trigger = "/input/trigger/value";
///
/// Constant for a boolean interaction binding '.../input/trigger/touch' OpenXR Input Binding.
///
public const string triggerTouch = "/input/trigger/touch";
///
/// Constant for a Vector2 interaction binding '.../input/thumbstick' OpenXR Input Binding.
///
public const string thumbstick = "/input/thumbstick";
///
/// Constant for a boolean interaction binding '.../input/thumbstick/click' OpenXR Input Binding.
///
public const string thumbstickClick = "/input/thumbstick/click";
///
/// Constant for a boolean interaction binding '.../input/thumbstick/touch' OpenXR Input Binding.
///
public const string thumbstickTouch = "/input/thumbstick/touch";
///
/// Constant for a Vector2 interaction binding '.../input/trackpad' OpenXR Input Binding.
///
public const string trackpad = "/input/trackpad";
///
/// Constant for a float interaction binding '.../input/trackpad/force' OpenXR Input Binding.
///
public const string trackpadForce = "/input/trackpad/force";
///
/// Constant for a boolean interaction binding '.../input/trackpad/touch' OpenXR Input Binding.
///
public const string trackpadTouch = "/input/trackpad/touch";
///
/// Constant for a pose interaction binding '.../input/grip/pose' OpenXR Input Binding.
///
public const string grip = "/input/grip/pose";
///
/// Constant for a pose interaction binding '.../input/aim/pose' OpenXR Input Binding.
///
public const string aim = "/input/aim/pose";
///
/// Constant for a haptic interaction binding '.../output/haptic' OpenXR Input Binding.
///
public const string haptic = "/output/haptic";
private const string kDeviceLocalizedName = "Index Controller OpenXR";
///
/// Registers the layout with the Input System.
///
protected override void RegisterDeviceLayout()
{
#if UNITY_EDITOR
if (!OpenXRLoaderEnabledForSelectedBuildTarget(EditorUserBuildSettings.selectedBuildTargetGroup))
return;
#endif
InputSystem.InputSystem.RegisterLayout(typeof(ValveIndexController),
matches: new InputDeviceMatcher()
.WithInterface(XRUtilities.InterfaceMatchAnyVersion)
.WithProduct(kDeviceLocalizedName));
}
///
/// Removes the layout from the Input System.
///
protected override void UnregisterDeviceLayout()
{
#if UNITY_EDITOR
if (!OpenXRLoaderEnabledForSelectedBuildTarget(EditorUserBuildSettings.selectedBuildTargetGroup))
return;
#endif
InputSystem.InputSystem.RemoveLayout(nameof(ValveIndexController));
}
///
/// Return device layout string that used for registering device for the Input System.
///
/// Device layout string.
protected override string GetDeviceLayoutName()
{
return nameof(ValveIndexController);
}
///
protected override void RegisterActionMapsWithRuntime()
{
ActionMapConfig actionMap = new ActionMapConfig()
{
name = "valveindexcontroller",
localizedName = kDeviceLocalizedName,
desiredInteractionProfile = profile,
manufacturer = "Valve",
serialNumber = "",
deviceInfos = new List()
{
new DeviceConfig()
{
characteristics = (InputDeviceCharacteristics)(InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Left),
userPath = UserPaths.leftHand
},
new DeviceConfig()
{
characteristics = (InputDeviceCharacteristics)(InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Right),
userPath = UserPaths.rightHand
}
},
actions = new List()
{
new ActionConfig()
{
name = "system",
localizedName = "System",
type = ActionType.Binary,
usages = new List()
{
"MenuButton"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = system,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "systemTouched",
localizedName = "System Touched",
type = ActionType.Binary,
usages = new List()
{
"MenuTouch"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = systemTouch,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "primaryButton",
localizedName = "Primary Button",
type = ActionType.Binary,
usages = new List()
{
"PrimaryButton"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = buttonA,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "primaryTouched",
localizedName = "Primary Touched",
type = ActionType.Binary,
usages = new List()
{
"PrimaryTouch"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = buttonATouch,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "secondaryButton",
localizedName = "Secondary Button",
type = ActionType.Binary,
usages = new List()
{
"SecondaryButton"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = buttonB,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "secondaryTouched",
localizedName = "Secondary Touched",
type = ActionType.Binary,
usages = new List()
{
"SecondaryTouch"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = buttonBTouch,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "grip",
localizedName = "Grip",
type = ActionType.Axis1D,
usages = new List()
{
"Grip"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = squeeze,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "gripPressed",
localizedName = "Grip Pressed",
type = ActionType.Binary,
usages = new List()
{
"GripButton"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = squeeze,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "gripForce",
localizedName = "Grip Force",
type = ActionType.Axis1D,
usages = new List()
{
"GripForce"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = squeezeForce,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "trigger",
localizedName = "Trigger",
type = ActionType.Axis1D,
usages = new List()
{
"Trigger"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = trigger,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "triggerPressed",
localizedName = "Triggger Pressed",
type = ActionType.Binary,
usages = new List()
{
"TriggerButton"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = triggerClick,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "triggerTouched",
localizedName = "Trigger Touched",
type = ActionType.Binary,
usages = new List()
{
"TriggerTouch"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = triggerTouch,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "thumbstick",
localizedName = "Thumbstick",
type = ActionType.Axis2D,
usages = new List()
{
"Primary2DAxis"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = thumbstick,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "thumbstickClicked",
localizedName = "Thumbstick Clicked",
type = ActionType.Binary,
usages = new List()
{
"Primary2DAxisClick"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = thumbstickClick,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "thumbstickTouched",
localizedName = "Thumbstick Touched",
type = ActionType.Binary,
usages = new List()
{
"Primary2DAxisTouch"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = thumbstickTouch,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "trackpad",
localizedName = "Trackpad",
type = ActionType.Axis2D,
usages = new List()
{
"Secondary2DAxis"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = trackpad,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "trackpadForce",
localizedName = "Trackpad Force",
type = ActionType.Axis1D,
usages = new List()
{
"Secondary2DAxisForce"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = trackpadForce,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "trackpadTouched",
localizedName = "Trackpad Touched",
type = ActionType.Binary,
usages = new List()
{
"Secondary2DAxisTouch"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = trackpadTouch,
interactionProfileName = profile,
}
}
},
// Device Pose
new ActionConfig()
{
name = "devicePose",
localizedName = "Device Pose",
type = ActionType.Pose,
usages = new List()
{
"Device"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = grip,
interactionProfileName = profile,
}
}
},
// Pointer Pose
new ActionConfig()
{
name = "pointer",
localizedName = "Pointer Pose",
type = ActionType.Pose,
usages = new List()
{
"Pointer"
},
bindings = new List()
{
new ActionBinding()
{
interactionPath = aim,
interactionProfileName = profile,
}
}
},
// Haptics
new ActionConfig()
{
name = "haptic",
localizedName = "Haptic Output",
type = ActionType.Vibrate,
usages = new List() { "Haptic" },
bindings = new List()
{
new ActionBinding()
{
interactionPath = haptic,
interactionProfileName = profile,
}
}
}
}
};
AddActionMap(actionMap);
}
}
}