POC: RawInput mouse via C# CLR

Post a reply


In an effort to prevent automatic submissions, we require that you complete the following challenge.
Smilies
:D :) ;) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :!: :?: :idea: :| :mrgreen: :geek: :ugeek: :arrow: :angel: :clap: :crazy: :eh: :lolno: :problem: :shh: :shifty: :sick: :silent: :think: :thumbup: :thumbdown: :salute: :wave: :wtf: :yawn: :facepalm: :bravo: :dance: :beard: :morebeard: :xmas: :HeHe: :trollface: :cookie: :rainbow: :monkeysee: :monkeysay: :happybday: :headwall: :offtopic: :superhappy: :terms: :beer:
View more smilies

BBCode is ON
[img] is OFF
[flash] is OFF
[url] is ON
Smilies are ON

Topic review
   

Expand view Topic review: POC: RawInput mouse via C# CLR

Re: POC: RawInput mouse via C# CLR

Post by evilC » 21 Mar 2019, 09:03

I don't know much about the Surface Dial, but the short answer is No - this will not *natively* support the dial.
What I mean by this is that the dial will likely be a HID device natively, sending dial-specific signals to the PC.
In order to support it natively, you could possibly use AHKHID.

However, it seems that in some modes, the dial sends normal mouse or keyboard signals, which this library *could* read, however that is not likely to be of much use, because...
If the dial sends, for example, wheel up or wheel down, RawInput *could* see it, but could *not* remap it (Make it do something else).

In that instance, you could use AHI (See link in signature) to subscribe to the wheel signals coming from the dial (And only the dial, it would not respond to your normal mouse wheel) and allow you to remap them

Re: POC: RawInput mouse via C# CLR

Post by Trej » 21 Mar 2019, 08:48

Hi @evilC,

Is there anyway to modify this to receive messages from the surface dial?

I have no idea where to start in implementing this in AHK.

Re: POC: RawInput mouse via C# CLR

Post by Avc001 » 30 Jul 2018, 23:34

Bro please help me... Can you do this for me???

Mouse move left = left arrow key , when stop moving = arrow key left up
Mouse move right = right arrow key , when stop moving = arrow key right up

put a deadzone on the x-axis as well is possible

and make sure the the mouse is infinite like its doesnt hit the edge and stops. Its lke in a real fps game you know. Please help

email me asap when you got it:
[email protected]


I want to use delta rawinput api of mouse on this code here:::
----------------------------------------------------------
CoordMode, Mouse, Screen

deadzone := 6
deadzoneX := Floor(deadzone*1.2)

cnt:=!!cnt
settimer, watchMouse, 10
return

watchMouse:
cnt++, pCnt:=cnt-1
mouseGetPos, mx%cnt%
send % ( mx%cnt%>mx%pCnt%+deadzoneX ? "{right}" : mx%cnt%<mx%pCnt%-deadzoneX ? "{left}" : "" )
return

esc::exitApp ; <-- press esc to exit
----------------------------------------------------------------------

Re: POC: RawInput mouse via C# CLR

Post by Galvatron » 20 Jul 2017, 12:22

Okay, made it to work. These values seem to be fine and more precise than with mousedelta:
MoveEvent(x, y, mouseId){
x := round(x / 2)
y := round(y / 2)
Global mdw
if (mdw.SelectedMouse == 0 || mdw.SelectedMouse == mouseId){
DllCall("mouse_event",uint,1,int, x ,int, y,uint,0,int,0)
}
}
But using "x / 3" or lower doesn't seem to work properly.

Re: POC: RawInput mouse via C# CLR

Post by evilC » 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.

Re: POC: RawInput mouse via C# CLR

Post by Helgef » 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

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

Code: Select all

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.

Re: POC: RawInput mouse via C# CLR

Post by Helgef » 12 Jun 2017, 15:37

I get an error.

Code: Select all

Error:  0x8002000E - Invalid number of parameters.

