#if ENABLE_VR || UNITY_GAMECORE || PACKAGE_DOCS_GENERATION
using System.Collections.Generic;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.XR;
using UnityEngine.Scripting;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UnityEngine.XR.Hands
{
///
/// An that surfaces common controller data
/// populated by hand joint poses. Devices will only be created if
/// hand-tracking is enabled in the build settings for the target platform.
///
///
/// The and
/// inherited from
/// represent the wrist pose.
///
/// Use the [XROrigin](xref:Unity.XR.CoreUtils.XROrigin) in the scene to position and orient the device
/// and gesture poses properly. If you are using this data to set the Transform of a GameObject in
/// the scene hierarchy, you can set the local position and rotation of the Transform and make
/// it a child of the CameraOffset object below the XROrigin. Otherwise, you can use the
/// Transform of the CameraOffset to transform the data into world space.
///
#if UNITY_EDITOR
[InitializeOnLoad]
#endif
[Preserve, InputControlLayout(displayName = "XR Hand Device", commonUsages = new[] { "LeftHand", "RightHand" })]
public class XRHandDevice : TrackedDevice
{
///
/// The left-hand that contains
/// s that surface common controller data
/// populated by hand joint poses.
///
public static XRHandDevice leftHand { get; internal set; }
///
/// The right-hand that contains
/// s that surface common controller data
/// populated by hand joint poses.
///
public static XRHandDevice rightHand { get; internal set; }
///
/// Position of the grip pose, representing the palm.
/// When transformed relative to the [XROrigin](xref:Unity.XR.CoreUtils.XROrigin),
/// the position will be in the correct position in the scene relative to the user.
///
[Preserve, InputControl]
public Vector3Control gripPosition { get; private set; }
///
/// Rotation of the grip pose, representing the palm.
/// When transformed relative to the [XROrigin](xref:Unity.XR.CoreUtils.XROrigin),
/// the rotation will be in the correct orientation in the scene relative to the user.
///
[Preserve, InputControl]
public QuaternionControl gripRotation { get; private set; }
///
/// Position of the poke pose, representing the index finger's tip.
/// When transformed relative to the [XROrigin](xref:Unity.XR.CoreUtils.XROrigin),
/// the position will be in the correct position in the scene relative to the user.
///
[Preserve, InputControl]
public Vector3Control pokePosition { get; private set; }
///
/// Rotation of the poke pose, representing the index finger's tip.
/// When transformed relative to the [XROrigin](xref:Unity.XR.CoreUtils.XROrigin),
/// the rotation will be in the correct orientation in the scene relative to the user.
///
[Preserve, InputControl]
public QuaternionControl pokeRotation { get; private set; }
///
/// Position of the pinch pose, representing the thumb's tip.
/// When transformed relative to the [XROrigin](xref:Unity.XR.CoreUtils.XROrigin),
/// the position will be in the correct position in the scene relative to the user.
///
[Preserve, InputControl]
public Vector3Control pinchPosition { get; private set; }
///
/// Rotation of the pinch pose, representing the thumb's tip.
/// When transformed relative to the [XROrigin](xref:Unity.XR.CoreUtils.XROrigin),
/// the rotation will be in the correct orientation in the scene relative to the user.
///
[Preserve, InputControl]
public QuaternionControl pinchRotation { get; private set; }
///
/// Perform final initialization tasks after the control hierarchy has been put into place.
///
protected override void FinishSetup()
{
base.FinishSetup();
gripPosition = GetChildControl("gripPosition");
gripRotation = GetChildControl("gripRotation");
pokePosition = GetChildControl("pokePosition");
pokeRotation = GetChildControl("pokeRotation");
pinchPosition = GetChildControl("pinchPosition");
pinchRotation = GetChildControl("pinchRotation");
var deviceDescriptor = XRDeviceDescriptor.FromJson(description.capabilities);
if (deviceDescriptor != null)
{
if ((deviceDescriptor.characteristics & InputDeviceCharacteristics.Left) != 0)
InputSystem.InputSystem.SetDeviceUsage(this, InputSystem.CommonUsages.LeftHand);
else if ((deviceDescriptor.characteristics & InputDeviceCharacteristics.Right) != 0)
InputSystem.InputSystem.SetDeviceUsage(this, InputSystem.CommonUsages.RightHand);
}
}
internal static XRHandDevice Create(
XRHandSubsystem subsystem,
Handedness handedness,
XRHandSubsystem.UpdateSuccessFlags updateSuccessFlags,
XRHandSubsystem.UpdateType updateType)
{
var extraCharacteristics = handedness == Handedness.Left ? InputDeviceCharacteristics.Left : InputDeviceCharacteristics.Right;
var desc = new InputDeviceDescription
{
product = k_DeviceProductName,
capabilities = new XRDeviceDescriptor
{
characteristics = InputDeviceCharacteristics.HandTracking | InputDeviceCharacteristics.TrackedDevice | extraCharacteristics,
inputFeatures = new List
{
new XRFeatureDescriptor
{
name = "grip_position",
featureType = FeatureType.Axis3D
},
new XRFeatureDescriptor
{
name = "grip_rotation",
featureType = FeatureType.Rotation
},
new XRFeatureDescriptor
{
name = "poke_position",
featureType = FeatureType.Axis3D
},
new XRFeatureDescriptor
{
name = "poke_rotation",
featureType = FeatureType.Rotation
},
new XRFeatureDescriptor
{
name = "pinch_position",
featureType = FeatureType.Axis3D
},
new XRFeatureDescriptor
{
name = "pinch_rotation",
featureType = FeatureType.Rotation
}
}
}.ToJson()
};
var handDevice = InputSystem.InputSystem.AddDevice(desc) as XRHandDevice;
if (handDevice != null)
{
subsystem.updatedHands += handDevice.OnUpdatedHands;
handDevice.m_Handedness = handedness;
handDevice.OnUpdatedHands(subsystem, updateSuccessFlags, updateType);
}
return handDevice;
}
void OnUpdatedHands(XRHandSubsystem subsystem, XRHandSubsystem.UpdateSuccessFlags updateSuccessFlags, XRHandSubsystem.UpdateType updateType)
{
XRHand hand;
bool isValid;
if (m_Handedness == Handedness.Left)
{
hand = subsystem.leftHand;
var success = XRHandSubsystem.UpdateSuccessFlags.LeftHandRootPose | XRHandSubsystem.UpdateSuccessFlags.LeftHandJoints;
isValid = (updateSuccessFlags & success) == success;
}
else
{
hand = subsystem.rightHand;
var success = XRHandSubsystem.UpdateSuccessFlags.RightHandRootPose | XRHandSubsystem.UpdateSuccessFlags.RightHandJoints;
isValid = (updateSuccessFlags & success) == success;
}
if (!m_WasValid && !isValid)
return;
if (m_WasValid && !isValid)
{
InputSystem.InputSystem.QueueDeltaStateEvent(isTracked, false);
InputSystem.InputSystem.QueueDeltaStateEvent(trackingState, InputTrackingState.None);
m_WasValid = false;
return;
}
if (!m_WasValid && isValid)
{
InputSystem.InputSystem.QueueDeltaStateEvent(isTracked, true);
InputSystem.InputSystem.QueueDeltaStateEvent(trackingState, InputTrackingState.Position | InputTrackingState.Rotation);
m_WasValid = true;
}
if (hand.GetJoint(XRHandJointID.Wrist).TryGetPose(out var wristPose))
{
InputSystem.InputSystem.QueueDeltaStateEvent(devicePosition, wristPose.position);
InputSystem.InputSystem.QueueDeltaStateEvent(deviceRotation, wristPose.rotation);
}
if (hand.GetJoint(XRHandJointID.Palm).TryGetPose(out var palmPose))
{
InputSystem.InputSystem.QueueDeltaStateEvent(gripPosition, palmPose.position);
InputSystem.InputSystem.QueueDeltaStateEvent(gripRotation, palmPose.rotation);
}
if (hand.GetJoint(XRHandJointID.IndexTip).TryGetPose(out var indexTipPose))
{
InputSystem.InputSystem.QueueDeltaStateEvent(pokePosition, indexTipPose.position);
InputSystem.InputSystem.QueueDeltaStateEvent(pokeRotation, indexTipPose.rotation);
}
if (hand.GetJoint(XRHandJointID.ThumbTip).TryGetPose(out var thumbTipPose))
{
InputSystem.InputSystem.QueueDeltaStateEvent(pinchPosition, thumbTipPose.position);
InputSystem.InputSystem.QueueDeltaStateEvent(pinchRotation, thumbTipPose.rotation);
}
}
static XRHandDevice() => Initialize();
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void Initialize()
{
#if ENABLE_INPUT_SYSTEM
InputSystem.InputSystem.RegisterLayout(
matches: new InputDeviceMatcher()
.WithProduct(k_DeviceProductName));
#endif // ENABLE_INPUT_SYSTEM
}
const string k_DeviceProductName = "XRHandDevice";
Handedness m_Handedness;
bool m_WasValid;
}
}
#endif // ENABLE_VR || UNITY_GAMECORE || PACKAGE_DOCS_GENERATION