Search code examples
mrtk

How to get associated pointer from an InputEventData?


I've setup a dual-axis input action and the corresponding handler.

Now I need to get the corresponding pointer/controller that raised this input action to figure out where it's pointing, e.g. if the event was raised from a motion controller's thumbstick, I want to get the pointer associated with that motion controller.

public void OnInputChanged(InputEventData<Vector2> eventData)
{
    if (eventData.MixedRealityInputAction.Description == "MyInputAction")
    {
        // How to do something like this?
        // var pointer = eventData.Pointer;

        eventData.Use();
    }
}

If there is no pointer associated with the action (if it's from a voice command, for instance), then I may handle it differently, using Gaze instead.


Solution

  • Answer updated 6/11/2019

    You can find a pointer associated with an Input{Down,Up,Updated} event via the following code:

    public void OnInputDown(InputEventData eventData)
    {
        foreach(var ptr in eventData.InputSource.Pointers)
        {
            // An input source has several pointers associated with it, if you handle OnInputDown all you get is the input source
            // If you want the pointer as a field of eventData, implement IMixedRealityPointerHandler
            if (ptr.Result != null && ptr.Result.CurrentPointerTarget.transform.IsChildOf(transform))
            {
                Debug.Log($"InputDown and Pointer {ptr.PointerName} is focusing this object or a descendant");
            }
            Debug.Log($"InputDown fired, pointer {ptr.PointerName} is attached to input source that fired InputDown");
        }
    }
    

    Note that if you care about pointers, you might be using the wrong event handler. Consider instead implementing IMixedRealityPointerHandler instead of IMixedRealityInputHandler.

    Original answer

    If you would like to get the rotation of the controller corresponding to your motion controllers, I think the most reliable way would be to first implement a new input handler for MixedRealityPoses. This will allow you to get updates when the underlying controller changes.

    class MyClass : IMixedRealityInputHandler<Vector2>, IMixedRealityInputHandler<MixedRealityPose>
    

    Then, keep track of the Source ID to pose mapping...

    Dictionary<uint, MixedRealityPose> controllerPoses = new Dictionary<uint, MixedRealityPose>;
    public void OnInputChanged(InputEventData<MixedRealityPose> eventData)
    {
        controllerPoses[eventData.SourceId] = eventData.InputData
    }
    

    Finally, get this data in your Handler:

    MixedRealityInputAction myInputAction;
    public void OnInputChanged(InputEventData<Vector2> eventData)
    {
        // NOTE: would recommend exposing a field myInputAction in Unity editor
        // and assigning there to avoid string comparison which could break more easily.
        if (eventData.MixedRealityInputAction == myInputAction)
        {
            MixedRealityPose controllerPose = controllerPoses[eventData.SourceId];
            // Do something with the pointer
        }
    }
    

    The reason you want to use this approach instead of going for pointers is because you can have multiple pointers assigned to a single input source. Since Input events are raised from input sources, it will not be obvious which pointer you want to use, and those could change over time. Grabbing the mixed reality pose and correlating them does seem a bit more convoluted at first, but will be more reliable for you long term.