// Copyright HTC Corporation All Rights Reserved. using System.Collections.Generic; using UnityEngine; using UnityEngine.Scripting; using UnityEngine.XR.OpenXR.Input; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Layouts; using UnityEngine.InputSystem.Controls; using UnityEngine.InputSystem.XR; using UnityEngine.XR; using UnityEngine.XR.OpenXR.Features; #if UNITY_EDITOR using UnityEditor; using UnityEditor.XR.OpenXR.Features; #endif #if USE_INPUT_SYSTEM_POSE_CONTROL // Scripting Define Symbol added by using OpenXR Plugin 1.6.0. using PoseControl = UnityEngine.InputSystem.XR.PoseControl; #else using PoseControl = UnityEngine.XR.OpenXR.Input.PoseControl; #endif namespace VIVE.OpenXR { /// /// This enables the use of HTC Vive Cosmos interaction profiles in OpenXR. /// #if UNITY_EDITOR [OpenXRFeature(UiName = "VIVE Cosmos Controller Interaction", BuildTargetGroups = new[] { BuildTargetGroup.Standalone, BuildTargetGroup.WSA }, Company = "HTC", Desc = "Allows for mapping input to the HTC Vive Cosmos interaction profile.", DocumentationLink = "https://developer.vive.com/resources/openxr/openxr-pcvr/tutorials/unity/cosmos-controller-openxr-feature-unity/", OpenxrExtensionStrings = "XR_HTC_vive_cosmos_controller_interaction", Version = "0.0.1", Category = FeatureCategory.Interaction, FeatureId = featureId)] #endif public class VIVECosmosProfile : OpenXRInteractionFeature { /// /// The feature id string. This is used to give the feature a well known id for reference. /// public const string featureId = "vive.openxr.feature.cosmoscontroller"; /// /// An Input System device based on the HTC Vive Cosmos Controller. /// /// [Preserve, InputControlLayout(displayName = "VIVE Cosmos Controller (OpenXR)", commonUsages = new[] { "LeftHand", "RightHand" })] public class ViveCosmosController : XRControllerWithRumble { /// /// A representing information from the OpenXR binding. /// [Preserve, InputControl(aliases = new[] { "GripAxis" })] public AxisControl grip { get; private set; } /// /// A representing information from the OpenXR binding. /// [Preserve, InputControl(aliases = new[] { "GripButton" })] public ButtonControl gripPressed { get; private set; } /// /// A representing the OpenXR bindings, depending on handedness. /// [Preserve, InputControl(aliases = new[] { "B", "Y" })] public ButtonControl secondaryButton { get; private set; } /// /// A representing the OpenXR bindings, depending on handedness. /// [Preserve, InputControl(aliases = new[] { "A", "X" })] public ButtonControl primaryButton { get; private set; } /// /// A representing information from the OpenXR binding. /// [Preserve, InputControl(aliases = new[] { "ShoulderButton" })] public ButtonControl shoulderPressed { get; private set; } /// /// A representing information from the OpenXR binding. /// [Preserve, InputControl(aliases = new[] { "Primary", "menubutton" })] public ButtonControl menu { get; private set; } /// /// A representing information from the OpenXR binding. /// [Preserve, InputControl(aliases = new[] { "triggeraxis" })] public AxisControl trigger { get; private set; } /// /// A representing information from the OpenXR binding. /// [Preserve, InputControl(aliases = new[] { "triggerbutton" })] public ButtonControl triggerPressed { get; private set; } /// /// A representing information from the OpenXR binding. /// [Preserve, InputControl(aliases = new[] { "Primary2DAxis", "joystickaxes" })] public Vector2Control joystick { get; private set; } /// /// A representing information from the OpenXR binding. /// [Preserve, InputControl(aliases = new[] { "joystickorpadpressed", "joystickpressed" })] public ButtonControl joystickClicked { get; private set; } /// /// A representing information from the OpenXR binding. /// [Preserve, InputControl(aliases = new[] { "joystickorpadtouched", "joysticktouched" })] public ButtonControl joystickTouched { get; private set; } /// /// A representing information from the OpenXR binding. /// [Preserve, InputControl(offset = 0, alias = "device")] public PoseControl devicePose { get; private set; } /// /// A representing information from the OpenXR binding. /// [Preserve, InputControl(offset = 0)] public PoseControl pointer { get; private set; } /// /// A required for back 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)] new public ButtonControl isTracked { get; private set; } /// /// A required for back compatibility with the XRSDK layouts. this represents the bit flag set indicating what data is valid. this value is equivalent to mapping devicePose/trackingState /// [Preserve, InputControl(offset = 32)] new public IntegerControl trackingState { get; private set; } /// /// A required for back compatibility with the XRSDK layouts. this is the device position, or grip position. this value is equivalent to mapping devicePose/position /// [Preserve, InputControl(offset = 36, aliases = new[] { "gripPosition" })] new public Vector3Control devicePosition { get; private set; } /// /// A required for back compatibility with the XRSDK layouts. this is the device orientation, or grip orientation. this value is equivalent to mapping devicePose/rotation /// [Preserve, InputControl(offset = 48, aliases = new[] { "gripOrientation", "gripRotation" })] new public QuaternionControl deviceRotation { get; private set; } /// /// A 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 required for back compatibility with the XRSDK layouts. this is the pointer rotation. this value is equivalent to mapping pointerPose/rotation /// [Preserve, InputControl(offset = 108, aliases = new[] { "pointerOrientation" })] public QuaternionControl pointerRotation { get; private set; } /// /// A that represents the binding. /// [Preserve, InputControl(usage = "Haptic")] public HapticControl haptic { get; private set; } /// protected override void FinishSetup() { base.FinishSetup(); grip = GetChildControl("grip"); gripPressed = GetChildControl("gripPressed"); primaryButton = GetChildControl("primaryButton"); secondaryButton = GetChildControl("secondaryButton"); shoulderPressed = GetChildControl("shoulderPressed"); menu = GetChildControl("menu"); trigger = GetChildControl("trigger"); triggerPressed = GetChildControl("triggerPressed"); joystick = GetChildControl("joystick"); joystickClicked = GetChildControl("joystickClicked"); joystickTouched = GetChildControl("joystickTouched"); 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 HTC Vive Controller. public const string profile = "/interaction_profiles/htc/vive_cosmos_controller"; /// /// Constant for a interaction binding '.../input/trigger/click' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string select = "/input/trigger/click"; /// /// Constant for a interaction binding '.../input/a/click' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string a = "/input/a/click"; /// /// Constant for a interaction binding '.../input/b/click' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string b = "/input/b/click"; /// /// Constant for a interaction binding '.../input/x/click' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string x = "/input/x/click"; /// /// Constant for a interaction binding '.../input/y/click' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string y = "/input/y/click"; /// /// Constant for a interaction binding '.../input/y/shoulder' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string shoulder = "/input/shoulder/click"; /// /// Constant for a interaction binding '.../input/squeeze/click' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string squeeze = "/input/squeeze/click"; /// /// Constant for a interaction binding '.../input/menu/click' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string menu = "/input/menu/click"; /// /// Constant for a interaction binding '.../input/trigger/value' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string trigger = "/input/trigger/value"; /// /// Constant for a interaction binding '.../input/trigger/click' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string triggerClick = "/input/trigger/click"; /// /// Constant for a interaction binding '.../input/trackpad' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string thumbstick = "/input/thumbstick"; /// /// Constant for a interaction binding '.../input/trackpad/click' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string thumbstickClick = "/input/thumbstick/click"; /// /// Constant for a interaction binding '.../input/trackpad/touch' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string thumbstickTouch = "/input/thumbstick/touch"; /// /// Constant for a interaction binding '.../input/grip/pose' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string grip = "/input/grip/pose"; /// /// Constant for a interaction binding '.../input/aim/pose' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string aim = "/input/aim/pose"; /// /// Constant for a interaction binding '.../output/haptic' OpenXR Input Binding. Used by to bind actions to physical inputs. /// public const string haptic = "/output/haptic"; private const string kLayoutName = "ViveCosmosController"; private const string kDeviceLocalizedName = "VIVE Cosmos Controller OpenXR"; /// /// Registers the layout with the Input System. Matches the that is registered with . /// protected override void RegisterDeviceLayout() { Debug.LogFormat("VIVECosmosProfile RegisterDeviceLayout() {0} , product: {1}", kLayoutName, kDeviceLocalizedName); InputSystem.RegisterLayout(typeof(ViveCosmosController), kLayoutName, matches: new InputDeviceMatcher() .WithInterface(XRUtilities.InterfaceMatchAnyVersion) .WithProduct(kDeviceLocalizedName)); } /// /// Removes the layout from the Input System. Matches the that is registered with . /// protected override void UnregisterDeviceLayout() { Debug.LogFormat("VIVECosmosProfile UnregisterDeviceLayout() {0}", kLayoutName); InputSystem.RemoveLayout(kLayoutName); } #if UNITY_XR_OPENXR_1_9_1 /// /// Return interaction profile type. VIVEFocus3Controller profile is Device type. /// /// Interaction profile type. protected override InteractionProfileType GetInteractionProfileType() { return typeof(ViveCosmosController).IsSubclassOf(typeof(XRController)) ? InteractionProfileType.XRController : InteractionProfileType.Device; } /// /// Return device layer out string used for registering device VIVEFocus3Controller in InputSystem. /// /// Device layout string. protected override string GetDeviceLayoutName() { return kLayoutName; } #endif /// /// Registers an with OpenXR that matches the HTC Vive Controller. Also calls when the Input System package is available. /// protected override void RegisterActionMapsWithRuntime() { ActionMapConfig actionMap = new ActionMapConfig() { name = "vivecosmoscontroller", localizedName = kDeviceLocalizedName, desiredInteractionProfile = profile, manufacturer = "HTC", serialNumber = "", deviceInfos = new List() { new DeviceConfig() { characteristics = InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Left, userPath = UserPaths.leftHand }, new DeviceConfig() { characteristics = InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Right, userPath = UserPaths.rightHand } }, actions = new List() { new ActionConfig() { name = "primarybutton", localizedName = "Primary Button", type = ActionType.Binary, usages = new List() { "PrimaryButton" }, bindings = new List() { new ActionBinding() { interactionPath = x, interactionProfileName = profile, userPaths = new List() { UserPaths.leftHand } }, new ActionBinding() { interactionPath = a, interactionProfileName = profile, userPaths = new List() { UserPaths.rightHand } }, } }, new ActionConfig() { name = "secondarybutton", localizedName = "Secondary Button", type = ActionType.Binary, usages = new List() { "SecondaryButton" }, bindings = new List() { new ActionBinding() { interactionPath = y, interactionProfileName = profile, userPaths = new List() { UserPaths.leftHand } }, new ActionBinding() { interactionPath = b, interactionProfileName = profile, userPaths = new List() { UserPaths.rightHand } }, } }, new ActionConfig() { name = "grip", localizedName = "Grip", type = ActionType.Axis1D, usages = new List() { "Grip" }, bindings = new List() { new ActionBinding() { interactionPath = squeeze, interactionProfileName = profile, } } }, new ActionConfig() { name = "grippressed", localizedName = "Grip Pressed", type = ActionType.Binary, usages = new List() { "GripPressed", "GripButton" }, bindings = new List() { new ActionBinding() { interactionPath = squeeze, interactionProfileName = profile, } } }, 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 ActionConfig() { name = "shoulderpressed", localizedName = "Shoulder Pressed", type = ActionType.Binary, usages = new List() { "ShoulderButton" }, bindings = new List() { new ActionBinding() { interactionPath = shoulder, interactionProfileName = profile, } } }, new ActionConfig() { name = "trigger", localizedName = "Trigger", type = ActionType.Axis1D, usages = new List() { "Trigger" }, bindings = new List() { new ActionBinding() { interactionPath = trigger, interactionProfileName = profile, } } }, new ActionConfig() { name = "triggerpressed", localizedName = "Trigger Pressed", type = ActionType.Binary, usages = new List() { "TriggerPressed", "TriggerButton" }, bindings = new List() { new ActionBinding() { interactionPath = triggerClick, interactionProfileName = profile, } } }, new ActionConfig() { name = "thumbstick", localizedName = "Thumbstick", type = ActionType.Axis2D, usages = new List() { "Primary2DAxis" }, bindings = new List() { new ActionBinding() { interactionPath = thumbstick, interactionProfileName = profile, } } }, new ActionConfig() { name = "thumbsticktouched", localizedName = "Thumbstick Touched", type = ActionType.Binary, usages = new List() { "Primary2DAxisTouch" }, bindings = new List() { new ActionBinding() { interactionPath = thumbstickTouch, interactionProfileName = profile, } } }, new ActionConfig() { name = "thumbstickclicked", localizedName = "Thumbstick Clicked", type = ActionType.Binary, usages = new List() { "Primary2DAxisClick" }, bindings = new List() { new ActionBinding() { interactionPath = thumbstickClick, interactionProfileName = profile, } } }, new ActionConfig() { name = "devicepose", localizedName = "Device Pose", type = ActionType.Pose, usages = new List() { "Device" }, bindings = new List() { new ActionBinding() { interactionPath = grip, interactionProfileName = profile, } } }, new ActionConfig() { name = "pointer", localizedName = "Pointer Pose", type = ActionType.Pose, usages = new List() { "Pointer" }, bindings = new List() { new ActionBinding() { interactionPath = aim, interactionProfileName = profile, } } }, 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); } } }