How to Ignore Mouse Input with Unity's New Input System while Clicking on an UI Element?

62 Views Asked by At

I receive input from the mouse with the New Input System, but I do not want to receive input while the mouse is on any UI object, regardless of it being over or under any non-UI object. I tried EventSystem.current.IsPointerOverGameObject(). It seems to work, but it also gives a warning every time input is received.

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 UnityEngine.EventSystems.EventSystem:IsPointerOverGameObject () ...

Here is my code:

private void OnEnable()
{
  mouseClick.Enable();
  mouseClick.performed += MousePressed;
}
private void OnDisable()
{
  mouseClick.performed -= MousePressed;
  mouseClick.Disable();
}

private void MousePressed(InputAction.CallbackContext context)
{
  if (EventSystem.current.IsPointerOverGameObject()) return;

  Ray ray = _playerCam.ScreenPointToRay(Mouse.current.position.ReadValue());
  RaycastHit hit;
  ...
}

What should I do?

1

There are 1 best solutions below

2
sashok On BEST ANSWER
private void MousePressed(InputAction.CallbackContext _)
{
    PointerEventData eventData = new(EventSystem.current)
    {
        position = Input.mousePosition
    };

    List<RaycastResult> results = new();

    EventSystem.current.RaycastAll(eventData, results);

    if (results.Count > 0)
            return;

    // ...
}

If you want to check whether you've clicked on any UI object, you can implement it using EventSystem.

First we get the PointerEventData from the current EventSystem and assign its PointerEventData.position to Input.mousePosition. We don't have to convert it, as the position takes coordinates in screen space, which is also the space of the returned value. This can be also implemented like this. Whatever feels more readable for you.

Vector2 mousePos = Input.mousePosition;

PointerEventData eventData = new(EventSystem.current);

eventData.position = mousePos;

Then we call the EventSystem.current.RaycastAll method for previously set PointerEventData and store the List<RaycastResult> in our created results. This method gets every UI Object which has Graphic.raycastTarget set to true. Otherwise those objects don't even respond to user's clicks.

If the list isn't empty, we break the method, because there's at least one UI found. Now, if you want to check this UI being e.g. a Button, you've mentioned in comments, you can enumerate through its items and check for it.

foreach (RaycastResult result in results)
{
    if (result.gameObject.GetComponent<Button>())
        return;
}

Additionally, you can find your UI by a tag.

foreach (RaycastResult result in results)
{
    if (result.gameObject.CompareTag("MyButton"))
        return;
}

Notice that CallbackContext's name is _, as we don't need it. In your case its value is float, which returns 1 if pressed and 0 if not.