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

Post your working scripts, libraries and tools
Sdentin Heyatszhem
Posts: 3
Joined: 16 Jan 2019, 17:42

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

30 Jan 2019, 08:11

evilC wrote:
18 Jan 2019, 08:14
@Sdentin Heyatszhem that behaviour would be expected for devices which are not regular USB.
PS/2 devices, and built-in keyboards for laptops etc will quite possibly fall into this category

Looking into it, I don't see how this is context mode specific
The "Could not get Keyboard with VID 0x000, PID 0x000, Instance 1" message would be thrown by a line like keyboardId := AHI.GetKeyboardId(0x0, 0x0), which would be common to both Context and Subscription mode
Yeah it was caused by my built-in keyboard, whoops. Used an external keyboard and everything is working as intended.
With the example I gave, I wasn't trying to pin it on Context Mode, I was just trying to include all details to make sure there wasn't anything I missed.

Unrelated to the above (and probably late for a response), the issue of keyboard/mouse devices being locked up is likely related to this:
https://github.com/oblitum/Interception/issues/25

From my own experience, when I set my laptop to sleep, I also disconnect my mouse (which I later reconnect when waking the laptop). This repeated behaviour leads to the mouse being ignored by Interception at some point because the HID is too high (the HID increases with each subsequent device reconnect). So I would surmise that sleep is only coincidental to the problem, assuming that the other person's situation was like my own.
User avatar
evilC
Posts: 4730
Joined: 27 Feb 2014, 12:30

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

30 Jan 2019, 08:24

@ppapkor - I don't know how it knows, the input comes *from the driver*, which is exactly how it would look for real input.
I have heard reports of some games being able to detect that Interception is installed, and refuse to run, but I have not heard about any games being able to identify a specific keystroke as being synthetic (Because to all intenteds and purposes, it isn't)
I take it that you are using AHI.GetKeyboardId() to get the ID of your keyboard? I think ID 1 is a "default" keyboard that I suppose could maybe be interpreted as synthetic?
User avatar
evilC
Posts: 4730
Joined: 27 Feb 2014, 12:30

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

30 Jan 2019, 08:25

@Sdentin - good catch regarding the devices stopping working after sleep.
I will look into it and see if there is anything I can do - maybe I can detect the sleep and re-enumerate the devices or something, thus stopping it from incrementing the device IDs
Sdentin Heyatszhem
Posts: 3
Joined: 16 Jan 2019, 17:42

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

31 Jan 2019, 21:40

I've run into another slight issue on my end: in the following code, I've essentially turned a side button on my mouse into a left click button. When I use this, however, each press sends two left clicks instead of one. A workaround I used was to simply add

Code: Select all

if (state == 1) { ... }
to the callback function which makes it send only one left click as intended. I'm not sure what I'm doing wrongly, or if this is intended behaviour.
User avatar
evilC
Posts: 4730
Joined: 27 Feb 2014, 12:30

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

01 Feb 2019, 05:11

state holds the state of the input - 1 for pressed, 0 for released.
Your code as it stands will press LMB when you press XB2, and never, ever release LMB.
Also, mouseId is not in scope in your function
To press LMB when you press XB2, and release LMB when you release XB2:

Code: Select all

testFunction(state){
    global mouseID
    AHI.SendMouseButtonEvent(mouseID, 0, state)
}
To press and release LMB when you press XB2, and do nothing when you release XB2:

Code: Select all

testFunction(state){
    global mouseID
    if (!state)
        return
    AHI.SendMouseButtonEvent(mouseID, 0, 1)
    Sleep 50
    AHI.SendMouseButtonEvent(mouseID, 0, 0)
}
User avatar
evilC
Posts: 4730
Joined: 27 Feb 2014, 12:30

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

10 Feb 2019, 09:47

Version 0.3.7 has been released!
https://github.com/evilC/AutoHotInterception/releases

A couple of bug fixes, but the big one is that I added support for Unsubscribing

This example shows a hotkey that is only active and blocking while Notepad is the active app:

Code: Select all

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

; Demonstrates Subscribe / Unsubscribe (Turn on/off block) dependent on active window
; Block is active in Notepad, inactive otherwise

AHI := new AutoHotInterception()

keyboardId := AHI.GetKeyboardId(0x04F2, 0x0112)

SetTimer, WatchWin, -0
return

KeyEvent(state){
	ToolTip % "State: " state
}

DoSub(state){
	global AHI, keyboardId
	if (state){
		AHI.SubscribeKey(keyboardId, GetKeySC("1"), true, Func("KeyEvent"))
	} else {
		AHI.UnsubscribeKey(keyboardId, GetKeySC("1"))
	}
}

WatchWin:
	Loop {
		WinWaitActive, ahk_class Notepad
		DoSub(true)
		WinWaitNotActive, ahk_class Notepad
		DoSub(false)
	}
	return

^Esc::
	ExitApp
SplatCatAU
Posts: 14
Joined: 27 Feb 2019, 06:42

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

27 Feb 2019, 07:49

Its been a while since I last poked around on the AHK forums, so long that I had to create a new account.
Anyway, I have been looking at all the work you (evilC) have been putting in, and I like what I see.
I have been knee deep in IT for just over three decades but I am no coder, most code does my head in, but I am able to nut out and adapt other peoples work to do what I need, mostly.
Recently I upgraded one of my gaming peripherals (Belkins Nostromo N52 to the new Razer Tartarus V2) to discover the supporting beta software has an always online and logged in requirement (to function as advertised) that I don't agree with.
As I make use of a utility (Xpadder) to configure the more advanced gaming/productivity actions, all I needed was something to configure the device keys/buttons as joystick buttons.
And here I am :)
The code below is what I quickly knocked up to allow me to uninstall Synapse3 and just use the device as I intended.
I was hoping that someone would critique and/or make it better, as well as sharing with others who are looking for a similar and simple solution.
I call it "Synapse3_Replacement.ahk"

