Skip to content

FIX: VirtualMouseInput not supporting UI scaling other than constant. #1119

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
{
"name": "",
"id": "39af39e2-c75c-421e-84bf-1e4ff9793ab4",
"path": "<VirtualMouse>/position",
"path": "<Mouse>/position",
"interactions": "",
"processors": "",
"groups": "",
Expand All @@ -45,7 +45,7 @@
{
"name": "",
"id": "f9d5a98e-68a3-44c8-a096-a1a30237ca81",
"path": "<VirtualMouse>/leftButton",
"path": "<Mouse>/leftButton",
"interactions": "",
"processors": "",
"groups": "",
Expand All @@ -56,7 +56,7 @@
{
"name": "",
"id": "7ffd960c-11ef-4fc0-b91b-4cbd02eba1b8",
"path": "<VirtualMouse>/scroll",
"path": "<Mouse>/scroll",
"interactions": "",
"processors": "",
"groups": "",
Expand Down
9 changes: 5 additions & 4 deletions Assets/Samples/GamepadMouseCursor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ This sample demonstrates how to set this up with the input system.
1) It uses a custom [actions file](./GamepadMouseCursorUIActions.inputactions) for feeding input to the UI as the default actions are set up for gamepad navigation &ndash; something we don't want here as it would conflict with gamepad input being used for virtual cursor navigation.
2) Note how `InputSystemUIInputModule` on the `EventSystem` GameObject is set up to reference actions from that file.
3) The key component to take a look at is `VirtualMouseInput` on `Canvas >> Cursor`. The component is set up to receive input from the gamepad and translates it into motion on the `RectTransform` it is given. When going into play mode, you should also see a `Virtual Mouse` being added to the devices by the component.
4) Note how the anchor position on the `RectTransform` is set to bottom left. This way the coordinate system responds to how mouse screen space operates.
5) Note how `Cursor` is the last child of `Canvas` so that it draws on top of everything else.
6) Note that `Raycast Target` on the `Image` component of the cursor is turned off to avoid raycasts from the mouse cursor hitting the cursor itself.
7) Note that `Cursor Mode` on the `VirtualMouseInput` component is set to `Hardware Cursor If Available`. This will cause the component to look for a system mouse. If present, the system mouse is disabled and the system mouse cursor is warped to the virtual mouse position using `Mouse.WarpCursorPosition`. If no system mouse is present, `Cursor Graphic` will be used as a software mouse cursor.
4) Note how `Cursor` is the last child of `Canvas` so that it draws on top of everything else.
5) Note that `Raycast Target` on the `Image` component of the cursor is turned off to avoid raycasts from the mouse cursor hitting the cursor itself.
6) Note that `Cursor Mode` on the `VirtualMouseInput` component is set to `Hardware Cursor If Available`. This will cause the component to look for a system mouse. If present, the system mouse is disabled and the system mouse cursor is warped to the virtual mouse position using `Mouse.WarpCursorPosition`. If no system mouse is present, `Cursor Graphic` will be used as a software mouse cursor.

>NOTE: The `VirtualMouseInput` component currently does not work correctly with world-space canvases.

# Licenses

Expand Down
75 changes: 65 additions & 10 deletions Assets/Samples/GamepadMouseCursor/VirtualMouseInput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

////TODO: respect cursor lock mode

////TODO: find a way to automatically turn the gamepad cursor on/off based on gamepad use

////TODO: investigate how driving the HW cursor behaves when FPS drops low
//// (also, maybe we can add support where we turn the gamepad mouse on and off automatically based on whether the system mouse is used)

Expand All @@ -13,6 +15,8 @@

////TODO: make it work with PlayerInput such that it will automatically look up actions in the actual PlayerInput instance it is used with (based on the action IDs it has)

////FIXME: make this work with world-space canvases

////REVIEW: should we default the SW cursor position to the center of the screen?