Specifically: SubscribeWheel

	Line#
	078: }
	080: {
	081: GuiControlGet,mouseId,,this.hDDL
	082: this.SelectedMouse := mouseId == "Any" ? 0 : mouseId  
	083: if (this.MoveCallback != 0)  
	084: this.md.SubscribeRelativeMove(this._MoveEvent.Bind(this), this.SelectedMouse)  
	085: if (this.WheelCallback != 0)  
--->	086: this.md.SubscribeWheel(this._WheelEvent.Bind(this), this.SelectedMouse)  
	087: }
	089: {
	090: GuiControl,,this.hDDL,mouseId
	091: }
	093: {
	094: if (!this.SeenMice.HasKey(mouseId))  
	094: {
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.

Re: POC: RawInput mouse via C# CLR

Post by evilC » 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

; ================= USER SCRIPT ================
#SingleInstance force
#NoEnv
#include <CLR>
OnExit, UnhookAndClose

GoSub, Hook

Gui, Add, Text, , Select Mouse:
mdw := new MouseDeltaWrapper("x+5 yp-3 w200")
mdw.SubscribeMove(Func("MoveEvent"))
mdw.SubscribeWheel(Func("WheelEvent"))
Gui, Show
return

^Esc::
UnhookAndClose:
GuiClose:
	GoSub, UnHook
	ExitApp

Hook:
	hHookMouse := SetWindowsHookEx(WH_MOUSE_LL	:= 14, RegisterCallback("MouseMove", "Fast"))
	return

UnHook:
	UnhookWindowsHookEx(hHookMouse)
	return

MoveEvent(x, y, mouseId){
	Global mdw
	if (mdw.SelectedMouse == 0 || mdw.SelectedMouse == mouseId){
		DllCall("mouse_event",uint,1,int, x ,int, y,uint,0,int,0)
	}
}

WheelEvent(value, mouseId){
	ToolTip % "Wheel: " value ", ID: " mouseId
}

; ================= WRAPPER LIBRARY ================
class MouseDeltaWrapper {
	SeenMice := {}
	SelectedMouse := 0
	MoveCallback := 0

	__New(guiOptions := "", dllPath := "MouseDelta.dll"){
		this.Callback := callback
		
		Gui, +HwndHwnd
		this.GuiHwnd := Hwnd
		
		Gui, Add, DDL, % "hwndhDDL " guiOptions, Any||
		this.hDDL := hDDL
		
		fn := this._UserSelectedMouse.Bind(this)
		GuiControl, +g, % this.hDDL, % fn
		
		asm := CLR_LoadLibrary(dllPath)
		md := asm.CreateInstance("MouseDelta")

		md.SubscribeRelativeMove(this._MoveEvent.Bind(this))
		md.SubscribeWheel(this._WheelEvent.Bind(this))
		this.md := md
		
		this._UserSelectedMouse()
	}
	
	SubscribeMove(callback){
		this.MoveCallback := callback
	}
	
	SubscribeWheel(callback){
		this.WheelCallback := callback
	}
	
	_UserSelectedMouse(){
		GuiControlGet, mouseId, , % this.hDDL
		this.SelectedMouse := mouseId == "Any" ? 0 : mouseId
		if (this.MoveCallback != 0)
			this.md.SubscribeRelativeMove(this._MoveEvent.Bind(this), this.SelectedMouse)
		if (this.WheelCallback != 0)
			this.md.SubscribeWheel(this._WheelEvent.Bind(this), this.SelectedMouse)
	}
	
	_AddMouseToDDL(mouseId){
		GuiControl, , % this.hDDL, % mouseId
	}
	
	_UpdateMice(mouseId){
		if (!this.SeenMice.HasKey(mouseId)){
			this.SeenMice[mouseId] := 1
			this._AddMouseToDDL(mouseId)
		}
	}
	
	_MoveEvent(x, y, mouseId){
		this._UpdateMice(mouseId)
		if (this.MoveCallback != 0 && (this.SelectedMouse == 0 || this.SelectedMouse == mouseId)){
			this.MoveCallback.Call(x, y, mouseId)
		}
	}
	
	_WheelEvent(value, mouseId){
		this._UpdateMice(mouseId)
		if (this.WheelCallback != 0 && (this.SelectedMouse == 0 || this.SelectedMouse == mouseId)){
			this.WheelCallback.Call(value, mouseId)
		}
	}
}

MouseMove(nCode, wParam, lParam)
{
	Critical
	SetFormat, Integer, D
	If !nCode && (wParam = 0x200){
		; Mouse movement - process
		if (NumGet(lParam+0, 12, "int")){
			; if the LLMHF_INJECTED flag is set, this is "injected" input (Came from mouse_event)
			; Let this input through
			Return CallNextHookEx(nCode, wParam, lParam)
		} else {
			; Block the input
			Return 1
		}
	} else {
		; Other mouse message - let through
		Return CallNextHookEx(nCode, wParam, lParam)
	}
}

SetWindowsHookEx(idHook, pfn)
{
	;Return DllCall("SetWindowsHookEx", "int", idHook, "Uint", pfn, "Uint", DllCall("GetModuleHandle", "Uint", 0), "Uint", 0)
	return DllCall("SetWindowsHookEx", "int", idHook, "Uint", pfn, "Uint", 0, "Uint", 0)
}

UnhookWindowsHookEx(hHook)
{
	Return DllCall("UnhookWindowsHookEx", "Uint", hHook)
}

CallNextHookEx(nCode, wParam, lParam, hHook = 0)
{
	Return DllCall("CallNextHookEx", "Uint", hHook, "int", nCode, "Uint", wParam, "Uint", lParam)
}
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.

Re: POC: RawInput mouse via C# CLR

Post by evilC » 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.

Re: POC: RawInput mouse via C# CLR

Post by evilC » 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

Re: POC: RawInput mouse via C# CLR

Post by Helgef » 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

// 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

// 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.

Re: POC: RawInput mouse via C# CLR

Post by evilC » 06 Jun 2017, 05:41

MouseDelta.dll is different for the various posts. Maybe I put the wrong DLL in some of the zips?

Re: POC: RawInput mouse via C# CLR

Post by Helgef » 06 Jun 2017, 05:33

That works :) Also, the scripts which failed before works with the MouseDelta.dll from Test.zip.

Re: POC: RawInput mouse via C# CLR

Post by evilC » 06 Jun 2017, 04:29

Hmm, just to be sure, here is a zip with everything needed.
Attachments
Test.zip
(114.4 KiB) Downloaded 616 times

Re: POC: RawInput mouse via C# CLR

Post by Helgef » 06 Jun 2017, 04:09

Unfortunately, the script silently closes on md := asm.CreateInstance("MouseDelta"). I added the sharpDX... files to the script directory.

Re: POC: RawInput mouse via C# CLR

Post by evilC » 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.

Re: POC: RawInput mouse via C# CLR

Post by evilC » 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.

Re: POC: RawInput mouse via C# CLR

Post by Helgef » 05 Jun 2017, 02:46

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

Code: Select all

#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.

Re: POC: RawInput mouse via C# CLR

Post by Helgef » 05 Jun 2017, 02:18

See MouseDelta and / or Raw Input.

Re: POC: RawInput mouse via C# CLR

Post by runie » 05 Jun 2017, 01:57

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

Top