Skip to content

Conversation

ritamerkl
Copy link
Collaborator

@ritamerkl ritamerkl commented Jul 24, 2025

Description

This PR introduces sending pointer data (e.g. mouse, pen, touch...) to native for the OnMouse events driven by the InputSystem. It also adds tests and samples for the OnMouse events working with the InputSystem. The behaviour on native side is introduced with this PR and both PR's should land together, or one (shortly) after the other.

Testing status & QA

Only manual testing for the sample.

Overall Product Risks

  • Complexity: 1
  • Halo Effect: 1

Comments to reviewers

Please review together with https://github.cds.internal.unity3d.com/unity/unity/pull/73198.

Checklist

Before review:

  • Changelog entry added.
    • Explains the change in Changed, Fixed, Added sections.
    • For API change contains an example snippet and/or migration example.
    • JIRA ticket linked, example (case %%). If it is a private issue, just add the case ID without a link.
    • Jira port for the next release set as "Resolved".
  • Tests added/changed, if applicable.
    • Functional tests Area_CanDoX, Area_CanDoX_EvenIfYIsTheCase, Area_WhenIDoX_AndYHappens_ThisIsTheResult.
    • Performance tests.
    • Integration tests.
  • Docs for new/changed API's.
    • Xmldoc cross references are set correctly.
    • Added explanation how the API works.
    • Usage code examples added.
    • The manual is updated, if needed.

During merge:

  • Commit message for squash-merge is prefixed with one of the list:
    • NEW: ___.
    • FIX: ___.
    • DOCS: ___.
    • CHANGE: ___.
    • RELEASE: 1.1.0-preview.3.

After merge:

  • Create forward/backward port if needed. If you are blocked from creating a forward port now please add a task to ISX-1444.

@codecov-git.colasdn.top
Copy link

codecov-git.colasdn.top bot commented Jul 24, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

@@             Coverage Diff             @@
##           develop    #2207      +/-   ##
===========================================
+ Coverage    68.14%   76.71%   +8.57%     
===========================================
  Files          367      465      +98     
  Lines        53685    87919   +34234     
===========================================
+ Hits         36584    67448   +30864     
- Misses       17101    20471    +3370     
Flag Coverage Δ
inputsystem_MacOS_2021.3 5.91% <ø> (?)
inputsystem_MacOS_2021.3_project 78.05% <ø> (?)
inputsystem_MacOS_2022.3 5.37% <ø> (?)
inputsystem_MacOS_2022.3_project 74.58% <ø> (?)
inputsystem_MacOS_6000.0 5.19% <ø> (?)
inputsystem_MacOS_6000.0_project 76.50% <ø> (?)
inputsystem_MacOS_6000.2 5.19% <ø> (?)
inputsystem_MacOS_6000.2_project 76.50% <ø> (?)
inputsystem_MacOS_6000.3 5.19% <ø> (?)
inputsystem_MacOS_6000.3_project 76.50% <ø> (?)
inputsystem_Ubuntu_2021.3 5.91% <ø> (?)
inputsystem_Ubuntu_2021.3_project 77.96% <ø> (?)
inputsystem_Ubuntu_2022.3 5.38% <ø> (?)
inputsystem_Ubuntu_2022.3_project 74.39% <ø> (?)
inputsystem_Ubuntu_6000.0 5.19% <ø> (?)
inputsystem_Ubuntu_6000.0_project 76.32% <ø> (?)
inputsystem_Ubuntu_6000.2 5.19% <ø> (?)
inputsystem_Ubuntu_6000.2_project 76.32% <ø> (?)
inputsystem_Ubuntu_6000.3 5.19% <ø> (?)
inputsystem_Ubuntu_6000.3_project 76.31% <ø> (?)
inputsystem_Windows_2021.3 5.91% <ø> (?)
inputsystem_Windows_2021.3_project 78.20% <ø> (?)
inputsystem_Windows_2022.3 5.37% <ø> (?)
inputsystem_Windows_2022.3_project 74.72% <ø> (?)
inputsystem_Windows_6000.0 5.19% <ø> (?)
inputsystem_Windows_6000.0_project 76.64% <ø> (?)
inputsystem_Windows_6000.2 5.19% <ø> (?)
inputsystem_Windows_6000.2_project 76.64% <ø> (?)
inputsystem_Windows_6000.3 5.19% <ø> (?)
inputsystem_Windows_6000.3_project 76.64% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
.../com.unity.inputsystem/InputSystem/InputManager.cs 88.77% <ø> (ø)

