Page 1 of 1

Creating Mode Keys - Best Practice

Posted: 26 Mar 2024, 02:37
by Aurasphere
Hi All
Just started AHK although have known it a long time and done mild coding

This is a bit more of a challenging project and was wondering what best practise for the following might be

I wish to extend ctrl, shift and alt behaviours to be like modes on a hardware midi controller (for lack of better example)

eg
  • A quick click on control (<200ms) will activate mode 1
    Then the script will wait for a number (either numeric KP or top row) pop up a small bit map showing the number choices and what they will do (for a training phase)
    The number will execute a switch directive which will assign arguments to varialbes
    Execution then flows to a sub ie sendcontrol, click etc
    The original pic is closed
The mode will be triggered by (as above), a quick click or a double click on any of the qualifiers

Hope that makes sense

Re: Creating Mode Keys - Best Practice

Posted: 26 Mar 2024, 06:44
by mikeyww
Welcome to this AutoHotkey forum!

Below is a way to get started. The documentation can help you in various areas. Enjoy!

Code: Select all

#Requires AutoHotkey v2.0
on := ''
g1 := Gui(, 'Buttons')                   ; Define a GUI to show buttons
g1.Name := 'g1'
g1.SetFont 's10'
g1.AddButton('w40', 'B1').OnEvent('Click', B1_Click)

RCtrl:: {                                ; RCTRL to start
 Global on
 ToolTip on := '===> TYPE A DIGIT <==='  ; Enable special digits
 SoundBeep 2500
}

#HotIf on                                ; Active when special digits are enabled
1::                                      ; 1 = Show GUI #1
Numpad1:: {
 Global on
 digit := SubStr(A_ThisHotkey, -1)       ; Get the digit that was pressed
 ToolTip on := ''                        ; Disable special digits
 g%digit%.Show()                         ; Show the GUI corresponding to the digit
}
#HotIf

B1_Click(btn, info) {                    ; Button was activated
 btn.Gui.Hide                            ; Hide the GUI to which the button belongs
 MsgBox 'GUI    : ' btn.Gui.Name '`n`n'  ; Display information about the GUI and button
      . 'Button: '  btn.Text, 'Information', 'Iconi'
}

Re: Creating Mode Keys - Best Practice

Posted: 26 Mar 2024, 06:56
by Rohwedder
Hallo,
I advise every beginner to start by using less important keys than Ctrl, Shift and Alt for something like this.
There are better places to learn to swim than Niagara Falls!
If you absolutely must use modifier keys for something like this, then only the ones on the right, i.e. RCtrl, RShift and RAlt.
When everything is finally running (and you are no longer so easily frustrated) then switch to the general modifier.

Re: Creating Mode Keys - Best Practice

Posted: 26 Mar 2024, 07:01
by mikeyww
Great advice! I updated accordingly.

Re: Creating Mode Keys - Best Practice

Posted: 27 Mar 2024, 17:50
by Aurasphere
Thanks so much
Im not sure why Im not getting notifications.
Im just about to give it a go...I tried a couple of examples without the solutions above but were 1.1 so I spent some time trying to decipher the changes to 2
BUT
The reason why I use these controls is that Im using a very comfortable gaming keypad (tartarus) for both DAW and architectural application so its quite a tight package and I could only think of switching modes
I have already spent way too long creating midi gestures in another package which, with times, was so verbose and impossible to quickly debug. AHK already has a lot of the timing stuff in there

Basically, in the end, I want to port the same gesture and behaviours using just AKK

eg each 'active' key has 4 gestures
quick press (<100)
single press <300
single hold >500
double press
and double press hold

all of this generates very muscle memory friendly etc
image.png
image.png (671.61 KiB) Viewed 430 times

Re: Creating Mode Keys - Best Practice

Posted: 27 Mar 2024, 18:21
by boiler
Aurasphere wrote: Im not sure why Im not getting notifications.
You probably are getting notifications for replies to topics to which you are subscribed when you visit the forum. You may not be getting email notifications for those occurrences. You can set those preferences in your "User Control Panel" > "Board preferences" tab > "Edit notification options" and check the "Email" column.

Re: Creating Mode Keys - Best Practice

Posted: 28 Mar 2024, 03:39
by Rohwedder
Hallo,
Your definition is not correct!
single press <300
single hold >300 - <500 ???
single hold >500
Try:

Code: Select all

#Requires AutoHotkey v2.0
q:: { ; Type Key Q
Switch Pattern := Type() {
Case "0":ToolTip Pattern " = quick press"
Case "1":ToolTip Pattern " = single press"
Case "20","21","22":ToolTip Pattern " = single hold"
Case "00","01","10","11":ToolTip Pattern " = double press"
Case "02","12":ToolTip Pattern " = double press hold"
Default:ToolTip Pattern " = Pattern without Case"
}}
!q:: { ; hold Alt + type Key Q
Switch Pattern := Type() {
Case "0":ToolTip Pattern " = quick press"
Case "1":ToolTip Pattern " = single press"
Case "20","21","22":ToolTip Pattern " = single hold"
Case "00","01","10","11":ToolTip Pattern " = double press"
Case "02","12":ToolTip Pattern " = double press hold"
Default:ToolTip Pattern " = Pattern without Case"
}}

Type(T1:=150,T2:=400) { ; grid times/ms 
	RegExMatch(A_ThisHotkey, "\W$|\w*$", &Key)
	T := A_TickCount+T1, Up := !KeyWait(Key[], "T" T2/1000)
	Pattern := (A_TickCount > T) + Up
	IF !KeyWait(Key[], "DT" T2/1000)
		Return Pattern
	T := A_TickCount+T1, Up := !KeyWait(Key[], "T" T2/1000)
	KeyWait(Key[])
	Return Pattern .= (A_TickCount > T) + Up
}
Adjust the grid times T1 and T2 to your needs.
When the Pattern assignment is finally correct, Instead of the ToolTips then the actions to be executed.

