mixedreality/com.microsoft.mixedreality..../Runtime/Subsystems/GestureSubsystem.cs

190 lines
6.3 KiB
C#

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.XR.OpenXR;
namespace Microsoft.MixedReality.OpenXR
{
[Flags]
internal enum NativeDirectionFlags
{
X = 1,
Y = 2,
Z = 4,
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
internal struct NativeGesturePoseData
{
public ulong gestureTime;
public Pose headPose;
public NativeSpaceLocationFlags headPoseFlags;
public Pose eyeGazePose;
public NativeSpaceLocationFlags eyeGazePoseFlags;
public Pose handAimPose;
public NativeSpaceLocationFlags handAimPoseFlags;
public Pose handGripPose;
public NativeSpaceLocationFlags handGripPoseFlags;
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
internal struct NativeGestureEventData
{
public GestureEventType eventType;
public GestureHandedness handedness;
public NativeGesturePoseData poseData;
public TappedEventData tappedData;
public ManipulationEventData manipulationData;
public NavigationEventData navigationData;
}
internal static class GestureSubsystemExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsValid(this NativeSpaceLocationFlags flags)
{
return flags.HasFlag(NativeSpaceLocationFlags.OrientationValid) &&
flags.HasFlag(NativeSpaceLocationFlags.PositionValid);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsTracked(this NativeSpaceLocationFlags flags)
{
return flags.HasFlag(NativeSpaceLocationFlags.OrientationTracked) &&
flags.HasFlag(NativeSpaceLocationFlags.PositionTracked);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsTappedEvent(this NativeGestureEventData eventData)
{
return eventData.eventType.HasFlag(GestureEventType.Tapped);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsManipulationEvent(this NativeGestureEventData eventData)
{
var eventType = eventData.eventType;
return eventType.HasFlag(GestureEventType.ManipulationStarted) ||
eventType.HasFlag(GestureEventType.ManipulationUpdated) ||
eventType.HasFlag(GestureEventType.ManipulationCompleted);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNavigationEvent(this NativeGestureEventData eventData)
{
var eventType = eventData.eventType;
return eventType.HasFlag(GestureEventType.NavigationStarted) ||
eventType.HasFlag(GestureEventType.NavigationUpdated) ||
eventType.HasFlag(GestureEventType.NavigationCompleted);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T? Get<T>(this NativeGestureEventData eventData, T value, bool hasValue) where T : struct
{
if (hasValue)
{
return value;
}
return null;
}
}
internal class GestureSubsystem : Disposable
{
private static MixedRealityFeaturePlugin Feature => OpenXRFeaturePlugin<MixedRealityFeaturePlugin>.Feature;
private readonly ulong m_gestureRecognizerHandle = 0;
private GestureSettings m_gestureSettings = GestureSettings.None;
private bool m_running = false;
private readonly object m_runningLock = new object();
internal static GestureSubsystem TryCreateGestureSubsystem(GestureSettings settings)
{
if (!Feature.IsValidAndEnabled())
{
Debug.LogWarning($"{MixedRealityFeaturePlugin.featureName} is not enabled.");
return null;
}
ulong handle = NativeLib.TryCreateGestureRecognizer(settings);
if (handle == 0)
{
Debug.LogWarning($"GestureSubsystem is not supported with settings: {settings}.");
return null;
}
return new GestureSubsystem(settings, handle);
}
private GestureSubsystem(GestureSettings settings, ulong handle)
{
m_gestureRecognizerHandle = handle;
m_gestureSettings = settings;
}
internal GestureSettings GestureSettings
{
get { return m_gestureSettings; }
set
{
if (m_gestureSettings != value)
{
if (NativeLib.TrySetGestureSettings(m_gestureRecognizerHandle, value))
{
m_gestureSettings = value;
}
else
{
Debug.LogWarning($"Cannot set gesture setting to {value}");
}
}
}
}
internal bool TryGetNextEvent(ref GestureEventData eventData)
{
return NativeLib.TryGetNextEventData(m_gestureRecognizerHandle, ref eventData);
}
internal void CancelPendingGestures()
{
NativeLib.CancelPendingGesture(m_gestureRecognizerHandle);
}
protected override void DisposeNativeResources()
{
base.DisposeNativeResources();
NativeLib.DestroyGestureRecognizer(m_gestureRecognizerHandle);
}
internal void Start()
{
lock (m_runningLock)
{
if (m_running)
{
Debug.LogError($"GestureSubsystem is already started.");
return;
}
NativeLib.StartGestureRecognizer(m_gestureRecognizerHandle);
m_running = true;
}
}
internal void Stop()
{
lock (m_runningLock)
{
if (!m_running)
{
Debug.LogError($"GestureSubsystem cannot be stopped before started.");
return;
}
m_running = false;
NativeLib.StopGestureRecognizer(m_gestureRecognizerHandle);
}
}
}
}