// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using Microsoft.MixedReality.Toolkit.Input; using Microsoft.MixedReality.Toolkit.Input.UnityInput; using Microsoft.MixedReality.Toolkit.Utilities; using System; using Unity.Profiling; using UnityEngine; namespace Microsoft.MixedReality.Toolkit.OpenVR.Input { /// /// Manages Open VR devices using Unity's input system. /// [MixedRealityDataProvider( typeof(IMixedRealityInputSystem), SupportedPlatforms.WindowsStandalone | SupportedPlatforms.MacStandalone | SupportedPlatforms.LinuxStandalone, "OpenVR Device Manager", supportedUnityXRPipelines: SupportedUnityXRPipelines.LegacyXR)] public class OpenVRDeviceManager : UnityJoystickManager, IMixedRealityCapabilityCheck { /// /// Constructor. /// /// The instance that loaded the data provider. /// The instance that receives data from this provider. /// Friendly name of the service. /// Service priority. Used to determine order of instantiation. /// The service's configuration profile. [Obsolete("This constructor is obsolete (registrar parameter is no longer required) and will be removed in a future version of the Microsoft Mixed Reality Toolkit.")] public OpenVRDeviceManager( IMixedRealityServiceRegistrar registrar, IMixedRealityInputSystem inputSystem, string name = null, uint priority = DefaultPriority, BaseMixedRealityProfile profile = null) : this(inputSystem, name, priority, profile) { Registrar = registrar; } /// /// Constructor. /// /// The instance that receives data from this provider. /// Friendly name of the service. /// Service priority. Used to determine order of instantiation. /// The service's configuration profile. public OpenVRDeviceManager( IMixedRealityInputSystem inputSystem, string name = null, uint priority = DefaultPriority, BaseMixedRealityProfile profile = null) : base(inputSystem, name, priority, profile) { } /// public bool CheckCapability(MixedRealityCapability capability) { // The OpenVR platform supports motion controllers. return (capability == MixedRealityCapability.MotionController); } #region Controller Utilities private static readonly ProfilerMarker GetOrAddControllerPerfMarker = new ProfilerMarker("[MRTK] OpenVRDeviceManager.GetOrAddController"); /// protected override GenericJoystickController GetOrAddController(string joystickName) { using (GetOrAddControllerPerfMarker.Auto()) { // If a device is already registered with the ID provided, just return it. if (ActiveControllers.ContainsKey(joystickName)) { var controller = ActiveControllers[joystickName]; Debug.Assert(controller != null); return controller; } Handedness controllingHand; if (joystickName.Contains("Left")) { controllingHand = Handedness.Left; } else if (joystickName.Contains("Right")) { controllingHand = Handedness.Right; } else { controllingHand = Handedness.None; } var currentControllerType = GetCurrentControllerType(joystickName); Type controllerType; switch (currentControllerType) { case SupportedControllerType.GenericOpenVR: controllerType = typeof(GenericOpenVRController); break; case SupportedControllerType.ViveWand: controllerType = typeof(ViveWandController); break; case SupportedControllerType.ViveKnuckles: controllerType = typeof(ViveKnucklesController); break; case SupportedControllerType.OculusTouch: controllerType = typeof(OculusTouchController); break; case SupportedControllerType.OculusRemote: controllerType = typeof(OculusRemoteController); break; case SupportedControllerType.WindowsMixedReality: controllerType = typeof(WindowsMixedRealityOpenVRMotionController); break; case SupportedControllerType.HPMotionController: controllerType = typeof(HPMotionController); break; default: return null; } IMixedRealityPointer[] pointers = RequestPointers(currentControllerType, controllingHand); IMixedRealityInputSource inputSource = Service?.RequestNewGenericInputSource($"{currentControllerType} Controller {controllingHand}", pointers, InputSourceType.Controller); GenericOpenVRController detectedController = Activator.CreateInstance(controllerType, TrackingState.NotTracked, controllingHand, inputSource, null) as GenericOpenVRController; if (detectedController == null || !detectedController.Enabled) { // Controller failed to be set up correctly. Debug.LogError($"Failed to create {controllerType.Name} controller"); // Return null so we don't raise the source detected. return null; } for (int i = 0; i < detectedController.InputSource?.Pointers?.Length; i++) { detectedController.InputSource.Pointers[i].Controller = detectedController; } ActiveControllers.Add(joystickName, detectedController); return detectedController; } } private static readonly ProfilerMarker RemoveControllerPerfMarker = new ProfilerMarker("[MRTK] OpenVRDeviceManager.RemoveController"); /// protected override void RemoveController(string joystickName) { using (RemoveControllerPerfMarker.Auto()) { var controller = GetOrAddController(joystickName); if (controller != null) { RecyclePointers(controller.InputSource); if (controller.Visualizer != null && controller.Visualizer.GameObjectProxy != null) { controller.Visualizer.GameObjectProxy.SetActive(false); } } base.RemoveController(joystickName); } } /// protected override SupportedControllerType GetCurrentControllerType(string joystickName) { if (string.IsNullOrEmpty(joystickName) || !joystickName.Contains("OpenVR")) { return 0; } if (joystickName.Contains("Oculus Rift CV1")) { return SupportedControllerType.OculusTouch; } if (joystickName.Contains("Oculus remote")) { return SupportedControllerType.OculusRemote; } if (joystickName.Contains("Vive Wand")) { return SupportedControllerType.ViveWand; } if (joystickName.Contains("Knuckles")) { return SupportedControllerType.ViveKnuckles; } if (joystickName.Contains("WindowsMR")) { // Working around the fact that HP controllers identify as a WindowsMR controller, but have a specific PID we can check // https://github.com/microsoft/MixedRealityToolkit-Unity/pull/8794#discussion_r523313899 if (joystickName.Contains("0x066A")) { return SupportedControllerType.HPMotionController; } else { return SupportedControllerType.WindowsMixedReality; } } Debug.Log($"{joystickName} does not have a defined controller type, falling back to generic controller type"); return SupportedControllerType.GenericOpenVR; } #endregion Controller Utilities } }