... and 100 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Collaborator

@jfreire-unity jfreire-unity left a comment

Choose a reason for hiding this comment

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

Nice work @ritamerkl ! I like the approach and the sample is of reasonable size to test the main functionality. Also really nice to have plenty of tests.

However:

  • This functionality needs to be guarded with defines in asmdef, as this will only be available from 6.3 forward AFAIK. So if I try this PR without the trunk PR, I'll get compilation errors.
  • I would like to see at least 1 test with Touch as well, particularly with more than 1 touch. Mouse and Pen are pretty similar as they are a single pointer.

@jfreire-unity
Copy link
Collaborator

Nice work @ritamerkl ! I like the approach and the sample is of reasonable size to test the main functionality. Also really nice to have plenty of tests.

However:

  • This functionality needs to be guarded with defines in asmdef, as this will only be available from 6.3 forward AFAIK. So if I try this PR without the trunk PR, I'll get compilation errors.
  • I would like to see at least 1 test with Touch as well, particularly with more than 1 touch. Mouse and Pen are pretty similar as they are a single pointer.

Also there's some CI failures that will need to be addressed. Not sure if it's only because of the lack of defines or if there's any impact on pointer devices functionality.

@ritamerkl
Copy link
Collaborator Author

ritamerkl commented Jul 25, 2025

WIP: working on adding touch samples (multi-touch) & parallel pointers (eg. touch&pen).

Copy link
Collaborator

@LeoUnity LeoUnity left a comment

Choose a reason for hiding this comment

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

This is looking great!
I'm happy to see us improving our feature parity! Also thanks for investing the time on the tests!
I've left a few comments, but I'll leave it up to you to decide which ones to address

@ritamerkl ritamerkl changed the title NEW: MouseEvents for InputSystem Samples & Tests NEW: MouseEvents for InputSystem - Sending data from package & Samples and Tests Aug 22, 2025
Copy link
Collaborator

@ekcoh ekcoh left a comment

Choose a reason for hiding this comment

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

I see 3 files under "untitled folder", the folder including those files should be removed from this PR right?

InvokeAfterUpdateCallback(updateType);
//send pointer data to backend for OnMouseEvents
if (Pointer.current != null && gameIsPlaying)
NativeInputSystem.SetMouseEventsData(Pointer.current.press.isPressed, Pointer.current.press.wasPressedThisFrame, Pointer.current.position.x.value, Pointer.current.position.y.value);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Shouldn't this be routed via INativeInputRuntime interface and its NativeInputRuntime and TestInputRuntime implementations?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

NativeInputRuntime is the name of the Bindings class in the module, I fail to understand what exactly you are referring to.
I placed it here to have all updated data after the inputsystem Update, this happens for test as well.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I referred to the fact that this is calling NativeInputSystem directly. If you look at NativeInputRuntime.cs you will see it implements INativeInputRuntime as an abstraction of the module to allow stubbing it away in e.g. tests. Hence InputTestRuntime also exists stubbing these calls. It's basically a mocking strategy that has historically been used. If this is possible to auto-test without mocking, it should right? Then I see no reason why this would be just fine, but just wanted to let you know in case you had not noticed since it seems SetMouseEventsData is part of Input module based on where its placed/mapped?

Copy link
Collaborator

@ekcoh ekcoh Aug 27, 2025

Choose a reason for hiding this comment

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

And NativeInputRuntime is not the bindings class, it's just an abstraction within the package. The bindings class (P/Invoke) is called NativeInputSystem which is the one you are calling here

Copy link
Collaborator

@jfreire-unity jfreire-unity Aug 28, 2025

Choose a reason for hiding this comment

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

I was adding this same comment. We should call this as m_Runtime.SetMouseEventsData(...);. This avoids making other classes (like this one) dependent on the bindings as well. This way we only have NativeInputRuntime class as a single dependent of the Module bindings (NativeInputSystem) and make it consistent across the codebase as is.

And by making it part of IInputRuntime interface we leverage the mocking strategy @ekcoh mentioned as well. So I think this should be improved.

Copy link
Collaborator Author

@ritamerkl ritamerkl Sep 8, 2025

Choose a reason for hiding this comment

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

