Remap combining keystrokes on a Stylus

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
jc0r
Posts: 29
Joined: 27 Nov 2015, 07:09

Remap combining keystrokes on a Stylus

20 Jul 2017, 06:42

Hi all

I have a wireless presenter stylus that has 3 buttons on, which are bound to Up, Down and B and cannot be changed.

I would like to use ahk to remap these buttons to preform mouse clicks instead, easy enough. Where I'm struggling is, I need to be able to have more than 3 mouse click options available, and for this I would like to use combinations. For example:

Code: Select all

Down & b::
Mouse click, left, 600, 300
This would normally work fine on a standard keyboard, so I would hold down 'Down Arrow' then press 'b' to get the desired effect. Unfortunately, on the presenter stylus, it doesn't recognise keys that were held down like a standard keyboard. So where a standard keyboard would see the Down key held as:

Code: Select all

'Down Arrow' Down
'Down Arrow' Down
'Down Arrow' Down etc...
The stylus output is:

Code: Select all

'Down Arrow' Down
'Down Arrow' Up
'Down Arrow' Down
'Down Arrow' Up
'Down Arrow' Down
'Down Arrow' Up etc...
Just wondered if anyone could help me achieve the desired effect using the stylus. I assume it has something to do with keystates?

Many thanks

Jon
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: Remap combining keystrokes on a Stylus

20 Jul 2017, 07:12

Mouse click, left, 600, 300 FYI this syntax is wrong, you want Click, left, 600, 300

Use the AHK keyhistory viewer. When it sends the down/up events, what are the timings?
If it presses / releases / presses quickly, then it should be simple enough to distinguish a held button from a pressed one.
jc0r
Posts: 29
Joined: 27 Nov 2015, 07:09

Re: Remap combining keystrokes on a Stylus

20 Jul 2017, 07:50

Many thanks for your reply. Not exactly sure what to do with this information but below is the raw output from the stylus when the Down, Up and B buttons are pressed once.

Hopefully something can be done with this information?

Code: Select all

VK  SC    Type    Up/Dn    Elapsed    Key        Window
-------------------------------------------------------------------------------------------------------------
28  150    a    d    22.66    Down               C:\Users\jc0r\Desktop\test.ahk - AutoHotkey v1.1.25.01
28  150    a    u    0.00    Down               
28  150    a    u    0.27    Down               
Press [F5] to refresh.

VK  SC    Type    Up/Dn    Elapsed    Key        Window
-------------------------------------------------------------------------------------------------------------
26  148    a    d    11.72    Up                 C:\Users\jc0r\Desktop\test.ahk - AutoHotkey v1.1.25.01
26  148    a    u    0.00    Up                 
26  148    a    u    0.06    Up                 
Press [F5] to refresh.

VK  SC    Type    Up/Dn    Elapsed    Key        Window
-------------------------------------------------------------------------------------------------------------
42  030    a    d    9.72    b                  C:\Users\jc0r\Desktop\test.ahk - AutoHotkey v1.1.25.01
42  030    a    u    0.00    b                  
42  030    a    u    0.16    b                  
Press [F5] to refresh.
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: Remap combining keystrokes on a Stylus

20 Jul 2017, 07:53

I kind of wanted to see a log of what it looked like when you held one of the keys.
I am interested in the "Elapsed" column - this should show me, for example, how long there is between the press and release events.
jc0r
Posts: 29
Joined: 27 Nov 2015, 07:09

Re: Remap combining keystrokes on a Stylus

20 Jul 2017, 08:25

Sorry about that. Here is one of the keys pressed

Code: Select all

