Controller Position only works in right hand

The following code is used to wrap the ML2-Controller inputs. This only works, when the user is holding the controller in the right hand. I need this to work always, no matter where the contoller is tracked or held. Is there a parameter to be set somwhere, to ignore the handedness?

using Core.Singletons;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;

namespace Qvra.UI
{
    public class LeapControllerInputHandler : Singleton<LeapControllerInputHandler>
    {
        public UnityEvent<Vector2> OnTouchpadUsed = new();
        public UnityEvent<float> OnTriggerUsed = new();
        public UnityEvent<float> OnTouchpadForce = new();
        public UnityEvent OnBumperPressed = new();
        public UnityEvent OnTouchpadClicked = new();
        public UnityEvent OnMenuPressed = new();
        public ControllerPresenceChecker PresenceChecker { get; private set; }

        public LeapControllerInputHandler()
        {
            PresenceChecker = new();
            PresenceChecker.Enable();
            _magicLeapInputs = new();
            _magicLeapInputs.Enable();
            _controllerActions = new MagicLeapInputs.ControllerActions(_magicLeapInputs);

            _controllerActions.Trigger.performed += TriggerPressed;
            _controllerActions.Bumper.performed += BumperPressed;
            _controllerActions.Menu.performed += MenuPressed;
            _controllerActions.TouchpadTouch.performed += TouchpadClicked;
            _controllerActions.TouchpadPosition.performed += TouchPadPosition;
            _controllerActions.TouchpadForce.performed += TouchpadForce;
        }

        public Vector3 ControllerPosition() => _controllerActions.Position.ReadValue<Vector3>();

        public Quaternion ControllerRotation() => _controllerActions.Rotation.ReadValue<Quaternion>();

        private void TouchpadForce(InputAction.CallbackContext context)
        {
            var value = context.ReadValue<float>();
            OnTouchpadForce.Invoke(value);
        }

        private void TouchPadPosition(InputAction.CallbackContext context)
        {
            var value = context.ReadValue<Vector2>();
            OnTouchpadUsed.Invoke(value);
        }

        private void TriggerPressed(InputAction.CallbackContext context)
        {
            var value = context.ReadValue<float>();
            OnTriggerUsed.Invoke(value);
        }

        private void BumperPressed(InputAction.CallbackContext context)
        {
            OnBumperPressed.Invoke();
        }

        private void MenuPressed(InputAction.CallbackContext context)
        {
            OnMenuPressed.Invoke();
        }

        private void TouchpadClicked(InputAction.CallbackContext context)
        {
            OnTouchpadClicked.Invoke();
        }

        public void OnDestroy()
        {
            _controllerActions.Trigger.performed -= TriggerPressed;
            _controllerActions.Bumper.performed -= BumperPressed;
            _controllerActions.Menu.performed -= MenuPressed;
            _controllerActions.TouchpadTouch.performed -= TouchpadClicked;
            _controllerActions.TouchpadPosition.performed -= TouchPadPosition;
            _controllerActions.TouchpadForce.performed -= TouchpadForce;

            _magicLeapInputs.Dispose();
        }

        private MagicLeapInputs _magicLeapInputs;
        private MagicLeapInputs.ControllerActions _controllerActions;

    }
}

Hand related subsystems:

Unity Editor version: 6000.0.44f1
ML2 OS version: 1.12
Leap SDK version: 2.5.0

I recommend using the the OpenXR version of the MRTK 3 package

You can compare your results to our example project project. There fully configured branches of the MRTK3’s MRTKDevTemplate project available on Magic Leap’s github fork of the project to run on ML2.

Here is the branch for Unity 6 and OpenXR

The DevTemplate contains Magic Leap SDK 2.6.0. The official GitHub page has only version 2.3.0 flagged as latest: Releases · magicleap/MagicLeapUnitySDK · GitHub

How do I get 2.6.0 into my project the official way? I cannot update the SDK via PackageManger

Update: I found out, that the problem actually only applies to the inputs on the controller. I’m able to get the position and rotation of the contoller, even when held in the left hand. But the hardware buttons line trigger or bumper are only registered when the controller is in the right hand.

The scripts in the main branch are actually the latest scripts. It’s just that the release page has not been updated to show this. Using the Magic Leap Hub or the npm package will import the latest version of the package: Configure Project Settings | MagicLeap Developer Documentation


Does the following script work for you in your project?

I solved it myself. The problem seems to be that the default InputActions in the SDK are all routed to the RightHand (even in the latest 2.6). If anyone stumbles upon this issue, feel free to use this code (AI won’t solve this for you :wink: )

using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;


    public class LeapControllerInputHandler : MonoSingleton<LeapControllerInputHandler>
    {
        public UnityEvent<bool> OnControllerActive = new();
        public UnityEvent OnTriggerDown = new();
        public UnityEvent OnTriggerUp = new();
        public UnityEvent OnBumperDown = new();
        public UnityEvent OnBumperUp = new();
        public UnityEvent OnMenuDown = new();
        public UnityEvent OnMenuUp = new();

        // TODO: Implement Trackpad if needed


        private void Start()
        {
            var controllerMap = _inputActions.FindActionMap("Controller", true);

            _bumperAction = controllerMap.FindAction("Bumper", true);
            _bumperAction.started += (_) => OnBumperDown.Invoke();
            _bumperAction.canceled += (_) => OnBumperUp.Invoke();
            _bumperAction.Enable();

            _triggerAction = controllerMap.FindAction("Trigger", true);
            _triggerAction.started += (_) => OnTriggerDown.Invoke();
            _triggerAction.canceled += (_) => OnTriggerUp.Invoke();
            _triggerAction.Enable();

            _triggerValueAction = controllerMap.FindAction("TriggerValue", true);
            _triggerValueAction.Enable();

            _menuAction = controllerMap.FindAction("MenuButton", true);
            _menuAction.started += (_) => OnMenuDown.Invoke();
            _menuAction.canceled += (_) => OnMenuUp.Invoke();
            _menuAction.Enable();

            _positionAction = controllerMap.FindAction("Position", true);
            _positionAction.Enable();

            _rotationAction = controllerMap.FindAction("Rotation", true);
            _rotationAction.Enable();

            _isTrackedAction = controllerMap.FindAction("IsTracked", true);
            _isTrackedAction.started += (_) => ControllerActive = true;
            _isTrackedAction.canceled += (_) => ControllerActive = false;
            _isTrackedAction.Enable();
        }

        public bool ControllerActive
        {
            get => _controllerActive;
            private set
            {
                if (value != _controllerActive)
                {
                    OnControllerActive.Invoke(value);
                    var state = value ? "ON" : "OFF";
                    Debug.Log($"Controller {state}");
                }
                _controllerActive = value;
            }
        }

        public Vector3 ControllerPosition() => _positionAction.ReadValue<Vector3>();
        public Quaternion ControllerRotation() => _positionAction.ReadValue<Quaternion>();
        public float TriggerValue() => _triggerValueAction.ReadValue<float>();

        [SerializeField] private InputActionAsset _inputActions;
        private bool _controllerActive;
        private InputAction _bumperAction;
        private InputAction _triggerAction;
        private InputAction _menuAction;
        private InputAction _positionAction;
        private InputAction _rotationAction;
        private InputAction _isTrackedAction;
        private InputAction _triggerValueAction;
    }

Just add this class to your scene and link it to the “MagicLeapInputsOpenXR” InputAsset. Using a different InputAsset may require to adjust the binding names.