Alright, so I understand what you are after. I confused the names :D
I was considering a change until I noticed:

  1. including SetMouseEventsData into the IInputRuntime would mean we would need a implementation for InputTestRuntime as well, since there is no way to mock setting the data, but we really need to send the data to the module to achieve reliable test results, this would mean we have to include NativeInputSystem there (so there are no savings on bindings).
  2. there is no way to mock sending the data for mouse events, so it does not really make sense to bloat the code with two extra methods in NativeInputRuntime/InputTestRuntime.

I would leave this as is, I guess that is fine for this kind. feel free to object if I missed something.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Hm, good point. Yeah, not sure how we could mock this in InputTestRuntime then. And from what you mentioned, it doesn't seem to make sense to have it in InputTestRuntime as well, if we really need to call the module.

I don't have a better answer right now so maybe this is fine as is.

It just feels odd to be breaking the class contract that in NativeInputRuntime should be the only file referencing NativeInputSystem. But maybe that's ok in this case?

Anyway, this is not a blocker at all. I'll leave it approved.

using UnityEngine.InputSystem.EnhancedTouch;
using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch;

public class OnMouseEventSample : MonoBehaviour
Copy link
Collaborator

Choose a reason for hiding this comment

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

If the intent here is to serve as a sample (and maybe also our own way to manually test or debug this), I would suggest that we have all the supported implicit script mouse event callback functions present in this file.

Copy link
Collaborator

Choose a reason for hiding this comment

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

E.g. missing OnMouseOver, OnMouseEnter, OnMouseExit, OnMouseUp, OnMouseUpAsButton

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Right, added here: 0bef5d2

@@ -0,0 +1,199 @@
#if UNITY_6000_4_OR_NEWER
Copy link
Collaborator

Choose a reason for hiding this comment

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

Great you added automated tests for all the events! This way we protect ourselves from regressions in this area. Similarly I think there is a lot to gain from having them covered in the sample as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done: 0bef5d2


private static HashSet<Type> _testDevices = new HashSet<Type> { typeof(Mouse), typeof(Pen), typeof(Touchscreen) };
// OnMouseOver/Exit and Hover events are not supported for touch
private static HashSet<Type> _testDevicesNoTouch = new HashSet<Type> { typeof(Mouse), typeof(Pen) };
Copy link
Collaborator

Choose a reason for hiding this comment

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

Isn't a HashSet overkill here (dynamic allocation etc) when function with a switch statement with 2 cases would be enough?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I can't see (or am I missing something) that we use lookup in the tests? If not, then I would recommend a plain static readonly array for these. (Less allocation, leaner, simpler) and also likely much faster. Also, when using HashSet, the iteration order is "random"

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done: 0a65443

