0
\$\begingroup\$

I'm developing a VR game using OpenXR in Unity (specifically developing on a Valve Index). When I try to access the input devices through the InputDevices.GetDevices() function, I get 0 devices back when I call this function from my script's Awake() or Start() methods. But when I call the same function from my script's Update() method, I see all the devices (e.g. head set, left controller, right controller).

Why can't I see the devices in the Awake() or Start() methods?

\$\endgroup\$
1
\$\begingroup\$

A bit better solution with Coroutine and reusable code for multiple controllers.

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

public class HandPresence : MonoBehaviour
{
    private InputDevice _rightController;
    private InputDevice _leftController;
    
    void Start()
    {
        var characteristics = InputDeviceCharacteristics.Right | InputDeviceCharacteristics.Controller;
        StartCoroutine(RepeatGetDevice(_rightController, characteristics));
        
        characteristics = InputDeviceCharacteristics.Left | InputDeviceCharacteristics.Controller;
        StartCoroutine(RepeatGetDevice(_leftController, characteristics));
    }

    private IEnumerator RepeatGetDevice(InputDevice device, InputDeviceCharacteristics characteristics )
    {
        var devices = new List<InputDevice>();

        do
        {
            yield return null;
            InputDevices.GetDevicesWithCharacteristics(characteristics, devices);
            if (devices.Count > 0)
                device = devices[0];
        } while (devices.Count == 0);
        
        Debug.Log($"{device.name} : {device.characteristics}");
    }
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Your answer could be improved with additional information. You could describe what parts of the code are key to the solution you provided. \$\endgroup\$
    – liggiorgio
    Oct 8 at 9:32
0
\$\begingroup\$

It turns out that some devices, like the Valve Index, don't initialize until you pick them up. Which can happen after the Start() method runs.

So to solve this, you need to write a function that is called later on during the Update() method until you have the device object(s) you need.

For example, if you want to find the left controller, you would run something like the following:

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

public class HandPresence : MonoBehaviour
{
    private InputDevice _targetDevice;
    
    void Start()
    {
        TryInitialize();
    }

    void TryInitialize()
    {
        var inputDevices = new List<InputDevice>();
        InputDeviceCharacteristics rightControllerCharacteristics =
            InputDeviceCharacteristics.Right | InputDeviceCharacteristics.Controller;
        InputDevices.GetDevicesWithCharacteristics(rightControllerCharacteristics, inputDevices);

        if (inputDevices.Count == 0)
        {
            return;
        }

        _targetDevice = inputDevices[0];
    }

    void Update()
    {
        if (!_targetDevice.isValid)
        {
            TryInitialize();
        }
        else
        {
            // Do what you would like with _targetDevice here
        }
    }
}

In this case, we use the TryInitialize() function to save the device into a private class variable. We run this function in the Start() method, but then check if we actually saved a device (by checking if the private class variable is valid) in the Update() method, and call TryInitialize() again if we did not.

This was tested and works in Unity 2020.2.7f1, with OpenXR 1.02.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.