Creating a wrapper for interception.dll (fixed and working!) Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
ToonyTom
Posts: 9
Joined: 04 Mar 2015, 04:41

Creating a wrapper for interception.dll (fixed and working!)

31 Dec 2016, 08:22

Interception is a driver / library for capturing key strokes, mouse button presses, and mouse movement (maybe joysticks as well?). It can then either block that input, let it through, or turn it into something else. The most important feature is all of this can be based on a device number or hardware id! Unlike AHKHID, this actually blocks the input of a device and can be device specific.

I'm a noob to NumGet / NumPut and DllCall, but somehow I managed to get most of this working :lol:
Problem is, I can't figure out how to properly get information from the "stroke" structure nor how to properly put data into it. But I did manage to easily change the key code that intercept sends.

To get this working you need to download interception.zip from here: https://github.com/oblitum/Interception/releases/
Extract it to a folder
go to the \commad line installer\ directory
"Run install-interception without any arguments inside an console executed as administrator and it will give instructions for installation."
This installs the driver.
Next, copy "interception.dll" from either \library\x32\ or \library\x64\ into the same directory as the script below
Also make sure that you use a unicode build of AHK, ANSI just doesn't work.

This demo script will transform your "Control" key into "X".
Pressing a key or using the mouse wheel will show a tooltip with info about it.
Pressing Escape will exit the while loop and the script.

For fun, try using:

Code: Select all

get_hardware_id(context,device)
to get the hardware id of a second keyboard or keypad.
Then use it in an if statement to send a different key or do something else.

Have a peek at set_filter()'s static vars for a list of strings you can use.
For the keyboard, use the ones beginning with "FILTER_", not "KEY_"
For the mouse, everything seems to work, but I have no clue how to change movement.

Code: Select all

;#include <_Struct>
#SingleInstance force
load()
context:=create_context()
set_filter(context, "keyboard","FILTER_KEY_ALL|FILTER_KEY_E0|FILTER_KEY_E1")
set_filter(context, "mouse", "MOUSE_WHEEL")

while ( recieve(context,device:=wait(context),stroke,1) >0 )
{
	if is_keyboard(device)
	{
    		code:=hex(NumGet(stroke,0,"Ushort"))
		if (code=0x01) ;escape EXIT
			break

		s:=get_stroke(device,stroke)
		if (s.name="LCONTROL")
		{
			key:=key2dec("X")
			NumPut(key,stroke,0,"Ushort")
		}
  	send(context,device,&stroke,1)
	}
	else if is_mouse(device)
	{
		;tooltip mouse!
   		 s:=get_stroke(device,stroke)
   		 send(context,device,&stroke,1)
	}
}
return


get_stroke(device,stroke)
{
	if is_keyboard(device)
	{
		/*
		interception.h:
		typedef struct
		{
		    unsigned short code;
		    unsigned short state;
		    unsigned int information;
		} InterceptionKeyStroke;

		msdn:
		typedef struct _KEYBOARD_INPUT_DATA {
		  USHORT UnitId;
		  USHORT MakeCode;
		  USHORT Flags;
		  USHORT Reserved;
		  ULONG  ExtraInformation;
		} KEYBOARD_INPUT_DATA, *PKEYBOARD_INPUT_DATA;
		*/
		o:={}
		o.code := hex(NumGet(stroke,0,"Ushort"))
		o.name:=GetKeyName("sc" o.code)
		o.state:= NumGet(stroke,2,"Short")
		o.info:= NumGet(stroke,4,"Uint")
		ToolTip % "(Press Escape to Exit)`n`nkeyboard:`nname=" o.name "`ncode=" o.code "`nstate=" o.state "`ninfo=" o.info
	}
	else
	{
		/*
		interception.h:
		typedef struct
		{
		    unsigned short state;
		    unsigned short flags;
		    short rolling;
		    int x;
		    int y;
		    unsigned int information;
		} InterceptionMouseStroke;

		msdn:
		typedef struct _MOUSE_INPUT_DATA {
			USHORT  UnitId;
			USHORT  Flags;
			_ANONYMOUS_UNION union {
				ULONG Buttons;
				_ANONYMOUS_STRUCT struct  {
					USHORT  ButtonFlags;
					USHORT  ButtonData;
				} DUMMYSTRUCTNAME;
			} DUMMYUNIONNAME;
			ULONG  RawButtons;
			LONG  LastX;
			LONG  LastY;
			ULONG  ExtraInformation;
		} MOUSE_INPUT_DATA, *PMOUSE_INPUT_DATA;
		*/
		o:={}
		size:=2
		o.state:=		NumGet(stroke,0,"ushort")
		o.flags:=		NumGet(stroke,2,"ushort")
		o.rolling:=	NumGet(stroke,4,"short")
		o.x:=				NumGet(stroke,6,"int")
		o.y:=				NumGet(stroke,10,"int")
		o.info:=    NumGet(stroke,14,"uint")
    ToolTip % "(Press Escape to Exit)`n`nmouse:`nstate=" o.state "`nflag=" o.flags "`nrolling=" o.rolling "`nx=" o.x "`ny=" o.y "`ninfo=" o.info
	}
	return o
}


send(context,device,stroke,nstroke){
global dll
	;interception_send(InterceptionContext context, InterceptionDevice device, const InterceptionStroke *stroke, unsigned int nstroke);
	res:=DllCall(dll . "\interception_send","Ptr",context,"int",device,"ptr",stroke,"int",nstroke,"Cdecl Int")
return res
}


recieve(context,device,ByRef stroke,ByRef nstroke){
global dll
;interception_receive(InterceptionContext context, InterceptionDevice device, InterceptionStroke *stroke, unsigned int nstroke);
VarSetCapacity(stroke,500)
res:=DllCall(dll . "\interception_receive","Ptr",context,"int",device,"str",stroke,"int*",nstroke,"Cdecl Int")
return res
}

get_hardware_id(context,device){
global dll
  VarSetCapacity(buffer,500)

	if (a_ptrsize > 4)
		DllCall(dll . "\interception_get_hardware_id","Ptr",context,"int",device,"str",buffer,"Uint",500,"Cdecl Int")
	else if (a_ptrsize < 4)
  	DllCall(dll . "\interception_get_hardware_id","Ptr",context,"int",device,"ptr",&buffer,"Uint",500,"Cdecl Int")

	return a_ptrsize > 4 ? buffer : StrGet(&buffer, "UTF-16")
}

wait(context){
	global
	return DllCall(dll . "\interception_wait","Ptr",context,"Cdecl Int")
}


