AutoHotInterception (AHI): Multi-Keyboard / Multi-Mouse support for AHK. Per-device blocking!

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: AutoHotInterception - Multi-Keyboard / Multi-Mouse support for AHK. Per-device blocking!

30 Mar 2018, 10:14

So I sat down and thought about this, and what you want is not so simple, especially considering your stretch goals of being able to monitor mouse movement and such.
The reason being that AHK is not a multi-threaded language, and is not well suited to high-volume updates (Such as mouse positional info).

Bear in mind that AHI is interacting with a keyboard and mouse driver. If AHI locks up, all filtered devices lock up, so I need to try and at least take precautions to try and stop AHI locking up if a callback in someone's AHK script takes ages to process (eg due to a sleep), thus stalling the processing queue. Therefore, my code fires off each callback on a new thread, so your callback functions (especially eg the mouse one) will have the absolute hell bombarded out of them.

This becomes an issue, when, for example, you want to delay reaction to something (eg the trigger) - just doing a sleep when one gun pulls it's trigger means another bit of code can lock up.

From your code, it is fairly apparent that to get you to the point you need to be, with you attempting to write the code, would take a lot of back-and-forth, so I decided to write something for you. Now this code may well initially go somewhat over your head, but if you can wrap your head around it, this is a very neat way of doing things.

Something you got right though was the turning on and off blocking. I had never anticipated using AHI like that, but it seems quite happy :)

You have two challenges which you seem to be grappling with - scope (lots of variables which need to be used in various places) and duplicity (two guns with identical logic, and you need to process both).

The answer to both of these problems is classes.
A class allows you to "encapsulate" all the logic and data for a particular "thing" into one object.
So we write a "Gun" class that knows how to handle one gun, then create two of those classes and each functions identically.
We can then easily write the code and test it with one gun, then when we have it working, create another gun class and it all works.
Each gun class can hold it's own set of variables or "properties" (eg what interception ID it is, what it's flashkey is etc) and functions which operate upon those properties.
No need for loads of global variables - you don't need a `global flashkey1`, you just need a concept of "MY flashkey".

Code: Select all

#SingleInstance force
#Persistent
#include Lib\AutoHotInterception.ahk

InterceptionWrapper := new AutoHotInterception()
global Interception := InterceptionWrapper.GetInstance()

devices := InterceptionWrapper.GetDeviceList()
if (!devices.Length()){
	msgbox Device List Check failed
	ExitApp
}

;id1 := Interception.GetDeviceId(true, 0x0B9A, 0x016A)
;id2 := Interception.GetDeviceId(true, 0x0B9A, 0x016A, 2)	; Uses new "Return 2nd instance of this VID/PID syntax

id1 := 15

gun1 := new Gun(id1, "a")
;gun2 := new Gun(id2, "k")

return

^Esc::
	ExitApp

; ==========================================================================

