Detect If Pointer Is Over Any UI Element

I’ve read a half dozen posts on what I think is one of the most common scenarios I can think of but I didn’t not find an answer that worked (cleanly).

I have a worldspace UI because I have units that will have action buttons that pop over their head. Naturally if the button is clicked to taken an action I dont want that click going through behind the button and hitting the grid (and hence making the unit take action and try to move too).

There used to be in the beta a function:
EventSystemManager.currentSystem.IsPointerOverEventSystemObject()

Which looked like it would do the trick. However it’s been since removed.

I see there is a way I can manually add an event to every UI element

But thats is the most ridiculous overkill solution ever.

Knowing if a pointer is over a UI element in any frame should be easily detected and Im curious if I missed something during my research?

Is there some sort of generic IsPointerOverUIElement() function?

Update
My next best solution is doing a raycast and checking for a UI element hit.

You can try this code. For me it’s working like a charm.

public static bool IsPointerOverUIObject()
{
    PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
    eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
    List<RaycastResult> results = new List<RaycastResult>();
    EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
    return results.Count > 0;
}

Try: EventSystems.EventSystem.IsPointerOverGameObject

I did a script that you can add to every Canvas. Then you can reach the static bool MouseInputUIBlocker.BlockedByUI from anywhere to see if the mouse is over UI or not.

I know it’s dirty with the static bool I only did this as a quick fix but it might help someone:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.EventSystems;

[RequireComponent(typeof(EventTrigger))]
public class MouseInputUIBlocker : MonoBehaviour
{
    public static bool BlockedByUI;
    private EventTrigger eventTrigger;

    private void Start()
    {
        eventTrigger = GetComponent<EventTrigger>();
        if(eventTrigger != null)
        {
            EventTrigger.Entry enterUIEntry = new EventTrigger.Entry();
            // Pointer Enter
            enterUIEntry.eventID = EventTriggerType.PointerEnter;
            enterUIEntry.callback.AddListener((eventData) => { EnterUI(); });
            eventTrigger.triggers.Add(enterUIEntry);

            //Pointer Exit
            EventTrigger.Entry exitUIEntry = new EventTrigger.Entry();
            exitUIEntry.eventID = EventTriggerType.PointerExit;
            exitUIEntry.callback.AddListener((eventData) => { ExitUI(); });
            eventTrigger.triggers.Add(exitUIEntry);
        }
    }

    public void EnterUI()
    {
        BlockedByUI = true;
    }
    public void ExitUI()
    {
        BlockedByUI = false;
    }

}

I think a better solution is

bool noUIcontrolsInUse = EventSystem.current.currentSelectedGameObject == null;

That’s because EventSystems.EventSystem.IsPointerOverGameObject will fail when the cursor moves off of a control even while it’s still controlling. e.g. when click-dragging a slider and you move off of it. (At least in Unity 2018.1)

EDIT: Read the comments below for an important limitation.

You can add Event Trigger component to your Canvas, and add actions OnPointerEnter & OnPointerExit. After that, made new method like this:

[SerializeField]
private bool OnUI;
public void OnPointerState(bool newState) { OnUI = newState; } // Recomendation: set true when method called from OnPointerEnter action, and set false in other case.

And call this method from your actions. This way detect all moments, when you pointer is enter or exit parent UI object (in this case - your canvas) and all his childrens, that have Image component (with turned on “Raycast target” option), so rarely can be buggy. Have a good codding expirience!
EDIT: This laggy when user have low framerate, in other cases - this works perfectly!

The solutions posted above will fail if EventSystem interfaces (IPointerClickHandler, etc… ) are used on non UI gameObjects without RectTransforms. To fix this problem use

  public static bool IsPointerOverUIObject()
        {
            PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
            eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
            List<RaycastResult> results = new List<RaycastResult>();
            EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
            foreach (RaycastResult r in results)
                if (r.gameObject.GetComponent<RectTransform>() != null)
                    return true;

            return false;
        }

Many years later, but I’m trying to do the same thing but I found adding a collider to the canvas and using this worked well Unity - Scripting API: MonoBehaviour.OnMouseOver()

//Attach this script to a GameObject to have it output messages when your mouse hovers over it.
using UnityEngine;

public class OnMouseOverLabel : MonoBehaviour
{

    private GameObject labelText;

    void Start()
    {
        labelText = GameObject.Find("Button");
        
        labelText.SetActive(false);
    }
    
    void OnMouseOver()
    {
        //If your mouse hovers over the GameObject with the script attached, output this message
        Debug.Log("Mouse is over GameObject.");

        labelText.SetActive(true);
    }

    void OnMouseExit()
    {
        //The mouse is no longer hovering over the GameObject so output this message each frame
        Debug.Log("Mouse is no longer on GameObject.");
        
        labelText.SetActive(false);
    }
}