This all works fine for the most part. I am able to utilize this mouse as I would a normal mouse (camera controllers work completely fine), however I am unable to interact with UI. When the virtual mouse is hovering over a button the button doesn’t transition to a hovered state, and when I click on a button or an input field nothing happens. Another thing to note is that EventSystem.current.IsPointerOverGameObject() always returns null when targeting the “virtual” mouse, but when I switch to the native mouse, it returns the correct values.
Is this a limitation in the new input system? If not, any help would be appreciated.
(I know that I could probaby work around this issue by using Mouse.WarpCursorPosition(), however I am unable to do so for my use case)
Yes, I have a InputSystemUIInputModule component in the scene:
Is there anything else I have to do to get it to work with the virtual mouse? I know that the module is functioning for my hardware/native mouse because if I disable the module, I cannot interact with any UI.
First thing I’d check is the input debugger to see whether the UI bindings are picking up the virtual mouse correctly. The controls for it should appear under the respective actions.
If that is working, next thing I’d probably check is whether the coordinates are indeed right. Mouse operates in player screen space, not canvas UI space.
If all that is working, could be there’s some interference from the “Pointer Behavior” setting (though there should be none). If switching to “All Pointers As Is” makes a difference, that’d likely be the case.
BTW looking at the VirtualMouseInput component that comes with the Gamepad Mouse Cursor sample may help. It adds a virtual mouse driven by the gamepad and works with the UI.
Starting off, both the native mouse and the virtual mouse look nearly identical when inspecting each device.
Here is the native mouse (Mouse):
Here is the virtual mouse (Mouse1):
The coordinates of the virtual mouse are perfect and I can see that mouse clicks are being registered as expected. The only difference appears to be that the the native mouse has a “Native” flag.
The UI bindings seem to be fine as well:
One thing that might be worth noting is that we assign the virtual mouse (and the other virtual devices) to an InputUser:
However we do not associate any actions with the user. Could that be the root of the issue?
Finally, changing the “Pointer Behavior” setting had no effect.
I have the same issue in the demo scene for Gamepad Mouse Cursor. The analog sticks move the cursor just fine, but there is no interaction when pressing any of the buttons.
+1 except I noticed that it’s not automatically adding the bindings for the virtual mouse’s actions. The mouse is associated to a user but none of the actions.
If you notice that adding a virtual mouse seems to click a random UI element when first enabled, disable the InputSystemUIInputModule component before connecting the virtual mouse and then enable it a few updates after adding the virtual mouse.
Disable the (Multiplayer) Event System’s “Send Navigation Events” checkbox. Otherwise the game will highlight seemingly random UI elements as you move the mouse because it will interpret the joystick motion as both mouse and menu navigation. This one had me pulling my hair out trying to fix the wrong bug until I figured it out.
I’ve tried everything in the above post by RaspberryPuppies, and I’m still unable to get the virtual mouse to interact with UI elements.
The only thing that works is to remove the PlayerInput component from the scene. (Not a solution)
The PlayerInput is doing something that prevents the virtual mouse from interacting with the UI.
It’s as though any updates to the mouse’s position aren’t reflected in the UI navigation. I am allowed to click the virtual mouse, but its position seems locked at (0,0).
I’ve come up with a solution that doesn’t depend on PlayerInput. I’ll share the code here.
I’m sure it could be improved, but this should be a decent start for anyone in a similar situation.
Simply place this script onto the GameObject you want to act as the cursor.
using System.Collections;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.UI;
[RequireComponent(typeof(RectTransform))]
public class AutoHideVirtualMouse : MonoBehaviour
{
[SerializeField] private InputActionReference _stickAction;
[SerializeField] private InputActionReference _mousePointAction;
[SerializeField] private InputActionReference _clickAction;
[SerializeField] private Graphic _image;
[SerializeField] private RectTransform _canvasTransform;
[SerializeField] private float _moveSpeed = 500;
private Mouse _virtualMouse;
private RectTransform _cursorTransform;
private Vector2 _delta;
private void Awake()
{
_cursorTransform = GetComponent<RectTransform>();
}
private void OnEnable()
{
if (_virtualMouse == null)
{
_virtualMouse = InputSystem.AddDevice<Mouse>("VirtualMouse");
}
SetCursorEnabled(false);
_stickAction.action.Enable();
_mousePointAction.action.Enable();
_clickAction.action.Enable();
_stickAction.action.performed += OnStickMove;
_mousePointAction.action.performed += OnMouseMove;
_clickAction.action.performed += OnClick;
InputSystem.onAfterUpdate += OnAfterUpdate;
}
private void OnDisable()
{
SetCursorEnabled(false);
InputSystem.onAfterUpdate -= OnAfterUpdate;
_stickAction.action.performed -= OnStickMove;
_mousePointAction.action.performed -= OnMouseMove;
_clickAction.action.performed -= OnClick;
}
private void SetCursorEnabled(bool enabled)
{
Cursor.visible = !enabled;
_image.enabled = enabled;
if (_virtualMouse == null) return;
if (enabled)
{
if (!_virtualMouse.added) InputSystem.AddDevice(_virtualMouse);
//move virtual mouse to screen center instead of having it start at (0,0)
InputState.Change(_virtualMouse.position, new Vector2(Screen.width / 2, Screen.height / 2));
}
else
{
InputSystem.RemoveDevice(_virtualMouse);
}
}
private void OnAfterUpdate()
{
if (!_virtualMouse.added) return;
var newPosition = (_virtualMouse.position.ReadValue() + _delta * _moveSpeed * Time.deltaTime);
newPosition.x = Mathf.Clamp(newPosition.x, 0, Screen.width);
newPosition.y = Mathf.Clamp(newPosition.y, 0, Screen.height);
//move virtual mouse screen position
InputState.Change(_virtualMouse.position, newPosition);
InputState.Change(_virtualMouse.delta, _delta * _moveSpeed * Time.deltaTime);
//move cursor transform accordingly
RectTransformUtility.ScreenPointToWorldPointInRectangle(_canvasTransform, newPosition, null, out Vector3 localPoint);
_cursorTransform.position = localPoint;
}
private void OnStickMove(InputAction.CallbackContext ctx)
{
if (!_image.enabled)
{
SetCursorEnabled(true);
}
if (!_virtualMouse.added) return;
_delta = ctx.ReadValue<Vector2>();
}
private void OnClick(InputAction.CallbackContext ctx)
{
if (!_virtualMouse.added) return;
_virtualMouse.CopyState(out MouseState mouseState);
mouseState.WithButton(MouseButton.Left, ctx.ReadValueAsButton());
InputState.Change(_virtualMouse, mouseState);
}
private void OnMouseMove(InputAction.CallbackContext ctx)
{
if (_image.enabled && ctx.control.device.name != "VirtualMouse")
{
StartCoroutine(Co_EndOfFrame());
}
//using local coroutine because removing the device before end of frame causes errors
IEnumerator Co_EndOfFrame()
{
yield return new WaitForEndOfFrame();
SetCursorEnabled(false);
}
}
}
Was implementing this today and had the same issues as above - the only way I got it working was by separating the input actions into separate files, one “UI” .inputactions file that is fed into the EventSystem, and one for everything else game related. I tried switching between active action maps when toggling the virtual mouse, but that didnt help either.
I was searching around and I found a solution on another forum; you need to set your Cursor.lockstate = CursorLockMode.Confined not Locked. The Locked will tick the virtual mouse to thinking it is on the center of the screen. That seems to help my project so good luck for yours!
Thank you for posting this. I tried this solution, and it was exactly what was needed to overcome the almost inexplicable ‘virtual mouse cursor does not register UI events like mouse-over or click’ problem.
I had only stumbled across Player Input as a potential culprit by going through my scene and deactivating parent Game Objects one by one until the virtual mouse started behaving correctly. That prompt led me to this thread, and then to your reply.
Creating a brand new Input Actions and having the Event System’s UI Input Manager reference it looks to be the fix.
A truly maddening bug because every tutorial I could find on virtual mouse implementation didn’t have any other Game Objects in the scene that had the Player Input component, so there was no indication that was the culprit. Ah, game development.
pulling my hair out over this. deeply regret choosing Unity…again… Tried all of this and other forum threads. Ridiculous this feature has such awful documentation and buggy implementation
I just discovered that Virtual Mouse will not work if his Cursor Graphics (Image) has “Raycast Target” ON. I looked at the Input System Sample and it was disabled.