Code: Select all

#SingleInstance force
#Persistent
#include <AutoHotInterception>
#include <CvJoyInterface>

SetBatchLines, -1
ListLines, Off

; Create an object from vJoy Interface Class.
global vJoyInterface := new CvJoyInterface()
global myStick := vJoyInterface.Devices[5]
global AHI := new AutoHotInterception()
global keyboardId := AHI.GetKeyboardId(0x1532, 0x022B)
global MouseId := AHI.GetMouseId(0x1532, 0x022B)


; Was vJoy installed and the DLL Loaded?
if (!vJoyInterface.vJoyEnabled()){
	; Show log of what happened
	Msgbox % vJoyInterface.LoadLibraryLog
	ExitApp
}

AHI.SubscribeKey(keyboardId, GetKeySC("1"), true, Func("KeyEvent01"))
AHI.SubscribeKey(keyboardId, GetKeySC("2"), true, Func("KeyEvent02"))
AHI.SubscribeKey(keyboardId, GetKeySC("3"), true, Func("KeyEvent03"))
AHI.SubscribeKey(keyboardId, GetKeySC("4"), true, Func("KeyEvent04"))
AHI.SubscribeKey(keyboardId, GetKeySC("5"), true, Func("KeyEvent05"))

AHI.SubscribeKey(keyboardId, GetKeySC("Tab"), true, Func("KeyEvent06"))
AHI.SubscribeKey(keyboardId, GetKeySC("q"), true, Func("KeyEvent07"))
AHI.SubscribeKey(keyboardId, GetKeySC("w"), true, Func("KeyEvent08"))
AHI.SubscribeKey(keyboardId, GetKeySC("e"), true, Func("KeyEvent09"))
AHI.SubscribeKey(keyboardId, GetKeySC("r"), true, Func("KeyEvent10"))

AHI.SubscribeKey(keyboardId, GetKeySC("CapsLock"), true, Func("KeyEvent11"))
AHI.SubscribeKey(keyboardId, GetKeySC("a"), true, Func("KeyEvent12"))
AHI.SubscribeKey(keyboardId, GetKeySC("s"), true, Func("KeyEvent13"))
AHI.SubscribeKey(keyboardId, GetKeySC("d"), true, Func("KeyEvent14"))
AHI.SubscribeKey(keyboardId, GetKeySC("f"), true, Func("KeyEvent15"))

AHI.SubscribeKey(keyboardId, GetKeySC("LShift"), true, Func("KeyEvent16"))
AHI.SubscribeKey(keyboardId, GetKeySC("z"), true, Func("KeyEvent17"))
AHI.SubscribeKey(keyboardId, GetKeySC("x"), true, Func("KeyEvent18"))
AHI.SubscribeKey(keyboardId, GetKeySC("c"), true, Func("KeyEvent19"))

AHI.SubscribeKey(keyboardId, GetKeySC("Space"), true, Func("KeyEvent20"))
AHI.SubscribeKey(keyboardId, GetKeySC("LAlt"), true, Func("KeyEvent21"))

AHI.SubscribeKey(keyboardId, GetKeySC("Left"), true, Func("KeyEvent22"))
AHI.SubscribeKey(keyboardId, GetKeySC("Right"), true, Func("KeyEvent23"))
AHI.SubscribeKey(keyboardId, GetKeySC("Up"), true, Func("KeyEvent24"))
AHI.SubscribeKey(keyboardId, GetKeySC("Down"), true, Func("KeyEvent25"))

AHI.SubscribeMouseButton(MouseId, GetKeySC("1"), true, Func("KeyEvent26")) ;mouse wheel button
;AHI.SubscribeMouseButton(MouseId, GetKeySC("4"), true, Func("KeyEvent27")) ;mouse wheel
;AHI.SubscribeMouseButton(MouseId, GetKeySC("5"), true, Func("KeyEvent28")) ;mouse wheel

return

KeyEvent01(state){
	myStick.SetBtn(state,1)
}
KeyEvent02(state){
	myStick.SetBtn(state,2)
}
KeyEvent03(state){
	myStick.SetBtn(state,3)
}
KeyEvent04(state){
	myStick.SetBtn(state,4)
}
KeyEvent05(state){
	myStick.SetBtn(state,5)
}
KeyEvent06(state){
	myStick.SetBtn(state,6)
}
KeyEvent07(state){
	myStick.SetBtn(state,7)
}
KeyEvent08(state){
	myStick.SetBtn(state,8)
}
KeyEvent09(state){
	myStick.SetBtn(state,9)
}
KeyEvent10(state){
	myStick.SetBtn(state,10)
}
KeyEvent11(state){
	myStick.SetBtn(state,11)
}
KeyEvent12(state){
	myStick.SetBtn(state,12)
}
KeyEvent13(state){
	myStick.SetBtn(state,13)
}
KeyEvent14(state){
	myStick.SetBtn(state,14)
}
KeyEvent15(state){
	myStick.SetBtn(state,15)
}
KeyEvent16(state){
	myStick.SetBtn(state,16)
}
KeyEvent17(state){
	myStick.SetBtn(state,17)
}
KeyEvent18(state){
	myStick.SetBtn(state,18)
}
KeyEvent19(state){
	myStick.SetBtn(state,19)
}
KeyEvent20(state){
	myStick.SetBtn(state,20)
}
KeyEvent21(state){
	myStick.SetBtn(state,21)
}
KeyEvent22(state){
	myStick.SetBtn(state,22)
}
KeyEvent23(state){
	myStick.SetBtn(state,23)
}
KeyEvent24(state){
	myStick.SetBtn(state,24)
}
KeyEvent25(state){
	myStick.SetBtn(state,25)
}
KeyEvent26(state){
	myStick.SetBtn(state,26)
}
;KeyEvent27(state){
;	myStick.SetDiscPov(state,1)
;}
;KeyEvent28(state){
;	myStick.SetAxisByIndex(state,1)
;}

