Skriptsprache

Ein AutoHotkey-Skript ist im Grunde eine Reihe von Instruktionen, die das Programm befolgen muss, geschrieben in einer benutzerdefinierten Sprache, die nur AutoHotkey versteht. Diese Sprache weist einige Ähnlichkeiten mit anderen Skriptsprachen auf, hat aber auch ihre eigenen Stärken und Schwächen. Dieses Dokument beschreibt die Sprache und versucht zudem, häufig auftretende Problemfälle aufzuzeigen.

Unter Konzepte und Konventionen finden Sie eine allgemeinere Erklärung der verschiedenen Konzepte, auf denen AutoHotkey basiert.

Es gibt zwei verschiedene Syntax-Stile, die in AutoHotkey verwendet werden können: Legacy-Syntax und Ausdrücke.

Inhaltsverzeichnis

Allgemeine Konventionen

Namen: Variablen- und Funktionsnamen sind nicht Groß-/Kleinschreibung-sensitiv (zum Beispiel ist AktuellesDatum dasselbe wie aktuellesdatum). Einzelheiten, einschließlich der maximalen Länge und der erlaubten Zeichen, finden Sie unter Namen.

Keine typisierten Variablen: Variablen haben keinen explizit definierten Typ; stattdessen kann jeder Variable (außer internen Variablen) ein beliebiger Wert zugewiesen werden. Es kann vorkommen, dass Zahlen je nach Situation automatisch in Zeichenketten (Text) umgewandelt werden und umgekehrt.

Deklarationen sind optional: Im Normalfall müssen Variablen nicht deklariert werden (in Funktionen gibt es Ausnahmen); Variablen werden erstellt, sobald sie verwendet werden (und enthalten zunächst eine leere Zeichenkette).

Leer- und Tabulatorzeichen werden meist ignoriert: Einrückungen (Leer- und Tabulatorzeichen am Anfang) sind nur für die Lesbarkeit des Codes wichtig, nicht für die Ausführung. Sie werden vom Programm nicht benötigt und werden in der Regel ignoriert. Leer- und Tabulatorzeichen werden grundsätzlich am Ende einer Zeile, innerhalb eines Ausdrucks (außer zwischen Anführungszeichen), und vor und nach Befehlsparametern ignoriert. In einigen Fällen sind diese Zeichen jedoch von Bedeutung:

Zeilenumbrüche sind von Bedeutung: Zeilenumbrüche dienen in der Regel als Trennzeichen für Anweisungen und terminieren den vorherigen Befehl oder Ausdruck. (Eine Anweisung ist einfach gesagt das kleinste eigenständige Element der Sprache, das eine ausführende Aktion ausdrückt.) Die Ausnahme davon ist die Zeilenfortsetzung (siehe unten).

Zeilenfortsetzung: Lange Zeilen können in mehrere kurze Zeilen aufgeteilt werden, um die Lesbarkeit und Wartbarkeit des Skripts zu verbessern. Dies erfolgt präprozedural, d.h. es ist nicht Teil der Sprache im eigentlichen Sinne. Es gibt zwei Methoden:

Kommentare

Kommentare sind Textbereiche innerhalb des Skripts, die vom Programm ignoriert werden. Sie werden in der Regel verwendet, um Erklärungen hinzuzufügen oder Teile des Codes zu deaktivieren.

Skripte können durch ein Semikolon am Anfang einer Zeile kommentiert werden. Zum Beispiel:

; Diese ganze Zeile ist ein Kommentar.

Kommentare können auch am Ende einer Zeile stehen - in diesem Fall muss links vom Semikolon mindestens ein Leer- oder Tabulatorzeichen stehen. Zum Beispiel:

Run Notepad  ; Dieser Kommentar steht auf derselben Zeile wie der Befehl.

Mit den Symbolen /* und */ können ganze Bereiche auskommentiert werden, allerdings müssen die Symbole am Anfang einer Zeile stehen (unabhängig von Leerraumzeichen). Zum Beispiel:

/*
MsgBox, Diese Zeile ist auskommentiert (deaktiviert).
MsgBox, Häufiger Fehler: */ Dies beendet nicht den Kommentar.
MsgBox, Diese Zeile ist auskommentiert. 
*/

Kommentare werden beim Start eines Skripts ignoriert und haben daher keinen Einfluss auf die Performanz oder Speicherauslastung.

Mit der #CommentFlag-Direktive kann das reguläre Kommentarzeichen (Semikolon) mit einem anderen Zeichen oder einer Zeichenkette überschrieben werden.

Ausdrücke (Expressions)

Ausdrücke sind Kombinationen beliebig vieler Werte, Variablen, Operatoren und Funktionsaufrufe. Zum Beispiel sind 10, 1+1 und MeineVar gültige Ausdrücke. Ein Ausdruck nimmt in der Regel einen oder mehrere Eingabewerte, führt eine oder mehrere Operationen durch, und erzeugt einen Ausgabewert. Die Prozedur, mit der der Wert eines Ausdrucks ermittelt wird, nennt sich Auswertung. Zum Beispiel wird der Ausdruck 1+1 zu der Zahl 2 ausgewertet.

Befehle sind so konzipiert, dass sie eine Liste von Parametern aufnehmen und nur eine einzige Aktion pro Zeile ausführen, während einfache Ausdrücke zu immer komplexeren Ausdrücken zusammengesetzt werden können. Wenn z.B. Rabatt/100 einen Rabattprozentsatz in eine Bruchzahl umwandelt, berechnet 1 - Rabatt/100 eine Bruchzahl, die den Restbetrag darstellt, während Preis * (1 - Rabatt/100) diese Bruchzahl verwendet, um den Nettopreis zu berechnen.

Werte sind Zahlen, Objekte oder Zeichenketten. Ein literaler Wert ist ein Wert, der physisch in das Skript geschrieben wird; also ein Wert, den Sie direkt im Code sehen können.

Zeichenketten / Text

Eine allgemeinere Erklärung von Zeichenketten finden Sie unter Zeichenketten (Strings).

Eine Zeichenkette ist einfach nur ein Textwert. In einem Ausdruck muss direkt geschriebener Text in Anführungszeichen gesetzt werden, um ihn von einem Variablennamen oder einem anderen Ausdruck zu unterscheiden. Dieser Zustand wird oft als in Anführungszeichen gesetzte, direkt geschriebene Zeichenkette oder einfach nur in Anführungszeichen gesetzte Zeichenkette bezeichnet. Zum Beispiel: "Dies ist eine in Anführungszeichen gesetzte Zeichenkette.".