/*
LightGun class for AutoHotInterception

Usage:
myGun := new Gun(<id>, <flashkey>)
eg
myGun := new Gun(15, "{F12}")

id			The Interception ID of the Gun
flashkey	The AHK key name of the key to send for the flash
*/
Class Gun {
	; Configure these to your liking
	flashtime := 500	; The amount of time the flash lasts
	mousebutton := 1	; Which mouse button is the trigger?
	
	; Called when you create a new Gun
	__New(id, flashkey){
		this.id := id
		this.flashkey := flashkey
		
		; Create the function needed for the flash timer
		this.FlashEndFn := this.FlashEnd.Bind(this)
		
		; Subscribe to the fire button
		Interception.SubscribeMouseButton(this.id, this.mousebutton, true, this.ButtonEvent.Bind(this))
		
		; Subscribe to movement, turn block off
		this.SetSubscriptionState(0)
	}
	
	; Called when the trigger is pressed or released
	ButtonEvent(state){
		if (state){
			; Button was pressed
			this.DoFlashSequence()
		}
	}
	
	; Called when the mouse moves
	MouseEvent(x, y){
		;~ Tooltip % x
	}
	
	; Called when the flash seqence starts
	DoFlashSequence(){
		;~ ToolTip % "Interception ID " this.id " Flash Start @ " A_TickCount
		this.SetSubscriptionState(1)	; block movement
		Send % this.flashkey			; Send the flash key
		this.SetButtonState(1)			; press the trigger
		
		; Start the timer running to handle end of flash
		fn := this.FlashEndFn
		SetTimer, % fn, % "-" this.flashtime
	}
	
	; Called at the end of the flash, on a timer
	FlashEnd(){
		this.SetButtonState(0)				; release the trigger
		this.SetSubscriptionState(0)		; unblock movement
		;~ ToolTip % "Interception ID " this.id " Flash End @ " A_TickCount
	}
	
	; Set the state of the button
	SetButtonState(state){
		Interception.SendMouseButtonEvent(this.id, this.mousebutton, state)
	}
	
	; Set state of movement subscription (blocked / unblocked)
	SetSubscriptionState(blocked){
		Interception.SubscribeMouseMoveAbsolute(this.id, blocked, this.MouseEvent.Bind(this))
	}
}
Also, note that the commented out code for your VID/PID uses the new syntax for GetDeviceId - so you should be able to get the ID of the 2nd gun :)
Last edited by evilC on 30 Mar 2018, 10:30, edited 2 times in total.
phasermaniac
Posts: 74
Joined: 09 Apr 2017, 14:05

Re: AutoHotInterception (AHI): Multi-Keyboard / Multi-Mouse support for AHK. Per-device blocking!

30 Mar 2018, 11:49

Many thanks! I updated to 2.1, and started to test your code. It is very different, not working for now, but It will take a while to me to understand. I'll give you the feedback once tested. thanks again
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: AutoHotInterception (AHI): Multi-Keyboard / Multi-Mouse support for AHK. Per-device blocking!

30 Mar 2018, 13:44

Sorry to move goalposts on you all again, I made more changes, but I think I have basically settled now on a way of doing things.

v3.0 is released!
https://github.com/evilC/AutoHotInterce ... s/tag/v3.0

Context mode is now WAY simpler, the callback is made for you.

Check out how clean and easy context mode is now:

Code: Select all

#include Lib\AutoHotInterception.ahk

AHI := new AutoHotInterception()
id1 := AHI.GetKeyboardId(0x04F2, 0x0112, 1)
cm1 := AHI.CreateContextManager(id1)
return

#if cm1.IsActive
::aaa::JACKPOT
1:: 
	ToolTip % "KEY DOWN EVENT @ " A_TickCount
	return
	
1 up::
	ToolTip % "KEY UP EVENT @ " A_TickCount
	return
#if

^Esc::
	ExitApp