set_filter(context,filter,keys){
global dll
Static keyboard:="interception_is_keyboard"
,mouse:="interception_is_mouse"
,KEY_DOWN           		= 0x00
,KEY_UP             		= 0x01
,KEY_NONE             	= 0x0000
,KEY_ALL              	= 0xFFFF
,KEY_E0              		= 0x02 ;Delete Key
,KEY_E1              		= 0x04
,KEY_TERMSRV_SET_LED 		= 0x08
,KEY_TERMSRV_SHADOW  		= 0x10
,KEY_TERMSRV_VKPACKET 	= 0x20
,FILTER_KEY_NONE             = 0x0000
,FILTER_KEY_ALL              = 0xFFFF
,FILTER_KEY_DOWN             := KEY_UP
,FILTER_KEY_UP               := KEY_UP << 1
,FILTER_KEY_E0               := KEY_E0 << 1
,FILTER_KEY_E1               := KEY_E1 << 1
,FILTER_KEY_TERMSRV_SET_LED  := KEY_TERMSRV_SET_LED << 1
,FILTER_KEY_TERMSRV_SHADOW   := KEY_TERMSRV_SHADOW << 1
,FILTER_KEY_TERMSRV_VKPACKET := KEY_TERMSRV_VKPACKET << 1
,MOUSE_NONE              = 0x0000
,MOUSE_ALL               = 0xFFFF
,MOUSE_LEFT_BUTTON_DOWN  = 0x001
,MOUSE_LEFT_BUTTON_UP    = 0x002
,MOUSE_RIGHT_BUTTON_DOWN = 0x004
,MOUSE_RIGHT_BUTTON_UP   = 0x008
,MOUSE_MIDDLE_BUTTON_DOWN= 0x010
,MOUSE_MIDDLE_BUTTON_UP  = 0x020
,MOUSE_BUTTON_1_DOWN     := MOUSE_LEFT_BUTTON_DOWN
,MOUSE_BUTTON_1_UP       := MOUSE_LEFT_BUTTON_UP
,MOUSE_BUTTON_2_DOWN     := MOUSE_RIGHT_BUTTON_DOWN
,MOUSE_BUTTON_2_UP       := MOUSE_RIGHT_BUTTON_UP
,MOUSE_BUTTON_3_DOWN     := MOUSE_MIDDLE_BUTTON_DOWN
,MOUSE_BUTTON_3_UP       := MOUSE_MIDDLE_BUTTON_UP
,MOUSE_BUTTON_4_DOWN     = 0x040
,MOUSE_BUTTON_4_UP       = 0x080
,MOUSE_BUTTON_5_DOWN     = 0x100
,MOUSE_BUTTON_5_UP       = 0x200
,MOUSE_WHEEL             = 0x400
,MOUSE_HWHEEL            = 0x800
,MOUSE_MOVE              = 0x1000
,MOUSE_MOVE_RELATIVE      = 0x000
,MOUSE_MOVE_ABSOLUTE      = 0x001
,MOUSE_VIRTUAL_DESKTOP    = 0x002
,MOUSE_ATTRIBUTES_CHANGED = 0x004
,MOUSE_MOVE_NOCOALESCE    = 0x008
,MOUSE_TERMSRV_SRC_SHADOW = 0x100

	if Instr(keys,"|")
	{
		loop,parse,keys,|
		{
			key:=%a_loopfield%
			if a_index=1
				keys2:=key
			else
				keys2:=keys2|key
		}
		keys:=keys2
	}
	else
		keys:=%keys%

	f:=get_pointer(%filter%)
	DllCall(dll . "\interception_set_filter","ptr",context,"ptr",f, "int",keys,"Cdecl Int")
}

is_mouse(device){
	global
  return DllCall(dll . "\interception_is_mouse","int",device)
}

is_keyboard(device){
	global
  return DllCall(dll . "\interception_is_keyboard","int",device)
}

get_pointer(func){
	global
	return DllCall("GetProcAddress", ptr, dllh, "astr", func, ptr)
}
create_context(){
	global
	return DllCall(dll . "\interception_create_context")
}

load(){
	global
	dll:="interception.dll"
	dllh:=DllCall("LoadLibrary", "Str", dll, "Ptr")
}

hex(n){
SetFormat, IntegerFast, hex
n+= 0  ; Sets Var (which previously contained 11) to be 0xb.
n.= ""  ; Necessary due to the "fast" mode.
SetFormat, IntegerFast, d
return n
}

dec(n){
SetFormat, Integer, D
Dec := (n) + 0
return Dec
}

key2dec(name){
hex:=GetKeySC(name)
return dec(hex)
}

This is basically just a bunch of function calls running inside of a while loop. I made a function get_stroke() to make pulling data from "stroke" a little less clunky. Inside of it I commented the structure definitions for the keyboard and mouse versions of stroke. Also pasted in the structure def from msdn that interception actually uses (i peeked at the source code). But I still feel very much in the dark with this and would appreciate any help in getting data into and out of the stroke structure. I also hope this code also helps anyone else who's been struggling to get this to work with practically no example code out there.
Last edited by ToonyTom on 09 Jan 2017, 00:29, edited 1 time in total.
ToonyTom
Posts: 9
Joined: 04 Mar 2015, 04:41

Re: Creating a wrapper for interception.dll (could use help with NumGet etc)

02 Jan 2017, 12:43

Got a little further this time. Now I can easily send keys with a homemade function: send_keys( ).
At first I couldn't figure out why it caused my mouse to go to to right edge whenever I used it. Then I realized that I was actually using the 'device number" for the mouse! :roll:
So, to use send_keys ( ) you have to give the device number of a keyboard as the first param, then any number of key names as params. Like, send_keys("2", "a","b","c").

It's also using the <_struct> class now to be able to build the key structure "kstroke" for send_keys( ),
but I haven't yet figured out how to have recieve( ) put data into a structure without it crashing.
Also, I sort of figured out how to get NumGet to spit out the right numbers, but the offset for "x"
doesn't make sense. It's right after a 'short' type variable in memory, and everything I've read says
that a short is 2 bytes and an Int is 4 bytes. But "x" is okay with being offset by 4 instead of 2. Doesn't really make sense.

So, in summary,

the bad news:
*still using numget to pull data out of the structure instead of _struct
*unable to use _struct with recieve( ) so far.
*if used to send mouse wheel "strokes" it's much slower than my free scrolling logitech mouse, so it's very inefficient as a pass-through for the mouse wheel. Don't know how to speed it up.
*doesn't seem to recognize CTRL+ALT pressed at the same time, but will if you press and hold ALT first then CTRL. Which is terrible for art programs ( most use CTRL+ALT) to change bursh size).
*doesn't let the custom key combo on my mouse go through. It's set to CTRL+ALT+SHIFT+F12. It will only work if using a key filter of "KEY_DOWN", but not "KEY_ALL" or any others...really strange.

the good news:
*blocks or lets through devices based on their number or hardware_id
*It seems quick enough at sending key up or key down messages
*can get "most" of the data out of the stroke structure using numget
*easy to setup

Still would appreciate some help on this if anyone has any insight on some of those "bad news" points.
There's a bunch of commented code I was trying inside recieve( ) that didn't quite work out.

requires:
_struct
sizeof
and interception as described in the first post above.

interception_demo_v2.ahk

Code: Select all

#Include <_Struct>
#SingleInstance force
#MaxHotkeysPerInterval 255
#MaxThreads 255
SetKeyDelay -1
SetBatchLines -1
critical

load()
context:=create_context()
set_filter(context, "keyboard","KEY_ALL")
;set_filter(context, "keyboard","FILTER_KEY_ALL")
;set_filter(context, "keyboard","KEY_DOWN|KEY_UP")
;set_filter(context, "keyboard","FILTER_KEY_DOWN|FILTER_KEY_UP")
set_filter(context, "mouse", "MOUSE_WHEEL")

_keystroke:="
(
 ushort code;
 ushort state;
 ushort information;
)"
kstroke:= new _Struct(_keystroke)

