QUEST OnPointerExit & OnPointerEnter events unexpectedly fire after pressing & releasing the trigger

,
  • I have a simple script that plays an audio clip when the OnPointerEnter event fires and stops when the OnPointerExit event is fired
  • If I hover over and then off of a UI element, like a toggle or button, the audio plays / stops as expected
  • If I pull the controller trigger while hovering over UI and release, the OnPointerExit & OnPointerEnter events fire, even though I never moved the pointer from the UI
  • This only occurs when in VR, not in a desktop scene, and is feels like a bug

Unity 2022.3.20f1
Meta SDK v62

Sounds like the same issue as I am having.

Unity 22.3.17f1
Meta SDK v63

I get this behaviour on a simple UI button.
My Scenario:

  • Meta ComprehensiveRig
  • Meta UnityCanvas prefab
  • Button on canvas
    Attached script on Button with OnPointerEnter → Debug.Log(“ENTER”) and OnPointerExit → Debug.Log(“EXIT”);
    When hovering the button and clicking it I get this log:
    EXIT
    EXIT
    ENTER

Though sometimes there is only one EXIT making it EXIT/ENTER.

I’m guessing the issue is the OnPointerExit is fired in error (or feature?) and since we are still holding the pointer over the button it will trigger OnPointerEnter as expected.

I might have found something that could be causing it, or at least be involved in the problem, though I have no solution for it.

First off, I’m pretty sure this was not an issue when using the OVRinputModule instead of the PointableCanvasModule.

For UI to work you need to add PointableCanvasModule.cs from the Meta XR Interaction SDK.
This will call ProcessPointer on each of the pointers which if released (I assume this means “clicked”) will call the base class in Unity UGUI package (EventSystem/InputModules/BaseInputModules.cs) using this call HandlePointerExitAndEnter(pointerEventData, null);
But it is always passing NULL as newEnterTarget and if null the code below get executed and looks like it will send exit events.

I would say this is a bug in the Meta XR Interaction SDK / PointableCanvasModule.cs.
I cannot imagine this being a feature as it creates quite a bit complexity for using OnPointerEnter and OnPointerLeave for custom hover functionality on clickable buttons.

But yes, knowing that it is hardcoded (If this indeed is the issue) to always send exit events to all hovered pointers including the root pointer inside the gameobject when clicking, I guess you could add some custom workaround, but as said it will create some terrible complexity.

BaseInputModules.cs

        // walk up the tree till a common root between the last entered and the current entered is found
        // send exit events up to (but not including) the common root. Then send enter events up to
        // (but not including) the common root.
        // Send move events before exit, after enter, and on hovered objects when pointer data has changed.
        protected void HandlePointerExitAndEnter(PointerEventData currentPointerData, GameObject newEnterTarget)
        {

// if we have no target / pointerEnter has been deleted
            // just send exit events to anything we are tracking
            // then exit
            if (newEnterTarget == null || currentPointerData.pointerEnter == null)
            {
                var hoveredCount = currentPointerData.hovered.Count;
                for (var i = 0; i < hoveredCount; ++i)
                {
                    currentPointerData.fullyExited = true;
                    ExecuteEvents.Execute(currentPointerData.hovered[i], currentPointerData, ExecuteEvents.pointerMoveHandler);
                    ExecuteEvents.Execute(currentPointerData.hovered[i], currentPointerData, ExecuteEvents.pointerExitHandler);
                }

                currentPointerData.hovered.Clear();

                if (newEnterTarget == null)
                {
                    currentPointerData.pointerEnter = null;
                    return;
                }
            }
...

EDIT: I tried commenting the else part out and also sending in the currentGO form the eventData ray instead of null, but still got the same result.

Hi, did you ever solve this?

This is what I did in lieu of an official fix by Meta to satisfy my specific use case (to predictably play audio on hover events):

using UnityEngine;
using Oculus.Interaction;

public class PlayAudioOnHoverMETA : MonoBehaviour
{
    [SerializeField] private AudioSource audioSource;
    private bool isPointerOver = false;
    
    void Start()
    {
        PointableCanvasModule.WhenSelectableHovered += OnSelectableHovered;
        PointableCanvasModule.WhenSelectableUnhovered += OnSelectableUnhovered;
    }

    void OnDestroy()
    {
        PointableCanvasModule.WhenSelectableHovered -= OnSelectableHovered;
        PointableCanvasModule.WhenSelectableUnhovered -= OnSelectableUnhovered;
    }

    private void OnSelectableHovered(PointableCanvasEventArgs args)
    {
        if (args.Hovered == this.gameObject && audioSource != null && !audioSource.isPlaying && !isPointerOver)
        {
            audioSource.Play();
            isPointerOver = true;
            //Debug.Log("Play Audio Clip on Enter\n");
        }
    }

    private void OnSelectableUnhovered(PointableCanvasEventArgs args)
    {
        if (audioSource != null)
        {
            audioSource.Stop();
            isPointerOver = false;
            //Debug.Log("Stop Audio Clip on Exit\n");
        }
    }
}

Hi,

Big thanks for taking the time to post this.
It looks like this might work for my use case as well to keep an element highlighted (no exit/enter glitch) after clicking it, i’m going to test it out.

1 Like