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

241 lines
8.6 KiB
C#

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Utilities;
using Unity.Profiling;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Input.UnityInput
{
[MixedRealityController(
SupportedControllerType.TouchScreen,
new[] { Handedness.Any })]
public class UnityTouchController : BaseController
{
public UnityTouchController(
TrackingState trackingState,
Handedness controllerHandedness,
IMixedRealityInputSource inputSource = null,
MixedRealityInteractionMapping[] interactions = null)
: base(trackingState, controllerHandedness, inputSource, interactions, new TouchScreenDefinition())
{ }
/// <summary>
/// Time in seconds to determine if the contact registers as a tap or a hold
/// </summary>
public float MaxTapContactTime { get; set; } = 0.5f;
/// <summary>
/// The threshold a finger must move before starting a manipulation gesture.
/// </summary>
public float ManipulationThreshold { get; set; } = 5f;
/// <summary>
/// Current Touch Data for the Controller.
/// </summary>
public Touch TouchData { get; internal set; }
/// <summary>
/// Current Screen point ray for the Touch.
/// </summary>
public Ray ScreenPointRay { get; internal set; }
/// <summary>
/// The current lifetime of the Touch.
/// </summary>
public float Lifetime { get; private set; } = 0.0f;
private bool isTouched;
private MixedRealityInputAction holdingAction;
private bool isHolding;
private MixedRealityInputAction manipulationAction;
private bool isManipulating;
private MixedRealityPose lastPose = MixedRealityPose.ZeroIdentity;
/// <inheritdoc />
public override void SetupDefaultInteractions()
{
base.SetupDefaultInteractions();
if (CoreServices.InputSystem?.InputSystemProfile.GesturesProfile != null)
{
var gestures = CoreServices.InputSystem.InputSystemProfile.GesturesProfile.Gestures;
for (int i = 0; i < gestures.Length; i++)
{
var gesture = gestures[i];
switch (gesture.GestureType)
{
case GestureInputType.Hold:
holdingAction = gesture.Action;
break;
case GestureInputType.Manipulation:
manipulationAction = gesture.Action;
break;
}
}
}
}
private bool isNewController = false;
/// <summary>
/// Start the touch.
/// </summary>
public void StartTouch()
{
// Indicate that this is a new controller.
isNewController = true;
}
private static readonly ProfilerMarker UpdatePerfMarker = new ProfilerMarker("[MRTK] UnityTouchController.Update");
/// <summary>
/// Update the touch data.
/// </summary>
public void Update()
{
using (UpdatePerfMarker.Auto())
{
var inputSystem = CoreServices.InputSystem;
if (inputSystem == null)
{
return;
}
if (isNewController)
{
isNewController = false;
inputSystem.RaiseOnInputDown(InputSource, Handedness.None, Interactions[2].MixedRealityInputAction);
inputSystem.RaisePointerDown(InputSource.Pointers[0], Interactions[2].MixedRealityInputAction);
isTouched = true;
inputSystem.RaiseGestureStarted(this, holdingAction);
isHolding = true;
}
if (!isTouched)
{
return;
}
Lifetime += Time.deltaTime;
if (TouchData.phase == TouchPhase.Moved)
{
Interactions[0].Vector2Data = TouchData.deltaPosition;
if (Interactions[0].Changed)
{
inputSystem.RaisePositionInputChanged(InputSource, ControllerHandedness, Interactions[0].MixedRealityInputAction, TouchData.deltaPosition);
}
lastPose.Position = InputSource.Pointers[0].Position;
lastPose.Rotation = InputSource.Pointers[0].Rotation;
inputSystem.RaiseSourcePoseChanged(InputSource, this, lastPose);
Interactions[1].PoseData = lastPose;
if (Interactions[1].Changed)
{
inputSystem.RaisePoseInputChanged(InputSource, ControllerHandedness, Interactions[1].MixedRealityInputAction, lastPose);
}
if (!isManipulating)
{
if (Mathf.Abs(TouchData.deltaPosition.x) > ManipulationThreshold ||
Mathf.Abs(TouchData.deltaPosition.y) > ManipulationThreshold)
{
inputSystem?.RaiseGestureCanceled(this, holdingAction);
isHolding = false;
inputSystem?.RaiseGestureStarted(this, manipulationAction);
isManipulating = true;
}
}
else
{
inputSystem.RaiseGestureUpdated(this, manipulationAction, TouchData.deltaPosition);
}
// Send dragged event, to inform manipulation handlers.
inputSystem.RaisePointerDragged(InputSource.Pointers[0], Interactions[1].MixedRealityInputAction);
}
}
}
private static readonly ProfilerMarker EndTouchPerfMarker = new ProfilerMarker("[MRTK] UnityTouchController.EndTouch");
/// <summary>
/// End the touch.
/// </summary>
public void EndTouch()
{
using (EndTouchPerfMarker.Auto())
{
var inputSystem = CoreServices.InputSystem;
if (inputSystem == null)
{
return;
}
if (TouchData.phase == TouchPhase.Ended)
{
if (Lifetime < MaxTapContactTime)
{
if (isHolding)
{
inputSystem.RaiseGestureCanceled(this, holdingAction);
isHolding = false;
}
if (isManipulating)
{
inputSystem.RaiseGestureCanceled(this, manipulationAction);
isManipulating = false;
}
inputSystem.RaisePointerClicked(InputSource.Pointers[0], Interactions[2].MixedRealityInputAction, TouchData.tapCount);
}
if (isHolding)
{
inputSystem.RaiseGestureCompleted(this, holdingAction);
isHolding = false;
}
if (isManipulating)
{
inputSystem.RaiseGestureCompleted(this, manipulationAction, TouchData.deltaPosition);
isManipulating = false;
}
}
if (isHolding)
{
inputSystem.RaiseGestureCompleted(this, holdingAction);
isHolding = false;
}
Debug.Assert(!isHolding);
if (isManipulating)
{
inputSystem.RaiseGestureCompleted(this, manipulationAction, TouchData.deltaPosition);
isManipulating = false;
}
Debug.Assert(!isManipulating);
inputSystem.RaiseOnInputUp(InputSource, Handedness.None, Interactions[2].MixedRealityInputAction);
inputSystem.RaisePointerUp(InputSource.Pointers[0], Interactions[2].MixedRealityInputAction);
Lifetime = 0.0f;
isTouched = false;
Interactions[1].PoseData = MixedRealityPose.ZeroIdentity;
Interactions[0].Vector2Data = Vector2.zero;
}
}
}
}