while ( recieve(context,device:=wait(context),stroke,1) >0 )
{

  if is_mouse(device)
	{

		state:=		NumGet(stroke,0,"ushort") ;ButtonFlags  1024:wheel, 0:moving,
		flags:=		NumGet(stroke,2,"ushort") ;Flags        always 0....don't know why
		rolling:=	NumGet(stroke,4,"short") ;ButtonData    for mouse wheel when it's "rolling" outputs -120 to +120
		x:=				NumGet(stroke,8,"int")   ;LastX         offset "should" be +2, but only works with +4?
		y:=				NumGet(stroke,12,"int")  ;LastY         actually works with 4...wowie
		info:=    NumGet(stroke,16,"uint") ;ExtraInformation uh...no idea?
		;ToolTip % "device=" device "`nstate=" state "`nflag=" flags "`nrolling=" rolling "`nx=" x "`ny=" y "`ninfo=" info
		;ToolTip % "device=" device "`nstate=" stroke.state "`nflag=" stroke.flags "`nrolling=" stroke.rolling "`nx=" stroke.x "`ny=" stroke.y "`ninfo=" stroke.info

		if (device=14)
		{
			/*
				if (rolling>0)
				  key:=key2dec("q")
	      if (rolling<0)
          key:=key2dec("w")

				NumPut(key,key_struct,0,"UShort") ;code
				NumPut(0,key_struct,2,"UShort")   ;state
				NumPut(0,key_struct,4,"UInt")     ;info

				send(context,device,&key_struct,1) ;down
				NumPut(1,key_struct,2,"UShort")
        send(context,device,&key_struct,1) ;up
				*/
				/*
        if (rolling>0)
          kstroke.code:= GetKeySC("Q")
        if (rolling<0)
          kstroke.code:= GetKeySC("W")
				;tooltip % kstroke[]
        kstroke.state:=0
				send(context,2,kstroke[""],1)
				kstroke.state:=1
        send(context,2,kstroke[""],1)
				;Continue
				*/
        if (rolling>0)
					send_keys(2,"Q")
        if (rolling<0)
          send_keys(2,"w")
	}
		else
			send(context,device,&stroke,1)
	}
	else if is_keyboard(device)
	{
		code := hex(NumGet(stroke,0,"Ushort")) ;Make Code
		state:= NumGet(stroke,2,"UShort")     ;Flags
 		info:= NumGet(stroke,4,"Uint")        ;ExtraInformatioa
   	name:=GetKeyName("sc" code)
		;ToolTip % "key=" name "`ncode=" code "`nstate=" state "`ninfo=" info
		;ToolTip % stroke.code

		if (code=0x01) ;escape EXIT
			break

		if name=A
		send_keys(device,"Q")
    else if name=S
    	send_keys(device,"w")
		else
			send(context,device,&stroke,1)
	}
}
return

send_keys(device,keys*){
global kstroke,context
	for every, key in keys
	{
    kstroke.code:=GetKeySC(key)
	  kstroke.state:=0
		send(context,device,kstroke[],1)
		kstroke.state:=1
	  send(context,device,kstroke[],1)
	}
}

send(context,device,stroke,nstroke){
global
Critical
	;interception_send(InterceptionContext context, InterceptionDevice device, const InterceptionStroke *stroke, unsigned int nstroke);
	res:=DllCall(dll . "\interception_send","Ptr",context,"int",device,"ptr",stroke,"int",nstroke,"Cdecl Int")
	;ToolTip % errorlevel "`n" res
return res
}

recieve(context,device,ByRef stroke,ByRef nstroke){
	global keystroke,mousestroke,dll
	Critical
	;interception_receive(InterceptionContext context, InterceptionDevice device, InterceptionStroke *stroke, unsigned int nstroke);
	VarSetCapacity(stroke,500)
  res:=DllCall(dll . "\interception_receive","Ptr",context,"int",device,"str",stroke,"int*",nstroke,"Cdecl Int")

	/*
if !IsObject(keystroke)
{
	_keystroke:="
	(
	 ushort code;
	 ushort state;
	 ushort information;
	)"
	keystroke:= new _Struct(_keystroke)
}
if !IsObject(mousestroke)
{
	_mousestroke:="
	(
	 ushort state;
	 uhort flags;
	 short rolling;
	 int x;
	 int y;
	 uint information;
	)"
  mousestroke:= new _Struct(_mousestroke)
}

if is_keyboard(device)
{
	res:=DllCall(dll . "\interception_receive","Ptr",context,"int",device,"ptr",keystroke[""],"int*",nstroke,"Cdecl Int")
  stroke:=keystroke
	ToolTip % "stroke=" stroke.code "`nkeystroke=" keystroke.code
}
if is_mouse(device)
{
	res:=DllCall(dll . "\interception_receive","Ptr",context,"int",device,"ptr",mousestroke[""],"int*",nstroke,"Cdecl Int")
	stroke:=mousestroke
}
*/
return res
}

get_hardware_id(context,device){
global dll
Critical
  VarSetCapacity(buffer,500)

	if (a_ptrsize > 4)
		DllCall(dll . "\interception_get_hardware_id","Ptr",context,"int",device,"str",buffer,"Uint",500,"Cdecl Int")
	else if (a_ptrsize < 4)
  	DllCall(dll . "\interception_get_hardware_id","Ptr",context,"int",device,"ptr",&buffer,"Uint",500,"Cdecl Int")

	return a_ptrsize > 4 ? buffer : StrGet(&buffer, "UTF-16")
}

wait(context){
	global
Critical
	return DllCall(dll . "\interception_wait","Ptr",context,"Cdecl Int")
}


set_filter(context,filter,keys){
global dll
Static keyboard:="interception_is_keyboard"
,mouse:="interception_is_mouse"
,KEY_DOWN           		= 0x00
,KEY_UP             		= 0x01
,KEY_NONE             	= 0x0000
,KEY_ALL              	= 0xFFFF
,KEY_E0              		= 0x02 ;Delete Key
,KEY_E1              		= 0x04
,KEY_TERMSRV_SET_LED 		= 0x08
,KEY_TERMSRV_SHADOW  		= 0x10
,KEY_TERMSRV_VKPACKET 	= 0x20
,FILTER_KEY_NONE             = 0x0000
,FILTER_KEY_ALL              = 0xFFFF
,FILTER_KEY_DOWN             := KEY_UP
,FILTER_KEY_UP               := KEY_UP << 1
,FILTER_KEY_E0               := KEY_E0 << 1
,FILTER_KEY_E1               := KEY_E1 << 1
,FILTER_KEY_TERMSRV_SET_LED  := KEY_TERMSRV_SET_LED << 1
,FILTER_KEY_TERMSRV_SHADOW   := KEY_TERMSRV_SHADOW << 1
,FILTER_KEY_TERMSRV_VKPACKET := KEY_TERMSRV_VKPACKET << 1
,MOUSE_NONE              = 0x0000
,MOUSE_ALL               = 0xFFFF
,MOUSE_LEFT_BUTTON_DOWN  = 0x001
,MOUSE_LEFT_BUTTON_UP    = 0x002
,MOUSE_RIGHT_BUTTON_DOWN = 0x004
,MOUSE_RIGHT_BUTTON_UP   = 0x008
,MOUSE_MIDDLE_BUTTON_DOWN= 0x010
,MOUSE_MIDDLE_BUTTON_UP  = 0x020
,MOUSE_BUTTON_1_DOWN     := MOUSE_LEFT_BUTTON_DOWN
,MOUSE_BUTTON_1_UP       := MOUSE_LEFT_BUTTON_UP
,MOUSE_BUTTON_2_DOWN     := MOUSE_RIGHT_BUTTON_DOWN
,MOUSE_BUTTON_2_UP       := MOUSE_RIGHT_BUTTON_UP
,MOUSE_BUTTON_3_DOWN     := MOUSE_MIDDLE_BUTTON_DOWN
,MOUSE_BUTTON_3_UP       := MOUSE_MIDDLE_BUTTON_UP
,MOUSE_BUTTON_4_DOWN     = 0x040
,MOUSE_BUTTON_4_UP       = 0x080
,MOUSE_BUTTON_5_DOWN     = 0x100
,MOUSE_BUTTON_5_UP       = 0x200
,MOUSE_WHEEL             = 0x400
,MOUSE_HWHEEL            = 0x800
,MOUSE_MOVE              = 0x1000
,MOUSE_MOVE_RELATIVE      = 0x000
,MOUSE_MOVE_ABSOLUTE      = 0x001
,MOUSE_VIRTUAL_DESKTOP    = 0x002
,MOUSE_ATTRIBUTES_CHANGED = 0x004
,MOUSE_MOVE_NOCOALESCE    = 0x008
,MOUSE_TERMSRV_SRC_SHADOW = 0x100

	if Instr(keys,"|")
	{
		loop,parse,keys,|
		{
			key:=%a_loopfield%
			if a_index=1
				keys2:=key
			else
				keys2:=keys2|key
		}
		keys:=keys2
	}
	else
		keys:=%keys%

	f:=get_pointer(%filter%)
	DllCall(dll . "\interception_set_filter","ptr",context,"ptr",f, "int",keys,"Cdecl Int")
}

