Skriptsprache

Ein AutoHotkey-Skript ist im Grunde eine Reihe von Instruktionen, die das Programm befolgen muss und in einer benutzerdefinierten Sprache geschrieben ist, 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 die AutoHotkey basiert.

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

Inhaltsverzeichnis

Allgemeine Konventionen

Namen: Variablen- und Funktionsnamen sind nicht-Groß-/Kleinschreibung-sensitiv (zum Beispiel wäre AktuellesDatum das gleiche wie aktuellesdatum). Einzelheiten wie maximale Länge und verwendbare Zeichen finden Sie unter Namen.

Keine typisierten Variablen: Variablen haben keinen explizit definierten Typ; stattdessen kann ein beliebiger Wert in eine beliebige Variable (außer interne Variable) gespeichert werden. Zahlen können 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 zu Beginn eine leere Zeichenkette).

Leer- und Tabulatorzeichen werden größtenteils ignoriert: Einrückungen (führende Leer- und Tabulatorzeichen) sind wichtig, um den Code besser lesbar zu machen, allerdings werden sie nicht vom Programm 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. Allerdings sind solche Zeichen in einigen Fällen signifikant:

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 mehreren kurzen Zeilen aufgeteilt werden, um sie übersichtlicher zu machen. Dies erfolgt prä-prozedural; das heißt, dass sie im eigentlichen Sinne nicht zur Sprache gehört. Es gibt zwei Methoden:

Kommentare

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

Um in Skripten etwas zu kommentieren, muss am Anfang einer Zeile ein Semikolon gesetzt werden. Zum Beispiel:

; Diese ganze Zeile ist ein Kommentar.

Kommentare können auch am Ende einer Zeile stehen - in diesem Fall muss auf der linken Seite des Semikolons mindestens ein Leer- oder Tabulatorzeichen erfolgen. Zum Beispiel:

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

Mithilfe der Symbole /* und */ können ganze Bereiche auskommentiert werden, allerdings müssen die Symbole am Anfang einer Zeile stehen. 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 Starten eines Skripts ignoriert, daher haben sie keinerlei Einfluss auf die Performance oder Speicherauslastung.

Mithilfe der #CommentFlag-Direktive kann das standardmäßige Kommentarzeichen (Semikolon) mit einem anderen Zeichen oder einer Zeichenkette überschrieben werden.

Ausdrücke (Expressions)

Ausdrücke sind Kombinationen aus einem oder mehreren Werten, Variablen, Operatoren und Funktionsaufrufen. 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. Der Vorgang zum Herausfinden des Wertes eines Ausdrucks nennt man Auswertung. Der Ausdruck 1+1 wird beispielsweise 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 Rabatt/100 beispielsweise einen Rabattprozentsatz in eine Bruchzahl umwandelt, könnte man mit 1 - Rabatt/100 eine Bruchzahl errechnen, die den verbleibenden Betrag repräsentiert, und mit Preis * (1 - Rabatt/100) den Nettopreis errechnen.

Werte sind Zahlen, Objekte oder Zeichenketten. Ein literaler Wert ist ein Wert, der physisch in das Skript geschrieben wird; einer, den man sehen kann, wenn man auf den Code schaut.

Zeichenketten / Text

Eine allgemeinere Erklärung zu 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.".

Um ein tatsächliches Anführungszeichen in eine in Anführungszeichen gesetzte Zeichenkette einzufügen, gibt man wie folgt zwei aufeinanderfolgende Anführungszeichen an: "Sie sagte: ""Ein Apfel täglich.""".

In Anführungszeichen gesetzte Zeichenketten können Escapesequenzen wie z. B. `t (Tabulator), `n (LF-Zeilenumbruchszeichen) und `r (CR-Zeilenumbruchszeichen) 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 Texte ohne Anführungszeichen notwendig. Das Verwenden der Escapesequenz `" zum Erzeugen eines direkt geschriebenen Anführungszeichens wird aktuell 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 nutzen, schreibt man einfach den Namen der Variable. 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 Wege, um Werte in einem Ausdruck zu verketten:

Implizite Verkettung wird auch Auto-Verkettung genannt. In beiden Fällen müssen die Leerzeichen vor der Variable und der Punkt vorhanden sein.

Die Format-Funktion kann auch für diesen Zweck genutzt werden. Zum Beispiel:

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

Um einer Variable einen Wert zuzuweisen, nutzt man den Zuweisungsoperator :=, wie z. B. in MeineVar := "Beliebiger Text".

Prozentzeichen innerhalb eines Ausdrucks werden genutzt, um dynamische Variablenreferenzen und dynamische Funktionsaufrufe zu erzeugen. Meistens werden diese Konstrukte nicht benötigt, daher sollten Variablennamen generell nicht mit Prozentzeichen innerhalb eines Ausdrucks 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, wird als Operand bezeichnet.

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 von einem negativen Wert erzeugen und umgekehrt).

Operatoren gleicher Priorität wie Multiplizieren (*) und Dividieren (/) werden von links nach rechts ausgewertet, sofern nicht anders in der Operatorentabelle angegeben. Ein Operator mit niedrigerer Priorität wie Addieren (+) wird erst ausgewertet, wenn ein höherer Operator wie Multiplizieren (*) ausgewertet wurde. Zum Beispiel würde 3 + 2 * 2 als 3 + (2 * 2) ausgewertet werden. Mit runden Klammern können die Prioritäten überschrieben werden. Zum Beispiel: (3 + 2) * 2

Funktionsaufrufe

Eine allgemeine Erläuterung zu Funktionen und verwandter Fachbegriffe finden Sie unter Funktionen/Befehle.

Funktionen nehmen eine unterschiedliche 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, schreibt man einfach ihren Namen, gefolgt von den Parametern, die in Klammern gesetzt sind. GetKeyState("Shift") beispielsweise gibt 1 zurück (wird zu dieser Zahl ausgewertet), wenn die Umschalt-Taste gedrückt gehalten wird, oder 0, wenn nicht.

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

Im Vergleich zu Befehlen mag die Forderung nach Klammern zunächst 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") erst eine 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 Variablen- als auch ein Funktionsname sein; das heißt, dass Round := 1 keinerlei Auswirkung auf Round(n) haben wird.

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 die Bedeutung anderer Teile des Ausdrucks beeinflussen, wie unten beschrieben. Diese Symbole beziehen sich alle irgendwie auf Objekte. Eine vollständige Erläuterung 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. Das heißt, dass Beta ein Name ist, der eine Bedeutung für das Objekt hat; 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] hat eine ähnliche Funktion 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önnten. Diese Syntax wird in der Regel genutzt, um ein Element eines Arrays oder eines assoziativen Arrays abzurufen.

new Klassenname() wird genutzt, um eine Klasse zu instanziieren oder ein Objekt zu erzeugen, das von einem anderen Objekt abgeleitet ist. Obwohl dies wie ein Funktionsaufruf aussieht, ist Klassenname eigentlich nur eine gewöhnliche Variable. Ebenso würde new Alpha.Beta() ein Objekt erzeugen, das von einem Objekt, das von Alpha.Beta zurückgegeben wurde, abgeleitet ist; 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.

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

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ügenderArray*]) oder Indexer (Alpha[Params*]) verwendet werden.

Ausdrucksanweisungen

Nicht alle Ausdrücke sollten allein auf 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 als normal, wenn sie allein auf einer Zeile stehen, da sie eigentlich das Äquivalent zu EnvAdd, EnvSub, EnvMult oder EnvDiv sind. Einzelheiten finden Sie bei "Bekannte Einschränkungen" unter Zuweisung in der Operatorentabelle.

