// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using Microsoft.MixedReality.Toolkit.Utilities; using UnityEngine; namespace Microsoft.MixedReality.Toolkit.Input { /// /// Waits for a controller to be initialized, then synchronizes its transform position to a specified handedness. /// [AddComponentMenu("Scripts/MRTK/SDK/ControllerPoseSynchronizer")] public class ControllerPoseSynchronizer : InputSystemGlobalHandlerListener, IMixedRealityControllerPoseSynchronizer { #region Helpers /// /// Helper function used to determine whether or not the controller pose synchronizer is configured to make use of the SourcePoseEventData /// protected bool SourcePoseDataUsable(SourcePoseEventData eventData) { return ((UseSourcePoseAsFallback && !poseActionDetected) || UseSourcePoseData) && eventData.SourceId == Controller?.InputSource.SourceId; } /// /// Helper function used to determine whether or not the controller pose synchronizer is configured to make use of the InputEventData /// protected bool InputEventDataUsable(InputEventData eventData) { return !UseSourcePoseData && eventData.SourceId == Controller?.InputSource.SourceId && PoseAction == eventData.MixedRealityInputAction; } #endregion #region IMixedRealityControllerPoseSynchronizer Implementation /// public Handedness Handedness { get => Controller == null ? Handedness.None : Controller.ControllerHandedness; } [SerializeField] [Tooltip("Should this GameObject clean itself up when its controller is lost?")] private bool destroyOnSourceLost = true; /// public bool DestroyOnSourceLost { get => destroyOnSourceLost; set => destroyOnSourceLost = value; } /// /// Is the controller this Synchronizer is registered to currently tracked? /// public bool IsTracked => TrackingState == TrackingState.Tracked; /// /// The current tracking state of the assigned /// protected TrackingState TrackingState = TrackingState.NotTracked; private IMixedRealityController controller; /// public virtual IMixedRealityController Controller { get => controller; set => controller = value; } [SerializeField] [Tooltip("Should the Transform's position be driven from the source pose or from input handler?")] private bool useSourcePoseData = true; /// public bool UseSourcePoseData { get => useSourcePoseData; set => useSourcePoseData = value; } [SerializeField] [Tooltip("Should the Transform's position use the source pose by default until the input handler events are received?")] private bool useSourcePoseAsFallback = true; /// /// Should the Transform's position use the source pose by default until the input handler events are received? /// public bool UseSourcePoseAsFallback { get => useSourcePoseAsFallback; set => useSourcePoseAsFallback = value; } /// /// Tracks whether or not a pose action event has been fired is actively being used by the pointer /// private bool poseActionDetected; [SerializeField] [Tooltip("The input action that will drive the Transform's pose, position, or rotation.")] private MixedRealityInputAction poseAction = MixedRealityInputAction.None; /// public MixedRealityInputAction PoseAction { get => poseAction; set => poseAction = value; } #endregion IMixedRealityControllerPoseSynchronizer Implementation #region InputSystemGlobalHandlerListener Implementation /// protected override void RegisterHandlers() { CoreServices.InputSystem?.RegisterHandler(this); } /// protected override void UnregisterHandlers() { CoreServices.InputSystem?.UnregisterHandler(this); } #endregion InputSystemGlobalHandlerListener Implementation #region IMixedRealitySourcePoseHandler Implementation /// public virtual void OnSourceDetected(SourceStateEventData eventData) { } /// public virtual void OnSourceLost(SourceStateEventData eventData) { if (eventData.SourceId == Controller?.InputSource.SourceId && eventData.Controller?.ControllerHandedness == Handedness) { poseActionDetected = false; TrackingState = TrackingState.NotTracked; if (DestroyOnSourceLost) { GameObjectExtensions.DestroyGameObject(gameObject); } } } /// public virtual void OnSourcePoseChanged(SourcePoseEventData eventData) { if (eventData.SourceId == Controller?.InputSource.SourceId) { TrackingState = eventData.SourceData; } } /// public virtual void OnSourcePoseChanged(SourcePoseEventData eventData) { } /// public virtual void OnSourcePoseChanged(SourcePoseEventData eventData) { if (SourcePoseDataUsable(eventData)) { TrackingState = eventData.Controller.TrackingState; transform.position = eventData.SourceData; } } /// public virtual void OnSourcePoseChanged(SourcePoseEventData eventData) { if (SourcePoseDataUsable(eventData)) { TrackingState = eventData.Controller.TrackingState; transform.rotation = eventData.SourceData; } } /// public virtual void OnSourcePoseChanged(SourcePoseEventData eventData) { if (SourcePoseDataUsable(eventData)) { TrackingState = eventData.Controller.TrackingState; transform.SetPositionAndRotation(eventData.SourceData.Position, eventData.SourceData.Rotation); } } #endregion IMixedRealitySourcePoseHandler Implementation #region IMixedRealityInputHandler Implementation /// public virtual void OnInputUp(InputEventData eventData) { } /// public virtual void OnInputDown(InputEventData eventData) { } /// public virtual void OnInputChanged(InputEventData eventData) { } /// public virtual void OnInputChanged(InputEventData eventData) { } /// public virtual void OnInputChanged(InputEventData eventData) { if (InputEventDataUsable(eventData)) { poseActionDetected = true; TrackingState = TrackingState.Tracked; transform.position = eventData.InputData; } } /// public virtual void OnInputChanged(InputEventData eventData) { if (InputEventDataUsable(eventData)) { poseActionDetected = true; TrackingState = TrackingState.Tracked; transform.rotation = eventData.InputData; } } /// public virtual void OnInputChanged(InputEventData eventData) { if (InputEventDataUsable(eventData)) { poseActionDetected = true; TrackingState = TrackingState.Tracked; transform.SetPositionAndRotation(eventData.InputData.Position, eventData.InputData.Rotation); } } #endregion IMixedRealityInputHandler Implementation #region Obsolete #pragma warning disable 0414 [SerializeField] [HideInInspector] [System.Obsolete("Use the Handedness property instead to get current handedness which is set by Controller attached")] [Tooltip("Use the Handedness property instead to get current handedness which is set by Controller attached")] private Handedness handedness = Handedness.Left; #pragma warning restore 0414 #endregion } }