^Esc::ExitApp

If anyone has a solution for the mouse wheel on the Tartarus V2 I would be grateful, as what I attempted would not work.
Also, I was thinking of using your (evilC) TapHoldManager (to make use of multiple vJoysticks), but every time I tried something I was rewarded with an increase in my bouncing 7 day old headache (I've tried to get it fixed but no one is willing to cut it off).
Anyway, thanks for your hard work. I really appreciate it.

Splat
SplatCatAU
Posts: 14
Joined: 27 Feb 2019, 06:42

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

27 Feb 2019, 22:25

I've noticed that some vjoystick buttons are getting stuck on the down state, I gather that's because my script works on a change of state rather than being polled continuously, correct?
User avatar
evilC
Posts: 4730
Joined: 27 Feb 2014, 12:30

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

28 Feb 2019, 05:30

It shouldn't be.
BTW, you only need one KeyEvent function:

Code: Select all

AHI.SubscribeKey(keyboardId, GetKeySC("1"), true, Func("KeyEvent").Bind(1))
AHI.SubscribeKey(keyboardId, GetKeySC("2"), true, Func("KeyEvent").Bind(2))

...

KeyEvent(btn, state){
	myStick.SetBtn(state, btn)
}
One thing that might be going wrong is that you are not filtering key down events. When you hold a key, KeyEvent will be repeatedly called with state of 1.
You maybe want something like this:

Code: Select all

KeyEvent(btn, state){
	static btnStates := {}
	if (btnStates[btn])
		return ; Filter repeats
	btnStates[btn] := state
	myStick.SetBtn(state, btn)
}
SplatCatAU
Posts: 14
Joined: 27 Feb 2019, 06:42

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

28 Feb 2019, 07:47

Only need one KeyEvent...I see that now. lol
Thanks muchly for that.
And about vjoystick buttons getting stuck, it only happened intermittently and every time on the very first button press after starting the script running.
I tried adding what you suggested and they all stayed pressed, so I simply added a loop to check.
I made the mouse wheel in to a couple of vjoystick buttons as well as adding the ability to select it as the SL0 axis.
I really dont know how to go about adding TapHoldManager, but I've decided to tackle that another day.

Below is a copy of the WIP script for Synapse3_Replacement.ahk

Code: Select all

;Synapse3_Replacement.ahk
;This is a replacement for Razers Synapse3 beta software for the Tartarus V2.
;This version will set each key/button/wheel as a virtual joystick button (28 currently).
;With minor adjustments it shouldn't be too hard to make it work with other keypad (half-a-keyboard) devices, incl full keyboards.
;Designed to be used in conjunction with advanced configuration software utilities (Xpadder or Pinnacle Game Profiler, etc).

#SingleInstance force
#Persistent
#include <AutoHotInterception>
#include <CvJoyInterface>

SetBatchLines, -1
ListLines, Off

; Create an object from vJoy Interface Class.
global vJoyInterface := new CvJoyInterface()
global myStick := vJoyInterface.Devices[5]
global AHI := new AutoHotInterception()
;Use Monitor.ahk by evilC to determine device VID and PID for below IDs
global keyboardId := AHI.GetKeyboardId(0x1532, 0x022B)
global MouseId := AHI.GetMouseId(0x1532, 0x022B)
global newstate := 16384

SetTimer, PollWatch, -0

; Was vJoy installed and the DLL Loaded?
if (!vJoyInterface.vJoyEnabled()){
	; Show log of what happened
	Msgbox % vJoyInterface.LoadLibraryLog
	ExitApp
}

AHI.SubscribeKey(keyboardId, GetKeySC("1"), true, Func("KeyEvent").Bind(1))
AHI.SubscribeKey(keyboardId, GetKeySC("2"), true, Func("KeyEvent").Bind(2))
AHI.SubscribeKey(keyboardId, GetKeySC("3"), true, Func("KeyEvent").Bind(3))
AHI.SubscribeKey(keyboardId, GetKeySC("4"), true, Func("KeyEvent").Bind(4))
AHI.SubscribeKey(keyboardId, GetKeySC("5"), true, Func("KeyEvent").Bind(5))

AHI.SubscribeKey(keyboardId, GetKeySC("Tab"), true, Func("KeyEvent").Bind(6))
AHI.SubscribeKey(keyboardId, GetKeySC("q"), true, Func("KeyEvent").Bind(7))
AHI.SubscribeKey(keyboardId, GetKeySC("w"), true, Func("KeyEvent").Bind(8))
AHI.SubscribeKey(keyboardId, GetKeySC("e"), true, Func("KeyEvent").Bind(9))
AHI.SubscribeKey(keyboardId, GetKeySC("r"), true, Func("KeyEvent").Bind(10))

AHI.SubscribeKey(keyboardId, GetKeySC("CapsLock"), true, Func("KeyEvent").Bind(11))
AHI.SubscribeKey(keyboardId, GetKeySC("a"), true, Func("KeyEvent").Bind(12))
AHI.SubscribeKey(keyboardId, GetKeySC("s"), true, Func("KeyEvent").Bind(13))
AHI.SubscribeKey(keyboardId, GetKeySC("d"), true, Func("KeyEvent").Bind(14))
AHI.SubscribeKey(keyboardId, GetKeySC("f"), true, Func("KeyEvent").Bind(15))

AHI.SubscribeKey(keyboardId, GetKeySC("LShift"), true, Func("KeyEvent").Bind(16))
AHI.SubscribeKey(keyboardId, GetKeySC("z"), true, Func("KeyEvent").Bind(17))
AHI.SubscribeKey(keyboardId, GetKeySC("x"), true, Func("KeyEvent").Bind(18))
AHI.SubscribeKey(keyboardId, GetKeySC("c"), true, Func("KeyEvent").Bind(19))

AHI.SubscribeKey(keyboardId, GetKeySC("Space"), true, Func("KeyEvent").Bind(20))
AHI.SubscribeKey(keyboardId, GetKeySC("LAlt"), true, Func("KeyEvent").Bind(21))

AHI.SubscribeKey(keyboardId, GetKeySC("Left"), true, Func("KeyEvent").Bind(22))
AHI.SubscribeKey(keyboardId, GetKeySC("Right"), true, Func("KeyEvent").Bind(23))
AHI.SubscribeKey(keyboardId, GetKeySC("Up"), true, Func("KeyEvent").Bind(24))
AHI.SubscribeKey(keyboardId, GetKeySC("Down"), true, Func("KeyEvent").Bind(25))

AHI.SubscribeMouseButton(MouseId, GetKeySC("1"), true, Func("MouseEvent").Bind(26))
AHI.SubscribeMouseButton(MouseId, GetKeySC("4"), true, Func("WheelEvent1"))
;AHI.SubscribeMouseButton(MouseId, GetKeySC("4"), true, Func("WheelEvent2"))
;Choose WheelEvent1 for vjoy button press and remark the other.
;Choose WheelEvent2 for vjoy sl0 axis and remark the other.

return

KeyEvent(btn, state){
	myStick.SetBtn(state, btn)
}
MouseEvent(btn, state){
	myStick.SetBtn(state, btn)
}
WheelEvent1(state){
	if state = 1
		myStick.SetBtn(1, 27)
	if state = -1
		myStick.SetBtn(1, 28)
	sleep 50
	myStick.SetBtn(0, 27)
	myStick.SetBtn(0, 28)
}
WheelEvent2(state){
	if newstate > 32767
		newstate = 32768
	if newstate < 1
		newstate = 0
	newstate = % newstate + (state*1000)
	;ToolTip % "State: " state " NewState: " newstate 
	myStick.SetAxisByIndex(newstate, 7)
}

PollWatch:
	Loop ,26 {
		myStick.SetBtn(state,A_Index)
	}
	return


^Esc::
    ExitApp


Thanks, again.

Splat
Last edited by SplatCatAU on 03 Mar 2019, 18:00, edited 2 times in total.
SplatCatAU
Posts: 14
Joined: 27 Feb 2019, 06:42

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

01 Mar 2019, 20:56

I have been trying to nut this out for a bit now with no success.
The plan is to have vJoyInterface.Devices[5] for single Tap, and vJoyInterface.Devices[6] for Hold or multi-tap.
This should get around any 32 button limits with hardware/software/operating systems.
The vJoy devices can use any free IDs (5 & 6 are the first free ones on my system).
The things I do know require adding;

TapHoldManager library

Code: Select all

#include <InterceptionTapHold>
Set to multi stick mode

Code: Select all

vJoyInterface.SingleStickMode := 0
A TapHold manager

Code: Select all

global kb1 := new InterceptionTapHold(0x1532, 0x022B)
Addition of a second vJoy device

Code: Select all

global myStick2 := vJoyInterface.Devices[6]
Events to direct to the second vJoy device. This may not be required depending on TapHoldManager usage/syntax/variables etc.

Code: Select all

KeyEvent2(btn, state){
	myStick2.SetBtn(state, btn)
}
The things I don't know;
I believe I need to add keys and callback functions but I just cant figure out the required structure/syntax to work correctly with AHK-CvJoyInterface and AutoHotInterception libraries.
I would appreciate any help, and I will not be offended if you treat me like the simpleton I feel I am.

Splat
SplatCatAU
Posts: 14
Joined: 27 Feb 2019, 06:42

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

02 Mar 2019, 15:25

I'm positive, actually.
I am referring to vJoyInterface.Devices[6], not the windows ID for vJoy (1234:BEAD).
I use a client/server utility called LEA Extended Input in conjunction with a Android tablet and vJoy on the PC to create and use multiple varied control sets with unlimited controls, as long as they fit within the sets and on the tablets screen.
I also have a few physical controllers (flight yoke/pedals, joystick, hotas, gamepad, steering wheel/pedals) and half-a-keyboards that I like to use with my other controllers, even though physical have no impact on vJoy IDs.
Each vJoystick (and physical device) is also configured in different ways using Xpadder (believed to have a 32 button limit per device), allowing for some complicated and advanced setups per individual joystick/game/app. Collectively, you can setup a 747 cockpit with more than enough controls, complete with unique control bindings.
Generally, not all are used at the same time but they are able to be if it becomes needed. Hence the reserved vJoy devices.
Touch screen control for flight sims that have many control bindings is just the "bee's knees".
To have 3 or 4 touch screens at once is plain luxury.
SplatCatAU
Posts: 14
Joined: 27 Feb 2019, 06:42

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

03 Mar 2019, 19:08

Got around to using, but actually testing, my previous script in action with game play.
It was again confirmed that I am no "coder", lucky if I can copy and paste with any proficiency it seems.
So I had another look at your (evilC) suggestion for keyevent and changed the "if" statement to a "not equal", and it works (in game) like a charm.
And now I am going to take my slightly older headache in to the bush and see if we cant loose each other. Any bets on which one returns?

The below should now be a complete and working version of Synapse3_Replacement_V1.ahk as it was intended.
Please, anyone, feel free to adapt and change it to your needs.

Code: Select all

;Synapse3_ReplacementV1.ahk
;This is a replacement for Razers Synapse3 beta software and driver for the Tartarus V2.
;Also can replace the original Belkin drivers and software for the Nostromo N50 & N52.
;Successfully tested with a small number of generic half-a-keyboards (gaming keypads).
;With minor adjustments it shouldn't be too hard to make it work with other keypad (half-a-keyboard) devices, even incl full keyboards.
;This version will set each key/button/wheel as a virtual joystick button (28 currently).
;Designed to be used in conjunction with advanced configuration software utilities (Xpadder or Pinnacle Game Profiler, etc).
;Do not use this script if you are using UCR, Universal Control Remapper by evilC.
;Special thanks to evilC for the additional libraries, and the AutoHotkey team and community.
;This script requires AutoHotInterception and CvJoyInterface libraries, and Shaul's vJoy. Follow install instructions at evilCs github.

#SingleInstance force
#Persistent
#HotkeyInterval 2000
#MaxHotkeysPerInterval 200
#MaxThreadsBuffer on
#include <AutoHotInterception>
#include <CvJoyInterface>

SetBatchLines, -1
ListLines, Off

; Create an object from vJoy Interface Class.
global vJoyInterface := new CvJoyInterface()
global myStick := vJoyInterface.Devices[5]
global AHI := new AutoHotInterception()
;Use Monitor.ahk by evilC to determine device VID and PID for below IDs
global keyboardId := AHI.GetKeyboardId(0x1532, 0x022B)
global MouseId := AHI.GetMouseId(0x1532, 0x022B)
global newstate := 16384

;SetTimer, PollWatch, -0	;not currently required

; Was vJoy installed and the DLL Loaded?
if (!vJoyInterface.vJoyEnabled()){
	; Show log of what happened
	Msgbox % vJoyInterface.LoadLibraryLog
	ExitApp
}

AHI.SubscribeKey(keyboardId, GetKeySC("1"), true, Func("KeyEvent").Bind(1))
AHI.SubscribeKey(keyboardId, GetKeySC("2"), true, Func("KeyEvent").Bind(2))
AHI.SubscribeKey(keyboardId, GetKeySC("3"), true, Func("KeyEvent").Bind(3))
AHI.SubscribeKey(keyboardId, GetKeySC("4"), true, Func("KeyEvent").Bind(4))
AHI.SubscribeKey(keyboardId, GetKeySC("5"), true, Func("KeyEvent").Bind(5))

AHI.SubscribeKey(keyboardId, GetKeySC("Tab"), true, Func("KeyEvent").Bind(6))
AHI.SubscribeKey(keyboardId, GetKeySC("q"), true, Func("KeyEvent").Bind(7))
AHI.SubscribeKey(keyboardId, GetKeySC("w"), true, Func("KeyEvent").Bind(8))
AHI.SubscribeKey(keyboardId, GetKeySC("e"), true, Func("KeyEvent").Bind(9))
AHI.SubscribeKey(keyboardId, GetKeySC("r"), true, Func("KeyEvent").Bind(10))

AHI.SubscribeKey(keyboardId, GetKeySC("CapsLock"), true, Func("KeyEvent").Bind(11))
AHI.SubscribeKey(keyboardId, GetKeySC("a"), true, Func("KeyEvent").Bind(12))
AHI.SubscribeKey(keyboardId, GetKeySC("s"), true, Func("KeyEvent").Bind(13))
AHI.SubscribeKey(keyboardId, GetKeySC("d"), true, Func("KeyEvent").Bind(14))
AHI.SubscribeKey(keyboardId, GetKeySC("f"), true, Func("KeyEvent").Bind(15))

AHI.SubscribeKey(keyboardId, GetKeySC("LShift"), true, Func("KeyEvent").Bind(16))
AHI.SubscribeKey(keyboardId, GetKeySC("z"), true, Func("KeyEvent").Bind(17))
AHI.SubscribeKey(keyboardId, GetKeySC("x"), true, Func("KeyEvent").Bind(18))
AHI.SubscribeKey(keyboardId, GetKeySC("c"), true, Func("KeyEvent").Bind(19))

AHI.SubscribeKey(keyboardId, GetKeySC("Space"), true, Func("KeyEvent").Bind(20))
AHI.SubscribeKey(keyboardId, GetKeySC("LAlt"), true, Func("KeyEvent").Bind(21))

AHI.SubscribeKey(keyboardId, GetKeySC("Left"), true, Func("KeyEvent").Bind(22))
AHI.SubscribeKey(keyboardId, GetKeySC("Right"), true, Func("KeyEvent").Bind(23))
AHI.SubscribeKey(keyboardId, GetKeySC("Up"), true, Func("KeyEvent").Bind(24))
AHI.SubscribeKey(keyboardId, GetKeySC("Down"), true, Func("KeyEvent").Bind(25))

AHI.SubscribeMouseButton(MouseId, GetKeySC("1"), true, Func("MouseEvent").Bind(26))
AHI.SubscribeMouseButton(MouseId, GetKeySC("4"), true, Func("WheelEvent1"))
;AHI.SubscribeMouseButton(MouseId, GetKeySC("4"), true, Func("WheelEvent2"))
;Choose WheelEvent1 for vjoy button press and remark the other.
;Choose WheelEvent2 for vjoy sl0 axis and remark the other.

return

KeyEvent(btn, state){
	static btnStates := {}
	if (btnStates![btn])
		return ; Filter repeats
	btnStates[btn] := state
	myStick.SetBtn(state, btn)
}
MouseEvent(btn, state){
	static btnStates := {}
	if (btnStates![btn])
		return ; Filter repeats
	btnStates[btn] := state
	myStick.SetBtn(state, btn)
}
WheelEvent1(state){
	if state = 1
		myStick.SetBtn(1, 27)
	if state = -1
		myStick.SetBtn(1, 28)
	sleep 50
	myStick.SetBtn(0, 27)
	myStick.SetBtn(0, 28)
}
WheelEvent2(state){
	if newstate > 32767
		newstate = 32768
	if newstate < 1
		newstate = 0
	newstate = % newstate + (state*1000)
	myStick.SetAxisByIndex(newstate, 7)
}

PollWatch:
	Loop ,26 {
		myStick.SetBtn(state,A_Index)
	}
	return


^Esc::
    ExitApp
I added TapHoldManager to my little project. It allows for 32 joystick buttons and the slider axis, with the top row of five keys used for single and double-tap, the "W" key is also single and double-tap, the wheel using the slider axis but configured more like a button, and the D-pad c/w its two neighboring buttons set as standard joystick buttons.
I was initially overthinking the use of TapHoldManager, AutoHotInterception and CvJoyInterface, making it seem harder than it should've been.
I know my script could be written more elegantly but my skills don't extend that far. If anyone get the itch to tidy or improve this script, feel free.

The below should now be a complete and working version of Synapse3_Replacement_V2.ahk with tap-hold support.
A very quick double-tap and hold is required for the extra functionality.

Code: Select all

;Synapse3_ReplacementV2.ahk
;This is a replacement for Razers Synapse3 beta software and driver for the Tartarus V2.
;Also can replace the original Belkin drivers and software for the Nostromo N50 & N52.
;Successfully tested with a small number of generic half-a-keyboards (gaming keypads).
;With minor adjustments it shouldn't be too hard to make it work with other keypad (half-a-keyboard) devices, even incl full keyboards.
;This version will set each key/button/wheel as a virtual joystick button (28 currently).
;Designed to be used in conjunction with advanced configuration software utilities (Xpadder or Pinnacle Game Profiler, etc).
;Do not use this script if you are using UCR, Universal Control Remapper by evilC.
;Special thanks to evilC for the additional libraries, and the AutoHotkey team and community.
;This script requires TapHoldManager, AutoHotInterception and CvJoyInterface libraries, and Shaul's vJoy. Follow install instructions at evilCs github.

#SingleInstance force
#Persistent
#HotkeyInterval 2000
#MaxHotkeysPerInterval 200
#MaxThreadsBuffer on
#include <AutoHotInterception>
#include <CvJoyInterface>
#include <InterceptionTapHold>

SetBatchLines, -1
ListLines, Off

;Your devices VID and PID. For safe keeping, has no impact on the script
;global vpids := 0x1532, 0x022B		;Tartarus V2
;global vpids := 0x050D, 0x0815		;Nostromo N52

; Create an object from vJoy Interface Class.
global vJoyInterface := new CvJoyInterface()
global myStick := vJoyInterface.Devices[5]
global AHI := new AutoHotInterception()
;Use Monitor.ahk by evilC to determine device VID and PID for below IDs
global keyboardId := AHI.GetKeyboardId(0x1532, 0x022B)
global MouseId := AHI.GetMouseId(0x1532, 0x022B)
global kb1 := new InterceptionTapHold(0x1532, 0x022B)
global newstate := 16384

; Was vJoy installed and the DLL Loaded?
if (!vJoyInterface.vJoyEnabled()){
	; Show log of what happened
	Msgbox % vJoyInterface.LoadLibraryLog
	ExitApp
}
kb1.Add("1", Func("Kb1Func1"),300,100,2) 	; tapTime, holdTime, maxTaps, prefixes
kb1.Add("2", Func("Kb1Func2"),300,100,2) 	; tapTime, holdTime, maxTaps, prefixes
kb1.Add("3", Func("Kb1Func3"),300,100,2) 	; tapTime, holdTime, maxTaps, prefixes
kb1.Add("4", Func("Kb1Func4"),300,100,2) 	; tapTime, holdTime, maxTaps, prefixes
kb1.Add("5", Func("Kb1Func5"),300,100,2) 	; tapTime, holdTime, maxTaps, prefixes

;AHI.SubscribeKey(keyboardId, GetKeySC("1"), true, Func("KeyEvent").Bind(1))
;AHI.SubscribeKey(keyboardId, GetKeySC("2"), true, Func("KeyEvent").Bind(2))
;AHI.SubscribeKey(keyboardId, GetKeySC("3"), true, Func("KeyEvent").Bind(3))
;AHI.SubscribeKey(keyboardId, GetKeySC("4"), true, Func("KeyEvent").Bind(4))
;AHI.SubscribeKey(keyboardId, GetKeySC("5"), true, Func("KeyEvent").Bind(5))

AHI.SubscribeKey(keyboardId, GetKeySC("Tab"), true, Func("KeyEvent").Bind(6))
AHI.SubscribeKey(keyboardId, GetKeySC("q"), true, Func("KeyEvent").Bind(7))
kb1.Add("w", Func("Kb1Func6"),300,100,2) 	; tapTime, holdTime, maxTaps, prefixes
;AHI.SubscribeKey(keyboardId, GetKeySC("w"), true, Func("KeyEvent").Bind(8))
AHI.SubscribeKey(keyboardId, GetKeySC("e"), true, Func("KeyEvent").Bind(9))
AHI.SubscribeKey(keyboardId, GetKeySC("r"), true, Func("KeyEvent").Bind(10))

AHI.SubscribeKey(keyboardId, GetKeySC("CapsLock"), true, Func("KeyEvent").Bind(11))
AHI.SubscribeKey(keyboardId, GetKeySC("a"), true, Func("KeyEvent").Bind(12))
AHI.SubscribeKey(keyboardId, GetKeySC("s"), true, Func("KeyEvent").Bind(13))
AHI.SubscribeKey(keyboardId, GetKeySC("d"), true, Func("KeyEvent").Bind(14))
AHI.SubscribeKey(keyboardId, GetKeySC("f"), true, Func("KeyEvent").Bind(15))

AHI.SubscribeKey(keyboardId, GetKeySC("LShift"), true, Func("KeyEvent").Bind(16))
AHI.SubscribeKey(keyboardId, GetKeySC("z"), true, Func("KeyEvent").Bind(17))
AHI.SubscribeKey(keyboardId, GetKeySC("x"), true, Func("KeyEvent").Bind(18))
AHI.SubscribeKey(keyboardId, GetKeySC("c"), true, Func("KeyEvent").Bind(19))

AHI.SubscribeKey(keyboardId, GetKeySC("Space"), true, Func("KeyEvent").Bind(20))
AHI.SubscribeKey(keyboardId, GetKeySC("LAlt"), true, Func("KeyEvent").Bind(21))

AHI.SubscribeKey(keyboardId, GetKeySC("Left"), true, Func("KeyEvent").Bind(22))
AHI.SubscribeKey(keyboardId, GetKeySC("Right"), true, Func("KeyEvent").Bind(23))
AHI.SubscribeKey(keyboardId, GetKeySC("Up"), true, Func("KeyEvent").Bind(24))
AHI.SubscribeKey(keyboardId, GetKeySC("Down"), true, Func("KeyEvent").Bind(25))

AHI.SubscribeMouseButton(MouseId, GetKeySC("1"), true, Func("MouseEvent").Bind(26))
;AHI.SubscribeMouseButton(MouseId, GetKeySC("4"), true, Func("WheelEvent1"))
AHI.SubscribeMouseButton(MouseId, GetKeySC("4"), true, Func("WheelEvent2"))

return

KeyEvent(btn, state){
	static btnStates := {}
	if (btnStates![btn])
		return ; Filter repeats
	btnStates[btn] := state
	myStick.SetBtn(state, btn)
}
;below is replaced by Kb1Func1-5 and kept as a fallback 
KeyEvent2(btn, state){
	if btn = 1
		dbtn := (btn +28)
	if btn = 2
		dbtn := (btn +28)
	if btn = 4
		dbtn := (btn +27)
	if btn = 5
		dbtn := (btn +27)
	static btnStates := {}
	if (btnStates![btn])
		return ; Filter repeats
	btnStates[btn] := state
;	ToolTip % "State: " state " Button: " btn 
	myStick.SetBtn(state, btn)
	myStick.SetBtn(state, dbtn)
}
MouseEvent(btn, state){
	static btnStates := {}
	if (btnStates![btn])
		return ; Filter repeats
	btnStates[btn] := state
	myStick.SetBtn(state, btn)
}
;below is replaced by WheelEvent2 and kept as a fallback 
WheelEvent1(state){
	if state = 1
		myStick.SetBtn(1, 27)
	if state = -1
		myStick.SetBtn(1, 28)
	sleep 50
	myStick.SetBtn(0, 27)
	myStick.SetBtn(0, 28)
}
WheelEvent2(state){
	if newstate > 32767
		newstate = 32768
	if newstate < 1
		newstate = 0
	newstate = % newstate + (state*2500)
	;ToolTip % "State: " state " NewState: " newstate 
	myStick.SetAxisByIndex(newstate, 7)
	sleep 100
	newstate := 16384
	myStick.SetAxisByIndex(newstate, 7)
}
Kb1Func1(isHold, taps, state){
	if taps = 1
		{
		btn := 1
		myStick.SetBtn(state, btn)
		if state = -1
			state := 0
		myStick.SetBtn(state, btn)
		;ToolTip % "KB 1 Key " btn "`n" (isHold ? "HOLD" : "TAP") "`nTaps: " taps "`nState: " state
		}
	if taps = 2
		{
		btn := 27
		myStick.SetBtn(state, btn)
		if state = -1
			state := 0
		myStick.SetBtn(state, btn)
		;ToolTip % "KB 1 Key " btn "`n" (isHold ? "HOLD" : "TAP") "`nTaps: " taps "`nState: " state
		}
}
Kb1Func2(isHold, taps, state){
	if taps = 1
		{
		btn := 2
		myStick.SetBtn(state, btn)
		if state = -1
			state := 0
		myStick.SetBtn(state, btn)
		;ToolTip % "KB 1 Key " btn "`n" (isHold ? "HOLD" : "TAP") "`nTaps: " taps "`nState: " state
		}
	if taps = 2
		{
		btn := 28
		myStick.SetBtn(state, btn)
		if state = -1
			state := 0
		myStick.SetBtn(state, btn)
		;ToolTip % "KB 1 Key " btn "`n" (isHold ? "HOLD" : "TAP") "`nTaps: " taps "`nState: " state
		}
}
Kb1Func3(isHold, taps, state){
	if taps = 1
		{
		btn := 3
		myStick.SetBtn(state, btn)
		if state = -1
			state := 0
		myStick.SetBtn(state, btn)
		;ToolTip % "KB 1 Key " btn "`n" (isHold ? "HOLD" : "TAP") "`nTaps: " taps "`nState: " state
		}
	if taps = 2
		{
		btn := 29
		myStick.SetBtn(state, btn)
		if state = -1
			state := 0
		myStick.SetBtn(state, btn)
		;ToolTip % "KB 1 Key " btn "`n" (isHold ? "HOLD" : "TAP") "`nTaps: " taps "`nState: " state
		}
}
Kb1Func4(isHold, taps, state){
	if taps = 1
		{
		btn := 4
		myStick.SetBtn(state, btn)
		if state = -1
			state := 0
		myStick.SetBtn(state, btn)
		;ToolTip % "KB 1 Key " btn "`n" (isHold ? "HOLD" : "TAP") "`nTaps: " taps "`nState: " state
		}
	if taps = 2
		{
		btn := 30
		myStick.SetBtn(state, btn)
		if state = -1
			state := 0
		myStick.SetBtn(state, btn)
		;ToolTip % "KB 1 Key " btn "`n" (isHold ? "HOLD" : "TAP") "`nTaps: " taps "`nState: " state
		}
}
Kb1Func5(isHold, taps, state){
	if taps = 1
		{
		btn := 5
		myStick.SetBtn(state, btn)
		if state = -1
			state := 0
		myStick.SetBtn(state, btn)
		;ToolTip % "KB 1 Key " btn "`n" (isHold ? "HOLD" : "TAP") "`nTaps: " taps "`nState: " state
		}
	if taps = 2
		{
		btn := 31
		myStick.SetBtn(state, btn)
		if state = -1
			state := 0
		myStick.SetBtn(state, btn)
		;ToolTip % "KB 1 Key " btn "`n" (isHold ? "HOLD" : "TAP") "`nTaps: " taps "`nState: " state
		}
}
Kb1Func6(isHold, taps, state){
	if taps = 1
		{
		btn := 8
		myStick.SetBtn(state, btn)
		if state = -1
			state := 0
		myStick.SetBtn(state, btn)
		;ToolTip % "KB 1 Key " btn "`n" (isHold ? "HOLD" : "TAP") "`nTaps: " taps "`nState: " state
		}
	if taps = 2
		{
		btn := 32
		myStick.SetBtn(state, btn)
		if state = -1
			state := 0
		myStick.SetBtn(state, btn)
		;ToolTip % "KB 1 Key " btn "`n" (isHold ? "HOLD" : "TAP") "`nTaps: " taps "`nState: " state
		}
}

^Esc::
    ExitApp


If anything, use this script as an example of one way of putting it together. It may not be a good example or even a correct example, but it is an example nonetheless.
Thanks very much for the libraries and your help.

Splat
SplatCatAU
Posts: 14
Joined: 27 Feb 2019, 06:42

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

11 Mar 2019, 01:31

So my headache finally broke today, and hopefully will give me a couple of days break.
Yep, the first thing I do is review something I have been working on and shared, to discover it's shyt.
Again, I would like to admit to not being a coder to any extent, and have learnt mainly the simpler way of writing (and reading) AHK scripts.
I see that what I did to your suggestion for keyevent simply bypassed the check. I have not seen vars written like that, and even after doing some reading, I am finding it hard to visualise the process that is meant to be occurring.
The thing that I dont understand at this point is how the script went from having buttons stick to not having buttons stick, where a check that did nothing was removed and a check that was bypassed was added, followed by Reload This Script.
I have hoped that the addition of #HotkeyInterval 2000, #MaxHotkeysPerInterval 200, and #MaxThreadsBuffer on do help to some extent to reduce the need for a state check to solve the vJoy buttons intermittently sticking.

Anyway, I will stop taking up space in this thread and post the script in the Asking For Help area of the forum (next few days).
I look forward to seeing your future efforts with AHK libraries and UCR.

Splat
serzh82saratov
Posts: 72
Joined: 01 Jul 2017, 03:04

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

18 Mar 2019, 16:26

Fix for SendKeyEvent when using ScanCodes > 255
Is it possible to add multi media keys? SendKeyEvent supports, for example Browser_Home (sc = 306), but SubscribeKey and ContextManager do not react at all.
serzh82saratov
Posts: 72
Joined: 01 Jul 2017, 03:04

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

19 Mar 2019, 06:41

Do you know what could be the reason for this limitation?
serzh82saratov
Posts: 72
Joined: 01 Jul 2017, 03:04

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

19 Mar 2019, 16:23

Thank you, it is now clear that this is a difficult question.
It is also strange that AHKHID responds to their emulated send, but does not respond to their physical ones.

Return to “Scripts and Functions”

Who is online

Users browsing this forum: Delta Pythagorean, gwarble, Shane and 29 guests