上传YomovSDK
This commit is contained in:
38
Packages/com.unity.xr.openxr/Runtime/input/HapticControl.cs
Normal file
38
Packages/com.unity.xr.openxr/Runtime/input/HapticControl.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.Scripting;
|
||||
|
||||
namespace UnityEngine.XR.OpenXR.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Data that the HapticControl represents. Since haptics are an Output the Haptic struct is empty.
|
||||
/// </summary>
|
||||
public struct Haptic
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Input System control that wraps up a <see cref="Haptic"/> structure.
|
||||
/// </summary>
|
||||
[Preserve]
|
||||
public class HapticControl : InputControl<Haptic>
|
||||
{
|
||||
/// <summary>
|
||||
/// Default Constructor required by the Input System for instantiation.
|
||||
/// </summary>
|
||||
public HapticControl()
|
||||
{
|
||||
// Since the haptic control has no children and the the Haptic data structure has no members we need
|
||||
// to fake having a size or the InputSystem will think this control is misconfigured and throw an exception.
|
||||
m_StateBlock.sizeInBits = 1;
|
||||
m_StateBlock.bitOffset = 0;
|
||||
m_StateBlock.byteOffset = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an empty haptic structure since haptics are an output and have no data
|
||||
/// </summary>
|
||||
/// <param name="statePtr">Raw state data to read from</param>
|
||||
/// <returns>Empty haptic structure</returns>
|
||||
public override unsafe Haptic ReadUnprocessedValueFromState(void* statePtr) => new Haptic();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a95153fe0b4435da68d3efd1830a340
|
||||
timeCreated: 1617987844
|
||||
40
Packages/com.unity.xr.openxr/Runtime/input/OpenXRDevice.cs
Normal file
40
Packages/com.unity.xr.openxr/Runtime/input/OpenXRDevice.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.InputSystem.XR;
|
||||
using UnityEngine.Scripting;
|
||||
|
||||
namespace UnityEngine.XR.OpenXR.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// OpenXR Input System device
|
||||
/// </summary>
|
||||
/// <seealso cref="UnityEngine.InputSystem.InputDevice"/>
|
||||
[Preserve, InputControlLayout(displayName = "OpenXR Action Map")]
|
||||
public abstract class OpenXRDevice : UnityEngine.InputSystem.InputDevice
|
||||
{
|
||||
/// <summary>
|
||||
/// See [InputControl.FinishSetup](xref:UnityEngine.InputSystem.InputControl.FinishSetup)
|
||||
/// </summary>
|
||||
protected override void FinishSetup()
|
||||
{
|
||||
base.FinishSetup();
|
||||
|
||||
var capabilities = description.capabilities;
|
||||
var deviceDescriptor = XRDeviceDescriptor.FromJson(capabilities);
|
||||
|
||||
if (deviceDescriptor != null)
|
||||
{
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
if ((deviceDescriptor.characteristics & InputDeviceCharacteristics.Left) != 0)
|
||||
InputSystem.InputSystem.SetDeviceUsage(this, InputSystem.CommonUsages.LeftHand);
|
||||
else if ((deviceDescriptor.characteristics & InputDeviceCharacteristics.Right) != 0)
|
||||
InputSystem.InputSystem.SetDeviceUsage(this, InputSystem.CommonUsages.RightHand);
|
||||
#else
|
||||
if (deviceDescriptor.deviceRole == InputDeviceRole.LeftHanded)
|
||||
InputSystem.SetDeviceUsage(this, CommonUsages.LeftHand);
|
||||
else if (deviceDescriptor.deviceRole == InputDeviceRole.RightHanded)
|
||||
InputSystem.SetDeviceUsage(this, CommonUsages.RightHand);
|
||||
#endif //UNITY_2019_3_OR_NEWER
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 817760b76f5e57b4698bd2a27c26f55d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
20
Packages/com.unity.xr.openxr/Runtime/input/OpenXRHmd.cs
Normal file
20
Packages/com.unity.xr.openxr/Runtime/input/OpenXRHmd.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using UnityEngine.InputSystem.Controls;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.InputSystem.XR;
|
||||
using UnityEngine.Scripting;
|
||||
|
||||
namespace UnityEngine.XR.OpenXR.Input
|
||||
{
|
||||
[Preserve, InputControlLayout(displayName = "OpenXR HMD")]
|
||||
internal class OpenXRHmd : XRHMD
|
||||
{
|
||||
[Preserve, InputControl] ButtonControl userPresence { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void FinishSetup()
|
||||
{
|
||||
base.FinishSetup();
|
||||
userPresence = GetChildControl<ButtonControl>("UserPresence");
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Packages/com.unity.xr.openxr/Runtime/input/OpenXRHmd.cs.meta
Normal file
11
Packages/com.unity.xr.openxr/Runtime/input/OpenXRHmd.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8dce6d72fc8d2d34e88488a09129d8a1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
848
Packages/com.unity.xr.openxr/Runtime/input/OpenXRInput.cs
Normal file
848
Packages/com.unity.xr.openxr/Runtime/input/OpenXRInput.cs
Normal file
@@ -0,0 +1,848 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
using UnityEngine.InputSystem.Utilities;
|
||||
using UnityEngine.InputSystem.XR;
|
||||
using UnityEngine.XR.OpenXR.Features;
|
||||
using UnityEngine.XR.OpenXR.Features.Interactions;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif // UNITY_EDITOR
|
||||
|
||||
namespace UnityEngine.XR.OpenXR.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// OpenXR Input related functionality.
|
||||
/// </summary>
|
||||
public static class OpenXRInput
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
private struct SerializedGuid
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public Guid guid;
|
||||
[FieldOffset(0)]
|
||||
public ulong ulong1;
|
||||
[FieldOffset(8)]
|
||||
public ulong ulong2;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
internal struct SerializedBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// Identifier of the action (created with CreateAction) to bind to
|
||||
/// </summary>
|
||||
public ulong actionId;
|
||||
|
||||
/// <summary>
|
||||
/// OpenXR path to bind too (full path including user path)
|
||||
/// </summary>
|
||||
public string path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flags used to indicate which parts of the the input source name is being requested from <see cref="OpenXRInput.TryGetInputSourceName"/>
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum InputSourceNameFlags
|
||||
{
|
||||
/// <summary>
|
||||
/// Request the localized name of the user path as part of the input source name
|
||||
/// </summary>
|
||||
UserPath = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Request the localized name of the interaction profile as part of the input source name
|
||||
/// </summary>
|
||||
InteractionProfile = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Request the localized name of the component as part of the input source name
|
||||
/// </summary>
|
||||
Component = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Request all components
|
||||
/// </summary>
|
||||
All = UserPath | InteractionProfile | Component
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary that provides a conversion between InputSystem.ExpectedControlType to OpenXRInteractionFeature.ActionType
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, OpenXRInteractionFeature.ActionType> ExpectedControlTypeToActionType = new Dictionary<string, OpenXRInteractionFeature.ActionType>
|
||||
{
|
||||
// Binary
|
||||
["Digital"] = OpenXRInteractionFeature.ActionType.Binary,
|
||||
["Button"] = OpenXRInteractionFeature.ActionType.Binary,
|
||||
|
||||
// Axis1D
|
||||
["Axis"] = OpenXRInteractionFeature.ActionType.Axis1D,
|
||||
["Integer"] = OpenXRInteractionFeature.ActionType.Axis1D,
|
||||
["Analog"] = OpenXRInteractionFeature.ActionType.Axis1D,
|
||||
|
||||
// Axis2D
|
||||
["Vector2"] = OpenXRInteractionFeature.ActionType.Axis2D,
|
||||
["Dpad"] = OpenXRInteractionFeature.ActionType.Axis2D,
|
||||
["Stick"] = OpenXRInteractionFeature.ActionType.Axis2D,
|
||||
|
||||
// Pose
|
||||
["Pose"] = OpenXRInteractionFeature.ActionType.Pose,
|
||||
["Vector3"] = OpenXRInteractionFeature.ActionType.Pose,
|
||||
["Quaternion"] = OpenXRInteractionFeature.ActionType.Pose,
|
||||
|
||||
// Haptics
|
||||
["Haptic"] = OpenXRInteractionFeature.ActionType.Vibrate
|
||||
};
|
||||
|
||||
private const string s_devicePoseActionName = "devicepose";
|
||||
|
||||
private const string s_pointerActionName = "pointer";
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary used to map virtual controls to concrete controls.
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, string> kVirtualControlMap = new Dictionary<string, string>
|
||||
{
|
||||
["deviceposition"] = s_devicePoseActionName,
|
||||
["devicerotation"] = s_devicePoseActionName,
|
||||
["trackingstate"] = s_devicePoseActionName,
|
||||
["istracked"] = s_devicePoseActionName,
|
||||
["pointerposition"] = s_pointerActionName,
|
||||
["pointerrotation"] = s_pointerActionName
|
||||
};
|
||||
|
||||
#if ENABLE_INPUT_SYSTEM && UNITY_EDITOR
|
||||
[InitializeOnLoadMethod]
|
||||
private static void RegisterFeatureLayouts()
|
||||
{
|
||||
static void OnFirstFrame()
|
||||
{
|
||||
EditorApplication.update -= OnFirstFrame;
|
||||
|
||||
// In the editor we need to make sure the OpenXR layouts get registered even if the user doesn't
|
||||
// navigate to the project settings. The following code will register the base layouts as well
|
||||
// as any enabled interaction features.
|
||||
RegisterLayouts();
|
||||
}
|
||||
|
||||
// LoadAssetFromPath is not supported from within InitializeOnLoad. To work around this we register
|
||||
// an update callback and wait for the first frame before registering our feature layouts.
|
||||
EditorApplication.update += OnFirstFrame;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
internal static void RegisterLayouts()
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
InputSystem.InputSystem.RegisterLayout<HapticControl>("Haptic");
|
||||
#if USE_INPUT_SYSTEM_POSE_CONTROL
|
||||
#if UNITY_FORCE_INPUTSYSTEM_XR_OFF
|
||||
InputSystem.InputSystem.RegisterLayout<UnityEngine.InputSystem.XR.PoseControl>("Pose");
|
||||
#endif //UNITY_FORCE_INPUTSYSTEM_XR_OFF
|
||||
#else
|
||||
InputSystem.InputSystem.RegisterLayout<PoseControl>("Pose");
|
||||
#endif //USE_INPUT_SYSTEM_POSE_CONTROL
|
||||
InputSystem.InputSystem.RegisterLayout<OpenXRDevice>();
|
||||
InputSystem.InputSystem.RegisterLayout<OpenXRHmd>(matches: new InputDeviceMatcher()
|
||||
.WithInterface(XRUtilities.InterfaceMatchAnyVersion)
|
||||
.WithProduct(@"Head Tracking - OpenXR")
|
||||
.WithManufacturer(@"OpenXR"));
|
||||
|
||||
OpenXRInteractionFeature.RegisterLayouts();
|
||||
#endif // ENABLE_INPUT_SYSTEM
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates a given ActionMapConfig to ensure that it is generally set up correctly.
|
||||
/// </summary>
|
||||
/// <param name="interactionFeature">InteractionFeature the ActionMapConfig belongs to</param>
|
||||
/// <param name="actionMapConfig">ActionMapConfig to validate</param>
|
||||
/// <returns>True if the action map config is valid</returns>
|
||||
private static bool ValidateActionMapConfig(OpenXRInteractionFeature interactionFeature, OpenXRInteractionFeature.ActionMapConfig actionMapConfig)
|
||||
{
|
||||
var valid = true;
|
||||
if (actionMapConfig.deviceInfos == null || actionMapConfig.deviceInfos.Count == 0)
|
||||
{
|
||||
Debug.LogError($"ActionMapConfig contains no `deviceInfos` in InteractionFeature '{interactionFeature.GetType()}'");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (actionMapConfig.actions == null || actionMapConfig.actions.Count == 0)
|
||||
{
|
||||
Debug.LogError($"ActionMapConfig contains no `actions` in InteractionFeature '{interactionFeature.GetType()}'");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attach all Unity actions to OpenXR
|
||||
/// Note: this should not be called more than once per session
|
||||
/// </summary>
|
||||
internal static void AttachActionSets()
|
||||
{
|
||||
var actionMaps = new List<OpenXRInteractionFeature.ActionMapConfig>();
|
||||
var additiveActionMaps = new List<OpenXRInteractionFeature.ActionMapConfig>();
|
||||
|
||||
foreach (var interactionFeature in OpenXRSettings.Instance.features.OfType<OpenXRInteractionFeature>().Where(f => f.enabled && !f.IsAdditive))
|
||||
{
|
||||
var start = actionMaps.Count;
|
||||
interactionFeature.CreateActionMaps(actionMaps);
|
||||
for (var index = actionMaps.Count - 1; index >= start; index--)
|
||||
{
|
||||
if (!ValidateActionMapConfig(interactionFeature, actionMaps[index]))
|
||||
actionMaps.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
if (!RegisterDevices(actionMaps, false))
|
||||
return;
|
||||
|
||||
foreach (var feature in OpenXRSettings.Instance.features.OfType<OpenXRInteractionFeature>().Where(f => f.enabled && f.IsAdditive))
|
||||
{
|
||||
//Create action maps for additive profiles and add extra actions to non-additive profiles.
|
||||
feature.CreateActionMaps(additiveActionMaps);
|
||||
feature.AddAdditiveActions(actionMaps, additiveActionMaps[additiveActionMaps.Count - 1]);
|
||||
}
|
||||
var interactionProfiles = new Dictionary<string, List<SerializedBinding>>();
|
||||
if (!CreateActions(actionMaps, interactionProfiles))
|
||||
return;
|
||||
if (additiveActionMaps.Count > 0)
|
||||
{
|
||||
RegisterDevices(additiveActionMaps, true);
|
||||
CreateActions(additiveActionMaps, interactionProfiles);
|
||||
}
|
||||
|
||||
//Support Binding modifications if available
|
||||
SetDpadBindingCustomValues();
|
||||
|
||||
// Suggest bindings
|
||||
foreach (var kv in interactionProfiles)
|
||||
{
|
||||
if (!Internal_SuggestBindings(kv.Key, kv.Value.ToArray(), (uint)kv.Value.Count))
|
||||
OpenXRRuntime.LogLastError();
|
||||
}
|
||||
|
||||
// Attach actions sets to commit all bindings
|
||||
if (!Internal_AttachActionSets())
|
||||
OpenXRRuntime.LogLastError();
|
||||
}
|
||||
|
||||
private static bool RegisterDevices(List<OpenXRInteractionFeature.ActionMapConfig> actionMaps, bool isAdditive)
|
||||
{
|
||||
foreach (var actionMap in actionMaps)
|
||||
{
|
||||
foreach (var deviceInfo in actionMap.deviceInfos)
|
||||
{
|
||||
var localizedName = actionMap.desiredInteractionProfile == null ? UserPathToDeviceName(deviceInfo.userPath) : actionMap.localizedName;
|
||||
if (0 == Internal_RegisterDeviceDefinition(deviceInfo.userPath, actionMap.desiredInteractionProfile, isAdditive, (uint)deviceInfo.characteristics, localizedName, actionMap.manufacturer, actionMap.serialNumber))
|
||||
{
|
||||
OpenXRRuntime.LogLastError();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool CreateActions(List<OpenXRInteractionFeature.ActionMapConfig> actionMaps, Dictionary<string, List<SerializedBinding>> interactionProfiles)
|
||||
{
|
||||
foreach (var actionMap in actionMaps)
|
||||
{
|
||||
string actionMapLocalizedName = SanitizeStringForOpenXRPath(actionMap.localizedName);
|
||||
var actionSetId = Internal_CreateActionSet(SanitizeStringForOpenXRPath(actionMap.name), actionMapLocalizedName, new SerializedGuid());
|
||||
if (0 == actionSetId)
|
||||
{
|
||||
OpenXRRuntime.LogLastError();
|
||||
return false;
|
||||
}
|
||||
// User paths specified in the deviceInfo
|
||||
var deviceUserPaths = actionMap.deviceInfos.Select(d => d.userPath).ToList();
|
||||
|
||||
foreach (var action in actionMap.actions)
|
||||
{
|
||||
// User paths specified in the bindings
|
||||
var bindingUserPaths = action.bindings.Where(b => b.userPaths != null).SelectMany(b => b.userPaths).Distinct().ToList();
|
||||
|
||||
// Combination of all user paths
|
||||
var allUserPaths = bindingUserPaths.Union(deviceUserPaths).ToArray();
|
||||
|
||||
var actionId = Internal_CreateAction(
|
||||
actionSetId,
|
||||
SanitizeStringForOpenXRPath(action.name),
|
||||
action.localizedName,
|
||||
(uint)action.type,
|
||||
new SerializedGuid(),
|
||||
allUserPaths, (uint)allUserPaths.Length, action.isAdditive,
|
||||
action.usages?.ToArray(), (uint)(action.usages?.Count ?? 0));
|
||||
|
||||
if (actionId == 0)
|
||||
{
|
||||
OpenXRRuntime.LogLastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var binding in action.bindings)
|
||||
{
|
||||
foreach (var userPath in binding.userPaths ?? deviceUserPaths)
|
||||
{
|
||||
var interactionProfile = action.isAdditive ? actionMap.desiredInteractionProfile : binding.interactionProfileName ?? actionMap.desiredInteractionProfile;
|
||||
if (!interactionProfiles.TryGetValue(interactionProfile, out var bindings))
|
||||
{
|
||||
bindings = new List<SerializedBinding>();
|
||||
interactionProfiles[interactionProfile] = bindings;
|
||||
}
|
||||
|
||||
bindings.Add(new SerializedBinding { actionId = actionId, path = userPath + binding.interactionPath });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void SetDpadBindingCustomValues()
|
||||
{
|
||||
var dpadFeature = OpenXRSettings.Instance.GetFeature<DPadInteraction>();
|
||||
if (dpadFeature != null && dpadFeature.enabled)
|
||||
{
|
||||
Internal_SetDpadBindingCustomValues(true, dpadFeature.forceThresholdLeft, dpadFeature.forceThresholdReleaseLeft, dpadFeature.centerRegionLeft, dpadFeature.wedgeAngleLeft, dpadFeature.isStickyLeft);
|
||||
Internal_SetDpadBindingCustomValues(false, dpadFeature.forceThresholdRight, dpadFeature.forceThresholdReleaseRight, dpadFeature.centerRegionRight, dpadFeature.wedgeAngleRight, dpadFeature.isStickyRight);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sanitize the given character for use as an OpenXR Path
|
||||
/// </summary>
|
||||
/// <param name="c">Character to sanitize</param>
|
||||
/// <returns>The sanitized character or 0 if the character should be excluded</returns>
|
||||
private static char SanitizeCharForOpenXRPath(char c)
|
||||
{
|
||||
if (char.IsLower(c) || char.IsDigit(c))
|
||||
return c;
|
||||
|
||||
if (char.IsUpper(c))
|
||||
return char.ToLower(c);
|
||||
|
||||
if (c == '-' || c == '.' || c == '_' || c == '/')
|
||||
return c;
|
||||
|
||||
return (char)0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OpenXR names can only contain certain characters. see https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#well-formed-path-strings
|
||||
/// </summary>
|
||||
/// <param name="input">the string we'll convert to a valid OpenXR path</param>
|
||||
private static string SanitizeStringForOpenXRPath(string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
return "";
|
||||
|
||||
// Find the first character that is not sanitized
|
||||
var i = 0;
|
||||
for (; i < input.Length && SanitizeCharForOpenXRPath(input[i]) == input[i]; ++i) ;
|
||||
|
||||
// Already clean
|
||||
if (i == input.Length)
|
||||
return input;
|
||||
|
||||
// Build the rest of the string by sanitizing each character but start with the
|
||||
// portion of the string we already know is sanitized
|
||||
var sb = new StringBuilder(input, 0, i, input.Length);
|
||||
for (; i < input.Length; ++i)
|
||||
{
|
||||
var c = SanitizeCharForOpenXRPath(input[i]);
|
||||
if (c != 0)
|
||||
sb.Append(c);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the control's action handle.
|
||||
/// </summary>
|
||||
/// <param name="control">The input control</param>
|
||||
/// <returns>The name of the action handle.</returns>
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
private static string GetActionHandleName(InputControl control)
|
||||
{
|
||||
// Extract the name of the action from the control path.
|
||||
// Example: /EyeTrackingOpenXR/pose/isTracked --> action is pose.
|
||||
InputControl inputControl = control;
|
||||
while (inputControl.parent != null && inputControl.parent.parent != null)
|
||||
{
|
||||
inputControl = inputControl.parent;
|
||||
}
|
||||
|
||||
string controlName = SanitizeStringForOpenXRPath(inputControl.name);
|
||||
if (kVirtualControlMap.TryGetValue(controlName, out var virtualControlName))
|
||||
{
|
||||
return virtualControlName;
|
||||
}
|
||||
|
||||
return controlName;
|
||||
}
|
||||
#endif // ENABLE_INPUT_SYSTEM
|
||||
|
||||
/// <summary>
|
||||
/// Send a haptic impulse using an action reference
|
||||
/// </summary>
|
||||
/// <param name="actionRef">Action Reference to send haptic impulse through</param>
|
||||
/// <param name="amplitude">Amplitude of the impulse [0-1]</param>
|
||||
/// <param name="duration">Duration of the impulse [0-] in seconds</param>
|
||||
/// <param name="inputDevice">Optional device to limit haptic impulse to</param>
|
||||
public static void SendHapticImpulse(InputActionReference actionRef, float amplitude, float duration, InputSystem.InputDevice inputDevice = null) =>
|
||||
SendHapticImpulse(actionRef, amplitude, 0.0f, duration, inputDevice);
|
||||
|
||||
/// <summary>
|
||||
/// Send a haptic impulse using an action reference
|
||||
/// </summary>
|
||||
/// <param name="actionRef">Action Reference to send haptic impulse through</param>
|
||||
/// <param name="amplitude">Amplitude of the impulse [0-1]</param>
|
||||
/// <param name="frequency">Frequency of the impulse in hertz (Hz). (Typical frequency values are between 0 and 300Hz) (0 = default). Note that not all runtimes support frequency.</param>
|
||||
/// <param name="duration">Duration of the impulse [0-] in seconds</param>
|
||||
/// <param name="inputDevice">Optional device to limit haptic impulse to</param>
|
||||
public static void SendHapticImpulse(InputActionReference actionRef, float amplitude, float frequency, float duration, InputSystem.InputDevice inputDevice = null) =>
|
||||
SendHapticImpulse(actionRef.action, amplitude, frequency, duration, inputDevice);
|
||||
|
||||
/// <summary>
|
||||
/// Send a haptic impulse using the given action
|
||||
/// </summary>
|
||||
/// <param name="action">Action to send haptic impulse through</param>
|
||||
/// <param name="amplitude">Amplitude of the impulse [0-1]</param>
|
||||
/// <param name="duration">Duration of the impulse [0-] in seconds</param>
|
||||
/// <param name="inputDevice">Optional device to limit haptic impulse to</param>
|
||||
public static void SendHapticImpulse(InputAction action, float amplitude, float duration, InputSystem.InputDevice inputDevice = null) =>
|
||||
SendHapticImpulse(action, amplitude, 0.0f, duration, inputDevice);
|
||||
|
||||
/// <summary>
|
||||
/// Send a haptic impulse using the given action
|
||||
/// </summary>
|
||||
/// <param name="action">Action to send haptic impulse through</param>
|
||||
/// <param name="amplitude">Amplitude of the impulse [0-1]</param>
|
||||
/// <param name="frequency">Frequency of the impulse in hertz (Hz). (Typical frequency values are between 0 and 300Hz) (0 = default). Note that not all runtimes support frequency.</param>
|
||||
/// <param name="duration">Duration of the impulse [0-] in seconds</param>
|
||||
/// <param name="inputDevice">Optional device to limit haptic impulse to</param>
|
||||
public static void SendHapticImpulse(InputAction action, float amplitude, float frequency, float duration, InputSystem.InputDevice inputDevice = null)
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
if (action == null)
|
||||
return;
|
||||
|
||||
var actionHandle = GetActionHandle(action, inputDevice);
|
||||
if (actionHandle == 0)
|
||||
return;
|
||||
|
||||
amplitude = Mathf.Clamp(amplitude, 0, 1);
|
||||
duration = Mathf.Max(duration, 0);
|
||||
|
||||
Internal_SendHapticImpulse(GetDeviceId(inputDevice), actionHandle, amplitude, frequency, duration);
|
||||
#endif // ENABLE_INPUT_SYSTEM
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop any haptics playing for the given action reference
|
||||
/// </summary>
|
||||
/// <param name="actionRef">Action reference to stop the haptics on.</param>
|
||||
/// <param name="inputDevice">Optional device filter for actions bound to multiple devices.</param>
|
||||
public static void StopHaptics(InputActionReference actionRef, InputSystem.InputDevice inputDevice = null)
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
if (actionRef == null)
|
||||
return;
|
||||
|
||||
StopHaptics(actionRef.action, inputDevice);
|
||||
#endif // ENABLE_INPUT_SYSTEM
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a haptic impulse using the given device
|
||||
/// </summary>
|
||||
/// <param name="device">Device to send haptic impulse</param>
|
||||
/// <param name="amplitude">Amplitude of the impulse [0-1]</param>
|
||||
/// <param name="frequency">Frequency of the impulse in hertz (Hz). (Typical frequency values are between 0 and 300Hz) (0 = default). Note that not all runtimes support frequency.</param>
|
||||
/// <param name="duration">Duration of the impulse [0-] in seconds</param>
|
||||
public static void SendHapticImpulse(XR.InputDevice device, float amplitude, float frequency, float duration)
|
||||
{
|
||||
if (!device.isValid)
|
||||
return;
|
||||
|
||||
Internal_SendHapticImpulseNoISX(GetDeviceId(device), amplitude, frequency, duration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop any haptics playing for the given device.
|
||||
/// </summary>
|
||||
/// <param name="device">Device to stop haptics on.</param>
|
||||
public static void StopHapticImpulse(XR.InputDevice device)
|
||||
{
|
||||
if (!device.isValid)
|
||||
return;
|
||||
|
||||
Internal_StopHapticsNoISX(GetDeviceId(device));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop any haptics playing for the given action
|
||||
/// </summary>
|
||||
/// <param name="inputAction">Input action to stop haptics for</param>
|
||||
/// <param name="inputDevice">Optional device filter for actions bound to multiple defices</param>
|
||||
public static void StopHaptics(InputAction inputAction, InputSystem.InputDevice inputDevice = null)
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
if (inputAction == null)
|
||||
return;
|
||||
|
||||
var actionHandle = GetActionHandle(inputAction, inputDevice);
|
||||
if (actionHandle == 0)
|
||||
return;
|
||||
|
||||
Internal_StopHaptics(GetDeviceId(inputDevice), actionHandle);
|
||||
#endif // ENABLE_INPUT_SYSTEM
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the name of the input source bound to the given action
|
||||
/// </summary>
|
||||
/// <param name="inputAction">Input Action</param>
|
||||
/// <param name="index">Index of the input source in the case of multiple bindings.</param>
|
||||
/// <param name="name">Name of the input source if an input source was found or an empty string if none was found</param>
|
||||
/// <param name="flags">Flags that indicate which parts of the input source name are requested.</param>
|
||||
/// <param name="inputDevice">Optional input device to limit search to</param>
|
||||
/// <returns>True if an input source was found</returns>
|
||||
public static bool TryGetInputSourceName(
|
||||
InputAction inputAction,
|
||||
int index,
|
||||
out string name,
|
||||
InputSourceNameFlags flags = InputSourceNameFlags.All,
|
||||
InputSystem.InputDevice inputDevice = null
|
||||
)
|
||||
{
|
||||
name = "";
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
if (index < 0)
|
||||
return false;
|
||||
|
||||
var actionHandle = GetActionHandle(inputAction, inputDevice);
|
||||
if (actionHandle == 0)
|
||||
return false;
|
||||
|
||||
return Internal_TryGetInputSourceName(GetDeviceId(inputDevice), actionHandle, (uint)index, (uint)flags, out name);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the active state of the given action
|
||||
/// </summary>
|
||||
/// <param name="inputAction">Input Action</param>
|
||||
/// <returns>True if the given action has any bindings that are active</returns>
|
||||
public static bool GetActionIsActive(InputAction inputAction)
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
if (inputAction != null &&
|
||||
inputAction.controls.Count > 0 &&
|
||||
inputAction.controls[0].device != null)
|
||||
{
|
||||
for (var index = 0; index < inputAction.controls.Count; ++index)
|
||||
{
|
||||
var deviceId = GetDeviceId(inputAction.controls[index].device);
|
||||
if (deviceId == 0)
|
||||
continue;
|
||||
|
||||
var controlName = GetActionHandleName(inputAction.controls[index]);
|
||||
if (Internal_GetActionIsActive(deviceId, controlName))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_INPUT_SYSTEM
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the active state of the given action
|
||||
/// </summary>
|
||||
/// <param name="device">InputDevice to get active state for</param>
|
||||
/// <param name="usage">InputFeatureUsage to get active state for</param>
|
||||
/// <returns>True if the given action has any bindings that are active</returns>
|
||||
public static bool GetActionIsActive(XR.InputDevice device, InputFeatureUsage usage)
|
||||
=> GetActionIsActive(device, usage.name);
|
||||
|
||||
/// <summary>
|
||||
/// Return the active state of the given action
|
||||
/// </summary>
|
||||
/// <param name="device">InputDevice to get active state for</param>
|
||||
/// <param name="usageName">InputFeatureUsage name to get active state for</param>
|
||||
/// <returns>True if the given action has any bindings that are active</returns>
|
||||
public static bool GetActionIsActive(XR.InputDevice device, string usageName)
|
||||
{
|
||||
var deviceId = GetDeviceId(device);
|
||||
if (deviceId == 0)
|
||||
return false;
|
||||
|
||||
return Internal_GetActionIsActiveNoISX(deviceId, usageName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set InputAction to be used for controller late latching (Vulkan Only Feature). Only support one inputAction for each left and right controller.
|
||||
/// See Controller Samples MarkLateLatchNode.cs for example code and usages.
|
||||
/// </summary>
|
||||
/// <param name="inputAction">Source InputAction - Pose Type</param>
|
||||
/// <returns>True if the given action is a valid pose action can be late latched</returns>
|
||||
public static bool TrySetControllerLateLatchAction(InputAction inputAction)
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
//only allow one binding per action for LateLatching
|
||||
if (inputAction == null || inputAction.controls.Count != 1)
|
||||
return false;
|
||||
if (inputAction.controls[0].device == null)
|
||||
return false;
|
||||
var deviceId = GetDeviceId(inputAction.controls[0].device);
|
||||
if (deviceId == 0)
|
||||
return false;
|
||||
var actionHandle = GetActionHandle(inputAction);
|
||||
if (actionHandle == 0)
|
||||
return false;
|
||||
return Internal_TrySetControllerLateLatchAction(deviceId, actionHandle);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set InputAction to be used for controller late latching (Vulkan Only
|
||||
/// Feature). Only support one input action for each left and right
|
||||
/// controller. See Controller XRInput Samples MarkLateLatchNodeXRInput.cs
|
||||
/// for example code and usages.
|
||||
/// </summary>
|
||||
/// <param name="device">Source device</param>
|
||||
/// <param name="usage">Source usage - attached to a Pose Type</param>
|
||||
/// <returns>True if the given action is a valid pose action can be late latched</returns>
|
||||
public static bool TrySetControllerLateLatchAction(XR.InputDevice device, InputFeatureUsage usage)
|
||||
=> TrySetControllerLateLatchAction(device, usage.name);
|
||||
|
||||
/// <summary>
|
||||
/// Set InputAction to be used for controller late latching (Vulkan Only
|
||||
/// Feature). Only support one input action for each left and right
|
||||
/// controller. See Controller XRInput Samples MarkLateLatchNodeXRInput.cs
|
||||
/// for example code and usages.
|
||||
/// </summary>
|
||||
/// <param name="device">Source device</param>
|
||||
/// <param name="usageName">Source usage name - attached to a Pose Type</param>
|
||||
/// <returns>True if the given action is a valid pose action can be late latched</returns>
|
||||
public static bool TrySetControllerLateLatchAction(XR.InputDevice device, string usageName)
|
||||
{
|
||||
var deviceId = GetDeviceId(device);
|
||||
if (deviceId == 0)
|
||||
return false;
|
||||
|
||||
var actionHandle = GetActionHandle(device, usageName);
|
||||
if (actionHandle == 0)
|
||||
return false;
|
||||
|
||||
return Internal_TrySetControllerLateLatchAction(deviceId, actionHandle);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = k_Size)]
|
||||
private struct GetInternalDeviceIdCommand : IInputDeviceCommandInfo
|
||||
{
|
||||
private static FourCC Type => new FourCC('X', 'R', 'D', 'I');
|
||||
private const int k_BaseCommandSizeSize = 8;
|
||||
private const int k_Size = k_BaseCommandSizeSize + sizeof(uint);
|
||||
|
||||
[FieldOffset(0)] private InputDeviceCommand baseCommand;
|
||||
[FieldOffset(8)] public readonly uint deviceId;
|
||||
|
||||
public FourCC typeStatic => Type;
|
||||
|
||||
public static GetInternalDeviceIdCommand Create() =>
|
||||
new GetInternalDeviceIdCommand { baseCommand = new InputDeviceCommand(Type, k_Size) };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the OpenXR action handle for the given input device and usage.
|
||||
/// </summary>
|
||||
/// <param name="device">Device to find action handle for.</param>
|
||||
/// <param name="usage">Usage to find action handle for.</param>
|
||||
/// <returns>OpenXR handle that is associated with the given device and usage, or 0 if not found</returns>
|
||||
public static ulong GetActionHandle(XR.InputDevice device, InputFeatureUsage usage)
|
||||
=> GetActionHandle(device, usage.name);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the OpenXR action handle for the given input device and usage name.
|
||||
/// </summary>
|
||||
/// <param name="device">Device to find action handle for.</param>
|
||||
/// <param name="usageName">Usage name to find action handle for.</param>
|
||||
/// <returns>OpenXR handle that is associated with the given device and usage, or 0 if not found</returns>
|
||||
public static ulong GetActionHandle(XR.InputDevice device, string usageName)
|
||||
{
|
||||
var deviceId = GetDeviceId(device);
|
||||
if (deviceId == 0)
|
||||
return 0;
|
||||
|
||||
return Internal_GetActionIdNoISX(deviceId, usageName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the OpenXR action handle for the given input action
|
||||
/// </summary>
|
||||
/// <param name="inputAction">Source InputAction</param>
|
||||
/// <param name="inputDevice">Optional InputDevice to filter by</param>
|
||||
/// <returns>OpenXR handle that is associated with the given InputAction or 0 if not found</returns>
|
||||
public static ulong GetActionHandle(InputAction inputAction, InputSystem.InputDevice inputDevice = null)
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
if (inputAction == null || inputAction.controls.Count == 0)
|
||||
return 0;
|
||||
|
||||
foreach (var control in inputAction.controls)
|
||||
{
|
||||
if (inputDevice != null && control.device != inputDevice || control.device == null)
|
||||
continue;
|
||||
|
||||
var deviceId = GetDeviceId(control.device);
|
||||
if (deviceId == 0)
|
||||
continue;
|
||||
|
||||
var controlName = GetActionHandleName(control);
|
||||
|
||||
// Populate the action handles list and make sure we dont overflow
|
||||
var xrAction = Internal_GetActionId(deviceId, controlName);
|
||||
|
||||
if (xrAction != 0)
|
||||
return xrAction;
|
||||
}
|
||||
#endif // ENABLE_INPUT_SYSTEM
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the OpenXR device identifier for the given input device
|
||||
/// </summary>
|
||||
/// <param name="inputDevice">Input device to return identifier for</param>
|
||||
/// <returns>Identifier the OpenXR plugin uses for this device. If a device could not be found an invalid device id of 0 will be returned</returns>
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
private static uint GetDeviceId(InputSystem.InputDevice inputDevice)
|
||||
{
|
||||
if (inputDevice == null)
|
||||
return 0;
|
||||
|
||||
var command = GetInternalDeviceIdCommand.Create();
|
||||
var result = inputDevice.ExecuteCommand(ref command);
|
||||
return result == 0 ? 0 : command.deviceId;
|
||||
}
|
||||
#endif // ENABLE_INPUT_SYSTEM
|
||||
|
||||
static uint GetDeviceId(XR.InputDevice inputDevice)
|
||||
=> Internal_GetDeviceId(inputDevice.characteristics, inputDevice.name);
|
||||
|
||||
/// <summary>
|
||||
/// Convert a user path into a device name
|
||||
/// </summary>
|
||||
/// <param name="userPath">User Path</param>
|
||||
/// <returns>Device name that represents the given user path</returns>
|
||||
private static string UserPathToDeviceName(string userPath)
|
||||
{
|
||||
// Build the device name from the user path
|
||||
var parts = userPath.Split('/', '_');
|
||||
var nameBuilder = new StringBuilder("OXR");
|
||||
foreach (var part in parts)
|
||||
{
|
||||
if (part.Length == 0)
|
||||
continue;
|
||||
|
||||
var sanitizedPart = SanitizeStringForOpenXRPath(part);
|
||||
nameBuilder.Append(char.ToUpper(sanitizedPart[0]));
|
||||
nameBuilder.Append(sanitizedPart.Substring(1));
|
||||
}
|
||||
|
||||
return nameBuilder.ToString();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private const string Library = "UnityOpenXR";
|
||||
|
||||
[DllImport(Library, EntryPoint = "OpenXRInputProvider_SetDpadBindingCustomValues", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void Internal_SetDpadBindingCustomValues([MarshalAs(UnmanagedType.I1)] bool isLeft, float forceThreshold, float forceThresholdReleased, float centerRegion, float wedgeAngle, [MarshalAs(UnmanagedType.I1)] bool isSticky);
|
||||
|
||||
[DllImport(Library, EntryPoint = "OpenXRInputProvider_SendHapticImpulse", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void Internal_SendHapticImpulse(uint deviceId, ulong actionId, float amplitude, float frequency, float duration);
|
||||
|
||||
[DllImport(Library, EntryPoint = "OpenXRInputProvider_SendHapticImpulseNoISX", CallingConvention = CallingConvention.Cdecl)]
|
||||
static extern void Internal_SendHapticImpulseNoISX(uint deviceId, float amplitude, float frequency, float duration);
|
||||
|
||||
[DllImport(Library, EntryPoint = "OpenXRInputProvider_StopHaptics", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void Internal_StopHaptics(uint deviceId, ulong actionId);
|
||||
|
||||
[DllImport(Library, EntryPoint = "OpenXRInputProvider_StopHapticsNoISX", CallingConvention = CallingConvention.Cdecl)]
|
||||
static extern void Internal_StopHapticsNoISX(uint deviceId);
|
||||
|
||||
[DllImport(Library, EntryPoint = "OpenXRInputProvider_GetActionIdByControl")]
|
||||
private static extern ulong Internal_GetActionId(uint deviceId, string name);
|
||||
|
||||
[DllImport(Library, EntryPoint = "OpenXRInputProvider_GetActionIdByUsageName", CharSet = CharSet.Ansi)]
|
||||
static extern ulong Internal_GetActionIdNoISX(uint deviceId, string usageName);
|
||||
|
||||
[DllImport(Library, EntryPoint = "OpenXRInputProvider_TryGetInputSourceName", CharSet = CharSet.Ansi)]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
private static extern bool Internal_TryGetInputSourceNamePtr(uint deviceId, ulong actionId, uint index, uint flags, out IntPtr outName);
|
||||
|
||||
internal static bool Internal_TryGetInputSourceName(uint deviceId, ulong actionId, uint index, uint flags, out string outName)
|
||||
{
|
||||
if (!Internal_TryGetInputSourceNamePtr(deviceId, actionId, index, flags, out var outNamePtr))
|
||||
{
|
||||
outName = "";
|
||||
return false;
|
||||
}
|
||||
|
||||
outName = Marshal.PtrToStringAnsi(outNamePtr);
|
||||
return true;
|
||||
}
|
||||
|
||||
[DllImport(Library, EntryPoint = "OpenXRInputProvider_TrySetControllerLateLatchAction")]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
private static extern bool Internal_TrySetControllerLateLatchAction(uint deviceId, ulong actionId);
|
||||
|
||||
[DllImport(Library, EntryPoint = "OpenXRInputProvider_GetActionIsActive")]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
private static extern bool Internal_GetActionIsActive(uint deviceId, string name);
|
||||
|
||||
[DllImport(Library, EntryPoint = "OpenXRInputProvider_GetActionIsActiveNoISX", CharSet = CharSet.Ansi)]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
static extern bool Internal_GetActionIsActiveNoISX(uint deviceId, string name);
|
||||
|
||||
[DllImport(Library, EntryPoint = "OpenXRInputProvider_RegisterDeviceDefinition", CharSet = CharSet.Ansi)]
|
||||
private static extern ulong Internal_RegisterDeviceDefinition(string userPath, string interactionProfile, [MarshalAs(UnmanagedType.I1)] bool isAdditive, uint characteristics, string name, string manufacturer, string serialNumber);
|
||||
|
||||
[DllImport(Library, EntryPoint = "OpenXRInputProvider_CreateActionSet", CharSet = CharSet.Ansi)]
|
||||
private static extern ulong Internal_CreateActionSet(string name, string localizedName, SerializedGuid guid);
|
||||
|
||||
[DllImport(Library, EntryPoint = "OpenXRInputProvider_CreateAction", CharSet = CharSet.Ansi)]
|
||||
private static extern ulong Internal_CreateAction(ulong actionSetId, string name, string localizedName, uint actionType, SerializedGuid guid, string[] userPaths, uint userPathCount, [MarshalAs(UnmanagedType.I1)] bool isAdditive, string[] usages, uint usageCount);
|
||||
|
||||
[DllImport(Library, EntryPoint = "OpenXRInputProvider_SuggestBindings", CharSet = CharSet.Ansi)]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static extern bool Internal_SuggestBindings(string interactionProfile, SerializedBinding[] serializedBindings, uint serializedBindingCount);
|
||||
|
||||
[DllImport(Library, EntryPoint = "OpenXRInputProvider_AttachActionSets", CharSet = CharSet.Ansi)]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static extern bool Internal_AttachActionSets();
|
||||
|
||||
[DllImport(Library, EntryPoint = "OpenXRInputProvider_GetDeviceId", CharSet = CharSet.Ansi)]
|
||||
static extern uint Internal_GetDeviceId(InputDeviceCharacteristics characteristics, string name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e3c40c4727414881b56fb6ba2ced6cf2
|
||||
timeCreated: 1603741942
|
||||
153
Packages/com.unity.xr.openxr/Runtime/input/PoseControl.cs
Normal file
153
Packages/com.unity.xr.openxr/Runtime/input/PoseControl.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.InputSystem.Controls;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.Scripting;
|
||||
using TrackingState = UnityEngine.XR.InputTrackingState;
|
||||
|
||||
namespace UnityEngine.XR.OpenXR.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a tracked object in real-world space. All poses are given in the same root space, dictated by <see cref="UnityEngine.XR.TrackingOriginModeFlags"/>.
|
||||
/// </summary>
|
||||
#if USE_INPUT_SYSTEM_POSE_CONTROL
|
||||
[Obsolete("OpenXR.Input.Pose is deprecated, Please use UnityEngine.InputSystem.XR.PoseState instead", false)]
|
||||
#endif
|
||||
public struct Pose
|
||||
{
|
||||
/// <summary>
|
||||
/// If true, this position is being accurately tracked in real-world space. This value means that no values are estimated and tracking is not currently inhibited in any way.
|
||||
/// </summary>
|
||||
public bool isTracked { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A series of flags that identify which tracking values currently have data. That data can be measured by the real world or estimated when tracking is inhibited.
|
||||
/// </summary>
|
||||
public TrackingState trackingState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The position, in meters, of the object in real-world space. This will be available if <see cref="trackingState"/> contains the <see cref="TrackingState.Position"/> flag.
|
||||
/// </summary>
|
||||
public Vector3 position { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The rotation, in radians, of the object in real-world space. This will be available if <see cref="trackingState"/> contains the <see cref="TrackingState.Rotation"/> flag.
|
||||
/// </summary>
|
||||
public Quaternion rotation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The velocity, in meters per second, of the object in real-world space. This will be available if <see cref="trackingState"/> contains the <see cref="TrackingState.Velocity"/> flag.
|
||||
/// </summary>
|
||||
public Vector3 velocity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The position, in radians per second, of the object in-real world space. This will be available if <see cref="trackingState"/> contains the <see cref="TrackingState.AngularVelocity"/> flag.
|
||||
/// </summary>
|
||||
public Vector3 angularVelocity { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Input System control that wraps up a <see cref="Pose"/> structure. All individual pose elements can be referenced separately. See <see cref="InputControl"/> for more details.
|
||||
/// </summary>
|
||||
#if USE_INPUT_SYSTEM_POSE_CONTROL
|
||||
[Obsolete("OpenXR.Input.PoseControl is deprecated. Please use UnityEngine.InputSystem.XR.PoseControl instead.", false)]
|
||||
#endif
|
||||
public class PoseControl : InputControl<Pose>
|
||||
{
|
||||
/// <summary>
|
||||
/// Separate access to the <see cref="Pose.isTracked"/> value.
|
||||
/// </summary>
|
||||
[Preserve]
|
||||
[InputControl(offset = 0)]
|
||||
public ButtonControl isTracked { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Separate access to the <see cref="Pose.trackingState"/> value.
|
||||
/// </summary>
|
||||
[Preserve]
|
||||
[InputControl(offset = 4)]
|
||||
public IntegerControl trackingState { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Separate access to the <see cref="Pose.position"/> value.
|
||||
/// </summary>
|
||||
[Preserve]
|
||||
[InputControl(offset = 8, noisy = true)]
|
||||
public Vector3Control position { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Separate access to the <see cref="Pose.rotation"/> value.
|
||||
/// </summary>
|
||||
[Preserve]
|
||||
[InputControl(offset = 20, noisy = true)]
|
||||
public QuaternionControl rotation { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Separate access to the <see cref="Pose.velocity"/> value.
|
||||
/// </summary>
|
||||
[Preserve]
|
||||
[InputControl(offset = 36, noisy = true)]
|
||||
public Vector3Control velocity { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Separate access to the <see cref="Pose.angularVelocity"/> value.
|
||||
/// </summary>
|
||||
[Preserve]
|
||||
[InputControl(offset = 48, noisy = true)]
|
||||
public Vector3Control angularVelocity { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default Constructor required by the Input System for instantiation.
|
||||
/// </summary>
|
||||
public PoseControl()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// See [InputControl.FinishSetup](xref:UnityEngine.InputSystem.InputControl.FinishSetup)
|
||||
/// </summary>
|
||||
protected override void FinishSetup()
|
||||
{
|
||||
isTracked = GetChildControl<ButtonControl>("isTracked");
|
||||
trackingState = GetChildControl<IntegerControl>("trackingState");
|
||||
position = GetChildControl<Vector3Control>("position");
|
||||
rotation = GetChildControl<QuaternionControl>("rotation");
|
||||
velocity = GetChildControl<Vector3Control>("velocity");
|
||||
angularVelocity = GetChildControl<Vector3Control>("angularVelocity");
|
||||
|
||||
base.FinishSetup();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read unprocessed state values from the input control state.
|
||||
/// </summary>
|
||||
/// <param name="statePtr">State data to read from.</param>
|
||||
/// <returns>The pose data from the unprocessed state.</returns>
|
||||
public override unsafe Pose ReadUnprocessedValueFromState(void* statePtr)
|
||||
{
|
||||
return new Pose()
|
||||
{
|
||||
isTracked = isTracked.ReadUnprocessedValueFromState(statePtr) > 0.5f,
|
||||
trackingState = (TrackingState)trackingState.ReadUnprocessedValueFromState(statePtr),
|
||||
position = position.ReadUnprocessedValueFromState(statePtr),
|
||||
rotation = rotation.ReadUnprocessedValueFromState(statePtr),
|
||||
velocity = velocity.ReadUnprocessedValueFromState(statePtr),
|
||||
angularVelocity = angularVelocity.ReadUnprocessedValueFromState(statePtr),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write value data into input control state.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write into the control state.</param>
|
||||
/// <param name="statePtr">A pointer to the control state data.</param>
|
||||
public override unsafe void WriteValueIntoState(Pose value, void* statePtr)
|
||||
{
|
||||
isTracked.WriteValueIntoState(value.isTracked, statePtr);
|
||||
trackingState.WriteValueIntoState((uint)value.trackingState, statePtr);
|
||||
position.WriteValueIntoState(value.position, statePtr);
|
||||
rotation.WriteValueIntoState(value.rotation, statePtr);
|
||||
velocity.WriteValueIntoState(value.velocity, statePtr);
|
||||
angularVelocity.WriteValueIntoState(value.angularVelocity, statePtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a97daaeb654fbf449ac3c32bd2785d6c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user