Geben Sie zwei aufeinanderfolgende Anführungszeichen an, um ein tatsächliches Anführungszeichen in eine in Anführungszeichen gesetzte Zeichenkette einzufügen. Zum Beispiel: "Sie sagte: ""Ein Apfel täglich.""".

In Anführungszeichen gesetzte Zeichenketten können Escapesequenzen wie z.B. `t (Tabulator), `n (LF) und `r (CR) enthalten. Da in Anführungszeichen gesetzte Zeichenketten keine Variablen enthalten können, müssen Kommas und Prozentzeichen nicht mit einem Escapezeichen versehen werden; dies ist nur für anführungszeichenlose Texte notwendig. Die Nutzung der Escapesequenz `" zum Erzeugen eines direkt geschriebenen Anführungszeichens wird derzeit nicht unterstützt; nutzen Sie stattdessen zwei aufeinanderfolgende Anführungszeichen wie oben gezeigt.

Variablen

Eine grundlegende Erklärung und allgemeine Details zu Variablen finden Sie unter Variablen.

Um Variablen in einem Ausdruck zu verwenden, geben Sie einfach den Namen der Variable an. Zum Beispiel: A_ScreenWidth/2. Allerdings können Variablen nicht in einer in Anführungszeichen gesetzten Zeichenkette verwendet werden. Stattdessen greift man auf eine Vorgehensweise zurück, die sich Verkettung nennt, um Variablen und andere Werte zu kombinieren. Es gibt zwei Möglichkeiten, um Werte in einem Ausdruck zu verketten:

Implizite Verkettung wird auch Auto-Verkettung genannt. In beiden Fällen sind die Leerzeichen vor der Variable und dem Punkt zwingend erforderlich.

Alternativ können Sie auch die Format-Funktion verwenden. Zum Beispiel:

MsgBox % Format("Sie verwenden AutoHotkey v{1} {2}-Bit.", A_AhkVersion, A_PtrSize*8)

Um einer Variable einen Wert zuzuweisen, verwenden Sie den Zuweisungsoperator :=, wie in MeineVar := "Beliebiger Text".

Prozentzeichen innerhalb eines Ausdrucks werden verwendet, um dynamische Variablenreferenzen und dynamische Funktionsaufrufe zu erzeugen. In den meisten Fällen werden diese Konstrukte nicht benötigt, daher sollten Variablennamen innerhalb eines Ausdrucks generell nicht mit Prozentzeichen umschlossen werden.

Operatoren

Operatoren haben die Form eines Symbols oder einer Gruppe von Symbolen, wie z.B. + oder :=, oder eines der Wörter and, or, not oder new. Sie nehmen einen, zwei oder drei Eingabewerte und geben einen Ausgabewert zurück. Ein Wert oder Teilausdruck, der als Eingabe für einen Operator dient, nennt sich Operand.

Einige unäre und binäre Operatoren teilen sich die gleichen Symbole - in diesem Fall hängt die Bedeutung des Operators davon ab, ob er vor, nach oder zwischen zwei Werten geschrieben wird. Zum Beispiel führt x-y eine Subtraktion durch, während -x das Vorzeichen von x invertiert (einen positiven Wert aus einem negativen Wert erzeugen und umgekehrt).

Operatoren gleicher Priorität wie Multiplizieren (*) und Dividieren (/) werden von links nach rechts ausgewertet, sofern in der Operatorentabelle nichts anderes angegeben ist. Ein Operator mit niedrigerer Priorität wie Addieren (+) wird erst ausgewertet, wenn ein höherer Operator wie Multiplizieren (*) ausgewertet wurde. Zum Beispiel wird 3 + 2 * 2 als 3 + (2 * 2) ausgewertet. Die Priorität kann mit runden Klammern überschrieben werden. Zum Beispiel: (3 + 2) * 2

Funktionsaufrufe

Eine allgemeine Erklärung von Funktionen und verwandten Begriffen finden Sie unter Funktionen/Befehle.

Funktionen akzeptieren eine beliebige Anzahl von Eingabewerten, führen eine Aktion oder Berechnung durch und geben dann ein Ergebnis via Return zurück. Die Eingabewerte einer Funktion werden als Parameter oder Argumente bezeichnet. Um eine Funktion aufzurufen, geben Sie einfach ihren Namen gefolgt von ihren Parametern in runden Klammern an. GetKeyState("Shift") beispielsweise gibt 1 zurück (wird zu dieser Zahl ausgewertet), wenn Umschalt gedrückt gehalten wird, andernfalls 0.

Hinweis: Zwischen dem Funktionsnamen und der runden Startklammer darf kein Leerzeichen stehen.

Im Vergleich zu Befehlen mag die Notwendigkeit von runden Klammern auf den ersten Blick kryptisch oder umständlich erscheinen, aber gerade sie ermöglichen es, einen Funktionsaufruf mit anderen Operationen zu kombinieren. Zum Beispiel wird der Ausdruck GetKeyState("Shift", "P") and GetKeyState("Ctrl", "P") nur dann 1 zurückgeben, wenn beide Tasten physisch gedrückt gehalten werden.

Funktionsnamen sind immer global und können mit gleichnamigen Variablen koexistieren. Zum Beispiel kann Round sowohl ein Variablenname als auch Funktionsname sein, d.h. Round := 1 hat keine Auswirkung auf Round(n).

Operatoren für Objekte

Es gibt noch andere Symbole, die in Ausdrücken verwendet werden, die nicht ganz in eine der oben genannten Kategorien passen oder die einen Einfluss auf die Bedeutung anderer Teile des Ausdrucks haben, wie unten beschrieben. Diese Symbole beziehen sich alle in irgendeiner Weise auf Objekte. Eine vollständige Erklärung dessen, was jedes Konstrukt tut, würde die Einführung weiterer Konzepte erfordern, die nicht in den Geltungsbereich dieses Abschnitts fallen.

