Creating Mode Keys - Best Practice

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
Aurasphere
Posts: 6
Joined: 26 Mar 2024, 02:24

Creating Mode Keys - Best Practice

26 Mar 2024, 02:37

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
User avatar
mikeyww
Posts: 26973
Joined: 09 Sep 2014, 18:38

Re: Creating Mode Keys - Best Practice

26 Mar 2024, 06:44

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'
}
Last edited by mikeyww on 26 Mar 2024, 07:01, edited 2 times in total.
Rohwedder
Posts: 7656
Joined: 04 Jun 2014, 08:33
Location: Germany

Re: Creating Mode Keys - Best Practice

26 Mar 2024, 06:56

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.
User avatar
mikeyww
Posts: 26973
Joined: 09 Sep 2014, 18:38

Re: Creating Mode Keys - Best Practice

26 Mar 2024, 07:01

Great advice! I updated accordingly.
Aurasphere
Posts: 6
Joined: 26 Mar 2024, 02:24

Re: Creating Mode Keys - Best Practice

27 Mar 2024, 17:50

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 269 times
User avatar
boiler
Posts: 16981
Joined: 21 Dec 2014, 02:44

Re: Creating Mode Keys - Best Practice

27 Mar 2024, 18:21

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.
Rohwedder
Posts: 7656
Joined: 04 Jun 2014, 08:33
Location: Germany

Re: Creating Mode Keys - Best Practice

28 Mar 2024, 03:39

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.
Aurasphere
Posts: 6
Joined: 26 Mar 2024, 02:24

Re: Creating Mode Keys - Best Practice

30 Mar 2024, 14:28

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 :-)
Aurasphere
Posts: 6
Joined: 26 Mar 2024, 02:24

Re: Creating Mode Keys - Best Practice

30 Mar 2024, 23:53

@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?
Rohwedder
Posts: 7656
Joined: 04 Jun 2014, 08:33
Location: Germany

Re: Creating Mode Keys - Best Practice

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.
Aurasphere
Posts: 6
Joined: 26 Mar 2024, 02:24

Re: Creating Mode Keys - Best Practice

31 Mar 2024, 18:34

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!
Aurasphere
Posts: 6
Joined: 26 Mar 2024, 02:24

Re: Creating Mode Keys - Best Practice

31 Mar 2024, 18:40

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?
Rohwedder
Posts: 7656
Joined: 04 Jun 2014, 08:33
Location: Germany

Re: Creating Mode Keys - Best Practice

01 Apr 2024, 01:23

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::

Return to “Ask for Help (v2)”

Who is online

Users browsing this forum: alawsareps, aleksbor, Descolada, reborn, vmech and 128 guests