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