Controller Usage

We will introduce the controller usages below including Pose, Button and Others (e.g. battery life, vibration) by using Unity XR, Unity Input System and VIVE Wave™ APIs.

Unity XR features are defined in CommonUsages.

You can read this document to learn the usages of Input System.

VIVE Wave™ XR plugin provides the controller API in the XRSDK package. (refer to Wave XR Plugin Packages).

You can find the controller samples at Assets > Samples > Wave > XR > XR > Controller after imported the Samples from XRSDK package.

../_images/VIVEWaveXRPlugin.png

Pose

For example, you have to access the right controller’s pose.

Unity XR - Pose

To apply the right controller’s pose to a GameObject, you will need to add the component Tracked Pose Driver.

../_images/06.png

To retrieve the right controller’s position in code, we use the CommonUsages.devicePosition in sample code below.

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;

public const InputDeviceCharacteristics kControllerRightCharacteristics = (
    InputDeviceCharacteristics.Right |
    InputDeviceCharacteristics.TrackedDevice |
    InputDeviceCharacteristics.Controller |
    InputDeviceCharacteristics.HeldInHand
);

internal List<InputDevice> m_InputDevices = new List<InputDevice>();

public bool GetRightControllerPosition(out Vector3 position)
{
    position = Vector3.zero;

    InputDevices.GetDevices(m_InputDevices);
    if (m_InputDevices != null && m_InputDevices.Count > 0)
    {
        for (int i = 0; i < m_InputDevices.Count; i++)
        {
            // The device is connected.
            if (m_InputDevices[i].characteristics.Equals(kControllerRightCharacteristics))
            {
                if (m_InputDevices[i].TryGetFeatureValue(CommonUsages.isTracked, out bool tracked))
                {
                    if (m_InputDevices[i].TryGetFeatureValue(CommonUsages.devicePosition, out Vector3 value))
                    {
                        position = value;
                        return true;
                    }
                }
            }
        }
    }

    return false;
}

Unity Input System - Pose

To apply the right controller’s pose to a GameObject, you will need to add the component Tracked Pose Driver (Input System).

../_images/07.png

To retrieve the right controller’s position in code, we use the InputActionReference Position and specify the binding path to <XRController>{RightHand}/devicePosition in sample code below.

../_images/08.png
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;

[SerializeField]
private InputActionReference m_Position = null;
public InputActionReference Position { get { return m_Position; } set { m_Position = value; } }

private bool VALIDATE(InputActionReference actionReference, out string msg)
{
    msg = "Normal";

    if (actionReference == null)
    {
        msg = "Null reference.";
        return false;
    }
    else if (actionReference.action == null)
    {
        msg = "Null reference action.";
        return false;
    }
    else if (!actionReference.action.enabled)
    {
        msg = "Reference action disabled.";
        return false;
    }
    else if (actionReference.action.activeControl == null)
    {
        msg = "No active control of the reference action, phase: " + actionReference.action.phase;
        return false;
    }
    else if (actionReference.action.controls.Count <= 0)
    {
        msg = "Action control count is " + actionReference.action.controls.Count;
        return false;
    }

    return true;
}

public bool GetPosition(out Vector3 position, out string msg)
{
    position = Vector3.zero;

    if (VALIDATE(m_Position, out msg))
    {
        if (m_Position.action.activeControl.valueType == typeof(Vector3))
            position = m_Position.action.ReadValue<Vector3>();

        return true;
    }

    return false;
}
#endif

Wave XR - Pose

After imported the XRSDK package, you can find the controller API at Packages > VIVE Wave XR Plugin > Runtime > WaveXRControl.cs.

By using the following code you can retrieve the right controller’s position.

using Wave.OpenXR;

public bool GetRightControllerPosition(out Vector3 position)
{
    return InputDeviceControl.GetPosition(InputDeviceControl.ControlDevice.Right, out position);
}

Button

For example, you have to access the right controller’s trigger button.

Unity XR - Button

About the button usage in Unity XR, please refer to Unity XR Input

Note

Avoid getting XR.InputDevice in MonoBehaviour OnEnable . Instead, we recommend you to get the input devices in Start or through polling in Update if you do NOT have the XR.InputDevice yet.

This is the button mapping table of Wave XR .

../_images/01.png

Note

The button support depends on the controller hardware. NOT all buttons will be supported in all VIVE Wave™ devices.

E.g. If you use Focus or Focus Plus , you will not get the primaryButton, primaryTouch, secondaryButton and secondaryTouch events because Focus and Focus Plus do NOT have the A/X and B/Y buttons.

For Vive Focus3 controller attributes, refer to Focus3 Controller Attributes.

Note

The * means the 1st button will be used as default. For example:

  • A controller supports the Touchpad button only: The Touchpad will be used as primary2DAxis.
  • A controller supports the Thumbstick button only: The Thumbstick will be used as primary2DAxis.
  • A controller supports both the Touchpad and Thumbstick buttons: The Touchpad will be used as primary2DAxis.

Note

The Thumbstick is as known as Joystick.

To retrieve the right controller’s trigger button in code, we use the CommonUsages.triggerButton in sample code below.

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;

public const InputDeviceCharacteristics kControllerRightCharacteristics = (
    InputDeviceCharacteristics.Right |
    InputDeviceCharacteristics.TrackedDevice |
    InputDeviceCharacteristics.Controller |
    InputDeviceCharacteristics.HeldInHand
);

internal List<InputDevice> m_InputDevices = new List<InputDevice>();