Funktionsaufrufe wie MeineFunk(Params). Nach einem alleinstehenden Funktionsaufruf kann jedoch keine geschweifte Startklammer { (am Zeilenende oder auf der nächsten Zeile) erfolgen, 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 Klassenname, weil manchmal eine Klasse nur wegen ihrer Nebenwirkungen instanziiert werden kann.

Ternäre Ausdrücke wie x ? AufrufenWennTrue() : AufrufenWennFalse(). In AutoHotkey v1 haben Befehlsnamen jedoch Vorrang. MsgBox ? 1 : 0 beispielsweise zeigt ein Mitteilungsfenster an.

Ausdrücke, die mit ( beginnen. In der Regel muss jedoch auf der gleichen Zeile ein entsprechendes ) stehen, sonst wird die Zeile als Anfang 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 momentan 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 genutzt 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.

Altmodische Syntax

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

Text ohne Anführungszeichen ist einfach nur Text, der nicht in Anführungszeichen gesetzt ist. Da der Text keine expliziten Start- und Endezeichen hat, endet er am Ende der Zeile oder am Ende des Parameters. Davor- oder dahinterliegende Leer- und Tabulatorzeichen werden ignoriert. Innerhalb eines Textes ohne Anführungszeichen haben die folgenden Zeichen eine besondere Bedeutung:

Befehle akzeptieren eine Mischung aus Text ohne Anführungszeichen, Variablennamen und numerischen Ausdrücken.

Send, Es ist %A_Hour% Uhr.

Altmodische Zuweisung weist einer Variable einen Text ohne Anführungszeichen 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 Ablaufsteuerungsanweisungen (wie z. B. Schleifen), die wie Befehle die altmodische 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 nicht vom Skript geändert werden.

Um einen Befehl aufzurufen, schreibt man einfach seinen Namen an den Anfang der Zeile, optional gefolgt von Parametern. Zum Beispiel:

MsgBox, Es ist %A_Hour% Uhr.

Das Komma, das den Befehlsnamen von seinen 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 Typen von Parametern:

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

AusgabeVar- und EingabeVar-Parameter

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

; Ersetze alle Leerzeichen mit Pluszeichen:
StringReplace, NeueZkette, AlteZkette, %A_Space%, +, All

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

Hinweis: Nur eine reine Variable kann als AusgabeVar genutzt 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 altmodischen If-Befehlen nicht unterstützt; benutzen Sie stattdessen If (Ausdruck).

Textparameter

Textparameter akzeptieren Text ohne Anführungszeichen. Zum Beispiel:

MsgBox, Es ist %A_Hour% Uhr.

Da Kommas und Prozentzeichen eine besondere Bedeutung haben, sollte man die Escapesequenzen `, oder `% angeben, wenn sie als direkt geschriebener Text interpretiert werden sollen. 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 an den Anfang oder Ende eines Parameters zu setzen, nutzt man die internen Variablen %A_Space% und %A_Tab% oder einen erzwungenen Ausdruck wie % " x ". [v1.1.06+]: Leer- oder Tabulatorzeichen können auch beibehalten werden, indem man sie mit einem Escapezeichen versieht, außer am Zeilenende.

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, einzeln 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 durchzuführen, umschließt man den Ausdruck mit runden Klammern: Sleep (%m%)

Beachten Sie, dass gemischte Parameter wie SetTimer's zweiter Parameter, 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 aber ignorieren das Prozentpräfix.

% 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 funktional identisch, da Sleep's erster Parameter standardmäßig ein Ausdruck sein kann:

Sleep MillisekundenWarten
Sleep %MillisekundenWarten%
Sleep % MillisekundenWarten

Hinweis: Die Verwendung des Prozent-Leerzeichen-Präfixes in einem numerischen Parameter führt nicht zwangsläufig dazu, dass er 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

Im oberen Bereich 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. Zum Beispiel kann der Run-Befehl ein bis vier Parameter akzeptieren. Alle folgenden Zeilen sind gültig:

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

Ausdrücke vs. altmodische Syntax

Viele 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 altmodische 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. So ein Text wird in Anführungszeichen gesetzte Zeichenkette genannt.

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 nutzen, die einen Parameterwert zudem auf verschiedene Weise formatieren kann.

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

Um einer Variable einen Wert zuzuweisen, nutzt man := anstelle von =:

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

Um einen Vergleich durchzuführen, nutzt man dieselben Symbole wie beim altmodischen If: =, <> 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 mithilfe der Operatoren and und or (bzw. && und ||) auch mit anderen Bedingungen kombiniert werden.

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

Dieses Problem lässt sich nur schwer vermeiden (zumindest solange, bis die Syntax der altmodischen Zuweisung entfernt wird), aber es kann hilfreich sein, immer := zu verwenden, wo eine Zuweisung beabsichtigt ist.

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
StringGetPosInStr
StringLenStrLen
StringReplaceStrReplace
StringSplitStrSplit
StringLower
StringUpper
Format("{:L}", Eingabe), Format("{:U}", Eingabe) or Format("{:T}", Eingabe)
StringLeft
StringMid
StringRight
StringTrimLeft
StringTrimRight
SubStr

Ablaufsteuerungsanweisungen

Eine allgemeine Erläuterung zur Ablaufsteuerung finden Sie unter Ablaufsteuerung.

Um Anweisungen zu einem Block zusammenzufassen, umschließt man sie mit geschweiften Klammern {}, wie in C, JavaScript und anderen ähnlichen Sprachen, allerdings müssen die Klammern in der Regel am Anfang einer Zeile stehen. Ablaufsteuerungsanweisungen können auf einen ganzen Block oder nur auf eine einzelne Anweisung angewendet werden.

Der Körper einer Ablaufsteuerungsanweisung besteht immer aus einer einzigen Gruppe von Anweisungen. Ein Block zählt als eine Gruppe von Anweisungen, ebenso wie eine Ablaufsteuerungsanweisung 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. Wenn also eine Gruppe dieser Anweisungen als Ganzes verwendet wird, muss sie nicht immer mit geschweiften Klammern umschlossen werden (einige Programmierstile enthalten jedoch aus Gründen der Übersichtlichkeit immer die geschweiften Klammern).

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

Es gibt die folgenden Ablaufsteuerungsanweisungen:

Ablaufsteuerung vs. Befehle

Ablaufsteuerungsanweisungen haben eine Syntax, die den Befehlen ähnelt, und werden oft als solche bezeichnet, aber einige unterscheiden sich von Befehlen:

If-Anweisung

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

Häufiger Anlass zu Verwirrung: Es gibt noch andere Typen von If-Anweisungen, die sehr ähnlich aussehen wie If (Ausdruck). Diese sollten in neuen Skripten vermieden werden. Im Zweifelsfall ist es ratsam, den Ausdruck immer mit einer runden Startklammer zu beginnen. Folgende "altmodische" If-Anweisungen sind damit gemeint:

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

Folgende Punkte sind häufige Anlässe zu Verwirrung in Bezug auf altmodische If-Anweisungen:

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

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

Benannte If-Anweisungen erlauben, dass ein Befehl auf die gleiche Zeile geschrieben werden kann, allerdings werden falsch geschriebene Befehlsnamen als direkt geschriebener Text behandelt. Solche Fehler sind nur schwer zu erkennen.

Loop-Anweisung

Es gibt verschiedene Typen von Loop-Anweisungen:

Break verlässt (terminiert) eine Schleife und bewirkt dadurch, dass die Zeile nach dem Schleifenkörper angesprungen wird.

Continue überspringt den Rest der aktuellen Schleife und beginnt einen neuen Durchlauf.

Until lässt eine Schleife terminieren, wenn ein Ausdruck als True gewertet wird. Der Ausdruck wird nach jedem Schleifendurchlauf ausgewertet.

Ein Label kann genutzt werden, um eine Schleife für Continue und Break zu "benennen". Auf diese Weise kann das Skript einfach eine beliebige Anzahl an verschachtelten Schleifen fortsetzen oder unterbrechen, ohne Goto verwenden zu müssen.

Die interne Variable A_Index enthält die Nummer des aktuellen Schleifendurchlaufs. Sie enthält eine 1, wenn der Schleifenkörper das erste Mal durchgeführt wurde. Beim zweiten Mal enthält sie eine 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, aber außerhalb einer Schleife enthält sie eine 0.

Einige Schleifentypen haben noch andere interne Variablen, die Informationen über das aktuelle Schleifenelement liefern (Registry-Key/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 der zuletzt gestarteten (aber noch nicht gestoppten) Schleife des entsprechenden Typs. A_LoopField beispielsweise gibt die aktuelle Teilzeichenkette der innersten Parsing-Schleife zurück, auch wenn sie innerhalb einer Datei- oder Registry-Schleife verwendet wird.

t := "Spalte 1`tSpalte 2`nWert 1`tWert 2"
Loop Parse, t, `n
{
    Reihentext := A_LoopField
    Reihennummer := A_Index  ; Für die Verwendung in der zweiten Schleife unten speichern.
    Loop Parse, Reihentext, `t
    {
        MsgBox %Reihennummer%:%A_Index% = %A_LoopField%
    }
}

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

Keine Ablaufsteuerung

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

Aufbau eines Skripts

Automatischer Ausführungsbereich

Das Skript startet, sofern es erfolgreich geladen wurde, bei der ersten Zeile und endet, wenn es entweder ein Return, Exit, den ersten Hotkey-/Hotstring-Label im Skript oder das physische Ende des Skripts erreicht hat (je nachdem was zuerst kommt). Dieser obere Bereich des Skripts wird auch als automatischer Ausführungsbereich bezeichnet, aber tatsächlich ist er nur eine Subroutine, die nach dem Programmstart aufgerufen wird.

Hinweis: Während das erste Hotkey/Hotstring-Label im Skript die gleiche Wirkung wie Return hat, haben andere Hotkeys und Label dies nicht.

Der automatische Ausführungsbereich wird oft genutzt, um Einstellungen zu konfigurieren, die für jeden neu gestarteten Thread gelten. Weitere Informationen finden Sie unter Der obere Bereich des Skripts.

Subroutinen

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

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

Es kann ein beliebiges Label als Startpunkt einer Subroutine bestimmt 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 aufgrund der Tatsache, dass Label wirkungslos sind, wenn sie während einer normalen Ausführung erreicht werden, das Mitteilungsfenster in diesem Beispiel zweimal angezeigt wird: einmal beim Ausführen der Subroutine und nochmals, nachdem die Subroutine ihr Return erreicht hat. Deshalb ist 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 beendet wird.

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

Hinweis: Subroutinen, die innerhalb einer Funktion definiert sind, haben gewisse Einschränkungen hinsichtlich der Verwendung von lokalen Variablen und dynamischen Variablenreferenzen, einschließlich GUI-Steuerelement-Variablen. Weitere Informationen finden Sie unter Verwenden von Subroutinen innerhalb einer Funktion.

Benutzerdefinierte Funktionen

Grundsätzlich ist eine Funktion so etwas wie eine Subroutine. In der AutoHotkey-Dokumentation bezieht sich "Subroutine" jedoch in der Regel auf die Art der Subroutine, die via Label definiert ist (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, der mit geschweiften Klammern umschlossen ist:

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

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

Der Zeilenumbruch zwischen der runden Endklammer und der geschweiften Startklammer ist optional. Es kann eine beliebige Anzahl von Leerraumzeichen oder Kommentaren zwischen den beiden sein.

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, fügt man nach dem Parameternamen := oder = an, 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 die Konsistenz mit Ausdruckszuweisungen zu bewahren.

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. Ansonsten 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 separaten Dateien aufzuteilen oder um Skriptbibliotheken anderer Benutzer zu nutzen.

Hinweis: In den folgenden Abschnitten werden einige Punkte aufgeführt, die viele Leute verwirrend finden.

Wenn Sie #Include verwenden, sollten Sie beachten, welchen Effekt der Inhalt der Datei haben würde, wenn er an dieser Stelle platziert werden würde, da #Include denselben Effekt hat. Zum Beispiel:

#Include kann innerhalb des automatischen Ausführungsbereichs sicher verwendet werden, wenn die einzubeziehende Datei nur Funktionsdefinitionen enthält, da Funktionsdefinitionen (aber keine Funktionsaufrufe) während der Ausführung übersprungen werden. Um zu verhindern, dass eine Datei andere Codezeilen ausführt und dadurch den automatischen Ausführungsbereich unterbricht, überspringt man mithilfe von Goto den Inhalt dieser Datei.

Im Gegensatz zu C/C++ macht #Include nichts, wenn die Datei bereits von einer früheren Direktive eingebunden wurde. Um den Inhalt einer Datei mehrfach einzubinden, nutzt man #IncludeAgain.

Skriptdateien, die Funktionen enthalten, können automatisch ohne #Include eingebunden werden, wenn sie in einem Standardverzeichnis gespeichert und entsprechend benannt sind. Der Effekt ist das gleiche wie, als würde man #Include am Ende der Hauptskriptdatei nutzen. Weitere Informationen finden Sie unter Funktionsbibliotheken.

Verschiedenes

Dynamische Variablen

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

Die bekannteste Form einer dynamischen Variablenreferenz nennt sich Doppelreferenzierung oder double-deref. Bevor man eine Doppelreferenzierung durchführen kann, muss der Name der Zielvariable in einer zweiten Variable gespeichert sein. Diese zweite Variable kann genutzt werden, um der Zielvariable indirekt einen Wert via Doppelreferenzierung 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%  ; Doppelreferenzierung in einem Ausdruck => 42

Zunächst scheint es so, dass Prozentzeichen eine unterschiedliche Bedeutung haben, je nachdem, ob sie im Text oder in einem Ausdruck verwendet werden. Sinnvoller ist es jedoch 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 zusammenfügen. Dazu schreibt man 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%. Mit dieser Methode kann man auf Pseudo-Arrays zugreifen, wie unten beschrieben.

Eine Beschreibung, wie dynamische Variablenreferenzen innerhalb von Funktionen aufgelöst werden, finden Sie unter Funktionen: Mehr über lokale und globale Variablen.

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 genutzt wird, entweder vollständig global oder vollständig lokal, allein abhängig vom ersten Element (bzw. dem Basisnamen) des Arrays. Einige der Variablen im Pseudo-Array sind eventuell nur abrufbar, wenn sie einzeln deklariert werden. Einzelheiten finden Sie unter Funktionen: Mehr über lokale und globale Variablen.

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

Label

Ein Label identifiziert eine Codezeile. Es dient als Ziel von Goto oder formt eine Subroutine. Es gibt drei verschiedene Labeltypen: Normale benannte Label, Hotkey-Label und Hotstring-Label.

Normale Label bestehen aus einem Namen, gefolgt von einem Doppelpunkt.

das_ist_ein_Label:

Hotkey-Label bestehen aus einem Hotkey, gefolgt von zwei Doppelpunkten.

^a::

Hotstring-Label bestehen aus einem Doppelpunkt, null oder mehr Optionen, einem weiteren Doppelpunkt, einer Abkürzung und zwei Doppelpunkten.

:*:bzw::

Grundsätzlich darf, außer Leerraumzeichen und Kommentare, kein anderer Code auf der Zeile eines Labels stehen. Allerdings:

Weitere Informationen finden Sie unter Label.