What is the expected/correct usage of Mouse.current.*?

I’m working with a large project that contains both the standard input system and the new input system, and I’m slowly migrating the old implementations to the new one.

I’ve read online how Mouse.current.leftButton.wasPressedThisFrame is often used instead of Input.GetMouseButtonDown(0), but I always got the impression that the new action-based system aimed at doing away with input polling from inside an Update(). Which is why I tried adding an “Left Click” action to my Input Actions and subscribed to the .performed event in my code to detect mouse clicks.

db5a20a34bced92807c3714e670b9809

At first glance both produce the same results… except in one specific case where I need to call EventSystem.current.IsPointerOverGameObject() when the mouse is clicked. For some reason, Unity cannot call this from within an action callback, and spits out this 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.

This breaks the previous functionality, as IsPointerOverGameObject() now seems to always return true.

My question is: what is the default usage of Mouse.current.* (or Pointer.current.*) that Unity expects us to implement with the new Input System? Is it a permanent stand-in replacement for the old Input.GetMouseButtonDown(0)? Should I try to handle as many inputs as possible with event callbacks, and only use Mouse.current.* in those edgecases where callbacks are not available?

Of course, I could have a mouse-click callback that toggles a local bool wasMouseClickedThisFrame, and then read its value in my Update(), but that hardly seems better than straight up calling Mouse.current.leftButton.wasPressedThisFrame where needed.

1 Like

There’s nothing wrong with polling input, and sometimes it’s the most effective way to handle things, while other times using the callback system is. Just need to use what works in each situation.

Edit: Also worth mentioning you can look up or reference specific input actions and poll those actions directly, rather than using Mouse.current.

1 Like

The Workflows page in the Input System documentation has an overview of the options, and the Directly Reading Device States sub-page has a breakdown of the pros and cons.

Directly polling inputs is a supported option in the Input System. You lose some features like (re-) binding and interactions but sometimes it can be more appropriate to use polling.

As for your issue with IsPointerOverGameObject(), it shouldn’t always return true, only use the data from the last frame, since callbacks are triggered during the Input System update, which is called before the Event System Input Module is updated in Update().

The documentation of IsPointerOverGameObject says this:

Be aware that this method relies on state set up during UI event processing that happens in EventSystem.Update, that is, as part of MonoBehaviour updates. This step happens after input processing. Thus, calling this method earlier than that in the frame will make it poll state from last frame.

Calling this method from within an InputAction callback (such as InputAction.performed) will result in a warning. See the “UI vs Game Input” sample shipped with the Input System package for how to deal with this fact.

Ad the explanation in the sample’s Readme:

For the most part, input processing is done in Update() such that actions are processed on a per-frame basis. Responses to actions that may conflict with UI input use IsPointerOverGameObject to determine whether the pointer is currently over UI. Since this is called from Update() and thus outside of input processing (i.e. not from within an InputAction callback), the method can be safely called and will return an accurate result.

There are two implementations of handling the Fire action. One uses the same approach just mentioned where the action’s response is dealt with once per frame. The second one, however, immediately creates a projectile within the callback and thus operates at sub-frame accuracy. For a low-frequency input such as the Fire action here, this is not generally a useful thing to do but it is done here for the sake of demonstration. We cannot call IsPointerOverGameObject from the action callback and thus need to use the UI’s public raycasting interface to determine “over UI?” state manually for the current pointer position.

The first approach just sets a bool, which is then processed in Update(). As you said, this is not much different than polling directly in Update().

The second approach works around the issue by raycasting the UI manually using EventSystem.current.RaycastAll.

You could also have a generic mechanism to queue a delegate to be executed in Update() (a bit like EditorApplication.delayedCall). Then you can bounce your processing form the action callback to Update() and use IsPointerOverGameObject from there. This doesn’t require you to add a bool field for every input you have.

3 Likes

Thanks, makes me feel less guilty of using it :smile:

Apparently the true value I was always getting was just a result of how things were setup in my scene.
I’ve gone with a hybrid approach that uses callbacks for most inputs, but switches to Mouse.current.leftButton to bypass the IsPointerOverGameObject() issue.

Thanks for both of your replies!

1 Like