[VK  SC    Type    Up/Dn    Elapsed    Key        Window
-------------------------------------------------------------------------------------------------------------
26  148    a    u    0.00    Up                 
26  148    a    d    0.03    Up                 
26  148    a    u    0.02    Up                 
26  148    a    d    0.01    Up                 
26  148    a    u    0.02    Up                 
26  148    a    d    0.05    Up                 
26  148    a    u    0.01    Up                 
26  148    a    d    0.02    Up                 
26  148    a    u    0.02    Up                 
26  148    a    d    0.06    Up                 
26  148    a    u    0.03    Up                 
26  148    a    d    0.03    Up                 
26  148    a    u    0.01    Up                 
26  148    a    d    0.02    Up                 
26  148    a    u    0.01    Up                 
26  148    a    d    0.06    Up                 
26  148    a    u    0.00    Up                 
26  148    a    d    0.02    Up                 
26  148    a    u    0.01    Up                 
26  148    a    d    0.03    Up                 
26  148    a    u    0.05    Up                 
26  148    a    d    0.02    Up                 
26  148    a    u    0.00    Up                 
26  148    a    d    0.03    Up                 
26  148    a    u    0.05    Up                 
26  148    a    d    0.02    Up                 
26  148    a    u    0.00    Up                 
26  148    a    d    0.05    Up                 
26  148    a    u    0.01    Up                 
26  148    a    d    0.06    Up                 
26  148    a    u    0.00    Up                 
26  148    a    d    0.03    Up                 
26  148    a    u    0.03    Up                 
26  148    a    d    0.03    Up                 
26  148    a    u    0.00    Up                 
26  148    a    d    0.03    Up                 
26  148    a    u    0.03    Up                 
26  148    a    d    0.03    Up                 
26  148    a    u    0.02    Up                 
26  148    a    u    0.00    Up                 
Press [F5] to refresh.


jc0r
Posts: 29
Joined: 27 Nov 2015, 07:09

Re: Remap combining keystrokes on a Stylus

20 Jul 2017, 08:39

Just another quick question about the elapsed column as my need is very speed focused. 0.03 on elapsed time, is that 30ms or 0.03 of a millisecond? 30ms as fast as that may sound can mean an awful lot in my industry. The faster I can execute my mouseclicks the better. From pressing the button, I can't afford to wait longer than 50ms before the script is executed
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: Remap combining keystrokes on a Stylus

20 Jul 2017, 10:06

OK, this is not a full solution, it's purpose is to abstract away the complexity and fire a function with more "accurate" press and release events for each key.

So in the UpEvent / DownEvent / BEvent functions, you would need to add logic to take appropriate actions.
You can check the "state" of the other hotkeys using b.State / Up.State / Down.State

Hope this helps?

Code: Select all

#SingleInstance force
#Persistent
OutputDebug DBGVIEWCLEAR

global b := new WrappedKey("b", Func("BEvent"))
global up := new WrappedKey("up", Func("UpEvent"))
global down := new WrappedKey("down", Func("DownEvent"))

OutputDebug % "AHK| Test #1"
DoTest(b, 10)
Sleep 100
OutputDebug % "AHK| Test #2"
DoTest(b, 100)
return

DoTest(key, t){
	; Test code
	Loop 10 {
		OutputDebug % "AHK| PRESS @ " A_TickCount
		key.KeyEvent(1)
		Sleep % t
		OutputDebug % "AHK| RELEASE @ " A_TickCount
		key.KeyEvent(0)
		Sleep % t
	}
}


^Esc::
	ExitApp

class WrappedKey {
	MinTime := 50
	TimerFn := 0
	TimerRunning := 0
	UpTime := 0
	State := 0
	
	__New(key, callback){
		this.Key := key
		this.Callback := callback
		this.TimerFn := this.Timer.Bind(this)
		fn := this.KeyEvent.Bind(this, 1)
		Hotkey, % key, % fn
		fn := this.KeyEvent.Bind(this, 0)
		Hotkey, % key " up", % fn
	}
	
	KeyEvent(state){
		if (state){
			; When the key is pressed, if it was released within <MinTime>, ignore
			if (this.TimerRunning && ((A_TickCount - this.UpTime) < this.MinTime)){
				; Re-press within <MinTime>
				this.SetTimerState(0)	; Cancel pending release
			} else {
				this.State := 1
				this.Callback.Call(1)
			}
		} else {
			this.SetTimerState(1)
			this.UpTime := A_TickCount
		}
	}
	
	SetTimerState(state){
		fn := this.TimerFn
		if (state){
			SetTimer, % fn, % "-" this.MinTime
			this.TimerRunning := 1
		} else {
			this.TimerRunning := 0
			SetTimer, % fn, Off
		}
	}
	
	Timer(){
		this.State := 0
		this.TimerRunning := 0
		this.callback.Call(0)
	}
}

BEvent(state){
	OutputDebug % "AHK| B changed state to: " state " @ " A_TickCount
}

UpEvent(state){
	OutputDebug % "AHK| Up changed state to: " state " @ " A_TickCount
}

DownEvent(state){
	OutputDebug % "AHK| Down changed state to: " state " @ " A_TickCount
}
Here you can see the debug output from the 2 tests:
Test #1 presses and releases b within 50ms (Trying to mimic what happens if you hold the button)
As you can see, it only fires the function on the first press and the last release

Test #2 presses and releases b within 100ms (Trying to mimic a tap of the button)
As you can see, it registers every press and release

Code: Select all

[32644] AHK| Test #1
[32644] AHK| PRESS @ 261117203
[32644] AHK| B changed state to: 1 @ 261117203
[32644] AHK| RELEASE @ 261117218
[32644] AHK| PRESS @ 261117234
[32644] AHK| RELEASE @ 261117250
[32644] AHK| PRESS @ 261117265
[32644] AHK| RELEASE @ 261117281
[32644] AHK| PRESS @ 261117296
[32644] AHK| RELEASE @ 261117312
[32644] AHK| PRESS @ 261117328
[32644] AHK| RELEASE @ 261117343
[32644] AHK| PRESS @ 261117359
[32644] AHK| RELEASE @ 261117375
[32644] AHK| PRESS @ 261117390
[32644] AHK| RELEASE @ 261117406
[32644] AHK| PRESS @ 261117421
[32644] AHK| RELEASE @ 261117437
[32644] AHK| PRESS @ 261117453
[32644] AHK| RELEASE @ 261117468
[32644] AHK| PRESS @ 261117484
[32644] AHK| RELEASE @ 261117500
[32644] AHK| B changed state to: 0 @ 261117562



[32644] AHK| Test #2
[32644] AHK| PRESS @ 261117625
[32644] AHK| B changed state to: 1 @ 261117625
[32644] AHK| RELEASE @ 261117734
[32644] AHK| B changed state to: 0 @ 261117796
[32644] AHK| PRESS @ 261117843
[32644] AHK| B changed state to: 1 @ 261117843
[32644] AHK| RELEASE @ 261117953
[32644] AHK| B changed state to: 0 @ 261118015
[32644] AHK| PRESS @ 261118062
[32644] AHK| B changed state to: 1 @ 261118062
[32644] AHK| RELEASE @ 261118171
[32644] AHK| B changed state to: 0 @ 261118234
[32644] AHK| PRESS @ 261118281
[32644] AHK| B changed state to: 1 @ 261118281
[32644] AHK| RELEASE @ 261118390
[32644] AHK| B changed state to: 0 @ 261118453
[32644] AHK| PRESS @ 261118500
[32644] AHK| B changed state to: 1 @ 261118500
[32644] AHK| RELEASE @ 261118609
[32644] AHK| B changed state to: 0 @ 261118671
[32644] AHK| PRESS @ 261118718
[32644] AHK| B changed state to: 1 @ 261118718
[32644] AHK| RELEASE @ 261118828
[32644] AHK| B changed state to: 0 @ 261118890
[32644] AHK| PRESS @ 261118937
[32644] AHK| B changed state to: 1 @ 261118937
[32644] AHK| RELEASE @ 261119046
[32644] AHK| B changed state to: 0 @ 261119109
[32644] AHK| PRESS @ 261119156
[32644] AHK| B changed state to: 1 @ 261119156
[32644] AHK| RELEASE @ 261119265
[32644] AHK| B changed state to: 0 @ 261119328
[32644] AHK| PRESS @ 261119375
[32644] AHK| B changed state to: 1 @ 261119375
[32644] AHK| RELEASE @ 261119484
[32644] AHK| B changed state to: 0 @ 261119546
[32644] AHK| PRESS @ 261119593
[32644] AHK| B changed state to: 1 @ 261119593
[32644] AHK| RELEASE @ 261119703
[32644] AHK| B changed state to: 0 @ 261119765
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: Remap combining keystrokes on a Stylus

20 Jul 2017, 10:37

Here is a version which actually does something useful.
It should, in theory, remap a hold of B and DOWN to Left Mouse

Code: Select all

#SingleInstance force
#Persistent
OutputDebug DBGVIEWCLEAR

global b := new WrappedKey("b", Func("KeyEvent"))
global up := new WrappedKey("up", Func("KeyEvent"))
global down := new WrappedKey("down", Func("KeyEvent"))

OutputDebug % "AHK| Test #1"
DoTest(10)
;~ Sleep 100
;~ OutputDebug % "AHK| Test #2"
;~ DoTest(100)
return

DoTest(t){
	; Test code
	Loop 10 {
		OutputDebug % "AHK| PRESS @ " A_TickCount
		b.KeyEvent(1)
		Down.KeyEvent(1)
		Sleep % t
		OutputDebug % "AHK| RELEASE @ " A_TickCount
		b.KeyEvent(0)
		Down.KeyEvent(0)
		Sleep % t
	}
}


KeyEvent(state){
	static LBState := 0
	if (LBState && !b.State && !Down.State){
		LBState := 0
		Send {LButton Up}
		OutputDebug % "LButton RELEASE @ " A_TickCount
	} else if (!LBState && b.State && Down.State){
		LBState := 1
		Send {LButton Down}
		OutputDebug % "LButton PRESS @ " A_TickCount
	}
}

^Esc::
	ExitApp

class WrappedKey {
	MinTime := 50
	TimerFn := 0
	TimerRunning := 0
	UpTime := 0
	State := 0
	
	__New(key, callback){
		this.Key := key
		this.Callback := callback
		this.TimerFn := this.Timer.Bind(this)
		fn := this.KeyEvent.Bind(this, 1)
		Hotkey, % key, % fn
		fn := this.KeyEvent.Bind(this, 0)
		Hotkey, % key " up", % fn
	}
	
	KeyEvent(state){
		if (state){
			; When the key is pressed, if it was released within <MinTime>, ignore
			if (this.TimerRunning && ((A_TickCount - this.UpTime) < this.MinTime)){
				; Re-press within <MinTime>
				this.SetTimerState(0)	; Cancel pending release
			} else {
				this.State := 1
				this.Callback.Call(1)
			}
		} else {
			this.SetTimerState(1)
			this.UpTime := A_TickCount
		}
	}
	
	SetTimerState(state){
		fn := this.TimerFn
		if (state){
			SetTimer, % fn, % "-" this.MinTime
			this.TimerRunning := 1
		} else {
			this.TimerRunning := 0
			SetTimer, % fn, Off
		}
	}
	
	Timer(){
		this.State := 0
		this.TimerRunning := 0
		this.callback.Call(0)
	}
}
jc0r
Posts: 29
Joined: 27 Nov 2015, 07:09

Re: Remap combining keystrokes on a Stylus

20 Jul 2017, 11:01

Ok, many thanks. I'm just at work right now. I will test it when I get home and report back. Thanks for all your time
jc0r
Posts: 29
Joined: 27 Nov 2015, 07:09

Re: Remap combining keystrokes on a Stylus

20 Jul 2017, 13:35

Hi again,

Ive managed to test your code and it seems to do the job! I've tried manipulating the code to add in extra key combinations but with no success. For example:

Code: Select all

KeyEvent(state){
	static LBState := 0
	static RBState := 0
	
	if (LBState && !b.State && !Down.State){
		LBState := 0
		Send {LButton Up}
		OutputDebug % "LButton RELEASE @ " A_TickCount
	} else if (!LBState && b.State && Down.State){
		LBState := 1
		Send {LButton Down}
		OutputDebug % "LButton PRESS @ " A_TickCount
	}
	
		if (LBState && !b.State && !Up.State){
		RBState := 0
		Send {RButton Up}
		OutputDebug % "RButton RELEASE @ " A_TickCount
	} else if (!RBState && b.State && Up.State){
		RBState := 1
		Send {RButton Down}
		OutputDebug % "RButton PRESS @ " A_TickCount
	}
	
	
}
Needless to say, that didn't work out to good. The other problem i am having is if a key is held down, i get the message:

Image

Many thanks
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: Remap combining keystrokes on a Stylus

20 Jul 2017, 13:58

If you hold a key, it will repeatedly fire the down event - it's a windows thing.
So what we need to do is when a key goes down, check if it is already down, and if so, ignore.

Try adjusting the code like so:
(I put comments where code changed)

Code: Select all

#SingleInstance force
#Persistent
OutputDebug DBGVIEWCLEAR

global b := new WrappedKey("b", Func("KeyEvent"))
global up := new WrappedKey("up", Func("KeyEvent"))
global down := new WrappedKey("down", Func("KeyEvent"))

OutputDebug % "AHK| Test #1"
DoTest(10)
;~ Sleep 100
;~ OutputDebug % "AHK| Test #2"
;~ DoTest(100)
return

DoTest(t){
	; Test code
	Loop 10 {
		OutputDebug % "AHK| PRESS @ " A_TickCount
		b.KeyEvent(1)
		Down.KeyEvent(1)
		Sleep % t
		OutputDebug % "AHK| RELEASE @ " A_TickCount
		b.KeyEvent(0)
		Down.KeyEvent(0)
		Sleep % t
	}
}


KeyEvent(state, keyObj){	; < --- this now takes an extra param
	static LBState := 0
	if (state && keyObj.State)	; < --- new code
		return	; filter repeat
	if (LBState && !b.State && !Down.State){
		LBState := 0
		Send {LButton Up}
		OutputDebug % "LButton RELEASE @ " A_TickCount
	} else if (!LBState && b.State && Down.State){
		LBState := 1
		Send {LButton Down}
		OutputDebug % "LButton PRESS @ " A_TickCount
	}
}

^Esc::
	ExitApp

class WrappedKey {
	MinTime := 50
	TimerFn := 0
	TimerRunning := 0
	UpTime := 0
	State := 0
	
	__New(key, callback){
		this.Key := key
		this.Callback := callback
		this.TimerFn := this.Timer.Bind(this)
		fn := this.KeyEvent.Bind(this, 1)
		Hotkey, % key, % fn
		fn := this.KeyEvent.Bind(this, 0)
		Hotkey, % key " up", % fn
	}
	
	KeyEvent(state){
		if (state){
			; When the key is pressed, if it was released within <MinTime>, ignore
			if (this.TimerRunning && ((A_TickCount - this.UpTime) < this.MinTime)){
				; Re-press within <MinTime>
				this.SetTimerState(0)	; Cancel pending release
			} else {
				this.State := 1
				this.Callback.Call(1, this)	; <-- this line changed
			}
		} else {
			this.SetTimerState(1)
			this.UpTime := A_TickCount
		}
	}
	
	SetTimerState(state){
		fn := this.TimerFn
		if (state){
			SetTimer, % fn, % "-" this.MinTime
			this.TimerRunning := 1
		} else {
			this.TimerRunning := 0
			SetTimer, % fn, Off
		}
	}
	
	Timer(){
		this.State := 0
		this.TimerRunning := 0
		this.callback.Call(0, this) ; <--- this line changed
	}
}
jc0r
Posts: 29
Joined: 27 Nov 2015, 07:09

Re: Remap combining keystrokes on a Stylus

20 Jul 2017, 14:10

I tried your amended code and it doesnt appear to trigger at all now. Ive tried both manually using the keyboard and the stylus. Sorry for the agrovation!
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: Remap combining keystrokes on a Stylus

20 Jul 2017, 14:16

I did not test the last code, cause I am unsure of how to repro on my machine.

With the previous code, If you edit the test function and comment out the release events, does the same issue exhibit when you call it at a 10ms rate?

ie

Code: Select all

DoTest(10)

DoTest(t){
	; Test code
	Loop 10 {
		OutputDebug % "AHK| PRESS @ " A_TickCount
		b.KeyEvent(1)
		Down.KeyEvent(1)
		Sleep % t
	}
}
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: Remap combining keystrokes on a Stylus

20 Jul 2017, 14:22

BTW, 71 hotkeys in 1700 ms does not sound like anything really bad is happening (eg a self-triggering loop), it's probably just due to how quickly the device is sending input.
It would probably be simplest to just put #MaxHotkeysPerInterval 200 at the start of the script.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Anput, Google [Bot] and 111 guests