using System.Collections.Generic; using UnityEngine.InputSystem.XR; using UnityEngine.InputSystem.Layouts; using UnityEngine.InputSystem.Controls; using UnityEngine.Scripting; using UnityEngine.XR.OpenXR.Features.Interactions; 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 namespace UnityEngine.XR.OpenXR.Features { /// /// This enables the use of HTC Vive hand interaction profiles in OpenXR. /// #if UNITY_EDITOR [UnityEditor.XR.OpenXR.Features.OpenXRFeature(UiName = "HTC Vive hand interaction Support", BuildTargetGroups = new[] { BuildTargetGroup.Standalone, BuildTargetGroup.WSA }, Company = "HTC", Desc = "Allows for mapping input to the HTC Vive hand interaction interaction profile.", DocumentationLink = "https://developer.vive.com/resources/openxr/openxr-pcvr/tutorials/unity/hand-interaction-profile/", OpenxrExtensionStrings = "XR_HTC_hand_interaction", Version = "0.0.1", Category = UnityEditor.XR.OpenXR.Features.FeatureCategory.Interaction, FeatureId = featureId)] #endif public class HtcViveHandInteractionInputFeature : OpenXRInteractionFeature { /// /// The feature id string. This is used to give the feature a well known id for reference. /// public const string featureId = "com.htc.openxr.feature.input.htcvivehandinteraction"; /// /// An Input System device based off the HTC Vive Controller. /// /// [Preserve, InputControlLayout(displayName = "HTC Vive hand interaction (OpenXR)", commonUsages = new[] { "LeftHand", "RightHand" })] public class ViveHandInteraction : XRController { /// /// A representing information from the OpenXR binding. /// [Preserve, InputControl(aliases = new[] { "GripAxis" })] public AxisControl grip { get; private set; } /// /// A representing information from the OpenXR binding. /// [Preserve, InputControl(aliases = new[] { "selectaxis" })] public AxisControl select { get; private set; } /// /// A representing information from the OpenXR binding. /// [Preserve, InputControl(offset = 0, alias = "device")] public PoseControl devicePose { get; private set; } /// /// A representing information from the OpenXR binding. /// [Preserve, InputControl(offset = 0)] public PoseControl pointer { get; private set; } /// /// A required for back 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 = 28)] new public ButtonControl isTracked { get; private set; } /// /// A required for back 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 = 32)] new public IntegerControl trackingState { get; private set; } /// /// A required for back compatibility with the XRSDK layouts. this is the device position, or grip position. this value is equivalent to mapping devicePose/position /// [Preserve, InputControl(offset = 36, aliases = new[] { "gripPosition" })] new public Vector3Control devicePosition { get; private set; } /// /// A required for back compatibility with the XRSDK layouts. this is the device orientation, or grip orientation. this value is equivalent to mapping devicePose/rotation /// [Preserve, InputControl(offset = 48, aliases = new[] { "gripOrientation", "gripRotation" })] new public QuaternionControl deviceRotation { get; private set; } /// A required for back compatibility with the XRSDK layouts. this is the pointer position. this value is equivalent to mapping pointerPose/position /// [Preserve, InputControl(offset = 96)] public Vector3Control pointerPosition { get; private set; } /// /// A required for back compatibility with the XRSDK layouts. this is the pointer rotation. this value is equivalent to mapping pointerPose/rotation /// [Preserve, InputControl(offset = 108, aliases = new[] { "pointerOrientation" })] public QuaternionControl pointerRotation { get; private set; } protected override void FinishSetup() { base.FinishSetup(); grip = GetChildControl("grip"); select = GetChildControl("select"); devicePose = GetChildControl("devicePose"); pointer = GetChildControl("pointer"); isTracked = GetChildControl("isTracked"); trackingState = GetChildControl("trackingState"); devicePosition = GetChildControl("devicePosition"); deviceRotation = GetChildControl("deviceRotation"); pointerPosition = GetChildControl("pointerPosition"); pointerRotation = GetChildControl("pointerRotation"); } } /// The interaction profile string used to reference the HTC Vive hand interaction. public const string profile = "/interaction_profiles/htc/hand_interaction"; /// /// Constant for a interaction binding '.../input/squeeze/click' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string squeeze = "/input/squeeze/value"; /// /// Constant for a interaction binding '.../input/select/value' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string select = "/input/select/value"; /// /// Constant for a interaction binding '.../input/grip/pose' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string grip = "/input/grip/pose"; /// /// Constant for a interaction binding '.../input/aim/pose' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string aim = "/input/aim/pose"; private const string kDeviceLocalizedName = "HTC Vive hand interaction OpenXR"; /// /// Registers the layout with the Input System. Matches the that is registered with . /// protected override void RegisterDeviceLayout() { InputSystem.InputSystem.RegisterLayout(typeof(ViveHandInteraction), matches: new InputDeviceMatcher() .WithInterface(XRUtilities.InterfaceMatchAnyVersion) .WithProduct(kDeviceLocalizedName)); } /// /// Removes the layout from the Input System. Matches the that is registered with . /// protected override void UnregisterDeviceLayout() { InputSystem.InputSystem.RemoveLayout(typeof(ViveHandInteraction).Name); } /// /// Registers an with OpenXR that matches the HTC Vive hand interaction. Also calls when the Input System package is available. /// protected override void RegisterActionMapsWithRuntime() { ActionMapConfig actionMap = new ActionMapConfig() { name = "ViveHandInteraction", localizedName = kDeviceLocalizedName, desiredInteractionProfile = profile, manufacturer = "HTC", serialNumber = "", deviceInfos = new List() { new DeviceConfig() { characteristics = (InputDeviceCharacteristics)(InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.HandTracking | InputDeviceCharacteristics.Left), userPath = "/user/hand_htc/left" }, new DeviceConfig() { characteristics = (InputDeviceCharacteristics)(InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.HandTracking | InputDeviceCharacteristics.Right), userPath = "/user/hand_htc/right" } }, actions = new List() { 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 = "select", localizedName = "Select", type = ActionType.Axis1D, usages = new List() { "Select" }, bindings = new List() { new ActionBinding() { interactionPath = select, interactionProfileName = profile, } } }, new ActionConfig() { name = "devicepose", localizedName = "Device Pose", type = ActionType.Pose, usages = new List() { "Device" }, bindings = new List() { new ActionBinding() { interactionPath = grip, interactionProfileName = profile, } } }, new ActionConfig() { name = "pointer", localizedName = "Pointer Pose", type = ActionType.Pose, usages = new List() { "Pointer" }, bindings = new List() { new ActionBinding() { interactionPath = aim, interactionProfileName = profile, } } } } }; AddActionMap(actionMap); } } }