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.

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 Konstanten und 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). Allerdings wird der Versuch, eine Variable zu lesen, bevor ihr ein Wert zugewiesen wurde, als Fehler gewertet.

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 und innerhalb eines Ausdrucks (außer zwischen Anführungszeichen) 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 Funktionsaufruf oder andere Anweisung. (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 drei 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 Funktionsaufruf.

Mit den Symbolen /* und */ können ganze Bereiche auskommentiert werden. Zum Beispiel:

/*
MsgBox "Diese Zeile ist auskommentiert (deaktiviert)."
MsgBox "Häufiger Fehler:" */ " Dies beendet nicht den Kommentar."
MsgBox "Diese Zeile ist auskommentiert."
*/
MsgBox "Diese Zeile ist nicht auskommentiert."
/* Dies ist auch gültig, aber auf dieser Zeile darf kein anderer Code stehen. */
MsgBox "Diese Zeile ist nicht auskommentiert."

Unabhängig von Tabulator- und Leerzeichen muss /* am Anfang der Zeile stehen, während */ nur am Anfang oder Ende einer Zeile stehen kann. Es ist auch möglich, */ wegzulassen - in diesem Fall wird der Rest der Datei auskommentiert.

Kommentare werden herausgefiltert, wenn das Skript aus der Datei gelesen wird, und haben daher keinen Einfluss auf die Performanz oder Speicherauslastung.

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.

Einfache Ausdrücke können zu immer komplexeren Ausdrücken zusammengesetzt werden. 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 einfachen oder doppelten 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." oder 'diese auch'.

Um ein tatsächliches Anführungszeichen in eine direkt geschriebene Zeichenkette einzufügen, verwenden Sie die Escapesequenz `" oder `' oder umschließen Sie das Zeichen mit gegenteiligen Anführungszeichen. Zum Beispiel: 'Sie sagte: "Ein Apfel täglich."'.

In Anführungszeichen gesetzte Zeichenketten können andere Escapesequenzen wie z.B. `t (Tabulator), `n (LF) und `r (CR) enthalten.

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 zu erzeugen, werden aber selten benötigt.

Konstanten

Eine Konstante ist nichts anderes als ein unveränderlicher Wert mit einem symbolischen Namen. AutoHotkey verfügt derzeit über die folgenden Konstanten:

NameWertTypeBeschreibung
False0IntegerBoolesches Falsch/Unwahr, bedeutet manchmal "aus", "nein" usw.
True1IntegerBoolesches Wahr, bedeutet manchmal "an", "ja" usw.

Im Gegensatz zu den schreibgeschützten internen Variablen, können diese nicht von einer dynamischen Referenz zurückgegeben 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, is, in oder contains. 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 Erläuterung von Funktionen und verwandten Begriffen finden Sie unter Funktionen.

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 die Zielfunktion gefolgt von 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 der Funktion und der runden Startklammer darf kein Leerzeichen stehen.

Für angehende Programmierer 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.

Obwohl ein Funktionsaufrufausdruck normalerweise mit einem direkt geschriebenen Funktionsnamen beginnt, kann das Ziel des Aufrufs ein beliebiger Ausdruck sein, der ein Funktionsobjekt erzeugt. Im Ausdruck GetKeyState("Shift") ist GetKeyState eigentlich eine Variablenreferenz, obwohl sie üblicherweise auf eine schreibgeschützte Variable verweist, die eine interne Funktion enthält.

Funktionsaufrufanweisungen

Wenn der Rückgabewert der Funktion nicht benötigt wird und der Funktionsname am Zeilenanfang steht (oder in einem anderen Kontext, wo eine Anweisung erlaubt ist, z.B. nach einem else oder einem Hotkey), können die Klammern weggelassen werden. In diesem Fall wird der Rest der Zeile als Parameterliste der Funktion interpretiert. Zum Beispiel:

Ergebnis := MsgBox("Dies benötigt runde Klammern.",, "OKCancel")
MsgBox "Dies nicht. Das Ergebnis war " Ergebnis "."

Im gleichen Kontext können die runden Klammern auch bei einem Methodenaufruf weggelassen werden, aber nur, wenn das Zielobjekt entweder eine Variable oder eine direkt benannte Eigenschaft ist, z.B. meineVar.meineMethode oder meineVar.meineEigenschaft.meineMethode.

Wie bei Funktionsaufrufausdrücken muss das Ziel einer Funktionsaufrufanweisung keine vordefinierte Funktion sein; es kann stattdessen eine Variable sein, die ein Funktionsobjekt enthält.

Eine Funktionsaufrufanweisung kann sich über mehrere Zeilen erstrecken.

Für Funktionsaufrufanweisungen gelten die folgenden Einschränkungen:

Optionale Parameter

Optionale Parameter können einfach leer gelassen werden, allerdings ist das Komma als Trennzeichen weiterhin notwendig, es sei denn, alle nachfolgenden Parameter werden ebenfalls weggelassen. Die Run-Funktion beispielsweise akzeptiert 1 bis 4 Parameter. Alle folgenden Zeilen sind gültig:

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

Innerhalb eines Funktionsaufrufs, eines direkt geschriebenen Arrays oder eines direkt geschriebenen Objekts kann das Schlüsselwort unset verwendet werden, um den Parameter oder Wert explizit wegzulassen. Ein ungesetzter Ausdruck hat eine der folgenden Auswirkungen:

Das unset-Schlüsselwort kann auch in einer Funktionsdefinition verwendet werden, um anzugeben, dass ein Parameter optional ist, aber keinen Standardwert hat. Bei der Ausführung der Funktion wird die lokale Variable des entsprechenden Parameters keinen Wert haben, wenn der Parameter weggelassen wurde.

Mit dem Vielleicht-Operator (Var?) kann eine Variable übergeben oder weggelassen werden, je nachdem, ob sie einen Wert hat oder nicht. Zum Beispiel ist Array(MeineVar?) äquivalent zu Array(IsSet(MeineVar) ? MeineVar : unset).

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. Die runden Klammern können in bestimmten Fällen weggelassen werden; siehe Funktionsaufrufanweisungen.

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). Variadische Aufrufe sind erlaubt.

Alpha.%vBeta%, Alpha.%vBeta%[Param] und Alpha.%vBeta%() sind ebenfalls Objektelementzugriffe, aber vBeta ist eine Variable oder ein Teilausdruck. Auf diese Weise kann der Name der Eigenschaft oder Methode während der Skriptausführung ermittelt werden. Solche Methodenaufrufe benötigen runde Klammern.

Alpha[Index] greift auf die Standardeigenschaft von Alpha zu und übergibt Index als Parameter. Sowohl Alpha als auch Index sind in diesem Fall Variablen, die mit praktisch jedem Teilausdruck ersetzt werden können. Diese Syntax wird in der Regel verwendet, um ein Element eines Arrays oder eines Map-Objekts abzurufen.

[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.

{Eigenschaft1: Wert1, Eigenschaft2: Wert2} erstellt ein Objekt mit den direkt geschriebenen Eigenschaften Eigenschaft1 und Eigenschaft2. Ein Wert kann später mit der oben beschriebenen Objektelementzugriff-Syntax abgerufen werden. Um einen Eigenschaftsnamen als Ausdruck auszuwerten, umschließen Sie ihn mit Prozentzeichen. Zum Beispiel: {%NameVar%: WertVar}.

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 enumerierbares Objekt wie z.B. Array zurückgibt, sein. Obwohl Params* nicht überall erlaubt ist, kann es in einem direkt geschriebenen Array ([A, B, C, AnzufügendesArray*]) oder in der Parameterliste einer Eigenschaft (Alpha.Beta[Params*] oder 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--.

Bekannte Einschränkung: Bei x++ und x-- darf derzeit kein Leerzeichen zwischen Variablenname und Operator stehen.

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.

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.

Bekannte Einschränkung: Aufgrund von Mehrdeutigkeiten bei Funktionsaufrufanweisungen sollten Bedingungen, die mit einem Variablennamen und Leerzeichen beginnen (aber auch andere Operatoren enthalten), in runde Klammern gesetzt werden. Zum Beispiel sind (x + 1) ? y : z und x+1 ? y : z Ausdruckszuweisungen, während x + 1 ? y : z eine Funktionsaufrufanweisung ist.

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 einer Doppeldereferenz (double-deref) beginnen, wie z.B. %VarName% := 1. Dies ist in erster Linie auf die Komplexität der Implementierung zurückzuführen.

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.

Funktionsaufrufanweisungen ähneln Ausdrucksanweisungen, sind aber technisch gesehen keine reinen Ausdrücke. Zum Beispiel: MsgBox "Hallo, Welt!", meineGui.Show oder x.y.z "meine Parameter".

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 oder Else; Try mit Catch und/oder Else 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. andere Anweisungen

Kontrollanweisungen unterscheiden sich von Funktionsaufrufanweisungen in mehrfacher Hinsicht:

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, die aus einer Schleife heraus aufgerufen wird.

Kein Kontrollfluss

Da Direktiven, Labels, Zweifach-Doppelpunkt-Tags von 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 die #HotIf-Direktive hat keinen Einfluss auf den Kontrollfluss; sie legt lediglich die Kriterien für die im Code angegebenen Hotkeys und Hotstrings fest. Die Kriterien eines Hotkeys werden jedes Mal ausgewertet, wenn er gedrückt wird, nicht wenn die Ausführung auf die #HotIf-Direktive trifft.

Aufbau eines Skripts

Globaler Code

Nach dem Laden des Skripts beginnt der Auto-Execute-Thread mit der Ausführung der obersten Zeile des Skripts, bis er z.B. durch Return, ExitApp oder Exit zum Stoppen gebracht wird. Das physische Ende des Skripts fungiert ebenfalls als Exit.

Globaler Code oder Code im globalen Gültigkeitsbereich ist ein ausführbarer Code, der sich nicht innerhalb einer Funktions- oder Klassendefinition befindet. Alle dortigen Variablenreferenzen gelten als global, da jede Funktion auf sie zugreifen kann (mit der richtigen Deklaration). Ein solcher Code wird oft verwendet, um Einstellungen für alle neuen Threads zu konfigurieren oder um globale Variablen zu initialisieren, die von Hotkeys und anderen Funktionen verwendet werden.

Auszuführender Code für die Startphase des Skripts (sofort wenn das Skript startet) wird oft am Anfang der Datei platziert. Dieser Code kann jedoch überall in der Datei platziert werden, zwischen (aber nicht innerhalb von) Funktions- und Klassendefinitionen. Der Grund dafür ist, dass der Körper jeder Funktions- oder Klassendefinition übersprungen wird, wann immer die Ausführung darauf stößt. In einigen Fällen kann das Skript vollständig aus globalem Code bestehen.

Siehe auch: Startphase des Skripts (der Auto-Execute-Thread)

Subroutinen

Eine Subroutine (auch Sub oder Prozedur genannt) ist ein wiederverwendbarer Codeblock, der bei Bedarf ausgeführt werden kann. Um eine Subroutine zu erstellen, definieren Sie eine Funktion (siehe unten). Diese Begriffe sind in AutoHotkey v2 grundsätzlich austauschbar, da Funktionen die einzigen Subroutinen sind.

Funktionen

Siehe auch: Funktionen (alles über das Definieren von Funktionen)

Neben den vielen nützlichen vordefinierten Funktionen kann ein Skript auch eigene Funktionen definieren. Diese Funktionen können grundsätzlich auf zwei verschiedene Arten verwendet werden:

  1. Eine Funktion kann vom Skript selbst aufgerufen werden. Diese Art von Funktion kann verwendet werden, um z.B. Wiederholungen zu vermeiden oder die Wartbarkeit des Codes zu verbessern.
  2. Eine Funktion kann vom Programm als Reaktion auf ein Ereignis aufgerufen werden, z.B. wenn der Benutzer einen Hotkey drückt. Zum Beispiel ist jedem Hotkey eine Funktion zugeordnet, die beim Drücken des Hotkeys ausgeführt wird.

Es gibt mehrere Möglichkeiten, eine Funktion zu definieren:

Variablen in Funktionen sind standardmäßig lokal für diese Funktion, außer in den folgenden Fällen:

Eine Funktion kann optional Parameter akzeptieren. Die Parameter werden innerhalb von runden Klammern definiert. Zum Beispiel:

MeineFunktion(ErsterParameter, Zweiter, &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.

Der ByRef-Marker (&) gibt an, dass der Aufrufer eine Variablenreferenz übergeben muss. Innerhalb der Funktion greift jede Referenz, die auf den Parameter verweist, eigentlich auf die Variable des Aufrufers zu. Dies ähnelt dem Weglassen von & und der expliziten Dereferenzierung des Parameters innerhalb der Funktion (z.B. %Dritter%), außer dass in diesem Fall die Prozentzeichen weggelassen werden. Wenn der Parameter optional ist und der Aufrufer ihn weglässt, verhält sich der Parameter wie eine normale lokale Variable.

Um einen optionalen Parameter anzugeben, müssen Sie nach dem Parameternamen := anfügen, gefolgt von einer direkt geschriebenen, in Anführungszeichen gesetzten Zeichenkette, einer Zahl, true, false oder unset.

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

Eine Funktionsdefinition muss nicht vor dem Aufruf dieser Funktion stehen.

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.

Eine #Include-Datei kann globalen Code für die Startphase des Skripts enthalten, allerdings wird solcher Code nur ausgeführt (analog zum Code in der Hauptskriptdatei), wenn der Auto-Execute-Thread nicht bereits vor der #Include-Direktive terminiert wird (z.B. mit einem bedingungslosen return). Standardmäßig wird eine Warnung angezeigt, wenn ein Code durch ein vorheriges return nicht ausgeführt werden kann.

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.

Um die gemeinsame Nutzung von Skripten zu erleichtern, sucht #Include an vordefinierten Orten nach einem Bibliotheksskript. Weitere Informationen finden Sie unter Skriptbibliotheksordner.

Verschiedenes

Dynamische Variablen

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

Hinweis: Eine Variable kann nicht durch eine dynamische Referenz erstellt werden, aber existierende Variablen können zugewiesen werden. Dies schließt alle Variablen ein, zu denen das Skript nicht-dynamische Referenzen enthält, auch wenn ihnen keine Werte zugewiesen wurden.

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 => Ziel
MsgBox %ZweiteVar%  ; Doppeldereferenz => 42

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.

Diese Techniken können auch auf Eigenschaften und Methoden von Objekten angewendet werden. Zum Beispiel:

Farbe := {}
for n, Komponente in ["Rot", "Grün", "Blau"]
    Farbe.%Komponente% := Random(0, 255)
MsgBox Farbe.Rot "," Farbe.Grün "," Farbe.Blau

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.

Der "Index", mit dem der endgültige Variablenname gebildet wurde, muss nicht numerisch sein; er kann auch ein Buchstabe oder Schlüsselwort sein.

Aus diesen Gründen ist es in der Regel ratsam, ein Array oder Map anstelle eines Pseudo-Arrays zu verwenden:

Labels

Ein Label identifiziert eine Codezeile und kann als Goto-Ziel oder zum Unterbrechen oder Fortsetzen einer bestimmten Schleife verwendet werden. Ein Label besteht aus einem Namen gefolgt von einem Doppelpunkt:

das_ist_ein_Label:

Abgesehen von Leerraumzeichen und Kommentaren darf kein weiterer Code auf der Zeile eines Labels stehen. Weitere Informationen finden Sie unter Labels.