using System.Collections.Generic; using UnityEngine.InputSystem.Controls; using UnityEngine.InputSystem.Layouts; using UnityEngine.InputSystem.XR; using UnityEngine.Scripting; using UnityEngine.XR.OpenXR.Input; #if UNITY_EDITOR using UnityEditor; #endif #if USE_INPUT_SYSTEM_POSE_CONTROL using PoseControl = UnityEngine.InputSystem.XR.PoseControl; #else using PoseControl = UnityEngine.XR.OpenXR.Input.PoseControl; #endif #if USE_STICK_CONTROL_THUMBSTICKS using ThumbstickControl = UnityEngine.InputSystem.Controls.StickControl; // If replaced, make sure the control extends Vector2Control #else using ThumbstickControl = UnityEngine.InputSystem.Controls.Vector2Control; #endif namespace UnityEngine.XR.OpenXR.Features.Interactions { /// /// This enables the use of Oculus TouchControllers interaction profiles in OpenXR. /// #if UNITY_EDITOR [UnityEditor.XR.OpenXR.Features.OpenXRFeature(UiName = "Oculus Touch Controller Profile", BuildTargetGroups = new[] { BuildTargetGroup.Standalone, BuildTargetGroup.WSA, BuildTargetGroup.Android}, Company = "Unity", Desc = "Allows for mapping input to the Oculus Touch Controller interaction profile.", DocumentationLink = Constants.k_DocumentationManualURL + "features/oculustouchcontrollerprofile.html", OpenxrExtensionStrings = "", Version = "0.0.1", Category = UnityEditor.XR.OpenXR.Features.FeatureCategory.Interaction, FeatureId = featureId)] #endif public class OculusTouchControllerProfile : OpenXRInteractionFeature { /// /// The feature id string. This is used to give the feature a well known id for reference. /// public const string featureId = "com.unity.openxr.feature.input.oculustouch"; /// /// An Input System device based on the hand interaction profile in the Oculus Touch Controller. /// [Preserve, InputControlLayout(displayName = "Oculus Touch Controller (OpenXR)", commonUsages = new[] { "LeftHand", "RightHand" })] public class OculusTouchController : XRControllerWithRumble { /// /// A [Vector2Control](xref:UnityEngine.InputSystem.Controls.Vector2Control)/[StickControl](xref:UnityEngine.InputSystem.Controls.StickControl) that represents the OpenXR binding. /// [Preserve, InputControl(aliases = new[] { "Primary2DAxis", "Joystick" }, usage = "Primary2DAxis")] public ThumbstickControl thumbstick { get; private set; } /// /// A [AxisControl](xref:UnityEngine.InputSystem.Controls.AxisControl) that represents the OpenXR binding. /// [Preserve, InputControl(aliases = new[] { "GripAxis", "squeeze" }, usage = "Grip")] public AxisControl grip { get; private set; } /// /// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR binding. /// [Preserve, InputControl(aliases = new[] { "GripButton", "squeezeClicked" }, usage = "GripButton")] public ButtonControl gripPressed { get; private set; } /// /// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR bindings, depending on handedness. /// [Preserve, InputControl(aliases = new[] { "Primary", "menuButton", "systemButton" }, usage = "MenuButton")] public ButtonControl menu { get; private set; } /// /// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR bindings, depending on handedness. /// [Preserve, InputControl(aliases = new[] { "A", "X", "buttonA", "buttonX" }, usage = "PrimaryButton")] public ButtonControl primaryButton { get; private set; } /// /// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR bindings, depending on handedness. /// [Preserve, InputControl(aliases = new[] { "ATouched", "XTouched", "ATouch", "XTouch", "buttonATouched", "buttonXTouched" }, usage = "PrimaryTouch")] public ButtonControl primaryTouched { get; private set; } /// /// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR bindings, depending on handedness. /// [Preserve, InputControl(aliases = new[] { "B", "Y", "buttonB", "buttonY" }, usage = "SecondaryButton")] public ButtonControl secondaryButton { get; private set; } /// /// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR bindings, depending on handedness. /// [Preserve, InputControl(aliases = new[] { "BTouched", "YTouched", "BTouch", "YTouch", "buttonBTouched", "buttonYTouched" }, usage = "SecondaryTouch")] public ButtonControl secondaryTouched { get; private set; } /// /// A [AxisControl](xref:UnityEngine.InputSystem.Controls.AxisControl) that represents the OpenXR binding. /// [Preserve, InputControl(usage = "Trigger")] public AxisControl trigger { get; private set; } /// /// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR binding. /// [Preserve, InputControl(aliases = new[] { "indexButton", "indexTouched", "triggerbutton" }, usage = "TriggerButton")] public ButtonControl triggerPressed { get; private set; } /// /// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR binding. /// [Preserve, InputControl(aliases = new[] { "indexTouch", "indexNearTouched" }, usage = "TriggerTouch")] public ButtonControl triggerTouched { get; private set; } /// /// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR binding. /// [Preserve, InputControl(aliases = new[] { "JoystickOrPadPressed", "thumbstickClick", "joystickClicked" }, usage = "Primary2DAxisClick")] public ButtonControl thumbstickClicked { get; private set; } /// /// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR binding. /// [Preserve, InputControl(aliases = new[] { "JoystickOrPadTouched", "thumbstickTouch", "joystickTouched" }, usage = "Primary2DAxisTouch")] public ButtonControl thumbstickTouched { get; private set; } /// /// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the OpenXR binding. /// [Preserve, InputControl(usage = "ThumbrestTouch")] public ButtonControl thumbrestTouched { get; private set; } /// /// A that represents the OpenXR binding. /// [Preserve, InputControl(offset = 0, aliases = new[] { "device", "gripPose" }, usage = "Device")] public PoseControl devicePose { get; private set; } /// /// A that represents the OpenXR binding. /// [Preserve, InputControl(offset = 0, alias = "aimPose", usage = "Pointer")] public PoseControl pointer { get; private set; } /// /// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) required for backwards compatibility with the XRSDK layouts. This represents the overall tracking state of the device. This value is equivalent to mapping devicePose/isTracked. /// [Preserve, InputControl(offset = 28, usage = "IsTracked")] new public ButtonControl isTracked { get; private set; } /// /// A [IntegerControl](xref:UnityEngine.InputSystem.Controls.IntegerControl) required for backwards compatibility with the XRSDK layouts. This represents the bit flag set to indicate what data is valid. This value is equivalent to mapping devicePose/trackingState. /// [Preserve, InputControl(offset = 32, usage = "TrackingState")] new public IntegerControl trackingState { get; private set; } /// /// A [Vector3Control](xref:UnityEngine.InputSystem.Controls.Vector3Control) required for backwards compatibility with the XRSDK layouts. This is the device position. For the Oculus Touch device, this is both the grip and the pointer position. This value is equivalent to mapping devicePose/position. /// [Preserve, InputControl(offset = 36, noisy = true, alias = "gripPosition")] new public Vector3Control devicePosition { get; private set; } /// /// A [QuaternionControl](xref:UnityEngine.InputSystem.Controls.QuaternionControl) required for backwards compatibility with the XRSDK layouts. This is the device orientation. For the Oculus Touch device, this is both the grip and the pointer rotation. This value is equivalent to mapping devicePose/rotation. /// [Preserve, InputControl(offset = 48, noisy = true, alias = "gripOrientation")] new public QuaternionControl deviceRotation { get; private set; } /// /// A [Vector3Control](xref:UnityEngine.InputSystem.Controls.Vector3Control) required for back compatibility with the XRSDK layouts. This is the pointer position. This value is equivalent to mapping pointerPose/position. /// [Preserve, InputControl(offset = 96)] public Vector3Control pointerPosition { get; private set; } /// /// A [QuaternionControl](xref:UnityEngine.InputSystem.Controls.QuaternionControl) required for backwards compatibility with the XRSDK layouts. This is the pointer rotation. This value is equivalent to mapping pointerPose/rotation. /// [Preserve, InputControl(offset = 108, alias = "pointerOrientation")] public QuaternionControl pointerRotation { get; private set; } /// /// A that represents the binding. /// [Preserve, InputControl(usage = "Haptic")] public HapticControl haptic { get; private set; } /// /// Internal call used to assign controls to the the correct element. /// protected override void FinishSetup() { base.FinishSetup(); thumbstick = GetChildControl("thumbstick"); trigger = GetChildControl("trigger"); triggerPressed = GetChildControl("triggerPressed"); triggerTouched = GetChildControl("triggerTouched"); grip = GetChildControl("grip"); gripPressed = GetChildControl("gripPressed"); menu = GetChildControl("menu"); primaryButton = GetChildControl("primaryButton"); primaryTouched = GetChildControl("primaryTouched"); secondaryButton = GetChildControl("secondaryButton"); secondaryTouched = GetChildControl("secondaryTouched"); thumbstickClicked = GetChildControl("thumbstickClicked"); thumbstickTouched = GetChildControl("thumbstickTouched"); thumbrestTouched = GetChildControl("thumbrestTouched"); devicePose = GetChildControl("devicePose"); pointer = GetChildControl("pointer"); isTracked = GetChildControl("isTracked"); trackingState = GetChildControl("trackingState"); devicePosition = GetChildControl("devicePosition"); deviceRotation = GetChildControl("deviceRotation"); pointerPosition = GetChildControl("pointerPosition"); pointerRotation = GetChildControl("pointerRotation"); haptic = GetChildControl("haptic"); } } /// /// The interaction profile string used to reference the Oculus Touch Controller. /// public const string profile = "/interaction_profiles/oculus/touch_controller"; // Available Bindings // Left Hand Only /// /// Constant for a boolean interaction binding '.../input/x/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the user path. /// public const string buttonX = "/input/x/click"; /// /// Constant for a boolean interaction binding '.../input/x/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the user path. /// public const string buttonXTouch = "/input/x/touch"; /// /// Constant for a boolean interaction binding '.../input/y/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the user path. /// public const string buttonY = "/input/y/click"; /// /// Constant for a boolean interaction binding '.../input/y/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the user path. /// public const string buttonYTouch = "/input/y/touch"; /// /// Constant for a boolean interaction binding '.../input/menu/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the user path. /// public const string menu = "/input/menu/click"; // Right Hand Only /// /// Constant for a boolean interaction binding '.../input/a/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the user path. /// public const string buttonA = "/input/a/click"; /// /// Constant for a boolean interaction binding '.../input/a/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the user path. /// public const string buttonATouch = "/input/a/touch"; /// /// Constant for a boolean interaction binding '..."/input/b/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the user path. /// public const string buttonB = "/input/b/click"; /// /// Constant for a boolean interaction binding '.../input/b/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the user path. /// public const string buttonBTouch = "/input/b/touch"; /// /// Constant for a boolean interaction binding '.../input/system/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the user path. /// public const string system = "/input/system/click"; // Both Hands /// /// Constant for a float interaction binding '.../input/grip/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. /// public const string squeeze = "/input/squeeze/value"; /// /// Constant for a float interaction binding '.../input/grip/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. /// public const string trigger = "/input/trigger/value"; /// /// Constant for a boolean interaction binding '.../input/grip/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. /// public const string triggerTouch = "/input/trigger/touch"; /// /// Constant for a Vector2 interaction binding '.../input/grip/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. /// public const string thumbstick = "/input/thumbstick"; /// /// Constant for a boolean interaction binding '.../input/grip/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. /// public const string thumbstickClick = "/input/thumbstick/click"; /// /// Constant for a boolean interaction binding '.../input/grip/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. /// public const string thumbstickTouch = "/input/thumbstick/touch"; /// /// Constant for a boolean interaction binding '.../input/grip/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. /// public const string thumbrest = "/input/thumbrest/touch"; /// /// Constant for a pose interaction binding '.../input/grip/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. /// public const string grip = "/input/grip/pose"; /// /// Constant for a pose interaction binding '.../input/grip/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. /// public const string aim = "/input/aim/pose"; /// /// Constant for a haptic interaction binding '.../input/grip/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. /// public const string haptic = "/output/haptic"; private const string kDeviceLocalizedName = "Oculus Touch Controller OpenXR"; /// /// Registers the layout with the Input System. /// protected override void RegisterDeviceLayout() { #if UNITY_EDITOR if (!OpenXRLoaderEnabledForSelectedBuildTarget(EditorUserBuildSettings.selectedBuildTargetGroup)) return; #endif InputSystem.InputSystem.RegisterLayout(typeof(OculusTouchController), matches: new InputDeviceMatcher() .WithInterface(XRUtilities.InterfaceMatchAnyVersion) .WithProduct(kDeviceLocalizedName)); } /// /// Removes the layout from the Input System. /// protected override void UnregisterDeviceLayout() { #if UNITY_EDITOR if (!OpenXRLoaderEnabledForSelectedBuildTarget(EditorUserBuildSettings.selectedBuildTargetGroup)) return; #endif InputSystem.InputSystem.RemoveLayout(nameof(OculusTouchController)); } /// /// Return device layout string that used for registering device for the Input System. /// /// Device layout string. protected override string GetDeviceLayoutName() { return nameof(OculusTouchController); } /// protected override void RegisterActionMapsWithRuntime() { ActionMapConfig actionMap = new ActionMapConfig() { name = "oculustouchcontroller", localizedName = kDeviceLocalizedName, desiredInteractionProfile = profile, manufacturer = "Oculus", serialNumber = "", deviceInfos = new List() { new DeviceConfig() { characteristics = (InputDeviceCharacteristics)(InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Left), userPath = UserPaths.leftHand }, new DeviceConfig() { characteristics = (InputDeviceCharacteristics)(InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Right), userPath = UserPaths.rightHand } }, actions = new List() { // Joystick new ActionConfig() { name = "thumbstick", localizedName = "Thumbstick", type = ActionType.Axis2D, usages = new List() { "Primary2DAxis" }, bindings = new List() { new ActionBinding() { interactionPath = thumbstick, interactionProfileName = profile, } } }, // Grip new ActionConfig() { name = "grip", localizedName = "Grip", type = ActionType.Axis1D, usages = new List() { "Grip" }, bindings = new List() { new ActionBinding() { interactionPath = squeeze, interactionProfileName = profile, } } }, // Grip Pressed new ActionConfig() { name = "gripPressed", localizedName = "Grip Pressed", type = ActionType.Binary, usages = new List() { "GripButton" }, bindings = new List() { new ActionBinding() { interactionPath = squeeze, interactionProfileName = profile, } } }, // Menu new ActionConfig() { name = "menu", localizedName = "Menu", type = ActionType.Binary, usages = new List() { "MenuButton" }, bindings = new List() { new ActionBinding() { interactionPath = menu, interactionProfileName = profile, userPaths = new List() { UserPaths.leftHand } }, new ActionBinding() { interactionPath = system, interactionProfileName = profile, userPaths = new List() { UserPaths.rightHand } }, } }, //A / X Press new ActionConfig() { name = "primaryButton", localizedName = "Primary Button", type = ActionType.Binary, usages = new List() { "PrimaryButton" }, bindings = new List() { new ActionBinding() { interactionPath = buttonX, interactionProfileName = profile, userPaths = new List() { UserPaths.leftHand } }, new ActionBinding() { interactionPath = buttonA, interactionProfileName = profile, userPaths = new List() { UserPaths.rightHand } }, } }, //A / X Touch new ActionConfig() { name = "primaryTouched", localizedName = "Primary Touched", type = ActionType.Binary, usages = new List() { "PrimaryTouch" }, bindings = new List() { new ActionBinding() { interactionPath = buttonXTouch, interactionProfileName = profile, userPaths = new List() { UserPaths.leftHand } }, new ActionBinding() { interactionPath = buttonATouch, interactionProfileName = profile, userPaths = new List() { UserPaths.rightHand } }, } }, //B / Y Press new ActionConfig() { name = "secondaryButton", localizedName = "Secondary Button", type = ActionType.Binary, usages = new List() { "SecondaryButton" }, bindings = new List() { new ActionBinding() { interactionPath = buttonY, interactionProfileName = profile, userPaths = new List() { UserPaths.leftHand } }, new ActionBinding() { interactionPath = buttonB, interactionProfileName = profile, userPaths = new List() { UserPaths.rightHand } }, } }, //B / Y Touch new ActionConfig() { name = "secondaryTouched", localizedName = "Secondary Touched", type = ActionType.Binary, usages = new List() { "SecondaryTouch" }, bindings = new List() { new ActionBinding() { interactionPath = buttonYTouch, interactionProfileName = profile, userPaths = new List() { UserPaths.leftHand } }, new ActionBinding() { interactionPath = buttonBTouch, interactionProfileName = profile, userPaths = new List() { UserPaths.rightHand } }, } }, // Trigger new ActionConfig() { name = "trigger", localizedName = "Trigger", type = ActionType.Axis1D, usages = new List() { "Trigger" }, bindings = new List() { new ActionBinding() { interactionPath = trigger, interactionProfileName = profile, } } }, // Trigger Pressed new ActionConfig() { name = "triggerPressed", localizedName = "Trigger Pressed", type = ActionType.Binary, usages = new List() { "TriggerButton" }, bindings = new List() { new ActionBinding() { interactionPath = trigger, interactionProfileName = profile, } } }, //Trigger Touch new ActionConfig() { name = "triggerTouched", localizedName = "Trigger Touched", type = ActionType.Binary, usages = new List() { "TriggerTouch" }, bindings = new List() { new ActionBinding() { interactionPath = triggerTouch, interactionProfileName = profile, } } }, //Thumbstick Clicked new ActionConfig() { name = "thumbstickClicked", localizedName = "Thumbstick Clicked", type = ActionType.Binary, usages = new List() { "Primary2DAxisClick" }, bindings = new List() { new ActionBinding() { interactionPath = thumbstickClick, interactionProfileName = profile, } } }, //Thumbstick Touched new ActionConfig() { name = "thumbstickTouched", localizedName = "Thumbstick Touched", type = ActionType.Binary, usages = new List() { "Primary2DAxisTouch" }, bindings = new List() { new ActionBinding() { interactionPath = thumbstickTouch, interactionProfileName = profile, } } }, //Thumbrest Touched new ActionConfig() { name = "thumbrestTouched", localizedName = "Thumbrest Touched", type = ActionType.Binary, usages = new List() { "ThumbrestTouch" }, bindings = new List() { new ActionBinding() { interactionPath = thumbrest, interactionProfileName = profile, } } }, // Device Pose new ActionConfig() { name = "devicePose", localizedName = "Device Pose", type = ActionType.Pose, usages = new List() { "Device" }, bindings = new List() { new ActionBinding() { interactionPath = grip, interactionProfileName = profile, } } }, // Pointer Pose new ActionConfig() { name = "pointer", localizedName = "Pointer Pose", type = ActionType.Pose, usages = new List() { "Pointer" }, bindings = new List() { new ActionBinding() { interactionPath = aim, interactionProfileName = profile, } } }, // Haptics new ActionConfig() { name = "haptic", localizedName = "Haptic Output", type = ActionType.Vibrate, usages = new List() { "Haptic" }, bindings = new List() { new ActionBinding() { interactionPath = haptic, interactionProfileName = profile, } } } } }; AddActionMap(actionMap); } } }