Alpha.Beta wird oft als Objektelementzugriff bezeichnet. Alpha ist eine gewöhnliche Variable und kann mit einem Funktionsaufruf oder einem anderen Teilausdruck, der ein Objekt zurückgibt, ersetzt werden. Beim Auswerten wird das Objekt mit der Anfrage konfrontiert, entweder den Wert oder die Eigenschaft Beta abzurufen, diesen Wert in die Eigenschaft Beta zu speichern oder die Methode namens Beta aufzurufen. Mit anderen Worten, Beta ist ein Name, der für das Objekt von Bedeutung ist; es ist keine lokale oder globale Variable.

Alpha.Beta() ist ein Methodenaufruf, wie oben beschrieben.

Alpha.Beta[Param] ist eine spezielle Form des Objektelementzugriffs, die zusätzliche Parameter in die Anfrage einbezieht. Während Beta ein einfacher Name ist, ist Param eine gewöhnliche Variable oder ein Teilausdruck, oder eine Liste von Teilausdrücken, die durch Kommas getrennt sind (wie in der Parameterliste einer Funktion).

Alpha[Index] funktioniert ähnlich wie Alpha.Beta, aber jeder Part wird in einer eher standardisierten Weise interpretiert. Das heißt, dass sowohl Alpha als auch Index in diesem Fall Variablen sind, die mit praktisch jedem Teilausdruck ersetzt werden können. Diese Syntax wird in der Regel verwendet, um ein Element eines Arrays oder eines assoziativen Arrays abzurufen.

new KlasseName() wird verwendet, um eine Klasse zu instanziieren oder ein Objekt zu erzeugen, das von einem anderen Objekt abgeleitet ist. Obwohl das wie ein Funktionsaufruf aussieht, ist KlasseName eigentlich nur eine gewöhnliche Variable. Ebenso würde new Alpha.Beta() ein Objekt erzeugen, das von einem Objekt abgeleitet ist, das von Alpha.Beta zurückgegeben wurde; Beta ist weder eine Funktion noch eine Methode. Wenn die optionalen runden Klammern vorhanden sind, können sie Parameter für die __New-Methode des Objekts enthalten.

[A, B, C] erzeugt ein Array mit den anfänglichen Inhalten von A, B und C (in diesem Fall alle Variablen), wobei A das Element 1 ist.

{Schlüssel1: Wert1, Schlüssel2: Wert2} erstellt ein assoziatives Array anhand einer Liste von Schlüssel-Wert-Paaren. Ein Wert kann später über den dazugehörigen Schlüssel abgerufen werden. Das Schreiben eines reinen Wortes (bestehend aus alphanumerischen Zeichen, Unterstrichen und ASCII-fremden Zeichen) auf der linken Seite von : ist dasselbe wie, als würde man dieses Wort in Anführungszeichen setzen. Zum Beispiel ist {A: B} dasselbe wie {"A": B}. {(A): B} hingegen nutzt den Inhalt der Variable A als Schlüssel.

MeineFunk(Params*) ist ein variadischer Funktionsaufruf. Das Sternchen muss unmittelbar vor der runden Endklammer am Ende der Parameterliste der Funktion stehen. Params muss eine Variable oder ein Teilausdruck, der ein Array-Objekt zurückgibt, sein. Obwohl Params* nicht überall erlaubt ist, kann es in einem direkt geschriebenen Array ([A, B, C, AnzufügendesArray*]) oder Indexer (Alpha[Params*]) verwendet werden.

Ausdrucksanweisungen

Nicht alle Ausdrücke können allein in einer Zeile stehen. Zum Beispiel würde eine Zeile, die nur aus 21*2 oder "Etwas Text" besteht, keinen Sinn ergeben. Die Ausdrucksanweisung ist ein eigenständiger Ausdruck, der in der Regel für seine Nebenwirkungen verwendet wird. Die meisten Ausdrücke mit Nebenwirkungen können auf diese Weise verwendet werden, daher ist es grundsätzlich nicht notwendig, sich die Details dieses Abschnitts zu merken.

Die folgenden Typen von Ausdrücken können als Anweisungen verwendet werden:

Zuweisungen, wie in x := y, Verbundzuweisungen wie x += y, und Inkrement-/Dekrementoperatoren wie ++x und x--. In AutoHotkey v1 verhalten sich ++, --, +=, -=, *= und /= allerdings etwas anders, wenn sie allein in einer Zeile stehen, da sie eigentlich äquivalent zu EnvAdd, EnvSub, EnvMult oder EnvDiv sind. Einzelheiten finden Sie im Abschnitt "Bekannte Einschränkungen" unter Zuweisung in der Operatorentabelle.

