Scripting Language

An AutoHotkey script is basically a set of instructions for the program to follow, written in a custom language exclusive to AutoHotkey. This language bears some similarities to several other scripting languages, but also has its own unique strengths and pitfalls. This document describes the language and also tries to point out common pitfalls.

See Concepts and Conventions for more general explanation of various concepts utilised by AutoHotkey.

Table of Contents

General Conventions

Names: Variable and function names are not case sensitive (for example, CurrentDate is the same as currentdate). For details such as maximum length and usable characters, see Names.

No typed variables: Variables have no explicitly defined type; instead, a value of any type can be stored in any variable (excluding built-in variables). Numbers may be automatically converted to strings (text) and vice versa, depending on the situation.

Declarations are optional: Except where noted on the functions page, variables do not need to be declared; they come into existence simply by using them (and each variable starts off empty/blank).

Spaces are mostly ignored: Indentation (leading space) is important for writing readable code, but is not required by the program and is generally ignored. Spaces and tabs are generally ignored at the end of a line and within an expression (except between quotes). However, spaces are significant in some cases, including:

Line breaks are meaningful: Line breaks generally act as a statement seperator, terminating the previous function call or other statement. (A statement is simply the smallest standalone element of the language that expresses some action to be carried out.) The exception to this is line continuation (see below).

Line continuation: Long lines can be divided up into a collection of smaller ones to improve readability and maintainability. This is achieved by preprocessing, so is not part of the language as such. There are three methods:


Comments are portions of text within the script which are ignored by the program. They are typically used to add explanation or disable parts of the code.

Scripts can be commented by using a semicolon at the beginning of a line. For example:

; This entire line is a comment.

Comments may also be added at the end of a line, in which case the semicolon must have at least one space or tab to its left. For example:

Run "Notepad"  ; This is a comment on the same line as a function call.

In addition, the /* and */ symbols can be used to comment out an entire section, but only if the symbols appear at the beginning of a line (or for */, the beginning or end) as in this example:

MsgBox "This line is commented out (disabled)."
MsgBox "Common mistake:" */ " this does not end the comment."
MsgBox "This line is commented out."
MsgBox "This line is not commented out."
/* This is also valid, but no other code can share the line. */

Since comments are ignored when a script is launched, they do not impact performance or memory utilization.


Expressions are combinations of one or more values, variables, operators and function calls. For example, 10, 1+1 and MyVar are valid expressions. Usually, an expression takes one or more values as input, performs one or more operations, and produces a value as the result. The process of finding out the value of an expression is called evaluation. For example, the expression 1+1 evaluates to the number 2.

Simple expressions can be pieced together to form increasingly more complex expressions. For example, if Discount/100 converts a discount percentage to a fraction, 1 - Discount/100 calculates a fraction representing the remaining amount, and Price * (1 - Discount/100) applies it to produce the net price.

Values are numbers, objects or strings. A literal value is one written physically in the script; one that you can see when you look at the code.

Strings / Text

For a more general explanation of strings, see Strings.

A string, or string of characters, is just a text value. In an expression, literal text must be enclosed in single or double quotation marks to differentiate it from a variable name or some other expression. This is often referred to as a quoted literal string, or just quoted string. For example, "this is a quoted string" and 'so is this'.

To include an actual quote character inside a quoted string, use the `" or `' escape sequence or enclose the character in the opposite type of quote mark. For example: 'She said, "An apple a day."'.

Quoted strings can contain other escape sequences such as `t (tab), `n (linefeed), and `r (carriage return).


For a basic explanation and general details about variables, see Variables.

Variables can be used in an expression simply by writing the variable's name. For example, A_ScreenWidth/2. However, variables cannot be used inside a quoted string. Instead, variables and other values can be combined with text through a process called concatenation. There are two ways to concatenate values in an expression:

Implicit concatenation is also known as auto-concat. In both cases, the spaces preceding the variable and dot are mandatory.

The Format function can also be used for this purpose. For example:

MsgBox Format("You are using AutoHotkey v{1} {2}-bit.", A_AhkVersion, A_PtrSize*8)

To assign a value to a variable, use the := assignment operator, as in MyVar := "Some text".

Percent signs within an expression are used to create dynamic variable references and dynamic function calls, but these are rarely needed.


Operators take the form of a symbol or group of symbols such as + or :=, or one of the words and, or, not, new, is, in or contains. They take one, two or three values as input and return a value as the result. A value or sub-expression used as input for an operator is called an operand.

Some unary and binary operators share the same symbols, in which case the meaning of the operator depends on whether it is written before, after or in between two values. For example, x-y performs subtraction while -x inverts the sign of x (producing a positive value from a negative value and vice versa).

Operators of equal precedence such as multiply (*) and divide (/) are evaluated in left-to-right order unless otherwise specified in the operator table. By contrast, an operator of lower precedence such as add (+) is evaluated after a higher one such as multiply (*). For example, 3 + 2 * 2 is evaluated as 3 + (2 * 2). Parentheses may be used to override precedence as in this example: (3 + 2) * 2

Function Calls

For a general explanation of functions and related terminology, see Functions.

Functions take a varying number of inputs, perform some action or calculation, and then return a result. The inputs of a function are called parameters or arguments. A function is called simply by writing its name followed by its parameters enclosed in parentheses. For example, GetKeyState("Shift") returns (evaluates to) 1 if the Shift key is being held down or 0 otherwise.

Note: There must not be any space between the function name and open parenthesis.

For those new to programming, the requirement for parentheses may seem cryptic or verbose at first, but they are what allows a function call to be combined with other operations. For example, the expression GetKeyState("Shift", "P") and GetKeyState("Ctrl", "P") returns 1 only if both keys are being physically held down.

Function names are always global, and are separate to variable names. For example, Round can be both a variable name and a function name, and Round := 1 will not affect Round(n) in any way.

Function Call Statements

If the return value of the function is not needed and the function name is written at the start of the line (or in other contexts which allow a statement, such as following else or a hotkey label), the parentheses can be omitted. In this case, the remainder of the line is taken as the function's parameter list. For example:

result := MsgBox("This one requires parentheses.",, "OKCancel")
MsgBox "This one doesn't. The result was " result "."

Known limitations:

Optional Parameters

Optional parameters can simply be left blank, but the delimiting comma is still required unless all subsequent parameters are also omitted. For example, the Run function can accept between one and four parameters. All of the following are valid:

Run "notepad.exe", "C:\"
Run "notepad.exe",, "Min"
Run("notepad.exe", , , notepadPID)

Operators for Objects

There are other symbols used in expressions which don't quite fit into any of the categories defined above, or that affect the meaning of other parts of the expression, as described below. These all relate to objects in some way. Providing a full explanation of what each construct does would require introducing more concepts which are outside the scope of this section.

Alpha.Beta is often called member access. Alpha is an ordinary variable, and could be replaced with a function call or some other sub-expression which returns an object. When evaluated, the object is sent a request "give me the value of property Beta", "store this value in property Beta" or "call the method named Beta". In other words, Beta is a name which has meaning to the object; it is not a local or global variable.

Alpha.Beta() is a method call, as described above.

Alpha.Beta[Param] is a specialised form of member access which includes additional parameters in the request. While Beta is a simple name, Param is an ordinary variable or sub-expression, or a list of sub-expressions separated by commas (the same as in a function's parameter list).

Alpha[Index] has a similar function to Alpha.Beta, but each part is interpreted in a more standard way. That is, both Alpha and Index are variables in this case, and could be replaced with virtually any sub-expression. This syntax is usually used to retrieve an element of an array or associative array.

new ClassName() is used to instantiate a class, or create an object derived from another object. Although this looks like a function call, ClassName is actually an ordinary variable. Similarly, new Alpha.Beta() would create an object derived from the object returned by Alpha.Beta; Beta is neither a function nor a method. If the optional parentheses are present, they may contain parameters for the object's __New method.

[A, B, C] creates an array with the initial contents A, B and C (all variables in this case), where A is element 1.

{Key1: Value1, Key2: Value2} creates an associative array from a list of key-value pairs. A value can later be retrieved by its associated key. Writing a plain word (consisting of alphanumeric characters, underscore and non-ASCII characters) to the left of : is equivalent to enclosing that word in quotation marks. For example, {A: B} is equivalent to {"A": B}. However, {(A): B} uses the contents of the variable A as the key.

MyFunc(Params*) is a variadic function call. The asterisk must immediately precede the closing parenthesis at the end of the function's parameter list. Params must be a variable or sub-expression which returns an array object. Although it isn't valid to use Params* just anywhere, it can be used in an array literal ([A, B, C, ArrayToAppend*]) or indexer (Alpha[Params*]).

Expression Statements

Not all expressions can be used alone on a line. For example, a line consisting of just 21*2 or "Some text" wouldn't make any sense. An expression statement is an expression used on its own, typically for its side-effects. Most expressions with side-effects can be used this way, so it is generally not necessary to memorise the details of this section.

The following types of expressions can be used as statements:

Assignments, as in x := y, compound assignments such as x += y, and increment/decrement operators such as ++x and x--.

Known limitation: For x++ and x--, there currently cannot be a space between the variable name and operator.

Function calls such as MyFunc(Params). However, a standalone function call cannot be followed by an open brace { (at the end of the line or on the next line), because it would be confused with a function declaration.

Method calls such as MyObj.MyMethod().

Member access using square brackets, such as MyObj[Index], which can have side-effects like a function call.

Expressions starting with the new operator, as in new ClassName, because sometimes a class can be instantiated just for its side-effects.

Ternary expressions such as x? CallIfTrue() : CallIfFalse().

Known limitation: There currently cannot be a space between the variable name and question mark.

Expressions starting with (. However, there usually must be a matching ) on the same line, otherwise the line would be interpreted as the start of a continuation section.

Expressions starting with a double-deref, such as %varname% := 1. This is primarily due to implementation complexity.

Expressions that start with any of those described above (but not those described below) are also allowed, for simplicity. For example, MyFunc()+1 is currently allowed, although the +1 has no effect and its result is discarded. Such expressions might become invalid in the future due to enhanced error-checking.

Method calls which lack parentheses take the remainder of the line as their parameter list. For example, ExcelApp.Quit or x.y.z "my parameter". This is technically not an expression, but rather a method call statement.

Control Flow Statements

For a general explanation of control flow, see Control Flow.

Statements are grouped together into a block by enclosing them in braces {}, as in C, JavaScript and similar languages, but usually the braces must appear at the start of a line. Control flow statements can be applied to an entire block or just a single statement.

The body of a control flow statement is always a single group of statements. A block counts as a single group of statements, as does a control flow statement and its body. The following related statements are also grouped with each other, along with their bodies: If with Else; Loop/For with Until; Try with Catch and/or Finally. In other words, when a group of these statements is used as a whole, it does not always need to be enclosed in braces (however, some coding styles always include the braces, for clarity).

Control flow statements which have a body and therefore must always be followed by a related statement or group of statements: If, Else, Loop, While, For, Try, Catch and Finally.

The following control flow statements exist:

Control Flow vs. Other Statements

Control flow statements differ from function call statements in several ways:

Loop Statement

There are several types of loop statements:

Break exits (terminates) a loop, effectively jumping to the next line after the loop's body.

Continue skips the rest of the current loop iteration and begins a new one.

Until causes a loop to terminate when an expression evaluates to true. The expression is evaluated after each iteration.

A label can be used to "name" a loop for Continue and Break. This allows the script to easily continue or break out of any number of nested loops without using Goto.

The built-in variable A_Index contains the number of the current loop iteration. It contains 1 the first time the loop's body is executed. For the second time, it contains 2; and so on. If an inner loop is enclosed by an outer loop, the inner loop takes precedence. A_Index works inside all types of loops, but contains 0 outside of a loop.

For some loop types, other built-in variables return information about the current loop item (registry key/value, file, substring or line of text). These variables have names beginning with A_Loop, such as A_LoopFileName and A_LoopReadLine. Their values always correspond to the most recently started (but not yet stopped) loop of the appropriate type. For example, A_LoopField returns the current substring in the innermost parsing loop, even if it is used inside a file or registry loop.

t := "column 1`tcolumn 2`nvalue 1`tvalue 2"
Loop Parse t, "`n"
    rowtext := A_LoopField
    rownum := A_Index  ; Save this for use in the second loop, below.
    Loop Parse rowtext, "`t"
        MsgBox rownum ":" A_Index " = " A_LoopField

Loop variables can also be used outside the body of a loop, such as in a function or subroutine which is called from within a loop.

Not Control Flow

As directives, labels (including hotkeys and hotstrings), and declarations without assignments are processed when the script is loaded from file, they are not subject to control flow. In other words, they take effect unconditionally, before the script ever executes any control flow statements. Similarly, the #If directive cannot affect control flow; it merely sets the criteria for any hotkey labels and hotstrings specified in the code. A hotkey's criteria is evaluated each time it is pressed, not when the #If directive is encountered in the code.

Structure of a Script

Auto-execute Section

After the script has been loaded, it begins executing at the top line, continuing until a Return, Exit, the script's first hotkey/hotstring label, or the physical end of the script is encountered (whichever comes first). This top portion of the script is referred to as the auto-execute section, but it is really just a subroutine which is called after program startup.

Note: While the script's first hotkey/hotstring label has the same effect as return, other hotkeys and labels do not.

The auto-execute section is often used to configure settings which apply to every newly launched thread. For details, see The Top of the Script.


A subroutine (or sub) is a reusable block of code which can be called to perform some task.

Scripts use subroutines to define what should happen when a particular hotkey is pressed or some other event occurs. Scripts can also call subroutines directly, by using Gosub.

Any label can be used as the starting point of a subroutine. A subroutine has no explicitly marked ending point, but instead ends if and when control is returned to the subroutine's caller by Return or when the thread is exited. For example:

gosub Label1

MsgBox A_ThisLabel

Note that as labels have no effect when reached during normal execution, in this example a MsgBox would be shown twice: once while the subroutine is running and again after it returns. One important consequence is that you cannot define one subroutine inside another subroutine, because the "body" of the inner subroutine would execute automatically and then return, effectively terminating the outer subroutine.

Subroutines should typically be defined separately to any other block of code, but can also be defined inside a function, allowing the subroutine access to that function's static variables (and local variables, but only while the function is running).

Note: Subroutines defined inside a function have certain limitations regarding the use of local variables and dynamic variable references. For details, see Using Subroutines Within a Function.

User-Defined Functions

Generally speaking, a function is a kind of subroutine. However, within the AutoHotkey documentation, "subroutine" typically refers to the kind of subroutine defined by a label (described above).

User-defined functions differ from subroutines in that they can accept parameters and return a value, and they can have local variables. They can be called either by a function call within the script or by the program itself, such as if a function was passed to Hotkey or SetTimer.

Functions are defined using syntax resembling a function call followed by a block of code enclosed in braces:

MyFunction(FirstParameter, Second, ByRef Third, Fourth:="")
    return "a value"

As with function calls, there must be no space between the function name and open-parenthesis.

The line break between the close-parenthesis and open-brace is optional. There can be any amount of whitespace or comments between the two.

ByRef indicates that the parameter accepts a variable reference, making that parameter an alias for whichever variable the caller passes. If the caller does not pass a variable, the parameter acts as a normal local variable. ByRef parameters can also be optional.

Optional parameters are specified by following the parameter name with := and a default value, which must be a literal quoted string, a number, true or false.

The function can return a value. If it does not, the default return value is an empty string.

A function cannot be defined inside another function. Otherwise, the position of a function definition does not matter; any function defined within the script can be called from anywhere else.

See Functions for much more detail.


The #Include directive causes the script to behave as though the specified file's contents are present at this exact position. This is often used to organise code into separate files, or to make use of script libraries written by other users.

Note: The following paragraphs detail some common points of confusion.

When using #Include, it is important to consider what effect the file's contents would have if placed at that position, since #Include will have the same effect. For instance:

#Include can be safely used within the auto-execute section to include files which contain only function definitions, since function definitions (but not function calls) are skipped over during execution. If a file contains other code, one can avoid breaking the auto-execute section by skipping over the file's contents with Goto.

Unlike in C/C++, #Include does nothing if the file has already been included by a previous directive. To include the contents of the same file multiple times, use #IncludeAgain.

Script files containing functions can be automatically included without having to use #Include, if they are saved in a standard location and named appropriately. The effect is similar to using #Include at the end of the main script file. For details, see Libraries of Functions.


Dynamic Variables

A dynamic variable reference takes a text value and interprets it as the name of a variable.

The most common form of dynamic variable reference is called a double reference or double-deref. Before performing a double reference, the name of the target variable is stored in a second variable. This second variable can then be used to assign a value to the target variable indirectly, using a double reference. For example:

target := 42
second := "target"
MsgBox  second   ; Normal (single) variable reference => target
MsgBox %second%  ; Double-deref => 42

Currently, second must always contain a variable name in the second case; arbitrary expressions are not supported.

A dynamic variable reference can also take one or more pieces of literal text and the content of one or more variables, and join them together to form a single variable name. This is done simply by writing the pieces of the name and percent-enclosed variables in sequence, without any spaces. For example, MyArray%A_Index% or MyGrid%X%_%Y%. This is used to access pseudo-arrays, described below.


A pseudo-array is actually just a bunch of discrete variables, but with a naming pattern which allows them to be used like elements of an array. For example:

MyArray1 := "A"
MyArray2 := "B"
MyArray3 := "C"
Loop 3
    MsgBox MyArray%A_Index%  ; Shows A, then B, then C.

As the individual elements are just normal variables, one can assign or retrieve a value, but cannot remove or insert elements. Because the pseudo-array itself doesn't really exist, it can't be passed to or returned from a function, or copied as a whole. For these reasons, it is generally recommended to use normal arrays instead, where possible.

Associative pseudo-arrays

The "index" used to form the final variable name does not have to be numeric; it could instead be a letter or keyword, making the pseudo-array similar to an associative array or an object.


A label identifies a line of code, and can be used as a Goto target or to form a subroutine. There are three kinds of label: normal named labels, hotkey labels and hotstring labels.

Normal labels consist of a name followed by a colon.


Hotkey labels consist of a hotkey followed by double-colon.


Hotstring labels consist of a colon, zero or more options, another colon, an abbreviation and double-colon.


Generally, aside from whitespace and comments, no other code can be written on the same line as a label. However:

For more details, see Labels.