I'm somewhat new to AutoHotKey. I made a toggleable macro that maps the WASD keys to the arrow keys.
The original code works but I'm trying to enable the hotkeys with a loop which is currently giving me a Nonexistent Hotkey error. How can I fix this loop, so that it works like the hard-coded nightmare below it?
for i in macros {
Hotkey, % keys[i], % macros[i], % state ; <<< This line is causing the error
}
arrowsActive := 0
; CTRL + WASD --> arrow keys
Enter::
arrowsActive := not arrowsActive
macros := [arrowUp1, arrowLeft1, arrowDown1, arrowRight1, arrowUp2, arrowLeft2, arrowDown2, arrowRight2]
keys := [W, A, S, D, W, A, S, D]
state = Off
if arrowsActive {
state = On
}
for i in macros {
Hotkey, % keys[i], % macros[i], % state
}
;Hotkey, W, arrowUp1, state
;Hotkey, A, arrowLeft1, state
;Hotkey, S, arrowDown1, state
;Hotkey, D, arrowRight1, state
;Hotkey, W Up, arrowUp2, state
;Hotkey, A Up, arrowLeft2, state
;Hotkey, S Up, arrowDown2, state
;Hotkey, D Up, arrowRight2, state
Return
arrowUp1:
send, {Up Down}
Return
arrowUp2:
send, {Up Up}
Return
arrowLeft1:
send, {Left Down}
Return
arrowLeft2:
send, {Left Up}
Return
arrowDown1:
send, {Down Down}
Return
arrowDown2:
send, {Down Up}
Return
arrowRight1:
send, {Right Down}
Return
arrowRight2:
send, {Right Up}
Return
The root of your problems seem to be with understanding the legacy vs expression syntax in AHK v1. Here is also a previous answer of mine about legacy syntax and expression syntax. You might find some help from it.
But now to the actual problems:
macros := [arrowUp1, arrowLeft1, arrowDown1, arrowRight1, arrowUp2, arrowLeft2, arrowDown2, arrowRight2]
keys := [W, A, S, D, W, A, S, D]
You're in an expression here, so what you're trying to do is create an array that includes values from the variables arrowUp1
, arrowLeft1
, ..., W
, A
,... But those variables don't exist, so you end up creating two arrays that are full of absolutely nothing. Just empty elements.
What you were trying to do is
macros := ["arrowUp1", "arrowLeft1", ...
keys := ["W", "A", ...
Also in your keys
array, you didn't specify w up
, a up
,... for the second half of the keys.
Other than that, it would work. But of course, the implementation could be a lot better.
Let's make it better:
remaps := { w: "Up"
, a: "Left"
, s: "Down"
, d: "Right" }
Enter::
;store this variable's value in the global scope, so it can be referred to
;on the following runs of this hotkey subroutine
global arrowsActive := !arrowsActive
for key, arrowKey in remaps
{
loop, 2
{
;first loop for hotkeys when pressing down
;second loop for hotkeys when releasing keys
keyFunction := Func("SendKey").bind(arrowKey, (A_Index - 1) ? true : false)
Hotkey, % key ((A_Index - 1) ? " Up" : ""), % keyFunction, % arrowsActive ? "On" : "Off"
}
}
return
SendKey(key, release := false)
{
SendInput, % "{" key (release ? " Up" : "") "}"
}
Useful documentation links to understand the code:
The answer also utilizes the fact that you shouldn't need to specify a Down
hotkey. If you have e.g. hotkeys a
and a up
, the hotkey a
gets called everything Windows' repeat key functionality triggers and repeats a key while you hold it down. And then a up
gets called when a is released.
If something else is unclear about the answer, feel free to ask.