POC: RawInput mouse via C# CLR

Discuss other programming languages besides AutoHotkey
User avatar
evilC
Posts: 3369
Joined: 27 Feb 2014, 12:30

POC: RawInput mouse via C# CLR

03 Jun 2017, 11:46

Here is the fruit of much endeavor - I have been trying to work out how to receive RawInput messages (Specifically, mouse movement) in C#, from within a DLL.

In order to receive RawInput messages, a thread needs to have a message handler. The simplest way to do this is to use a form, but that then means that when the flow of execution hits Application.Run(), execution halts, so your DLL constructor never returns. Eventually I worked out how to use a primitive version of a form, running in another thread, so that the code can be asynchronous.

So here it is: RawInput in AHK with the heavy lifting done in C# via the SharpDX library

FOR ALL DEMOS IN THIS THREAD:

The SharpDX DLLs from SharpDX.zip in this post are required for the demos in all posts in this thread
You will need CLR.ahk from here
For each demo, extract the SharpDX DLLs from this post, plus the MouseDelta zip for that post into the same folder

AHK code:

Code: [Select all] [Expand] [Download] GeSHi © Codebox Plus



You can also build MouseDelta.dll yourself from the included C# code
The procedure is always the same:
Create a new class library project, add a reference to SharpDX.RawInput via NuGet
Paste in the C# code
Compile

Code: [Select all] [Expand] [Download] GeSHi © Codebox Plus

Attachments
SharpDX.zip
Required for all demos in this thread
(110.77 KiB) Downloaded 29 times
MouseDelta-Basic.zip
(3.66 KiB) Downloaded 33 times
Last edited by evilC on 17 Jun 2017, 15:07, edited 5 times in total.
Helgef
Posts: 1886
Joined: 17 Jul 2016, 01:02
Contact:

Re: POC: RawInput mouse via C# CLR

03 Jun 2017, 12:25

Interesting :think:
I will probably return with questions and or comments :D
Thanks for sharing.
User avatar
evilC
Posts: 3369
Joined: 27 Feb 2014, 12:30

Re: POC: RawInput mouse via C# CLR

04 Jun 2017, 06:41

[Edit: Updated to make AHK script not receive any callbacks when a non-selected mouse moves]
I made a version that allows per-mouse filtering.
At the moment, it just uses the VID/PID string, but at least this is better than the Handle string of the previous incarnation.
I think I remember someone saying they came up with a way to uniquely identify two instances of the same device - we could maybe bolt that on.
I did not bother with trying to display mouse names - I have the code, but for my main mouse it just pulled out "Logitech Receiver", and for another of my mice without a driver, it got nothing, so it seems pretty pointless.
For simplicity of use, I wrote an AHK wrapper that allows you to inject a DDL into your script which you can use to select which mouse to take input from.

Image

Code: [Select all] [Expand] [Download] GeSHi © Codebox Plus



C# code, same deal as before.

Code: [Select all] [Expand] [Download] GeSHi © Codebox Plus

Attachments
MouseDelta-MultiMouse.zip
(4.91 KiB) Downloaded 11 times
Last edited by evilC on 19 Jul 2017, 13:50, edited 4 times in total.
User avatar
evilC
Posts: 3369
Joined: 27 Feb 2014, 12:30

Re: POC: RawInput mouse via C# CLR

04 Jun 2017, 10:11