Funktionsaufrufe wie MeineFunk(Params). Nach einem alleinstehenden Funktionsaufruf sollte jedoch keine geschweifte Startklammer { (am Zeilenende oder auf der nächsten Zeile) folgen, da dies als Funktionsdeklaration fehlinterpretiert werden würde.

Methodenaufrufe wie MeinObj.MeineMethode().

Objektelementzugriff via eckige Klammern, wie z.B. MeinObj[Index], das Nebenwirkungen wie ein Funktionsaufruf haben kann.

Ausdrücke, die mit dem new-Operator beginnen, wie in new KlasseName, weil manchmal eine Klasse nur wegen ihrer Nebenwirkungen instanziiert werden kann.

Ternäre Ausdrücke wie x ? AufrufenWennTrue() : AufrufenWennFalse(). Es ist jedoch sicherer, die unten beschriebene Regel anzuwenden; also den Ausdruck (oder nur die Bedingung) immer mit Klammern zu umschließen.

Hinweis: Befehlsnamen haben in AutoHotkey v1 Vorrang vor ternären Ausdrücken. Zum Beispiel zeigt MsgBox ? 1 : 0 ein Mitteilungsfenster an.

Hinweis: Die Bedingung darf nicht mit ! oder einem anderen Ausdrucksoperator beginnen, da sie sonst als Fortsetzungszeile interpretiert werden würde.

Ausdrücke, die mit ( beginnen. In der Regel muss jedoch auf der gleichen Zeile ein entsprechendes ) stehen, sonst wird die Zeile als Beginn eines Fortsetzungsbereichs interpretiert.

Ausdrücke, die mit den oben genannten Elementen beginnen (aber nicht mit den unten genannten), sind aus praktischen Gründen ebenfalls erlaubt. Zum Beispiel ist MeineFunk()+1 derzeit erlaubt, obwohl +1 keine Wirkung hat und das Ergebnis verworfen wird. Solche Ausdrücke können in Zukunft durch eine erweiterte Fehlerprüfung ungültig werden.

Objektelementzugriff via Punkt (ein oder mehrmals), wie z.B. ExcelApp.Quit oder x.y.z. Solange keine runden Klammern verwendet werden (wie bei einem Methodenaufruf), kann diese Schreibweise nicht das Präfix eines größeren Ausdrucks sein. Zum Beispiel ist ExcelApp.Quit, xxx wegen der offensichtlichen Ähnlichkeit mit der Befehlssyntax nicht zulässig.

Legacy-Syntax

Die Legacy- bzw. Befehlssyntax erlaubt in der Regel nur eine einzige Aktion pro Zeile, benötigt aber weniger Zeichen, um einfache Aufgaben wie das Senden von Tastendrücken oder das Starten eines Programms auszuführen. Die Syntax besteht aus Befehls- und Variablennamen, anführungszeichenlosem Text und einigen wenigen Symbolen wie ,, = und %.

Anführungszeichenloser Text ist einfach nur Text, der nicht in Anführungszeichen gesetzt ist. Da der Text keine expliziten Start- und Endzeichen hat, endet er am Ende der Zeile oder am Ende des Parameters. Am Anfang und Ende befindliche Leer- und Tabulatorzeichen werden ignoriert. Innerhalb eines anführungszeichenlosen Textes haben die folgenden Zeichen eine besondere Bedeutung:

Befehle akzeptieren eine Mischung aus anführungszeichenlosem Text, Variablennamen und numerischen Ausdrücken.

Send, Es ist %A_Hour% Uhr.

Legacy-Zuweisung weist einer Variable einen anführungszeichenlosen Text zu.

Clipboard = Dieser Text wird in die Zwischenablage kopiert.

If-Anweisungen führen eine Aktion nur aus, wenn eine bestimmte Bedingung erfüllt ist.

If Var = Textwert

Es gibt auch einige Kontrollanweisungen (wie z.B. Schleifen), die ähnlich wie Befehle die Legacy-Syntax verwenden.

Befehle

Ein Befehl ist eine Aufforderung zum Ausführen einer bestimmten, vordefinierten Aktion. "Befehl" kann sich auch auf eine bestimmte vordefinierte Aktion beziehen, wie z.B. MsgBox. Der Satz an verfügbaren Befehlen ist vordefiniert und kann vom Skript nicht geändert werden.

Um einen Befehl aufzurufen, geben Sie einfach seinen Namen am Anfang einer Zeile an, optional gefolgt von Parametern. Zum Beispiel:

MsgBox, Es ist %A_Hour% Uhr.

Das Komma, das den Befehlsnamen von den Parametern trennt, ist optional, außer in den folgenden Fällen:

Jeder Parameter eines Befehls akzeptiert je nach Befehl eventuell eine andere Syntax. Es gibt vier verschiedene Parametertypen:

In den meisten Fällen kann das Prozentpräfix verwendet werden, um einen Ausdruck zu übergeben.

AusgabeVar- und EingabeVar-Parameter

AusgabeVar- und EingabeVar-Parameter benötigen einen Variablennamen oder eine dynamische Variablenreferenz. Zum Beispiel:

; Alle Leerzeichen mit Pluszeichen ersetzen:
StringReplace, NeueZkette, AlteZkette, %A_Space%, +, All

Dieser Befehl liest den Wert von AlteZkette (EingabeVar) und speichert das Ergebnis in NeueZkette (AusgabeVar).

Hinweis: Für AusgabeVar kann nur eine reine Variable verwendet werden. Array-Elemente, Eigenschaften und andere Ausdrücke werden nicht unterstützt.

EingabeVar-Parameter können einen Ausdruck nur akzeptieren, wenn das Prozentpräfix verwendet wird. Allerdings wird das Präfix in den Var-Parametern von Legacy-If-Befehlen nicht unterstützt; benutzen Sie stattdessen If (Ausdruck).

Textparameter

Textparameter akzeptieren einen anführungszeichenlosen Text. Zum Beispiel:

MsgBox, Es ist %A_Hour% Uhr.

Da Kommas und Prozentzeichen eine besondere Bedeutung haben, nutzen Sie die Escapesequenzen `, oder `%, um sie als direkt geschriebenen Text anzugeben. Um Missverständnissen vorzubeugen, ist es am besten, jedes Komma, das direkt geschrieben sein soll, mit einem Escapezeichen zu versehen. In den folgenden Fällen muss das nicht getan werden:

Um ein Leer- oder Tabulatorzeichen am Anfang oder Ende eines Parameters zu setzen, verwenden Sie die internen Variablen %A_Space% und %A_Tab% oder einen erzwungenen Ausdruck wie % " x ". [v1.1.06+]: Leer- oder Tabulatorzeichen am Zeilenanfang können auch durch Voranstellen eines Escapezeichens beibehalten werden.

Textparameter können auch einen erzwungenen Ausdruck akzeptieren.

Numerische Parameter

Numerische Parameter akzeptieren eine direkt geschriebene Zahl oder einen Ausdruck und können durch Formulierungen wie "Dieser Parameter kann ein Ausdruck sein" identifiziert werden.

Aus historischen Gründen werden einfache Variablenreferenzen, allein oder in Kombination mit Ziffern, nicht als Ausdrücke interpretiert. Zum Beispiel:

Sleep %n%000  ; Warte n Sekunden.
Sleep %m%     ; Warte m Millisekunden.

Um in solchen Fällen eine Doppeldereferenzierung (double-deref) durchzuführen, umschließen Sie den Ausdruck mit runden Klammern: Sleep (%m%)

Beachten Sie, dass Parameter gemischten Typs (wie der zweite Parameter von SetTimer, der manchmal eine Zahl oder eine Zeichenkette wie On oder Off akzeptiert) eigentlich Textparameter sind und als solche keine Ausdrücke akzeptieren, es sei denn, das Prozentpräfix wird verwendet.

Numerische Parameter erlauben das Prozentpräfix, ignorieren es aber.

% Ausdruck

Obwohl rein numerische Parameter standardmäßig einen Ausdruck akzeptieren, ist das bei allen anderen Befehlsparametern nicht der Fall. Geben Sie ein Prozentzeichen gefolgt von einem Leer- oder Tabulatorzeichen an, um einen Parameter dazu zu zwingen, einen Ausdruck zu akzeptieren. Die folgenden drei Beispiele sind funktionsgleich, da der erste Parameter von Sleep standardmäßig ein Ausdruck sein kann:

Sleep Wartezeit
Sleep %Wartezeit%
Sleep % Wartezeit

Hinweis: Die Verwendung des Prozent-Leerzeichen-Präfixes in einem numerischen Parameter führt nicht zwangsläufig dazu, dass der Parameter zu einem Ausdruck wird.

Alle Parameter unterstützen das Prozent-Leerzeichen-Präfix, außer:

Einige Benutzer bevorzugen es, immer einen Ausdruck zu erzwingen, um die Syntax so konsistent wie möglich zu halten (Ausdruckssyntax).

Konventionen in der Dokumentation

Oben auf jeder Seite, die einen Befehl dokumentiert, befindet sich in der Regel ein Block, der eine Syntax wie folgt zeigt:

StringLower, AusgabeVar, EingabeVar , T

Die eckigen Klammern kennzeichnen optionale Parameter; die Klammern selbst müssen im eigentlichen Code weggelassen werden.

Manchmal ist der Wert, den ein Parameter akzeptiert, direkt im Syntaxblock enthalten. Zum Beispiel akzeptiert der dritte Parameter von StringLower, wie oben gezeigt, den Buchstaben T als Text. Die genaue Verwendung eines Parameters ist im Abschnitt Parameter beschrieben und variiert je nach Befehl.

Optionale Parameter

Optionale Parameter können einfach leer gelassen werden. Das Komma vor einem optionalen Parameter kann auch weggelassen werden, wenn alle nachfolgenden Parameter weggelassen werden. Der Run-Befehl beispielsweise akzeptiert 1 bis 4 Parameter. Alle folgenden Zeilen sind gültig:

Run, notepad.exe, C:\
Run, notepad.exe,, Min
Run notepad.exe, , , notepadPID

Ausdrücke vs. Legacy-Syntax

Die meisten Befehlsparameter akzeptieren standardmäßig keine Ausdrücke. Benutzen Sie das Prozent-Leerzeichen-Präfix am Anfang eines Parameters, um diesen Parameter als Ausdruck auszuwerten. In den folgenden Beispielen ist der Ausdruck jeweils auf der ersten Zeile zu sehen (beginnend nach dem Prozentzeichen), während die reine Legacy-Syntax auf der zweiten Zeile angezeigt wird.

MsgBox % 1+1  ; Zeigt "2"
MsgBox   1+1  ; Zeigt "1+1"

Direkt geschriebener Text innerhalb eines Ausdrucks wird immer in Anführungszeichen gesetzt. Solche Texte werden als in Anführungszeichen gesetzte Zeichenketten bezeichnet.

MsgBox % "Das ist Text."
MsgBox    Das ist Text.

Variablen werden innerhalb eines Ausdrucks nie mit Prozentzeichen umschlossen, außer um eine Doppelreferenz zu erzeugen.

MsgBox %  A_AhkVersion
MsgBox   %A_AhkVersion%

Variablen können nicht in einer in Anführungszeichen gesetzten Zeichenkette verwendet werden.

MsgBox % "Hallo %A_UserName%."  ; Zeigt "%A_UserName%"
MsgBox    Hallo %A_UserName%.   ; Zeigt Ihren Benutzernamen.

Stattdessen verkettet man Werte. Um das zu tun, schreibt man sie nebeneinander und trennt sie entweder mit einem Leer- oder Tabulatorzeichen oder mit einem Punkt, der von Leerzeichen umschlossen ist.

MsgBox % "Hallo " . A_UserName . "."  ; Zeigt Ihren Benutzernamen.

Alternativ können Sie auch die Format-Funktion verwenden, die einen Parameterwert zudem auf verschiedene Arten formatieren kann.

MsgBox % Format("Hallo {1}.", A_UserName)  ; {} statt {1} funktioniert auch.

Um einer Variable einen Wert zuzuweisen, müssen Sie := anstelle von = verwenden:

MeineVar := "Das ist Text."
MeineVar = Das ist Text.

Um einen Vergleich durchzuführen, können Sie dieselben Symbole wie beim Legacy-If verwenden: =, <> oder !=, >, >=, < und <=.

if (Var1 = Var2)
if Var1 = %Var2%

In einem Ausdruck können beide Werte einfache Werte oder komplexe Teilausdrücke sein. Ein Vergleich kann auch mit anderen Bedingungen kombiniert werden, unter Nutzung von Operatoren wie z.B. and und or (bzw. && und ||).

if (Var1 >= Niedrig and Var1 <= Hoch)
if Var1 between %Niedrig% and %Hoch%  

Unterschiedlich funktionierende Gleichheitszeichen

Häufig wird der Fehler gemacht, = zu schreiben, wo eigentlich := notwendig ist. Zum Beispiel:

Total = A + B   ; Weist den direkt geschriebenen Text "A + B" zu

Diese Verwechslung ist schwer zu vermeiden (zumindest bis die Syntax der Legacy-Zuweisung entfernt wird), aber es kann hilfreich sein, immer := für eine Zuweisung zu verwenden.

Das Gleichheitszeichen (sofern es nicht mit einem anderen Symbol verwendet wird, wie z.B. <=) hat folgende Bedeutung:

Die ersten beiden Fälle können vermieden werden, indem man immer den Zuweisungsoperator := und if (Ausdruck) verwendet.

In den letzten drei Fällen hätte man := statt = verwenden können.

Befehle vs. Funktionen

In AutoHotkey v1 ist es derzeit nicht möglich, einen Befehl aus einem Ausdruck heraus aufzurufen oder eine Funktion über die Befehlssyntax aufzurufen. Einige Befehle haben jedoch eine Funktion als Ersatz.

BefehlErsatz
FileAppendFileOpen und File.Write
FileGetAttribFileExist
FileReadFileOpen und File.Read
GetKeyStateGetKeyState (die Funktion gibt 0 oder 1 zurück, nicht "U" oder "D")
IfExistFileExist
IfInStringInStr
IfWinActiveWinActive
IfWinExistWinExist
OnExitOnExit (die Funktion registriert eine Rückruffunktion, keine Subroutine)
StringGetPosInStr
StringLenStrLen
StringReplaceStrReplace
StringSplitStrSplit
StringLower
StringUpper
Format("{:L}", Eingabe), Format("{:U}", Eingabe) or Format("{:T}", Eingabe)
StringLeft
StringMid
StringRight
StringTrimLeft
StringTrimRight
SubStr

Kontrollanweisungen

Eine allgemeine Erklärung des Kontrollflusses finden Sie unter Kontrollfluss.

Um Anweisungen zu einem Block zusammenzufassen, umschließt man sie mit geschweiften Klammern {}, wie es auch in C, JavaScript und anderen ähnlichen Sprachen der Fall ist, allerdings müssen die Klammern in der Regel am Anfang einer Zeile stehen. Kontrollanweisungen können sich auf einen ganzen Block oder auf eine Einzelanweisung beziehen.

Der Körper einer Kontrollanweisung besteht immer aus einer Gruppe von Anweisungen. Ein Block zählt als eine Gruppe von Anweisungen, ebenso wie eine Kontrollanweisung und ihr Körper. Die folgenden verwandten Anweisungen werden ebenfalls mit ihren Körpern gruppiert: If mit Else; Loop/For mit Until; Try mit Catch und/oder Finally. Mit anderen Worten: Wenn eine Gruppe dieser Anweisungen als Ganzes verwendet wird, muss sie nicht immer mit geschweiften Klammern umschlossen werden (einige Programmierstile verwenden jedoch immer die geschweiften Klammern, aus Gründen der Übersichtlichkeit).

Kontrollanweisungen, die einen Körper haben und daher immer eine nachfolgende Anweisung oder eine Gruppe von Anweisungen haben müssen: If, Else, Loop, While, For, Try, Catch und Finally.

Es gibt folgende Kontrollanweisungen:

Kontrollfluss vs. Befehle

Kontrollanweisungen haben eine ähnliche Syntax wie Befehle und werden oft als solche bezeichnet, aber einige unterscheiden sich von Befehlen:

If-Anweisung

If (Ausdruck) wertet einen Ausdruck aus und führt die nachfolgende Anweisung nur aus, wenn das Ergebnis wahr ist.

Häufiger Anlass zu Verwirrung: Es gibt noch andere Arten von If-Anweisungen, von denen einige sehr ähnlich zu If (Ausdruck) sind. Diese sollten in neuen Skripten vermieden werden. Im Zweifelsfall ist es ratsam, den Ausdruck immer mit einer runden Startklammer zu beginnen. Die folgenden "Legacy"-If-Anweisungen sind damit gemeint:

Jede If-Anweisung, die nicht mit einem der oben Genannten übereinstimmt, wird als If (Ausdruck) interpretiert.

Die folgenden Punkte sind ein häufiger Anlass zu Verwirrung bei Legacy-If-Anweisungen:

Die folgenden benannten "Legacy"-If-Anweisungen sind ebenfalls vorhanden:

Mit Ausnahme von IfMsgBox sind sie alle veraltet und sollten in neuen Skripten generell vermieden werden.

Bei benannten If-Anweisungen kann ein Befehl auf derselben Zeile stehen, allerdings werden falsch geschriebene Befehlsnamen als direkt geschriebener Text behandelt. Solche Fehler können schnell übersehen werden.

Schleifenanweisung

Es gibt verschiedene Varianten von Schleifenanweisungen:

Break beendet (unterbricht) eine Schleife und springt zur nächsten Zeile nach dem Schleifenkörper.

Continue überspringt den Rest der aktuellen Schleifenwiederholung und beginnt eine neue.

Until unterbricht eine Schleife, wenn die Auswertung eines Ausdrucks False ergibt. Der Ausdruck wird nach jeder Wiederholung ausgewertet.

Ein Label kann verwendet werden, um eine Schleife für Continue und Break zu "benennen". Dadurch kann das Skript von einer inneren Schleife heraus den aktuellen Durchlauf einer äußeren Schleife überspringen oder die äußere Schleife unterbrechen, ohne Goto verwenden zu müssen.

Die interne Variable A_Index enthält die Nummer der aktuellen Schleifenwiederholung. Sie enthält 1, wenn der Körper der Schleife zum ersten Mal ausgeführt wurde. Beim zweiten Mal enthält sie 2 und so weiter. Wenn eine innere Schleife von einer äußeren Schleife umschlossen ist, hat die innere Schleife Vorrang. A_Index funktioniert in jeder Schleifenvariante, enthält aber außerhalb einer Schleife eine 0.

Einige Schleifenvarianten haben weitere interne Variablen, die Informationen über das aktuelle Schleifenelement liefern (Registry-Schlüssel/Wert, Datei, Teilzeichenkette oder Textzeile). Solche Variablen haben Namen, die mit A_Loop beginnen, wie z.B. A_LoopFileName und A_LoopReadLine. Ihre Werte gehören immer zur zuletzt gestarteten (aber noch nicht gestoppten) Schleife des entsprechenden Typs. Zum Beispiel gibt A_LoopField die aktuelle Teilzeichenkette der innersten Parsing-Schleife zurück, sogar wenn es innerhalb einer Datei- oder Registry-Schleife verwendet wird.

t := "Spalte 1`tSpalte 2`nWert 1`tWert 2"
Loop Parse, t, `n
{
    ZeileText := A_LoopField
    ZeileNummer := A_Index  ; Zur Verwendung in der zweiten Schleife unten speichern.
    Loop Parse, ZeileText, `t
    {
        MsgBox %ZeileNummer%:%A_Index% = %A_LoopField%
    }
}

