Check if UI was clicked with unity new input system 1.2.0

I’ve run into some problems when updating my project to Unity 2020.3.25f1. The update has made some changes to the input system which affects the way I am checking if the mouse click was performed over UI or not.

public class ClickHandler : MonoBehaviour
{
    private Controls controls;

	private void Awake()
	{
        //Get the new control system and set the controls needed for this script
        controls = new Controls();
		controls.Player.MouseClick.performed += _ => OnMouseClicked();
	}

	private void OnEnable() => controls.Enable();

	private void OnDisable() => controls.Disable();

    public void OnMouseClicked()
	{
        //ignore if UI was clicked.
        if (UIManager.Instance.IsMouseOverUI())
        {
            return;
        }}

In UIManager script:

 public bool IsMouseOverUI()
    {
        return EventSystem.current.IsPointerOverGameObject();
    }

With the new version I now recieve the following warning:

Calling IsPointerOverGameObject() from within event processing (such as from InputAction callbacks) will not work as expected; it will query UI state from the last frame

I understand that I can solve this by moving the IsPointerOverGameObject() into Unity Update() function, which guarantees the logic to run each frame. I fail to understand how to make this work with the new eventsystem, where I check inputs through events rather than an update polling-approach.

What is a good way to use the new input system and check if UI was pressed or not?

Thanks in advance!

This worked for me. (I know this post is a few months old)

PointerEventData pointerEventData = new PointerEventData(EventSystem.current);
pointerEventData.position = Mouse.current.position.ReadValue();
List<RaycastResult> raycastResultsList = new List<RaycastResult>();
EventSystem.current.RaycastAll(pointerEventData, raycastResultsList);
mouseOverUI = false;
for (int i=0; i < raycastResultsList.Count; i++)
{
    if (raycastResultsList*.gameObject.GetType() == typeof(GameObject))*

{
mouseOverUI = true;
break;
}
}
if (mouseOverUI) return;

Honestly, i don’t know the answer, but i would personally try to use EventSystem.current.currentSelectedGameObject != null instead, maybe, with some adjustments, it will magically work. Hope you get better answers.

See if you can implement pointer events. ex:

public class Foo : MonoBehavior, IPointerEnterHandler, IPointerExitHandler, IPointerUpHandler, IPointerDownHandler

I haven’t used it in the new input system, but I think it should work.

otherwise, you could implement:

This is a pretty old topic, but it’s still high in search results. Basically there are two ways.

The simplest by far is to just store IsPointerOverGameObject() every frame

public class GameInputManager: MonoBehaviour
{
    public static bool IsPointerOverUI { get; private set;}

    public void Update()
    { 
        // Setting the flag here, as querying it during the event callback is creates warning
        // It does mean that this flag will still be one frame late, but there's no easy fix
        IsPointerOverUI =
            EventSystem.current.NP()?.IsPointerOverGameObject() ?? false;
    }
}

The second solution is to add a component to all your root canvases that detects hovers:


public class UIHoverDetector : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
  private static HashSet<UIHoverDetector> ActiveHover = new HashSet<UIHoverDetector>();

  public static bool IsPointerOverGameObject
  {
    get
    {
      foreach (var hover in ActiveHover)
      {
        if (hover != null && hover.isActiveAndEnabled)
          return true;
      }
      return false;
    }
  }

  void IPointerEnterHandler.OnPointerEnter(PointerEventData eventData)
  {
    ActiveHover.Add(this);
  }
  void IPointerEnterHandler.OnPointerExit(PointerEventData eventData)
  {
    ActiveHover.Remove(this);
  }
  void OnDisable()
  {
    ActiveHover.Remove(this);
  }
}