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); } } }