Schleifenvariablen können auch außerhalb des Schleifenkörpers verwendet werden, z.B. in einer Funktion oder Subroutine, die aus einer Schleife heraus aufgerufen wird.

Kein Kontrollfluss

Da Direktiven, Labels (einschließlich Hotkeys und Hotstrings) und Deklarationen ohne Zuweisungen bereits verarbeitet werden, während das Skript aus der Datei geladen wird, unterliegen sie nicht dem Kontrollfluss. Das heißt, dass sie bedingungslos wirksam werden, bevor das Skript überhaupt Kontrollanweisungen ausführt. Auch #If-Direktiven wie #IfWinActive haben keinen Einfluss auf den Kontrollfluss; sie legen lediglich die Kriterien für die im Code angegebenen Hotkey- und Hotstring-Labels fest. Die Kriterien eines Hotkeys werden jedes Mal ausgewertet, wenn er gedrückt wird, nicht wenn die Ausführung auf die #If-Direktive trifft.

Aufbau eines Skripts

Automatischer Ausführungsbereich

Nachdem das Skript geladen wurde, beginnt die Ausführung bei der obersten Zeile, bis ein Return, Exit, das erste Hotkey-/Hotstring-Label oder das physische Ende des Skripts erreicht wird (je nachdem, was zuerst kommt). Dieser oberste Bereich des Skripts wird auch als automatischer Ausführungsbereich bezeichnet, ist aber eigentlich nur eine Subroutine, die nach dem Programmstart aufgerufen wird.

Hinweis: Während das erste Hotkey/Hotstring-Label des Skripts denselben Effekt wie Return hat, haben andere Hotkeys und Labels diesen nicht.

Der automatische Ausführungsbereich wird oft verwendet, um Einstellungen zu konfigurieren, die für jeden neuen Thread gelten. Weitere Informationen finden Sie unter Der Anfang des Skripts.

Subroutinen

Eine Subroutine (oder Sub) ist ein wiederverwendbarer Codeblock, der aufgerufen werden kann, um eine Aufgabe auszuführen.

Skripte verwenden Subroutinen, um zu definieren, was passieren soll, wenn ein bestimmter Hotkey gedrückt wird oder ein anderes Ereignis stattfindet. Skripte können Subroutinen auch direkt mit Gosub aufrufen.

Es kann ein beliebiges Label als Startpunkt einer Subroutine verwendet werden. Eine Subroutine hat keinen explizit markierten Endpunkt, sondern endet, wenn die Kontrolle via Return an den Aufrufer der Subroutine zurückgegeben wird oder wenn der Thread beendet wird. Zum Beispiel:

Gosub Label1

Label1:
MsgBox %A_ThisLabel%
return

Beachten Sie, dass Labels keinen Effekt haben, wenn sie während der normalen Ausführung erreicht werden, weshalb in diesem Beispiel das Mitteilungsfenster zweimal angezeigt wird: einmal beim Ausführen der Subroutine und nochmals, nachdem die Subroutine ihr Return erreicht hat. Es ist daher wichtig zu wissen, dass es nicht möglich ist, eine Subroutine innerhalb einer anderen Subroutine zu definieren, da der "Körper" der inneren Subroutine automatisch ausgeführt und dann via Return beendet wird, wodurch die äußere Subroutine terminiert wird.

Subroutinen sollten in der Regel getrennt von allen anderen Codeblöcken definiert werden, können aber auch innerhalb einer Funktion definiert werden, um der Subroutine den Zugriff auf die statischen Variablen dieser Funktion (und auf ihre lokalen Variablen, aber nur während der Ausführung der Funktion) zu ermöglichen.

Hinweis: Für Subroutinen, die innerhalb einer Funktion definiert sind, gelten bestimmte Einschränkungen hinsichtlich der Verwendung von lokalen Variablen und dynamischen Variablenreferenzen, einschließlich GUI-Steuerelement-Variablen. Weitere Informationen finden Sie unter Subroutinen innerhalb von Funktionen.

Benutzerdefinierte Funktionen

Im Prinzip ist eine Funktion eine Art Subroutine. In der AutoHotkey-Dokumentation bezieht sich der Begriff "Subroutine" jedoch in der Regel auf eine via Label definierte Subroutine (siehe oben).

Benutzerdefinierte Funktionen unterscheiden sich von Subroutinen dadurch, dass sie Parameter akzeptieren und einen Wert zurückgeben können, und dass sie lokale Variablen haben können. Sie können entweder durch einen Funktionsaufruf innerhalb des Skripts oder durch das Programm selbst aufgerufen werden, z.B. wenn eine Funktion an die Hotkey- oder SetTimer-Befehle übergeben wurde.

Funktionen werden mit einer Syntax definiert, die einem Funktionsaufruf ähnelt, gefolgt von einem Codeblock in geschweiften Klammern:

MeineFunktion(ErsterParameter, Zweiter, ByRef Dritter, Vierter:="")
{
    ...
    return "ein Wert"
}

Wie bei Funktionsaufrufen darf zwischen dem Funktionsnamen und der runden Startklammer kein Leerzeichen stehen.

Der Zeilenumbruch zwischen der runden Endklammer und der geschweiften Startklammer ist optional. Zwischen der runden Endklammer und der geschweiften Startklammer können beliebig viele Leerraumzeichen oder Kommentare stehen.

ByRef zeigt an, dass der Parameter eine Variablenreferenz akzeptiert, wodurch dieser Parameter ein Alias für jede Variable sein kann, die der Aufrufer übergibt. Wenn der Aufrufer keine Variable übergibt, verhält sich der Parameter wie eine normale lokale Variable. ByRef-Parameter können auch optional sein.

Um einen optionalen Parameter anzugeben, müssen Sie nach dem Parameternamen := oder = anfügen, gefolgt von einer direkt geschriebenen, in Anführungszeichen gesetzte Zeichenkette, einer Zahl, true oder false. Die Operatoren := und = sind aus historischen Gründen austauschbar, aber es ist ratsam, := zu verwenden, um mit Ausdruckszuweisungen konsistent zu sein.

Die Funktion kann einen Wert via Return zurückgeben. Wenn sie das nicht tut, gibt sie standardmäßig eine leere Zeichenkette zurück.

Eine Funktion kann nicht innerhalb einer anderen Funktion definiert werden. Andernfalls spielt die Position einer Funktionsdefinition keine Rolle; jede im Skript definierte Funktion kann von überall her aufgerufen werden.

Einzelheiten finden Sie unter Funktionen.

#Include

Die #Include-Direktive veranlasst das Skript, sich so zu verhalten, als wäre der Inhalt einer bestimmten Datei an genau dieser Stelle vorhanden. Dies wird oft verwendet, um Code in separate Dateien aufzuteilen oder um Skriptbibliotheken anderer Benutzer zu verwenden.

Hinweis: In den folgenden Absätzen werden Punkte behandelt, die für einige verwirrend sind.

Wenn Sie #Include verwenden, sollten Sie beachten, welchen Effekt der Inhalt der Datei hätte, wenn er an dieser Stelle stünde, da #Include denselben Effekt haben wird. Zum Beispiel:

