How to detect if mouse is over UI?

I have a simple script called InputManager and (for now) all it does is just to detect whether the mouse is over UI elements or not, just to prevent unwanted behaviors in the game.

void Update()
    {
        if (EventSystem.current.IsPointerOverGameObject())
        {
            Debug.Log("Its over UI elements");
        }
        else
        {
            Debug.Log("Its NOT over UI elements");
        }
}

The problem is that the message “Its over UI elements” always shows up in the console, I turned off the canvas just to see if there is something messing with this function but nothing happened, apparently a lot of devs are suffering from the same issue.

Can someone tell me what to do?

2 Likes

I’ve used this which works well - comes from an old forum post.

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

public class UITest : MonoBehaviour
{
    int UILayer;

    private void Start()
    {
        UILayer = LayerMask.NameToLayer("UI");
    }

    private void Update()
    {
        print(IsPointerOverUIElement() ? "Over UI" : "Not over UI");
    }


    //Returns 'true' if we touched or hovering on Unity UI element.
    public bool IsPointerOverUIElement()
    {
        return IsPointerOverUIElement(GetEventSystemRaycastResults());
    }


    //Returns 'true' if we touched or hovering on Unity UI element.
    private bool IsPointerOverUIElement(List<RaycastResult> eventSystemRaysastResults)
    {
        for (int index = 0; index < eventSystemRaysastResults.Count; index++)
        {
            RaycastResult curRaysastResult = eventSystemRaysastResults[index];
            if (curRaysastResult.gameObject.layer == UILayer)
                return true;
        }
        return false;
    }


    //Gets all event system raycast results of current mouse or touch position.
    static List<RaycastResult> GetEventSystemRaycastResults()
    {
        PointerEventData eventData = new PointerEventData(EventSystem.current);
        eventData.position = Input.mousePosition;
        List<RaycastResult> raysastResults = new List<RaycastResult>();
        EventSystem.current.RaycastAll(eventData, raysastResults);
        return raysastResults;
    }

}
55 Likes

Hi dave thank you for your answer but I have already found the issue, the problem was is that I have 2 cameras in the scene one for the UI (UICamera) and second one is for the rest of the gameobjects (MainCamera), a PhysicsRaycaster component was attached to the MainCamera just to detect mouse/touch inputs on the gameobjects using unity pointer interfaces (IEventSystemHandler) and once I disabled that component everything went ok.

4 Likes

Dave, your answer was helpful for me! Thank you!

1 Like

Thanks daveMennenoh your solution really worked great for me.

1 Like

You dont need to disable the PhysicsRaycaster, just uncheck the event mask(layer mask) that you dont want it to interfere with. because you might still need to use the PhysicsRaycaster to select a 3d object, but if you disable it you wont be able to. hope this helps

2 Likes

Thanks daveMennenoh your solution was great for me too.

1 Like

It’s not often I can copy code directly from an answer and it just works. This time it did. You saved me atleast 30 minutes of looking this up and figuring it out on my own. Thank you!

1 Like
public UnityEvent OnPointerStay;

    int UILayer;

    private void Start()
    {
        UILayer = LayerMask.NameToLayer("UI");
    }

    private void Update()
    {
        if (IsPointerOverUIElement())
        {
            OnPointerStay?.Invoke();
        }
    }


    //Returns 'true' if we touched or hovering on Unity UI element.
    public bool IsPointerOverUIElement()
    {
        return IsPointerOverUIElement(GetEventSystemRaycastResults());
    }


    //Returns 'true' if we touched or hovering on Unity UI element.
    private bool IsPointerOverUIElement(List<RaycastResult> eventSystemRaysastResults)
    {
        for (int index = 0; index < eventSystemRaysastResults.Count; index++)
        {
            RaycastResult curRaysastResult = eventSystemRaysastResults[index];
            if (curRaysastResult.gameObject.layer == UILayer && curRaysastResult.gameObject == this.gameObject)
                return true;
        }
        return false;
    }


    //Gets all event system raycast results of current mouse or touch position.
    static List<RaycastResult> GetEventSystemRaycastResults()
    {
        PointerEventData eventData = new PointerEventData(EventSystem.current);
        eventData.position = Input.mousePosition;
        List<RaycastResult> raysastResults = new List<RaycastResult>();
        EventSystem.current.RaycastAll(eventData, raysastResults);
        return raysastResults;
    }

Encountered a bug which triggering one will trigger all of the same component, so I added curRaysastResult.gameObject == this.gameObject to fix it.

3 Likes

Just came up with the solution below…

  • Assuming mouse
  • Requires the “New Input System” (used V1.3)
public static bool IsMouseOverUi
    {
        get
        {
            // [Only works well while there is not PhysicsRaycaster on the Camera)
            //EventSystem eventSystem = EventSystem.current;
            //return (eventSystem != null && eventSystem.IsPointerOverGameObject());

            // [Works with PhysicsRaycaster on the Camera. Requires New Input System. Assumes mouse.)
            if (EventSystem.current == null)
            {
                return false;
            }
            RaycastResult lastRaycastResult = ((InputSystemUIInputModule)EventSystem.current.currentInputModule).GetLastRaycastResult(Mouse.current.deviceId);
            const int uiLayer = 5;
            return lastRaycastResult.gameObject != null && lastRaycastResult.gameObject.layer == uiLayer;
        }
    }

Not sure yet if it works reliably… but looks good so far.

I wanted to avoid shooting raycasts with every query, so I was looking for a way to access the EventSystem’s last raycast result.

6 Likes

Can’t you just use the Event Trigger component? Sorry I’m new, but it’s what I use all the time.

2 Likes

This is what I use.

Very helpful, thank you!

Dave thank you so much your answer was helpful

1 Like

If you want to know that the mouse is over a specific UI element and do a function ( eg. show a tooltip ). You can use the IPointer events on that gameobject.

EG.

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

// Event System's IPointer things are very easy to work with. Though, can be a little laggy.

public class SC_TooltipShower : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
     {
     public SC_GameController gameController;

     public string header = "";
     [TextArea(5,10)]
     public string body = "";
     public string footer = "";

     void Start()
          {
          gameController = FindObjectOfType<SC_GameController>();
          if (header == null)
               {
               header = "";
               }
          if (body == null)
               {
               body = "";
               }
          if (footer == null)
               {
               footer = "";
               }
          }

     public void OnPointerEnter(PointerEventData eventData)
          {
          gameController.tooltipHandler.ShowTooltip(body, header, footer);
          }

     public void OnPointerExit(PointerEventData eventData)
          {
          gameController.tooltipHandler.Hide();
          }

     }
2 Likes

This is the Solution I use
using UnityEngine.EventSystems;

void Update()
{
if (MouseOverUI())
{
Debug.Log(“Over UI”);
}

}
private bool MouseOverUI()
{
return EventSystem.current.IsPointerOverGameObject();
}

5 Likes

How would you adjust this to check if the mouse is over a specific UI by tag?

An easy way that works for me, is to first write the using statement “using UnityEngine.EventSystems;” at the top of the script attached to the UI element you want that should react to your mouse pointer.
After that, add the interfaces “IPointerEnterHandler” and “IPointerExitHandler” to the class line, like this :
“public class YourScript : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler”, this will let you use the methods “void OnPointerEnter(PointerEventData pointerEventData)”
and “void OnPointerExit(PointerEventData pointerEventData)”. Those ways will of course detect when the mouse enters that UI element’s space and when it exits it. Make sure no other UI elements are covering the element you want to interact with, they could be transparent.

4 Likes

yes this is what I ended up doing, thank you!

oh my god, there was a transparent image over mine. Thanks so much