is_mouse(device){
	global
  Critical
  return DllCall(dll . "\interception_is_mouse","int",device)
}

is_keyboard(device){
	global
  Critical
  return DllCall(dll . "\interception_is_keyboard","int",device)
}

get_pointer(func){
	global
	return DllCall("GetProcAddress", ptr, dllh, "astr", func, ptr)
}
create_context(){
	global
	return DllCall(dll . "\interception_create_context")
}
destroy_context(context){
	global
	return DllCall(dll . "\interception_destroy_context","ptr",context)
}

load(){
	global
	dll:="interception.dll"
	dllh:=DllCall("LoadLibrary", "Str", dll, "Ptr")
}

hex(n){
SetFormat, IntegerFast, hex
n+= 0  ; Sets Var (which previously contained 11) to be 0xb.
n.= ""  ; Necessary due to the "fast" mode.
SetFormat, IntegerFast, d
return n
}

dec(n){
SetFormat, Integer, D
Dec := (n) + 0
return Dec
}

key2dec(name){
hex:=GetKeySC(name)
return dec(hex)
}
acq
Posts: 2
Joined: 05 Jan 2017, 05:03

Re: Creating a wrapper for interception.dll (could use help with NumGet etc)

05 Jan 2017, 10:24

Hello ToonyTom! Great thing to open interception.dll to AHK

I am looking at AHK to customize the use of 2nd (and third and…) keyboards and mice for helping on accessibility limitations. For this it is essential to get the info from which device the input originated, and to manipulate that devices input accordingly.

Unfortunately I am away from coding for long time now, and I did not yet set up a coding-environment - so I did not test your code. Forgive me if my findings are nonesense, but looking at your code I thought I should comment what I believe to have seen:

