using System; #if XR_LEGACY_INPUT_HELPERS_2_1_OR_NEWER || PACKAGE_DOCS_GENERATION using UnityEngine.Experimental.XR.Interaction; using UnityEngine.SpatialTracking; #endif namespace UnityEngine.XR.Interaction.Toolkit { /// /// Interprets feature values on a tracked input controller device from the XR input subsystem /// into XR Interaction states, such as Select. Additionally, it applies the current Pose value /// of a tracked device to the transform of the . /// /// /// It is recommended to use instead of this behavior. /// This behavior does not need as much initial setup as compared to , /// however input processing is less customizable and the cannot be used to drive /// this behavior. /// /// /// [AddComponentMenu("/XR Controller (Device-based)", 11)] [HelpURL(XRHelpURLConstants.k_XRController)] [Obsolete("XRController has been deprecated in version 3.0.0. Its functionality has been distributed into different components.")] public class XRController : XRBaseController { [SerializeField] XRNode m_ControllerNode = XRNode.RightHand; XRNode m_InputDeviceControllerNode; /// /// The for this controller. /// public XRNode controllerNode { get => m_ControllerNode; set => m_ControllerNode = value; } [SerializeField] InputHelpers.Button m_SelectUsage = InputHelpers.Button.Grip; /// /// The input to use for detecting a select. /// public InputHelpers.Button selectUsage { get => m_SelectUsage; set => m_SelectUsage = value; } [SerializeField] InputHelpers.Button m_ActivateUsage = InputHelpers.Button.Trigger; /// /// The input to use for detecting activation. /// public InputHelpers.Button activateUsage { get => m_ActivateUsage; set => m_ActivateUsage = value; } [SerializeField] InputHelpers.Button m_UIPressUsage = InputHelpers.Button.Trigger; /// /// The input to use for detecting a UI press. /// public InputHelpers.Button uiPressUsage { get => m_UIPressUsage; set => m_UIPressUsage = value; } [SerializeField] float m_AxisToPressThreshold = 0.1f; /// /// The amount that a user needs to press an axis in order to trigger an interaction event. /// public float axisToPressThreshold { get => m_AxisToPressThreshold; set => m_AxisToPressThreshold = value; } [SerializeField] InputHelpers.Button m_RotateAnchorLeft = InputHelpers.Button.PrimaryAxis2DLeft; /// /// The input to use to rotate an anchor to the Left. /// public InputHelpers.Button rotateObjectLeft { get => m_RotateAnchorLeft; set => m_RotateAnchorLeft = value; } [SerializeField] InputHelpers.Button m_RotateAnchorRight = InputHelpers.Button.PrimaryAxis2DRight; /// /// The input to use to rotate an anchor to the Right. /// public InputHelpers.Button rotateObjectRight { get => m_RotateAnchorRight; set => m_RotateAnchorRight = value; } [SerializeField] InputHelpers.Button m_MoveObjectIn = InputHelpers.Button.PrimaryAxis2DUp; /// /// The input that will be used to translate the anchor away from the interactor (into the screen / away from the player). /// public InputHelpers.Button moveObjectIn { get => m_MoveObjectIn; set => m_MoveObjectIn = value; } [SerializeField] InputHelpers.Button m_MoveObjectOut = InputHelpers.Button.PrimaryAxis2DDown; /// /// The input that will be used to translate the anchor towards the interactor (out of the screen / towards the player). /// public InputHelpers.Button moveObjectOut { get => m_MoveObjectOut; set => m_MoveObjectOut = value; } [SerializeField] InputHelpers.Axis2D m_DirectionalAnchorRotation = InputHelpers.Axis2D.PrimaryAxis2D; /// /// The input to use to compute a directional angle to rotate the interactor's attach point to match it. /// public InputHelpers.Axis2D directionalAnchorRotation { get => m_DirectionalAnchorRotation; set => m_DirectionalAnchorRotation = value; } #if XR_LEGACY_INPUT_HELPERS_2_1_OR_NEWER || PACKAGE_DOCS_GENERATION [SerializeField] BasePoseProvider m_PoseProvider; /// /// Pose provider used to provide tracking data separate from the . /// public BasePoseProvider poseProvider { get => m_PoseProvider; set => m_PoseProvider = value; } #else // Try to maintain the serialized reference if the XR Legacy Input Helpers package is not installed [SerializeField] MonoBehaviour m_PoseProvider; #endif InputDevice m_InputDevice; /// /// (Read Only) The Unity uses to read data from. /// public InputDevice inputDevice { get { if (m_InputDeviceControllerNode != m_ControllerNode || !m_InputDevice.isValid) { m_InputDevice = InputDevices.GetDeviceAtXRNode(m_ControllerNode); m_InputDeviceControllerNode = m_ControllerNode; } return m_InputDevice; } } /// protected override void Awake() { base.Awake(); #if !XR_LEGACY_INPUT_HELPERS_2_1_OR_NEWER if (m_PoseProvider != null) { Debug.LogWarning("Pose Provider requires the XR Legacy Input Helpers (com.unity.xr.legacyinputhelpers) package to be installed to use.", this); } #endif } /// protected override void UpdateTrackingInput(XRControllerState controllerState) { base.UpdateTrackingInput(controllerState); if (controllerState == null) return; controllerState.isTracked = inputDevice.TryGetFeatureValue(CommonUsages.isTracked, out var isTracked) && isTracked; controllerState.inputTrackingState = InputTrackingState.None; #if XR_LEGACY_INPUT_HELPERS_2_1_OR_NEWER if (m_PoseProvider != null) { var retFlags = m_PoseProvider.GetPoseFromProvider(out var poseProviderPose); if ((retFlags & PoseDataFlags.Position) != 0) { controllerState.position = poseProviderPose.position; controllerState.inputTrackingState |= InputTrackingState.Position; } if ((retFlags & PoseDataFlags.Rotation) != 0) { controllerState.rotation = poseProviderPose.rotation; controllerState.inputTrackingState |= InputTrackingState.Rotation; } } else #endif { if (inputDevice.TryGetFeatureValue(CommonUsages.trackingState, out var trackingState)) { controllerState.inputTrackingState = trackingState; if ((trackingState & InputTrackingState.Position) != 0 && inputDevice.TryGetFeatureValue(CommonUsages.devicePosition, out var devicePosition)) { controllerState.position = devicePosition; } if ((trackingState & InputTrackingState.Rotation) != 0 && inputDevice.TryGetFeatureValue(CommonUsages.deviceRotation, out var deviceRotation)) { controllerState.rotation = deviceRotation; } } } } /// protected override void UpdateInput(XRControllerState controllerState) { base.UpdateInput(controllerState); if (controllerState == null) return; controllerState.ResetFrameDependentStates(); controllerState.selectInteractionState.SetFrameState(IsPressed(m_SelectUsage), ReadValue(m_SelectUsage)); controllerState.activateInteractionState.SetFrameState(IsPressed(m_ActivateUsage), ReadValue(m_ActivateUsage)); controllerState.uiPressInteractionState.SetFrameState(IsPressed(m_UIPressUsage), ReadValue(m_UIPressUsage)); } /// /// Evaluates whether the button is considered pressed. /// /// The button to check. /// Returns when the button is considered pressed. Otherwise, returns . protected virtual bool IsPressed(InputHelpers.Button button) { inputDevice.IsPressed(button, out var pressed, m_AxisToPressThreshold); return pressed; } /// /// Reads and returns the given action value. /// /// The button to read the value from. /// Returns the button value. protected virtual float ReadValue(InputHelpers.Button button) { inputDevice.TryReadSingleValue(button, out var value); return value; } /// public override bool SendHapticImpulse(float amplitude, float duration) { if (inputDevice.TryGetHapticCapabilities(out var capabilities) && capabilities.supportsImpulse) { return inputDevice.SendHapticImpulse(0u, amplitude, duration); } return false; } } }