Re: Creating Mode Keys - Best Practice

Posted: 30 Mar 2024, 14:28
by Aurasphere
Guten Morgen aus Sydney!

It is correct but I will elaborate
Tap = <100ms is a very quick tap but is gesturally specific
Press > 100 and < 400ms is prob clearer to most
Press > 400ms is an actuall hold
Double dont work as well and need about 220ms for reliable operation and feel
and double and hold greater than 400 works fine

Ill give this a go though :-)

Re: Creating Mode Keys - Best Practice

Posted: 30 Mar 2024, 23:53
by Aurasphere
@Rohwedder
Absolutely elegant code!

One tweak I have found is that it seems best when the timer actually triggers on the hold actions vs on key release

What is best practice for that ie when held > 500ms, the event fires on a callback at 500ms?

Re: Creating Mode Keys - Best Practice

Posted: 31 Mar 2024, 02:01
by Rohwedder
Then perhaps?:

Code: Select all

#Requires AutoHotkey v2.0
q:: { ; Type Key Q
Switch Pattern := Type() {
Case "0":ToolTip Pattern " = quick press"
Case "1":ToolTip Pattern " = single press"
Case "20","21","22":ToolTip Pattern " = single hold"
Case "00","01","10","11":ToolTip Pattern " = double press"
Case "02","12":ToolTip Pattern " = double press hold"
Default:ToolTip Pattern " = Pattern without Case"
} KeyWait HotKeyKey
}
!q:: { ; hold Alt + type Key Q
Switch Pattern := Type() {
Case "0":ToolTip Pattern " = quick press"
Case "1":ToolTip Pattern " = single press"
Case "20","21","22":ToolTip Pattern " = single hold"
Case "00","01","10","11":ToolTip Pattern " = double press"
Case "02","12":ToolTip Pattern " = double press hold"
Default:ToolTip Pattern " = Pattern without Case"
} KeyWait HotKeyKey
}

Type(T1:=150,T2:=400) { ; grid times/ms
	Global HotKeyKey ; = Key from the Hotkey
	; i.e. the Key from: Key:: !Key:: ~LButton & Key:: 
	RegExMatch(A_ThisHotkey, "\W$|\w*$", &Key)
	T := A_TickCount+T1, Up := !KeyWait(Key[], "T" T2/1000)
	Pattern := (A_TickCount > T) + Up
	IF !KeyWait(HotKeyKey:=Key[], "DT" T2/1000)
		Return Pattern
	T := A_TickCount+T1, Up := !KeyWait(Key[], "T" T2/1000)
	KeyWait(Key[], "DT" T2/1000) ; hold > T2 --> callback
	Return Pattern .= (A_TickCount > T) + Up
}
The KeyWait HotKeyKey after the Switch blocks prevents the Hotkey from being triggered again immediately.

Re: Creating Mode Keys - Best Practice

Posted: 31 Mar 2024, 18:34
by Aurasphere
Rohwedder wrote:
31 Mar 2024, 02:01
Then perhaps?:

Code: Select all

#Requires AutoHotkey v2.0
q:: { ; Type Key Q
Switch Pattern := Type() {
Case "0":ToolTip Pattern " = quick press"
Case "1":ToolTip Pattern " = single press"
Case "20","21","22":ToolTip Pattern " = single hold"
Case "00","01","10","11":ToolTip Pattern " = double press"
Case "02","12":ToolTip Pattern " = double press hold"
Default:ToolTip Pattern " = Pattern without Case"
} KeyWait HotKeyKey
}
!q:: { ; hold Alt + type Key Q
Switch Pattern := Type() {
Case "0":ToolTip Pattern " = quick press"
Case "1":ToolTip Pattern " = single press"
Case "20","21","22":ToolTip Pattern " = single hold"
Case "00","01","10","11":ToolTip Pattern " = double press"
Case "02","12":ToolTip Pattern " = double press hold"
Default:ToolTip Pattern " = Pattern without Case"
} KeyWait HotKeyKey
}

Type(T1:=150,T2:=400) { ; grid times/ms
	Global HotKeyKey ; = Key from the Hotkey
	; i.e. the Key from: Key:: !Key:: ~LButton & Key:: 
	RegExMatch(A_ThisHotkey, "\W$|\w*$", &Key)
	T := A_TickCount+T1, Up := !KeyWait(Key[], "T" T2/1000)
	Pattern := (A_TickCount > T) + Up
	IF !KeyWait(HotKeyKey:=Key[], "DT" T2/1000)
		Return Pattern
	T := A_TickCount+T1, Up := !KeyWait(Key[], "T" T2/1000)
	KeyWait(Key[], "DT" T2/1000) ; hold > T2 --> callback
	Return Pattern .= (A_TickCount > T) + Up
}
The KeyWait HotKeyKey after the Switch blocks prevents the Hotkey from being triggered again immediately.
Perfect!

Re: Creating Mode Keys - Best Practice

Posted: 31 Mar 2024, 18:40
by Aurasphere
1 thing; is it possible to have AHK use HID unit ID so I can intercept the keypresses? The midi prog still gets the plain vanilla keypresses but I need it to receive only the AKH translated outputs?

Re: Creating Mode Keys - Best Practice

Posted: 01 Apr 2024, 01:23
by Rohwedder
As a Windows Messages non-insider, I am not aware of anything like this.
Maybe some money will help? https://www.autohotkey.com/docs/v2/Hotkeys.htm#prefixdollar
I.e. $q:: resp. $!q::