• keystroke --> ...ushort information; ?? Not UInt? … see struct InterceptionKeyStroke
• while …,stroke… --> byref stroke (in receive), but stroke is not previously allocated (as a string): maybe this causes a memory-allocation-problem (different object-sizes of "defaul-object" and object-type "str" returned from the dll-call ( char InterceptionStroke[sizeof(InterceptionMouseStroke)] ) - Maybe stroke should be initialized with a properly sized string (sizeof(InterceptionMouseStroke) ). Possibly this posts supports that: https://autohotkey.com/boards/viewtopic ... 839#p67839 more profound.

Also I wonder, if this wrapper should be better encapsulated into a dll of its own (which utilizes the interception.dll ), exposing the routines and data of the interception.dll in a more AHK-friendly way (e.g. dont crack up data with "numget" and such, but inside the wrapper rather "simply" fill in byref-parameters of AHK-defined _struct structures ). Maybe this also could boost performance (elimnating the overhead in AHK).
ToonyTom
Posts: 9
Joined: 04 Mar 2015, 04:41

Re: Creating a wrapper for interception.dll (could use help with NumGet etc)  Topic is solved

08 Jan 2017, 14:18

Hi ACQ! Thank you very much for the advice! I took a look at my code again and found what was causing the slow down and memory spikes :mrgreen:
It was nstroke, in the receive() function! The one variable I ignored the longest because it seemed to not do very much. I had it set as "int*" or an integer pointer
in the DllCall. In interception.h nstroke was supposed to be a uint. Once I switched it to that type, the amount of memory consumed remained stable at 3mb
(before it would spike to over 100mb+). The speed problem was also taken care of and the double button press problem vanished!

Now it's completely usable and functional now! I just need to wrap a few more trivial functions and write some function descriptions, and that should be it for the wrapper :dance:
I'm planning on building a nice GUI to help easily setup the hotkeys for different devices and programs / exe's. I'll post in the script section when it's all done!

For now, here's what I got, and here's some info about the functions:
load - loads "interception.dll" into memory. Call this first.
create_context - creates a "context" for interception to work in. Yeah...I don't know what that means either haha, but call this second.
destroy_context - kills the context, usually called before exiting the program.
set_filter - this sets the kind of device ("keyboard" or "mouse") that interception will watch and it's buttons ("KEY_UP|KEY_DOWN"). Have a look at the set_filter function for key names. Call this third.
receive - this is a function that waits for a device by using the wait() function as one of it's parameters, you also set a name for the keyboard object and mouse object, and give it a "1" at the end for nstroke. You have to put this function inside of a while loop because it will return a 1 as long as everything is working as it should.
wait - this function will wait for a device (which you setup with set_filter) to be used. When it detects something it will return the number of the device it happened on. Like, my keyboard is device 2 for example.
is_keyboard - returns a 1 if the device number is a keyboard and 0 if not.
is_mouse - returns a 1 if the device number is a mouse and 0 if not.
get_hardware_id - gets a string of letters and numbers that (hopefully) uniquely identifies your device.
send - sends key strokes as if they are coming from a device you specify. In the demo script below, I used key.device - which is the device number of my keyboard - to send key presses when I roll the mouse wheel on my second mouse.
get_keyname - This is a function I made to easily get info from the "keyboard" and "mouse" objects. You give it one of the name of the var names you set in the receive function such as "keyboard" or "mouse", then you give it a variable name to store the name and another variable name to store the state of that key, which is 1 for down and 0 for up. It works for the keyboard keys and mouse keys.

to use this demo script you'll need to install the interception driver
located here in interception.zip: https://github.com/oblitum/Interception ... /tag/1.0.0
extract it, and go to the "command line installer folder"
type "cmd" inside of an explorer window to open a command prompt to that folder
type "install-interception /install"
now to go the library folder and copy interception.dll from either "x32" or "x64" (depending on which version of AHK you like to use) to the folder with the demo script
You also need _struct.ahk and sizeof.ahk located here: https://github.com/HotKeyIt/_Struct
download each one and put them into your LIB folder for AHK. In my case, I like to make a LIB folder inside AutoHotKey's install directory and put frequently used scripts with fucntions there.
Now you should be ready to run the demo script

Code: Select all

#Include <_Struct>
#SingleInstance force
#MaxHotkeysPerInterval 255
#MaxThreads 255
SetKeyDelay -1
SetBatchLines -1


load()
context:=create_context()
set_filter(context, "keyboard","KEY_ALL")
loop,5 ;everything but MOUSE_MOVE
	mouse_filter.="MOUSE_BUTTON_" a_index "_DOWN|MOUSE_BUTTON_" a_index "_UP|"
set_filter(context, "mouse", mouse_filter "MOUSE_WHEEL|MOUSE_HWHEEL")

while ( receive(context,device:=wait(context),key,mouse,1) >0 )
{
	critical
	if is_keyboard(device)
	{
   	get_keyname(key,name,state)
		ToolTip % "device: " device "`nname:" name "`nstate:" state

		if name=Escape
			break

		if name=A
     	key.code:=GetKeySC("Q")

      send(context,device,key,1)
	}
  else if is_mouse(device)
	{
		get_keyname(mouse,name,state)
		ToolTip % "device: " device "`nname:" name "`nstate:" state

		;ToolTip % clipboard:=get_hardware_id(context,device)
		;hardware_id:=get_hardware_id(context,device)
		;if  hardware_id = HID\VID_046D&PID_C07D&REV_8802&MI_00 ;my mouse

		if device=14 ;my razer nostromo
		{
			if name=wheel
			{
				if state ;DOWN
					key.code:= GetKeySC("Q")
				else if !state ;UP
					key.code:= GetKeySC("W")

				key.state:=0, send(context, key.device, key,1)
      	                       key.state:=1, send(context, key.device, key,1)
      }
		}
		else
		send(context,device,mouse,1)
	}
}
destroy_context(context)
return



get_keyname(o,ByRef name,ByRef state){
	Critical
	if is_keyboard(o.device)
	{
    state:=o.state
		name:=GetKeyName("sc" hex(o.code))
	  hex:=hex(o.code)
		;ToolTip % state "`n" name "`n" hex
		if !name ;windows key
		{
			if hex=0x5b
				name=LWin
			if hex=0x5c
				name=RWin
		}
		else if name in LControl,LAlt
		{
			if state=2
				name:= "R" . SubStr(name,2, strlen(name))
			if state=3
				name:= "R" . SubStr(name,2, strlen(name))
		}
		else if name
		{
			if hex=0x53
			{
				if state in 0,1
					name= NumpadDot
				if state in 2,3
					name=Delete
			}
			else if hex=0x36
				name=RShift
      else if (hex=0x2a) AND state=3
				name:="PrintScreen", state:=1
      else if (hex=0x37) AND state=2
				name:="PrintScreen", state:=0
		}

		if state in 0,2 ;down
			state:=1
		else if state in 1,3 ;up
	    state:=0
	}
	else if is_mouse(o.device)
	{
    state:=o.state

		if state in 1,2
	    name=LButton
	  else if state in 4,8
	    name=RButton
	  else if state in 16,32
	    name=MButton
		else if state in 64,128
	  	name=XButton1
	      else if state in 256,512
	  	name=XButton2
		else if state=1024
		{
			name=Wheel
			if (o.rolling<0)
				state:=1 ;down
			else
				state:=0 ;up
		}

		if state in 1,4,16,64,256 ;down
			state:=1
	  if state in 2,8,32,128,512 ;up
	    state:=0
	}
}


send_keys(device,ByRef stroke,keys*){
global
	for every, key in keys
	{
    stroke.code:=GetKeySC(key)
		send(context,device,stroke,1)
	}
}

send(context,device,stroke,nstroke){
global
Critical
	res:=DllCall(dll . "\interception_send","Ptr",context,"int",device,"ptr",stroke[],"uint",nstroke,"Cdecl Int")
return res
}

receive(context,device,ByRef key,ByRef mouse,nstroke){
	global dll
	Critical

	if !isObject(key)
	{
		_key:="
		(
		 ushort code;
		 ushort state;
		 uint information;
		 uint device;
		)"
		;varsetcapacity(key,12)
		key:= new _Struct(_key)
	}

	if !isObject(mouse)
	{
		_mouse:="
		(
		 ushort state;
		 ushort flags;
		 short rolling;
		 int x;
		 int y;
		 uint information;
		 uint device;
		)"
		;varsetcapacity(mouse,18)
		mouse:= new _Struct(_mouse)
	}


	if is_keyboard(device)
	{
		res:=DllCall(dll . "\interception_receive","Ptr",context,"int",device,"ptr",key[""],"uint",nstroke,"Cdecl Int")
		key.device:=device
	}
	else if is_mouse(device)
	{
		res:=DllCall(dll . "\interception_receive","Ptr",context,"int",device,"ptr",mouse[""],"uint",nstroke,"Cdecl Int")
		mouse.device:=device
	}
return res
}

get_hardware_id(context,device){
global dll
Critical
VarSetCapacity(buffer,500)

	if (a_ptrsize > 4)
		DllCall(dll . "\interception_get_hardware_id","Ptr",context,"int",device,"str",buffer,"Uint",500,"Cdecl Int")
	else if (a_ptrsize < 4)
  	DllCall(dll . "\interception_get_hardware_id","Ptr",context,"int",device,"ptr",&buffer,"Uint",500,"Cdecl Int")

	return a_ptrsize > 4 ? buffer : StrGet(&buffer, "UTF-16")
}

wait(context){
	global
Critical
	return DllCall(dll . "\interception_wait","Ptr",context,"Cdecl Int")
}


set_filter(context,filter,keys){
global dll
Static keyboard:="interception_is_keyboard"
,mouse:="interception_is_mouse"
,KEY_DOWN           		= 0x00
,KEY_UP             		= 0x01
,KEY_NONE             	= 0x0000
,KEY_ALL              	= 0xFFFF
,KEY_E0              		= 0x02 ;Delete Key
,KEY_E1              		= 0x04
,KEY_TERMSRV_SET_LED 		= 0x08
,KEY_TERMSRV_SHADOW  		= 0x10
,KEY_TERMSRV_VKPACKET 	= 0x20
,FILTER_KEY_NONE             = 0x0000
,FILTER_KEY_ALL              = 0xFFFF
,FILTER_KEY_DOWN             := KEY_UP
,FILTER_KEY_UP               := KEY_UP << 1
,FILTER_KEY_E0               := KEY_E0 << 1
,FILTER_KEY_E1               := KEY_E1 << 1
,FILTER_KEY_TERMSRV_SET_LED  := KEY_TERMSRV_SET_LED << 1
,FILTER_KEY_TERMSRV_SHADOW   := KEY_TERMSRV_SHADOW << 1
,FILTER_KEY_TERMSRV_VKPACKET := KEY_TERMSRV_VKPACKET << 1
,MOUSE_NONE              = 0x0000
,MOUSE_ALL               = 0xFFFF
,MOUSE_LEFT_BUTTON_DOWN  = 0x001
,MOUSE_LEFT_BUTTON_UP    = 0x002
,MOUSE_RIGHT_BUTTON_DOWN = 0x004
,MOUSE_RIGHT_BUTTON_UP   = 0x008
,MOUSE_MIDDLE_BUTTON_DOWN= 0x010
,MOUSE_MIDDLE_BUTTON_UP  = 0x020
,MOUSE_BUTTON_1_DOWN     := MOUSE_LEFT_BUTTON_DOWN
,MOUSE_BUTTON_1_UP       := MOUSE_LEFT_BUTTON_UP
,MOUSE_BUTTON_2_DOWN     := MOUSE_RIGHT_BUTTON_DOWN
,MOUSE_BUTTON_2_UP       := MOUSE_RIGHT_BUTTON_UP
,MOUSE_BUTTON_3_DOWN     := MOUSE_MIDDLE_BUTTON_DOWN
,MOUSE_BUTTON_3_UP       := MOUSE_MIDDLE_BUTTON_UP
,MOUSE_BUTTON_4_DOWN     = 0x040
,MOUSE_BUTTON_4_UP       = 0x080
,MOUSE_BUTTON_5_DOWN     = 0x100
,MOUSE_BUTTON_5_UP       = 0x200
,MOUSE_WHEEL             = 0x400
,MOUSE_HWHEEL            = 0x800
,MOUSE_MOVE              = 0x1000
,MOUSE_MOVE_RELATIVE      = 0x000
,MOUSE_MOVE_ABSOLUTE      = 0x001
,MOUSE_VIRTUAL_DESKTOP    = 0x002
,MOUSE_ATTRIBUTES_CHANGED = 0x004
,MOUSE_MOVE_NOCOALESCE    = 0x008
,MOUSE_TERMSRV_SRC_SHADOW = 0x100
	if Instr(keys,"|")
	{
		loop,parse,keys,|
		{
			key:=%a_loopfield%

			if a_index=1
				keys2:=key
			else
				keys2:=keys2|key
		}
		keys:=keys2
	}
	else
		keys:=%keys%

	f:=get_pointer(%filter%)
	DllCall(dll . "\interception_set_filter","ptr",context,"ptr",f, "int",keys,"Cdecl Int")
}

is_mouse(device){
	global
  Critical
  return DllCall(dll . "\interception_is_mouse","int",device)
}

is_keyboard(device){
	global
  Critical
  return DllCall(dll . "\interception_is_keyboard","int",device)
}

get_pointer(func){
	global
	return DllCall("GetProcAddress", ptr, dllh, "astr", func, ptr)
}
create_context(){
	global
	return DllCall(dll . "\interception_create_context")
}
destroy_context(context){
	global
	return DllCall(dll . "\interception_destroy_context","ptr",context)
}

load(){
	global
	dll:="interception.dll"
	dllh:=DllCall("LoadLibrary", "Str", dll, "Ptr")
}

hex(n){
SetFormat, IntegerFast, hex
n+= 0
n.= ""
SetFormat, IntegerFast, d
return n
}

dec(n){
SetFormat, Integer, D
Dec := (n) + 0
return Dec
}

key2dec(name){
hex:=GetKeySC(name)
return dec(hex)
}
I hope the demo is easy to make sense of. I was working on a function called "send_keys", but it's not quite usable yet.
Oh, and ACQ, an editor that I like to use for AHK scripts is called PSPad: http://www.pspad.com/en/
It has syntax hilighting for AHK, and if you find a script called "intellisense" it can help you by auto-completing commands as you type them. I know it requires a file "%ahk_dir%\Extras\Editors\Syntax\Commands.txt" but that file is no longer in the autohotkey installer. Maybe it's possible to find it online somewhere. I'll have a look later.
Noesis
Posts: 301
Joined: 26 Apr 2014, 07:57

Re: Creating a wrapper for interception.dll (could use help with NumGet etc)

08 Jan 2017, 20:34

Hi ToonyTom, Nice work on getting this into AHK, I had a go once and gave up (ended up creating a helper C# app to access it's functions, and while it worked didn't get around to finishing as I had to reinstall windows and still haven't installed visual studio to continue work on it), and am now thinking it may not be worth finishing as native ahk support would likely be the better alternative.

Anyway just wondering about Mouse_Move. I noticed in the example code there is a comment saying "everything but Mouse_Move", and that is unfortunately exactly the thing I was most interested in. Just curious as to if this is something you're planning to implement in the future ?
ToonyTom
Posts: 9
Joined: 04 Mar 2015, 04:41

Re: Creating a wrapper for interception.dll (could use help with NumGet etc)

09 Jan 2017, 00:11

Hey Noesis! You know, I was actually thinking about doing almost the same thing! Before I found the solution to fixing this, I had installed visual studio and code::blocks and trying to learn C language...hah! I did manage to get some example code working in those once or twice, but trying to include libraries "the right way" was so difficult and cumbersome it was impossible to even compile and run anything! Every day I struggled with that and gave up sometimes. All the nonsense about typing and declaring every single variable made me miss the simplicity of AHk A LOT!

MOUSE_MOVE works btw. The reason I commented it like that is because when you use it while showing a tooltip it will slow down your mouse considerably. But if you use MOUSE_MOVE without having a tooltip, it works perfectly fine as far as I could tell.
Try replacing this:

Code: Select all

set_filter(context, "keyboard","KEY_ALL")
loop,5 ;everything but MOUSE_MOVE
	mouse_filter.="MOUSE_BUTTON_" a_index "_DOWN|MOUSE_BUTTON_" a_index "_UP|"
set_filter(context, "mouse", mouse_filter "MOUSE_WHEEL|MOUSE_HWHEEL")
with this:

Code: Select all

set_filter(context, "keyboard","KEY_ALL")
set_filter(context, "mouse", "MOUSE_ALL")
or this:

Code: Select all

set_filter(context, "keyboard","KEY_ALL")
set_filter(context, "mouse", "MOUSE_MOVE")
All the values you can use are inside of the set_filter function of the demo:

Code: Select all

set_filter(context,filter,keys){
global dll
Static keyboard:="interception_is_keyboard"
,mouse:="interception_is_mouse"
,KEY_DOWN           		= 0x00
,KEY_UP             		= 0x01
,KEY_NONE             	= 0x0000
,KEY_ALL              	= 0xFFFF
,KEY_E0              		= 0x02 ;Delete Key
,KEY_E1              		= 0x04
,KEY_TERMSRV_SET_LED 		= 0x08
,KEY_TERMSRV_SHADOW  		= 0x10
,KEY_TERMSRV_VKPACKET 	= 0x20
,FILTER_KEY_NONE             = 0x0000
,FILTER_KEY_ALL              = 0xFFFF
,FILTER_KEY_DOWN             := KEY_UP
,FILTER_KEY_UP               := KEY_UP << 1
,FILTER_KEY_E0               := KEY_E0 << 1
,FILTER_KEY_E1               := KEY_E1 << 1
,FILTER_KEY_TERMSRV_SET_LED  := KEY_TERMSRV_SET_LED << 1
,FILTER_KEY_TERMSRV_SHADOW   := KEY_TERMSRV_SHADOW << 1
,FILTER_KEY_TERMSRV_VKPACKET := KEY_TERMSRV_VKPACKET << 1
,MOUSE_NONE              = 0x0000
,MOUSE_ALL               = 0xFFFF
,MOUSE_LEFT_BUTTON_DOWN  = 0x001
,MOUSE_LEFT_BUTTON_UP    = 0x002
,MOUSE_RIGHT_BUTTON_DOWN = 0x004
,MOUSE_RIGHT_BUTTON_UP   = 0x008
,MOUSE_MIDDLE_BUTTON_DOWN= 0x010
,MOUSE_MIDDLE_BUTTON_UP  = 0x020
,MOUSE_BUTTON_1_DOWN     := MOUSE_LEFT_BUTTON_DOWN
,MOUSE_BUTTON_1_UP       := MOUSE_LEFT_BUTTON_UP
,MOUSE_BUTTON_2_DOWN     := MOUSE_RIGHT_BUTTON_DOWN
,MOUSE_BUTTON_2_UP       := MOUSE_RIGHT_BUTTON_UP
,MOUSE_BUTTON_3_DOWN     := MOUSE_MIDDLE_BUTTON_DOWN
,MOUSE_BUTTON_3_UP       := MOUSE_MIDDLE_BUTTON_UP
,MOUSE_BUTTON_4_DOWN     = 0x040
,MOUSE_BUTTON_4_UP       = 0x080
,MOUSE_BUTTON_5_DOWN     = 0x100
,MOUSE_BUTTON_5_UP       = 0x200
,MOUSE_WHEEL             = 0x400
,MOUSE_HWHEEL            = 0x800
,MOUSE_MOVE              = 0x1000
,MOUSE_MOVE_RELATIVE      = 0x000
,MOUSE_MOVE_ABSOLUTE      = 0x001
,MOUSE_VIRTUAL_DESKTOP    = 0x002
,MOUSE_ATTRIBUTES_CHANGED = 0x004
,MOUSE_MOVE_NOCOALESCE    = 0x008
,MOUSE_TERMSRV_SRC_SHADOW = 0x100
	if Instr(keys,"|")
	{
		loop,parse,keys,|
		{
			key:=%a_loopfield%

			if a_index=1
				keys2:=key
			else
				keys2:=keys2|key
		}
		keys:=keys2
	}
	else
		keys:=%keys%

	f:=get_pointer(%filter%)
	DllCall(dll . "\interception_set_filter","ptr",context,"ptr",f, "int",keys,"Cdecl Int")
}
Hope that helps ;) Let me know how it works for you.
acq
Posts: 2
Joined: 05 Jan 2017, 05:03

Re: Creating a wrapper for interception.dll (fixed and working!)

09 Jan 2017, 09:31

Hi ToonyTom!

Thanks for your effort and your reply. What you put together already seems very usable - will try as soon I get onto it. Thanks again.

And, btw, I tried Notepad++ with AutoIT (set as language) - this also gives nice context highlighting though not totally correct).
Noesis
Posts: 301
Joined: 26 Apr 2014, 07:57

