Skip to main content
Version: 10 Jul 2024

Input Device Feature Values

It is recommended that developers use the Unity Input System to obtain the Gaze Input. However, developers can also obtain eye tracking input directly from the InputDevice. This section provides an example of how to read input using the TryGetFeatureValue method and EyeTrackingUsages features.

Developers can utilize the User Calibration OpenXR feature to ensure the wearer has properly calibrated eye tracking and a well-fitted headset. This will ensure that the user's gaze is accurately detected.

If the User Calibration API indicates a “Bad Fit” or if the eyes are uncalibrated, we recommend notifying the user and prompting them to run the eye calibration. You can launch the eye calibration application using standard Android intents. Please refer to this article for more details.

caution

This features requires the EYE_TRACKING permission to be requested at runtime and enabled in your project's Manifest Settings (Edit > Project Settings > Magic Leap > Manifest Settings).

caution

This feature requires the Eye Gaze Interaction Profile OpenXR Interaction Profile to be enabled in your project's OpenXR Settings (Window > XR Plugin Manager > OpenXR Settings).

note

If your Application collects, stores, transfers or otherwise uses data off the Magic Leap 2 device that is received via this API, then you must comply with the Magic Leap 2 Eye Tracking Data Transparency Policy.

Example

This example script finds a connected controller if one is present and logs the input values using the TryGetFeatureValue() method and EyeTrackingUsages.

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
using UnityEngine.XR.MagicLeap;
using UnityEngine.XR.OpenXR.Features.Interactions;
using InputDevice = UnityEngine.XR.InputDevice;

/// <summary>
/// This script finds a connected eye tracking input device and logs it's input values.
/// Requires the Eye Gaze Interaction Profile to be enabled in the project's OpenXR settings
/// </summary>
public class GazeInputExample : MonoBehaviour
{
private InputDevice _eyeTrackingDevice;
private bool _permissionGranted;
private readonly MLPermissions.Callbacks _permissionCallbacks = new MLPermissions.Callbacks();

void Start()
{
// Request Magic Leap Eye Tracking Permission
_permissionCallbacks.OnPermissionGranted += OnPermissionGranted;
_permissionCallbacks.OnPermissionDenied += OnPermissionDenied;
_permissionCallbacks.OnPermissionDeniedAndDontAskAgain += OnPermissionDenied;
MLPermissions.RequestPermission(MLPermission.EyeTracking, _permissionCallbacks);
}

private void Update()
{
if (!_permissionGranted)
{
// Wait for permission
return;
}

// Get the EyeTracking Input Device
if (!_eyeTrackingDevice.isValid)
{
List<InputDevice> inputDeviceList = new List<InputDevice>();
InputDevices.GetDevicesWithCharacteristics(InputDeviceCharacteristics.EyeTracking, inputDeviceList);
if (inputDeviceList.Count > 0)
{
_eyeTrackingDevice = inputDeviceList[0];
}

if (!_eyeTrackingDevice.isValid)
{
Debug.LogWarning($"Unable to acquire eye tracking device. Have permissions been granted?");
return;
}
}

//Obtain gaze tracking input
bool hasData = _eyeTrackingDevice.TryGetFeatureValue(CommonUsages.isTracked, out bool isTracked);
hasData &= _eyeTrackingDevice.TryGetFeatureValue(EyeTrackingUsages.gazePosition, out Vector3 position);
hasData &= _eyeTrackingDevice.TryGetFeatureValue(EyeTrackingUsages.gazeRotation, out Quaternion rotation);

if (isTracked && hasData)
{
Vector3 direction = rotation * Vector3.forward;
// Use the position and rotation
Debug.Log($"Gaze Origin: {position} | Gaze Rotation: {rotation} | Gaze Direction {direction}");
}
}

private void OnDestroy()
{
_permissionCallbacks.OnPermissionGranted -= OnPermissionGranted;
_permissionCallbacks.OnPermissionDenied -= OnPermissionDenied;
_permissionCallbacks.OnPermissionDeniedAndDontAskAgain -= OnPermissionDenied;
}

private void OnPermissionDenied(string permission)
{
// Logic for permission not granted
Debug.LogError($"Eye tracking permission denied.");
}

private void OnPermissionGranted(string permission)
{
_permissionGranted = true;
}
}