上传YomovSDK

This commit is contained in:
Sora丶kong
2026-03-03 03:15:46 +08:00
parent 9096da7e6c
commit eb97f31065
6477 changed files with 1932208 additions and 3 deletions

View 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();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3a95153fe0b4435da68d3efd1830a340
timeCreated: 1617987844

View 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
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 817760b76f5e57b4698bd2a27c26f55d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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");
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8dce6d72fc8d2d34e88488a09129d8a1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e3c40c4727414881b56fb6ba2ced6cf2
timeCreated: 1603741942

View 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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a97daaeb654fbf449ac3c32bd2785d6c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: