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
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.
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.