Another version.
This one allows you to subscribe to mouse "Stop" events (Windows doesn't really have one).
When the stop event callback fires, you are passed the sum of the last 10 moves, plus the last move (x and y for both, so 4 params)

This is all the info that my RollMouse app uses, so I wrote a version of it using this lib + MicroTimer.

Move the mouse and pick it up while in motion, and it will keep moving in the direction and at roughly the same speed until you put the mouse back on the mat. Also works with trackpads.

AHK code:

Code: [Select all] [Expand] [Download] GeSHi © Codebox Plus



C# (You will also need the MicroTimer DLL, included in attached ZIP)

Code: [Select all] [Expand] [Download] GeSHi © Codebox Plus

Attachments
MouseDelta-Stop.zip
(9.8 KiB) Downloaded 23 times
Last edited by evilC on 06 Jun 2017, 14:30, edited 1 time in total.
User avatar
RUNIE
Posts: 205
Joined: 03 May 2014, 14:50
GitHub: Run1e

Re: POC: RawInput mouse via C# CLR

05 Jun 2017, 01:57

What's the advantage of this over a normal mouse hook?
Helgef
Posts: 1886
Joined: 17 Jul 2016, 01:02
Contact:

Re: POC: RawInput mouse via C# CLR

05 Jun 2017, 02:46

@ evilC
I couldn't get this to work. :cry:

Code: [Select all] [Download] GeSHi © Codebox Plus

#Persistent
SetWorkingDir, % A_ScriptDir
; I have CLR.ahk in my user lib.
asm := CLR_LoadLibrary("MouseDelta.dll")
MsgBox, % IsObject(asm) ; 1
md := asm.CreateInstance("MouseDelta") ; Chrash

I tried with MouseDelta.dll from your first and last post. Tried on Ahk 1.1.25.02 64/32 Unicode. I'm on Windows 7.
User avatar
evilC
Posts: 3369
Joined: 27 Feb 2014, 12:30

Re: POC: RawInput mouse via C# CLR

05 Jun 2017, 04:23

Run1e wrote:What's the advantage of this over a normal mouse hook?

Mouse Hooks (SetWindowsHookEx API) CAN'T distinguish between different mice but CAN block input.

RawInput (What this uses) CAN distinguish between different mice but CAN'T block input.

However, with Nefarius' HidGuardian on the horizon, we can potentially stop certain apps from being able to see certain devices, so we potentially do not need hooks to be able to block input (do a hard remap).

The main point of this code is that because mouse input happens so stupidly fast, I am trying to move as much as possible out of interpreted AHK code and into compiled C# code, allowing people to write mouse scripts in AHK that have as minimal of an impact on CPU as possible.
Last edited by evilC on 05 Jun 2017, 04:55, edited 1 time in total.
User avatar
evilC
Posts: 3369
Joined: 27 Feb 2014, 12:30

Re: POC: RawInput mouse via C# CLR

05 Jun 2017, 04:49

Helgef wrote:@ evilC
I couldn't get this to work. :cry:


It seems you also need the SharpDX DLLs.
I attached them to the OP.
Helgef
Posts: 1886
Joined: 17 Jul 2016, 01:02
Contact:

Re: POC: RawInput mouse via C# CLR

06 Jun 2017, 04:09

Unfortunately, the script silently closes on md := asm.CreateInstance("MouseDelta"). I added the sharpDX... files to the script directory.
User avatar
evilC
Posts: 3369
Joined: 27 Feb 2014, 12:30

Re: POC: RawInput mouse via C# CLR

06 Jun 2017, 04:29

Hmm, just to be sure, here is a zip with everything needed.
Attachments
Test.zip
(114.4 KiB) Downloaded 29 times
Helgef
Posts: 1886
Joined: 17 Jul 2016, 01:02
Contact:

Re: POC: RawInput mouse via C# CLR

06 Jun 2017, 05:33

That works :) Also, the scripts which failed before works with the MouseDelta.dll from Test.zip.
User avatar
evilC
Posts: 3369
Joined: 27 Feb 2014, 12:30

Re: POC: RawInput mouse via C# CLR

06 Jun 2017, 05:41

MouseDelta.dll is different for the various posts. Maybe I put the wrong DLL in some of the zips?
Helgef
Posts: 1886
Joined: 17 Jul 2016, 01:02
Contact:

Re: POC: RawInput mouse via C# CLR

06 Jun 2017, 06:42

I tried (and failed) with the dlls from this post and the first post.


My brief testing tells me this is an improvement w.r.t to accuracy and cpu usage, compared to your ahk MouseDelta. :thumbup:


Although this is POC, for your future reference, be aware that each rawinput can contain any combination of events, i.e., both movements, clicks and wheel scrolls, hence

Code: [Select all] [Download] (Untitled.cs)GeSHi © Codebox Plus

// Fire appropriate Callback
if (args.Mode == MouseMode.MoveRelative && relativeMoveCallback != null && (Math.Abs(args.X) + Math.Abs(args.Y) > 0))
{
relativeMoveCallback(args.X, args.Y, seenMice[args.Device]);
}
else if (args.WheelDelta != 0 && wheelCallback != null)
{
wheelCallback(args.WheelDelta / 120, seenMice[args.Device]);
}

might need to be something like

