rabidus-test/Assets/BNG Framework/Scripts/Core/InputBridge.cs

1598 lines
67 KiB
C#
Raw Normal View History

2023-07-24 16:38:13 +03:00
#define VRIF
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
2023-09-04 12:48:24 +03:00
using UnityEngine.Events;
2023-07-24 16:38:13 +03:00
#if UNITY_2018_4_OR_NEWER
using UnityEngine.XR;
#endif
#if STEAM_VR_SDK
using Valve.VR;
#endif
namespace BNG {
#region Enums
public enum ControllerHand {
Left,
Right,
None
}
/// <summary>
/// Controller Options available to bind buttons to via Inspector. You can use GetControllerBindingValue() to determine if that button has been pressed.
/// </summary>
public enum ControllerBinding {
None,
AButton,
AButtonDown,
BButton,
BButtonDown,
XButton,
XButtonDown,
YButton,
YButtonDown,
LeftTrigger,
LeftTriggerDown,
LeftGrip,
LeftGripDown,
LeftThumbstick,
LeftThumbstickDown,
RightTrigger,
RightTriggerDown,
RightGrip,
RightGripDown,
RightThumbstick,
RightThumbstickDown,
StartButton,
StartButtonDown,
BackButton,
BackButtonDown
}
/// <summary>
/// Controller Options available to bind buttons to via Inspector. Input is relative to the controller holding it.
/// Ex : Button 1 = Button A if held in Right controller, Button X if held in Left.
/// </summary>
public enum GrabbedControllerBinding {
None,
Button1, // Button A, X
Button1Down,
Button2, // Button B, Y
Button2Down,
Trigger,
TriggerDown,
Grip,
GripDown
}
public enum InputAxis {
None,
LeftThumbStickAxis,
LeftTouchPadAxis,
RightThumbStickAxis,
RightTouchPadAxis
}
public enum ControllerType {
None,
Unknown,
OculusTouch,
Wand,
Knuckles
}
public enum HandControl {
LeftGrip,
RightGrip,
LeftTrigger,
RightTrigger,
None
}
public enum GrabButton {
Grip,
Trigger,
Inherit
}
public enum HoldType {
HoldDown, // Hold down the grab button
Toggle, // Click the grab button down to switch between hold and release
Inherit // Inherit from Grabber
}
public enum XRInputSource {
XRInput,
OVRInput,
SteamVR,
Pico,
UnityInput
}
public enum SDKProvider {
Unknown,
OculusSDK,
OpenVR
}
#endregion
/// <summary>
/// A proxy for handling input from various input providers such as OVRInput, XRInput, and SteamVR.
/// </summary>
public class InputBridge : MonoBehaviour {
#region Singleton
/// <summary>
/// Instance of our Singleton
/// </summary>
public static InputBridge Instance {
get {
if (_instance == null) {
_instance = FindObjectOfType<InputBridge>();
if (_instance == null) {
_instance = new GameObject("InputBridge").AddComponent<InputBridge>();
}
}
return _instance;
}
}
private static InputBridge _instance;
#endregion
#region Input Properties
[Header("Input Settings")]
[SerializeField]
public XRInputSource InputSource = XRInputSource.XRInput;
[SerializeField]
[Tooltip("Specify an InputActionSet for when using the Unity Input system. These actions will be enabled on load.")]
public UnityEngine.InputSystem.InputActionAsset actionSet;
[Header("Tracking Origin")]
[SerializeField]
[Tooltip("Set the TrackingOriginModeFlags on device connect. Should typically be set to 'Floor'")]
public TrackingOriginModeFlags TrackingOrigin = TrackingOriginModeFlags.Floor;
[Header("Thumbstick Deadzone")]
/// <summary>
/// Thumbstick X must be greater than this amount to be considered valid
/// </summary>
[Tooltip("Thumbstick X must be greater than this amount to be considered valid")]
public float ThumbstickDeadzoneX = 0.001f;
/// <summary>
/// Thumbstick Y must be greater than this amount to be considered valid
/// </summary>
[Tooltip("Thumbstick Y must be greater than this amount to be considered valid")]
public float ThumbstickDeadzoneY = 0.001f;
#endregion
#region Raw Inputs
[Header("Grip")]
/// <summary>
/// How far Left Grip is Held down. Values : 0 - 1 (Fully Open / Closed)
/// </summary>
public float LeftGrip = 0;
/// <summary>
/// Left Grip was pressed down this frame, but not last
/// </summary>
public bool LeftGripDown = false;
/// <summary>
/// How far Right Grip is Held down. Values : 0 - 1 (Fully Open / Closed)
/// </summary>
public float RightGrip = 0;
/// <summary>
/// Right Grip was pressed down this frame, but not last
/// </summary>
public bool RightGripDown = false;
[Header("Trigger")]
/// <summary>
/// How far Left Trigger is Held down. Values : 0 - 1 (Fully Open / Closed)
/// </summary>
public float LeftTrigger = 0;
public bool LeftTriggerNear = false;
public bool LeftTriggerUp = false;
/// <summary>
/// Returns true if Left Trigger was held down this frame but not the last
/// </summary>
public bool LeftTriggerDown = false;
/// <summary>
/// How far Left Trigger is Held down. Values : 0 - 1 (Fully Open / Closed)
/// </summary>
public float RightTrigger = 0;
/// <summary>
/// Returns true if Right Trigger is all the way up this frame but not last
/// </summary>
public bool RightTriggerUp = false;
/// <summary>
/// Returns true if Right Trigger was held down this frame but not the last
/// </summary>
public bool RightTriggerDown = false;
public bool RightTriggerNear = false;
public bool LeftThumbNear = false;
public bool RightThumbNear = false;
[Header("Thumbstick")]
/// <summary>
/// Pressed down this frame, but not last
/// </summary>
public bool LeftThumbstickDown = false;
/// <summary>
/// Released this frame but not last
/// </summary>
public bool LeftThumbstickUp = false;
/// <summary>
/// Pressed down this frame, but not last
/// </summary>
public bool RightThumbstickDown = false;
/// <summary>
/// Released this frame but not last
/// </summary>
public bool RightThumbstickUp = false;
/// <summary>
/// Currently Held Down
/// </summary>
public bool LeftThumbstick = false;
public bool RightThumbstick = false;
[Header("Buttons")]
/// <summary>
/// Is the A button currently being held down
/// </summary>
public bool AButton = false;
/// <summary>
/// Returns true if the A Button was pressed down this frame but not last
/// </summary>
[Tooltip("Returns true if the A Button was pressed down this frame but not last")]
public bool AButtonDown = false;
// A Button Up this frame but down the last
public bool AButtonUp = false;
/// <summary>
/// Is the B button currently being held down
/// </summary>
public bool BButton = false;
/// <summary>
/// Returns true if the B Button was pressed down this frame but not last
/// </summary>
[Tooltip("Returns true if the B Button was pressed down this frame but not last")]
public bool BButtonDown = false;
// B Button Up this frame but down the last
public bool BButtonUp = false;
public bool XButton = false;
/// <summary>
/// Returns true if the X Button was pressed down this frame but not last
/// </summary>
[Tooltip("Returns true if the X Button was pressed down this frame but not last")]
public bool XButtonDown = false;
// X Button Up this frame but down the last
public bool XButtonUp = false;
public bool YButton = false;
/// <summary>
/// Returns true if the Y Button was pressed down this frame but not last
/// </summary>
public bool YButtonDown = false;
public bool YButtonUp = false;
public bool StartButton = false;
public bool StartButtonDown = false;
public bool BackButton = false;
public bool BackButtonDown = false;
[Header("Axis")]
public Vector2 LeftThumbstickAxis;
public Vector2 RightThumbstickAxis;
public Vector2 LeftTouchPadAxis;
public Vector2 RightTouchPadAxis;
[Header("Finger Tracking")]
[Tooltip("SteamVR Only - Shows the curl value of the thumb. 0 = Fully extended, 1 = Fully Curled")]
public float LeftThumbCurl = 0f;
public float LeftIndexCurl = 0f;
public float LeftMiddleCurl = 0f;
public float LeftRingCurl = 0f;
public float LeftPinkyCurl = 0f;
[Tooltip("SteamVR Only - Shows the curl value of the thumb. 0 = Fully extended, 1 = Fully Curled")]
public float RightThumbCurl = 0f;
public float RightIndexCurl = 0f;
public float RightMiddleCurl = 0f;
public float RightRingCurl = 0f;
public float RightPinkyCurl = 0f;
#endregion
#region Device Properties
/// <summary>
/// What threshold constitutes a "down" event.
/// For example, pushing the trigger down 20% (0.2) of the way considered starting a trigger down event
/// This is used in XRInput
/// </summary>
public float DownThreshold {
get {
return _downThreshold;
}
}
private float _downThreshold = 0.2f;
bool SteamVRSupport = false;
[Header("HMD / Hardware")]
public ControllerType ConnectedControllerType;
[Tooltip("Is there an HMD present and in use.")]
2023-09-04 12:48:24 +03:00
public bool HMDActive
{
get => _hmdActive;
set
{
_hmdActive = value;
if (_hmdActive)
{
OnConnected?.Invoke();
}
else
{
OnDisconnected?.Invoke();
}
}
}
private bool _hmdActive = false;
public UnityEvent OnConnected;
public UnityEvent OnDisconnected;
2023-07-24 16:38:13 +03:00
public SDKProvider LoadedSDK { get; private set; }
public bool IsOculusDevice { get; private set; }
public bool IsOculusQuest { get; private set; }
public bool IsHTCDevice { get; private set; }
public bool IsPicoDevice { get; private set; }
public bool IsValveIndexController { get; private set; }
/// <summary>
/// Returns true if the controller has both a Touchpad and a Joystick. Currently only the Valve Index has both.
/// </summary>
[Tooltip("Returns true if the controller has both a Touchpad and a Joystick. Currently on the Valve Index has both.")]
public bool SupportsBothTouchPadAndJoystick;
/// <summary>
/// Returns true if the controllers support the 'indexTouch' (or 'near trigger') XR input mapping. Currently only Oculus devices on the Oculus SDK support index touch. OpenVR is not supported.
/// </summary>
[Tooltip("Returns true if the controllers support the 'indexTouch' XR input mapping. Currently only Oculus devices on the Oculus SDK support thumb touch. OpenVR is not supported.")]
public bool SupportsIndexTouch;
/// <summary>
/// Returns true if the controllers support the 'ThumbTouch' (or near thumbstick) XR input mapping. Currently only Oculus devices on the Oculus SDK support index touch. OpenVR is not supported.
/// </summary>
[Tooltip("Returns true if the controllers support the 'ThumbTouch' (or near thumbstick) XR input mapping. Currently only Oculus devices on the Oculus SDK support thumb touch. OpenVR is not supported.")]
public bool SupportsThumbTouch;
#if UNITY_2019_3_OR_NEWER
static List<InputDevice> devices = new List<InputDevice>();
#endif
#endregion
#region Events
// Events
/// <summary>
/// Called after update loop.
/// </summary>
public delegate void InputsUpdatedAction();
public static event InputsUpdatedAction OnInputsUpdated;
/// <summary>
/// Called once a controller has been successfully detected
/// </summary>
public delegate void ControllerFoundAction();
public static event ControllerFoundAction OnControllerFound;
#endregion
#region Unity Input Actions
UnityEngine.InputSystem.InputAction leftGrip;
UnityEngine.InputSystem.InputAction leftTrigger;
UnityEngine.InputSystem.InputAction leftTriggerNear;
UnityEngine.InputSystem.InputAction rightGrip;
UnityEngine.InputSystem.InputAction rightTrigger;
UnityEngine.InputSystem.InputAction rightTriggerNear;
UnityEngine.InputSystem.InputAction leftThumbstick;
UnityEngine.InputSystem.InputAction leftThumbstickDown;
UnityEngine.InputSystem.InputAction leftThumbNear;
UnityEngine.InputSystem.InputAction leftTouchpad;
UnityEngine.InputSystem.InputAction leftTouchpadDown;
UnityEngine.InputSystem.InputAction rightThumbstick;
UnityEngine.InputSystem.InputAction rightThumbstickDown;
UnityEngine.InputSystem.InputAction rightThumbNear;
UnityEngine.InputSystem.InputAction rightTouchpad;
UnityEngine.InputSystem.InputAction rightTouchpadDown;
UnityEngine.InputSystem.InputAction aButton;
UnityEngine.InputSystem.InputAction bButton;
UnityEngine.InputSystem.InputAction xButton;
UnityEngine.InputSystem.InputAction yButton;
UnityEngine.InputSystem.InputAction startButton;
UnityEngine.InputSystem.InputAction backButton;
#endregion
#region Input Debugging
// Used for showing a custom inspector
[HideInInspector]
public bool ShowInputDebugger = false;
#endregion
private void Awake() {
// Destroy any duplicate instances that may have been created
if (_instance != null && _instance != this) {
Destroy(this);
return;
}
_instance = this;
// Update all device properties
List<InputDevice> devices = new List<InputDevice>();
InputDevices.GetDevices(devices);
setDeviceProperties();
}
void Start() {
SetTrackingOriginMode(TrackingOrigin);
#if STEAM_VR_SDK
SteamVRSupport = true;
// Warn that input source has not been set, even though the SteamVR SDK is present.
if(InputSource != XRInputSource.SteamVR) {
Debug.Log("SteamVR SDK detected, but not set as source on InputBridge. Recommend switching input Source from " + InputSource.ToString() + " to SteamVR.");
}
// Set the default action set if not provided
SteamVR_ActivateActionSetOnLoad VRIFLoader = FindObjectOfType<SteamVR_ActivateActionSetOnLoad>();
if (VRIFLoader == null) {
Debug.Log("SteamVR_ActivateActionSetOnLoad component not found - adding VRIF custom actions default.");
VRIFLoader = gameObject.AddComponent<SteamVR_ActivateActionSetOnLoad>();
VRIFLoader.actionSet = SteamVR_Actions.VRIF;
}
SteamVR.Initialize();
#endif
}
void OnEnable() {
#if UNITY_2019_3_OR_NEWER
InputDevices.deviceConfigChanged += onDeviceChanged;
InputDevices.deviceConnected += onDeviceChanged;
InputDevices.deviceDisconnected += onDeviceChanged;
#endif
CreateUnityInputActions();
EnableActions();
}
void OnDisable() {
#if UNITY_2019_3_OR_NEWER
InputDevices.deviceConfigChanged -= onDeviceChanged;
InputDevices.deviceConnected -= onDeviceChanged;
InputDevices.deviceDisconnected -= onDeviceChanged;
#endif
DisableActions();
}
void Update() {
UpdateDeviceActive();
UpdateInputs();
}
public virtual void UpdateInputs() {
// SteamVR uses an action system. Only update if HMD is reported as Active
if (InputSource == XRInputSource.SteamVR && SteamVRSupport && HMDActive) {
UpdateSteamInput();
}
// Use OVRInput to get more Oculus Specific inputs, such as "Near Touch"
else if (InputSource == XRInputSource.OVRInput) {
UpdateOVRInput();
}
// Use XRInput
else if(InputSource == XRInputSource.XRInput) {
UpdateXRInput();
}
// New Unity Input System
else if(InputSource == XRInputSource.UnityInput) {
UpdateUnityInput();
}
// Pico
else if(InputSource == XRInputSource.Pico) {
UpdatePicoInput();
}
// Call events
OnInputsUpdated?.Invoke();
}
#region SteamVR Action Input
public virtual void UpdateSteamInput() {
#if STEAM_VR_SDK
LeftThumbstickAxis = ApplyDeadZones(SteamVR_Actions.vRIF_LeftThumbstickAxis.axis, ThumbstickDeadzoneX, ThumbstickDeadzoneY);
RightThumbstickAxis = ApplyDeadZones(SteamVR_Actions.vRIF_RightThumbstickAxis.axis, ThumbstickDeadzoneX, ThumbstickDeadzoneY);
var prevBool = LeftThumbstick;
LeftThumbstick = SteamVR_Actions.vRIF_LeftThumbstickDown.state;
// LeftThumbstickDown = SteamVR_Actions.vRIF_LeftThumbstickDown.stateDown;
LeftThumbstickDown = prevBool == false && LeftThumbstick == true;
LeftThumbstickUp = prevBool == true && LeftThumbstick == false;
prevBool = RightThumbstick;
RightThumbstick = SteamVR_Actions.vRIF_RightThumbstickDown.state;
// RightThumbstickDown = SteamVR_Actions.vRIF_RightThumbstickDown.stateDown;
RightThumbstickDown = prevBool == false && RightThumbstick == true;
RightThumbstickUp = prevBool == true && RightThumbstick == false;
LeftThumbNear = SteamVR_Actions.vRIF_LeftThumbstickNear.state;
//LeftThumbNear = SteamVR_Actions.vRIF_LeftTrackpadNear.state;
RightThumbNear = SteamVR_Actions.vRIF_RightThumbstickNear.state;
//RightThumbNear = SteamVR_Actions.vRIF_RightTrackpadNear.state;
var prevVal = LeftGrip;
LeftGrip = LeftGrip = correctValue(SteamVR_Actions.vRIF_LeftGrip.axis);
LeftGripDown = prevVal < _downThreshold && LeftGrip >= _downThreshold;
prevVal = RightGrip;
RightGrip = correctValue(SteamVR_Actions.vRIF_RightGrip.axis);
RightGripDown = prevVal < _downThreshold && RightGrip >= _downThreshold;
prevVal = LeftTrigger;
LeftTrigger = correctValue(SteamVR_Actions.vRIF_LeftTrigger.axis);
LeftTriggerDown = prevVal < _downThreshold && LeftTrigger >= _downThreshold;
LeftTriggerUp = prevVal > _downThreshold && LeftTrigger < _downThreshold;
LeftTriggerNear = SteamVR_Actions.vRIF_LeftTriggerNear.state;
prevVal = RightTrigger;
RightTrigger = correctValue(SteamVR_Actions.vRIF_RightTrigger.axis);
RightTriggerDown = prevVal < _downThreshold && RightTrigger >= _downThreshold;
RightTriggerUp = prevVal > _downThreshold && RightTrigger < _downThreshold;
RightTriggerNear = SteamVR_Actions.vRIF_RightTriggerNear.state;
AButton = SteamVR_Actions.vRIF_AButton.state;
AButtonDown = SteamVR_Actions.vRIF_AButton.stateDown;
AButtonUp = SteamVR_Actions.vRIF_AButton.stateUp;
BButton = SteamVR_Actions.vRIF_BButton.state;
BButtonDown = SteamVR_Actions.vRIF_BButton.stateDown;
BButtonUp = SteamVR_Actions.vRIF_AButton.stateUp;
XButton = SteamVR_Actions.vRIF_XButton.state;
XButtonDown = SteamVR_Actions.vRIF_XButton.stateDown;
XButtonUp = SteamVR_Actions.vRIF_XButton.stateUp;
YButton = SteamVR_Actions.vRIF_YButton.state;
YButtonDown = SteamVR_Actions.vRIF_YButton.stateDown;
YButtonUp = SteamVR_Actions.vRIF_YButton.stateUp;
// Hand Tracking (Ie Valve Knuckles Finger Tracking)
LeftThumbCurl = SteamVR_Actions.vRIF_SkeletonLeftHand.thumbCurl;
LeftIndexCurl = SteamVR_Actions.vRIF_SkeletonLeftHand.indexCurl;
LeftMiddleCurl = SteamVR_Actions.vRIF_SkeletonLeftHand.middleCurl;
LeftRingCurl = SteamVR_Actions.vRIF_SkeletonLeftHand.ringCurl;
LeftPinkyCurl = SteamVR_Actions.vRIF_SkeletonLeftHand.pinkyCurl;
RightThumbCurl = SteamVR_Actions.vRIF_SkeletonRightHand.thumbCurl;
RightIndexCurl = SteamVR_Actions.vRIF_SkeletonRightHand.indexCurl;
RightMiddleCurl = SteamVR_Actions.vRIF_SkeletonRightHand.middleCurl;
RightRingCurl = SteamVR_Actions.vRIF_SkeletonRightHand.ringCurl;
RightPinkyCurl = SteamVR_Actions.vRIF_SkeletonRightHand.pinkyCurl;
//prevBool = StartButton;
//StartButton = SteamVR_Actions.vRIF_StartButton.state;
//StartButtonDown = prevBool == false && StartButton == true;
//prevBool = BackButton;
//BackButton = SteamVR_Actions.vRIF_BackButton.state;
//BackButtonDown = prevBool == false && BackButton == true;
#endif
}
#endregion
#region XR Input
#if UNITY_2019_3_OR_NEWER
#region XRInputVariables
InputDevice primaryLeftController;
InputDevice primaryRightController;
InputFeatureUsage<Vector2> thumbstickAxis;
InputFeatureUsage<Vector2> thumbstickAxisSecondary;
InputFeatureUsage<bool> thumbstickAxisClick;
#endregion
#endif
public virtual void UpdateXRInput() {
#if UNITY_2019_3_OR_NEWER
// Refresh XR devices
InputDevices.GetDevices(devices);
// Left XR Controller
primaryLeftController = GetLeftController();
// Right XR Controller
primaryRightController = GetRightController();
// For most cases thumbstick is on the primary2DAxis
// However, if the Controller has both a touchpad and a controller on it (i.e. Valve Index Knuckles) then the thumbstick axis is actually on the secondary axis, not the primary axis
thumbstickAxis = SupportsBothTouchPadAndJoystick ? CommonUsages.secondary2DAxis : CommonUsages.primary2DAxis;
thumbstickAxisSecondary = SupportsBothTouchPadAndJoystick ? CommonUsages.primary2DAxis : CommonUsages.secondary2DAxis;
thumbstickAxisClick = SupportsBothTouchPadAndJoystick ? CommonUsages.secondary2DAxisClick : CommonUsages.primary2DAxisClick;
var prevBool = LeftThumbstick;
LeftThumbstick = getFeatureUsage(primaryLeftController, thumbstickAxisClick);
LeftThumbstickDown = prevBool == false && LeftThumbstick == true;
LeftThumbstickUp = prevBool == true && LeftThumbstick == false;
prevBool = RightThumbstick;
RightThumbstick = getFeatureUsage(primaryRightController, thumbstickAxisClick);
RightThumbstickDown = prevBool == false && RightThumbstick == true;
RightThumbstickUp = prevBool == true && RightThumbstick == false;
LeftTouchPadAxis = ApplyDeadZones(getFeatureUsage(primaryLeftController, thumbstickAxisSecondary), ThumbstickDeadzoneX, ThumbstickDeadzoneY);
LeftThumbstickAxis = ApplyDeadZones(getFeatureUsage(primaryLeftController, thumbstickAxis), ThumbstickDeadzoneX, ThumbstickDeadzoneY);
RightTouchPadAxis = ApplyDeadZones(getFeatureUsage(primaryRightController, thumbstickAxisSecondary), ThumbstickDeadzoneX, ThumbstickDeadzoneY);
RightThumbstickAxis = ApplyDeadZones(getFeatureUsage(primaryRightController, thumbstickAxis), ThumbstickDeadzoneX, ThumbstickDeadzoneY);
// Store copy of previous value so we can determine if we need to call OnDownEvent
var prevVal = LeftGrip;
LeftGrip = correctValue(getFeatureUsage(primaryLeftController, CommonUsages.grip));
LeftGripDown = prevVal < _downThreshold && LeftGrip >= _downThreshold;
prevVal = RightGrip;
RightGrip = correctValue(getFeatureUsage(primaryRightController, CommonUsages.grip));
RightGripDown = prevVal < _downThreshold && RightGrip >= _downThreshold;
prevVal = LeftTrigger;
LeftTrigger = correctValue(getFeatureUsage(primaryLeftController, CommonUsages.trigger));
LeftTriggerUp = prevVal > _downThreshold && LeftTrigger < _downThreshold;
LeftTriggerDown = prevVal < _downThreshold && LeftTrigger >= _downThreshold;
prevVal = RightTrigger;
RightTrigger = correctValue(getFeatureUsage(primaryRightController, CommonUsages.trigger));
RightTriggerUp = prevVal > _downThreshold && RightTrigger < _downThreshold;
RightTriggerDown = prevVal < _downThreshold && RightTrigger >= _downThreshold;
// While OculusUsages.indexTouch is recommended, only CommonUsages.indexTouch is currently providing proper values on certain platforms
// OculusUsages.indexTouch is returning proper values in Oculus XR plugin >= v1.6.0
// Oculus Desktop / Android packages require CommonUsages, not OculusUsages ¯\_(ツ)_/¯
#pragma warning disable 0618
LeftTriggerNear = getFeatureUsage(primaryLeftController, CommonUsages.indexTouch) > 0;
// Check Oculus Usage if not found with CommonUsages
if (!LeftTriggerNear) {
#if OCULUS_XR_PLUGIN
LeftTriggerNear = getFeatureUsage(primaryLeftController, Unity.XR.Oculus.OculusUsages.indexTouch);
#endif
}
// Fallback to checking UnityInput if available
if (!LeftTriggerNear && leftTriggerNear != null && correctValue(leftTriggerNear.ReadValue<float>()) > 0) {
LeftTriggerNear = true;
};
LeftThumbNear = getFeatureUsage(primaryLeftController, CommonUsages.thumbTouch) > 0 ||
getFeatureUsage(primaryLeftController, CommonUsages.primaryTouch) ||
getFeatureUsage(primaryLeftController, CommonUsages.secondaryTouch) ||
getFeatureUsage(primaryLeftController, CommonUsages.primary2DAxisTouch);
if (!LeftThumbNear) {
#if OCULUS_XR_PLUGIN
LeftThumbNear = getFeatureUsage(primaryLeftController, Unity.XR.Oculus.OculusUsages.thumbTouch);
#endif
}
RightTriggerNear = getFeatureUsage(primaryRightController, CommonUsages.indexTouch) > 0;
// Try Oculus Usages if not found with Common
if (!RightTriggerNear) {
#if OCULUS_XR_PLUGIN
RightTriggerNear = getFeatureUsage(primaryRightController, Unity.XR.Oculus.OculusUsages.indexTouch);
#endif
}
// Fallback to checking UnityInput for trigger near if available
if (!RightTriggerNear && rightTriggerNear != null && correctValue(rightTriggerNear.ReadValue<float>()) > 0) {
RightTriggerNear = true;
};
RightThumbNear = getFeatureUsage(primaryRightController, CommonUsages.thumbTouch) > 0 ||
getFeatureUsage(primaryRightController, CommonUsages.primaryTouch) ||
getFeatureUsage(primaryRightController, CommonUsages.secondaryTouch) ||
getFeatureUsage(primaryRightController, CommonUsages.primary2DAxisTouch);
if (!RightThumbNear) {
#if OCULUS_XR_PLUGIN
RightThumbNear = getFeatureUsage(primaryRightController, Unity.XR.Oculus.OculusUsages.thumbTouch);
#endif
}
#pragma warning restore 0618
prevBool = AButton;
AButton = getFeatureUsage(primaryRightController, CommonUsages.primaryButton);
AButtonDown = prevBool == false && AButton == true;
AButtonUp = prevBool == true && AButton == false;
prevBool = BButton;
BButton = getFeatureUsage(primaryRightController, CommonUsages.secondaryButton);
BButtonDown = prevBool == false && BButton == true;
BButtonUp = prevBool == true && BButton == false;
prevBool = XButton;
XButton = getFeatureUsage(primaryLeftController, CommonUsages.primaryButton);
XButtonDown = prevBool == false && XButton == true;
XButtonUp = prevBool == true && XButton == false;
prevBool = YButton;
YButton = getFeatureUsage(primaryLeftController, CommonUsages.secondaryButton);
YButtonDown = prevBool == false && YButton == true;
YButtonUp = prevBool == true && YButton == false;
prevBool = StartButton;
StartButton = getFeatureUsage(primaryRightController, CommonUsages.menuButton);
StartButtonDown = prevBool == false && StartButton == true;
prevBool = BackButton;
BackButton = getFeatureUsage(primaryLeftController, CommonUsages.menuButton);
BackButtonDown = prevBool == false && BackButton == true;
#endif
}
#endregion
#region Unity Input
public virtual void UpdateUnityInput() {
var prevVal = LeftGrip;
LeftGrip = correctValue(leftGrip.ReadValue<float>());
LeftGripDown = prevVal < _downThreshold && LeftGrip >= _downThreshold;
prevVal = LeftTrigger;
LeftTrigger = correctValue(leftTrigger.ReadValue<float>());
LeftTriggerDown = prevVal < _downThreshold && LeftTrigger >= _downThreshold;
LeftTriggerNear = correctValue(leftTriggerNear.ReadValue<float>()) > 0;
LeftTriggerUp = prevVal > _downThreshold && LeftTrigger < _downThreshold;
prevVal = RightGrip;
RightGrip = correctValue(rightGrip.ReadValue<float>());
RightGripDown = prevVal < _downThreshold && RightGrip >= _downThreshold;
prevVal = RightTrigger;
RightTrigger = correctValue(rightTrigger.ReadValue<float>());
RightTriggerDown = prevVal < _downThreshold && RightTrigger >= _downThreshold;
RightTriggerNear = correctValue(rightTriggerNear.ReadValue<float>()) > 0;
RightTriggerUp = prevVal > _downThreshold && RightTrigger < _downThreshold;
LeftThumbstickAxis = leftThumbstick.ReadValue<Vector2>();
var prevBool = LeftThumbstick;
LeftThumbstick = correctValue(leftThumbstickDown.ReadValue<float>()) > 0;
LeftThumbstickDown = prevBool == false && LeftThumbstick == true;
LeftThumbstickUp = prevBool == true && LeftThumbstick == false;
LeftThumbNear = correctValue(leftThumbNear.ReadValue<float>()) > 0;
LeftTouchPadAxis = leftTouchpad.ReadValue<Vector2>();
RightThumbstickAxis = rightThumbstick.ReadValue<Vector2>();
prevBool = RightThumbstick;
RightThumbstick = correctValue(rightThumbstickDown.ReadValue<float>()) > 0;
RightThumbstickDown = prevBool == false && RightThumbstick == true;
RightThumbstickUp = prevBool == true && RightThumbstick == false;
RightThumbNear = correctValue(rightThumbNear.ReadValue<float>()) > 0;
RightTouchPadAxis = rightTouchpad.ReadValue<Vector2>();
prevBool = AButton;
AButton = correctValue(aButton.ReadValue<float>()) > 0;
AButtonDown = prevBool == false && AButton == true;
AButtonUp = prevBool == true && AButton == false;
prevBool = BButton;
BButton = correctValue(bButton.ReadValue<float>()) > 0;
BButtonDown = prevBool == false && BButton == true;
BButtonUp = prevBool == true && BButton == false;
prevBool = XButton;
XButton = correctValue(xButton.ReadValue<float>()) > 0;
XButtonDown = prevBool == false && XButton == true;
XButtonUp = prevBool == true && XButton == false;
prevBool = YButton;
YButton = correctValue(yButton.ReadValue<float>()) > 0;
YButtonDown = prevBool == false && YButton == true;
YButtonUp = prevBool == true && YButton == false;
prevBool = StartButton;
StartButton = correctValue(startButton.ReadValue<float>()) > 0;
StartButtonDown = prevBool == false && StartButton == true;
prevBool = BackButton;
BackButton = correctValue(backButton.ReadValue<float>()) > 0;
BackButtonDown = prevBool == false && BackButton == true;
}
public virtual void CreateUnityInputActions() {
leftGrip = CreateInputAction("leftGrip", "<XRController>{LeftHand}/{grip}", true);
leftTrigger = CreateInputAction("leftTrigger", "<XRController>{LeftHand}/{trigger}", true);
leftTriggerNear = CreateInputAction("leftTriggerNear", "<XRController>{LeftHand}/triggerTouched", true);
rightGrip = CreateInputAction("rightGrip", "<XRController>{RightHand}/{grip}", true);
rightTrigger = CreateInputAction("rightTrigger", "<XRController>{RightHand}/{trigger}", true);
rightTriggerNear = CreateInputAction("rightTriggerNear", "<XRController>{RightHand}/triggerTouched", true);
leftThumbstick = CreateInputAction("leftThumbstick", "<XRController>{LeftHand}/{primary2DAxis}", true);
leftThumbstickDown = CreateInputAction("leftThumbstickDown", "<XRController>{LeftHand}/{primary2DAxisClick}", false);
leftThumbNear = CreateInputAction("leftThumbNear", "<XRController>{LeftHand}/thumbstickTouched", true);
leftTouchpad = CreateInputAction("leftTouchpad", "<XRController>{LeftHand}/{secondary2DAxis}", true);
leftTouchpadDown = CreateInputAction("leftTouchpadDown", "<XRController>{LeftHand}/{secondary2DAxisClick}", false);
rightThumbstick = CreateInputAction("rightThumbstick", "<XRController>{RightHand}/{primary2DAxis}", true);
rightThumbstickDown = CreateInputAction("rightThumbstickDown", "<XRController>{RightHand}/{primary2DAxisClick}", false);
rightThumbNear = CreateInputAction("rightThumbNear", "<XRController>{RightHand}/thumbstickTouched", true);
rightTouchpad = CreateInputAction("rightTouchpad", "<XRController>{RightHand}/{secondary2DAxis}", true);
rightTouchpadDown = CreateInputAction("rightTouchpadDown", "<XRController>{RightHand}/{secondary2DAxisClick}", false);
aButton = CreateInputAction("aButton", "<XRController>{RightHand}/{primaryButton}", false);
bButton = CreateInputAction("bButton", "<XRController>{RightHand}/{secondaryButton}", false);
xButton = CreateInputAction("xButton", "<XRController>{LeftHand}/{primaryButton}", false);
yButton = CreateInputAction("yButton", "<XRController>{LeftHand}/{secondaryButton}", false);
startButton = CreateInputAction("startButton", "<XRController>{RightHand}/{menu}", false);
backButton = CreateInputAction("backButton", "<XRController>{LeftHand}/{menu}", false);
}
public virtual void EnableActions() {
if (actionSet != null) {
foreach (var map in actionSet.actionMaps) {
foreach (var action in map) {
action.Enable();
}
}
}
}
public virtual void DisableActions() {
if (actionSet != null) {
foreach (var map in actionSet.actionMaps) {
foreach (var action in map) {
action.Disable();
}
}
}
}
public UnityEngine.InputSystem.InputAction CreateInputAction(string actionName, string binding, bool valueType) {
var act = new UnityEngine.InputSystem.InputAction(actionName,
valueType ? UnityEngine.InputSystem.InputActionType.Value : UnityEngine.InputSystem.InputActionType.Button,
binding);
// Automatically enable this binding
act.Enable();
return act;
}
#endregion
#region OVR Input
public virtual void UpdateOVRInput() {
#if OCULUS_INTEGRATION
LeftThumbstickAxis = ApplyDeadZones(OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick), ThumbstickDeadzoneX, ThumbstickDeadzoneY);
RightThumbstickAxis = ApplyDeadZones(OVRInput.Get(OVRInput.Axis2D.SecondaryThumbstick), ThumbstickDeadzoneX, ThumbstickDeadzoneY);
LeftGrip = correctValue(OVRInput.Get(OVRInput.Axis1D.PrimaryHandTrigger, OVRInput.Controller.LTouch));
LeftGripDown = OVRInput.GetDown(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.LTouch);
RightGrip = correctValue(OVRInput.Get(OVRInput.Axis1D.PrimaryHandTrigger, OVRInput.Controller.RTouch));
RightGripDown = OVRInput.GetDown(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.RTouch);
LeftTrigger = correctValue(OVRInput.Get(OVRInput.Axis1D.PrimaryIndexTrigger, OVRInput.Controller.LTouch));
LeftTriggerUp = OVRInput.GetUp(OVRInput.Button.PrimaryIndexTrigger, OVRInput.Controller.LTouch);
LeftTriggerDown = OVRInput.GetDown(OVRInput.Button.PrimaryIndexTrigger, OVRInput.Controller.LTouch);
RightTrigger = correctValue(OVRInput.Get(OVRInput.Axis1D.PrimaryIndexTrigger, OVRInput.Controller.RTouch));
RightTriggerUp = OVRInput.GetUp(OVRInput.Button.PrimaryIndexTrigger, OVRInput.Controller.RTouch);
RightTriggerDown = OVRInput.GetDown(OVRInput.Button.PrimaryIndexTrigger, OVRInput.Controller.RTouch);
LeftTriggerNear = OVRInput.Get(OVRInput.NearTouch.PrimaryIndexTrigger, OVRInput.Controller.LTouch);
LeftThumbNear = OVRInput.Get(OVRInput.NearTouch.PrimaryThumbButtons, OVRInput.Controller.LTouch);
RightTriggerNear = OVRInput.Get(OVRInput.NearTouch.PrimaryIndexTrigger, OVRInput.Controller.RTouch);
RightThumbNear = OVRInput.Get(OVRInput.NearTouch.PrimaryThumbButtons, OVRInput.Controller.RTouch);
AButton = OVRInput.Get(OVRInput.Button.One, OVRInput.Controller.RTouch);
AButtonDown = OVRInput.GetDown(OVRInput.Button.One, OVRInput.Controller.RTouch);
AButtonUp = OVRInput.GetUp(OVRInput.Button.One, OVRInput.Controller.RTouch);
BButton = OVRInput.Get(OVRInput.Button.Two);
BButtonDown = OVRInput.GetDown(OVRInput.Button.Two);
BButtonUp = OVRInput.GetUp(OVRInput.Button.Two);
XButton = OVRInput.Get(OVRInput.Button.Three);
XButtonDown = OVRInput.GetDown(OVRInput.Button.Three);
XButtonUp = OVRInput.GetUp(OVRInput.Button.Three);
YButton = OVRInput.Get(OVRInput.Button.Four);
YButtonDown = OVRInput.GetDown(OVRInput.Button.Four);
YButtonUp = OVRInput.GetUp(OVRInput.Button.Four);
StartButton = OVRInput.Get(OVRInput.Button.Start);
StartButtonDown = OVRInput.GetDown(OVRInput.Button.Start);
BackButton = OVRInput.Get(OVRInput.Button.Back);
BackButtonDown = OVRInput.GetDown(OVRInput.Button.Back);
LeftThumbstickDown = OVRInput.GetDown(OVRInput.Button.PrimaryThumbstick, OVRInput.Controller.LTouch);
LeftThumbstickUp = OVRInput.GetUp(OVRInput.Button.PrimaryThumbstick, OVRInput.Controller.LTouch);
RightThumbstickDown = OVRInput.GetDown(OVRInput.Button.PrimaryThumbstick, OVRInput.Controller.RTouch);
RightThumbstickUp = OVRInput.GetUp(OVRInput.Button.PrimaryThumbstick, OVRInput.Controller.RTouch);
LeftThumbstick = OVRInput.Get(OVRInput.Button.PrimaryThumbstick, OVRInput.Controller.LTouch);
RightThumbstick = OVRInput.Get(OVRInput.Button.PrimaryThumbstick, OVRInput.Controller.RTouch);
#endif
// Call events
OnInputsUpdated?.Invoke();
}
#endregion
#region Pico Input
public virtual void UpdatePicoInput() {
#if PICO_SDK
int rightHand = 1;
int leftHand = 0;
var prevBool = LeftThumbstick;
var prevVal = LeftGrip;
LeftThumbstickAxis = ApplyDeadZones(Pvr_UnitySDKAPI.Controller.UPvr_GetAxis2D(leftHand), ThumbstickDeadzoneX, ThumbstickDeadzoneY);
RightThumbstickAxis = ApplyDeadZones(Pvr_UnitySDKAPI.Controller.UPvr_GetAxis2D(rightHand), ThumbstickDeadzoneX, ThumbstickDeadzoneY);
prevBool = LeftThumbstick;
LeftThumbstick = Pvr_UnitySDKAPI.Controller.UPvr_GetKey(leftHand, Pvr_UnitySDKAPI.Pvr_KeyCode.TOUCHPAD);
LeftThumbstickDown = Pvr_UnitySDKAPI.Controller.UPvr_GetKeyDown(leftHand, Pvr_UnitySDKAPI.Pvr_KeyCode.TOUCHPAD);
LeftThumbstickUp = prevBool == true && LeftThumbstick == false;
prevBool = RightThumbstick;
RightThumbstick = Pvr_UnitySDKAPI.Controller.UPvr_GetKey(rightHand, Pvr_UnitySDKAPI.Pvr_KeyCode.TOUCHPAD);
RightThumbstickDown = Pvr_UnitySDKAPI.Controller.UPvr_GetKeyDown(rightHand, Pvr_UnitySDKAPI.Pvr_KeyCode.TOUCHPAD);
RightThumbstickUp = prevBool == true && RightThumbstick == false;
LeftThumbNear = Pvr_UnitySDKAPI.Controller.UPvr_IsTouching(leftHand);
RightThumbNear = Pvr_UnitySDKAPI.Controller.UPvr_IsTouching(rightHand);
prevVal = LeftGrip;
LeftGrip = Pvr_UnitySDKAPI.Controller.UPvr_GetKey(leftHand, Pvr_UnitySDKAPI.Pvr_KeyCode.Left) ? 1f : 0;
LeftGripDown = Pvr_UnitySDKAPI.Controller.UPvr_GetKeyDown(leftHand, Pvr_UnitySDKAPI.Pvr_KeyCode.Left);
prevVal = RightGrip;
RightGrip = Pvr_UnitySDKAPI.Controller.UPvr_GetKey(rightHand, Pvr_UnitySDKAPI.Pvr_KeyCode.Right) ? 1f : 0;
RightGripDown = Pvr_UnitySDKAPI.Controller.UPvr_GetKeyDown(rightHand, Pvr_UnitySDKAPI.Pvr_KeyCode.Right);
prevVal = LeftTrigger;
LeftTrigger = Pvr_UnitySDKAPI.Controller.UPvr_GetControllerTriggerValue(leftHand) / 255f;
LeftTriggerUp = prevVal > _downThreshold && LeftTrigger < _downThreshold;
LeftTriggerDown = prevVal < _downThreshold && LeftTrigger >= _downThreshold;
prevVal = RightTrigger;
RightTrigger = Pvr_UnitySDKAPI.Controller.UPvr_GetControllerTriggerValue(rightHand) / 255f;
RightTriggerUp = prevVal > _downThreshold && RightTrigger < _downThreshold;
RightTriggerDown = prevVal < _downThreshold && RightTrigger >= _downThreshold;
prevBool = AButton;
AButton = Pvr_UnitySDKAPI.Controller.UPvr_GetKey(rightHand, Pvr_UnitySDKAPI.Pvr_KeyCode.A);
AButtonDown = Pvr_UnitySDKAPI.Controller.UPvr_GetKeyDown(rightHand, Pvr_UnitySDKAPI.Pvr_KeyCode.A);
AButtonUp = prevBool == true && AButton == false;
prevBool = BButton;
BButton = Pvr_UnitySDKAPI.Controller.UPvr_GetKey(rightHand, Pvr_UnitySDKAPI.Pvr_KeyCode.B);
BButtonDown = Pvr_UnitySDKAPI.Controller.UPvr_GetKeyDown(rightHand, Pvr_UnitySDKAPI.Pvr_KeyCode.B);
BButtonUp = prevBool == true && BButton == false;
prevBool = XButton;
XButton = Pvr_UnitySDKAPI.Controller.UPvr_GetKey(leftHand, Pvr_UnitySDKAPI.Pvr_KeyCode.X);
XButtonDown = Pvr_UnitySDKAPI.Controller.UPvr_GetKeyDown(leftHand, Pvr_UnitySDKAPI.Pvr_KeyCode.X);
XButtonUp = prevBool == true && XButton == false;
prevBool = YButton;
YButton = Pvr_UnitySDKAPI.Controller.UPvr_GetKey(leftHand, Pvr_UnitySDKAPI.Pvr_KeyCode.Y);
YButtonDown = prevBool == false && YButton == true;
// Alternatively :
// YButtonDown = Pvr_UnitySDKAPI.Controller.UPvr_GetKeyDown(leftHand, Pvr_UnitySDKAPI.Pvr_KeyCode.Y);
YButtonUp = prevBool == true && YButton == false;
#endif
}
#endregion
public virtual void UpdateDeviceActive() {
InputDevice hmd = GetHMD();
// Can bail early
if (hmd.isValid == false) {
HMDActive = false;
return;
}
// Make sure the device supports the presence feature
bool userPresent = false;
bool presenceFeatureSupported = hmd.TryGetFeatureValue(CommonUsages.userPresence, out userPresent);
if(presenceFeatureSupported) {
HMDActive = userPresent;
}
else {
HMDActive = XRSettings.isDeviceActive;
}
}
/// <summary>
/// Round to nearest thousandth. This can alleviate some floating point precision errors found when using certain inputs.
/// </summary>
/// <param name="inputValue"></param>
/// <returns></returns>
float correctValue(float inputValue) {
return (float)System.Math.Round(inputValue * 1000f) / 1000f;
}
/// <summary>
/// Returns true if the given binding is pressed
/// </summary>
public bool GetControllerBindingValue(ControllerBinding val) {
if (val == ControllerBinding.AButton && AButton) { return true; }
if (val == ControllerBinding.AButtonDown && AButtonDown) { return true; }
if (val == ControllerBinding.BButton && BButton) { return true; }
if (val == ControllerBinding.BButtonDown && BButtonDown) { return true; }
if (val == ControllerBinding.XButton && XButton) { return true; }
if (val == ControllerBinding.XButtonDown && XButtonDown) { return true; }
if (val == ControllerBinding.YButton && YButton) { return true; }
if (val == ControllerBinding.YButtonDown && YButtonDown) { return true; }
if (val == ControllerBinding.LeftTrigger && LeftTrigger > _downThreshold) { return true; }
if (val == ControllerBinding.LeftTriggerDown && LeftTriggerDown) { return true; }
if (val == ControllerBinding.LeftGrip && LeftGrip > _downThreshold) { return true; }
if (val == ControllerBinding.LeftGripDown && LeftGripDown) { return true; }
if (val == ControllerBinding.LeftThumbstick && LeftThumbstick) { return true; }
if (val == ControllerBinding.LeftThumbstickDown && LeftThumbstickDown) { return true; }
if (val == ControllerBinding.RightTrigger && RightTrigger > _downThreshold) { return true; }
if (val == ControllerBinding.RightTriggerDown && RightTriggerDown) { return true; }
if (val == ControllerBinding.RightGrip && RightGrip > _downThreshold) { return true; }
if (val == ControllerBinding.RightGripDown && RightGripDown) { return true; }
if (val == ControllerBinding.RightThumbstick && RightThumbstick) { return true; }
if (val == ControllerBinding.RightThumbstickDown && RightThumbstickDown) { return true; }
if (val == ControllerBinding.StartButton && StartButton) { return true; }
if (val == ControllerBinding.StartButtonDown && StartButtonDown) { return true; }
if (val == ControllerBinding.BackButton && BackButton) { return true; }
if (val == ControllerBinding.BackButtonDown && BackButtonDown) { return true; }
return false;
}
public bool GetGrabbedControllerBinding(GrabbedControllerBinding val, ControllerHand hand) {
if(hand == ControllerHand.Right) {
if (val == GrabbedControllerBinding.Button1 && AButton) { return true; }
if (val == GrabbedControllerBinding.Button1Down && AButtonDown) { return true; }
if (val == GrabbedControllerBinding.Button2 && BButton) { return true; }
if (val == GrabbedControllerBinding.Button2Down && BButtonDown) { return true; }
if (val == GrabbedControllerBinding.Grip && RightGrip > _downThreshold) { return true; }
if (val == GrabbedControllerBinding.GripDown && RightGripDown) { return true; }
if (val == GrabbedControllerBinding.Trigger && RightTrigger > _downThreshold) { return true; }
if (val == GrabbedControllerBinding.TriggerDown && RightTriggerDown) { return true; }
}
else if (hand == ControllerHand.Left) {
if (val == GrabbedControllerBinding.Button1 && XButton) { return true; }
if (val == GrabbedControllerBinding.Button1Down && XButtonDown) { return true; }
if (val == GrabbedControllerBinding.Button2 && YButton) { return true; }
if (val == GrabbedControllerBinding.Button2Down && YButtonDown) { return true; }
if (val == GrabbedControllerBinding.Grip && LeftGrip > _downThreshold) { return true; }
if (val == GrabbedControllerBinding.GripDown && LeftGripDown) { return true; }
if (val == GrabbedControllerBinding.Trigger && LeftTrigger > _downThreshold) { return true; }
if (val == GrabbedControllerBinding.TriggerDown && LeftTriggerDown) { return true; }
}
return false;
}
public Vector2 GetInputAxisValue(InputAxis val) {
if (val == InputAxis.LeftThumbStickAxis) { return LeftThumbstickAxis; }
if (val == InputAxis.RightThumbStickAxis) { return RightThumbstickAxis; }
if (val == InputAxis.LeftTouchPadAxis) { return LeftTouchPadAxis; }
if (val == InputAxis.RightTouchPadAxis) { return RightTouchPadAxis; }
return Vector3.zero;
}
Vector2 ApplyDeadZones(Vector2 pos, float deadZoneX, float deadZoneY) {
if (Mathf.Abs(pos.x) < deadZoneX) {
pos.x = 0f;
}
if (Mathf.Abs(pos.y) < deadZoneY) {
pos.y = 0f;
}
return pos;
}
// Called when an input device has changed (connect / disconnect, etc.)
void onDeviceChanged(InputDevice inputDevice) {
setDeviceProperties();
SetTrackingOriginMode(TrackingOrigin);
}
void setDeviceProperties() {
// Update device properties such as device name, controller properties, etc.
// We only want to update this information if a device has changed in order to skip unnecessary checks every frame
IsOculusDevice = GetIsOculusDevice();
IsOculusQuest = GetIsOculusQuest();
IsHTCDevice = GetIsHTCDevice();
IsPicoDevice = GetIsPicoDevice();
IsValveIndexController = GetIsValveIndexController();
// Set the SDK we are using
LoadedSDK = GetLoadedSDK();
// Get specific device support
SupportsIndexTouch = GetSupportsIndexTouch();
SupportsThumbTouch = GetSupportsThumbTouch();
// Currently only the Valve Index has both a touchpad and a joystick on the same controller
SupportsBothTouchPadAndJoystick = IsValveIndexController;
// Update Controller Type
ConnectedControllerType = GetControllerType();
// Call any events
if(!string.IsNullOrEmpty(InputBridge.Instance.GetControllerName())) {
OnControllerFound?.Invoke();
}
}
/// <summary>
/// Returns true if the controllers support the 'indexTouch' XR input mapping.Currently only Oculus devices on the Oculus SDK support index touch. OpenVR is not supported.
/// </summary>
/// <returns></returns>
public virtual bool GetSupportsIndexTouch() {
//if(IsOculusDevice && LoadedSDK == SDKProvider.OculusSDK) {
// return true;
//}
return true;
}
public virtual SDKProvider GetLoadedSDK() {
// Can exit early if no device name has been picked up yet
if (XRSettings.loadedDeviceName == null) {
return SDKProvider.Unknown;
}
string deviceName = XRSettings.loadedDeviceName.ToLower();
// Example : "oculus display"
if (deviceName.StartsWith("oculus")) {
return SDKProvider.OculusSDK;
}
// Example : "OpenVR Display"
else if (deviceName.StartsWith("openvr")) {
return SDKProvider.OpenVR;
}
return SDKProvider.Unknown;
}
public virtual bool GetSupportsThumbTouch() {
//if (IsOculusDevice && LoadedSDK == SDKProvider.OculusSDK) {
// return true;
//}
return true;
}
public virtual bool GetIsOculusDevice() {
var primaryHMD = GetHMD();
// OpenVR Format
if (primaryHMD != null && primaryHMD.manufacturer == "Oculus") {
return true;
}
#if UNITY_2019_2_OR_NEWER
return XRSettings.loadedDeviceName != null && XRSettings.loadedDeviceName.ToLower().Contains("oculus");
#else
return true;
#endif
}
public virtual bool GetIsOculusQuest() {
#if UNITY_2019_2_OR_NEWER
var primaryHMD = GetHMD();
// Example : "OpenVR Headset(Oculus Quest)"
if (primaryHMD != null && primaryHMD.name != null && primaryHMD.name.EndsWith("(Oculus Quest)")) {
return true;
}
// Non-OpenVR version use "contains" on string.
else if (primaryHMD != null && primaryHMD.name != null && primaryHMD.name.Contains("Oculus Quest")) {
return true;
}
// Fallback to refresh rate
return GetIsOculusDevice() && XRDevice.refreshRate == 72f;
#else
if (Application.platform == RuntimePlatform.Android) {
return true;
}
return false;
#endif
}
public virtual bool GetIsHTCDevice() {
// Is HTC Device
#if UNITY_2019_2_OR_NEWER
var primaryHMD = GetHMD();
// OpenVR Format
if (primaryHMD != null && primaryHMD.manufacturer == "HTC") {
return true;
}
return XRSettings.loadedDeviceName.StartsWith("HTC");
#else
return false;
#endif
}
public virtual bool GetIsPicoDevice() {
#if UNITY_2019_2_OR_NEWER
return InputSource == XRInputSource.Pico || XRSettings.loadedDeviceName.StartsWith("Pico");
#else
return InputSource == XRInputSource.Pico;
#endif
}
public InputDevice GetHMD() {
InputDevices.GetDevices(devices);
var hmds = new List<InputDevice>();
var dc1 = InputDeviceCharacteristics.HeadMounted;
InputDevices.GetDevicesWithCharacteristics(dc1, hmds);
return hmds.FirstOrDefault();
}
/// <summary>
/// Returns the name of the InputDevice if found. Returns String.empty if not found
/// </summary>
/// <returns> The name of the InputDevice if found, or String.empty if not found</returns>
public string GetHMDName() {
var device = GetHMD();
if(device != null) {
return device.name;
}
return string.Empty;
}
public Vector3 GetHMDLocalPosition() {
Vector3 localPosition;
GetHMD().TryGetFeatureValue(CommonUsages.devicePosition, out localPosition);
return localPosition;
}
public Quaternion GetHMDLocalRotation() {
Quaternion localRotation;
GetHMD().TryGetFeatureValue(CommonUsages.deviceRotation, out localRotation);
return localRotation;
}
public InputDevice GetLeftController() {
InputDevices.GetDevices(devices);
var leftHandedControllers = new List<InputDevice>();
var dc = InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.Left | InputDeviceCharacteristics.Controller;
InputDevices.GetDevicesWithCharacteristics(dc, leftHandedControllers);
return leftHandedControllers.FirstOrDefault();
}
public InputDevice GetRightController() {
InputDevices.GetDevices(devices);
var rightHandedControllers = new List<InputDevice>();
var dc = InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.Right | InputDeviceCharacteristics.Controller;
InputDevices.GetDevicesWithCharacteristics(dc, rightHandedControllers);
return rightHandedControllers.FirstOrDefault();
}
public Vector3 GetControllerLocalPosition(ControllerHand handSide) {
Vector3 localPosition = Vector3.zero;
if (handSide == ControllerHand.Left) {
GetLeftController().TryGetFeatureValue(CommonUsages.devicePosition, out localPosition);
}
else if (handSide == ControllerHand.Right) {
GetRightController().TryGetFeatureValue(CommonUsages.devicePosition, out localPosition);
}
return localPosition;
}
public Quaternion GetControllerLocalRotation(ControllerHand handSide) {
Quaternion localRotation = Quaternion.identity;
if (handSide == ControllerHand.Left) {
GetLeftController().TryGetFeatureValue(CommonUsages.deviceRotation, out localRotation);
}
else if (handSide == ControllerHand.Right) {
GetRightController().TryGetFeatureValue(CommonUsages.deviceRotation, out localRotation);
}
return localRotation;
}
public virtual ControllerType GetControllerType() {
if (IsValveIndexController) {
return ControllerType.Knuckles;
}
else if (IsOculusDevice) {
return ControllerType.OculusTouch;
}
else if (IsHTCDevice) {
return ControllerType.Wand;
}
return ControllerType.Unknown;
}
public Vector3 GetControllerVelocity(ControllerHand hand) {
InputDevice inputDevice = hand == ControllerHand.Left ? GetLeftController() : GetRightController();
return getFeatureUsage(inputDevice, CommonUsages.deviceVelocity);
}
public Vector3 GetControllerAngularVelocity(ControllerHand hand) {
InputDevice inputDevice = hand == ControllerHand.Left ? GetLeftController() : GetRightController();
return getFeatureUsage(inputDevice, CommonUsages.deviceAngularVelocity);
}
/// <summary>
/// Get the name of the primary controller
/// </summary>
/// <returns>The name of the primary controller. Returns empty if no controller found</returns>
public virtual string GetControllerName() {
// First try right controller
var rightHandedControllers = new List<InputDevice>();
var dc = InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.Right | InputDeviceCharacteristics.Controller;
InputDevices.GetDevicesWithCharacteristics(dc, rightHandedControllers);
var primaryRightController = rightHandedControllers.FirstOrDefault();
// Return name of the found controller
if (primaryRightController != null && !System.String.IsNullOrEmpty(primaryRightController.name)) {
return primaryRightController.name;
}
// No right controller found, try the left
var leftHandedControllers = new List<InputDevice>();
dc = InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.Left | InputDeviceCharacteristics.Controller;
InputDevices.GetDevicesWithCharacteristics(dc, leftHandedControllers);
var primaryLeftController = leftHandedControllers.FirstOrDefault();
// Return name of the found controller
if (primaryLeftController != null && !System.String.IsNullOrEmpty(primaryLeftController.name)) {
return primaryLeftController.name;
}
return string.Empty;
}
public virtual bool GetIsValveIndexController() {
var rightHandedControllers = new List<InputDevice>();
var dc = InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.Right | InputDeviceCharacteristics.Controller;
InputDevices.GetDevicesWithCharacteristics(dc, rightHandedControllers);
var primaryRightController = rightHandedControllers.FirstOrDefault();
// Are we using Valve Index Controllers?
if (primaryRightController != null && !System.String.IsNullOrEmpty(primaryRightController.name)) {
return primaryRightController.name.Contains("Knuckles");
}
return false;
}
#if UNITY_2019_2_OR_NEWER
float getFeatureUsage(InputDevice device, InputFeatureUsage<float> usage, bool clamp = true) {
float val;
device.TryGetFeatureValue(usage, out val);
return Mathf.Clamp01(val);
}
bool getFeatureUsage(InputDevice device, InputFeatureUsage<bool> usage) {
bool val;
if (device.TryGetFeatureValue(usage, out val)) {
return val;
}
return val;
}
Vector2 getFeatureUsage(InputDevice device, InputFeatureUsage<Vector2> usage) {
Vector2 val;
if (device.TryGetFeatureValue(usage, out val)) {
return val;
}
return val;
}
Vector3 getFeatureUsage(InputDevice device, InputFeatureUsage<Vector3> usage) {
Vector3 val;
if (device.TryGetFeatureValue(usage, out val)) {
return val;
}
return val;
}
#endif
bool setTrackingOrigin = false;
public virtual void SetTrackingOriginMode(TrackingOriginModeFlags trackingOrigin) {
// 2019.4 Needs to use XRDevice.SetTrackingSpaceType; TrySetTrackingOriginMode does not function properly.
// *Removed from VRIF v1.6 as XR plugin should properly set tracking space
#if UNITY_2019_4
if (trackingOrigin == TrackingOriginModeFlags.Floor) {
#pragma warning disable
XRDevice.SetTrackingSpaceType(TrackingSpaceType.RoomScale);
#pragma warning restore
}
#endif
StartCoroutine(changeOriginModeRoutine(trackingOrigin));
}
IEnumerator changeOriginModeRoutine(TrackingOriginModeFlags trackingOrigin) {
// Wait one frame as Unity has an issue with calling this immediately
yield return null;
if(!setTrackingOrigin) {
List<XRInputSubsystem> subsystems = new List<XRInputSubsystem>();
SubsystemManager.GetInstances(subsystems);
int subSystemsCount = subsystems.Count;
if (subSystemsCount > 0) {
for (int x = 0; x < subSystemsCount; x++) {
if (subsystems[x].TrySetTrackingOriginMode(trackingOrigin)) {
setTrackingOrigin = true;
// Debug.Log("Successfully set TrackingOriginMode to " + trackingOrigin);
}
else {
Debug.LogWarning("Failed to set TrackingOriginMode to " + trackingOrigin);
}
}
}
else {
// Debug.LogWarning("No subsystems detected. Unable to set Tracking Origin to " + trackingOrigin);
}
}
}
// Start Vibration on controller
public void VibrateController(float frequency, float amplitude, float duration, ControllerHand hand) {
if (InputSource == XRInputSource.OVRInput) {
StartCoroutine(Vibrate(frequency, amplitude, duration, hand));
}
else if (InputSource == XRInputSource.SteamVR && SteamVRSupport && HMDActive) {
#if STEAM_VR_SDK
if (hand == ControllerHand.Right) {
if(SteamVR_Actions.vRIF_Haptic != null) {
SteamVR_Actions.vRIF_Haptic.Execute(0, duration, frequency, amplitude, SteamVR_Input_Sources.RightHand);
}
}
else {
if (SteamVR_Actions.vRIF_Haptic != null) {
SteamVR_Actions.vRIF_Haptic.Execute(0, duration, frequency, amplitude, SteamVR_Input_Sources.LeftHand);
}
}
#endif
}
// Default / Fallback to XRInput
else {
if (hand == ControllerHand.Right) {
InputDevices.GetDevicesWithCharacteristics(InputDeviceCharacteristics.Right, devices);
}
else {
InputDevices.GetDevicesWithCharacteristics(InputDeviceCharacteristics.Left, devices);
}
for (int x = 0; x < devices.Count; x++) {
HapticCapabilities capabilities;
if (devices[x].TryGetHapticCapabilities(out capabilities)) {
if (capabilities.supportsImpulse) {
uint channel = 0;
devices[x].SendHapticImpulse(channel, amplitude, duration);
}
}
}
}
}
IEnumerator Vibrate(float frequency, float amplitude, float duration, ControllerHand hand) {
#if OCULUS_INTEGRATION
// Start vibration
if (hand == ControllerHand.Right) {
OVRInput.SetControllerVibration(frequency, amplitude, OVRInput.Controller.RTouch);
}
else if (hand == ControllerHand.Left) {
OVRInput.SetControllerVibration(frequency, amplitude, OVRInput.Controller.LTouch);
}
yield return new WaitForSeconds(duration);
// Stop vibration
if (hand == ControllerHand.Right) {
OVRInput.SetControllerVibration(0, 0, OVRInput.Controller.RTouch);
}
else if (hand == ControllerHand.Left) {
OVRInput.SetControllerVibration(0, 0, OVRInput.Controller.LTouch);
}
#else
yield return new WaitForSeconds(duration);
#endif
}
}
}