In both modes, you now only need to interact with one object (The AHK wrapper), and I renamed the the example objects in the sample scripts to be shorter and less misleading (ie it's all now AHI.this and AHI.that)
I thought it best to get this out the way now, before people get too invested in (or put off by) the old way of doing things.

@Phaser - this will not impact you much.
BTW, if you wanna chat, drop by my Discord Channel
phasermaniac
Posts: 74
Joined: 09 Apr 2017, 14:05

Re: AutoHotInterception (AHI) v3.0: Multi-Keyboard / Multi-Mouse support for AHK. Per-device blocking!

30 Mar 2018, 15:20

Hi, I havent tried the 3.0 version, but was having your code working, in my test program, that only shows direct input devices, and had a major problem:
When I began testing with real games and emulators, wich uses rawinput, guns are not detected as the original devices, in mame, if I press trigger of any gun with the script running I get the click on the system mouse.
I tested the script I sent you, but with the 2.1 librarys and I'm having the same behaviour
User avatar
haichen
Posts: 631
Joined: 09 Feb 2014, 08:24

Re: AutoHotInterception (AHI) v3.0: Multi-Keyboard / Multi-Mouse support for AHK. Per-device blocking!

31 Mar 2018, 03:53

Works now! My Error was very dumb. I really thougth there must be only one dll. I thought -I don't know why- you made your own interception.dll and renamed it to AutoHotInterception.dll! That was quite nonsens, i know.

Thank you very much!
This is a damn useful work.
phasermaniac
Posts: 74
Joined: 09 Apr 2017, 14:05

Re: AutoHotInterception (AHI) v3.0: Multi-Keyboard / Multi-Mouse support for AHK. Per-device blocking!

31 Mar 2018, 04:01

Updated to 3.0, worked as before without changing the code, I only changed the referencies to AHI to simplificate and continues working as before.
But I keep having the problem I said before. I tested in another Computer, confirmed the interception.dll was the right one(64 version), but no luck.
It's strange as I see the script changes in the behaviour of the gun in its driver panel, and buttons keep working as normal, each one for his gun.
But in mame and emulators they seem are not seen as rawinput devices. (only buttons, movement is detected ok, but keep in mind I simulate the buttons but only block the movement, Im not simulating it, so seems logic in someway...
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: AutoHotInterception (AHI) v3.0: Multi-Keyboard / Multi-Mouse support for AHK. Per-device blocking!

31 Mar 2018, 13:26

Nice info Phaser, it led me on a journey.

OK, so I did a little investigation by rigging up a RawInput monitor app (Attached) which I adapted from the SharpDX samples.
It appears that (At least with my graphics tablet) that when you click, coordinates are also populated, and the absolute flag is set. A click is not just a click it seems.

I also discovered one reason why, when I try to move to 0, 0 that it is on my main monitor. Because my side monitors are not as tall, so Y=0 does not exist. Duh!

I also noticed some slightly dodgy code in the latest version that may have stopped SendMouseMoveAbsolute working properly, so I fixed that.

And finally, to try and solve your problem, I added a new function - SendMouseButtonEventAbsolute(<mouseId>, <button>, <state>, <x>, <y>)
In order to supply the correct coordinates for the click, you may well need to store current x and current y in the (currently empty) move callback.
Then, when you need to send mouse button events at specific coordinates, you have them handy.

Something like this should do it:

Code: Select all

#SingleInstance force
#Persistent
#include Lib\AutoHotInterception.ahk

global AHI := new AutoHotInterception()

id1 := AHI.GetDeviceId(true, 0xB57, 0x9091)		; Parblo Tablet
;id1 := Interception.GetDeviceId(true, 0x0B9A, 0x016A)
;id2 := Interception.GetDeviceId(true, 0x0B9A, 0x016A, 2)	; Uses new "Return 2nd instance of this VID/PID syntax

gun1 := new Gun(id1, "a")
;gun2 := new Gun(id2, "k")

return

^Esc::
	ExitApp

; ==========================================================================

/*
LightGun class for AutoHotInterception

Usage:a
myGun := new Gun(<id>, <flashkey>)
eg
myGun := new Gun(15, "{F12}")

id			The Interception ID of the Gun
flashkey	The AHK key name of the key to send for the flash
*/
Class Gun {
	; Configure these to your liking
	flashtime := 500	; The amount of time the flash lasts
	mousebutton := 1	; Which mouse button is the trigger?
	
	; Called when you create a new Gun
	__New(id, flashkey){
		this.id := id
		this.flashkey := flashkey
		
		; Create the function needed for the flash timer
		this.FlashEndFn := this.FlashEnd.Bind(this)
		
		; Subscribe to the fire button
		AHI.SubscribeMouseButton(this.id, this.mousebutton, true, this.ButtonEvent.Bind(this))
		
		; Subscribe to movement, turn block off
		this.SetSubscriptionState(0)
	}
	
	; Called when the trigger is pressed or released
	ButtonEvent(state){
		;~ ToolTip % "State: " state
		if (state){
			; Button was pressed
			this.DoFlashSequence()
		}
	}
	
	; Called when the mouse movesa
	MouseEvent(x, y){
		;~ ToolTip % "X: " x
		this.x := x, this.y := y
	}
	
	; Called when the flash seqence starts
	DoFlashSequence(){
		;~ ToolTip % "Interception ID " this.id " Flash Start @ " A_TickCount
		this.SetSubscriptionState(1)	; block movement
		Send % this.flashkey			; Send the flash key
		this.SetButtonState(1)			; press the trigger
		
		; Start the timer running to handle end of flash
		fn := this.FlashEndFn
		SetTimer, % fn, % "-" this.flashtime
	}
	
	; Called at the end of the flash, on a timer
	FlashEnd(){
		this.SetButtonState(0)				; release the trigger
		this.SetSubscriptionState(0)		; unblock movement
		;~ ToolTip % "Interception ID " this.id " Flash End @ " A_TickCount
	}
	
	; Set the state of the button
	SetButtonState(state){
		AHI.SendMouseButtonEventAbsolute(this.id, this.mousebutton, state, this.x, this.y)
	}
	
	; Set state of movement subscription (blocked / unblocked)
	SetSubscriptionState(blocked){
		AHI.SubscribeMouseMoveAbsolute(this.id, blocked, this.MouseEvent.Bind(this))
	}
}
Attachments
RawInputTrack.zip
(127.61 KiB) Downloaded 254 times
Last edited by evilC on 31 Mar 2018, 13:36, edited 1 time in total.
phasermaniac
Posts: 74
Joined: 09 Apr 2017, 14:05

Re: AutoHotInterception (AHI) v3.0: Multi-Keyboard / Multi-Mouse support for AHK. Per-device blocking!

31 Mar 2018, 14:28

Wow! First testings are working. Never thought the problem were the coordinates
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: AutoHotInterception (AHI) v3.0: Multi-Keyboard / Multi-Mouse support for AHK. Per-device blocking!

31 Mar 2018, 15:01

Nor did I, but now I know, the structure of RawInput / Interception makes more sense. I always wondered why, when in relative mode, coordinates of 0, 0 were passed.
Now it all makes sense - in absolute mode, clicks are at coordinates and the same structure is used for both modes.
I always suspected that exploring your use-case would teach me new stuff, glad I finally took the time to do it :)
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: AutoHotInterception (AHI) v3.0: Multi-Keyboard / Multi-Mouse support for AHK. Per-device blocking!

31 Mar 2018, 15:30

@phaser - I just realized the solution is not quite perfect:
https://github.com/evilC/AutoHotInterception/issues/10
TLDR: When you click, it will be currently throwing away the actual coordinates of the click. The x and y you will be using will be the coordinates just before the click.
In all likelihood, you will not notice, but it is something I would like to try and address at some point, for completeness' sake.
Once you get is all working, then I can maybe whip up some test code to explore ways of doing things to get a perfect result.
A lot of the problem I face when writing this code is testing it, especially "in anger" so to speak. So to have someone put this code to regular use and be able to help me nail the reliability is really useful.
phasermaniac
Posts: 74
Joined: 09 Apr 2017, 14:05

Re: AutoHotInterception (AHI) v3.0: Multi-Keyboard / Multi-Mouse support for AHK. Per-device blocking!

31 Mar 2018, 18:08

I tested inthearcade cabinet, with two guns, and I can say It works.
Moreover your timer methode seems way more precise than the precision sleeps I was using. Before in dark games, maybe there were like 5% of missed shots, now seems to be 0%, but I have to test it more.
The problem of getting the coordinates befpre the click is something I noticed with the ahkwrapper, but with autohotinterception I can unblock the movement whilethe simulated button is down, and this fixes some games for me (games where you reload without shoting with my guns reloaded when aiming over dark places)
I want to simulate rbutton when shooting offscreen, and its near working, but mAybe it implies what you said, I have to test more.
Many thanks for the help! Once tested ill share the code
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: AutoHotInterception (AHI) v3.0: Multi-Keyboard / Multi-Mouse support for AHK. Per-device blocking!

31 Mar 2018, 18:24

The timers are just regular AHK timers. It's entirely possible that the problem was something else - your previous code may well have not worked well with two players for example.
Glad to hear that it scaled properly to two players :)
Not sure you can detect "not pointing at screen" with the mouse relative data, I dunno - you could maybe ensure 0,0 is covered up on the screen, and thus know if you ever get a value of 0,0 that it really means "no data"?
phasermaniac
Posts: 74
Joined: 09 Apr 2017, 14:05

Re: AutoHotInterception (AHI) v3.0: Multi-Keyboard / Multi-Mouse support for AHK. Per-device blocking!

31 Mar 2018, 18:30

Yes when aiming offscreen and dark zones I get 0,0. When onscreen 0-65000, 0-65000
phasermaniac
Posts: 74
Joined: 09 Apr 2017, 14:05

Re: AutoHotInterception (AHI) v3.0: Multi-Keyboard / Multi-Mouse support for AHK. Per-device blocking!

01 Apr 2018, 03:18

For now, I have it like this, I'm having 4 main goals:

1- Delay the trigger press. As I'm using crt guns, they need the screen to be all white in the press trigger moment. So I capture the real trigger and send the flasher instead. After the "triggerdelay" I simulate the trigger, controlling its duration "triggerlenght" to be inside the flasher duration (controlled in the flasher program). WORKING

2- Block the mouse movement if the simulated trigger is not down. For some modern games where you reload only aiming offscreen without shooting. This may never work right with crt guns as reloads when over a dark place, but blocking the movement this way I prevent these undesired reloads. WORKING

3- Simulate button on offscreen shoot. This is an option my guns driver panel have, but I can't change per game, so I wanted cover it here. Some games dont reload aiming offscreen, but pressing button2. So this way I would make all those games reload offscreen too. NOT WORKING