Code: [Select all] [Download] (Untitled.cs)GeSHi © Codebox Plus

// Fire appropriate Callback
if (args.Mode == MouseMode.MoveRelative && relativeMoveCallback != null && (Math.Abs(args.X) + Math.Abs(args.Y) > 0))
{
relativeMoveCallback(args.X, args.Y, seenMice[args.Device]);
}
if (args.WheelDelta != 0 && wheelCallback != null) // removed else
{
wheelCallback(args.WheelDelta / 120, seenMice[args.Device]);
}

or you will miss the wheel event if it occurs at the same time as a movement.

Cheers.
User avatar
evilC
Posts: 3369
Joined: 27 Feb 2014, 12:30

Re: POC: RawInput mouse via C# CLR

06 Jun 2017, 06:57

Yeah, I was wondering that...

When I get home tonight, I will try to make sure the zips in each post contain all the relevant files and test that they all work
User avatar
evilC
Posts: 3369
Joined: 27 Feb 2014, 12:30

Re: POC: RawInput mouse via C# CLR

06 Jun 2017, 14:32

OK, it seems like SharpDX got updated on 30th may, some of the code seems to have been targetting the old SharpDX version (4.0.0.0), so that explains why some were not working.
I updated each MouseDelta.dll to target the newest SharpDX version (4.0.1.0), and all seems fine now.
User avatar
evilC
Posts: 3369
Joined: 27 Feb 2014, 12:30

Re: POC: RawInput mouse via C# CLR

12 Jun 2017, 09:12

This demo uses extends the "MultiMouse" example to demo selectively blocking input from one mouse, while letting input through from another mouse.
Yep, that's right - we thought it could not be done, but here it is:

Code: [Select all] [Expand] [Download] GeSHi © Codebox Plus



How it works:
In reality, ALL input is blocked, but MoveEvent still fires for all input and is passed the VID/PID of the mouse that moved.
In MoveEvent, if the input came from the selected mouse, it resends synthetic input using the mouse_event API call
The hook checks for the presence of the LLMHF_INJECTED flag, which is set to 1 if the input came from a mouse_event API call, and lets it through.
Last edited by evilC on 17 Jun 2017, 15:19, edited 1 time in total.
Helgef
Posts: 1886
Joined: 17 Jul 2016, 01:02
Contact:

Re: POC: RawInput mouse via C# CLR

12 Jun 2017, 15:37

I get an error.

Code: [Select all] [Expand] [Download] GeSHi © Codebox Plus


Same problem occurs if I uncomment the wheel subscriptions, but then for the SubscribeRelativeMove.

I do something similar with the cursor plugin, but I do not install my own hook, instead I use (ahk's hook) blockinput, mousemove and MouseButtons::return, then I do stuff (move and click) depending on which mouse is moved, detected via rawinput (your mousedelta).

Cheers.
Helgef
Posts: 1886
Joined: 17 Jul 2016, 01:02
Contact:

Re: POC: RawInput mouse via C# CLR

13 Jun 2017, 02:56

I figured out what I was doing wrong, I didn't use the MouseDelta-Multi mouse version :oops:. Now, it works nice and smooth with the alt version :thumbup:.
However, the hook didn't initialise, so I changed,

Code: [Select all] [Download] GeSHi © Codebox Plus

DllCall("SetWindowsHookEx", "int", idHook, "Uint", pfn, "Uint", DllCall("GetModuleHandle", "Uint", 0), "Uint", 0)

to

Code: [Select all] [Download] GeSHi © Codebox Plus

DllCall("SetWindowsHookEx", "int", idHook, "Uint", pfn, "Uint", 0, "Uint", 0)

SetWindowsHookEx wrote:The hMod parameter must be set to NULL if the dwThreadId parameter specifies a thread created by the current process and if the hook procedure is within the code associated with the current process.
source- My bold

And finally, when I close the gui, i.e., quit the script, it crashes.
User avatar
evilC
Posts: 3369
Joined: 27 Feb 2014, 12:30

Re: POC: RawInput mouse via C# CLR

18 Jun 2017, 08:24

Something still seems to be going on with the files in this thread - I am about to remote into a user's PC who is having problems to see if I can get to the bottom of it.

Return to “Other Programming Languages”

Who is online

Users browsing this forum: No registered users and 1 guest