Files
dungeons/Assets/ThirdParty/UltimateXR/Runtime/Scripts/Devices/Integrations/SteamVR/UxrSteamVRControllerInput.cs

658 lines
32 KiB
C#

// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrSteamVRControllerInput.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Avatar.Controllers;
using UltimateXR.Core;
using UltimateXR.Haptics;
using UnityEngine;
#if ULTIMATEXR_USE_STEAMVR_SDK
using System;
using System.Linq;
using System.Text;
using Valve.VR;
using UltimateXR.Avatar.Rig;
using UltimateXR.Core.Settings;
using UltimateXR.Manipulation;
#endif
#pragma warning disable 414 // Disable warnings due to unused values
namespace UltimateXR.Devices.Integrations.SteamVR
{
/// <summary>
/// Base class for all SteamVR input devices.
/// Provides common input handling thanks to using the actions exported by the
/// SteamVRActionsExporter.
/// Child classes will require some overrides and minimal input handling if necessary.
/// </summary>
public abstract class UxrSteamVRControllerInput : UxrControllerInput
{
#region Inspector Properties/Serialized Fields
// These will be shown only in custom inspectors for controllers that use them (f.e. index controllers).
[SerializeField] [HideInInspector] private string _openHandPoseName;
[SerializeField] [HideInInspector] private float _indexCurlAmount = 60.0f;
[SerializeField] [HideInInspector] private float _middleCurlAmount = 60.0f;
[SerializeField] [HideInInspector] private float _ringCurlAmount = 60.0f;
[SerializeField] [HideInInspector] private float _littleCurlAmount = 60.0f;
[SerializeField] [HideInInspector] private float _thumbCurlAmount = 60.0f;
[SerializeField] [HideInInspector] private float _thumbSpreadAmount = 30.0f;
#endregion
#region Public Types & Data
/// <summary>
/// Gets list of controller names that the component can handle.
/// </summary>
public abstract IEnumerable<string> ControllerNames { get; }
/// <summary>
/// Gets if the class will use hand skeletons.
/// </summary>
public virtual bool UsesHandSkeletons => false;
#endregion
#region Public Overrides UxrControllerInput
/// <inheritdoc />
public override bool IsHandednessSupported => true;
/// <summary>
/// SteamVR child classes will require SteamVR SDK to access functionality.
/// </summary>
public override string SDKDependency => UxrConstants.SdkSteamVR;
/// <inheritdoc />
public override bool IsControllerEnabled(UxrHandSide handSide)
{
#if ULTIMATEXR_USE_STEAMVR_SDK
if (s_controllerList.TryGetValue(GetType().Name, out List<int> controllerIndices))
{
return controllerIndices.Contains(handSide == UxrHandSide.Left
? (int)OpenVR.System.GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole.LeftHand)
: (int)OpenVR.System.GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole.RightHand));
}
return false;
#else
return false;
#endif
}
/// <inheritdoc />
public override float GetInput1D(UxrHandSide handSide, UxrInput1D input1D, bool getIgnoredInput = false)
{
if (ShouldIgnoreInput(handSide, getIgnoredInput))
{
return 0.0f;
}
#if ULTIMATEXR_USE_STEAMVR_SDK
SteamVR_Input_Sources source = handSide == UxrHandSide.Left ? SteamVR_Input_Sources.LeftHand : SteamVR_Input_Sources.RightHand;
if (_actionsInput1D.TryGetValue(input1D, out SteamVR_Action_Single action))
{
return action[source].axis;
}
#endif
return 0.0f;
}
/// <inheritdoc />
public override Vector2 GetInput2D(UxrHandSide handSide, UxrInput2D input2D, bool getIgnoredInput = false)
{
if (ShouldIgnoreInput(handSide, getIgnoredInput))
{
return Vector2.zero;
}
#if ULTIMATEXR_USE_STEAMVR_SDK
SteamVR_Input_Sources source = handSide == UxrHandSide.Left ? SteamVR_Input_Sources.LeftHand : SteamVR_Input_Sources.RightHand;
if (_actionsInput2D.TryGetValue(input2D, out SteamVR_Action_Vector2 action))
{
return FilterTwoAxesDeadZone(action[source].axis, JoystickDeadZone);
}
#endif
return Vector2.zero;
}
/// <inheritdoc />
public override void SendHapticFeedback(UxrHandSide handSide, UxrHapticClip hapticClip)
{
if (hapticClip.FallbackClipType != UxrHapticClipType.None)
{
SendHapticFeedback(handSide, hapticClip.FallbackClipType, hapticClip.FallbackAmplitude, hapticClip.FallbackDurationSeconds, hapticClip.HapticMode);
}
}
/// <inheritdoc />
public override void SendHapticFeedback(UxrHandSide handSide,
float frequency,
float amplitude,
float durationSeconds,
UxrHapticMode hapticMode = UxrHapticMode.Mix)
{
#if ULTIMATEXR_USE_STEAMVR_SDK
SteamVR_Input_Sources source = handSide == UxrHandSide.Left ? SteamVR_Input_Sources.LeftHand : SteamVR_Input_Sources.RightHand;
_handHapticsAction.Execute(0.0f, durationSeconds, frequency, amplitude, source);
#endif
}
/// <inheritdoc />
public override void StopHapticFeedback(UxrHandSide handSide)
{
// TODO. Doesn't seem to be supported.
}
#endregion
#region Unity
/// <summary>
/// Takes care of registering the component in the global list of SteamVR input components.
/// Builds the action list to access input and starts listening for device connections.
/// </summary>
protected override void Awake()
{
base.Awake();
#if ULTIMATEXR_USE_STEAMVR_SDK
// Build actions
BuildActionObjects();
if (enabled)
{
// Listen to device connected events
SteamVR_Events.DeviceConnected.Remove(OnDeviceConnected);
SteamVR_Events.DeviceConnected.Listen(OnDeviceConnected);
}
_awakeFinished = true;
if (enabled)
{
// Disabled by default at the beginning, unless we already these controllers registered.
// If we already have the controllers registered it is due to an Awake() when loading a new scene.
enabled = s_controllerList.TryGetValue(InputClassName, out List<int> controllerIndices) && controllerIndices.Count > 0;
RaiseConnectOnStart = enabled;
if (!s_initializedSteamVR)
{
global::Valve.VR.SteamVR.Initialize();
SteamVR_Input.GetActionSet(UxrSteamVRConstants.ActionSetName).Activate();
s_initializedSteamVR = true;
}
}
#else
enabled = false;
#endif
}
/// <summary>
/// Called when the component is disabled. In the case the component was using skeletal
/// input, the hand will be driven by the Avatar Animator back again.
/// </summary>
protected override void OnDisable()
{
base.OnDisable();
if (UsesHandSkeletons)
{
if (!_awakeFinished || !UxrManager.Instance || !Avatar || !Avatar.AvatarController)
{
return;
}
UxrStandardAvatarController standardAvatarController = Avatar.AvatarController as UxrStandardAvatarController;
if (standardAvatarController == null)
{
return;
}
if (!string.IsNullOrEmpty(_openHandPoseName))
{
standardAvatarController.LeftHandDefaultPoseNameOverride = null;
standardAvatarController.RightHandDefaultPoseNameOverride = null;
standardAvatarController.LeftHandGrabPoseNameOverride = null;
standardAvatarController.RightHandGrabPoseNameOverride = null;
}
}
}
/// <summary>
/// Initializes SteamVR if necessary and activates the UltimateXR action set.
/// Will initialize skeleton functionality if necessary.
/// </summary>
protected override void Start()
{
base.Start();
#if ULTIMATEXR_USE_STEAMVR_SDK
if (UsesHandSkeletons)
{
_handSkeletonActionLeft.SetSkeletalTransformSpace(EVRSkeletalTransformSpace.Model);
_handSkeletonActionRight.SetSkeletalTransformSpace(EVRSkeletalTransformSpace.Model);
}
#endif
}
/// <summary>
/// If the component has skeleton capabilities, the hand bones will be updated here.
/// </summary>
private void LateUpdate()
{
if (Avatar == null)
{
}
#if ULTIMATEXR_USE_STEAMVR_SDK
// Update using skeleton if necessary
if (UsesHandSkeletons)
{
UxrStandardAvatarController avatarControllerStandard = Avatar.AvatarController as UxrStandardAvatarController;
UxrAvatarRig avatarRig = Avatar.AvatarRig;
if (avatarControllerStandard == null)
{
return;
}
float curlIndex = _handSkeletonActionLeft.fingerCurls[SteamVR_Skeleton_FingerIndexes.index] * _indexCurlAmount;
float curlMiddle = _handSkeletonActionLeft.fingerCurls[SteamVR_Skeleton_FingerIndexes.middle] * _middleCurlAmount;
float curlRing = _handSkeletonActionLeft.fingerCurls[SteamVR_Skeleton_FingerIndexes.ring] * _ringCurlAmount;
float curlLittle = _handSkeletonActionLeft.fingerCurls[SteamVR_Skeleton_FingerIndexes.pinky] * _littleCurlAmount;
float curlThumb = _handSkeletonActionLeft.fingerCurls[SteamVR_Skeleton_FingerIndexes.thumb] * _thumbCurlAmount;
float splayThumb = _handSkeletonActionLeft.fingerSplays[SteamVR_Skeleton_FingerIndexes.thumb] * _thumbSpreadAmount;
if (!UxrGrabManager.Instance.IsHandGrabbing(Avatar, UxrHandSide.Left) && !avatarControllerStandard.IsLeftHandInsideFingerPointingVolume)
{
if (!string.IsNullOrEmpty(_openHandPoseName))
{
avatarControllerStandard.LeftHandDefaultPoseNameOverride = _openHandPoseName;
avatarControllerStandard.LeftHandGrabPoseNameOverride = _openHandPoseName;
Avatar.SetCurrentHandPoseImmediately(UxrHandSide.Left, _openHandPoseName);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Left, Avatar.LeftHand.Index, curlIndex, curlIndex, curlIndex);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Left, Avatar.LeftHand.Middle, curlMiddle, curlMiddle, curlMiddle);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Left, Avatar.LeftHand.Ring, curlRing, curlRing, curlRing);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Left, Avatar.LeftHand.Little, curlLittle, curlLittle, curlLittle);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Left, Avatar.LeftHand.Thumb, curlThumb * 0.1f, curlThumb * 0.3f, curlThumb * 1.0f, splayThumb);
}
}
else
{
if (!string.IsNullOrEmpty(_openHandPoseName))
{
avatarControllerStandard.LeftHandDefaultPoseNameOverride = null;
}
}
curlIndex = _handSkeletonActionRight.fingerCurls[SteamVR_Skeleton_FingerIndexes.index] * _indexCurlAmount;
curlMiddle = _handSkeletonActionRight.fingerCurls[SteamVR_Skeleton_FingerIndexes.middle] * _middleCurlAmount;
curlRing = _handSkeletonActionRight.fingerCurls[SteamVR_Skeleton_FingerIndexes.ring] * _ringCurlAmount;
curlLittle = _handSkeletonActionRight.fingerCurls[SteamVR_Skeleton_FingerIndexes.pinky] * _littleCurlAmount;
curlThumb = _handSkeletonActionRight.fingerCurls[SteamVR_Skeleton_FingerIndexes.thumb] * _thumbCurlAmount;
splayThumb = _handSkeletonActionRight.fingerSplays[SteamVR_Skeleton_FingerIndexes.thumb] * _thumbSpreadAmount;
if (!UxrGrabManager.Instance.IsHandGrabbing(Avatar, UxrHandSide.Right) && !avatarControllerStandard.IsRightHandInsideFingerPointingVolume)
{
if (!string.IsNullOrEmpty(_openHandPoseName))
{
avatarControllerStandard.RightHandDefaultPoseNameOverride = _openHandPoseName;
avatarControllerStandard.RightHandGrabPoseNameOverride = _openHandPoseName;
Avatar.SetCurrentHandPoseImmediately(UxrHandSide.Right, _openHandPoseName);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Right, Avatar.RightHand.Index, curlIndex, curlIndex, curlIndex);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Right, Avatar.RightHand.Middle, curlMiddle, curlMiddle, curlMiddle);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Right, Avatar.RightHand.Ring, curlRing, curlRing, curlRing);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Right, Avatar.RightHand.Little, curlLittle, curlLittle, curlLittle);
UxrAvatarRig.CurlFinger(Avatar, UxrHandSide.Right, Avatar.RightHand.Thumb, curlThumb * 0.1f, curlThumb * 0.3f, curlThumb * 1.0f, splayThumb);
}
}
else
{
if (!string.IsNullOrEmpty(_openHandPoseName))
{
avatarControllerStandard.RightHandDefaultPoseNameOverride = null;
}
}
}
#endif
}
#endregion
#region Protected Overrides UxrControllerInput
/// <summary>
/// Updates the complete input state using our common SteamVR actions. This allows to use the same interface
/// for all controllers and enables the implementation of new devices with minimal effort.
/// </summary>
protected override void UpdateInput()
{
base.UpdateInput();
// Get joystick values
Vector2 leftJoystickValue = GetInput2D(UxrHandSide.Left, UxrInput2D.Joystick);
Vector2 rightJoystickValue = GetInput2D(UxrHandSide.Right, UxrInput2D.Joystick);
Vector2 leftJoystick2Value = GetInput2D(UxrHandSide.Left, UxrInput2D.Joystick2);
Vector2 rightJoystick2Value = GetInput2D(UxrHandSide.Right, UxrInput2D.Joystick2);
#if ULTIMATEXR_USE_STEAMVR_SDK
var system = OpenVR.System;
if (system == null)
{
return;
}
// Update buttons
foreach (UxrInputButtons button in Enum.GetValues(typeof(UxrInputButtons)))
{
if (button != UxrInputButtons.None && button != UxrInputButtons.Any && button != UxrInputButtons.Everything)
{
SetButtonFlags(ButtonFlags.PressFlagsLeft, button, _actionsButtonClick[button][SteamVR_Input_Sources.LeftHand].state);
SetButtonFlags(ButtonFlags.PressFlagsRight, button, _actionsButtonClick[button][SteamVR_Input_Sources.RightHand].state);
SetButtonFlags(ButtonFlags.TouchFlagsLeft, button, _actionsButtonTouch[button][SteamVR_Input_Sources.LeftHand].state);
SetButtonFlags(ButtonFlags.TouchFlagsRight, button, _actionsButtonTouch[button][SteamVR_Input_Sources.RightHand].state);
}
}
#endif
// These ones are mainly for teleporting functionality when we don't get touch values out of joysticks:
if (leftJoystickValue != Vector2.zero && leftJoystickValue.magnitude > AnalogAsDPadThreshold)
{
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Joystick, true);
}
if (rightJoystickValue != Vector2.zero && rightJoystickValue.magnitude > AnalogAsDPadThreshold)
{
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Joystick, true);
}
// Same for joystick2 just in case
if (leftJoystick2Value != Vector2.zero && leftJoystick2Value.magnitude > AnalogAsDPadThreshold)
{
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Joystick2, true);
}
if (rightJoystick2Value != Vector2.zero && rightJoystick2Value.magnitude > AnalogAsDPadThreshold)
{
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Joystick2, true);
}
// Update joystick/DPad direction buttons using joystick analog value and pressed state
uint leftDirectionFlags = GetButtonFlags(MainJoystickIsTouchpad ? ButtonFlags.PressFlagsLeft : ButtonFlags.TouchFlagsLeft);
if (leftJoystickValue != Vector2.zero && leftJoystickValue.magnitude > AnalogAsDPadThreshold && (leftDirectionFlags & (int)UxrInputButtons.Joystick) != 0)
{
float leftJoystickAngle = Input2DToAngle(leftJoystickValue);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadLeft, IsInput2dDPadLeft(leftJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadRight, IsInput2dDPadRight(leftJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadUp, IsInput2dDPadUp(leftJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadDown, IsInput2dDPadDown(leftJoystickAngle));
}
else
{
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadLeft, false);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadRight, false);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadUp, false);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadDown, false);
}
uint leftButtonPressFlags = GetButtonFlags(ButtonFlags.PressFlagsLeft);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickLeft, (leftButtonPressFlags & (uint)UxrInputButtons.DPadLeft) != 0);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickRight, (leftButtonPressFlags & (uint)UxrInputButtons.DPadRight) != 0);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickUp, (leftButtonPressFlags & (uint)UxrInputButtons.DPadUp) != 0);
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickDown, (leftButtonPressFlags & (uint)UxrInputButtons.DPadDown) != 0);
uint rightDirectionFlags = GetButtonFlags(MainJoystickIsTouchpad ? ButtonFlags.PressFlagsRight : ButtonFlags.TouchFlagsRight);
if (rightJoystickValue != Vector2.zero && rightJoystickValue.magnitude > AnalogAsDPadThreshold && (rightDirectionFlags & (int)UxrInputButtons.Joystick) != 0)
{
float rightJoystickAngle = Input2DToAngle(rightJoystickValue);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadLeft, IsInput2dDPadLeft(rightJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadRight, IsInput2dDPadRight(rightJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadUp, IsInput2dDPadUp(rightJoystickAngle));
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadDown, IsInput2dDPadDown(rightJoystickAngle));
}
else
{
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadLeft, false);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadRight, false);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadUp, false);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadDown, false);
}
uint rightButtonPressFlags = GetButtonFlags(ButtonFlags.PressFlagsRight);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickLeft, (rightButtonPressFlags & (uint)UxrInputButtons.DPadLeft) != 0);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickRight, (rightButtonPressFlags & (uint)UxrInputButtons.DPadRight) != 0);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickUp, (rightButtonPressFlags & (uint)UxrInputButtons.DPadUp) != 0);
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickDown, (rightButtonPressFlags & (uint)UxrInputButtons.DPadDown) != 0);
}
#endregion
#region Private Types & Data
private string InputClassName => GetType().Name;
// Global data
private static readonly Dictionary<string, List<int>> s_controllerList = new Dictionary<string, List<int>>();
private static bool s_initializedSteamVR;
// Local data
private bool _awakeFinished;
#endregion
#if ULTIMATEXR_USE_STEAMVR_SDK
/// <summary>
/// Given a controller name, gets a list of controller names using the Virtual Desktop controller naming convention.
/// </summary>
/// <param name="controllerName">Controller name to get the virtual desktop controller names for</param>
/// <returns>List of virtual desktop controller names</returns>
private static IEnumerable<string> GetVirtualDesktopWrappedControllerNames(string controllerName)
{
yield return $"OpenVR Controller({controllerName}) - Left";
yield return $"OpenVR Controller({controllerName}) - Right";
}
/// <summary>
/// Called when a SteamVR device is connected
/// </summary>
/// <param name="index">Device index</param>
/// <param name="connected">True if connected, false if disconnected</param>
private static void OnDeviceConnected(int index, bool connected)
{
if (OpenVR.System == null)
{
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Errors)
{
Debug.LogError($"{UxrConstants.DevicesModule} {nameof(UxrSteamVRControllerInput)}::{nameof(OnDeviceConnected)}: OpenVR.System is null");
}
return;
}
if (OpenVR.System.GetTrackedDeviceClass((uint)index) != ETrackedDeviceClass.Controller)
{
// Ignore devices that aren't controllers
return;
}
var renderModelName = new StringBuilder(ModelNameMaxLength);
var error = ETrackedPropertyError.TrackedProp_Success;
OpenVR.System.GetStringTrackedDeviceProperty((uint)index, ETrackedDeviceProperty.Prop_ModelNumber_String, renderModelName, ModelNameMaxLength, ref error);
string modelNameString = renderModelName.ToString();
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Relevant)
{
Debug.Log($"{UxrConstants.DevicesModule} {nameof(UxrSteamVRControllerInput)}::{nameof(OnDeviceConnected)}: connected={connected}, model={modelNameString}");
}
IEnumerable<UxrSteamVRControllerInput> inputsSteamVR = AllComponents.Where(i => i is UxrSteamVRControllerInput).Cast<UxrSteamVRControllerInput>();
UxrSteamVRControllerInput inputSteamVR = inputsSteamVR.FirstOrDefault(i =>
i.ControllerNames.Any(n => string.Equals(n, modelNameString)) || i.ControllerNames.SelectMany(GetVirtualDesktopWrappedControllerNames).Any(n => string.Equals(n, modelNameString)));
if (inputSteamVR != null)
{
// Model is one of the registered SteamVR inputs and needs to be processed
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Relevant)
{
Debug.Log($"{UxrConstants.DevicesModule} {nameof(UxrSteamVRControllerInput)}::{nameof(OnDeviceConnected)}: Device name {modelNameString} was registered by {inputSteamVR.InputClassName} and is being processed!");
}
if (!s_controllerList.TryGetValue(inputSteamVR.InputClassName, out List<int> controllerIndices))
{
controllerIndices = new List<int>();
s_controllerList.Add(inputSteamVR.InputClassName, controllerIndices);
}
if (connected)
{
// Connected
controllerIndices.Add(index);
if (inputSteamVR.enabled == false)
{
// First controller: Notify device is connected since we consider the device the whole setup
inputSteamVR.enabled = true;
inputSteamVR.OnDeviceConnected(new UxrDeviceConnectEventArgs(true));
}
}
else
{
// Disconnected
controllerIndices.Remove(index);
if (controllerIndices.Count == 0)
{
// Last controller disconnected: Notify device is disconnected.
inputSteamVR.enabled = false;
inputSteamVR.OnDeviceConnected(new UxrDeviceConnectEventArgs(false));
}
}
}
else
{
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Relevant)
{
Debug.Log($"{UxrConstants.DevicesModule} {nameof(UxrSteamVRControllerInput)}::{nameof(OnDeviceConnected)}: Device is not recognized as input by any of {inputsSteamVR.Count()} components");
}
}
}
/// <summary>
/// Gets the action bound to the given button and input type.
/// </summary>
/// <param name="button">Button to look for</param>
/// <param name="inputType">Type of input to handle. Use <see cref="UxrSteamVRConstants" />.</param>
/// <returns>
/// Action bound to the given button and input type. If the button doesn't exist
/// in the current controller it will return a fake action showing no input
/// </returns>
private static SteamVR_Action_Boolean GetButtonAction(UxrInputButtons button, string inputType)
{
return SteamVR_Input.GetAction<SteamVR_Action_Boolean>(UxrSteamVRConstants.ActionSetName, $"{button.ToString().ToLower()}_{inputType}_{UxrSteamVRConstants.BindingVarBool}");
}
/// <summary>
/// Gets the action bound to the given <see cref="UxrInput1D" />.
/// </summary>
/// <param name="input1D">Element to look for</param>
/// <returns>
/// Action bound to the given 1D input. If the element doesn't exist in the current controller it will return a
/// fake action showing no input
/// </returns>
private static SteamVR_Action_Single GetInput1DAction(UxrInput1D input1D)
{
return SteamVR_Input.GetAction<SteamVR_Action_Single>(UxrSteamVRConstants.ActionSetName, $"{input1D.ToString().ToLower()}_{UxrSteamVRConstants.BindingVarVector1}");
}
/// <summary>
/// Gets the action bound to the given <see cref="UxrInput2D" />.
/// </summary>
/// <param name="input2D">Element to look for</param>
/// <returns>
/// Action bound to the given 2D input. If the element doesn't exist in the current controller it will return a fake
/// action showing no input
/// </returns>
private static SteamVR_Action_Vector2 GetInput2DAction(UxrInput2D input2D)
{
return SteamVR_Input.GetAction<SteamVR_Action_Vector2>(UxrSteamVRConstants.ActionSetName, $"{input2D.ToString().ToLower()}_{UxrSteamVRConstants.BindingVarVector2}");
}
/// <summary>
/// Builds all action objects needed to check for input using SteamVR.
/// We use enumeration of all elements inside an Enum to build our action list and,
/// thanks to the functionality of SteamVR, when an action doesn't exist it will
/// generate a fake action showing no input.
/// </summary>
private void BuildActionObjects()
{
// Buttons
foreach (UxrInputButtons button in Enum.GetValues(typeof(UxrInputButtons)))
{
if (button != UxrInputButtons.None && button != UxrInputButtons.Any && button != UxrInputButtons.Everything)
{
_actionsButtonClick.Add(button, GetButtonAction(button, UxrSteamVRConstants.BindingInputClick));
_actionsButtonTouch.Add(button, GetButtonAction(button, UxrSteamVRConstants.BindingInputTouch));
}
}
// UxrInput1D
foreach (UxrInput1D input1D in Enum.GetValues(typeof(UxrInput1D)))
{
if (input1D != UxrInput1D.None)
{
_actionsInput1D.Add(input1D, GetInput1DAction(input1D));
}
}
// UxrInput2D
foreach (UxrInput2D input2D in Enum.GetValues(typeof(UxrInput2D)))
{
if (input2D != UxrInput2D.None)
{
_actionsInput2D.Add(input2D, GetInput2DAction(input2D));
}
}
}
#endif
#if ULTIMATEXR_USE_STEAMVR_SDK
private const int ModelNameMaxLength = 256;
private readonly Dictionary<UxrInputButtons, SteamVR_Action_Boolean> _actionsButtonClick = new Dictionary<UxrInputButtons, SteamVR_Action_Boolean>();
private readonly Dictionary<UxrInputButtons, SteamVR_Action_Boolean> _actionsButtonTouch = new Dictionary<UxrInputButtons, SteamVR_Action_Boolean>();
private readonly Dictionary<UxrInput1D, SteamVR_Action_Single> _actionsInput1D = new Dictionary<UxrInput1D, SteamVR_Action_Single>();
private readonly Dictionary<UxrInput2D, SteamVR_Action_Vector2> _actionsInput2D = new Dictionary<UxrInput2D, SteamVR_Action_Vector2>();
private readonly SteamVR_Action_Skeleton _handSkeletonActionLeft = SteamVR_Input.GetAction<SteamVR_Action_Skeleton>(UxrSteamVRConstants.ActionSetName, UxrSteamVRConstants.ActionNameHandSkeletonLeft);
private readonly SteamVR_Action_Skeleton _handSkeletonActionRight = SteamVR_Input.GetAction<SteamVR_Action_Skeleton>(UxrSteamVRConstants.ActionSetName, UxrSteamVRConstants.ActionNameHandSkeletonRight);
private readonly SteamVR_Action_Vibration _handHapticsAction = SteamVR_Input.GetAction<SteamVR_Action_Vibration>(UxrSteamVRConstants.ActionSetName, UxrSteamVRConstants.ActionNameHandHaptics);
#endif
}
}
#pragma warning restore 414 // Restore warnings due to unused values