946 lines
46 KiB
C#
946 lines
46 KiB
C#
// --------------------------------------------------------------------------------------------------------------------
|
|
// <copyright file="UxrUnityXRControllerInput.cs" company="VRMADA">
|
|
// Copyright (c) VRMADA, All rights reserved.
|
|
// </copyright>
|
|
// --------------------------------------------------------------------------------------------------------------------
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UltimateXR.Core;
|
|
using UltimateXR.Core.Settings;
|
|
using UltimateXR.Haptics;
|
|
using UnityEngine;
|
|
using UnityEngine.XR;
|
|
#if ULTIMATEXR_UNITY_XR_OCULUS
|
|
using Unity.XR.Oculus;
|
|
#endif
|
|
|
|
namespace UltimateXR.Devices.Integrations
|
|
{
|
|
/// <summary>
|
|
/// Generic base class for left-right input devices that can be handled through the new
|
|
/// generic Unity XR input interface. Before, we had to manually support each SDK individually.
|
|
/// </summary>
|
|
public abstract partial class UxrUnityXRControllerInput : UxrControllerInput
|
|
{
|
|
#region Public Types & Data
|
|
|
|
/// <summary>
|
|
/// Gets list of controller names that the component can handle
|
|
/// </summary>
|
|
public abstract IEnumerable<string> ControllerNames { get; }
|
|
|
|
/// <summary>
|
|
/// We use this when we are implementing new controllers that we don't know the name of, in order to
|
|
/// show the controller names in the UxrDebugControllerPanel.
|
|
/// Returning true will register the controllers in <see cref="InputDevices_DeviceConnected" /> no
|
|
/// matter which input device gets connected. Then using the UxrDebugControllerPanel we can see which
|
|
/// devices got connected.
|
|
/// This is mostly useful for untethered devices that cannot be tested directly in Unity.
|
|
/// </summary>
|
|
public virtual bool ForceUseAlways => false;
|
|
|
|
#endregion
|
|
|
|
#region Public Overrides UxrControllerInput
|
|
|
|
/// <inheritdoc />
|
|
public override string LeftControllerName => _deviceLeft.isValid ? _deviceLeft.name : string.Empty;
|
|
|
|
/// <inheritdoc />
|
|
public override string RightControllerName => _deviceRight.isValid ? _deviceRight.name : string.Empty;
|
|
|
|
/// <inheritdoc />
|
|
public override bool IsControllerEnabled(UxrHandSide handSide)
|
|
{
|
|
return GetInputDevice(handSide).isValid;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override float GetInput1D(UxrHandSide handSide, UxrInput1D input1D, bool getIgnoredInput = false)
|
|
{
|
|
if (ShouldIgnoreInput(handSide, getIgnoredInput))
|
|
{
|
|
return 0.0f;
|
|
}
|
|
|
|
InputDevice inputDevice = GetInputDevice(handSide);
|
|
|
|
if (inputDevice.isValid)
|
|
{
|
|
float value;
|
|
|
|
switch (input1D)
|
|
{
|
|
case UxrInput1D.Grip:
|
|
|
|
if (inputDevice.TryGetFeatureValue(CommonUsages.grip, out value))
|
|
{
|
|
return value;
|
|
}
|
|
|
|
break;
|
|
|
|
case UxrInput1D.Trigger:
|
|
|
|
if (inputDevice.TryGetFeatureValue(CommonUsages.trigger, out value))
|
|
{
|
|
return value;
|
|
}
|
|
|
|
break;
|
|
|
|
case UxrInput1D.Trigger2: break;
|
|
}
|
|
}
|
|
|
|
return 0.0f;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override Vector2 GetInput2D(UxrHandSide handSide, UxrInput2D input2D, bool getIgnoredInput = false)
|
|
{
|
|
if (ShouldIgnoreInput(handSide, getIgnoredInput))
|
|
{
|
|
return Vector2.zero;
|
|
}
|
|
|
|
InputDevice inputDevice = GetInputDevice(handSide);
|
|
|
|
if (inputDevice.isValid)
|
|
{
|
|
Vector2 value;
|
|
|
|
switch (input2D)
|
|
{
|
|
case UxrInput2D.Joystick:
|
|
|
|
if (inputDevice.TryGetFeatureValue(CommonUsages.primary2DAxis, out value))
|
|
{
|
|
return FilterTwoAxesDeadZone(value, JoystickDeadZone);
|
|
}
|
|
|
|
break;
|
|
|
|
case UxrInput2D.Joystick2:
|
|
|
|
if (inputDevice.TryGetFeatureValue(CommonUsages.secondary2DAxis, out value))
|
|
{
|
|
return FilterTwoAxesDeadZone(value, JoystickDeadZone);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Vector2.zero;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override UxrControllerInputCapabilities GetControllerCapabilities(UxrHandSide handSide)
|
|
{
|
|
UxrControllerInputCapabilities capabilities = 0;
|
|
|
|
InputDevice inputDevice = GetInputDevice(handSide);
|
|
|
|
if (!inputDevice.isValid)
|
|
{
|
|
return capabilities;
|
|
}
|
|
|
|
if (inputDevice.TryGetHapticCapabilities(out HapticCapabilities hapticCapabilities))
|
|
{
|
|
if (hapticCapabilities.supportsBuffer)
|
|
{
|
|
capabilities |= UxrControllerInputCapabilities.HapticClips;
|
|
}
|
|
|
|
if (hapticCapabilities.supportsImpulse)
|
|
{
|
|
capabilities |= UxrControllerInputCapabilities.HapticImpulses;
|
|
}
|
|
}
|
|
|
|
return capabilities;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override void SendHapticFeedback(UxrHandSide handSide, UxrHapticClip hapticClip)
|
|
{
|
|
InputDevice inputDevice = GetInputDevice(handSide);
|
|
|
|
if (!inputDevice.isValid)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (hapticClip == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!inputDevice.TryGetHapticCapabilities(out HapticCapabilities hapticCapabilities))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (hapticClip.Clip == null || !hapticCapabilities.supportsBuffer)
|
|
{
|
|
SendHapticFeedback(handSide,
|
|
hapticClip.FallbackClipType,
|
|
hapticClip.FallbackAmplitude,
|
|
hapticClip.FallbackDurationSeconds,
|
|
hapticClip.HapticMode);
|
|
return;
|
|
}
|
|
|
|
// Create haptics clip from audio
|
|
byte[] hapticBuffer = CreateHapticBufferFromAudioClip(inputDevice, hapticClip.Clip);
|
|
|
|
if (hapticBuffer == null)
|
|
{
|
|
SendHapticFeedback(handSide,
|
|
hapticClip.FallbackClipType,
|
|
hapticClip.FallbackAmplitude,
|
|
hapticClip.FallbackDurationSeconds,
|
|
hapticClip.HapticMode);
|
|
return;
|
|
}
|
|
|
|
// Readjust amplitude?
|
|
if (Mathf.Approximately(hapticClip.ClipAmplitude, 1.0f) == false)
|
|
{
|
|
for (int i = 0; i < hapticBuffer.Length; ++i)
|
|
{
|
|
hapticBuffer[i] = (byte)Mathf.Clamp(Mathf.RoundToInt(hapticBuffer[i] * hapticClip.ClipAmplitude), 0, 255);
|
|
}
|
|
}
|
|
|
|
// Send using replace or mix
|
|
uint channel = 0;
|
|
|
|
if (hapticClip.HapticMode == UxrHapticMode.Mix && hapticCapabilities.numChannels > 0)
|
|
{
|
|
if (handSide == UxrHandSide.Left)
|
|
{
|
|
_leftHapticChannel = (_leftHapticChannel + 1) % hapticCapabilities.numChannels;
|
|
channel = _leftHapticChannel;
|
|
}
|
|
else
|
|
{
|
|
_rightHapticChannel = (_rightHapticChannel + 1) % hapticCapabilities.numChannels;
|
|
channel = _rightHapticChannel;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
inputDevice.StopHaptics();
|
|
|
|
_leftHapticChannel = 0;
|
|
_rightHapticChannel = 0;
|
|
}
|
|
|
|
inputDevice.SendHapticBuffer(channel, hapticBuffer);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override void SendHapticFeedback(UxrHandSide handSide,
|
|
float frequency,
|
|
float amplitude,
|
|
float durationSeconds,
|
|
UxrHapticMode hapticMode = UxrHapticMode.Mix)
|
|
{
|
|
InputDevice inputDevice = GetInputDevice(handSide);
|
|
|
|
if (!inputDevice.isValid)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!inputDevice.TryGetHapticCapabilities(out HapticCapabilities hapticCapabilities))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Setup using replace or mix
|
|
uint channel = 0;
|
|
|
|
if (hapticMode == UxrHapticMode.Mix && hapticCapabilities.numChannels > 0)
|
|
{
|
|
if (handSide == UxrHandSide.Left)
|
|
{
|
|
_leftHapticChannel = (_leftHapticChannel + 1) % hapticCapabilities.numChannels;
|
|
channel = _leftHapticChannel;
|
|
}
|
|
else
|
|
{
|
|
_rightHapticChannel = (_rightHapticChannel + 1) % hapticCapabilities.numChannels;
|
|
channel = _rightHapticChannel;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
inputDevice.StopHaptics();
|
|
|
|
_leftHapticChannel = 0;
|
|
_rightHapticChannel = 0;
|
|
}
|
|
|
|
// Send
|
|
if (hapticCapabilities.supportsBuffer)
|
|
{
|
|
byte[] samples = new byte[(int)(hapticCapabilities.bufferFrequencyHz * durationSeconds)];
|
|
int steps = frequency > 0.0f ? Mathf.RoundToInt(hapticCapabilities.bufferFrequencyHz / frequency) : -1;
|
|
byte sample = (byte)Mathf.Clamp(amplitude * 255.0f, 0, 255.0f);
|
|
|
|
for (int i = 0; i < samples.Length; ++i)
|
|
{
|
|
if (steps < 2)
|
|
{
|
|
samples[i] = sample;
|
|
}
|
|
else
|
|
{
|
|
samples[i] = i % steps == 0 ? sample : (byte)0;
|
|
}
|
|
}
|
|
|
|
inputDevice.SendHapticBuffer(channel, samples);
|
|
}
|
|
else if (hapticCapabilities.supportsImpulse)
|
|
{
|
|
inputDevice.SendHapticImpulse(channel, amplitude, durationSeconds);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override void StopHapticFeedback(UxrHandSide handSide)
|
|
{
|
|
InputDevice inputDevice = GetInputDevice(handSide);
|
|
|
|
if (!inputDevice.isValid)
|
|
{
|
|
return;
|
|
}
|
|
|
|
inputDevice.StopHaptics();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Unity
|
|
|
|
/// <summary>
|
|
/// Initializes variables and subscribes to events.
|
|
/// If the controllers were already initialized, enables the component. Otherwise it begins disabled until devices are
|
|
/// connected.
|
|
/// </summary>
|
|
protected override void Awake()
|
|
{
|
|
base.Awake();
|
|
|
|
_leftHapticChannel = 0;
|
|
_rightHapticChannel = 0;
|
|
|
|
if (enabled)
|
|
{
|
|
InputDevices.deviceConnected += InputDevices_DeviceConnected;
|
|
InputDevices.deviceDisconnected += InputDevices_DeviceDisconnected;
|
|
|
|
// Check if the device is already connected. This may happen if a new scene was loaded, because
|
|
// the connection events were already triggered and processed. We should have them registered in
|
|
// our static fields.
|
|
_deviceLeft = s_activeInputDevices.FirstOrDefault(d => ControllerNames.Any(n => string.Equals(d.name, n)) && IsLeftController(d));
|
|
_deviceRight = s_activeInputDevices.FirstOrDefault(d => ControllerNames.Any(n => string.Equals(d.name, n)) && IsRightController(d));
|
|
|
|
List<InputDevice> devices = new List<InputDevice>();
|
|
InputDevices.GetDevices(devices);
|
|
|
|
if (!_deviceLeft.isValid)
|
|
{
|
|
_deviceLeft = devices.FirstOrDefault(d => ControllerNames.Any(n => string.Equals(d.name, n)) && IsLeftController(d));
|
|
}
|
|
|
|
if (!_deviceRight.isValid)
|
|
{
|
|
_deviceRight = devices.FirstOrDefault(d => ControllerNames.Any(n => string.Equals(d.name, n)) && IsRightController(d));
|
|
}
|
|
|
|
enabled = _deviceLeft.isValid || _deviceRight.isValid;
|
|
RaiseConnectOnStart = enabled;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unsubscribes from device events.
|
|
/// </summary>
|
|
protected override void OnDestroy()
|
|
{
|
|
base.OnDestroy();
|
|
|
|
InputDevices.deviceConnected -= InputDevices_DeviceConnected;
|
|
InputDevices.deviceDisconnected -= InputDevices_DeviceDisconnected;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Event Handling Methods
|
|
|
|
/// <summary>
|
|
/// Event called when a device is connected. Check for compatible devices.
|
|
/// </summary>
|
|
/// <param name="inputDevice">The device that was connected</param>
|
|
private void InputDevices_DeviceConnected(InputDevice inputDevice)
|
|
{
|
|
// Check if device is compatible with component
|
|
if (ForceUseAlways || ControllerNames.Any(n => string.Equals(n, inputDevice.name)))
|
|
{
|
|
// Found compatible device. Look for features.
|
|
List<InputFeatureUsage> listFeatures = new List<InputFeatureUsage>();
|
|
|
|
bool isController = false;
|
|
|
|
// Check for controllers and side
|
|
if (IsLeftController(inputDevice))
|
|
{
|
|
// Left controller
|
|
|
|
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Relevant)
|
|
{
|
|
Debug.Log($"{UxrConstants.DevicesModule} {InputClassName}::{nameof(InputDevices_DeviceConnected)}: Device name {inputDevice.name} was registered by {InputClassName} and is being processed as left controller. InputDevice.isValid={inputDevice.isValid}");
|
|
}
|
|
|
|
_deviceLeft = inputDevice;
|
|
isController = true;
|
|
}
|
|
else if (IsRightController(inputDevice))
|
|
{
|
|
// Right controller
|
|
|
|
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Relevant)
|
|
{
|
|
Debug.Log($"{UxrConstants.DevicesModule} {InputClassName}::{nameof(InputDevices_DeviceConnected)}: Device name {inputDevice.name} was registered by {InputClassName} and is being processed as right controller. InputDevice.isValid={inputDevice.isValid}");
|
|
}
|
|
|
|
_deviceRight = inputDevice;
|
|
isController = true;
|
|
}
|
|
|
|
if (isController)
|
|
{
|
|
// Register active device
|
|
s_activeInputDevices.Add(inputDevice);
|
|
|
|
if (!enabled)
|
|
{
|
|
// Component is disabled. Enable it and send Connected event.
|
|
enabled = true;
|
|
OnDeviceConnected(new UxrDeviceConnectEventArgs(true));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Check for controllers and side
|
|
if (IsLeftController(inputDevice))
|
|
{
|
|
// Left controller
|
|
|
|
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Relevant)
|
|
{
|
|
Debug.Log($"{UxrConstants.DevicesModule} {InputClassName}::{nameof(InputDevices_DeviceConnected)}: Left device connected unknown: {inputDevice.name}. InputDevice.isValid={inputDevice.isValid}");
|
|
}
|
|
}
|
|
else if (IsRightController(inputDevice))
|
|
{
|
|
// Right controller
|
|
|
|
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Relevant)
|
|
{
|
|
Debug.Log($"{UxrConstants.DevicesModule} {InputClassName}::{nameof(InputDevices_DeviceConnected)}: Right device connected unknown: {inputDevice.name}. InputDevice.isValid={inputDevice.isValid}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Event called when a device is disconnected. We use it to update our internal lists.
|
|
/// </summary>
|
|
/// <param name="inputDevice">The device that was disconnected</param>
|
|
private void InputDevices_DeviceDisconnected(InputDevice inputDevice)
|
|
{
|
|
// Check if device is compatible with component
|
|
if (ForceUseAlways || ControllerNames.Any(n => string.Equals(n, inputDevice.name)))
|
|
{
|
|
if (string.Equals(inputDevice.serialNumber, _deviceLeft.serialNumber) || string.Equals(inputDevice.serialNumber, _deviceRight.serialNumber))
|
|
{
|
|
if (UxrGlobalSettings.Instance.LogLevelDevices >= UxrLogLevel.Relevant)
|
|
{
|
|
Debug.Log($"{UxrConstants.DevicesModule} {InputClassName}::{nameof(InputDevices_DeviceDisconnected)}: Device name {inputDevice.name} was registered by {InputClassName} and is being disconnected. InputDevice.isValid={inputDevice.isValid}");
|
|
}
|
|
}
|
|
|
|
// Unregister device
|
|
s_activeInputDevices.RemoveAll(i => string.Equals(i.name, inputDevice.name));
|
|
|
|
// If last device was disconnected, disable component. Component will be re-enabled using connection event.
|
|
if (enabled && !_deviceLeft.isValid && !_deviceRight.isValid)
|
|
{
|
|
enabled = false;
|
|
OnDeviceConnected(new UxrDeviceConnectEventArgs(false));
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Protected Overrides UxrControllerInput
|
|
|
|
/// <summary>
|
|
/// Updates the input state. This should not be called by the user since it is called by the framework already.
|
|
/// </summary>
|
|
protected override void UpdateInput()
|
|
{
|
|
base.UpdateInput();
|
|
|
|
bool buttonPressTriggerLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Trigger, ButtonContact.Press);
|
|
bool buttonPressTriggerRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Trigger, ButtonContact.Press);
|
|
bool buttonPressTrigger2Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Trigger2, ButtonContact.Press);
|
|
bool buttonPressTrigger2Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Trigger2, ButtonContact.Press);
|
|
bool buttonPressJoystickLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Joystick, ButtonContact.Press);
|
|
bool buttonPressJoystickRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Joystick, ButtonContact.Press);
|
|
bool buttonPressJoystick2Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Joystick2, ButtonContact.Press);
|
|
bool buttonPressJoystick2Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Joystick2, ButtonContact.Press);
|
|
bool buttonPressButton1Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Button1, ButtonContact.Press);
|
|
bool buttonPressButton1Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Button1, ButtonContact.Press);
|
|
bool buttonPressButton2Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Button2, ButtonContact.Press);
|
|
bool buttonPressButton2Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Button2, ButtonContact.Press);
|
|
bool buttonPressButton3Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Button3, ButtonContact.Press);
|
|
bool buttonPressButton3Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Button3, ButtonContact.Press);
|
|
bool buttonPressButton4Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Button4, ButtonContact.Press);
|
|
bool buttonPressButton4Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Button4, ButtonContact.Press);
|
|
bool buttonPressBumperLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Bumper, ButtonContact.Press);
|
|
bool buttonPressBumperRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Bumper, ButtonContact.Press);
|
|
bool buttonPressBumper2Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Bumper2, ButtonContact.Press);
|
|
bool buttonPressBumper2Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Bumper2, ButtonContact.Press);
|
|
bool buttonPressMenuLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Menu, ButtonContact.Press);
|
|
bool buttonPressMenuRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Menu, ButtonContact.Press);
|
|
bool buttonPressGripLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Grip, ButtonContact.Press);
|
|
bool buttonPressGripRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Grip, ButtonContact.Press);
|
|
bool buttonPressThumbCapSenseLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.ThumbCapSense, ButtonContact.Press);
|
|
bool buttonPressThumbCapSenseRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.ThumbCapSense, ButtonContact.Press);
|
|
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Trigger, buttonPressTriggerLeft);
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Trigger, buttonPressTriggerRight);
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Trigger2, buttonPressTrigger2Left);
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Trigger2, buttonPressTrigger2Right);
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick, buttonPressJoystickLeft);
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Joystick, buttonPressJoystickRight);
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Joystick2, buttonPressJoystick2Left);
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Joystick2, buttonPressJoystick2Right);
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button1, buttonPressButton1Left);
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Button1, buttonPressButton1Right);
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button2, buttonPressButton2Left);
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Button2, buttonPressButton2Right);
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button3, buttonPressButton3Left);
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Button3, buttonPressButton3Right);
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Button4, buttonPressButton4Left);
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Button4, buttonPressButton4Right);
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Bumper, buttonPressBumperLeft);
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Bumper, buttonPressBumperRight);
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Bumper2, buttonPressBumper2Left);
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Bumper2, buttonPressBumper2Right);
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Menu, buttonPressMenuLeft);
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Menu, buttonPressMenuRight);
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.Grip, buttonPressGripLeft);
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.Grip, buttonPressGripRight);
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.ThumbCapSense, buttonPressThumbCapSenseLeft);
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.ThumbCapSense, buttonPressThumbCapSenseRight);
|
|
|
|
bool buttonTouchTriggerLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Trigger, ButtonContact.Touch);
|
|
bool buttonTouchTriggerRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Trigger, ButtonContact.Touch);
|
|
bool buttonTouchTrigger2Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Trigger2, ButtonContact.Touch);
|
|
bool buttonTouchTrigger2Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Trigger2, ButtonContact.Touch);
|
|
bool buttonTouchJoystickLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Joystick, ButtonContact.Touch);
|
|
bool buttonTouchJoystickRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Joystick, ButtonContact.Touch);
|
|
bool buttonTouchJoystick2Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Joystick2, ButtonContact.Touch);
|
|
bool buttonTouchJoystick2Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Joystick2, ButtonContact.Touch);
|
|
bool buttonTouchButton1Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Button1, ButtonContact.Touch);
|
|
bool buttonTouchButton1Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Button1, ButtonContact.Touch);
|
|
bool buttonTouchButton2Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Button2, ButtonContact.Touch);
|
|
bool buttonTouchButton2Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Button2, ButtonContact.Touch);
|
|
bool buttonTouchButton3Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Button3, ButtonContact.Touch);
|
|
bool buttonTouchButton3Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Button3, ButtonContact.Touch);
|
|
bool buttonTouchButton4Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Button4, ButtonContact.Touch);
|
|
bool buttonTouchButton4Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Button4, ButtonContact.Touch);
|
|
bool buttonTouchBumperLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Bumper, ButtonContact.Touch);
|
|
bool buttonTouchBumperRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Bumper, ButtonContact.Touch);
|
|
bool buttonTouchBumper2Left = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Bumper2, ButtonContact.Touch);
|
|
bool buttonTouchBumper2Right = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Bumper2, ButtonContact.Touch);
|
|
bool buttonTouchMenuLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Menu, ButtonContact.Touch);
|
|
bool buttonTouchMenuRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Menu, ButtonContact.Touch);
|
|
bool buttonTouchGripLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.Grip, ButtonContact.Touch);
|
|
bool buttonTouchGripRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.Grip, ButtonContact.Touch);
|
|
bool buttonTouchThumbCapSenseLeft = HasButtonContact(UxrHandSide.Left, UxrInputButtons.ThumbCapSense, ButtonContact.Touch);
|
|
bool buttonTouchThumbCapSenseRight = HasButtonContact(UxrHandSide.Right, UxrInputButtons.ThumbCapSense, ButtonContact.Touch);
|
|
|
|
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Trigger, buttonTouchTriggerLeft);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Trigger, buttonTouchTriggerRight);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Trigger2, buttonTouchTrigger2Left);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Trigger2, buttonTouchTrigger2Right);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Joystick, buttonTouchJoystickLeft);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Joystick, buttonTouchJoystickRight);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Joystick2, buttonTouchJoystick2Left);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Joystick2, buttonTouchJoystick2Right);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Button1, buttonTouchButton1Left);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Button1, buttonTouchButton1Right);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Button2, buttonTouchButton2Left);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Button2, buttonTouchButton2Right);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Button3, buttonTouchButton3Left);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Button3, buttonTouchButton3Right);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Button4, buttonTouchButton4Left);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Button4, buttonTouchButton4Right);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Bumper, buttonTouchBumperLeft);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Bumper, buttonTouchBumperRight);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Bumper2, buttonTouchBumper2Left);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Bumper2, buttonTouchBumper2Right);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Menu, buttonTouchMenuLeft);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Menu, buttonTouchMenuRight);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.Grip, buttonTouchGripLeft);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.Grip, buttonTouchGripRight);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsLeft, UxrInputButtons.ThumbCapSense, buttonTouchThumbCapSenseLeft);
|
|
SetButtonFlags(ButtonFlags.TouchFlagsRight, UxrInputButtons.ThumbCapSense, buttonTouchThumbCapSenseRight);
|
|
|
|
Vector2 leftJoystick = GetInput2D(UxrHandSide.Left, UxrInput2D.Joystick, true);
|
|
Vector2 leftDPad = leftJoystick; // Mapped to joystick by default
|
|
|
|
if (leftJoystick != Vector2.zero && leftJoystick.magnitude > AnalogAsDPadThreshold)
|
|
{
|
|
float joystickAngle = Input2DToAngle(leftJoystick);
|
|
bool touchPadFix = !MainJoystickIsTouchpad || buttonPressJoystickLeft;
|
|
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickLeft, touchPadFix && IsInput2dDPadLeft(joystickAngle));
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickRight, touchPadFix && IsInput2dDPadRight(joystickAngle));
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickUp, touchPadFix && IsInput2dDPadUp(joystickAngle));
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickDown, touchPadFix && IsInput2dDPadDown(joystickAngle));
|
|
}
|
|
else
|
|
{
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickLeft, false);
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickRight, false);
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickUp, false);
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.JoystickDown, false);
|
|
}
|
|
|
|
if (leftDPad != Vector2.zero && leftDPad.magnitude > AnalogAsDPadThreshold)
|
|
{
|
|
float dPadAngle = Input2DToAngle(leftDPad);
|
|
bool touchPadFix = !MainJoystickIsTouchpad || buttonPressJoystickLeft;
|
|
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadLeft, touchPadFix && IsInput2dDPadLeft(dPadAngle));
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadRight, touchPadFix && IsInput2dDPadRight(dPadAngle));
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadUp, touchPadFix && IsInput2dDPadUp(dPadAngle));
|
|
SetButtonFlags(ButtonFlags.PressFlagsLeft, UxrInputButtons.DPadDown, touchPadFix && IsInput2dDPadDown(dPadAngle));
|
|
}
|
|
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);
|
|
}
|
|
|
|
Vector2 rightJoystick = GetInput2D(UxrHandSide.Right, UxrInput2D.Joystick, true);
|
|
Vector2 rightDPad = rightJoystick; // Mapped to joystick by default
|
|
|
|
if (rightJoystick != Vector2.zero && rightJoystick.magnitude > AnalogAsDPadThreshold)
|
|
{
|
|
float joystickAngle = Input2DToAngle(rightJoystick);
|
|
bool touchPadFix = !MainJoystickIsTouchpad || buttonPressJoystickRight;
|
|
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickLeft, touchPadFix && IsInput2dDPadLeft(joystickAngle));
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickRight, touchPadFix && IsInput2dDPadRight(joystickAngle));
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickUp, touchPadFix && IsInput2dDPadUp(joystickAngle));
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickDown, touchPadFix && IsInput2dDPadDown(joystickAngle));
|
|
}
|
|
else
|
|
{
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickLeft, false);
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickRight, false);
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickUp, false);
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.JoystickDown, false);
|
|
}
|
|
|
|
if (rightDPad != Vector2.zero && rightDPad.magnitude > AnalogAsDPadThreshold)
|
|
{
|
|
float dPadAngle = Input2DToAngle(rightDPad);
|
|
bool touchPadFix = !MainJoystickIsTouchpad || buttonPressJoystickRight;
|
|
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadLeft, touchPadFix && IsInput2dDPadLeft(dPadAngle));
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadRight, touchPadFix && IsInput2dDPadRight(dPadAngle));
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadUp, touchPadFix && IsInput2dDPadUp(dPadAngle));
|
|
SetButtonFlags(ButtonFlags.PressFlagsRight, UxrInputButtons.DPadDown, touchPadFix && IsInput2dDPadDown(dPadAngle));
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Protected Methods
|
|
|
|
/// <summary>
|
|
/// Checks whether a non-standard button in a controller is currently being touched or pressed.
|
|
/// </summary>
|
|
/// <param name="handSide">Which controller side to check</param>
|
|
/// <param name="button">Button to check</param>
|
|
/// <param name="buttonContact">Type of contact to check for (touch or press)</param>
|
|
/// <returns>Boolean telling whether the specified button has contact</returns>
|
|
protected virtual bool HasButtonContactOther(UxrHandSide handSide, UxrInputButtons button, ButtonContact buttonContact)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the input device interface in Unity's input system for a given hand.
|
|
/// Usually if it is a left+right setup it will give a list with a single entry but the system is very generic
|
|
/// so it is prepared to handle different setups.
|
|
/// Normally we get the list and just use the first entry if available.
|
|
/// </summary>
|
|
/// <param name="handSide">Hand to get the input devices for</param>
|
|
/// <returns><see cref="InputDevice" /> representing the input device</returns>
|
|
protected InputDevice GetInputDevice(UxrHandSide handSide)
|
|
{
|
|
return handSide == UxrHandSide.Left ? _deviceLeft : _deviceRight;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Using an audio file, creates a haptic samples buffer that can be sent for feedback.
|
|
/// This code is based on the Oculus SDK (OVRHaptics.cs).
|
|
/// </summary>
|
|
/// <param name="inputDevice">Unity input device that will be the feedback target</param>
|
|
/// <param name="audioClip">Audio clip whose audio sample will be used to create haptics</param>
|
|
/// <returns>Buffer that can be sent to the device as haptic feedback</returns>
|
|
protected byte[] CreateHapticBufferFromAudioClip(InputDevice inputDevice, AudioClip audioClip)
|
|
{
|
|
float[] audioData = new float[audioClip.samples * audioClip.channels];
|
|
audioClip.GetData(audioData, 0);
|
|
|
|
if (!inputDevice.TryGetHapticCapabilities(out HapticCapabilities hapticCapabilities) || !hapticCapabilities.supportsBuffer)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (hapticCapabilities.bufferFrequencyHz == 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
double stepSizePrecise = (audioClip.frequency + 1e-6) / hapticCapabilities.bufferFrequencyHz;
|
|
|
|
if (stepSizePrecise < 1.0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
int stepSize = (int)stepSizePrecise;
|
|
double stepSizeError = stepSizePrecise - stepSize;
|
|
int length = audioData.Length;
|
|
|
|
double accumStepSizeError = 0.0f;
|
|
byte[] samples = new byte[length];
|
|
int i = 0;
|
|
int s = 0;
|
|
|
|
while (i < length)
|
|
{
|
|
byte sample = (byte)(Mathf.Clamp01(Mathf.Abs(audioData[i])) * byte.MaxValue);
|
|
|
|
if (s < samples.Length)
|
|
{
|
|
samples[s] = sample;
|
|
s++;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
i += stepSize * audioClip.channels;
|
|
accumStepSizeError += stepSizeError;
|
|
if ((int)accumStepSizeError > 0)
|
|
{
|
|
i += (int)accumStepSizeError * audioClip.channels;
|
|
accumStepSizeError = accumStepSizeError - (int)accumStepSizeError;
|
|
}
|
|
}
|
|
|
|
return samples;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private Methods
|
|
|
|
/// <summary>
|
|
/// Gets if the given input device is a left side VR controller
|
|
/// </summary>
|
|
/// <param name="inputDevice">Device to check</param>
|
|
/// <returns>Whether the given input device is a left side VR controller</returns>
|
|
private static bool IsLeftController(InputDevice inputDevice)
|
|
{
|
|
return inputDevice.characteristics.HasFlag(InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Left);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets if the given input device is a right side VR controller
|
|
/// </summary>
|
|
/// <param name="inputDevice">Device to check</param>
|
|
/// <returns>Whether the given input device is a right side VR controller</returns>
|
|
private static bool IsRightController(InputDevice inputDevice)
|
|
{
|
|
return inputDevice.characteristics.HasFlag(InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Right);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks whether the given button in a controller is currently being touched or pressed.
|
|
/// </summary>
|
|
/// <param name="handSide">Which controller side to check</param>
|
|
/// <param name="button">Button to check</param>
|
|
/// <param name="buttonContact">Type of contact to check for (touch or press)</param>
|
|
/// <returns>Boolean telling whether the specified button has contact</returns>
|
|
private bool HasButtonContact(UxrHandSide handSide, UxrInputButtons button, ButtonContact buttonContact)
|
|
{
|
|
InputDevice inputDevice = GetInputDevice(handSide);
|
|
if (!inputDevice.isValid)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (button == UxrInputButtons.Joystick)
|
|
{
|
|
var featureUsage = buttonContact == ButtonContact.Press ? CommonUsages.primary2DAxisClick : CommonUsages.primary2DAxisTouch;
|
|
if (inputDevice.TryGetFeatureValue(featureUsage, out bool value))
|
|
{
|
|
return value;
|
|
}
|
|
}
|
|
else if (button == UxrInputButtons.Joystick2)
|
|
{
|
|
return false;
|
|
}
|
|
else if (button == UxrInputButtons.Trigger)
|
|
{
|
|
if (buttonContact == ButtonContact.Touch)
|
|
{
|
|
#if ULTIMATEXR_UNITY_XR_OCULUS
|
|
if (inputDevice.TryGetFeatureValue(OculusUsages.indexTouch, out bool valueTouch))
|
|
{
|
|
return valueTouch;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (inputDevice.TryGetFeatureValue(CommonUsages.trigger, out float valueFloat))
|
|
{
|
|
// We try getting the float value first because in analog buttons like the oculus it will trigger too early with the bool version.
|
|
return valueFloat > AnalogAsDPadThreshold;
|
|
}
|
|
|
|
if (inputDevice.TryGetFeatureValue(CommonUsages.triggerButton, out bool value))
|
|
{
|
|
return value;
|
|
}
|
|
}
|
|
else if (button == UxrInputButtons.Trigger2)
|
|
{
|
|
return false;
|
|
}
|
|
else if (button == UxrInputButtons.Grip)
|
|
{
|
|
if (inputDevice.TryGetFeatureValue(CommonUsages.gripButton, out bool value))
|
|
{
|
|
return value;
|
|
}
|
|
}
|
|
else if (button == UxrInputButtons.Button1)
|
|
{
|
|
var featureUsage = buttonContact == ButtonContact.Press ? CommonUsages.primaryButton : CommonUsages.primaryTouch;
|
|
if (inputDevice.TryGetFeatureValue(featureUsage, out bool value))
|
|
{
|
|
return value;
|
|
}
|
|
}
|
|
else if (button == UxrInputButtons.Button2)
|
|
{
|
|
var featureUsage = buttonContact == ButtonContact.Press ? CommonUsages.secondaryButton : CommonUsages.secondaryTouch;
|
|
if (inputDevice.TryGetFeatureValue(featureUsage, out bool value))
|
|
{
|
|
return value;
|
|
}
|
|
}
|
|
else if (button == UxrInputButtons.Menu)
|
|
{
|
|
if (inputDevice.TryGetFeatureValue(CommonUsages.menuButton, out bool value))
|
|
{
|
|
return value;
|
|
}
|
|
}
|
|
else if (button == UxrInputButtons.ThumbCapSense)
|
|
{
|
|
if (buttonContact == ButtonContact.Press)
|
|
{
|
|
#if ULTIMATEXR_UNITY_XR_OCULUS
|
|
if (inputDevice.TryGetFeatureValue(OculusUsages.thumbrest, out bool value))
|
|
{
|
|
return value;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (buttonContact == ButtonContact.Touch)
|
|
{
|
|
#if ULTIMATEXR_UNITY_XR_OCULUS
|
|
if (inputDevice.TryGetFeatureValue(OculusUsages.thumbTouch, out bool value))
|
|
{
|
|
return value;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else if (button == UxrInputButtons.IndexCapSense)
|
|
{
|
|
}
|
|
else if (button == UxrInputButtons.MiddleCapSense)
|
|
{
|
|
}
|
|
else if (button == UxrInputButtons.RingCapSense)
|
|
{
|
|
}
|
|
else if (button == UxrInputButtons.LittleCapSense)
|
|
{
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private Types & Data
|
|
|
|
private string InputClassName => GetType().Name;
|
|
|
|
private static readonly List<InputDevice> s_activeInputDevices = new List<InputDevice>();
|
|
|
|
private InputDevice _deviceLeft;
|
|
private InputDevice _deviceRight;
|
|
private uint _leftHapticChannel;
|
|
private uint _rightHapticChannel;
|
|
|
|
#endregion
|
|
}
|
|
} |