[Category("MouseEvents")]
public IEnumerator MouseEvents_CanReceiveOnMouseDown([ValueSource(nameof(_testDevices))] Type pointerType)
{
var pointer = (Pointer)InputSystem.s_Manager.AddDevice(pointerType);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: It looks like this

var pointer = (Pointer)InputSystem.s_Manager.AddDevice(pointerType);
InputSystem.AddDevice(pointer);

Is repeated for all the tests. Can't we just embed it into SetUpScene() and have it as an out parameter from that function to reduce redundant code?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done: 0a65443


### Added
- Exposed MediaPlayPause, MediaRewind, MediaForward keys on Keyboard.
- Added OnMouse events for the InputSystem from editor version 6.3, including samples and tests.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would suggest saying "Added support for (MonoBehavior OnMouse-events) [https://docs.unity3d.com/ScriptReference/MonoBehaviour.html] when running the Input System on Unity 6.3 or newer."

Then I would make a separate entry for the sample linking to it. It makes more sense to say Unity 6.3 IMO since editor might indicate it would only be supported in editor but this is for players as well right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

good idea, especially the link. Changed here: a9cff76

//send pointer data to backend for OnMouseEvents
#if UNITY_6000_4_OR_NEWER
if (Pointer.current != null && gameIsPlaying)
NativeInputSystem.SetMouseEventsData(Pointer.current.press.isPressed, Pointer.current.press.wasPressedThisFrame, Pointer.current.position.x.value, Pointer.current.position.y.value);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks for putting this together @ritamerkl, I added a few suggestions and my only main concern is still whether this will behave similar to Input Manager when we only call into the SetMouseEventData(...) function once every frame - this looks incorrect to me. I would have expected that this would not be based on a polling-based evaluation like this here but rather sit inside the event processing loop above or from within the device state updates after event compression. Does this work for e.g. 1 FPS?

Maybe I am overlooking something.... but was Input Manager only calling this once every frame?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think we talked about this before, but to clarify: before this was happening on a PlayerLoopCallback, which was set on module registration. The player loop happens once a frame, the timing of this is "PreUpdate".
Unless I am terribly mistaking something here, I think that is the same logic, except the Input update is set to FixedUpdate or custom (and changed to any other time).

@ekcoh
Copy link
Collaborator

ekcoh commented Aug 27, 2025

I see CI is failing with "Packages\com.unity.inputsystem\InputSystem\InputManager.cs(3710,35): error CS0117: 'NativeInputSystem' does not contain a definition for 'SetMouseEventsData'" but this would be expected until the feature is available in Unity.

@ritamerkl
Copy link
Collaborator Author

ritamerkl commented Aug 28, 2025

I see CI is failing with "Packages\com.unity.inputsystem\InputSystem\InputManager.cs(3710,35): error CS0117: 'NativeInputSystem' does not contain a definition for 'SetMouseEventsData'" but this would be expected until the feature is available in Unity.

It is weird since this is wrapped in defines for unity 600.4 or newer, but still fails on 600.3 🤔

InvokeAfterUpdateCallback(updateType);
//send pointer data to backend for OnMouseEvents
#if UNITY_6000_4_OR_NEWER
if (Pointer.current != null && gameIsPlaying)
Copy link
Collaborator

Choose a reason for hiding this comment

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

This means we will be calling this every frame, regardless of having received an event from a Pointer device or not, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

right

Copy link
Collaborator

Choose a reason for hiding this comment

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

We need to look at how its implemented under the hood, there might even be timeout logic in there which would require it to be once a frame.

Copy link
Collaborator

Choose a reason for hiding this comment

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

there might even be timeout logic in there which would require it to be once a frame.

I'm not sure I understand what you mean with this. Could you specify it a bit?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There is no timeout logic for the MouseEvents.cs if you mean that

//// same goes for events that someone may queue from a change monitor callback
InvokeAfterUpdateCallback(updateType);
//send pointer data to backend for OnMouseEvents
#if UNITY_6000_4_OR_NEWER
Copy link
Collaborator

@ekcoh ekcoh Aug 29, 2025

Choose a reason for hiding this comment

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

I would advise against this. Instead, create an asmdef symbol that defines the feature/capability, e.g. UNITY_INPUTSYSTEM_HAS_MOUSE_SCRIPT_EVENTS_SUPPORTED, then let that symbol be conditionally compiled based on the specific version that contains the native changes, e.g. 6000.0.4.a7, that is more specific and also removes versions from the source code which only cares about a certain API being a certain way instead. And it centralises the version number mess. At least this is what we agreed upon in #2176, and the same technique was used in #2200 to handle the API difference in module API and behaviour .

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Right, very good point. I did that here: 7b13b3e

InvokeAfterUpdateCallback(updateType);
//send pointer data to backend for OnMouseEvents
if (Pointer.current != null && gameIsPlaying)
NativeInputSystem.SetMouseEventsData(Pointer.current.press.isPressed, Pointer.current.press.wasPressedThisFrame, Pointer.current.position.x.value, Pointer.current.position.y.value);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hm, good point. Yeah, not sure how we could mock this in InputTestRuntime then. And from what you mentioned, it doesn't seem to make sense to have it in InputTestRuntime as well, if we really need to call the module.

I don't have a better answer right now so maybe this is fine as is.

It just feels odd to be breaking the class contract that in NativeInputRuntime should be the only file referencing NativeInputSystem. But maybe that's ok in this case?

Anyway, this is not a blocker at all. I'll leave it approved.

@Pauliusd01
Copy link
Collaborator

Pauliusd01 commented Sep 22, 2025

Without your trunk PR I get:

Packages\com.unity.inputsystem\InputSystem\InputManager.cs(3711,35): error CS0117: 'NativeInputSystem' does not contain a definition for 'DoSendMouseEvents'

This needs a version check? Also, should this really be a shipped sample? It seems more like a simple test scene (not to knock down its value, it is just maybe too niche?)

Copy link
Collaborator

@Pauliusd01 Pauliusd01 left a comment

Choose a reason for hiding this comment

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

Updating status

Copy link
Collaborator

@ekcoh ekcoh left a comment

Choose a reason for hiding this comment

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

Changes looks good now. I marked a few comments I was involved in resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants