AutoHotkey Syntax Problems

By Xah Lee. Date: . Last updated: .

The AutoHotkey language syntax is pretty bad, from a pure design point of view. This page gives some examples.

If you add a blank line in the wrong place, it is a compiler error. For a example, the following compiles fine:

;;; make the numpad star “*” key to do next tab
WinGet, myProcName, ProcessName, A
If ( WinActive("ahk_class Chrome_WindowImpl_0")
Or WinActive("ahk_class MozillaUIWindowClass")
Or WinActive("ahk_class gdkWindowToplevel") )
  Send ^{PgDn}
Else If (WinActive("ahk_class IEFrame")
  Or WinActive("ahk_class OpWindow")
Or (myProcName = "safari.exe") )
  Send ^{Tab}
Else {
  Send {NumpadMult}

But if the line:

If ( WinActive("ahk_class Chrome_WindowImpl_0")

has a newline after the paren like this:

If (
 WinActive("ahk_class Chrome_WindowImpl_0")

The compiler generates a error.

Following is another example on the newline problem. This is ok:

; OK
Else If (WinActive("ahk_class Emacs")
  Or WinActive("ahk_class Chrome_WidgetWin_0")
Or WinActive("ahk_class MozillaUIWindowClass")
Or WinActive("ahk_class gdkWindowToplevel") )

But putting the closing paren in a separate line creates compiler error:

; Compiler Error
Else If (WinActive("ahk_class Emacs")
  Or WinActive("ahk_class Chrome_WidgetWin_0")
Or WinActive("ahk_class MozillaUIWindowClass")
Or WinActive("ahk_class gdkWindowToplevel")

Syntax Soup

Also, the syntax is quite a syntax soup. example

IfWinActive ahk_class Notepad
IfWinActive, ahk_class Notepad
if WinActive("ahk_class Notepad")
if WinActive("ahk_class" . "Notepad")

are pretty much the same. I still don't quite understand if they are exactly equivalent at the syntax level, or if they are just semantically equivalent, or if they are semantically similar but not equivalent.

Key Syntax Mud Ball

Its syntax for keys is also badly designed, with huge amount of special cases.

For example, the syntax for Ctrl+n is ^n or Control & n. But if you want the single key Ctrl to send some key combination, you cannot use ^::Send …, you have to use Control::Send ….

The syntax seems more complex for the right hand side. For example, to assign Alt+F4to the Pause key, you can write Pause::Send !{F4} but not Pause::Send !F4. You need the “{}” there. But the !F4 is the proper syntax if it is on the left side. !{F4}::Send ^o generates a compiler error. Suppose you want to assign Ctrl+o, then you can use Pause::Send ^o, no need for “{}”.

The general form for the left side is one of:

However, you can have special meaning characters in front of the key syntax, like this:

$NumpadDiv::Send !{Left}

That dollar sign means if a NumpadDiv press is generated by AHK, don't interpret it in this definition. (useful to prevent infinite recursion)

So, the meaning of the form charkey_name depends on whether if the “char” is a special char for modifiers.

Also, for some commands, you can add a # char in front and it became a directive. example

#IfWinActive ahk_class Notepad
#Space::MsgBox You pressed Win+Spacebar in Notepad.

In the above, the #IfWinActive is a directive, changing the meaning all lines below. In a C-like syntax, it would be something like this:

If ( WinActive( ahk_class("Notepad") ) ) {
 #Space::MsgBox("You pressed Win+Spacebar in Notepad.")

However, not all commands can become a directive by adding a #. Also, some directives, starts with # but does not become command without #. For example, #NoTrayIcon.

Also note, the prefix of # char has multiple meanings depending on what follows. In the above example, the #Space is a key syntax, meaning ❖ Window+Space.

Assignment and Equality Operator

To assign a value to a var, you can use = or :=. The = is for assigning numbers, but for expressions you have to use :=. Also, equality operator can be = or ==, depending on context.

Why It Sucks

The reason the syntax is lousy is due to the language's history, of course. AHK is a language that evolved out of practical needs. It is a branch off of the AutoIt scripting language. AutoIt is scripting language for task automation for Windows. At the time, the language does not feature defining hotkeys. The AHK author Chris Mallett was a fan of AutoIt, suggested the hotkey feature, but got turned down or got no reaction, so he branched off and started AHK. So, key-binding syntax is grafted onto the language. Further, it is safe to presume the keybinding features just got added gradually from practical experimentation, so even the key syntax is quite inconsistent.

I've been learning and using AHK since . On average perhaps spending 1 hour per week for the past 2 years. However, i can't see any general principle of the syntax. It seems just a soup of commands, much like unix shells, Perl, but i think it's even worse than perl.