4- Make a "direct input conversion". I thought in this to make any game (not rawinput) like flash, unity etc... playable with 2 guns:
This mode is similar to block, but remmapping the guns buttons. so gun1button1:b, gun1button2:d, gun1button3:1 and gun2button1:o, gun2button2:q, gun2button3:2.
This way, both guns will be using the same system mouse coordinates, but as the movement gets bocked but the shot instant, theoricaly, may not be a problem.
As suspected it "works" unless both players shoot at the same time, then you get some shots in the other players aiming. NOT WORKING

To make all this customizable for each game I use parameters from the commandline so you can launch the program with any game this way:
triggerDelayer.exe <triggerdelay> <triggerlenght> <"block"/"dinput"> < "offscreen"> where 3 and 4th parameters are optional and conmutable.

expl:

Code: Select all

START C:\arcade\KeyFlasher.exe C:\arcade\FLASHERS\60.ftx ; It loads a ftx where I can custom the flash duration and the flasherkeys.
START C:\arcade\TriggerDelayer.exe 30 60 dinput offscreen
START /wait C:\arcade\game.exe 
taskkill.exe /F /IM KeyFlasher.exe
taskkill.exe /F /IM TriggerDelayer.exe

Code: Select all

#SingleInstance force
#Persistent
;#NoTrayIcon
#SingleInstance, Force
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
;#Warn, All, OutputDebug
#MaxHotkeysPerInterval 255
#MaxThreads 255
SetKeyDelay -1
SetBatchLines -1
SetWorkingDir %A_ScriptDir%

Process, Priority,,High
#include <AutoHotInterception>

triggerdelay=%1%
triggerlength=%2%
;triggerdelay := 500
;triggerlength := 500
NumberOfParameters = %0%
Loop, %NumberOfParameters%
	{
	Parameter := %A_Index%
	if Parameter = offscreen
		reload = offscreen
	if Parameter = block
		tracking = block
	if Parameter = dinput
		tracking = dinput
	}
global triggerdelay := triggerdelay
global triggerlength := triggerlength
global reload := reload
global tracking := tracking
;global mx, my

AHIWrapper := new AutoHotInterception()
global AHI := AHIWrapper.GetInstance()

devices := AHIWrapper.GetDeviceList()
if (!devices.Length()){
	msgbox Device List Check failed
	ExitApp
}

;id1 := AHI.GetDeviceId(true, 0x0B9A, 0x016A)
;id2 := AHI.GetDeviceId(true, 0x0B9A, 0x016A, 2)

id1 := 12
;id2 := 13