public bool GetRightControllerTriggerButton(out bool pressed)
{
    pressed = false;

    InputDevices.GetDevices(m_InputDevices);
    if (m_InputDevices != null && m_InputDevices.Count > 0)
    {
        for (int i = 0; i < m_InputDevices.Count; i++)
        {
            // The device is connected.
            if (m_InputDevices[i].characteristics.Equals(kControllerRightCharacteristics))
            {
                if (m_InputDevices[i].TryGetFeatureValue(CommonUsages.triggerButton, out bool value))
                {
                    pressed = value;
                    return true;
                }
            }
        }
    }

    return false;
}

Unity Input System - Button

To retrieve the right controller’s trigger button in code, we use the InputActionReference ActionReference and specify the binding path to <XRController>{RightHand}/{triggerButton} in sample code below.

../_images/09.png
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;

[SerializeField]
private InputActionReference m_ActionReference;
public InputActionReference ActionReference { get => m_ActionReference ; set => m_ActionReference = value; }

private bool VALIDATE(InputActionReference actionReference, out string msg)
{
    msg = "Normal";

    if (actionReference == null)
    {
        msg = "Null reference.";
        return false;
    }
    else if (actionReference.action == null)
    {
        msg = "Null reference action.";
        return false;
    }
    else if (!actionReference.action.enabled)
    {
        msg = "Reference action disabled.";
        return false;
    }
    else if (actionReference.action.activeControl == null)
    {
        msg = "No active control of the reference action, phase: " + actionReference.action.phase;
        return false;
    }
    else if (actionReference.action.controls.Count <= 0)
    {
        msg = "Action control count is " + actionReference.action.controls.Count;
        return false;
    }

    return true;
}

public bool GetButton(out bool value, out string msg)
{
    value = false;

    if (VALIDATE(m_ActionReference, out msg))
    {
        if (m_ActionReference.action.activeControl.valueType == typeof(float))
            value = m_ActionReference.action.ReadValue<float>() > 0;
        if (m_ActionReference.action.activeControl.valueType == typeof(bool))
            value = m_ActionReference.action.ReadValue<bool>();

        return true;
    }

    return false;
}

Wave XR - Button

After imported the XRSDK package, you can find the controller API at Packages > VIVE Wave XR Plugin > Runtime > WaveXRControl.cs.

By using the following code you can retrieve the right controller’s trigger button.

using Wave.OpenXR;

public bool IsRightControllerTriggerButtonPressed()
{
    return InputDeviceControl.KeyDown(InputDeviceControl.ControlDevice.Right, CommonUsages.triggerButton);
}

Unity Input Helper

Unity XR provides an additional feature package named XR Interaction Toolkit which can be imported from the Window > Package Manager.

../_images/02.png

After imported the XR Interaction Toolkit package, you can use the InputHelper to retrieve the button state.

For example, you will get a pressed state when you touch the Focus Plus touchpad up with the axis value [0, 1] bigger than 0.7 by using the following code.

using UnityEngine.XR;

void Update()
{
    bool touchpad_Y_pressed = false;
    if (InputHelpers.IsPressed(InputDevices.GetDeviceAtXRNode(XRNode.RightHand), InputHelpers.Button.PrimaryAxis2DUp, out bool value, .7f))
    {
        // True if right touchpad Y axis > 0.7
        touchpad_Y_pressed = value;
    }
}

Others

Battery Life

For example, you have to retrieve the right controller’s battery life.

  • Unity XR: Use CommonUsages.batteryLevel.

  • Unity Input System: Use <XRController>{RightHand}/batteryLevel.

    ../_images/10.png
  • Wave XR: Use InputDeviceControl.GetBatteryLevel.

Vibration

For example, you have to vibrate the right controller.

  • Unity XR: Sample code as below.
using UnityEngine.XR;
using System.Collections.Generic;

public const InputDeviceCharacteristics kControllerRightCharacteristics = (
    InputDeviceCharacteristics.Right |
    InputDeviceCharacteristics.TrackedDevice |
    InputDeviceCharacteristics.Controller |
    InputDeviceCharacteristics.HeldInHand
);

internal List<InputDevice> m_InputDevices = new List<InputDevice>();

public bool VibrateRightController(float amplitude, float duration)
{
    InputDevices.GetDevices(m_InputDevices);
    if (m_InputDevices != null && m_InputDevices.Count > 0)
    {
        for (int i = 0; i < m_InputDevices.Count; i++)
        {
            // The device is connected.
            if (m_InputDevices[i].characteristics.Equals(kControllerRightCharacteristics))
            {
                if (m_InputDevices[i].TryGetHapticCapabilities(out HapticCapabilities value))
                {
                    if (value.supportsImpulse)
                    {
                        amplitude = Mathf.Clamp(amplitude, 0, 1);
                        return m_InputDevices[i].SendHapticImpulse(0, amplitude, duration);
                    }
                }
            }
        }
    }

    return false;
}
  • Unity Input System: Sample code as below.
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.XR;

public InputActionReference action;
public float _amplitude = 1.0f;
public float _duration = 0.1f;

private void Start()
{
    if (action == null)
        return;

    action.action.Enable();
    action.action.performed += (ctx) =>
    {
        var control = action.action.activeControl;
        if (null == control)
            return;

        if (control.device is XRControllerWithRumble rumble)
            rumble.SendImpulse(_amplitude, _duration);
    };
}
  • Wave XR: Use InputDeviceControl.SendHapticImpulse.