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

212 lines
8.4 KiB
C#

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Utilities;
using System.Collections.Generic;
using Unity.Profiling;
using UnityEngine;
using UInput = UnityEngine.Input;
namespace Microsoft.MixedReality.Toolkit.Input.UnityInput
{
/// <summary>
/// Manages Touch devices using unity input system.
/// </summary>
[MixedRealityDataProvider(
typeof(IMixedRealityInputSystem),
(SupportedPlatforms)(-1), // All platforms supported by Unity
"Unity Touch Device Manager")]
public class UnityTouchDeviceManager : 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>
[System.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 UnityTouchDeviceManager(
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 UnityTouchDeviceManager(
IMixedRealityInputSystem inputSystem,
string name = null,
uint priority = DefaultPriority,
BaseMixedRealityProfile profile = null) : base(inputSystem, name, priority, profile) { }
private readonly Dictionary<int, UnityTouchController> ActiveTouches = new Dictionary<int, UnityTouchController>();
private List<UnityTouchController> touchesToRemove = new List<UnityTouchController>();
private static readonly ProfilerMarker UpdatePerfMarker = new ProfilerMarker("[MRTK] UnityTouchDeviceManager.Update");
/// <inheritdoc />
public override void Update()
{
using (UpdatePerfMarker.Auto())
{
if (!IsEnabled)
{
return;
}
base.Update();
// Ensure that touch up and source lost events are at least one frame apart.
for (int i = 0; i < touchesToRemove.Count; i++)
{
IMixedRealityController controller = touchesToRemove[i];
Service?.RaiseSourceLost(controller.InputSource, controller);
}
touchesToRemove.Clear();
int touchCount = UInput.touchCount;
for (int i = 0; i < touchCount; i++)
{
Touch touch = UInput.touches[i];
// Construct a ray from the current touch coordinates
Ray ray = CameraCache.Main.ScreenPointToRay(touch.position);
switch (touch.phase)
{
case TouchPhase.Began:
AddTouchController(touch, ray);
break;
case TouchPhase.Moved:
case TouchPhase.Stationary:
UpdateTouchData(touch, ray);
break;
case TouchPhase.Ended:
case TouchPhase.Canceled:
RemoveTouchController(touch);
break;
}
}
}
}
/// <inheritdoc />
public override void Disable()
{
base.Disable();
foreach (var controller in ActiveTouches)
{
if (controller.Value == null || Service == null) { continue; }
foreach (var inputSource in Service.DetectedInputSources)
{
if (inputSource.SourceId == controller.Value.InputSource.SourceId)
{
Service.RaiseSourceLost(controller.Value.InputSource, controller.Value);
}
}
}
ActiveTouches.Clear();
}
private static readonly ProfilerMarker AddTouchControllerPerfMarker = new ProfilerMarker("[MRTK] UnityTouchDeviceManager.AddTouchController");
private void AddTouchController(Touch touch, Ray ray)
{
using (AddTouchControllerPerfMarker.Auto())
{
UnityTouchController controller;
if (!ActiveTouches.TryGetValue(touch.fingerId, out controller))
{
IMixedRealityInputSource inputSource = null;
if (Service != null)
{
var pointers = RequestPointers(SupportedControllerType.TouchScreen, Handedness.Any);
inputSource = Service.RequestNewGenericInputSource($"Touch {touch.fingerId}", pointers);
}
controller = new UnityTouchController(TrackingState.NotApplicable, Handedness.Any, inputSource);
if (inputSource != null)
{
for (int i = 0; i < inputSource.Pointers.Length; i++)
{
inputSource.Pointers[i].Controller = controller;
var touchPointer = (IMixedRealityTouchPointer)inputSource.Pointers[i];
touchPointer.TouchRay = ray;
touchPointer.FingerId = touch.fingerId;
}
}
ActiveTouches.Add(touch.fingerId, controller);
}
Service?.RaiseSourceDetected(controller.InputSource, controller);
controller.TouchData = touch;
controller.StartTouch();
}
}
private static readonly ProfilerMarker UpdateTouchDataPerfMarker = new ProfilerMarker("[MRTK] UnityTouchDeviceManager.UpdateTouchData");
private void UpdateTouchData(Touch touch, Ray ray)
{
using (UpdateTouchDataPerfMarker.Auto())
{
UnityTouchController controller;
if (!ActiveTouches.TryGetValue(touch.fingerId, out controller))
{
return;
}
controller.TouchData = touch;
var pointer = (IMixedRealityTouchPointer)controller.InputSource.Pointers[0];
controller.ScreenPointRay = pointer.TouchRay = ray;
controller.Update();
}
}
private static readonly ProfilerMarker RemoveTouchControllerPerfMarker = new ProfilerMarker("[MRTK] UnityTouchDeviceManager.RemoveTouchController");
private void RemoveTouchController(Touch touch)
{
using (RemoveTouchControllerPerfMarker.Auto())
{
UnityTouchController controller;
if (!ActiveTouches.TryGetValue(touch.fingerId, out controller))
{
return;
}
RecyclePointers(controller.InputSource);
controller.TouchData = touch;
controller.EndTouch();
// Schedule the source lost event.
touchesToRemove.Add(controller);
// Remove from the active collection
ActiveTouches.Remove(touch.fingerId);
}
}
}
}