mixedreality/com.microsoft.mixedreality..../Core/Providers/UnityInput/UnityJoystickManager.cs

256 lines
11 KiB
C#

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using Unity.Profiling;
using UnityEngine;
using UInput = UnityEngine.Input;
namespace Microsoft.MixedReality.Toolkit.Input.UnityInput
{
/// <summary>
/// Manages joysticks using unity input system.
/// </summary>
[MixedRealityDataProvider(
typeof(IMixedRealityInputSystem),
(SupportedPlatforms)(-1), // All platforms supported by Unity
"Unity Joystick Manager")]
public class UnityJoystickManager : BaseInputDeviceManager
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="registrar">The <see cref="IMixedRealityServiceRegistrar"/> instance that loaded the data provider.</param>
/// <param name="inputSystem">The <see cref="Microsoft.MixedReality.Toolkit.Input.IMixedRealityInputSystem"/> instance that receives data from this provider.</param>
/// <param name="name">Friendly name of the service.</param>
/// <param name="priority">Service priority. Used to determine order of instantiation.</param>
/// <param name="profile">The service's configuration profile.</param>
[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 UnityJoystickManager(
IMixedRealityServiceRegistrar registrar,
IMixedRealityInputSystem inputSystem,
string name = null,
uint priority = DefaultPriority,
BaseMixedRealityProfile profile = null) : this(inputSystem, name, priority, profile)
{
Registrar = registrar;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="inputSystem">The <see cref="Microsoft.MixedReality.Toolkit.Input.IMixedRealityInputSystem"/> instance that receives data from this provider.</param>
/// <param name="name">Friendly name of the service.</param>
/// <param name="priority">Service priority. Used to determine order of instantiation.</param>
/// <param name="profile">The service's configuration profile.</param>
public UnityJoystickManager(
IMixedRealityInputSystem inputSystem,
string name = null,
uint priority = DefaultPriority,
BaseMixedRealityProfile profile = null) : base(inputSystem, name, priority, profile) { }
private const float DeviceRefreshInterval = 3.0f;
protected readonly Dictionary<string, GenericJoystickController> ActiveControllers = new Dictionary<string, GenericJoystickController>();
private float deviceRefreshTimer;
private string[] lastDeviceList;
private static readonly ProfilerMarker UpdatePerfMarker = new ProfilerMarker("[MRTK] UnityJoystickManager.Update");
/// <inheritdoc />
public override void Update()
{
using (UpdatePerfMarker.Auto())
{
base.Update();
deviceRefreshTimer += Time.unscaledDeltaTime;
if (deviceRefreshTimer >= DeviceRefreshInterval)
{
deviceRefreshTimer = 0.0f;
RefreshDevices();
}
foreach (var controller in ActiveControllers)
{
controller.Value?.UpdateController();
}
}
}
/// <inheritdoc />
public override void Disable()
{
base.Disable();
foreach (var genericJoystick in ActiveControllers)
{
if (genericJoystick.Value != null)
{
Service?.RaiseSourceLost(genericJoystick.Value.InputSource, genericJoystick.Value);
}
}
ActiveControllers.Clear();
}
private static readonly ProfilerMarker GetActiveControllersPerfMarker = new ProfilerMarker("[MRTK] UnityJoystickManager.GetActiveControllers");
/// <inheritdoc/>
public override IMixedRealityController[] GetActiveControllers()
{
using (GetActiveControllersPerfMarker.Auto())
{
IMixedRealityController[] controllers = ActiveControllers.Values.ToArray<IMixedRealityController>();
return controllers;
}
}
private static readonly ProfilerMarker RefreshDevicesPerfMarker = new ProfilerMarker("[MRTK] UnityJoystickManager.RefreshDevices");
private void RefreshDevices()
{
using (RefreshDevicesPerfMarker.Auto())
{
var joystickNames = UInput.GetJoystickNames();
if (joystickNames.Length <= 0)
{
return;
}
if (lastDeviceList != null && joystickNames.Length == lastDeviceList.Length)
{
for (int i = 0; i < lastDeviceList.Length; i++)
{
if (joystickNames[i].Equals(lastDeviceList[i])) { continue; }
if (ActiveControllers.ContainsKey(lastDeviceList[i]))
{
var controller = GetOrAddController(lastDeviceList[i]);
if (controller != null)
{
Service?.RaiseSourceLost(controller.InputSource, controller);
}
RemoveController(lastDeviceList[i]);
}
}
}
for (var i = 0; i < joystickNames.Length; i++)
{
if (string.IsNullOrEmpty(joystickNames[i]))
{
continue;
}
if (!ActiveControllers.ContainsKey(joystickNames[i]))
{
var controller = GetOrAddController(joystickNames[i]);
if (controller != null)
{
Service?.RaiseSourceDetected(controller.InputSource, controller);
}
}
}
lastDeviceList = joystickNames;
}
}
private static readonly ProfilerMarker GetOrAddControllerPerfMarker = new ProfilerMarker("[MRTK] UnityJoystickManager.GetOrAddController");
/// <summary>
/// Gets or adds a controller using the joystick name provided.
/// </summary>
/// <param name="joystickName">The name of the joystick from Unity's <see href="https://docs.unity3d.com/ScriptReference/Input.GetJoystickNames.html">Input.GetJoystickNames</see></param>
/// <returns>A new controller reference.</returns>
protected virtual GenericJoystickController GetOrAddController(string joystickName)
{
using (GetOrAddControllerPerfMarker.Auto())
{
if (ActiveControllers.ContainsKey(joystickName))
{
var controller = ActiveControllers[joystickName];
Debug.Assert(controller != null);
return controller;
}
Type controllerType;
switch (GetCurrentControllerType(joystickName))
{
default:
return null;
case SupportedControllerType.GenericUnity:
controllerType = typeof(GenericJoystickController);
break;
case SupportedControllerType.Xbox:
controllerType = typeof(XboxController);
break;
}
IMixedRealityInputSource inputSource = Service?.RequestNewGenericInputSource($"{controllerType.Name} Controller", sourceType: InputSourceType.Controller);
GenericJoystickController detectedController = Activator.CreateInstance(controllerType, TrackingState.NotTracked, Handedness.None, inputSource, null) as GenericJoystickController;
if (detectedController == null || !detectedController.Enabled)
{
// Controller failed to be setup correctly.
Debug.LogError($"Failed to create {controllerType.Name} controller");
// Return null so we don't raise the source detected.
return null;
}
ActiveControllers.Add(joystickName, detectedController);
return detectedController;
}
}
/// <summary>
/// Removes a controller using the joystick name provided.
/// </summary>
/// <param name="joystickName">The name of the joystick from Unity's <see href="https://docs.unity3d.com/ScriptReference/Input.GetJoystickNames.html">Input.GetJoystickNames</see></param>
protected virtual void RemoveController(string joystickName)
{
ActiveControllers.Remove(joystickName);
}
/// <summary>
/// Gets the current controller type for the joystick name provided.
/// </summary>
/// <param name="joystickName">The name of the joystick from Unity's <see href="https://docs.unity3d.com/ScriptReference/Input.GetJoystickNames.html">Input.GetJoystickNames</see></param>
/// <returns>The supported controller type</returns>
protected virtual SupportedControllerType GetCurrentControllerType(string joystickName)
{
// todo: this should be using an allow list, not a disallow list
if (string.IsNullOrEmpty(joystickName) ||
joystickName.Contains("OpenVR") || // This catches input sources from legacy OpenVR
joystickName.Contains("OpenXR") || // This catches input sources from OpenXR Plugin
joystickName.Contains("Oculus") || // This catches controllers from Oculus XR Plugin
joystickName.Contains("Hand - ") || // This catches HoloLens hands from Windows XR Plugin
joystickName.Contains("Spatial")) // This catches controllers from Windows XR Plugin and all input sources from legacy WMR
{
return 0;
}
if (joystickName.ToLower().Contains("xbox"))
{
return SupportedControllerType.Xbox;
}
Debug.Log($"{joystickName} does not have a defined controller type, falling back to generic controller type");
return SupportedControllerType.GenericUnity;
}
}
}