Search Unity

Any example of the new 2019.1 XR input system?

Discussion in 'AR/VR (XR) Discussion' started by fariazz, Feb 15, 2019.

  1. kavanavak

    kavanavak

    Joined:
    Sep 30, 2015
    Posts:
    54
    That looks about right. I made an input script to take all input and send out events when buttons are pressed, which I house on my main controller object. I link those events through the editor to GO scripts nested in that main controller, scripts that have generic TriggerPressed() or ActionType() values that perform their own controller specific functions when called.

    Code (CSharp):
    1. private void Start()
    2.     {
    3.         //INPUT DATA
    4.         m_Controller = GetComponentInParent<XRController>();
    5.         m_Node = m_Controller.controllerNode;
    6.         InitializeDevice();
    7.     }
    8.  
    9.     private void InitializeDevice()
    10.     {
    11.         m_InputDevice = InputDevices.GetDeviceAtXRNode(m_Node);
    12.         if (m_Node == XRNode.LeftHand)
    13.         {
    14.             GetComponent<ControllerStatus>().isLeftController = true;
    15.         }
    16.         if (m_Node == XRNode.RightHand)
    17.         {
    18.             GetComponent<ControllerStatus>().isRightController = true;
    19.         }
    20.     }
    21. private void Update()
    22.     {
    23. if (m_InputDevice == null)
    24.         {
    25.             Debug.LogError("no device found on " + m_Node);
    26.             return;
    27.         }
    28.  
    29.         if (m_ControllersEnabled)
    30.         {
    31.             //TRIGGER
    32.             m_InputDevice.TryGetFeatureValue(CommonUsages.trigger, out m_TriggerValue);//m_InputDevice.TryGetFeatureValue(new InputFeatureUsage<float>("Trigger"), out m_TriggerValue);
    33.             m_InputDevice.TryGetFeatureValue(new InputFeatureUsage<bool>("TriggerButton"), out m_TriggerButtonStatus);
    34.             if ((m_TriggerValue == 1) & !m_TriggerAlreadyActive)
    35.             {
    36.                 Trigger();
    37.                 m_TriggerAlreadyActive = true;
    38.             }
    39.             if ((m_TriggerValue != 1) & m_TriggerAlreadyActive)
    40.             {
    41.                 m_TriggerAlreadyActive = false;
    42.             }
    43. ...
    44.  
     
  2. Loths

    Loths

    Joined:
    Aug 18, 2017
    Posts:
    9
    Looks pretty similar to what I'm attempting, don't really see anything that wouldn't make it work on my end. Is there anything outside of the script that needs to be set up? Anything in input or player settings or something like that?
     
  3. Loths

    Loths

    Joined:
    Aug 18, 2017
    Posts:
    9
    Turns out it was working all along and the input just wasn't coming through. Apparently that's an issue with oculus, this thread solved it for me: https://forum.unity.com/threads/oculus-touch-input-not-detected.546942/
     
    kavanavak likes this.
  4. Alverik

    Alverik

    Joined:
    Apr 15, 2016
    Posts:
    417
    Tried making a VrInput class which works a little more like the regular input class. And since I wanted it to be usable for multiple devices at the same time I created a special class that holds the "keys" and hand to be checked per device (the intention is to return a result based on what device is plugged in... but I mostly intend to use it for Rift and Vive). But still has a few things that need to be improved, or verified because I only have an old Rift to test (which was pretty hard to get where I live). Some of the device names seem to be different depending on the backend in use, so I can't guarantee it'll work without some tweaks (I'm using the device names to know what result to provide, but I have no way to test for a while)... Seems to work as expected using the new backend and the Rift though.

    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3.  
    4. namespace Clunia
    5. {
    6.     public class VrInputEvents : MonoBehaviour
    7.     {
    8.         public delegate void EventHandler(HandType hand);
    9.         public delegate void HmdEventHandler();
    10.    
    11.         public static event HmdEventHandler OnHmdMounted;
    12.         public static event HmdEventHandler OnHmdUnmounted;
    13.    
    14.         public static event EventHandler OnPrimary2DAxisClickDown;
    15.         public static event EventHandler OnSecondary2DAxisClickDown;
    16.    
    17.         public static event EventHandler OnPrimary2DAxisTouchDown;
    18.         public static event EventHandler OnPrimaryTouchDown;
    19.         public static event EventHandler OnSecondaryTouchDown;
    20.    
    21.         public static event EventHandler OnPrimaryButtonDown;
    22.         public static event EventHandler OnSecondaryButtonDown;
    23.         public static event EventHandler OnGripButtonDown;
    24.         public static event EventHandler OnTriggerButtonDown;
    25.         public static event EventHandler OnMenuButtonDown;
    26.         public static event EventHandler OnUserPresenceDown;
    27.  
    28.    
    29.    
    30.         public static event EventHandler OnPrimary2DAxisClickUp;
    31.         public static event EventHandler OnSecondary2DAxisClickUp;
    32.    
    33.         public static event EventHandler OnPrimary2DAxisTouchUp;
    34.         public static event EventHandler OnPrimaryTouchUp;
    35.         public static event EventHandler OnSecondaryTouchUp;
    36.    
    37.         public static event EventHandler OnPrimaryButtonUp;
    38.         public static event EventHandler OnSecondaryButtonUp;
    39.         public static event EventHandler OnGripButtonUp;
    40.         public static event EventHandler OnTriggerButtonUp;
    41.         public static event EventHandler OnMenuButtonUp;
    42.         public static event EventHandler OnUserPresenceUp;
    43.  
    44.         public static bool LeftControllerActive { get; private set; }
    45.         public static bool RightControllerActive { get; private set; }
    46.    
    47.  
    48.         protected static void Primary2DAxisClickDownCaller(HandType hand)
    49.         {
    50.             OnPrimary2DAxisClickDown?.Invoke(hand);
    51.         }
    52.    
    53.         protected static void Secondary2DAxisClickDownCaller(HandType hand)
    54.         {
    55.             OnSecondary2DAxisClickDown?.Invoke(hand);
    56.         }
    57.    
    58.         protected static void Primary2DAxisTouchDownCaller(HandType hand)
    59.         {
    60.             OnPrimary2DAxisTouchDown?.Invoke(hand);
    61.         }
    62.    
    63.         protected static void PrimaryTouchDownCaller(HandType hand)
    64.         {
    65.             OnPrimaryTouchDown?.Invoke(hand);
    66.         }
    67.    
    68.         protected static void SecondaryTouchDownCaller(HandType hand)
    69.         {
    70.             OnSecondaryTouchDown?.Invoke(hand);
    71.         }
    72.    
    73.         protected static void PrimaryButtonDownCaller(HandType hand)
    74.         {
    75.             OnPrimaryButtonDown?.Invoke(hand);
    76.         }
    77.    
    78.         protected static void SecondaryButtonDownCaller(HandType hand)
    79.         {
    80.             OnSecondaryButtonDown?.Invoke(hand);
    81.         }
    82.    
    83.         protected static void GripButtonDownCaller(HandType hand)
    84.         {
    85.             OnGripButtonDown?.Invoke(hand);
    86.         }
    87.    
    88.         protected static void TriggerButtonDownCaller(HandType hand)
    89.         {
    90.             OnTriggerButtonDown?.Invoke(hand);
    91.         }
    92.    
    93.         protected static void MenuButtonDownCaller(HandType hand)
    94.         {
    95.             OnMenuButtonDown?.Invoke(hand);
    96.         }
    97.    
    98.         protected static void UserPresenceDownCaller(HandType hand)
    99.         {
    100.             switch (hand)
    101.             {
    102.                 case HandType.Left:
    103.                     LeftControllerActive = true;
    104.                     break;
    105.                 case HandType.Right:
    106.                     RightControllerActive = true;
    107.                     break;
    108.             }
    109.        
    110.             OnUserPresenceDown?.Invoke(hand);
    111.         }
    112.    
    113.         //------------------
    114.    
    115.         protected static void Primary2DAxisClickUpCaller(HandType hand)
    116.         {
    117.             OnPrimary2DAxisClickUp?.Invoke(hand);
    118.         }
    119.    
    120.         protected static void Secondary2DAxisClickUpCaller(HandType hand)
    121.         {
    122.             OnSecondary2DAxisClickUp?.Invoke(hand);
    123.         }
    124.    
    125.         protected static void Primary2DAxisTouchUpCaller(HandType hand)
    126.         {
    127.             OnPrimary2DAxisTouchUp?.Invoke(hand);
    128.         }
    129.    
    130.         protected static void PrimaryTouchUpCaller(HandType hand)
    131.         {
    132.             OnPrimaryTouchUp?.Invoke(hand);
    133.         }
    134.    
    135.         protected static void SecondaryTouchUpCaller(HandType hand)
    136.         {
    137.             OnSecondaryTouchUp?.Invoke(hand);
    138.         }
    139.    
    140.         protected static void PrimaryButtonUpCaller(HandType hand)
    141.         {
    142.             OnPrimaryButtonUp?.Invoke(hand);
    143.         }
    144.    
    145.         protected static void SecondaryButtonUpCaller(HandType hand)
    146.         {
    147.             OnSecondaryButtonUp?.Invoke(hand);
    148.         }
    149.    
    150.         protected static void GripButtonUpCaller(HandType hand)
    151.         {
    152.             OnGripButtonUp?.Invoke(hand);
    153.         }
    154.    
    155.         protected static void TriggerButtonUpCaller(HandType hand)
    156.         {
    157.             OnTriggerButtonUp?.Invoke(hand);
    158.         }
    159.    
    160.         protected static void MenuButtonUpCaller(HandType hand)
    161.         {
    162.             OnMenuButtonUp?.Invoke(hand);
    163.         }
    164.    
    165.         protected static void UserPresenceUpCaller(HandType hand)
    166.         {
    167.             switch (hand)
    168.             {
    169.                 case HandType.Left:
    170.                     LeftControllerActive = false;
    171.                     break;
    172.                 case HandType.Right:
    173.                     RightControllerActive = false;
    174.                     break;
    175.             }
    176.        
    177.             OnUserPresenceUp?.Invoke(hand);
    178.         }
    179.    
    180.         //-----------------------
    181.  
    182.         protected static void HmdMountedCaller()
    183.         {
    184.             OnHmdMounted?.Invoke();
    185.         }
    186.    
    187.         protected static void HmdUnmountedCaller()
    188.         {
    189.             OnHmdUnmounted?.Invoke();
    190.         }
    191.  
    192.     }
    193. }
    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3. using UnityEngine.XR;
    4. using System.Collections.Generic;
    5. using UnityEngine.PlayerLoop;
    6. using UnityEngine.SpatialTracking;
    7. using UnityEngine.XR.Interaction.Toolkit;
    8.  
    9. namespace Clunia
    10. {
    11.  
    12.     #region public enums
    13.     public enum RiftKeyCodes
    14.     {
    15.         None,
    16.         Trigger,
    17.         Grip,
    18.         Menu,
    19.         ButtonOne,
    20.         ButtonTwo,
    21.         ThumbStick,
    22.         ButtonOneTouch,
    23.         ButtonTwoTouch,
    24.         ThumbStickTouch
    25.     }
    26.  
    27.     public enum ViveKeyCodes
    28.     {
    29.         None,
    30.         Trigger,
    31.         Grip,
    32.         Menu,
    33.         Trackpad,
    34.         TrackpadUp,
    35.         TrackpadDown,
    36.         TrackpadLeft,
    37.         TrackpadRight,
    38.         TrackpadRightUp,
    39.         TrackpadRightDown,
    40.         TrackpadLeftUp,
    41.         TrackpadLeftDown
    42.     }
    43.     public enum ViveKnuckleKeyCodes
    44.     {
    45.         None,
    46.         Trigger,
    47.         Grip,
    48.         Primary,
    49.         Alternate,
    50.         Joystick,
    51.         JoystickTouch
    52.     }
    53.  
    54.     public enum GearVrKeyCodes
    55.     {
    56.         None,
    57.         Trigger,
    58.         Touchpad,
    59.         TouchpadTouch
    60.     }
    61.  
    62.     public enum HandType
    63.     {
    64.         Left,Right
    65.     }
    66.  
    67.     public enum GetKeyType
    68.     {
    69.         Get,GetDown,GetUp
    70.     }
    71.  
    72. #endregion
    73.  
    74.     public class VrInput : VrInputEvents
    75.     {
    76.         private enum TrackpadDirection
    77.         {
    78.             Left,Right,Up,Down,
    79.             LeftUp, RightUp, LeftDown,RightDown
    80.         }
    81.  
    82.         public static string LoadedDeviceName => XRSettings.loadedDeviceName;
    83.         public static bool XrPresent { get; private set; }
    84.  
    85.         //device name constants
    86.         private const string OpenVrDeviceName = "OpenVR";
    87.         private const string OculusDeviceName = "Oculus";
    88.         private const string OculusDeviceNameB = "oculus display";
    89.         private const string GearVrDeviceName = "GearVr";
    90.  
    91.         #region Raw Inputs
    92.    
    93.         private static List<InputDevice> _headDevices = new List<InputDevice>();
    94.         private static List<InputDevice> _leftHandDevices = new List<InputDevice>();
    95.         private static List<InputDevice> _rightHandDevices = new List<InputDevice>();
    96.  
    97.         private static InputDevice Head { get; set; }
    98.         private static InputDevice LeftHand { get; set; }
    99.         private static InputDevice RightHand { get; set; }
    100.  
    101.         public static bool LeftControllerConnected { get; private set; } = true;
    102.         public static bool RightControllerConnected { get; private set; } = true;
    103.  
    104.  
    105.         public class InputBase
    106.         {
    107.             public class KeyData
    108.             {
    109.                 public bool Pressed;
    110.                 public bool Down;
    111.                 public bool Up;
    112.  
    113.                 public bool Last { get; private set; }
    114.  
    115.                 public void Update()
    116.                 {
    117.                     Last = Pressed;
    118.                 }
    119.             }
    120.        
    121.             public void SetDevice(InputDevice device)
    122.             {
    123.                 Device = device;
    124.             }
    125.        
    126.             protected InputDevice Device { get; private set; }
    127.        
    128.             public Vector3 Position => Get3DAxis(Device, CommonUsages.devicePosition);
    129.  
    130.             public Quaternion Rotation => GetRot(Device, CommonUsages.deviceRotation);
    131.        
    132.             public Vector3 Velocity => Get3DAxis(Device, CommonUsages.deviceVelocity);
    133.             public Vector3 Acceleration => Get3DAxis(Device, CommonUsages.deviceAcceleration);
    134.             public Vector3 AngularVelocity => Get3DAxis(Device, CommonUsages.deviceAngularVelocity);
    135.             public Vector3 AngularAcceleration => Get3DAxis(Device, CommonUsages.deviceAngularAcceleration);
    136.  
    137.             public float BatteryLevel => GetAxis(Device, CommonUsages.batteryLevel);
    138.        
    139.             protected Vector3 Get3DAxis(InputDevice device, InputFeatureUsage<Vector3> usage)
    140.             {
    141.                 device.TryGetFeatureValue(usage, out var val);
    142.                 return val;
    143.             }
    144.        
    145.             protected Quaternion GetRot(InputDevice device, InputFeatureUsage<Quaternion> usage)
    146.             {
    147.                 device.TryGetFeatureValue(usage, out var val);
    148.                 return val;
    149.             }
    150.        
    151.             protected bool GetKey(InputDevice device, InputFeatureUsage<bool> usage)
    152.             {
    153.                 device.TryGetFeatureValue(usage, out var val);
    154.                 return val;
    155.             }
    156.        
    157.             protected float GetAxis(InputDevice device, InputFeatureUsage<float> usage)
    158.             {
    159.                 device.TryGetFeatureValue(usage, out var val);
    160.                 return val;
    161.             }
    162.    
    163.             protected Vector2 Get2DAxis(InputDevice device, InputFeatureUsage<Vector2> usage)
    164.             {
    165.                 device.TryGetFeatureValue(usage, out var val);
    166.                 return val;
    167.             }
    168.         }
    169.  
    170.         public class HeadsetInputs : InputBase
    171.         {
    172.             public KeyData UserPresence = new KeyData();
    173.  
    174.             public void Update()
    175.             {
    176.                 UserPresence.Pressed = GetKey(Device, CommonUsages.userPresence);
    177.            
    178.                 GetState(UserPresence.Pressed, UserPresence.Last, out UserPresence.Down,
    179.                     out UserPresence.Up,HmdMountedCaller,HmdUnmountedCaller);
    180.            
    181.                 UserPresence.Update();
    182.             }
    183.        
    184.             void GetState(bool cur, bool prev, out bool keyDown, out bool keyUp,
    185.                 Action mounted, Action unmounted)
    186.             {
    187.                 if (cur != prev) //if changed
    188.                 {
    189.                     if (cur)
    190.                     {
    191.                         keyDown = true;
    192.                         keyUp = false;
    193.                         mounted?.Invoke();
    194.                         HmdMounted = true;
    195.                         //Debug.Log("Hmd put on");
    196.                     }
    197.                     else
    198.                     {
    199.                         keyUp = true;
    200.                         keyDown = false;
    201.                         unmounted?.Invoke();
    202.                         HmdMounted = false;
    203.                         //Debug.Log("Hmd put removed");
    204.                     }
    205.                     return;
    206.                 }
    207.                 //if same as previous, button is held or not being pressed at all
    208.                 keyDown = false;
    209.                 keyUp = false;
    210.             }
    211.         }
    212.  
    213.         public class ControllerInputs: InputBase
    214.         {
    215.             public ControllerInputs(HandType hand)
    216.             {
    217.                 Hand = hand;
    218.             }
    219.        
    220.             private HandType Hand { get; }
    221.        
    222.        
    223.             public Vector3 Primary2DAxis => Get2DAxis(Device, CommonUsages.primary2DAxis);
    224.             public Vector3 Secondary2DAxis => Get2DAxis(Device, CommonUsages.secondary2DAxis);
    225.    
    226.             public float Grip => GetAxis(Device, CommonUsages.grip);
    227.             public float Trigger => GetAxis(Device, CommonUsages.trigger);
    228.  
    229.  
    230.             //get key
    231.             public KeyData Primary2DAxisClick = new KeyData();
    232.             public KeyData Secondary2DAxisClick = new KeyData();
    233.    
    234.             public KeyData Primary2DAxisTouch = new KeyData();
    235.             public KeyData PrimaryTouch = new KeyData();
    236.             public KeyData SecondaryTouch = new KeyData();
    237.    
    238.             public KeyData PrimaryButton = new KeyData();
    239.             public KeyData SecondaryButton = new KeyData();
    240.             public KeyData GripButton = new KeyData();
    241.             public KeyData TriggerButton = new KeyData();
    242.             public KeyData MenuButton = new KeyData();
    243.             public KeyData UserPresence = new KeyData();
    244.  
    245.             public void Update()
    246.             {
    247.                 //Debug.Log(Hand + " - Primary Axis: "+ Primary2DAxis + " - Time: " + Time.realtimeSinceStartup);
    248.                 Primary2DAxisClick.Pressed = GetKey(Device, CommonUsages.primary2DAxisClick);
    249.                 Secondary2DAxisClick.Pressed = GetKey(Device, CommonUsages.secondary2DAxisClick);
    250.            
    251.                 Primary2DAxisTouch.Pressed = GetKey(Device, CommonUsages.primary2DAxisTouch);
    252.                 PrimaryTouch.Pressed = GetKey(Device, CommonUsages.primaryTouch);
    253.                 SecondaryTouch.Pressed = GetKey(Device, CommonUsages.secondaryTouch);
    254.            
    255.                 PrimaryButton.Pressed = GetKey(Device, CommonUsages.primaryButton);
    256.                 SecondaryButton.Pressed = GetKey(Device, CommonUsages.secondaryButton);
    257.                 GripButton.Pressed = GetKey(Device, CommonUsages.gripButton);
    258.                 TriggerButton.Pressed = GetKey(Device, CommonUsages.triggerButton);
    259.                 MenuButton.Pressed = GetKey(Device, CommonUsages.menuButton);
    260.                 UserPresence.Pressed = GetKey(Device, CommonUsages.userPresence);
    261.  
    262.                 //check for changes
    263.  
    264.                 GetState(Primary2DAxisClick.Pressed, Primary2DAxisClick.Last, out Primary2DAxisClick.Down,
    265.                     out Primary2DAxisClick.Up, Primary2DAxisClickDownCaller, Primary2DAxisClickUpCaller);
    266.            
    267.                 GetState(Secondary2DAxisClick.Pressed, Secondary2DAxisClick.Last, out Secondary2DAxisClick.Down,
    268.                     out Secondary2DAxisClick.Up,Secondary2DAxisClickDownCaller,Secondary2DAxisClickUpCaller);
    269.            
    270.                 GetState(Primary2DAxisTouch.Pressed, Primary2DAxisTouch.Last, out Primary2DAxisTouch.Down,
    271.                     out Primary2DAxisTouch.Up,Primary2DAxisTouchDownCaller,Primary2DAxisTouchUpCaller);
    272.            
    273.                 GetState(PrimaryTouch.Pressed, PrimaryTouch.Last, out PrimaryTouch.Down,
    274.                     out PrimaryTouch.Up,PrimaryTouchDownCaller,PrimaryTouchUpCaller);
    275.            
    276.                 GetState(SecondaryTouch.Pressed, SecondaryTouch.Last, out SecondaryTouch.Down,
    277.                     out SecondaryTouch.Up, SecondaryTouchDownCaller, SecondaryTouchUpCaller);
    278.            
    279.            
    280.            
    281.                 GetState(PrimaryButton.Pressed, PrimaryButton.Last, out PrimaryButton.Down,
    282.                     out PrimaryButton.Up,PrimaryButtonDownCaller,PrimaryButtonUpCaller);
    283.            
    284.                 GetState(SecondaryButton.Pressed, SecondaryButton.Last, out SecondaryButton.Down,
    285.                     out SecondaryButton.Up,SecondaryButtonDownCaller,SecondaryButtonUpCaller);
    286.            
    287.                 GetState(GripButton.Pressed, GripButton.Last, out GripButton.Down,
    288.                     out GripButton.Up,GripButtonDownCaller,GripButtonUpCaller);
    289.            
    290.                 GetState(TriggerButton.Pressed, TriggerButton.Last, out TriggerButton.Down,
    291.                     out TriggerButton.Up,TriggerButtonDownCaller,TriggerButtonUpCaller);
    292.            
    293.                 GetState(MenuButton.Pressed, MenuButton.Last, out MenuButton.Down,
    294.                     out MenuButton.Up,MenuButtonDownCaller,MenuButtonUpCaller);
    295.            
    296.                 GetState(UserPresence.Pressed, UserPresence.Last, out UserPresence.Down,
    297.                     out UserPresence.Up,UserPresenceDownCaller,UserPresenceUpCaller);
    298.            
    299.                 //Then record frame
    300.                 Primary2DAxisClick.Update();
    301.                 Secondary2DAxisClick.Update();
    302.            
    303.                 Primary2DAxisTouch.Update();
    304.                 PrimaryTouch.Update();
    305.                 SecondaryTouch.Update();
    306.  
    307.                 PrimaryButton.Update();
    308.                 SecondaryButton.Update();
    309.                 GripButton.Update();
    310.                 TriggerButton.Update();
    311.                 MenuButton.Update();
    312.                 UserPresence.Update();
    313.  
    314.             }
    315.  
    316.             void GetState(bool cur, bool prev, out bool keyDown, out bool keyUp,
    317.                 Action<HandType> onKeyDown, Action<HandType> onKeyUp)
    318.             {
    319.                 if (cur != prev) //if changed
    320.                 {
    321.                     if (cur)
    322.                     {
    323.                         keyDown = true;
    324.                         keyUp = false;
    325.                         onKeyDown?.Invoke(Hand);
    326.                     }
    327.                     else
    328.                     {
    329.                         keyUp = true;
    330.                         keyDown = false;
    331.                         onKeyUp?.Invoke(Hand);
    332.                     }
    333.                     return;
    334.                 }
    335.                 //if same as previous, button is held or not being pressed at all
    336.                 keyDown = false;
    337.                 keyUp = false;
    338.             }
    339.         }
    340.  
    341.    
    342.         private static HeadsetInputs HeadInput { get; set; }
    343.         private static ControllerInputs LeftInput { get; set; }
    344.         private static ControllerInputs RightInput { get; set; }
    345.  
    346.         #endregion
    347.  
    348.         #region General Data
    349.  
    350.         //------Hmd
    351.         public static TrackedPoseDriver HmdTrackedPoseDriver { get; private set; }
    352.         public static Vector3 PositionHmd => Head.isValid ? HeadInput.Position : Vector3.zero;
    353.         public static Quaternion RotationHmd => Head.isValid ? HeadInput.Rotation : Quaternion.identity;
    354.    
    355.         public static Vector3 VelocityHmd => Head.isValid ? HeadInput.Velocity : Vector3.zero;
    356.         public static Vector3 AccelerationHmd => Head.isValid ? HeadInput.Acceleration : Vector3.zero;
    357.         public static Vector3 AngularVelocityHmd => Head.isValid ? HeadInput.AngularVelocity : Vector3.zero;
    358.         public static Vector3 AngularAccelerationHmd => Head.isValid ? HeadInput.AngularAcceleration : Vector3.zero;
    359.    
    360.         public static float BatteryLevelHmd => Head.isValid ? HeadInput.BatteryLevel : 0;
    361.         public static bool HmdMounted { get; private set; }
    362.    
    363.    
    364.         //------Left hand
    365.         public static XRController LeftXrController { get; private set; }
    366.         public static Vector3 PositionL => LeftHand.isValid ? LeftInput.Position : Vector3.zero;
    367.         public static Quaternion RotationL => LeftHand.isValid ? LeftInput.Rotation : Quaternion.identity;
    368.    
    369.         public static Vector3 VelocityL => LeftHand.isValid ? LeftInput.Velocity : Vector3.zero;
    370.         public static Vector3 AccelerationL => LeftHand.isValid ? LeftInput.Acceleration : Vector3.zero;
    371.         public static Vector3 AngularVelocityL => LeftHand.isValid ? LeftInput.AngularVelocity : Vector3.zero;
    372.         public static Vector3 AngularAccelerationL => LeftHand.isValid ? LeftInput.AngularAcceleration : Vector3.zero;
    373.         public static Vector3 Primary2DAxisL => LeftHand.isValid ? LeftInput.Primary2DAxis : Vector3.zero;
    374.         public static Vector3 Secondary2DAxisL => LeftHand.isValid ? LeftInput.Secondary2DAxis : Vector3.zero;
    375.  
    376.         public static float GripPressureL => LeftHand.isValid ? LeftInput.Grip : 0;
    377.         public static float TriggerPressureL => LeftHand.isValid ? LeftInput.Trigger : 0;
    378.         public static float BatteryLevelL => LeftHand.isValid ? LeftInput.BatteryLevel : 0;
    379.    
    380.         //------Right hand
    381.  
    382.         public static XRController RightXrController { get; private set; }
    383.         public static Vector3 PositionR => RightHand.isValid ? RightInput.Position : Vector3.zero;
    384.         public static Quaternion RotationR => RightHand.isValid ? RightInput.Rotation: Quaternion.identity;
    385.    
    386.         public static Vector3 VelocityR => RightHand.isValid ? RightInput.Velocity : Vector3.zero;
    387.         public static Vector3 AccelerationR => RightHand.isValid ? RightInput.Acceleration : Vector3.zero;
    388.         public static Vector3 AngularVelocityR => RightHand.isValid ? RightInput.AngularVelocity : Vector3.zero;
    389.         public static Vector3 AngularAccelerationR => RightHand.isValid ? RightInput.AngularAcceleration : Vector3.zero;
    390.         public static Vector3 Primary2DAxisR => RightHand.isValid ? RightInput.Primary2DAxis : Vector3.zero;
    391.         public static Vector3 Secondary2DAxisR => RightHand.isValid ? RightInput.Secondary2DAxis : Vector3.zero;
    392.  
    393.         public static float GripPressureR => RightHand.isValid ? RightInput.Grip : 0;
    394.         public static float TriggerPressureR => RightHand.isValid ? RightInput.Trigger : 0;
    395.         public static float BatteryLevelR => RightHand.isValid ? RightInput.BatteryLevel : 0;
    396.  
    397.         #endregion
    398.    
    399.         #region unity event and init
    400.         public static void Init(GameObject go)
    401.         {
    402.             XrPresent = !LoadedDeviceName.Equals("");
    403.             if (!XrPresent) return;
    404.             go.AddComponent<VrInput>();
    405.         }
    406.    
    407.         private void OnEnable()
    408.         {
    409.             InputDevices.deviceConnected += Connected;
    410.             InputDevices.deviceDisconnected += Disconnected;
    411.        
    412.             HeadInput= new HeadsetInputs();
    413.             LeftInput = new ControllerInputs(HandType.Left);
    414.             RightInput = new ControllerInputs(HandType.Right);
    415.  
    416.             var controllers = FindObjectsOfType<XRController>();
    417.             foreach (var c in controllers)
    418.             {
    419.                 switch (c.controllerNode)
    420.                 {
    421.                     case XRNode.LeftHand:
    422.                         LeftXrController = c;
    423.                         break;
    424.                     case XRNode.RightHand:
    425.                         RightXrController = c;
    426.                         break;
    427.                 }
    428.             }
    429.  
    430.             HmdTrackedPoseDriver = FindObjectOfType<TrackedPoseDriver>();
    431.  
    432.             Debug.Log("Loaded hmd: "+ LoadedDeviceName);
    433.             // OpenVR Controller(Vive Controller MV) - Left
    434.             // OpenVR Controller(Knuckles EV3.0 Left) - Left
    435.         }
    436.  
    437.         private void OnDisable()
    438.         {
    439.             InputDevices.deviceConnected -= Connected;
    440.             InputDevices.deviceDisconnected -= Disconnected;
    441.         }
    442.  
    443.  
    444.         static void UpdateControllerObjects()
    445.         {
    446.             if (!Head.isValid)
    447.             {
    448.                 _headDevices = new List<InputDevice>();
    449.                 InputDevices.GetDevicesAtXRNode(XRNode.Head, _headDevices);
    450.            
    451.                 if (_headDevices.Count > 0)
    452.                 {
    453.                     Head = _headDevices[0];
    454.  
    455.                     foreach (var d in _headDevices)
    456.                     {
    457.                         Debug.Log("Head Device: " + d.name);
    458.                     }
    459.                
    460.                     HeadInput.SetDevice(Head);
    461.                 }
    462.                 else
    463.                     Debug.Log("No headset found!");
    464.            
    465.                 if(_headDevices.Count > 1)
    466.                     Debug.Log("Found more than one headset!");
    467.            
    468.             }
    469.  
    470.             if (!LeftHand.isValid)
    471.             {
    472.                 _leftHandDevices = new List<InputDevice>();
    473.                 InputDevices.GetDevicesAtXRNode(XRNode.LeftHand, _leftHandDevices);
    474.            
    475.                 if (_leftHandDevices.Count > 0)
    476.                 {
    477.                     LeftHand = _leftHandDevices[0];
    478.  
    479.                     foreach (var d in _leftHandDevices)
    480.                     {
    481.                         Debug.Log("Left Device: " + d.name);
    482.                     }
    483.            
    484.                     LeftInput.SetDevice(LeftHand);
    485.                 }
    486.                 else
    487.                     Debug.Log("No left hand found!");
    488.            
    489.                 if(_leftHandDevices.Count > 1)
    490.                     Debug.Log("Found more than one left hand!");
    491.             }
    492.        
    493.             if (!RightHand.isValid)
    494.             {
    495.                 _rightHandDevices = new List<InputDevice>();
    496.                 InputDevices.GetDevicesAtXRNode(XRNode.RightHand, _rightHandDevices);
    497.            
    498.                 if (_rightHandDevices.Count > 0)
    499.                 {
    500.                     foreach (var d in _rightHandDevices)
    501.                     {
    502.                         Debug.Log("Right Device: " + d.name);
    503.                     }
    504.            
    505.                     RightHand = _rightHandDevices[0];
    506.                     RightInput.SetDevice(RightHand);
    507.                 }
    508.                 else
    509.                     Debug.Log("No right hand found!");
    510.            
    511.                 if(_rightHandDevices.Count > 1)
    512.                     Debug.Log("Found more than one right hand!");
    513.             }
    514.         }
    515.  
    516.         private static void Connected(InputDevice device)
    517.         {
    518.             if (device == LeftHand) LeftControllerConnected = true;
    519.             if (device == RightHand) RightControllerConnected = true;
    520.         }
    521.    
    522.         private static void Disconnected(InputDevice device)
    523.         {
    524.             if (device == LeftHand) LeftControllerConnected = false;
    525.             if (device == RightHand) RightControllerConnected = false;
    526.         }
    527.  
    528.         void Update()
    529.         {
    530.             UpdateControllerObjects();
    531.        
    532.             if (Head.isValid) HeadInput.Update();
    533.             if (LeftHand.isValid) LeftInput.Update();
    534.             if (RightHand.isValid) RightInput.Update();
    535.        
    536.             //Debug.Log(" Right hand - Primary Axis: "+ Primary2DAxisR + " - Time: " + Time.realtimeSinceStartup);
    537.         }
    538.  
    539.  
    540.         #endregion
    541.  
    542.  
    543.         #region Merged GetKey methods
    544.         /// <summary>
    545.         /// Returns pressed state of key.
    546.         /// Checks controllers based on active headset
    547.         /// </summary>
    548.         public static bool GetKey(RiftKeyCodes rkey,ViveKeyCodes vkey, ViveKnuckleKeyCodes kKey, GearVrKeyCodes gKey,
    549.             HandType hand, GetKeyType type, bool useKnuckles)
    550.         {
    551.             if (!XrPresent) return false;
    552.        
    553.             switch (XRSettings.loadedDeviceName)
    554.             {
    555.                 case OpenVrDeviceName:
    556.                     return useKnuckles ? GetKey(kKey, hand, type) : GetKey(vkey, hand, type);
    557.                 case OculusDeviceName:
    558.                 case OculusDeviceNameB:
    559.                     return GetKey(rkey, hand,type);
    560.                 case GearVrDeviceName:
    561.                     return GetKey(gKey, hand,type);
    562.             }
    563.  
    564.             return false;
    565.         }
    566.  
    567.         public static bool GetKey(VrKeyCode inputs,GetKeyType type = GetKeyType.Get)
    568.         {
    569.             if (!XrPresent) return false;
    570.        
    571.             //Debug.Log(loadedDeviceName);
    572.             var riftHand = inputs.OculusHand;
    573.             var viveHand = inputs.ViveHand;
    574.             var knuckleHand = inputs.KnuclesHand;
    575.             var gearVrHand = inputs.GearVrHand;
    576.  
    577.             var riftKey = inputs.OculusKey;
    578.             var viveKey = inputs.ViveKey;
    579.             var kKey = inputs.KnuckleKey;
    580.             var gKey = inputs.GearVrKey;
    581.  
    582.             var useKnuckles = inputs.UseKnuckles;
    583.        
    584.             if (riftHand == viveHand &&
    585.                 knuckleHand == gearVrHand &&
    586.                 riftHand == knuckleHand)//if they use the same hand, use unified method
    587.             {
    588.                 return GetKey(riftKey, viveKey,kKey, gKey, riftHand, type, useKnuckles);
    589.             }
    590.  
    591.             switch (LoadedDeviceName)
    592.             {
    593.                 case OpenVrDeviceName:
    594.                     return useKnuckles ? GetKey(kKey, knuckleHand, type) :
    595.                         GetKey(viveKey, viveHand, type);
    596.                 case OculusDeviceName:
    597.                 case OculusDeviceNameB:
    598.                     return GetKey(riftKey, riftHand, type);
    599.                 case GearVrDeviceName:
    600.                     return GetKey(gKey, gearVrHand, type);
    601.                 default:
    602.                     return false;
    603.             }
    604.  
    605.         }
    606.         #endregion
    607.  
    608.         #region Oculus Public methods
    609.         public static  bool GetKey(RiftKeyCodes key,HandType hand)
    610.         {
    611.             return XrPresent && GetKey(key, hand, GetKeyType.Get);
    612.         }
    613.    
    614.         public static  bool GetKeyDown(RiftKeyCodes key,HandType hand)
    615.         {
    616.             return XrPresent && GetKey(key, hand, GetKeyType.GetDown);
    617.         }
    618.    
    619.         public static  bool GetKeyUp(RiftKeyCodes key,HandType hand)
    620.         {
    621.             return XrPresent && GetKey(key, hand, GetKeyType.GetUp);
    622.         }
    623.         #endregion
    624.    
    625.         #region vive Public methods
    626.         public static  bool GetKey(ViveKeyCodes key,HandType hand)
    627.         {
    628.             return XrPresent && GetKey(key, hand, GetKeyType.Get);
    629.         }
    630.    
    631.         public static  bool GetKeyDown(ViveKeyCodes key,HandType hand)
    632.         {
    633.             return XrPresent && GetKey(key, hand, GetKeyType.GetDown);
    634.         }
    635.    
    636.         public static  bool GetKeyUp(ViveKeyCodes key,HandType hand)
    637.         {
    638.             return XrPresent && GetKey(key, hand, GetKeyType.GetUp);
    639.         }
    640.         #endregion
    641.    
    642.         #region Vive Knuckle Public methods
    643.         public static  bool GetKey(ViveKnuckleKeyCodes key,HandType hand)
    644.         {
    645.             return XrPresent && GetKey(key, hand, GetKeyType.Get);
    646.         }
    647.    
    648.         public static  bool GetKeyDown(ViveKnuckleKeyCodes key,HandType hand)
    649.         {
    650.             return XrPresent && GetKey(key, hand, GetKeyType.GetDown);
    651.         }
    652.    
    653.         public static  bool GetKeyUp(ViveKnuckleKeyCodes key,HandType hand)
    654.         {
    655.             return XrPresent && GetKey(key, hand, GetKeyType.GetUp);
    656.         }
    657.         #endregion
    658.    
    659.         #region GearVr Public methods
    660.         public static  bool GetKey(GearVrKeyCodes key,HandType hand)
    661.         {
    662.             return XrPresent && GetKey(key, hand, GetKeyType.Get);
    663.         }
    664.    
    665.         public static  bool GetKeyDown(GearVrKeyCodes key,HandType hand)
    666.         {
    667.             return XrPresent && GetKey(key, hand, GetKeyType.GetDown);
    668.         }
    669.    
    670.         public static  bool GetKeyUp(GearVrKeyCodes key,HandType hand)
    671.         {
    672.             return XrPresent && GetKey(key, hand, GetKeyType.GetUp);
    673.         }
    674.         #endregion
    675.    
    676.         #region GetKey methods
    677.         static bool GetKey(InputBase.KeyData d, GetKeyType type)
    678.         {
    679.             switch (type)
    680.             {
    681.                 case GetKeyType.GetDown:
    682.                     return d.Down;
    683.                 case GetKeyType.GetUp:
    684.                     return d.Up;
    685.                 default:
    686.                     return d.Pressed;
    687.             }
    688.         }
    689.    
    690.    
    691.         static bool GetKey(RiftKeyCodes key,HandType hand, GetKeyType type)
    692.         {
    693.             if (!HandValid(hand) || key == RiftKeyCodes.None) return false;
    694.  
    695.             var device = hand == HandType.Left ? LeftInput : RightInput;
    696.  
    697.             if (!XrPresent) return SimGetKey(key, type);
    698.        
    699.             switch (key)
    700.             {
    701.                 case RiftKeyCodes.Trigger:
    702.                     return GetKey(device.TriggerButton, type);
    703.                 case RiftKeyCodes.Grip:
    704.                     return GetKey(device.GripButton, type);
    705.                 case RiftKeyCodes.Menu:
    706.                     return GetKey(device.MenuButton, type);
    707.                 case RiftKeyCodes.ButtonOne:
    708.                     return GetKey(device.PrimaryButton, type);
    709.                 case RiftKeyCodes.ButtonTwo:
    710.                     return GetKey(device.SecondaryButton, type);
    711.                 case RiftKeyCodes.ThumbStick:
    712.                     return GetKey(device.Primary2DAxisClick, type);
    713.  
    714.                 case RiftKeyCodes.ButtonOneTouch:
    715.                     return GetKey(device.PrimaryTouch, type);
    716.                 case RiftKeyCodes.ButtonTwoTouch:
    717.                     return GetKey(device.SecondaryTouch, type);
    718.            
    719.                 case RiftKeyCodes.ThumbStickTouch:
    720.                     return GetKey(device.Primary2DAxisTouch, type);
    721.             }
    722.  
    723.             return false;
    724.         }
    725.    
    726.         static bool GetKey(ViveKeyCodes key,HandType hand, GetKeyType type)
    727.         {
    728.             if (!HandValid(hand) || key == ViveKeyCodes.None) return false;
    729.  
    730.             var device = hand == HandType.Left ? LeftInput : RightInput;
    731.  
    732.             if (!XrPresent) return SimGetKey(key, type);
    733.        
    734.             switch (key)
    735.             {
    736.                 case ViveKeyCodes.Trigger:
    737.                     return GetKey(device.TriggerButton, type);
    738.                 case ViveKeyCodes.Grip:
    739.                     return GetKey(device.GripButton, type);
    740.                 case ViveKeyCodes.Menu:
    741.                     return GetKey(device.PrimaryButton, type);
    742.  
    743.                 case ViveKeyCodes.Trackpad:
    744.                     return GetKey(device.Primary2DAxisClick, type);
    745.            
    746.                 case ViveKeyCodes.TrackpadUp:
    747.                     return GetTrackpad(device, TrackpadDirection.Up, type);
    748.                 case ViveKeyCodes.TrackpadDown:
    749.                     return GetTrackpad(device, TrackpadDirection.Down, type);
    750.                 case ViveKeyCodes.TrackpadLeft:
    751.                     return GetTrackpad(device, TrackpadDirection.Left, type);
    752.                 case ViveKeyCodes.TrackpadRight:
    753.                     return GetTrackpad(device, TrackpadDirection.Right, type);
    754.            
    755.                 case ViveKeyCodes.TrackpadRightUp:
    756.                     return GetTrackpad(device, TrackpadDirection.RightUp, type);
    757.                 case ViveKeyCodes.TrackpadRightDown:
    758.                     return GetTrackpad(device, TrackpadDirection.RightDown, type);
    759.                 case ViveKeyCodes.TrackpadLeftUp:
    760.                     return GetTrackpad(device, TrackpadDirection.LeftUp, type);
    761.                 case ViveKeyCodes.TrackpadLeftDown:
    762.                     return GetTrackpad(device, TrackpadDirection.LeftDown, type);
    763.             }
    764.  
    765.             return false;
    766.         }
    767.    
    768.         static bool GetKey(ViveKnuckleKeyCodes key,HandType hand, GetKeyType type)
    769.         {
    770.             if (!HandValid(hand) || key == ViveKnuckleKeyCodes.None) return false;
    771.  
    772.             var device = hand == HandType.Left ? LeftInput : RightInput;
    773.  
    774.             if (!XrPresent) return SimGetKey(key, type);
    775.        
    776.             switch (key)
    777.             {
    778.                 case ViveKnuckleKeyCodes.Trigger:
    779.                     return GetKey(device.TriggerButton, type);
    780.                 case ViveKnuckleKeyCodes.Grip:
    781.                     return GetKey(device.GripButton, type);
    782.                 case ViveKnuckleKeyCodes.Primary:
    783.                     return GetKey(device.PrimaryButton, type);
    784.                 case ViveKnuckleKeyCodes.Alternate:
    785.                     return GetKey(device.SecondaryButton, type);
    786.            
    787.                 case ViveKnuckleKeyCodes.Joystick:
    788.                     return GetKey(device.Primary2DAxisClick, type);
    789.  
    790.                 case ViveKnuckleKeyCodes.JoystickTouch:
    791.                     return GetKey(device.Primary2DAxisTouch, type);
    792.             }
    793.  
    794.             return false;
    795.         }
    796.    
    797.         static bool GetKey(GearVrKeyCodes key,HandType hand, GetKeyType type)
    798.         {
    799.             if (!HandValid(hand) || key == GearVrKeyCodes.None) return false;
    800.  
    801.             var device = hand == HandType.Left ? LeftInput : RightInput;
    802.  
    803.             if (!XrPresent) return SimGetKey(key, type);
    804.        
    805.             switch (key)
    806.             {
    807.                 case GearVrKeyCodes.Trigger:
    808.                     return GetKey(device.TriggerButton, type);
    809.                 case GearVrKeyCodes.Touchpad:
    810.                     return GetKey(device.Primary2DAxisClick, type);
    811.                 case GearVrKeyCodes.TouchpadTouch:
    812.                     return GetKey(device.Primary2DAxisTouch, type);
    813.             }
    814.  
    815.             return false;
    816.         }
    817.         #endregion
    818.  
    819.         #region Sim GetKey methods
    820.         static bool SimGetKey(RiftKeyCodes key, GetKeyType type)
    821.         {
    822.             if (key == RiftKeyCodes.None) return false;
    823.  
    824.             switch (type)
    825.             {
    826.                 case GetKeyType.GetDown:
    827.                     return Input.GetKeyDown(GetSimKeyId(key));
    828.                 case GetKeyType.GetUp:
    829.                     return Input.GetKeyUp(GetSimKeyId(key));
    830.                 default:
    831.                     return Input.GetKey(GetSimKeyId(key));
    832.             }
    833.        
    834.         }
    835.    
    836.         static bool SimGetKey(ViveKeyCodes key, GetKeyType type)
    837.         {
    838.             if (key == ViveKeyCodes.None) return false;
    839.  
    840.             bool GetCombo(KeyCode a, KeyCode b)
    841.             {
    842.                 switch (type)
    843.                 {
    844.                     case GetKeyType.GetDown:
    845.                         return Input.GetKeyDown(a) && Input.GetKeyDown(b);
    846.                     case GetKeyType.GetUp:
    847.                         return Input.GetKeyUp(a) && Input.GetKeyUp(b);
    848.                     default:
    849.                         return Input.GetKey(a) && Input.GetKey(b);
    850.                 }
    851.             }
    852.  
    853.             switch (key)
    854.             {
    855.                 case ViveKeyCodes.TrackpadRightUp:
    856.                     return GetCombo(KeyCode.D, KeyCode.W);
    857.                 case ViveKeyCodes.TrackpadLeftDown:
    858.                     return GetCombo(KeyCode.A, KeyCode.S);
    859.                 case ViveKeyCodes.TrackpadLeftUp:
    860.                     return GetCombo(KeyCode.A, KeyCode.W);
    861.                 case ViveKeyCodes.TrackpadRightDown:
    862.                     return GetCombo(KeyCode.D, KeyCode.S);
    863.             }
    864.                
    865.             switch (type)
    866.             {
    867.                 case GetKeyType.GetDown:
    868.                     return Input.GetKeyDown(GetSimKeyId(key));
    869.                 case GetKeyType.GetUp:
    870.                     return Input.GetKeyUp(GetSimKeyId(key));
    871.                 default:
    872.                     return Input.GetKey(GetSimKeyId(key));
    873.             }
    874.         }
    875.    
    876.         static bool SimGetKey(ViveKnuckleKeyCodes key, GetKeyType type)
    877.         {
    878.             if (key == ViveKnuckleKeyCodes.None) return false;
    879.             switch (type)
    880.             {
    881.                 case GetKeyType.GetDown:
    882.                     return Input.GetKeyDown(GetSimKeyId(key));
    883.                 case GetKeyType.GetUp:
    884.                     return Input.GetKeyUp(GetSimKeyId(key));
    885.                 default:
    886.                     return Input.GetKey(GetSimKeyId(key));
    887.             }
    888.         }
    889.    
    890.         static bool SimGetKey(GearVrKeyCodes key, GetKeyType type)
    891.         {
    892.             if (key == GearVrKeyCodes.None) return false;
    893.             switch (type)
    894.             {
    895.                 case GetKeyType.GetDown:
    896.                     return Input.GetKeyDown(GetSimKeyId(key));
    897.                 case GetKeyType.GetUp:
    898.                     return Input.GetKeyUp(GetSimKeyId(key));
    899.                 default:
    900.                     return Input.GetKey(GetSimKeyId(key));
    901.             }
    902.         }
    903.         #endregion
    904.    
    905.         #region Simulator KeyId methods
    906.         static KeyCode GetSimKeyId(RiftKeyCodes key)
    907.         {
    908.             switch (key)
    909.             {
    910.                 case RiftKeyCodes.Trigger:
    911.                     return KeyCode.Mouse1;
    912.                 case RiftKeyCodes.Grip:
    913.                     return KeyCode.Mouse0;
    914.                 case RiftKeyCodes.Menu:
    915.                     return KeyCode.KeypadEnter;
    916.                 case RiftKeyCodes.ButtonOne:
    917.                     return KeyCode.E;
    918.                 case RiftKeyCodes.ButtonTwo:
    919.                     return KeyCode.Q;
    920.            
    921.                 case RiftKeyCodes.ThumbStick:
    922.                     return KeyCode.End;
    923.                 case RiftKeyCodes.ButtonOneTouch:
    924.                     return KeyCode.Alpha1;
    925.                 case RiftKeyCodes.ButtonTwoTouch:
    926.                     return KeyCode.Alpha3;
    927.                 case RiftKeyCodes.ThumbStickTouch:
    928.                     return KeyCode.X;
    929.             }
    930.  
    931.             return KeyCode.Mouse0;
    932.         }
    933.    
    934.         static KeyCode GetSimKeyId(ViveKeyCodes key)
    935.         {
    936.             switch (key)
    937.             {
    938.                 case ViveKeyCodes.Trigger:
    939.                     return KeyCode.Mouse1;
    940.                 case ViveKeyCodes.Grip:
    941.                     return KeyCode.Mouse0;
    942.                 case ViveKeyCodes.Menu:
    943.                     return KeyCode.KeypadEnter;
    944.  
    945.                 case ViveKeyCodes.Trackpad:
    946.                     return KeyCode.End;
    947.  
    948.                 case ViveKeyCodes.TrackpadUp:
    949.                     return KeyCode.W;
    950.                 case ViveKeyCodes.TrackpadDown:
    951.                     return KeyCode.S;
    952.                 case ViveKeyCodes.TrackpadLeft:
    953.                     return KeyCode.A;
    954.                 case ViveKeyCodes.TrackpadRight:
    955.                     return KeyCode.D;
    956.             }
    957.  
    958.             return KeyCode.Mouse0;
    959.         }
    960.    
    961.         static KeyCode GetSimKeyId(ViveKnuckleKeyCodes key)
    962.         {
    963.             switch (key)
    964.             {
    965.                 case ViveKnuckleKeyCodes.Trigger:
    966.                     return KeyCode.Mouse1;
    967.                 case ViveKnuckleKeyCodes.Grip:
    968.                     return KeyCode.Mouse0;
    969.                 case ViveKnuckleKeyCodes.Primary:
    970.                     return KeyCode.E;
    971.                 case ViveKnuckleKeyCodes.Alternate:
    972.                     return KeyCode.Q;
    973.            
    974.                 case ViveKnuckleKeyCodes.Joystick:
    975.                     return KeyCode.End;
    976.                 case ViveKnuckleKeyCodes.JoystickTouch:
    977.                     return KeyCode.X;
    978.             }
    979.  
    980.             return KeyCode.Mouse0;
    981.         }
    982.    
    983.         static KeyCode GetSimKeyId(GearVrKeyCodes key)
    984.         {
    985.             switch (key)
    986.             {
    987.                 case GearVrKeyCodes.Trigger:
    988.                     return KeyCode.Mouse1;
    989.                 case GearVrKeyCodes.Touchpad:
    990.                     return KeyCode.End;
    991.                 case GearVrKeyCodes.TouchpadTouch:
    992.                     return KeyCode.X;
    993.             }
    994.  
    995.             return KeyCode.Mouse0;
    996.         }
    997.    
    998.         static Vector2 GetSim2DAxis()
    999.         {
    1000.             float x = 0, y = 0;
    1001.        
    1002.             if (Input.GetKey(KeyCode.D))
    1003.             {
    1004.                 x = -1;
    1005.             }
    1006.             else if (Input.GetKey(KeyCode.A))
    1007.             {
    1008.                 x = 1;
    1009.             }
    1010.        
    1011.             if (Input.GetKey(KeyCode.S))
    1012.             {
    1013.                 y = -1;
    1014.             }
    1015.             else if (Input.GetKey(KeyCode.W))
    1016.             {
    1017.                 y = 1;
    1018.             }
    1019.  
    1020.             return new Vector2(x, y);
    1021.         }
    1022.    
    1023.         static float GetSim1DAxis()
    1024.         {
    1025.             float y = 0;
    1026.        
    1027.             if (Input.GetKey(KeyCode.UpArrow))
    1028.             {
    1029.                 y = -1;
    1030.             }
    1031.             else if (Input.GetKey(KeyCode.DownArrow))
    1032.             {
    1033.                 y = 1;
    1034.             }
    1035.  
    1036.             return y;
    1037.         }
    1038.         #endregion
    1039.  
    1040.         #region Trackpad methods
    1041.         static bool GetTrackpad(ControllerInputs device,TrackpadDirection dir, GetKeyType type)
    1042.         {
    1043.  
    1044.             switch (type)
    1045.             {
    1046.                 case GetKeyType.Get:
    1047.                     if (!device.Primary2DAxisClick.Pressed) return false;
    1048.                     break;
    1049.                 case GetKeyType.GetDown:
    1050.                     if (!device.Primary2DAxisClick.Down) return false;
    1051.                     break;
    1052.                 case GetKeyType.GetUp:
    1053.                     if (!device.Primary2DAxisClick.Up) return false;
    1054.                     break;
    1055.             }
    1056.        
    1057.             return GetTrackpadDirection(device.Primary2DAxis, dir);
    1058.         }
    1059.  
    1060.         static bool GetTrackpadDirection(Vector2 curAxis,TrackpadDirection dir)
    1061.         {
    1062.             switch (dir)
    1063.             {
    1064.                 case TrackpadDirection.Left:
    1065.                     //if left and not a diagonal
    1066.                     if (curAxis.x < -0.65f &&
    1067.                         curAxis.y < 0.65f && curAxis.y > -0.65f)
    1068.                     {
    1069.                         //Debug.Log("Trackpad - Pressed Left");
    1070.                         return true;
    1071.                     }
    1072.                     break;
    1073.                 case TrackpadDirection.Right:
    1074.                     //if right and not a diagonal
    1075.                     if (curAxis.x > 0.65f &&
    1076.                         curAxis.y < 0.65f && curAxis.y > -0.65f)
    1077.                     {
    1078.                         //Debug.Log("Trackpad - Pressed Right");
    1079.                         return true;
    1080.                     }
    1081.                     break;
    1082.                 case TrackpadDirection.Up:
    1083.                     //if up and not a diagonal
    1084.                     if (curAxis.y > 0.65f &&
    1085.                         curAxis.x > -0.65f && curAxis.x < 0.65f)
    1086.                     {
    1087.                         //Debug.Log("Trackpad - Pressed up");
    1088.                         return true;
    1089.                     }
    1090.                     break;
    1091.                 case TrackpadDirection.Down:
    1092.                     //if down and not a diagonal
    1093.                     if (curAxis.y < -0.65f &&
    1094.                         curAxis.x > -0.65f && curAxis.x < 0.65f)
    1095.                     {
    1096.                         //Debug.Log("Trackpad - Pressed Down");
    1097.                         return true;
    1098.                     }
    1099.                     break;
    1100.                 case TrackpadDirection.LeftUp:
    1101.                     if (curAxis.x < -0.65f && curAxis.y > 0.65f)
    1102.                     {
    1103.                         //Debug.Log("Trackpad - Pressed LeftUp");
    1104.                         return true;
    1105.                     }
    1106.                     break;
    1107.                 case TrackpadDirection.RightUp:
    1108.                     if (curAxis.x > 0.65f && curAxis.y > 0.65f)
    1109.                     {
    1110.                         //Debug.Log("Trackpad - Pressed RightUp");
    1111.                         return true;
    1112.                     }
    1113.                     break;
    1114.                 case TrackpadDirection.LeftDown:
    1115.                     if (curAxis.x < -0.4f && curAxis.y < -0.65f)
    1116.                     {
    1117.                         //Debug.Log("Trackpad - Pressed LeftDown");
    1118.                         return true;
    1119.                     }
    1120.                     break;
    1121.                 case TrackpadDirection.RightDown:
    1122.                     if (curAxis.x > 0.4f && curAxis.y < -0.65f)
    1123.                     {
    1124.                         //Debug.Log("Trackpad - Pressed RightDown");
    1125.                         return true;
    1126.                     }
    1127.                     break;
    1128.             }
    1129.        
    1130.             return false;
    1131.         }
    1132.         #endregion
    1133.  
    1134.         #region Haptics
    1135.  
    1136.         public static void HapticImpulse(HandType hand,float amplitude = 0.5f, float duration = 0.2f, uint channel = 0)
    1137.         {
    1138.             if (!XrPresent) return;
    1139.             Impulse(hand == HandType.Left ? LeftHand : RightHand, amplitude, duration, channel);
    1140.         }
    1141.  
    1142.         static void Impulse(InputDevice device,float amplitude, float duration, uint channel)
    1143.         {
    1144.             if (!device.TryGetHapticCapabilities(out var capabilities)) return;
    1145.             if (capabilities.supportsImpulse)
    1146.             {
    1147.                 device.SendHapticImpulse(channel, amplitude, duration);
    1148.             }
    1149.         }
    1150.  
    1151.         #endregion
    1152.    
    1153.         static bool HandValid(HandType hand)
    1154.         {
    1155.             switch (hand)
    1156.             {
    1157.                 case HandType.Left:
    1158.                     return LeftHand.isValid;
    1159.                 default:
    1160.                     return RightHand.isValid;
    1161.             }
    1162.         }
    1163.     }
    1164.  
    1165.     [System.Serializable]
    1166.     public class VrKeyCode
    1167.     {
    1168.         public bool UseKnuckles = true;
    1169.    
    1170.         public RiftKeyCodes OculusKey = RiftKeyCodes.Trigger;
    1171.         public ViveKeyCodes ViveKey = ViveKeyCodes.Trigger;
    1172.         public ViveKnuckleKeyCodes KnuckleKey = ViveKnuckleKeyCodes.Trigger;
    1173.         public GearVrKeyCodes GearVrKey = GearVrKeyCodes.Trigger;
    1174.    
    1175.         public HandType OculusHand = HandType.Right;
    1176.         public HandType ViveHand = HandType.Right;
    1177.         public HandType KnuclesHand = HandType.Right;
    1178.         public HandType GearVrHand = HandType.Right;
    1179.    
    1180.    
    1181.         public bool ExpandInEditor = true;
    1182.     }
    1183.  
    1184. }
    1185.  
    1186.  
    Editor code example:

    Code (CSharp):
    1.                         EditorGUILayout.LabelField(varName);
    2.                    
    3.                         if(!i.VrKeyCode.ExpandInEditor) return;
    4.  
    5.                         EditorGUILayout.BeginVertical("box");
    6.                    
    7.  
    8.                         BoolSelector(ref i.VrKeyCode.UseKnuckles, "Use Vive knuckle mapping",150);
    9.                    
    10.                         EditorGUILayout.BeginHorizontal("helpbox");
    11.                         EditorGUILayout.LabelField("Oculus", GUILayout.Width(90));
    12.                         i.VrKeyCode.OculusKey = (RiftKeyCodes) EditorGUILayout.EnumPopup(i.VrKeyCode.OculusKey);
    13.                         EditorGUILayout.LabelField("Hand", GUILayout.Width(40));
    14.                         i.VrKeyCode.OculusHand = (HandType) EditorGUILayout.EnumPopup(i.VrKeyCode.OculusHand);
    15.                         EditorGUILayout.EndHorizontal();
    16.  
    17.                         if (i.VrKeyCode.UseKnuckles)
    18.                         {
    19.                             EditorGUILayout.BeginHorizontal("helpbox");
    20.                             EditorGUILayout.LabelField("Vive Knuckles", GUILayout.Width(90));
    21.                             i.VrKeyCode.KnuckleKey = (ViveKnuckleKeyCodes) EditorGUILayout.EnumPopup(i.VrKeyCode.KnuckleKey);
    22.                             EditorGUILayout.LabelField("Hand", GUILayout.Width(40));
    23.                             i.VrKeyCode.KnuclesHand = (HandType) EditorGUILayout.EnumPopup(i.VrKeyCode.KnuclesHand);
    24.                             EditorGUILayout.EndHorizontal();
    25.                         }
    26.                         else
    27.                         {
    28.                             EditorGUILayout.BeginHorizontal("helpbox");
    29.                             EditorGUILayout.LabelField("Vive", GUILayout.Width(90));
    30.                             i.VrKeyCode.ViveKey = (ViveKeyCodes) EditorGUILayout.EnumPopup(i.VrKeyCode.ViveKey);
    31.                             EditorGUILayout.LabelField("Hand", GUILayout.Width(40));
    32.                             i.VrKeyCode.ViveHand = (HandType) EditorGUILayout.EnumPopup(i.VrKeyCode.ViveHand);
    33.                             EditorGUILayout.EndHorizontal();
    34.                         }
    35.  
    36.                         EditorGUILayout.BeginHorizontal("helpbox");
    37.                         EditorGUILayout.LabelField("GearVr", GUILayout.Width(90));
    38.                         i.VrKeyCode.GearVrKey = (GearVrKeyCodes) EditorGUILayout.EnumPopup(i.VrKeyCode.GearVrKey);
    39.                         EditorGUILayout.LabelField("Hand", GUILayout.Width(40));
    40.                         i.VrKeyCode.GearVrHand = (HandType) EditorGUILayout.EnumPopup(i.VrKeyCode.GearVrHand);
    41.                         EditorGUILayout.EndHorizontal();
    42.                    
    43.                         EditorGUILayout.EndVertical();
    Code (CSharp):
    1.         public static void BoolSelector(ref bool var, string varName = "", float width = -1)
    2.         {
    3.             string[] options = {"True","False"};
    4.             int selected = var ? 0 : 1;
    5.  
    6.             if (width <= 0)
    7.             {
    8.                 selected = varName.Equals("")
    9.                     ? EditorGUILayout.Popup(selected, options)
    10.                     : EditorGUILayout.Popup(varName, selected, options);
    11.             }
    12.             else
    13.             {
    14.                 if (varName.Equals(""))
    15.                 {
    16.                     selected = EditorGUILayout.Popup(selected, options, GUILayout.Width(width));
    17.                 }
    18.                 else
    19.                 {
    20.                     EditorGUILayout.BeginHorizontal();
    21.                     {
    22.                         EditorGUILayout.LabelField(varName, GUILayout.Width(width));
    23.                         selected = EditorGUILayout.Popup(selected, options);
    24.                     }
    25.                     EditorGUILayout.EndHorizontal();
    26.                 }
    27.             }
    28.  
    29.  
    30.             var = selected == 0;
    31.         }
    You got to call the VrInput.Init(gameObject); method in your PersistentEngine or GameEngine script (or delete that and just added it to your GameEngine object I guess).
     
    Last edited: May 8, 2020
  5. Alverik

    Alverik

    Joined:
    Apr 15, 2016
    Posts:
    417
    Haven't used it in a while but it would go like this:

    Code (CSharp):
    1.      
    2. var hand = HandType.Left;
    3.  
    4. var gripInput = new VrKeyCode
    5.             {
    6.                 OculusKey = RiftKeyCodes.Grip,
    7.                 ViveKey = ViveKeyCodes.Grip,
    8.                 KnuckleKey = ViveKnuckleKeyCodes.Grip,
    9.                 GearVrKey = GearVrKeyCodes.Touchpad,
    10.                 OculusHand = hand,
    11.                 ViveHand = hand,
    12.                 KnuclesHand = hand,
    13.                 GearVrHand = hand
    14.             };
    15.  
    16.                 if (VrInput.GetKey(gripInput, GetKeyType.GetDown))
    17.                 {
    18.     //grip press down
    19.                 }
    20.  
    21.  
    The intention is you can select different buttons on different devices (and different hands), and get a different result based on the device connected. And you can make the keycode public so you can select the buttons and hands per device on your script, or change them via UI, etc. (But there are some static methods to check specific devices too).
    Hope later I can fix it so it knows if you are using the Vive knuckles right away (probably verifying the device names at the beginning too).

    And haptics:

    Code (CSharp):
    1.  
    2.  
    3. var amplitud = .5f;
    4. var duration = .2f;
    5. var channel = 0;
    6.  
    7. VrInput.HapticImpulse(Hand, amplitude, duration, (uint) channel);
    8.  
     
    Last edited: May 8, 2020
    Hal9000QAQ likes this.
  6. wpetillo

    wpetillo

    Joined:
    May 23, 2017
    Posts:
    24
    Here is a simple way to get XR input on the Oculus Quest, haven't tested yet if it also works on Vive. First getting basic button presses:

    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3. using UnityEngine.Events;
    4. using UnityEngine.XR;
    5. using UnityEngine.XR.Interaction.Toolkit;
    6.  
    7. [Serializable] public class BoolEvent : UnityEvent<bool> { }
    8.  
    9. public class XRInput : MonoBehaviour
    10. {
    11.     [SerializeField] XRController controller;      
    12.     [SerializeField] XRBinding[] bindings;
    13.              
    14.     void Update()
    15.     {            
    16.         foreach (var binding in bindings)
    17.             binding.Update(controller.inputDevice);
    18.     }
    19. }
    20.  
    21. [Serializable]
    22. public class XRBinding
    23. {
    24.     [SerializeField] XRButton button;
    25.     [SerializeField] PressType condition;
    26.     [SerializeField] UnityEvent OnActive;
    27.  
    28.     bool isPressed;
    29.     bool wasPressed;
    30.  
    31.     public void Update(InputDevice device)
    32.     {
    33.         device.TryGetFeatureValue(XRStatics.GetFeature(button), out isPressed);
    34.      
    35.         switch (condition)
    36.         {
    37.             case PressType.Continuous: if (isPressed) OnActive.Invoke(); break;
    38.             case PressType.Begin: if (isPressed && !wasPressed) OnActive.Invoke(); break;
    39.             case PressType.End: if (!isPressed && wasPressed) OnActive.Invoke(); break;
    40.         }
    41.      
    42.         wasPressed = isPressed;
    43.     }
    44. }
    45.  
    46. public static class XRStatics
    47. {
    48.     public static InputFeatureUsage<bool> GetFeature(XRButton button)
    49.     {
    50.         switch (button)
    51.         {
    52.             case XRButton.Trigger: return CommonUsages.triggerButton;
    53.             case XRButton.Grip: return CommonUsages.gripButton;
    54.             case XRButton.Primary: return CommonUsages.primaryButton;
    55.             case XRButton.PrimaryTouch: return CommonUsages.primaryTouch;
    56.             case XRButton.Secondary: return CommonUsages.secondaryButton;
    57.             case XRButton.SecondaryTouch: return CommonUsages.secondaryTouch;
    58.             case XRButton.Primary2DAxisClick: return CommonUsages.primary2DAxisClick;
    59.             case XRButton.Primary2DAxisTouch: return CommonUsages.primary2DAxisTouch;
    60.             case XRButton.Thumbrest: return CommonUsages.thumbrest;
    61.             case XRButton.Menu: return CommonUsages.menuButton;
    62.             default: Debug.LogError(button + " not found"); return CommonUsages.primaryButton;
    63.         }
    64.     }
    65. }
    66.  
    67. public enum PressType
    68. {
    69.     Begin, End, Continuous
    70. }
    71.  
    72. public enum XRButton
    73. {
    74.     Trigger,
    75.     Grip,
    76.     Primary,
    77.     PrimaryTouch,
    78.     Secondary,
    79.     SecondaryTouch,
    80.     Primary2DAxisClick,
    81.     Primary2DAxisTouch,
    82.     Thumbrest,
    83.     Menu
    84. }
    Setup by attaching this script as a component to any object and drop in a hand object that has an XRController component attached. Assign as many bindings as you like. For each binding, select which button to use and whether to respond on the first frame of a press (or touch), the last frame, or every frame.

    Next, getting joystick position:

    Code (CSharp):
    1.  
    2. using System;
    3. using UnityEngine;
    4. using UnityEngine.Events;
    5. using UnityEngine.XR;
    6. using UnityEngine.XR.Interaction.Toolkit;
    7.  
    8. [Serializable] public class Vector2Event : UnityEvent<Vector2> { }
    9.  
    10. public class XRInput2D : MonoBehaviour
    11. {
    12.     [SerializeField] XRController controller;    
    13.     [SerializeField] Vector2Event OnActive;
    14.    
    15.     Vector2 value;
    16.                
    17.     public void GetAxisValue()
    18.     {      
    19.         controller.inputDevice.TryGetFeatureValue(CommonUsages.primary2DAxis, out value);
    20.         OnActive.Invoke(value);
    21.     }
    22. }
    23.  
    Setup by attaching to any object, preferably the same as XRInput. Create a binding in XRInput setting the button field to Primary2DAxisTouch or Primary2DAxisClick, the condition field to Continuous, and calling XRInput2D.GetAxisValue(). Whenever there is input, XRInput2D will then send out the Vector2 value via OnActive.
     
    Last edited: May 11, 2020
    FloBeber, wm-VR and appels like this.
  7. Reahreic

    Reahreic

    Joined:
    Mar 23, 2011
    Posts:
    254
    I've implemented a system for detecting and configuring controllers in my project using InputDevices.deviceConnected, and it's been working great from the editor (2019.2.11f1). Unfortunately, deviceConnected is never called from builds. If a (Vive) controller is off when the app is launched, it'll never be detected until you completely restart the app with the controller already powered on.

    @StayTalm_Unity Is there something i'm missing?

    Code (CSharp):
    1.  
    2. private List<InputDevice> allInputDevices = new List<InputDevice>();
    3.  
    4. //Called once from a singleton game manager after splash screens are initialized.
    5. public void Initialize() {
    6.     XRDevice.SetTrackingSpaceType(TrackingSpaceType.RoomScale);
    7.  
    8.     GetInputDevices();
    9.  
    10.     InputDevices.deviceConnected += OnInputDeviceConnected;
    11.     InputDevices.deviceDisconnected += OnInputDeviceDisconnected;
    12. }
    13.  
    14. private void GetInputDevices() {
    15.     InputDevices.GetDevices(allInputDevices);
    16.  
    17.     for (int i = 0; i < allInputDevices.Count; i++) {
    18.         SortInputDevice(allInputDevices[i]);
    19.     }
    20.    
    21.     allInputDevices.Clear();
    22. }
    23.  
    24. private void OnInputDeviceConnected(InputDevice obj) {
    25.     SortInputDevice(obj);
    26. }
    27.  
    28. private void OnInputDeviceDisconnected(InputDevice obj) {
    29.     if(obj == null) { return; }
    30.    
    31.     //Unload associated visuals and events.
    32.    
    33.     Debug.Log("Disconnected Device: " + obj.name + " of role: " + obj.role);
    34. }
    35.  
    36. private void SortInputDevice(InputDevice obj) {
    37.     //Sorts input device by role and configures visuals & control mapping as required
    38. }
    39.  
     
  8. RetroFlight

    RetroFlight

    Joined:
    Nov 16, 2019
    Posts:
    41
    Thanks for posting all of this... I have a question on how you would use it in another script. How would you, say, write an if statement for the trigger being pulled? I have spent the whole day trying to figure it out before asking. I am good with basic C# but still very green.

    Thanks!
     
  9. wpetillo

    wpetillo

    Joined:
    May 23, 2017
    Posts:
    24
    You wouldn't. The point of the UnityEvent based approach that the script using is to prevent other scripts from being dependent on your input system--or your input system dependent on other game logic. Instead, have public methods in your other scripts that respond to trigger presses (at the beginning of the press, the end, or continuously each frame), and connect them to the input component via the inspector.

    The advantages of a decoupled approach are that it allows for re-usability (for example, an AI character, a player with a VR trackpad, and a regular keyboard to all share the same logic for movement, animation, etc.) and makes it possible to limit the scope of a script so that once it is fully tested, streamlined, and fleshed out to include low-hanging variations it is DONE and never has to be edited or really thought about much again--because any additional features are out of scope and better added through a separate script.

    As an example, here is a link to an open-source character controller I am working on: https://github.com/Will9371/Character-Template/tree/master/Assets/Playcraft/VR. Parts of the repo are very much a work in progress (especially the 3rd person animations), but nearly all of it follows the same pattern, and the section I linked to includes controlling a third person humanoid character with the joystick on a Quest (like in Moss).
     
  10. Reahreic

    Reahreic

    Joined:
    Mar 23, 2011
    Posts:
    254
    Integrated with the singleton detection script i previously posted we register and manage controller events from anywhere using helper methods for the event type. (Button, Trigger, Touchpad) Essentially having one start and one end 'listening for event' method that's responsible for initializing the actual event attachment. This allows us to keep a list of registered events so that we can apply them automagically to a newly added/reconnected controller as part of it's initialization.

    Because we keep a tracked list of active controllers, when we call the method to attach the event we identify the controller via it's 'handedness' (left, right, both), which component (button, trigger, touchpad) we wan't to listen to using it's 'identity', the specific component event we want to listen for, and a callback method.

    Our Controller classes (Base, Derived), which are what is initialized and tracked as the 'controller' in my first paragraph, is then responsible for listening to the physical device, broadcasting it's list of active events, and managing it's own visual model.

    It's a tad more complicated that just directly tying into a controller, but it works well for handling controllers in a platform agnostic way allowing me to not need to revisit this part of the code as i develop my application. And if i add a new VR platform, i don't need to go back and anything in my game except add a new controller type.

    I can't paste all the code here as the UserInputModule is not open source (up to our client) and around 3k lines of code, but the above should give you a high level idea to work with, and the below is the basic 'controller level' functionality. (took like 60 mins to extract from our module)

    Example:
    Code (CSharp):
    1. //Acquire device tracking data value example, Look into 'UnityEngine.XR.CommonUsages' for all the things you could listen for
    2. Vector3 pos = Vector3.zero;
    3. if (!UnityEngine.XR.InputDevice.TryGetFeatureValue(UnityEngine.XR.CommonUsages.devicePosition, out pos)) {
    4.     Debug.LogWarning("Unable to get feature: '" + UnityEngine.XRCommonUsages.devicePosition.ToString());
    5. }
    6.          
    7. //Acquire state for button identified by  identity -> UnityEngine.XR.CommonUsages.primaryButton
    8. bool buttonState = false;
    9. if (UnityEngine.XR.InputDevice.TryGetFeatureValue(identity, out outState)) {
    10.     Debug.LogWarning("Unable to get feature: '" + UnityEngine.XRCommonUsages.primaryButton.ToString());
    11. }
    12.  
    13. //Acquire state for trigger.
    14. //Note the trigger can respond as both a slider (float) and a button (bool), depending on which identity you use
    15. //identity -> UnityEngine.XR.CommonUsages.trigger or .triggerButton
    16. float triggerState = 0f;
    17. if (parent.device.TryGetFeatureValue(identity, out outState)) {
    18.     Debug.LogWarning("Unable to get feature: '" + UnityEngine.XRCommonUsages.trigger .ToString());
    19. }
    20.  
    21. //Touchpad support is a essentially the same see the 'TryGetCustomTouchpadValues' method below, however because we detect gesture, touch and position, press and press position with it we had to extend it's identity to handle the different input methods being tracked and their return data types. (bool, vector3, customGestureEnum)
    22.  
    23. //As such the below is an excerpt and won't work for you as-is, but should give you a mental model to work from.
    24. public class ControllerTouchPad{
    25.     public Action<ControllerTouchPad> OnStartTouch;
    26.     private void OnTouchPadStartTouch() {
    27.         OnStartTouch?.Invoke(this);
    28.     }
    29.  
    30.     private TouchPadEventData _currentState = TouchPadEventData.none;
    31.     public new TouchPadEventData state {
    32.         get {
    33.             return _currentState;
    34.         }
    35.         private set {
    36.             //Ensures changes can be determined prior to updating values for simultaneous events
    37.             bool isStartTouch = value.isTouching && !_currentState.isTouching;
    38.             bool isTouching = value.isTouching && _currentState.isTouching;
    39.             bool isEndTouch = !value.isTouching && _currentState.isTouching;
    40.          
    41.             bool posChanged = value.touchPosition != _currentState.touchPosition;
    42.  
    43.             bool isStartPress = value.isPressing && !_currentState.isPressing;
    44.             bool isPressing = value.isPressing && _currentState.isPressing;
    45.             bool isEndPress = !value.isPressing && _currentState.isPressing;
    46.  
    47.             _currentState = value;
    48.  
    49.             if (isStartTouch) {
    50.                 //OnTouchPadStartTouch();
    51.  
    52.             } else if (isTouching) {
    53.                 //OnTouchPadTouching();
    54.  
    55.             if (posChanged) {
    56.                 //OnTouchPadPositionChange(); <- this is where you can detect gestures such as swiping
    57.             }
    58.  
    59.             } else if (isEndTouch) {
    60.                 //OnTouchPadEndTouch();
    61.             }
    62.  
    63.             if (isStartPress) {
    64.                 //OnTouchPadPress();
    65.  
    66.             } else if (isPressing) {
    67.                 //OnTouchPadHeldDown();
    68.  
    69.             } else if (isEndPress) {
    70.                 //OnTouchPadRelease();
    71.             }
    72.         }
    73.     }
    74.  
    75.     private update(){
    76.         state = TryGetCustomTouchpadValues();
    77.     }
    78.     private TouchPadEventData TryGetCustomTouchpadValues() {
    79.         bool touchState = false;
    80.         supportsTouch = parent.device.TryGetFeatureValue(CommonUsages.primary2DAxisTouch, out touchState);
    81.  
    82.         bool pressState = false;
    83.         supportsPress = parent.device.TryGetFeatureValue(CommonUsages.primary2DAxisClick, out pressState);
    84.  
    85.         Vector2 touchPos = Vector2.zero;
    86.         supportsPosition = parent.device.TryGetFeatureValue(CommonUsages.primary2DAxis, out touchPos);
    87.  
    88.         return new TouchPadEventData(touchState, pressState, touchPos, GetTouchpadQuadrant(touchPos), state.gesture);
    89.     }
    90. }
    Edit: Fixed a stupid
     
    Last edited: Jun 12, 2020
  11. Riiich

    Riiich

    Joined:
    Sep 30, 2014
    Posts:
    19
    How do you handle controller disconnects? :D
     
  12. josrodes

    josrodes

    Joined:
    Nov 15, 2017
    Posts:
    10
    Code (CSharp):
    1.  
    2.     private void Awake()
    3.     {
    4.         InputDevices.deviceConnected += InputDevices_deviceConnected;
    5.         InputDevices.deviceDisconnected += InputDevices_deviceDisconnected;
    6.         InputDevices.deviceConfigChanged += InputDevices_deviceConfigChanged;
    7.     }
    8.  
    9.     private void OnDestroy()
    10.     {
    11.         InputDevices.deviceConnected -= InputDevices_deviceConnected;
    12.         InputDevices.deviceDisconnected -= InputDevices_deviceDisconnected;
    13.         InputDevices.deviceConfigChanged -= InputDevices_deviceConfigChanged;
    14.     }
    15.  
    16.     private void InputDevices_deviceDisconnected(InputDevice device)
    17.     {
    18.         CheckForControllers();
    19.     }
    20.  
    21.     private void InputDevices_deviceConfigChanged(InputDevice device)
    22.     {
    23.         CheckForControllers();
    24.     }
    25.  
    26.     private void InputDevices_deviceConnected(InputDevice device)
    27.     {
    28.         CheckForControllers();
    29.     }
    30.  
    31.    
    32. public void CheckForControllers()
    33.     {
    34.         bool controllerFound = false;
    35.  
    36.         List<InputDevice> leftHandDevices = new List<InputDevice>();
    37.         InputDevices.GetDevicesWithCharacteristics(InputDeviceCharacteristics.Left, leftHandDevices);
    38.  
    39.         if (leftHandDevices.Count > 0)
    40.         {
    41.             controllerFound = true;
    42.         }
    43.        
    44.         List<InputDevice> rightHandDevices = new List<InputDevice>();
    45.         InputDevices.GetDevicesWithCharacteristics(InputDeviceCharacteristics.Right, rightHandDevices);
    46.         if (rightHandDevices.Count > 0)
    47.         {
    48.             controllerFound = true;
    49.         }
    50.        
    51.         if (!controllerFound)
    52.         {
    53.             //A controller is required, please reconnect to continue;
    54.         }
    55.     }
     
    Riiich and HeyBishop like this.
  13. stevendimmerse

    stevendimmerse

    Joined:
    Aug 7, 2018
    Posts:
    9
    This doesn't seem to be working on quest atm for the Stationary mode

    subSystem.GetTrackingOriginMode() == TrackingOriginModeFlags.Device is false

    XRDevice.GetTrackingSpaceType() == TrackingSpaceType.Stationary this is true

    For now im just using GetTrackingSpaceType

    using 2019.4.3 with xr 1.0.1 and oculus xr 1.4.0
     
  14. skidvis

    skidvis

    Joined:
    Jun 3, 2017
    Posts:
    18
    Hi, This sounds like a great idea.. can you provide an example of how you did this?

    [edit] I seem to have figured it out.. Is this how you do it?
    Code (CSharp):
    1. var _teleportationProvider = GetComponent<TeleportationProvider>();
    2. var teleportRequest = new TeleportRequest();
    3. teleportRequest.destinationPosition = newPosition.transform.position;
    4. _teleportationProvider.QueueTeleportRequest(teleportRequest);
     
    Last edited: Aug 2, 2020
  15. john_primitive

    john_primitive

    Joined:
    Jan 4, 2019
    Posts:
    7
    @StayTalm_Unity first of all: thank you for all of your hard work on this. I've been in VR for 5 years now and have been waiting for a unified input system. This is a dream come true in terms of code reduction.

    Question:
    I'm seeing the same concern raised multiple times here and not getting addressed. So far I've only had success getting trigger events for Oculus Quest. My OpenVR Controller (Vive MV) is only reporting that it has useages for properties like DevicePosition, Rotation, Velocity etc. but NO buttons or trigger. The same goes for my Oculus Touch controller.

    Are these input devices currently in a state of flux? Are they working under certain versions of SteamVR and Oculus Runtime but not others? I've tried a lot of testing across multiple devices and can't seem to crack it. Thank you.

    For reference, I'm using your approach for deviceConnected and TryGetFeatureValue (literally copy paste from your PrimaryButtonWatcher example). Help from anyone at this point is much appreciated.
     
  16. mobfish_cai

    mobfish_cai

    Joined:
    May 3, 2018
    Posts:
    23
    Looking for information and saw this. I'm surprised that both Unity and Oculus hasn't make it official bug yet.

    @john_primitive The new Input System, relys on XR provider's implementation to get it working. And almost none of the providers use the Unity Standard, that's why some inputs are working, some are not, and it seems it works with a very very weird way.

    Take Oculus Touch as example. In code implementation, aka DeviceLayouts.cs, the OculusTouchController class indicated that "triggerPressed" is the ButtonControl, with alias indexButton. However, you won't get any feedback using these names, although they're written in code. You can list all the "available" controls for a device in runtime by using this:

    Code (CSharp):
    1.        
    2. public static List<string> GetValidInputControl(UnityEngine.InputSystem.InputDevice testId)
    3.         {
    4.             List<string> result = new List<string>();
    5.             result.Add(testId.name);
    6.             foreach (InputControl ic in testId.children)
    7.             {
    8.                 result.Add("- " + ic.name + " ; " + ic.valueType);
    9.             }
    10.  
    11.             return result;
    12.         }
    13.  
    And you'll find many other names are in the list, in runtime, and it's totally different than what they are in Editor c# code.

    The correct way to access trigger button for Oculus Touch is:

    ((ButtonControl)XRController.rightHand["triggerpressed"]).isPressed
    //Assume none of these are null.

    And the only way to get it to work, is to use string as key, in this case, "triggerpressed". I didn't find any other way to do this.

    And different vendor has different key names. In Wave XR SDK which I worked on, it is "rightcontrollertriggerbutton" for right hand. I havent encountered an XR Management implementation, worked with "triggerPressed".

    As for OpenVR, they already said they don't support this, you have to use the traditional way.
     
    Last edited: Aug 27, 2020
    john_primitive likes this.
  17. DevJeeth

    DevJeeth

    Joined:
    Mar 26, 2019
    Posts:
    1
    Oculus, as well as steamVR, shows my controllers as connected and I can see my oculus controllers been tracked in the unity scene(Editor). But When I check XR devices I am not getting the controllers just the HMD. I remember getting it initially quite a while back. Is there some particular player settings that needs to be set.


    Code (CSharp):
    1. //Getting XR input devices
    2.     public void XRDevices()
    3.     {
    4.         UnityEngine.XR.InputDevices.GetDevices(m_lstXRInputDevices);
    5.         Debug.Log("[HapticSystem][XRDevice] Number of XR: "+ m_lstXRInputDevices.Count);
    6.  
    7.         foreach (var device in m_lstXRInputDevices)
    8.         {
    9.             Debug.Log("<color=green>"+string.Format("[HapticSystem][XRDevice] Device found with name '{0}' and role '{1}'",
    10.                       device.name, device.characteristics.ToString()) + "</color>");
    11.  
    12.             if(device.TryGetHapticCapabilities(out UnityEngine.XR.HapticCapabilities capabilities))
    13.             {
    14.                 Debug.Log("[HapticSystem][XRDevice] XR Haptic Capabilities: "+capabilities.ToString()+" by: "+ string.Format("Device found with name '{0}' and role '{1}'",
    15.                       device.name, device.characteristics.ToString()));
    16.             }
    17.             else
    18.             {
    19.                 Debug.Log("<color=red>[HapticSystem][XRDevice] XR Haptic Capabilities NOT supported"+" by: "+string.Format("Device found with name '{0}' and role '{1}'",
    20.                       device.name, device.characteristics.ToString()) + "</color>");
    21.             }
    22.  
    23.         }
    24.  
    25.         UnityEngine.XR.InputDevice leftController = UnityEngine.XR.InputDevices.GetDeviceAtXRNode(UnityEngine.XR.XRNode.LeftHand);
    26.         if(leftController != null)
    27.         {
    28.             Debug.Log("<color=red>[HapticSystem][XRDevice] Left Controller NAME: "+leftController.name+" ROLE: "+leftController.characteristics.ToString()+"</color>");
    29.         }
    30.  
    31.         UnityEngine.XR.InputDevice rightController = UnityEngine.XR.InputDevices.GetDeviceAtXRNode(UnityEngine.XR.XRNode.RightHand);
    32.         if (rightController != null)
    33.         {
    34.             Debug.Log("<color=red>[HapticSystem][XRDevice] Right Controller NAME: " + rightController.name + " ROLE: " + rightController.characteristics.ToString() + "</color>");
    35.         }
    36.     }
    Do help me out. Thanks in advance
     
  18. ROBYER1

    ROBYER1

    Joined:
    Oct 9, 2015
    Posts:
    1,454
    Please use the Unity Bug Reporter to report the issue and post case number back here in your post

    https://unity3d.com/unity/qa/bug-reporting
     
  19. Pavoex

    Pavoex

    Joined:
    Oct 23, 2020
    Posts:
    2
    Hey
    I want to use the primary and secondary Button of my HP Reverb G2 in Unity. How can I integrate them?
    Atm I use the XR Interaction Toolkit.
     
  20. AnthonyJackson81

    AnthonyJackson81

    Joined:
    May 30, 2019
    Posts:
    32
    The only way I have found to this, so far...... is to use input player component and use the event system in that, with my 'event' set in Input Mappings, to a custom script, which doesnt inherit any of the XR base classes.

    I could be wrong. Ideally Id like to use the primary and econdary buttons also, inside my XRGrabbable script, along with OnActivated, OnSelectEntered etc. But I am struggling to do all this in 1 script
     
  21. Scottiedean

    Scottiedean

    Joined:
    Sep 20, 2018
    Posts:
    4
    This does not work unless you can figure out were did they create device at
     
  22. VKumar165498

    VKumar165498

    Joined:
    Sep 10, 2019
    Posts:
    1
    If you want callback on Trigger down and up, you can use this

    Code (CSharp):
    1. void CheckTrigger()
    2.     {
    3.         bool triggerButtonPressed = false;
    4.         if (device.TryGetFeatureValue(CommonUsages.triggerButton, out triggerButtonPressed) && triggerButtonPressed)
    5.         {
    6.          //   print("Trigger Button Pressed : " +triggerButtonPressed);
    7.         }
    8.  
    9.         bool triggerPulled = false;
    10.      
    11.         device.TryGetFeatureValue(CommonUsages.trigger, out trig);
    12.  
    13.         triggerPulled = (trig == 1);
    14.  
    15.         if (!triggerPulled)
    16.         {
    17.             if (isTriggerPressed)
    18.                 print("Trigger UP");
    19.  
    20.             isTriggerPressed = false;
    21.  
    22.         }
    23.  
    24.         if(triggerPulled && !isTriggerPressed)
    25.         {
    26.             print("Trigger Pressed : ");
    27.             isTriggerPressed = true;
    28.         }
    29.     }
     
    Last edited: Jun 7, 2021
    nawc_tg likes this.
  23. greenpau

    greenpau

    Joined:
    Jan 9, 2022
    Posts:
    1
    Inspired by the initial response to this thread.

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.Events;
    6. using UnityEngine.XR;
    7.  
    8. public class RightHandController : MonoBehaviour
    9. {
    10.     static readonly Dictionary<string, InputFeatureUsage<bool>> availableButtons = new Dictionary<string, InputFeatureUsage<bool>>
    11.         {
    12.             {"triggerButton", CommonUsages.triggerButton },
    13.             {"primary2DAxisClick", CommonUsages.primary2DAxisClick },
    14.             {"primary2DAxisTouch", CommonUsages.primary2DAxisTouch },
    15.             {"menuButton", CommonUsages.menuButton },
    16.             {"gripButton", CommonUsages.gripButton },
    17.             {"secondaryButton", CommonUsages.secondaryButton },
    18.             {"secondaryTouch", CommonUsages.secondaryTouch },
    19.             {"primaryButton", CommonUsages.primaryButton },
    20.             {"primaryTouch", CommonUsages.primaryTouch },
    21.         };
    22.  
    23.     public enum ButtonOption
    24.     {
    25.         triggerButton,
    26.         primary2DAxisClick,
    27.         primary2DAxisTouch,
    28.         menuButton,
    29.         gripButton,
    30.         secondaryButton,
    31.         secondaryTouch,
    32.         primaryButton,
    33.         primaryTouch
    34.     };
    35.  
    36.     [Tooltip("The name of the button triggering the action")]
    37.     public ButtonOption actionButtonName;
    38.  
    39.     [Tooltip("The event being triggered when the action button is being pressed")]
    40.     public UnityEvent OnPress;
    41.  
    42.     [Tooltip("The event being triggered when the action button is being released")]
    43.     public UnityEvent OnRelease;
    44.  
    45.     public bool IsPressed { get; private set; }
    46.  
    47.     UnityEngine.XR.InputDevice rigthHandedController;
    48.     UnityEngine.XR.InputFeatureUsage<bool> actionButtonUsage;
    49.     bool actionButtonValue;
    50.  
    51.  
    52.     private void Start()
    53.     {
    54.         // Initialize Right-Hand Controllers
    55.         var rigthHandedControllers = new List<UnityEngine.XR.InputDevice>();
    56.         var desiredCharacteristics = InputDeviceCharacteristics.HeldInHand | UnityEngine.XR.InputDeviceCharacteristics.Right | UnityEngine.XR.InputDeviceCharacteristics.Controller;
    57.         InputDevices.GetDevicesWithCharacteristics(desiredCharacteristics, rigthHandedControllers);
    58.         foreach (var device in rigthHandedControllers)
    59.         {
    60.             if (device.name.ToString().Contains("Oculus Touch Controller - Right")) {
    61.                 Debug.Log(string.Format("Found right-hand controller: '{0}' has characteristics '{1}'", device.name, device.characteristics.ToString()));
    62.                 rigthHandedController = device;
    63.             }
    64.         }
    65.  
    66.         // Get the button that will trigger the action.
    67.         string actionButton = Enum.GetName(typeof(ButtonOption), actionButtonName);
    68.         Debug.Log(string.Format("Actions button is {0}", actionButton));
    69.  
    70.         // find dictionary entry
    71.         availableButtons.TryGetValue(actionButton, out actionButtonUsage);
    72.     }
    73.  
    74.     void Update()
    75.     {
    76.             if (rigthHandedController.TryGetFeatureValue(actionButtonUsage, out actionButtonValue) && actionButtonValue)
    77.             {
    78.                 if (!IsPressed)
    79.                 {
    80.                     Debug.Log(string.Format("---\n{0} was pressed", rigthHandedController.name));
    81.                     IsPressed = true;
    82.                     OnPress.Invoke();
    83.                 }
    84.             }
    85.             else if (IsPressed)
    86.             {
    87.                 Debug.Log(string.Format("{0} was released", rigthHandedController.name));
    88.                 IsPressed = false;
    89.                 OnRelease.Invoke();
    90.             }
    91.  
    92.     }
    93. }
    94.  
    After that attach "On Press" and "On Release" actions in "Inspector" view.


    Code (csharp):
    1.  
    2. Found right-hand controller: 'Oculus Touch Controller - Right' has characteristics 'HeldInHand, TrackedDevice, Controller, Right'
    3. UnityEngine.Debug:Log (object)
    4. ManageBalloonController:Start () (at Assets/Scripts/RightHandController.cs:61)
    5.  
    6. Actions button is triggerButton
    7. UnityEngine.Debug:Log (object)
    8. ManageBalloonController:Start () (at Assets/Scripts/RightHandController.cs:68)
    9.  
    10. ---
    11. Oculus Touch Controller - Right was pressed
    12. UnityEngine.Debug:Log (object)
    13. ManageBalloonController:Update () (at Assets/Scripts/RightHandController.cs:80)
    14.  
    15. Oculus Touch Controller - Right was released
    16. UnityEngine.Debug:Log (object)
    17. ManageBalloonController:Update () (at Assets/Scripts/RightHandController.cs:87)
     
  24. Reahreic

    Reahreic

    Joined:
    Mar 23, 2011
    Posts:
    254
    I really liked the 2019.2 version of XRInput that used OpenVR and It worked really well for our needs. However as it's been obsoleted now, I'm trying to wrap my head around porting our existing applications code base to use the new 'new' 2019.4-2020.x system.

    I've read through a bunch of docs on the new system but am still unsure how to integrate our action/event based codebase with the new system. I've added the XR Plug-in Manager package, as well as the XR Interaction Subsystems and XRInteraction Toolkit packages, but am unsure on where to go next. DO I really need to install Microsofts MRTK, as well as SteamVR, as well as Windows Mixed Reality just to support the VIVE and HP Reverb G2 headsets?
     
    ROBYER1 likes this.
  25. Rickmc3280

    Rickmc3280

    Joined:
    Jun 28, 2014
    Posts:
    189
    OpenXR Works with Vive too. Cant speak on HP Reverb.
     
  26. Reahreic

    Reahreic

    Joined:
    Mar 23, 2011
    Posts:
    254
    That's my understanding, but I'm having trouble migrating from the 2019.0 - 2019.3 OpenVR solution to the newer 2019.4-2021.x OpenXR variant. so far the rest of the project has upgraded without breaking as is usually the case, but I either get white screening or the editor and SteamVR crash on play.

    XR Plugin-Management is setup per all the guides below and uses OpenXR with the WMR subset.

    https://docs.unity3d.com/Packages/com.unity.xr.openxr@0.1/manual/index.html
    https://docs.unity3d.com/Packages/com.unity.xr.windowsmr.metro@3.0/manual/index.html
    https://developers.hp.com/omnicept-xr/blog/reverb-g2-tracking-openxr-unity
    https://docs.microsoft.com/en-us/windows/mixed-reality/develop/unity/unity-reverb-g2-controllers

    It's rather painful for me as the 'old new' system that's discussed in this thread just worked well for me. (I understood it without difficulty) The 'new new' system is just painfully obtuse and complex by comparison lol
     
  27. Rickmc3280

    Rickmc3280

    Joined:
    Jun 28, 2014
    Posts:
    189
    You could do what I did... create a script with all of the buttons you want to use. (Actions) then create your own input system using events (not unity events). Using passthru you get the data and run your math.
    upload_2022-6-29_21-18-35.png

    If you do this, it will work for you. You have to subscribe to .performed and you also have to enable the action.

    recieving function must have "InputAction.CallbackContext" despite if you are going to use it or not.
    upload_2022-6-29_21-20-31.png
     
  28. Reahreic

    Reahreic

    Joined:
    Mar 23, 2011
    Posts:
    254
    Tank you, I've been coming up to speed with the new Input system, and your post helps with that. The primary Issue I now have is when I press play SteamVR unexpectedly crashes and nothing is sent to the HMD. The app continues to run in the background but isn't sent to the HMD when SteamVR is re-launched.

    There's obviously something in my config that's not right, but I haven't' come across what it is yet.
     
  29. Rickmc3280

    Rickmc3280

    Joined:
    Jun 28, 2014
    Posts:
    189
    What are the specs on your computer? Graphics Card? VR Headset? What Input System components are you using? XR Rig/ XR Origin in scene? Have you updated your graphics drivers recently?
     
  30. Reahreic

    Reahreic

    Joined:
    Mar 23, 2011
    Posts:
    254
    I literally just figured it out and it's not what I thought in my other posts... Was about to open an issue ticket when I saw your reply so I figured I'd update the thread.

    --- Trigger Warning ---

    My unity game tab was set to 'Play Unfocused' and I had my editor tab selected. So when I pressed play, it didn't automatically switch to the game tab, and as such failed to initialize OpenXR... WTF UNITY, WTEVERLOVINGF!

    Unity PlayUnfocused.JPG

    Good thing is the fix is easy, select the play tab then press play, or set the dropdown to 'PlayFocused' then once XR initializes change back to the editor tab.

    I'm pissed, I'm tired, and I'm going home now. (After I open the ticket.)