gun1 := new Gun(id1, "a", "b", "d", "1")
;gun2 := new Gun(id2, "k", "o", "q", "2")

return
F12::
	ExitApp

; ==========================================================================
Class Gun {
	__New(id, flashkey, button1, button2, button3 ){
		this.id := id
		this.flashkey := flashkey
		this.button1 := button1
		this.button2 := button2
		this.button3 := button3
		this.triggerDownTmr := this.triggerDown.Bind(this)		
		this.triggerUpTmr := this.triggerUp.Bind(this)
		this.reloadUpTmr := this.reloadUp.Bind(this)
		AHI.SubscribeMouseButton(this.id, 0, true, this.ButtonEvent1.Bind(this))
		if	( tracking = "dinput" )
		{
			AHI.SubscribeMouseButton(this.id, 1, true, this.ButtonEvent2.Bind(this))
			AHI.SubscribeMouseButton(this.id, 2, true, this.ButtonEvent3.Bind(this))
		}
		if (tracking = "block" || tracking = "dinput" )
			this.SetMoveState(1)
		else
			this.SetMoveState(0)
	}
	ButtonEvent1(state){
		if (state)
			this.SimulateTrigger()	
	}
	ButtonEvent2(state){
		if (state)
			Send % this.button2	
	}
	ButtonEvent3(state){
		if (state)
			Send % this.button3
	}
	MouseEvent(x, y){
		;mx := x, my := y
		this.x := x, this.y := y
	}
	SimulateTrigger(){
		;~ ToolTip % "AHI ID " this.id " Flash Start @ " A_TickCount
		Send % this.flashkey

		td := this.triggerDownTmr
		SetTimer, % td, % "-" triggerdelay		
	}
	triggerDown(){
		if (tracking = "block" || tracking = "dinput"){
			this.SetMoveState(0)
			}
		if (reload = "offscreen" &&	this.x=0 && this.y=0){
			if (tracking = "dinput")
				Send % this.button2 down
			else
				this.SetReloadState(1)
			ru := this.reloadUpTmr
			SetTimer, % ru, % "-" triggerlength
			}
		else{
			if (tracking = "dinput")
					Send % this.button1 down
			else
				this.SetTriggerState(1)	
			tu := this.triggerUpTmr
			SetTimer, % tu, % "-" triggerlength
			}
	}
	triggerUp(){
		if (tracking = "block" || tracking = "dinput")
			this.SetMoveState(1)
		if (tracking = "dinput")
			Send % this.button1 up
		else
			this.SetTriggerState(0)
	}
	reloadUp(){
		if (tracking = "block" || tracking = "dinput")
			this.SetMoveState(1)
		if (tracking = "dinput")
			Send % this.button2 up
		else
			this.SetReloadState(0)
	}
	SetTriggerState(state){
		AHI.SendMouseButtonEventAbsolute(this.id, 0, state, this.x, this.y)
		;AHI.SendMouseButtonEvent(this.id, 0, state)
	}
	SetReloadState(state){
		AHI.SendMouseButtonEventAbsolute(this.id, 1, state, this.x, this.y)
		AHI.SendMouseButtonEvent(this.id, 1, state)
	}
	SetMoveState(blocked){
		AHI.SubscribeMouseMoveAbsolute(this.id, blocked, this.MouseEvent.Bind(this))
	}
}
ZachL
Posts: 3
Joined: 01 Apr 2018, 09:59

Re: AutoHotInterception (AHI) v3.0: Multi-Keyboard / Multi-Mouse support for AHK. Per-device blocking!

01 Apr 2018, 12:44

Wow! This is pretty awesome, thanks for making this.So you seamed interested in peoples use cases so I though I'd share mine. I wanted to disable hovering on my tablet so I could play fps games with it easier. I was able to get the behavior I wanted with regular autohotkey, but the game detected mouse movement at a lower level than autohotkey, so it didn't work. AHI worked perfectly, and was very easy to implement (good job on that). Here's my code:

Code: Select all

#SingleInstance force
#Persistent
#include Lib\AutoHotInterception.ahk