#Include kann innerhalb des automatischen Ausführungsbereichs sicher verwendet werden, wenn die zu inkludierende Datei nur Funktionsdefinitionen enthält, da Funktionsdefinitionen (aber keine Funktionsaufrufe) während der Ausführung übersprungen werden. Wenn eine Datei Codezeilen enthält, die den automatischen Ausführungsbereich unterbrechen würden, verwenden Sie Goto, um den Inhalt dieser Datei zu überspringen.

Im Gegensatz zu C/C++ macht #Include nichts, wenn die Datei bereits durch eine frühere Direktive inkludiert wurde. Um den Inhalt einer Datei mehrfach zu inkludieren, verwenden Sie #IncludeAgain.

Skriptdateien, die Funktionen enthalten, können automatisch ohne #Include inkludiert werden, wenn sie in einem Standardverzeichnis gespeichert und entsprechend benannt sind. Der Effekt ist ähnelt der Verwendung von #Include am Ende der Hauptskriptdatei. Weitere Informationen finden Sie unter Funktionsbibliotheken.

Verschiedenes

Dynamische Variablen

Eine dynamische Variablenreferenz nimmt einen Textwert und interpretiert ihn als den Namen einer Variable.

Die bekannteste Form einer dynamischen Variablenreferenz nennt sich Doppeldereferenz oder double-deref. Bevor eine Doppeldereferenzierung erfolgt, muss der Name der Zielvariable in einer zweiten Variable gespeichert werden. Diese zweite Variable kann verwendet werden, um der Zielvariable indirekt einen Wert via Doppeldereferenzierung zuzuweisen. Zum Beispiel:

Ziel := 42
ZweiteVar := "Ziel"
MsgBox   %ZweiteVar%  ; Normale (einfache) Variablenreferenz in einem Text => Ziel
MsgBox %  ZweiteVar   ; Normale (einfache) Variablenreferenz in einem Ausdruck => Ziel
MsgBox % %ZweiteVar%  ; Doppeldereferenz in einem Ausdruck => 42

Auf den ersten Blick sieht es so aus, als hätten Prozentzeichen eine unterschiedliche Bedeutung, je nachdem, ob sie im Text oder in einem Ausdruck verwendet werden. Es ist jedoch sinnvoller anzunehmen, dass %ZweiteVar% in beiden Fällen mit dem Inhalt der Variable ZweiteVar ersetzt wurde:

Momentan muss ZweiteVar im zweiten Fall immer einen Variablennamen enthalten; beliebige Ausdrücke werden nicht unterstützt.

Eine dynamische Variablenreferenz kann auch einen oder mehrere direkt geschriebene Texte und den Inhalt einer oder mehrerer Variablen zu einem einzigen Variablennamen zusammenfassen. Schreiben Sie einfach die Bestandteile des Namens und die mit Prozentzeichen umschlossenen Variablen der Reihe nach ohne Leerzeichen auf. Zum Beispiel: MeinArray%A_Index% oder MeinRaster%X%_%Y%. Dies ermöglicht den Zugriff auf Pseudo-Arrays, wie unten beschrieben.

Eine Beschreibung, wie dynamische Variablenreferenzen innerhalb von Funktionen aufgelöst werden, finden Sie unter Funktionen: Mehr zu lokalen und globalen Deklarationen.

Pseudo-Arrays

Ein Pseudo-Array ist eigentlich nur ein Haufen einzelner Variablen, deren Namensmuster es aber möglich machen, sie wie Elemente eines Arrays zu verwenden. Zum Beispiel:

MeinArray1 = A
MeinArray2 = B
MeinArray3 = C
Loop 3
    MsgBox % MeinArray%A_Index%  ; Zeigt A, dann B, dann C.

Da es sich bei den einzelnen Elementen um normale Variablen handelt, kann man zwar einen Wert zuweisen oder abrufen, aber keine Elemente entfernen oder einfügen. Aufgrund der Tatsache, dass das Pseudo-Array eigentlich nicht existiert, kann es nicht an eine Funktion übergeben oder von einer Funktion zurückgegeben werden, oder als Ganzes kopiert werden. Aus diesen Gründen ist es in der Regel ratsam, normale Arrays wenn möglich zu verwenden.

Assoziative Pseudo-Arrays

Der "Index", mit dem der endgültige Variablenname gebildet wurde, muss nicht numerisch sein; er kann auch ein Buchstabe oder Schlüsselwort sein, um das Pseudo-Array ähnlich zu einem assoziativen Array oder einem Objekt zu machen. Das folgende Beispiel erzeugt ein Pseudo-Array mit den Elementen "Left", "Top", "Right" und "Bottom":

SysGet, WA, MonitorWorkArea
MsgBox, Links: %WALeft% -- Oben: %WATop% -- Rechts: %WARight% -- Unten: %WABottom%.

Pseudo-Array-erstellende Befehle

Es gibt mehrere Befehle, die assoziative Pseudo-Arrays erzeugen:

Achtung: Diese Befehle folgen nicht den Regeln einer dynamischen Variablenreferenz. Das resultierende Pseudo-Array ist, wenn es in einer Funktion verwendet wird, entweder vollständig global oder vollständig lokal, allein abhängig vom ersten Element (oder Basisnamen) des Arrays. Auf einige der Variablen im Pseudo-Array kann nur zugegriffen werden, wenn sie einzeln deklariert werden. Einzelheiten finden Sie unter Funktionen: Mehr zu lokalen und globalen Deklarationen.

AutoHotkey erstellt auch ein globales Pseudo-Array, das alle Befehlszeilenparameter enthält, die an das Skript übergeben wurden.

Labels

Ein Label identifiziert eine Codezeile und kann als Goto-Ziel oder zur Erstellung einer Subroutine verwendet werden. Es gibt drei verschiedene Arten von Labels: Normale benannte Labels, Hotkey-Labels und Hotstring-Labels.

Normale Labels bestehen aus einem Namen gefolgt von einem Doppelpunkt.

das_ist_ein_Label:

Hotkey-Labels bestehen aus einem Hotkey gefolgt von zwei Doppelpunkten.

^a::

Hotstring-Labels bestehen aus einem Doppelpunkt, beliebig vielen Optionen, einem weiteren Doppelpunkt, einer Abkürzung und zwei Doppelpunkten.

:*:bzw::

Abgesehen von Leerraumzeichen und Kommentaren darf grundsätzlich kein weiterer Code auf der Zeile eines Labels stehen. Allerdings:

Weitere Informationen finden Sie unter Labels.