using System; using System.Collections.Generic; using System.Reflection; using UnityEngine.InputSystem.Controls; using UnityEngine.InputSystem.Layouts; using UnityEngine.InputSystem.XR; using UnityEngine.Scripting; using UnityEngine.XR.OpenXR.Features; using UnityEngine.XR.OpenXR.Features.Interactions; using UnityEngine.XR.OpenXR.Input; #if USE_INPUT_SYSTEM_POSE_CONTROL using PoseControl = UnityEngine.InputSystem.XR.PoseControl; #else using PoseControl = UnityEngine.XR.OpenXR.Input.PoseControl; #endif #if UNITY_EDITOR using UnityEditor; #endif namespace UnityEngine.XR.OpenXR.Tests { /// /// Mock Interaction feature used in tests to test interaction features. /// #if UNITY_EDITOR [UnityEditor.XR.OpenXR.Features.OpenXRFeature(UiName = "Mock Interaction Feature", BuildTargetGroups = new[] { BuildTargetGroup.Standalone, BuildTargetGroup.Android }, Company = "Unity", Desc = "Mock interaction feature used for testing interactions", DocumentationLink = Constants.k_DocumentationManualURL + "features/khrsimplecontrollerprofile.html", OpenxrExtensionStrings = "", Version = "0.0.1", Category = UnityEditor.XR.OpenXR.Features.FeatureCategory.Interaction, Hidden = true, Priority = int.MinValue, FeatureId = featureId)] #endif internal class MockInteractionFeature : OpenXRInteractionFeature { public const string featureId = "com.unity.openxr.feature.input.mockinteraction"; private const string kDeviceLocalizedName = "Mock Controller OpenXR"; /// /// Mock controller used in testing of interaction features /// [Preserve, InputControlLayout(displayName = kDeviceLocalizedName, commonUsages = new[] { "LeftHand", "RightHand" })] public class MockController : XRControllerWithRumble { [Preserve, InputControl] public AxisControl trigger { get; private set; } [Preserve, InputControl] public ButtonControl triggerPressed { get; private set; } [Preserve, InputControl] public Vector2Control thumbstick { get; private set; } [Preserve, InputControl(offset = 0)] public PoseControl devicePose { get; private set; } [Preserve, InputControl(offset = 2)] public new ButtonControl isTracked { get; private set; } [Preserve, InputControl(offset = 4)] public new IntegerControl trackingState { get; private set; } [Preserve, InputControl] public new Vector3Control devicePosition { get; private set; } [Preserve, InputControl] public new QuaternionControl deviceRotation { get; private set; } [Preserve, InputControl] public HapticControl haptic { get; private set; } protected override void FinishSetup() { base.FinishSetup(); trigger = GetChildControl("trigger"); triggerPressed = GetChildControl("triggerPressed"); thumbstick = GetChildControl("thumbstick"); devicePose = GetChildControl("devicePose"); isTracked = GetChildControl("isTracked"); trackingState = GetChildControl("trackingState"); devicePosition = GetChildControl("devicePosition"); deviceRotation = GetChildControl("deviceRotation"); haptic = GetChildControl("haptic"); } } /// /// Get/Set the action map config that should be used to register actions for this profile. If no /// config is specified the default action map config will be used. /// public ActionMapConfig actionMapConfig { get; set; } /// /// Registers the layout with the Input System. /// protected override void RegisterDeviceLayout() { InputSystem.InputSystem.RegisterLayout(typeof(MockController), matches: new InputDeviceMatcher() .WithInterface(XRUtilities.InterfaceMatchAnyVersion) .WithProduct(kDeviceLocalizedName)); } /// /// Removes the layout from the Input System. /// protected override void UnregisterDeviceLayout() { InputSystem.InputSystem.RemoveLayout(nameof(MockController)); } protected override string GetDeviceLayoutName() { return nameof(MockController); } /// /// Create a default action map config for the controller /// /// public ActionMapConfig CreateDefaultActionMapConfig() => new ActionMapConfig() { name = "mockcontroller", localizedName = kDeviceLocalizedName, manufacturer = "Unity", serialNumber = "", desiredInteractionProfile = "/interaction_profiles/unity/mock_controller", deviceInfos = new List { new DeviceConfig { userPath = UserPaths.leftHand, characteristics = InputDeviceCharacteristics.Left | InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.Controller }, new DeviceConfig { userPath = UserPaths.rightHand, characteristics = InputDeviceCharacteristics.Right | InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.Controller } }, actions = new List { new ActionConfig { name = nameof(MockController.triggerPressed), localizedName = "Trigger Pressed", type = ActionType.Binary, bindings = new List { new ActionBinding { interactionPath = "/input/trigger/click" } } }, new ActionConfig { name = nameof(MockController.trigger), localizedName = "Trigger", type = ActionType.Axis1D, bindings = new List { new ActionBinding { interactionPath = "/input/trigger/value" } } }, new ActionConfig { name = nameof(MockController.thumbstick), localizedName = "Thumbstick", type = ActionType.Axis2D, bindings = new List { new ActionBinding { interactionPath = "/input/thumbstick/value" } } }, new ActionConfig { name = nameof(MockController.devicePose), localizedName = "Grip", type = ActionType.Pose, bindings = new List { new ActionBinding { interactionPath = "/input/grip/pose" } } }, new ActionConfig { name = nameof(MockController.haptic), localizedName = "Haptic Output", type = ActionType.Vibrate, bindings = new List { new ActionBinding { interactionPath = "/output/haptic" } } } } }; protected override void RegisterActionMapsWithRuntime() { AddActionMap(actionMapConfig ?? CreateDefaultActionMapConfig()); } } }