AHI := new AutoHotInterception()
notHovering = 0

AHI.SubscribeMouseMoveRelative(12, true, Func("MouseMoveEvent"))
AHI.SubscribeMouseButton(12, 0, true, Func("MouseButtonEvent"))
return

MouseMoveEvent(x, y)
{
	global notHovering
	global AHI
	if (notHovering == 1)
	{
		AHI.SendMouseMove(12, x, y)
	}
}

MouseButtonEvent(state)
{
	global notHovering
	notHovering = % state
}

^Esc::
	ExitApp
And I can see myself using this for many other things in the future too. like rebinding keys for games that block window's keyboard and mouse dll calls or perhaps using a numpad for extra keys.

I also want to report a couple of bugs I found.

First the monitor example doesn't work perfectly. I attached a screenshot below. For reference I have one keyboard, one trackball, and one graphics tablet attached. As you can see it detects my keyboard at four different ids (note: only one actually works), though I imagine this is a problem on intercepts end not yours (perhaps caused by unplugging and replugging?) Also while 2 Unique mice seem to show up only one works (my trackball), the other two ids don't monitor my trackball or my tablet; however, my tablet, while not showing up, is detected by interception at id 12. Interestingly it has 2 ids actually, 12 when it is in relative mode and 11 in absolute mode (I change mode using the driver). I found this by using this script:

Code: Select all

#SingleInstance force
#Persistent
#include Lib\AutoHotInterception.ahk

global AHI := new AutoHotInterception()

cm1 := AHI.CreateContextManager(1)
cm2 := AHI.CreateContextManager(2)
cm3 := AHI.CreateContextManager(3)
cm4 := AHI.CreateContextManager(4)
cm5 := AHI.CreateContextManager(5)
cm6 := AHI.CreateContextManager(6)
cm7 := AHI.CreateContextManager(7)
cm8 := AHI.CreateContextManager(8)
cm9 := AHI.CreateContextManager(9)
cm10 := AHI.CreateContextManager(10)
cm11 := AHI.CreateContextManager(11)
cm12 := AHI.CreateContextManager(12)
cm13 := AHI.CreateContextManager(13)
cm14 := AHI.CreateContextManager(14)
cm15 := AHI.CreateContextManager(15)
cm16 := AHI.CreateContextManager(16)
cm17 := AHI.CreateContextManager(17)
cm18 := AHI.CreateContextManager(18)
cm19 := AHI.CreateContextManager(19)
cm20 := AHI.CreateContextManager(20)
return

#if cm1.IsActive
e:: 
	ToolTip "ID=1" 
	return
#if
#if cm2.IsActive
e:: 
	ToolTip "ID=2" 
	return
#if
#if cm3.IsActive
e:: 
	ToolTip "ID=3" 
	return
#if
#if cm4.IsActive
e:: 
	ToolTip "ID=4" 
	return
#if
#if cm5.IsActive
e:: 
	ToolTip "ID=5" 
	return
#if
#if cm6.IsActive
e:: 
	ToolTip "ID=6" 
	return
#if
#if cm7.IsActive
e:: 
	ToolTip "ID=7" 
	return
#if
#if cm8.IsActive
e:: 
	ToolTip "ID=8" 
	return
#if
#if cm9.IsActive
e:: 
	ToolTip "ID=9" 
	return
#if
#if cm10.IsActive
e:: 
	ToolTip "ID=10" 
	return
#if
#if cm11.IsActive
LButton:: 
	ToolTip "ID=11" 
	return
#if
#if cm12.IsActive
LButton:: 
	ToolTip "ID=12" 
	return
#if
#if cm13.IsActive
LButton:: 
	ToolTip "ID=13" 
	return
#if
#if cm14.IsActive
LButton:: 
	ToolTip "ID=14" 
	return
#if
#if cm15.IsActive
LButton:: 
	ToolTip "ID=15" 
	return
#if
#if cm16.IsActive
LButton:: 
	ToolTip "ID=16" 
	return
#if
#if cm17.IsActive
LButton:: 
	ToolTip "ID=17" 
	return