////REVIEW: consider this for inclusion directly in the input system
Expand Down Expand Up @@ -74,9 +78,10 @@ public float cursorSpeed
/// that is made to correspond to the position of <see cref="virtualMouse"/>. If this is set to <see
/// cref="CursorMode.HardwareCursorIfAvailable"/> and there is a native <see cref="Mouse"/> device present,
/// the component will take over that mouse device and disable it (so as for it to not also generate position
/// updates). It will then use <see cref="Mouse.WarpCursorPosition"/> to move the system mouse cursor to
/// correspond to the position of the <see cref="virtualMouse"/>. In this case, <see cref="cursorGraphic"/>
/// will be disabled and <see cref="cursorTransform"/> will not be updated.
/// updates) except when this is explicitly disabled via <see cref="disableSystemMouse"/>. It will then use
/// <see cref="Mouse.WarpCursorPosition"/> to move the system mouse cursor to correspond to the position of the
/// <see cref="virtualMouse"/>. In this case, <see cref="cursorGraphic"/> will be disabled and
/// <see cref="cursorTransform"/> will not be updated.
/// </summary>
/// <value>Whether the system mouse cursor (if present) should be made to correspond with the virtual mouse position.</value>
/// <remarks>
Expand All @@ -96,7 +101,8 @@ public CursorMode cursorMode
// If we're turning it off, make sure we re-enable the system mouse.
if (m_CursorMode == CursorMode.HardwareCursorIfAvailable && m_SystemMouse != null)
{
InputSystem.EnableDevice(m_SystemMouse);
if (m_DisableSystemMouse)
InputSystem.EnableDevice(m_SystemMouse);
m_SystemMouse = null;
}

Expand Down Expand Up @@ -153,11 +159,51 @@ public float scrollSpeed
/// </remarks>
public Mouse virtualMouse => m_VirtualMouse;

/// <summary>
/// If <see cref="cursorMode"/> is set to <see cref="CursorMode.HardwareCursorIfAvailable"/>, whether to
/// disable the system mouse, if present. This is on by default.
/// </summary>
/// <value>If true, the system mouse will be disabled if present and while the VirtualMouseInput component is active.</value>
/// <remarks>
/// If the component drives the system mouse cursor rather than using a software cursor, the system mouse cursor position will
/// get warped around using <see cref="Mouse.WarpCursorPosition"/>. This, however, has the side-effect of generating input
/// on the system <see cref="Mouse"/> device. In other words, mouse motion from the gamepad will come in through both
/// the VirtualMouse created for the gamepad and the <see cref="Mouse"/> added by the system (with a one frame lag for
/// the latter).
///
/// To avoid this, the system mouse will by default get disabled while the VirtualMouseInput component is enabled. Thus,
/// the system <see cref="Mouse"/> will not receive input while the VirtualMouseInput component is enabled. The idea here
/// is that the application should determine when the gamepad is used and only turn on the gamepad cursor while this is
/// the case. One possible approach is to set up a control scheme for gamepads and enable the gamepad mouse cursor only
/// while the gamepad scheme is active.
///
/// However, by setting this property to false, the disabling of the system <see cref="Mouse"/> device can be suppressed.
/// This means the system mouse will stay fully functional. You will, however, see concurrent input on both the VirtualMouse
/// and the system mouse. This may, for example, interfere with automatic control scheme switching (which is why the disabling
/// is on by default).
/// </remarks>
public bool disableSystemMouse
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A user got caught off guard that the system mouse wouldn't work if VirtualMouseInput is used. This is intentional and IMO the better thing to do in the current setup. However, I can see how that can be quite undesirable so I opted for just exposing an option to toggle the behavior off. Default is on so behavior is unchanged from before.

{
get => m_DisableSystemMouse;
set
{
if (value == m_DisableSystemMouse)
return;
m_DisableSystemMouse = value;

if (m_SystemMouse != null)
{
if (value)
InputSystem.DisableDevice(m_SystemMouse);
else
InputSystem.EnableDevice(m_SystemMouse);
}
}
}

/// <summary>
/// The Vector2 stick input that drives the mouse cursor, i.e. <see cref="Mouse.position"/> on
/// <see cref="virtualMouse"/> and the <a
/// href="https://docs.unity3d.com/ScriptReference/RectTransform-anchoredPosition.html">anchoredPosition</a>
/// on <see cref="cursorTransform"/> (if set).
/// <see cref="virtualMouse"/> and the position on <see cref="cursorTransform"/> (if set).
/// </summary>
/// <value>Stick input that drives cursor position.</value>
/// <remarks>
Expand Down Expand Up @@ -290,7 +336,7 @@ protected void OnEnable()
// Set initial cursor position.
if (m_CursorTransform != null)
{
var position = m_CursorTransform.anchoredPosition;
var position = m_CursorTransform.position;
InputState.Change(m_VirtualMouse.position, position);
m_SystemMouse?.WarpCursorPosition(position);
}
Expand Down Expand Up @@ -384,7 +430,8 @@ private void TryEnableHardwareCursor()
return;
}

InputSystem.DisableDevice(m_SystemMouse);
if (m_DisableSystemMouse)
InputSystem.DisableDevice(m_SystemMouse);

