// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using Microsoft.MixedReality.Toolkit.Input; using UnityEngine; namespace Microsoft.MixedReality.Toolkit.Utilities.Solvers { /// /// ControllerFinder is a base class providing simple event handling for getting/releasing MotionController Transforms. /// public abstract class ControllerFinder : MonoBehaviour, IMixedRealitySourceStateHandler { [SerializeField] [Tooltip("The handedness of the controller that should be found.")] private Handedness handedness = Handedness.None; /// /// The handedness of the controller that should be found. /// public Handedness Handedness { get { return handedness; } set { // We need to refresh which controller we're attached to if we switch handedness. if (handedness != value) { handedness = value; RefreshControllerTransform(); } } } /// /// The Transform of the currently found controller. /// protected Transform ControllerTransform; #region MonoBehaviour Implementation protected virtual void OnEnable() { // Look if the controller has loaded. CoreServices.InputSystem?.RegisterHandler(this); RefreshControllerTransform(); } protected virtual void OnDisable() { CoreServices.InputSystem?.UnregisterHandler(this); } #endregion MonoBehaviour Implementation #region IMixedRealitySourceStateHandler Implementation public void OnSourceDetected(SourceStateEventData eventData) { // Check the handedness and don't track hands if (eventData.Controller?.ControllerHandedness == handedness && !(eventData.Controller is IMixedRealityHand)) { AddControllerTransform(eventData.Controller); } } public void OnSourceLost(SourceStateEventData eventData) { if (eventData.Controller?.ControllerHandedness == handedness) { RemoveControllerTransform(); } } #endregion IMixedRealitySourceStateHandler Implementation /// /// Looks to see if the controller model already exists and registers it if so. /// protected virtual void TryAndAddControllerTransform() { // Look if the controller was already loaded. This could happen if the // GameObject was instantiated at runtime and the model loaded event has already fired. if (CoreServices.InputSystem == null) { // The InputSystem could not be found. return; } foreach (IMixedRealityController controller in CoreServices.InputSystem.DetectedControllers) { if (controller.ControllerHandedness == handedness) { AddControllerTransform(controller); return; } } } /// /// Starts to track the passed in controller's transform, assuming it meets the previously set handedness criteria. /// /// The new controller to be tracked. protected virtual void AddControllerTransform(IMixedRealityController newController) { if (newController == null || newController.Visualizer == null || newController.Visualizer.GameObjectProxy == null || newController.Visualizer.GameObjectProxy.transform == null) { return; } if (newController.ControllerHandedness == handedness && !newController.Visualizer.GameObjectProxy.transform.Equals(ControllerTransform)) { ControllerTransform = newController.Visualizer.GameObjectProxy.transform; OnControllerFound(); } } /// /// Remove whichever controller is currently tracked, if any. /// protected virtual void RemoveControllerTransform() { if (ControllerTransform != null) { OnControllerLost(); ControllerTransform = null; } } /// /// Remove whichever controller is currently tracked, if any, and try to add a new one based on existing sources. /// protected virtual void RefreshControllerTransform() { if (ControllerTransform != null) { RemoveControllerTransform(); } TryAndAddControllerTransform(); } /// /// Override this method to act when the correct controller is actually found. /// This provides similar functionality to overriding AddControllerTransform, /// without the overhead of needing to check that handedness matches. /// protected virtual void OnControllerFound() { } /// /// Override this method to act when the correct controller is actually lost. /// This provides similar functionality to overriding AddControllerTransform, /// without the overhead of needing to check that handedness matches. /// protected virtual void OnControllerLost() { } } }