Skip to content
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

No way to disable mouse move event capture. #27

Open
d3xMachina opened this issue Jan 16, 2024 · 4 comments
Open

No way to disable mouse move event capture. #27

d3xMachina opened this issue Jan 16, 2024 · 4 comments

Comments

@d3xMachina
Copy link

Hello, I only need to capture mouse button inputs. All events are captured and dispatched when using the following :
WindowsInput.Capture.Global.MouseAsync(true);

The issue I have with mouse move events being captured is that it triggers a ton of events and a lot of memory allocations.

Example after a few seconds of moving the mouse :
image
The 2 spikes are memory allocations due to moving the mouse, after I stop moving the mouse.

Stack trace of relevant memory allocations (over a few seconds) :
image

I believe it would be nice to have a way to disable the capture of mouse move events as it adds a ton of overhead.

@TonyValenti
Copy link
Collaborator

I'm pretty sure you have to capture all events - I don't think the windows api lets you selectively listen.

Allocations are likely due to the class vs struct nature of things which can't really be changed.

@d3xMachina
Copy link
Author

d3xMachina commented Jan 17, 2024

Instead of preventing the capture, what could be done is to just ignore the event and not do any processing if it's a mouse move event.

I have made some tests. The two parts that cause the memory allocations are :

  • Mostly : In MouseEventSourceState.cs : public EventSourceEventArgs<MouseEvent> GetEventArgs(EventSourceEventArgs<MouseInput> e) :
var Data = new MouseEvent(Wait, Move, Scroll, Down, Up, Click, ClickHold, DoubleClick, DragStarted, DragFinished);
var ret = new EventSourceEventArgs<MouseEvent>(e.Timestamp, Data, e.RawData);
  • Then In CallBackData.cs : EventSourceEventArgs<MouseInput> ToMouseEventArgs(GlobalMouseEventSourceCallbackData data) :
    var ret = EventSourceEventArgs.Create(data.Data.Timestamp, new MouseInput(button, data.Data.Point, mouseDelta, Status), data);

So instead of doing :
In GlobalMouseEventSource.cs :

protected override bool Callback(CallbackData data) {
    var e = data.ToGlobalMouseEventArgs();
    var Events = State.GetEventArgs(e);
    var ret = InvokeMany(Events.Data, e, Events.Timestamp);

    return ret.Next_Hook_Enabled;
}

We could do something like (we check the type of event from the callback data) :

protected override bool Callback(CallbackData data) {
    var Data = data.ToGlobalMouseEventSourceCallbackData();
    bool ignore = CheckIgnoredEvent(Data);
    if (ignore) {
        return false; // not 100% sure for the return value
    }

    var e = ToGlobalMouseEventArgs(Data);
    var Events = State.GetEventArgs(e);
    var ret = InvokeMany(Events.Data, e, Events.Timestamp);

    return ret.Next_Hook_Enabled;
}

The logic to interpret the type of event (for the CheckIgnoredEvent function) is in MouseEventSourceState.cs : public EventSourceEventArgs<MouseEvent> GetEventArgs(EventSourceEventArgs<MouseInput> e) with var Move = (LastInput?.Data.X != e.Data.X || LastInput?.Data.Y != e.Data.Y) for the mouse move event for example.

@TonyValenti
Copy link
Collaborator

This is a great analysis!

Here my thoughts:
I have seldom seen applications, whose performance was majorly impacted by allocations. Yes, removing allocations makes an application faster, however, in my experience, the speed cannot be perceived by a human. (It is much more relevant for benchmarks.)

It has been a long time since I wrote a lot of this code, and I would honestly be concerned about making too many changes to it. As you look at things, you will notice that it has the ability to capture events, and then replay them! That was no easy feat!

Anyways, I noticed that the method that you wanted to optimize was virtual so you could do your own custom filtering directly in it. Does that work? I would be much more open to enabling you to override a method, then implementing an optimization specific to avoid allocations.

@d3xMachina
Copy link
Author

Thanks for the fast replies. I appreciate your work!

It would be indeed great to have the ability to override the callback method and possibly being able to call the original callback method from the overriding one.

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

No branches or pull requests

2 participants