#if
#if cm18.IsActive
LButton:: 
	ToolTip "ID=18" 
	return
#if
#if cm19.IsActive
LButton:: 
	ToolTip "ID=19" 
	return
#if
#if cm20.IsActive
LButton:: 
	ToolTip "ID=20" 
	return
#if
I also tried using GetDeviceList() with the same results (as a note the isMouse property is -1 for my detected mice). So perhaps your detection of devices doesn't work very well. Maybe try to detect them by seeing if you can send key presses or mouse movements from them? (IDK I'm not familiar with how interception handles it). Another thing to note is that using my script the tooltip only pops up in about 1 in 10 or 20 key/button presses (though I think this would be better with subscription mode). Also you may have noticed that in my first script I hard coded the id rather than using the VID/PID. I have done this in all my scripts because my devices seem to have multiple ids even though only one actually works (e.g. using the get id from VID/PID function for my keyboard returns 5, even though I need 8.)

Another thing is that SendMouseMoveAbsolute() doesn't seem to work properly. I wrote this script to test it

Code: Select all

CoordMode, Mouse, Screen

p = 100
while (p<30000)
{
	AHI.SendMouseMoveAbsoulte(12, p, p)
	MouseGetPos, x, y
	Tooltip % p/x
	p = % p+100
	sleep, 50
}
From this I was able to determine that, not only do the x & y coordinates for the function not correspond to pixels as they are way to big (30000 was less than half of my 720p screen), but that they also are not linear, as the value of p/x changed (and not in a linear faction so it isn't exponential either) as the mouse moved across the screen (also I tried p/y, which gave me different values seaming to mean that x and y scale differently.)

This isn't so much a bug, but something that I am curious about. From my testing it seems that AHI intercepts input before it even makes it to the drivers (which is really cool). there are some custom buttons on my tablet and mouse which can be remapped by their drivers, but that I couldn't figure out how to intercept. Is this a limit of interception, or do you think these could be detected in the future? Also I tried a keyboard with custom buttons and media keys and none of these keys seemed to work either (didn't show up in monitor). Media keys do have scan codes, so why wouldn't they work?

Oh BTW your documentation states that mice ids go up to 21, but I tried use 21 and it threw and error.

I used version 3.1 (at least I think so, maybe consider putting the version number in the help file).
Attachments
AHIMonitorCapture.PNG
AHIMonitorCapture.PNG (14.42 KiB) Viewed 10871 times
phasermaniac
Posts: 74
Joined: 09 Apr 2017, 14:05

Re: AutoHotInterception (AHI) v3.0: Multi-Keyboard / Multi-Mouse support for AHK. Per-device blocking!

01 Apr 2018, 13:11

Hi ZachL from what I've seen absolute coordinates are always 0-65000, they dont seem to have nothing to do with resolution, but I thought they would grow linearly...
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: AutoHotInterception (AHI) v3.0: Multi-Keyboard / Multi-Mouse support for AHK. Per-device blocking!

01 Apr 2018, 14:12

@Phaser - I will try to review your code in the next day or two, I am taking a little bit of a break from coding today (At least until I get bored of KSP)

@ZachL - Glad you like the tool - a large part of why I am doing this is as research for a larger project, which aims to try and remap anything to anything, so I like to know of new and interesting use-cases to see if what I have planned could handle it.
The id 21 issue was an error in the docs, max is 20. This has now been corrected.

Regarding multiple vids/pids:
Many devices have multiple vids/pids.
I have heard of keyboards that have 4 vids/pids.
As in 4 actual devices in device manager.
I am still not 100% sure if Interception is doing a good enough job of reporting what is a keyboard and what is a mouse, but it is out of my control (For now, we are thinking of writing our own version of Interception).

Regarding absolute mode coordinates:
As Phaser mentions, these are 0..65535
How could a graphics tablet possibly know what resolution your monitor is ;) Bear in mind this is all happening at a driver level. The keyboard driver knows nothing about monitors.
Also what if you have multiple monitors?
In windows, there is one 65545 square coordinate space that maps to all monitors.

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 104 guests