// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Utilities;
using Unity.Profiling;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Input
{
///
/// Base Mouse Pointer Implementation.
///
public abstract class BaseMousePointer : BaseControllerPointer, IMixedRealityMousePointer
{
protected float timeoutTimer = 0.0f;
private bool isInteractionEnabled = false;
private bool cursorWasDisabledOnDown = false;
protected bool isDisabled = true;
#region IMixedRealityMousePointer Implementation
[SerializeField]
[Tooltip("If true, the cursor will hide on movement timeout")]
private bool hideCursorWhenInactive = true;
///
/// If true, the cursor will hide on movement timeout
///
public bool HideCursorWhenInactive => hideCursorWhenInactive;
[SerializeField]
[Range(0.01f, 1f)]
[Tooltip("Movement threshold to reach before un-hiding the mouse cursor")]
private float movementThresholdToUnHide = 0.1f;
///
/// Movement threshold to reach before un-hiding the mouse cursor
///
public float MovementThresholdToUnHide => movementThresholdToUnHide;
[SerializeField]
[Range(0f, 10f)]
[Tooltip("Time the mouse cursor must stay immobile to be hidden")]
private float hideTimeout = 3.0f;
///
/// Time the mouse cursor must stay immobile to be hidden
///
public float HideTimeout => hideTimeout;
#endregion IMixedRealityMousePointer Implementation
#region IMixedRealityPointer Implementation
///
public override bool IsInteractionEnabled => isInteractionEnabled;
protected abstract string ControllerName { get; }
///
public override IMixedRealityController Controller
{
get => base.Controller;
set
{
base.Controller = value;
TrackingState = TrackingState.NotApplicable;
}
}
#endregion IMixedRealityPointer Implementation
public override Vector3 Position => CameraCache.Main.transform.position + transform.forward * DefaultPointerExtent;
protected virtual void SetVisibility(bool visible) => isDisabled = !visible;
#region IMixedRealitySourcePoseHandler Implementation
private static readonly ProfilerMarker OnSourceDetectedPerfMarker = new ProfilerMarker("[MRTK] BaseMousePointer.OnSourceDetected");
///
public override void OnSourceDetected(SourceStateEventData eventData)
{
using (OnSourceDetectedPerfMarker.Auto())
{
if (RayStabilizer != null)
{
RayStabilizer = null;
}
base.OnSourceDetected(eventData);
if (eventData.SourceId == Controller?.InputSource.SourceId)
{
isInteractionEnabled = true;
}
}
}
private static readonly ProfilerMarker OnSourceLostPerfMarker = new ProfilerMarker("[MRTK] BaseMousePointer.OnSourceLost");
///
public override void OnSourceLost(SourceStateEventData eventData)
{
using (OnSourceLostPerfMarker.Auto())
{
base.OnSourceLost(eventData);
if (eventData.SourceId == Controller?.InputSource.SourceId)
{
isInteractionEnabled = false;
}
}
}
#endregion IMixedRealitySourcePoseHandler Implementation
#region IMixedRealityInputHandler Implementation
private static readonly ProfilerMarker OnInputDownPerfMarker = new ProfilerMarker("[MRTK] BaseMousePointer.OnInputDown");
///
public override void OnInputDown(InputEventData eventData)
{
using (OnInputDownPerfMarker.Auto())
{
cursorWasDisabledOnDown = isDisabled;
if (cursorWasDisabledOnDown)
{
ResetCursor();
}
else
{
base.OnInputDown(eventData);
}
}
}
private static readonly ProfilerMarker OnInputUpPerfMarker = new ProfilerMarker("[MRTK] BaseMousePointer.OnInputUp");
///
public override void OnInputUp(InputEventData eventData)
{
using (OnInputUpPerfMarker.Auto())
{
if (!cursorWasDisabledOnDown)
{
base.OnInputUp(eventData);
if (isDisabled)
{
ResetCursor();
}
}
}
}
#endregion IMixedRealityInputHandler Implementation
private static readonly ProfilerMarker ResetCursorPerfMarker = new ProfilerMarker("[MRTK] BaseMousePointer.ResetCursor");
private void ResetCursor()
{
using (ResetCursorPerfMarker.Auto())
{
SetVisibility(true);
transform.rotation = CameraCache.Main.transform.rotation;
}
}
#region MonoBehaviour Implementation
protected override void Start()
{
isDisabled = DisableCursorOnStart;
base.Start();
if (RayStabilizer != null)
{
RayStabilizer = null;
}
foreach (var inputSource in CoreServices.InputSystem.DetectedInputSources)
{
if (inputSource.SourceId == Controller.InputSource.SourceId)
{
isInteractionEnabled = true;
break;
}
}
}
private static readonly ProfilerMarker UpdatePerfMarker = new ProfilerMarker("[MRTK] BaseMousePointer.Update");
private void Update()
{
using (UpdatePerfMarker.Auto())
{
if (!hideCursorWhenInactive || isDisabled) { return; }
timeoutTimer += Time.unscaledDeltaTime;
if (timeoutTimer >= hideTimeout)
{
timeoutTimer = 0.0f;
SetVisibility(false);
}
}
}
#endregion MonoBehaviour Implementation
}
}