// Sync position.
if (m_VirtualMouse != null)
Expand Down Expand Up @@ -446,7 +493,7 @@ private void UpdateMotion()
if (m_CursorTransform != null &&
(m_CursorMode == CursorMode.SoftwareCursor ||
(m_CursorMode == CursorMode.HardwareCursorIfAvailable && m_SystemMouse == null)))
m_CursorTransform.anchoredPosition = newPosition;
m_CursorTransform.position = newPosition;

m_LastStickValue = stickValue;
m_LastTime = currentTime;
Expand All @@ -468,8 +515,16 @@ private void UpdateMotion()
}

[Header("Cursor")]
[Tooltip("Whether to use the system mouse cursor, if available. Or whether to use a pure software cursor only.")]
[SerializeField] private CursorMode m_CursorMode;
[Tooltip("With 'Cursor Mode' set to 'Hardware Cursor If Available', whether to disable the system mouse. The cursor warping that is used "
+ "to drive the HW cursor will generate input on the mouse device which mirrors the input on the virtual mouse. By enabling this flag, "
+ "this input can be suppressed by disabling the system mouse altogether. Note that this will make *no* input from the system mouse come "
+ "through while the VirtualMouseInput component is active.")]
[SerializeField] private bool m_DisableSystemMouse = true;
[Tooltip("The UI graphic that represents the software cursor.")]
[SerializeField] private Graphic m_CursorGraphic;
[Tooltip("The UI transform for the UI object that represents the software cursor.")]
[SerializeField] private RectTransform m_CursorTransform;

[Header("Motion")]
Expand Down
7 changes: 6 additions & 1 deletion Packages/com.unity.inputsystem/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ however, it has to be formatted properly to pass verification tests.

### Fixed

- `VirtualMouseInput` not moving the software cursor when set to `HardwareCursorIsAvailable` but not having a hardware cursor ()
- `VirtualMouseInput` not moving the software cursor when set to `HardwareCursorIsAvailable` but not having a hardware cursor.
- `VirtualMouseInput` not working correctly with `CanvasScaler` settings other than `ConstantPixelSize`. Fix contributed by [ad-walker](https://github.com/ad-walker) in [#1078](https://github.com/Unity-Technologies/InputSystem/pull/1078).
- Can now override built-in Android gamepad layouts. Previously, the input system would always choose its default defaults even after registering more specific layouts using `InputSystem.RegisterLayout`.
- `InputControlPath.TryGetControlLayout` no longer throws `NotImplementedException` for `<Mouse>/scroll/x` and similar paths where the layout is modifying a control it inherited from its base layout ([thread](https://forum.unity.com/threads/notimplementedexception-when-using-inputcontrolpath-trygetcontrollayout-on-mouse-controls.847129/)).
- Fixed compilation errors when disabling built-in VR and XR packages. ([case 1214248](https://issuetracker.unity3d.com/issues/enable-input-system-symbol-is-not-being-updated-when-the-input-system-is-changed-in-player-settings/)).
Expand Down Expand Up @@ -40,6 +41,10 @@ however, it has to be formatted properly to pass verification tests.
- `InputDevice.all` has been deprecated due to the confusion it creates with other getters like `Gamepad.all`. Use `InputSystem.devices` instead ([case 1231216](https://issuetracker.unity3d.com/issues/joystick-dot-all-lists-more-than-just-joysticks)).
* In the same vein, we added a new `Joystick.all` getter that works the same as `Gamepad.all`.

### Added

- Added an explicit `Disable System Mouse` setting to `VirtualMouseInput` to allow toggling the default behavior off which makes the component turn off the system mouse while it is enabled (so as to suppress the system mouse doubling the input activity on the VirtualMouse).

## [1.0.0-preview.6] - 2020-03-06

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ internal class RemoteInputPlayerConnection :
{
public static readonly Guid kNewDeviceMsg = new Guid("fcd9651ded40425995dfa6aeb78f1f1c");
public static readonly Guid kNewLayoutMsg = new Guid("fccfec2b7369466d88502a9dd38505f4");
public static readonly Guid kNewEventsMsg = new Guid("34d9b47f923142ff847c0d1f8b0554d9");
public static readonly Guid kNewEventsMsg = new Guid("53546641df1347bc8aa315278a603586");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated fix but so minor I didn't bother routing it in separately. This one was a copypaste mistake where I ended up inadvertently reusing a GUID from the docs. Which then someone discovered because another Unity system had done the same :D

public static readonly Guid kRemoveDeviceMsg = new Guid("e5e299b2d9e44255b8990bb71af8922d");
public static readonly Guid kChangeUsagesMsg = new Guid("b9fe706dfc854d7ca109a5e38d7db730");
public static readonly Guid kStartSendingMsg = new Guid("0d58e99045904672b3ef34b8797d23cb");
Expand Down