Re: Creating a wrapper for interception.dll (fixed and working!)

11 Jan 2017, 06:25

Yeah, I agree works very well, naturally with mouse move, the tooltip in combination with sending of mouse movements creates a bit of an event queue (i.e. the cursor lags a bit) but changing the tooltip to display at predefined x, y coordinates speeds things up considerably, while not displaying one (or displaying only the tip without sending the movement) seems to make it respond normally, (at least I'm not noticing any lag under those conditions).

Also, my guess is you don't have a mouse with a Horizontal wheel since it wasn't accounted for in the get_device_name() function. Just put this underneath the horizontal wheel entry:

Code: Select all

		else if state = 2048
		{
			name=HWheel
			if (o.rolling>0)
				state:=1 ;right
			else
				state:=0 ;left
		}
I changed the second o.rolling if statement here compared to the vertical one to check the opposite way as it just makes sense for me if 0 is up & 1 is down then left should be less than right (kind of mirroring how screen coordinates work).

Awesome job ToonyTom.
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: Creating a wrapper for interception.dll (fixed and working!)

29 Mar 2017, 04:36

Hi guys.
Defo interested in this and similar projects. I am just starting to get into C#, and my plan is to try and write a C# wrapper to encapsulate a bunch of functionality (DirectInput, XInput, RawInput etc) which we can then call from AHK. I am looking at interception support, but not sure on how to go about wrapping it in a C# DLL.

Would certainly be interested in working with any of you guys to work towards this goal.
Noesis
Posts: 301
Joined: 26 Apr 2014, 07:57

Re: Creating a wrapper for interception.dll (fixed and working!)

05 Apr 2017, 02:17

Hi Evil. I'm not entirely sure interception can be wrapped quite the way you're proposing (unless I'm misunderstanding what you mean in the thread you mentioned), as it's not really something that simply reports stuff, it is basically a kind of mouse and keyboard driver itself. (it runs just above the actual driver layer, but essentially what it does becomes what everything else will see, Interception does see what the driver produces i.e. stuff like LGS which can change mouse button to keypress, it sees a key not a mouse button, but it doesn't see other faked input like ahk's send for example)

Another potential issue is once an intercept is underway, you can't simply tell it to stop and have it obey, it must process that command to stop which means it needs to be triggered by an actual physical key or mouse event (if you're intercepting mouse movement, this isn't a big deal but if you're only capturing the keyboard, it requires the keyboard be used before it will stop/exit). You can forcefully kill the process it's running on, and that will work but C# as far as I know, doesn't allow forceful thread termination, so you will be stuck with this limitation, but it can be worked around so probably not a big deal.

Finally the loop which does the processing must be in it's own process/thread, if not then it will work but nothing else in the thread/process will work - and with C# you'll most likely get an exception error if you try and interact with anything in that thread (like a form) which possibly (not always) has the effect of you having no way to dismiss the error box without holding down the computers power button to force a restart. - just letting you know, as I found out the hard way.

Anyway like I said earlier in this topic I was working on this in C#, but since this ahk version has been done, I think it's easier just using this with ahk and not needing to use C#, essentially for me every program that I use this with will have different requirements, so each would need to be custom anyway. Most the code I did was messy test version stuff, and isn't really something you're likely interested in, about the only thing you'd possibly be interested in is this part which is essentially what toony tom did with ahk but in C#.
Interception.cs
totalwaa
Posts: 5
Joined: 01 Dec 2016, 03:54
Contact:

Re: Creating a wrapper for interception.dll (fixed and working!)

19 Apr 2017, 09:42

Is it possible to somehow force windows mouse acceleration on through interception so I have it on always ?? it would be so cool! anyone know this ?
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: Creating a wrapper for interception.dll (fixed and working!)

19 Apr 2017, 11:53

Windows Mouse Acceleration is nothing to do with games.
FPS games utterly ignore it, as it is a pointer setting, not an input setting.

There are equivalent options on some mice, but they do not use Windows Mouse Acceleration.

As I have probably said before - you seriously do not want this setting as it makes it nigh on impossible to form proper muscle memory.
Noesis
Posts: 301
Joined: 26 Apr 2014, 07:57

Re: Creating a wrapper for interception.dll (fixed and working!)

20 Apr 2017, 09:24

No, you couldn't force Windows mouse acceleration on with a game using interception. You could however implement your own mouse acceleration algorithm, but to be honest I tend to agree with evilC here.

I have one of those mice he mentions, and I doubt you'd want this (possible exception is RTS or Click & Point adventure game i.e. something with a cursor, but these usually have an in game option to use mouse acceleration anyway). with regard to FPS games, my reasoning isn't so much to do with muscle memory, but more along the lines of how mouse acceleration works with respect to how these games are played. i.e a small fast movement turns into a large movement, so when you need to rapidly adjust your sight slightly, you end up turning too much, if you do it fast, so you have to do it less fast, meaning you can't rapidly do it - it's counter productive, and frustrating. Hence I always set my mouse to turn off mouse acceleration for FPS games, and often lower the mouses dpi a bit too.
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: Creating a wrapper for interception.dll (fixed and working!)

20 Apr 2017, 13:29

Low mouse sensitivity for the win.

If you want to maintain low sensitivity for high accuracy, but still be able to generate large movements without ratcheting, then see my RollMouse app.
This will make your mouse behave somewhat like a trackball - if you move the mouse fast and pick it up while still in motion, then it will keep sending mouse movement until you put the mouse back on the mat. Great for tanks in BF!
phasermaniac
Posts: 74
Joined: 09 Apr 2017, 14:05

Re: Creating a wrapper for interception.dll (fixed and working!)

21 Apr 2017, 16:27

Hello
I have 2 crt lightguns working nice in win10, they work by rawinput, absolute coordinates with Mame and other amulators.
But I have a problem: no drivers that flashes the screen when shot, and crt lightguns need it to track fine in dark colors, and this makes unplayable almost every game.

Another crt lightgun user found a solution, that does the next:
A program that shared with me, which produces the flash under a keypress,
An electronics citcuit to divide trigger in two buttons: one for activating the flasher program, and the other the original trigger button but delayed and shortened by a timer.

The guns are always allways tracking their position when pointing at screen, but they stop when a dark area. So I only need the flash being launched a short time before and while the button press to the shot being placed over dark areas


I was wondering if the electronics part could be with your wrapper, as I've been said with interception will be the only way I can simulate the buttons of rawinput mice.

In emulators, triggers must be mouseXbutton0, mouseYbutton0.
The guns driver let me map gun buttons to any mice button, and a keyboard key at the time, so I can map gun1 trigger to mouse0button4 (that has no action in the emus, and so I have not to blind this button) and key F (that launches the screen flash), and gun2 trigger to mouse1button4 and key F.

and a little script like:

mouse0button4:: ;no action in emus
Sleep,5
send, mouse0button0 -> shot P1

mouse0button4:: ;no action in emus
Sleep,5
send, mouse0button0 -> shot P2

do you think this would work with your wrapper? If yes a little help would be appreciated as I can do simple ahk scripts, but in all the dll think I'm very lost.
Many thanks anyway!
Noesis
Posts: 301
Joined: 26 Apr 2014, 07:57

Re: Creating a wrapper for interception.dll (fixed and working!)

22 Apr 2017, 09:44

It should work, assuming interception will be able to see the device - this will need to be tested, go to the answer post above (yellow one) by ToonyTom (he's the one that wrote the wrapper), and follow the instructions he provided about running the demo script.

Before you run the demo script, You need the buttons of the light guns to use the exact buttons the emulator will need to receive for this test, also you will need to only use one output for each trigger at a time, otherwise you'll only see information for whichever key/button event happens last.

If for some reason you can't switch off or nullify one of the trigger outputs (so one Mousebutton per trigger), We'll need a different way to get the info. (DO NOT change the tooltips to msgbox's, you'll loose all ability to type/click anything in windows until you hard reset you're computer if you do that. OutuputDebug would work if you have a debugger you can use ?)

If you can get the Info, You'll need to take note of what device is reported and also what "name" (the key/button) is reported. State should change between 1 & 0 depending on if the trigger is down or up. If you can't get the info or get stuck, just post back, with some details on what happened.

Also using this wrapper is quite different to a regular ahk script so if you put stuff like hotkeys in this script - they won't work like normal ahk would. Out of curiosity, are you familiar with other languages, or only ahk ?.
phasermaniac
Posts: 74
Joined: 09 Apr 2017, 14:05

Re: Creating a wrapper for interception.dll (fixed and working!)

22 Apr 2017, 10:32

Hello noesis, thanks for the response, amazing!
I'm familiar with html css php some javascript, but not programming inputs and dlls...
At this moment I have the example running, I have been testing the script, and I understand some things but I'm a bit lost.
the tooltips report me the gun id and I also tested the hardware_id and works too, I am able to blind a button, (even the guns drivers can't see it, perfect!) but I can't create a keypress from a determinated mouse(gun), something like:

Code: Select all

#include <_Struct>

#SingleInstance force
#MaxHotkeysPerInterval 255
#MaxThreads 255
SetKeyDelay -1
SetBatchLines -1


load()
context:=create_context()
set_filter(context, "keyboard","KEY_ALL")
loop,5 ;everything but MOUSE_MOVE
set_filter(context, "mouse", mouse_filter "MOUSE_BUTTON_5_DOWN|MOUSE_BUTTON_5_UP")

while ( receive(context,device:=wait(context),key,mouse,1) >0 )
{
	critical
	if is_keyboard(device)
	{
   	get_keyname(key,name,state)
		ToolTip % "device: " device "`nname:" name "`nstate:" state

		if name=Escape
			break

      send(context,device,key,1)
	}
  else if is_mouse(device)
	{
		;ToolTip % clipboard:=get_hardware_id(context,device)
		;hardware_id:=get_hardware_id(context,device)
		;if  hardware_id = HID\VID_0B9A&PID_016A&REV_0100&Col01 ;gun1	
		get_keyname(mouse,name,state)
		ToolTip % "device: " device "`nname:" name "`nstate:" state
	if device=14 ;gun1		
		{
		if name=XButton2
			{		
				[b]send_keys (14,"LButton")[/b]
			}
		}
		else
		send(context,device,mouse,1)
	}
}
destroy_context(context)
return
and so on...
Last edited by phasermaniac on 23 Apr 2017, 10:34, edited 1 time in total.
phasermaniac
Posts: 74
Joined: 09 Apr 2017, 14:05

Re: Creating a wrapper for interception.dll (fixed and working!)

22 Apr 2017, 12:10

I'm getting it near working...
leaving trigger as LButton (which shots in the emulators), I can blind it

set_filter(context, "mouse", mouse_filter "MOUSE_BUTTON_1_DOWN|MOUSE_BUTTON_1_UP")

and so delay it:

Code: Select all

		if device=14 ;gun1
		{
			if name=LButton
			{
				send k
				sleep, 500
				send(context,device,mouse,1)
			}
		}
I'm seeing the correct results on the guns driver: (now I delay the LButton 500ms to be evident)
and I'm only getting one last problem: k is sent the real and the simulated LButton, and may only be fired first time.
I also tried

Code: Select all

		if device=14 ;gun1
		{
			if name=LButton
			{
				key.code:= GetKeySC("K")
				send(context, key.device, key,1)
				sleep, 500
				send(context,device,mouse,1)
			}
		}
but It had no effect
Last edited by phasermaniac on 23 Apr 2017, 10:34, edited 1 time in total.
phasermaniac
Posts: 74
Joined: 09 Apr 2017, 14:05

Re: Creating a wrapper for interception.dll (fixed and working!)

22 Apr 2017, 14:03

Also I noted if I chain two mice

Code: Select all

  else if is_mouse(device)
	{
		get_keyname(mouse,name,state)
		ToolTip % "device: " device "`nname:" name "`nstate:" state
		;if device=14 ;gun1
		
		;ToolTip % clipboard:=get_hardware_id(context,device)
		hardware_id:=get_hardware_id(context,device)
		
		;if  hardware_id = HID\VID_0B9A&PID_016A&REV_0100&Col01 ;my mouse

		if device=11 
		{
			if name=LButton
			{
				send k
				sleep, 500
				send(context,device,mouse,1)
			}
		}
		if device=14 
		{
			if name=LButton
			{
				send k
				sleep, 500
				send(context,device,mouse,1)
			}
		}
		else
		send(context,device,mouse,1)
	}
}
The first has a strange behavior, I changed them and the first seems to send k and Backwards and tnhe second sends k twice.
I need twice mice to send k only on the real LButton. What I'm doing wrong?
Last edited by phasermaniac on 23 Apr 2017, 10:35, edited 1 time in total.
Noesis
Posts: 301
Joined: 26 Apr 2014, 07:57

Re: Creating a wrapper for interception.dll (fixed and working!)

23 Apr 2017, 10:05

phasermaniac wrote:The first has a strange behavior, I changed them and the first seems to send k and Backwards and tnhe second sends k twice.
I need twice mice to send k only on the real LButton. What I'm doing wrong?
Hi again,
firstly when posting code, can you please use the code button (in full editor/preview) and put your code inside the code tags, it makes it a lot easier to read the posts, and also If you could include the complete code it will make it easier for me to see exactly whats going on and to edit.
Secondly, I'm not sure what you mean by it "sends k and Backwards" i.e. do you mean it sends a backspace or left arrow or something else - I'm just confused by it.

Anyway device 11 will send two mouse buttons (trigger presses/releases) as you left out an "else" and I'm not sure if there is any other buttons on the guns (or if the triggers are actually two stage or something) but if so they won't work. I'm going to assume this isn't a problem.

Also I'd recommend not using ahk's send command instead use the wrappers send function after taking note of your keyboards device number, also not sure if you want the key to press and release before the mouse button is sent or do you want it down the entire time the button is sent ? I've put in some commented code below to do that last bit in theory it's untested so may not work.

My original thought was to map the keyborad button back to the driver after the test so all you would actually need to do in this script is block the mouse button part. The other script would have a hotkey in it like ~k:: , and it would wait then send the mouse button like the original post you made. A sleep in this loop essentially means all the filtered input is blocked for the duration of the sleep period this may have been a problem. You could also change the filters in the setup to only include the mouse left button and not filter the keyboard and then keep the sleep on the lbutton down for the devices concerned, as it only filters what you set it to filter if that makes sense. - there's a few ways you could do it.

Code: Select all

	else if is_mouse(device)
	{
		get_keyname(mouse,name,state)
		ToolTip % "device: " device "`nname:" name "`nstate:" state
		;if device=14 ;gun1
		
		;ToolTip % clipboard:=get_hardware_id(context,device)
		hardware_id:=get_hardware_id(context,device)
		
		;if  hardware_id = HID\VID_0B9A&PID_016A&REV_0100&Col01 ;my mouse
		if name=LButton
		{
			if (device=11 or device=14)
			{
			;	Create a key object to send via interceptions send()
			; 	- not sure if this will work I've never tested creating a key from a mouse button being sent
			;	key.device := put appropriate number here for your keyboard
			;	key.code := GetKeySC("K")
			;	if (state = 1)
			;	{
			;		key.state := 1
			;		send(context,key.device,key,1)
					sleep, 500		; I'm assuming you only need to pause on the trigger being pressed not when it's released
			;	}
			;	else
			;	{
			;		key.state := 0	
			;		send(context,key.device,key,1)
			;	}
			}
			send(context,device,mouse,1)
		}
		else
			send(context,device,mouse,1)
}

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: morkovka18 and 175 guests