Aller au contenu principal

Exemples

Des scripts fonctionnels qui couvrent la syntaxe et les domaines de fonctions intégrées. Filtrez-les par thème ou recherchez dans leur code et leur texte. Les scripts qui utilisent les fonctions intégrées Context* nécessitent un déclencheur de geste ou de raccourci clavier. Dans la console de diagnostic, ces fonctions intégrées renvoient leurs valeurs vides par défaut.

Bonjour, console​

Le plus petit script. UtilityPrint écrit dans la console de diagnostic, ou dans le journal d'affichage lorsque le script n'a pas été exécuté depuis la console.

UtilityPrint("Hello from Input.Observer");

Les cinq types de valeurs​

Une variable de chaque type, affichée via StringFormat, seul moyen de convertir en Text une valeur qui n'est pas un Text.

count = 3; // Integer
ratio = 0.75; // Real
name = "Notepad"; // Text
enabled = true; // Bool
w = WindowGetActive(); // Window

UtilityPrint(StringFormat("count={0} ratio={1}", count, ratio)); // count=3 ratio=0.750000
UtilityPrint(StringFormat("name={0} enabled={1}", name, enabled)); // name=Notepad enabled=true
UtilityPrint(StringFormat("window handle={0}", w, ""));

Valeur de vérité de chaque type​

Ce que if considère comme vrai pour chaque type : les nombres non nuls, les Text non vides, les handles non nuls.

if (0) UtilityPrint("never");
if (-1) UtilityPrint("-1 is true");
if (0.0) UtilityPrint("never");
if ("") UtilityPrint("never");
if (" ") UtilityPrint("a single space is true");
if ("false") UtilityPrint("the text \"false\" is true -- it's not empty");
if (!WindowFindByTitle("no window has this title zzz")) UtilityPrint("null handle is false");

Chaîne else-if​

Classer la position horizontale du curseur dans l'un des trois tiers de l'écran situé dessous.

x = MouseGetCursorX();
y = MouseGetCursorY();
left = DisplayMonitorGetRectXFromPoint(x, y, false);
width = DisplayMonitorGetRectWidthFromPoint(x, y, false);

offset = x - left;
if (offset < width / 3) {
zone = "left";
} else if (offset < width * 2 / 3) {
zone = "center";
} else {
zone = "right";
}
UtilityPrint("Cursor is in the " + zone + " third");

Boucles de comptage : croissantes, décroissantes et par pas​

Les trois parties de for sont des affectations ou des expressions de votre choix.

sum = 0;
for (i = 1; i <= 100; i = i + 1) sum = sum + i;
UtilityPrint(StringFormat("1..100 = {0}", sum, "")); // 5050

for (i = 5; i > 0; i = i - 1) UtilityPrint(StringFormat("{0}...", i, ""));

for (p = 1; p <= 1024; p = p * 2) UtilityPrint(StringFormat("{0}", p, "")); // powers of two

Boucles imbriquées : une table de multiplication​

Des boucles for imbriquées qui construisent une ligne de Text par rangée.

for (r = 1; r <= 5; r = r + 1) {
line = "";
for (c = 1; c <= 5; c = c + 1) {
line = line + StringFormat("{0}\t", r * c, "");
}
UtilityPrint(line);
}

Boucle while : attendre une fenêtre, avec un délai maximal​

La condition fait le travail du « while », et le compteur le limite à 5 secondes.

ShellRun("notepad.exe");
w = WindowFindByTitle("Notepad");
for (tries = 0; !w && tries < 50; tries = tries + 1) {
UtilityWait(100);
w = WindowFindByTitle("Notepad");
}
if (w) {
WindowCenterToScreen(w);
} else {
UtilityPrint("Notepad didn't appear within 5 seconds");
}

while (true) avec un indicateur de sortie​

Un pas qui s'affecte à lui-même (go = go) crée une boucle qui ne s'arrête que lorsque son corps efface l'indicateur. Le raccourci d'arrêt de toutes les actions y met toujours fin aussi.

rolls = 0;
for (go = true; go; go = go) {
rolls = rolls + 1;
if (MathRandom(1, 6) == 6) go = false;
}
UtilityPrint(StringFormat("Rolled a six after {0} tries", rolls, ""));

break et continue​

Placez le compteur au-delà de la limite pour un break. Mettez le reste du corps dans un if pour un continue.

n = StringSplit("keep,,skip-me,keep too,STOP,never reached", ",");
for (i = 0; i < n; i = i + 1) {
part = StringGetSplitPartAt(i);
if (part == "STOP") {
i = n; // break
} else if (part && !StringStartsWith(part, "skip")) { // continue for empty / skip-*
UtilityPrint(part);
}
}

Surprises de priorité​

Deux pièges de priorité du C, et les parenthèses explicites qui les corrigent.

flags = 6;
a = flags & 4 == 4; // flags & (4 == 4) -> 6 & true -> 0 (Bool operand)
b = (flags & 4) == 4; // true

x = 5;
c = 0 < x < 10; // (0 < x) < 10 -> true < 10 -> false (Bool vs Integer)
d = x > 0 && x < 10; // true

UtilityPrint(StringFormat("a={0} b={1}", a, b));
UtilityPrint(StringFormat("c={0} d={1}", c, d));

&& et || évaluent les deux côtés​

Les deux opérandes s'exécutent toujours, ce qui compte lorsque le côté droit a un effet ou peut échouer.

StorageSetValue("calls", 0);

// Both sides run even though the left is false; the right side's
// StorageSetValue still happens.
if (false && StorageSetValue("calls", 1)) { }
UtilityPrint(StringFormat("calls = {0}", StorageGetValue("calls"), "")); // calls = 1

// Guard a call that could fail with a nested if, not &&:
text = "no colon here";
idx = StringGetIndexOf(text, ":");
if (idx >= 0) {
UtilityPrint(StringGetSubstring(text, idx + 1, 100));
}

Égalité entre types différents​

Integer et Real se comparent numériquement. Toute autre paire de types différents est simplement inégale.

UtilityPrint(StringFormat("5 == 5.0 -> {0}", 5 == 5.0, "")); // true
UtilityPrint(StringFormat("1 == true -> {0}", 1 == true, "")); // false
UtilityPrint(StringFormat("\"5\" == 5 -> {0}", "5" == 5, "")); // false
UtilityPrint(StringFormat("\"a\" == \"A\" -> {0}", "a" == "A", "")); // false (case-sensitive)
w = WindowFindByTitle("zzz no such window");
UtilityPrint(StringFormat("w == 0 -> {0}, !w -> {1}", w == 0, !w)); // false, true

L'arithmétique entre types mélangés se replie sur 0​

Les combinaisons qu'un opérateur ne comprend pas donnent l'Integer 0 sans erreur. Affichez une valeur lorsqu'un résultat semble faux.

a = "Total: " + 5; // 0 -- not "Total: 5"
b = true + 1; // 0
c = -"text"; // 0
d = 2.5 & 1; // 0 -- bitwise needs Integers
e = "Total: " + StringFormat("{0}", 5, ""); // "Total: 5"
UtilityPrint(StringFormat("{0} {1}", a, b) + StringFormat(" {0} {1} ", c, d) + e);

Commentaires, instructions vides et blocs​

Commentaires de ligne et de bloc, un point-virgule isolé et un bloc de niveau supérieur (qui ne crée pas de portée).

// line comment
/* block comment
spanning lines */
x = 1;; // the extra ';' is an empty statement
{
y = x + 1; /* blocks group statements... */
}
UtilityPrint(StringFormat("y = {0}", y, "")); // ...but y is still visible here

Division Integer ou Real, et division par zéro​

La division entière tronque vers zéro, un seul opérande Real donne un résultat Real, et la division par zéro donne 0.

a = 7 / 2; // 3
b = 7 / 2.0; // 3.5
c = 7 * 1.0 / 2; // 3.5 -- convert first, then divide
d = -7 / 2; // -3 (toward zero)
e = 5 / 0; // 0, no error
UtilityPrint(StringFormat("{0} {1}", a, b) + StringFormat(" {0} {1}", c, d) + StringFormat(" {0}", e, ""));

Reste sans %​

n - (n / d) * d est le % du C. Avec un diviseur puissance de deux, un masque fait de même pour les nombres positifs ou nuls.

n = 17;
d = 5;
rem = n - (n / d) * d; // 2
isEven = (n & 1) == 0; // false
low3 = n & 7; // 17 % 8 == 1
UtilityPrint(StringFormat("17 % 5 = {0}, even = {1}", rem, isEven));
UtilityPrint(StringFormat("17 % 8 = {0}", low3, ""));

Arrondis et fonctions mathématiques sur les Real​

Un Integer passé là où une fonction intégrée déclare Real devient un Real. L'arrondi éloigne les moitiés de zéro.

n = 16;
root = MathSqrt(n); // 4.0 -- n is widened to 16.0

UtilityPrint(StringFormat("round 2.5 -> {0}", MathRound(2.5), "")); // 3
UtilityPrint(StringFormat("round -2.5 -> {0}", MathRound(-2.5), "")); // -3
UtilityPrint(StringFormat("floor -1.5 -> {0}", MathFloor(-1.5), "")); // -2
UtilityPrint(StringFormat("ceil 1.01 -> {0}", MathCeil(1.01), "")); // 2
UtilityPrint(StringFormat("sqrt 16 -> {0}", MathRound(root), "")); // 4

Limiter une valeur à une plage​

MathClamp (comme MathMin/MathMax) accepte l'un ou l'autre type numérique et renvoie la valeur retenue telle quelle.

v = 300;
v = MathClamp(v, 0, 255); // 255
dist = MathAbs(-42); // 42 (Integer stays Integer)
UtilityPrint(StringFormat("clamped={0} abs={1}", v, dist));

Nombres aléatoires et pile ou face​

MathRandom inclut les deux bornes de la plage.

die = MathRandom(1, 6);
if (MathRandom(0, 1) == 1) side = "heads"; else side = "tails";
UtilityPrint(StringFormat("die={0}, coin={1}", die, side));

Longueur du tracé d'un geste​

Additionne la distance en ligne droite entre les points consécutifs du geste. La somme Integer des carrés devient un Real en passant dans MathSqrt.

n = ContextGetPointCount();
total = 0.0;
for (i = 1; i < n; i = i + 1) {
dx = ContextGetPointX(i) - ContextGetPointX(i - 1);
dy = ContextGetPointY(i) - ContextGetPointY(i - 1);
total = total + MathSqrt(dx * dx + dy * dy);
}
UtilityPrint(StringFormat("{0} points, {1} px long", n, MathRound(total)));

Déplacer la souris en cercle​

Conversion des degrés en radians, trigonométrie sur des Real, puis MathRound pour revenir à des coordonnées en pixels de type Integer.

cx = MouseGetCursorX();
cy = MouseGetCursorY();
radius = 80.0;
for (deg = 0; deg <= 360; deg = deg + 10) {
rad = deg * MathGetPi() / 180;
MouseMoveTo(cx + MathRound(radius * MathCos(rad)), cy + MathRound(radius * MathSin(rad)));
UtilityWait(15);
}
MouseMoveTo(cx, cy);

Mettre en forme un Real sans six décimales​

Mettez à l'échelle et arrondissez pour obtenir un pourcentage, ou pour séparer une valeur en partie entière et centièmes afin d'afficher deux décimales. Fonctionne pour les valeurs positives ou nulles.

ratio = 2.0 / 3.0;
pct = MathRound(ratio * 100); // 67

value = 3.14159;
cents = MathRound(value * 100); // 314
whole = cents / 100; // 3
frac = cents - whole * 100; // 14
if (frac < 10) fracText = StringFormat("0{0}", frac, ""); else fracText = StringFormat("{0}", frac, "");
UtilityPrint(StringFormat("{0}% and {1}", pct, StringFormat("{0}.", whole, "") + fracText)); // 67% and 3.14

Masques d'indicateurs : activer, désactiver, inverser, tester​

Les quatre opérations de masque habituelles sur vos propres valeurs d'indicateurs.

BOLD = 0x1;
ITALIC = 0x2;
UNDERLINE = 0x4;

style = BOLD | UNDERLINE; // 0b101 = 5
style = style | ITALIC; // set -> 7
style = style & ~BOLD; // clear -> 6
style = style ^ UNDERLINE; // toggle -> 2

if ((style & ITALIC) != 0) UtilityPrint("italic is on");
if ((style & BOLD) == 0) UtilityPrint("bold is off");
UtilityPrint(StringFormat("style = {0}", style, ""));

Lire la couleur du pixel sous le curseur​

Décomposez l'Integer 0xRRGGBB avec des décalages et des masques.

c = DisplayGetPixelColorFromPoint(MouseGetCursorX(), MouseGetCursorY());
if (c < 0) {
UtilityPrint("The cursor isn't over any monitor");
} else {
r = (c >> 16) & 0xFF;
g = (c >> 8) & 0xFF;
b = c & 0xFF;
UtilityPrint(StringFormat("R={0} G={1}", r, g) + StringFormat(" B={0}", b, ""));
if (r > 200 && g < 80 && b < 80) UtilityPrint("That's red");
}

Integer en texte hexadécimal​

Aucune fonction intégrée n'écrit en hexadécimal : détachez quatre bits à la fois et cherchez chaque chiffre dans un Text.

digits = "0123456789ABCDEF";
value = 48879;
hex = "";
for (v = value; v > 0; v = v >> 4) {
hex = StringGetSubstring(digits, v & 0xF, 1) + hex;
}
if (!hex) hex = "0";
UtilityPrint("0x" + hex); // 0xBEEF

Compter les bits à 1​

Parcourez les 64 bits par décalage et additionnez chaque bit de poids faible.

v = 0xB6; // 1011 0110
bits = 0;
for (i = 0; i < 64; i = i + 1) {
bits = bits + ((v >> i) & 1);
}
UtilityPrint(StringFormat("0xB6 has {0} bits set", bits, "")); // 5

Cas limites des décalages​

>> conserve le signe, et un décalage hors de la plage 0–63 donne 0.

UtilityPrint(StringFormat("1 << 10 = {0}", 1 << 10, "")); // 1024
UtilityPrint(StringFormat("-16 >> 2 = {0}", -16 >> 2, "")); // -4
UtilityPrint(StringFormat("1 << 64 = {0}", 1 << 64, "")); // 0
UtilityPrint(StringFormat("~0 = {0}", ~0, "")); // -1

Échanger deux Integer​

La méthode ordinaire nécessite une variable temporaire. Le OU exclusif échange sans elle.

a = 12; b = 34;
t = a; a = b; b = t; // with a temporary
a = a ^ b; b = a ^ b; a = a ^ b; // XOR swap back
UtilityPrint(StringFormat("a={0} b={1}", a, b)); // a=12 b=34

Bits d'état des touches​

KeyboardGetKeyState renvoie la valeur Win32 brute : le bit de poids fort indique que la touche est enfoncée, le bit de poids faible qu'elle est verrouillée. Les fonctions intégrées Is* font le même test pour vous.

caps = KeyboardGetKeyState(VirtualKey.CapsLock);
shift = KeyboardGetKeyState(VirtualKey.ShiftKey);
UtilityPrint(StringFormat("Caps Lock on: {0}, Shift held: {1}", (caps & 1) != 0, (shift & 0x8000) != 0));
UtilityPrint(StringFormat("same via builtins: {0}, {1}",
KeyboardIsKeyToggled(VirtualKey.CapsLock), KeyboardIsKeyDown(VirtualKey.ShiftKey)));

Séquences d'échappement et chemins Windows​

Doublez chaque barre oblique inverse d'un chemin. \t, \n et \r sont des séquences d'échappement, et toute autre barre oblique inverse est supprimée.

good = "C:\\Temp\\report.txt"; // C:\Temp\report.txt
bad = "C:\Temp\new.txt"; // C:<no backslash>Temp<line break>ew.txt
quote = "He said \"stop\"";
tabs = "Name\tValue";
cont = "one logical line, \
written on two";
UtilityPrint(good);
UtilityPrint(bad);
UtilityPrint(quote);
UtilityPrint(tabs);
UtilityPrint(cont);

Mettre en forme plus de deux valeurs​

StringFormat ne remplit que {0} et {1}. Imbriquez un appel, ou joignez-en plusieurs avec +.

w = WindowGetActive();
x = WindowGetX(w); y = WindowGetY(w);
width = WindowGetWidth(w); height = WindowGetHeight(w);

// nest: the inner call leaves "{0},{1}" for the outer call to fill
a = StringFormat(StringFormat("{0}x{1} at ", width, height) + "{0},{1}", x, y);
// concatenate: each call formats its own piece
b = StringFormat("pos {0},{1}", x, y) + StringFormat(" size {0}x{1}", width, height);
UtilityPrint(a);
UtilityPrint(b);

Découper et parcourir​

StringSplit renvoie le nombre de parties, et StringGetSplitPartAt lit chacune d'elles. Les parties situées entre deux délimiteurs adjacents sont vides.

n = StringSplit("red,green,,blue", ",");
for (i = 0; i < n; i = i + 1) {
UtilityPrint(StringFormat("{0}: [{1}]", i, StringGetSplitPartAt(i)));
}
// 0: [red] 1: [green] 2: [] 3: [blue]

Découpages imbriqués : paires clé=valeur​

Le découpage interne remplace les parties du découpage externe : redécoupez donc la liste externe au début de chaque passage.

config = "width=800;height=600;title=Main";
n = StringSplit(config, ";");
for (i = 0; i < n; i = i + 1) {
StringSplit(config, ";"); // restore the outer parts...
pair = StringGetSplitPartAt(i); // ...and copy this one out
StringSplit(pair, "="); // now the cache holds key, value
UtilityPrint(StringFormat("{0} -> {1}", StringGetSplitPartAt(0), StringGetSplitPartAt(1)));
}

Dernier index de : une extension de fichier​

Il n'existe pas de LastIndexOf : vérifiez donc chaque position et conservez la dernière correspondance.

file = "report.final.v2.pdf";
last = -1;
len = StringGetLength(file);
for (i = 0; i < len; i = i + 1) {
if (StringGetSubstring(file, i, 1) == ".") last = i;
}
if (last >= 0) {
ext = StringGetSubstring(file, last + 1, len - last - 1);
base = StringGetSubstring(file, 0, last);
UtilityPrint(StringFormat("base={0} ext={1}", base, ext)); // base=report.final.v2 ext=pdf
}

Lire un nombre saisi par quelqu'un​

false le lit dans le format régional de l'utilisateur (un utilisateur allemand tape 1.234,5). Les groupes de chiffres doivent alors respecter ce format : pour un utilisateur en français (France), 1 234,5 est un nombre et 12 34,5 n'en est pas un. StringIsNumber intercepte un texte qui n'est pas un nombre, que StringToNumber seule transformerait en 0.

text = UIShowInputBox("Width in pixels:", "Resize", "800");
if (!StringIsNumber(text, false)) {
UIShowMessageBox("Not a number: " + text, "Resize", "OK", "Warning");
} else {
width = StringToNumber(text, false); // Integer 800, or a Real if they typed a fraction
shown = StringFromNumber(width * 1.5, 1, false); // "1,200.0" in en-US, "1.200,0" in de-DE
UtilityPrint("one and a half times that: " + shown);
}

Lancer un programme, attendre sa fenêtre, agir dessus​

WindowWaitFor interroge jusqu'à l'expiration du délai (60 secondes au maximum) et donne une fenêtre nulle si rien n'a correspondu. Le motif est une expression régulière insensible à la casse appliquée au titre ; le titre d'un programme suit la langue d'affichage de Windows : faites donc correspondre la partie qui ne change pas.

ShellRun("notepad.exe");
w = WindowWaitFor("notepad$", 10000);
if (w) {
WindowSetActive(w);
KeyboardTypeText("Notes for today:\n");
WindowWaitClose(w, 60000); // carries on once the user closes it, or after a minute
UtilityPrint("Notepad is gone");
} else {
UtilityPrint("Notepad didn't open in 10 seconds");
}

Extraire une valeur d'un texte copié avec une expression régulière​

Syntaxe PCRE2, sensible à la casse sauf si le motif commence par (?i), et compatible Unicode (\w correspond aux lettres accentuées). Le groupe 0 est la correspondance entière ; une barre oblique inverse dans le motif s'écrit \\ dans une chaîne de script. $1 dans un remplacement désigne le groupe 1. Les fonctions intégrées Window*Regex/Shell*Regex utilisent le même moteur, toujours insensible à la casse.

text = ClipboardGetText();
if (StringRegexMatch(text, "(?i)order\\s*#?(\\d+)")) {
UtilityPrint("order number: " + StringRegexGetGroupAt(1));
} else {
UtilityPrint("no order number on the clipboard");
}
// every run of spaces, tabs and line breaks becomes one space; "#1234" becomes "order 1234"
text = StringRegexReplace(text, "\\s+", " ");
ClipboardSetText(StringRegexReplace(text, "#(\\d+)", "order $1"));

Compléter un nombre par des zéros​

Ajoutez des caractères en tête jusqu'à ce que le Text soit assez long.

n = 7;
s = StringFormat("{0}", n, "");
for (s = s; StringGetLength(s) < 3; s = s) {
s = "0" + s;
}
UtilityPrint(s); // 007

Inverser un Text​

Parcourez le Text à rebours, une unité UTF-16 à la fois. Les caractères hors du plan multilingue de base (la plupart des emoji) occupent deux unités et ressortiraient coupés en deux.

text = "Input.Observer";
rev = "";
for (i = StringGetLength(text) - 1; i >= 0; i = i - 1) {
rev = rev + StringGetSubstring(text, i, 1);
}
UtilityPrint(rev); // revresbO.tupnI

Compter les mots du Presse-papiers​

Transformez les tabulations et les sauts de ligne en espaces, découpez sur les espaces et comptez les parties non vides.

text = ClipboardGetText();
text = StringReplace(text, "\n", " ");
text = StringReplace(text, "\t", " ");
n = StringSplit(text, " ");
words = 0;
for (i = 0; i < n; i = i + 1) {
if (StringTrim(StringGetSplitPartAt(i))) words = words + 1;
}
UtilityPrint(StringFormat("{0} words", words, ""));

Comparaisons insensibles à la casse​

Mettez les deux côtés en minuscules, car chaque opérateur et chaque fonction intégrée de Text est sensible à la casse.

title = WindowGetTitle(WindowGetActive());
if (StringContains(StringToLower(title), "visual studio")) {
UtilityPrint("In Visual Studio");
}
exe = WindowGetExecutableName(WindowGetActive());
if (StringToLower(exe) == "notepad.exe") UtilityPrint("In Notepad");

L'ordre du texte est ordinal​

< compare des unités de code UTF-16 : toutes les lettres ASCII majuscules sont triées avant toutes les minuscules.

UtilityPrint(StringFormat("\"apple\" < \"banana\" : {0}", "apple" < "banana", "")); // true
UtilityPrint(StringFormat("\"Zebra\" < \"apple\" : {0}", "Zebra" < "apple", "")); // true
UtilityPrint(StringFormat("\"apple\" < \"Banana\" : {0}", "apple" < "Banana", "")); // false
a = "apple"; b = "Banana";
UtilityPrint(StringFormat("case-folded : {0}", StringToLower(a) < StringToLower(b), "")); // true

Remplir un modèle et le coller​

StringReplace remplit les espaces réservés %NAME%. Le Presse-papiers est enregistré puis restauré autour du collage.

template = "Hi %NAME%,\n\nThanks for the report on %APP%.\n";
text = StringReplace(template, "%NAME%", "Sam");
text = StringReplace(text, "%APP%", ContextGetApplicationName());
ClipboardSave();
ClipboardPasteReplacementText(text);
UtilityWait(150); // let the target app read the clipboard first
ClipboardRestore();

Joindre les lignes du Presse-papiers en une seule​

Découpez sur \n. StringTrim supprime aussi le \r des fins de ligne Windows : cela fonctionne donc que les lignes se terminent par \r\n ou par \n seul.

n = StringSplit(ClipboardGetText(), "\n");
out = "";
for (i = 0; i < n; i = i + 1) {
part = StringTrim(StringGetSplitPartAt(i));
if (part) {
if (out) out = out + " ";
out = out + part;
}
}
ClipboardSetText(out);

Rechercher sur le web le texte sélectionné​

ClipboardCopySelection attend que la copie aboutisse au lieu de deviner. StringUrlEncode empêche &, #, les espaces et les lettres accentuées de casser l'adresse. N'encodez que le terme recherché, jamais l'URL entière.

ClipboardSave();
term = StringTrim(ClipboardCopySelection(1000));
ClipboardRestore();
if (term) ShellRun("https://www.bing.com/search?q=" + StringUrlEncode(term));

Un geste, plusieurs choix​

UIShowMenu prend un élément par ligne (- seul est un séparateur) et renvoie l'index de l'élément choisi, en comptant à partir de 0 et sans compter les séparateurs, ou -1 si le menu est fermé sans choix. UIShowInputBox renvoie "" en cas d'annulation.

choice = UIShowMenu("Maximize\nMinimize\n-\nRename window...");
w = ContextGetWindow();
if (choice == 0) WindowMaximize(w);
else if (choice == 1) WindowMinimize(w);
else if (choice == 2) {
title = UIShowInputBox("New title for this window:", "Rename", WindowGetTitle(w));
if (title) WindowSetTitle(w, title);
}

La date du jour, et un nom de fichier horodaté​

DateTimeGetNow renvoie un texte ISO 8601. DateTimeFormat l'écrit selon les préférences de l'utilisateur, ou sous forme de FileStamp qui se trie par ordre chronologique et peut figurer sans risque dans un nom de fichier.

now = DateTimeGetNow();
KeyboardTypeText(DateTimeFormat(now, DateTimeStyle.LongDate));
path = ShellExpandEnvironmentVariables("%USERPROFILE%\\Desktop\\note-") + DateTimeFormat(now, DateTimeStyle.FileStamp) + ".txt";
FileCreate(path, ClipboardGetText());
if (DateTimeGetPart(now, DateTimePart.Hour) >= 17) UtilityPrint("after hours");

Constantes nommées ou nombres bruts​

Une constante est compilée en son nombre : ces appels sont donc identiques. L'hexadécimal correspond à la documentation Win32.

KeyboardPressKey(VirtualKey.VolumeMute);
KeyboardPressKey(0xAD); // the same key, as a hex VK code
KeyboardPressKey(173); // and in decimal
UtilityPrint(StringFormat("VirtualKey.A = {0}, MouseButton.Right = {1}", VirtualKey.A, MouseButton.Right));

Basculer l'agrandissement de la fenêtre du geste​

L'action de geste la plus courante. ContextGetWindow est la fenêtre au-dessus de laquelle le geste a commencé.

w = ContextGetWindow();
if (WindowIsMaximized(w)) WindowRestore(w); else WindowMaximize(w);

Épingler une fenêtre au premier plan​

WindowSetTopmost définit explicitement l'état toujours au premier plan, et WindowToggleTopmost l'inverse. Une propriété de fenêtre retient l'état choisi par ce script.

w = ContextGetWindow();
pinned = WindowGetPropertyInteger(w, "io.pinned") == 1;
WindowSetTopmost(w, !pinned);
if (pinned) {
WindowRemoveProp(w, "io.pinned");
} else {
WindowSetPropertyInteger(w, "io.pinned", 1);
ShellShowToast("Pinned on top", WindowGetTitle(w));
}

Faire varier la transparence d'une fenêtre​

Fait passer l'opacité par paliers de 255 à 105, puis revient à 255. Une fenêtre qui n'est pas superposée (layered) signale 255.

w = ContextGetWindow();
a = WindowGetAlpha(w) - 50;
if (a < 100) a = 255;
WindowSetAlpha(w, a);

Ancrer la fenêtre active dans la moitié gauche de son écran​

Utilise la zone de travail (true) pour que la fenêtre ne recouvre pas la barre des tâches.

w = WindowGetActive();
cx = WindowGetX(w) + WindowGetWidth(w) / 2;
cy = WindowGetY(w) + WindowGetHeight(w) / 2;
x = DisplayMonitorGetRectXFromPoint(cx, cy, true);
y = DisplayMonitorGetRectYFromPoint(cx, cy, true);
width = DisplayMonitorGetRectWidthFromPoint(cx, cy, true);
height = DisplayMonitorGetRectHeightFromPoint(cx, cy, true);
WindowRestore(w);
WindowMoveTo(w, x, y);
WindowResizeTo(w, width / 2, height);

Ancrer une fenêtre dans une cellule d'une grille 3×2 sous le curseur​

Les fonctions intégrées Region* découpent un rectangle en cellules, trouvent la cellule qui contient un point et en donnent les limites.

mx = MouseGetCursorX();
my = MouseGetCursorY();
x = DisplayMonitorGetRectXFromPoint(mx, my, true);
y = DisplayMonitorGetRectYFromPoint(mx, my, true);
w = DisplayMonitorGetRectWidthFromPoint(mx, my, true);
h = DisplayMonitorGetRectHeightFromPoint(mx, my, true);

cell = RegionGetCellIndexAt(x, y, w, h, 3, 2, mx, my);
win = ContextGetWindow();
if (cell >= 0 && win) {
WindowRestore(win);
WindowMoveTo(win, RegionGetX(x, y, w, h, 3, 2, cell), RegionGetY(x, y, w, h, 3, 2, cell));
WindowResizeTo(win, RegionGetWidth(x, y, w, h, 3, 2, cell), RegionGetHeight(x, y, w, h, 3, 2, cell));
}

Envoyer une fenêtre sur l'écran suivant​

Le second argument déplace la souris avec la fenêtre.

WindowSendToNextScreen(ContextGetWindow(), true);

Lister les fenêtres de niveau supérieur visibles​

Énumérer puis indexer, en ignorant les fenêtres masquées, voilées (cloaked) et sans titre.

n = WindowGetAllTopLevel();
shown = 0;
for (i = 0; i < n; i = i + 1) {
w = WindowGetEnumeratedAt(i);
if (WindowGetVisible(w)) {
if (!WindowIsCloaked(w)) {
title = WindowGetTitle(w);
if (title) {
UtilityPrint(StringFormat("{0} [{1}]", title, WindowGetExecutableName(w)));
shown = shown + 1;
}
}
}
}
UtilityPrint(StringFormat("{0} of {1} windows", shown, n));

Réduire toutes les fenêtres d'une application​

Fait correspondre l'exécutable avec une expression régulière insensible à la casse. Notez le \\. : un \. d'expression régulière écrit dans une chaîne de script.

n = WindowFindAllByModuleRegex("notepad\\.exe$");
for (i = 0; i < n; i = i + 1) {
WindowMinimize(WindowGetEnumeratedAt(i));
}
UtilityPrint(StringFormat("Minimized {0} Notepad windows", n, ""));

Fermer des fenêtres selon un motif de titre, après confirmation​

Une expression régulière appliquée aux titres, un nombre dans le message et une vérification du bouton cliqué.

n = WindowFindAllByTitleRegex("^Untitled - ");
if (n > 0) {
answer = UIShowMessageBox(StringFormat("Close {0} untitled window(s)?", n, ""),
"Tidy up", "YesNo", "Question");
if (answer == "Yes") {
for (i = 0; i < n; i = i + 1) WindowClose(WindowGetEnumeratedAt(i));
}
}

Mémoriser et restaurer la position d'une fenêtre​

Les propriétés de fenêtre conservent des Integer sur la fenêtre elle-même, d'une exécution à l'autre, jusqu'à sa fermeture. Une propriété jamais définie se lit 0.

w = ContextGetWindow();
if (WindowGetPropertyInteger(w, "io.saved") == 1) {
WindowMoveTo(w, WindowGetPropertyInteger(w, "io.x"), WindowGetPropertyInteger(w, "io.y"));
WindowRemoveProp(w, "io.saved");
WindowRemoveProp(w, "io.x");
WindowRemoveProp(w, "io.y");
} else {
WindowSetPropertyInteger(w, "io.x", WindowGetX(w));
WindowSetPropertyInteger(w, "io.y", WindowGetY(w));
WindowSetPropertyInteger(w, "io.saved", 1);
WindowCenterToScreen(w);
}

Inspecter les contrôles enfants d'une fenêtre​

Les enfants utilisent le même cache de fenêtres que l'énumération de niveau supérieur.

w = ContextGetWindow();
n = WindowGetAllChildren(w, true);
for (i = 0; i < n; i = i + 1) {
c = WindowGetEnumeratedAt(i);
UtilityPrint(StringFormat("{0}: {1}", WindowGetClassName(c), WindowGetTitle(c)));
}

Du processus à la fenêtre​

Énumérez les identificateurs de processus par nom d'exécutable, puis trouvez la fenêtre de chacun.

n = ShellEnumerateProcessIdsByExeRegex("^explorer\\.exe$");
for (i = 0; i < n; i = i + 1) {
pid = ShellGetEnumeratedProcessIdAt(i);
w = WindowFromProcessId(pid);
UtilityPrint(StringFormat("pid {0}: {1}", pid, WindowGetTitle(w)));
}

Décrire ce qui se trouve sous le curseur​

Le contrôle situé sous un point, sa fenêtre de niveau supérieur, et le point converti en coordonnées client.

x = MouseGetCursorX();
y = MouseGetCursorY();
control = WindowControlFromPoint(x, y);
top = WindowGetRoot(control);
UtilityPrint(StringFormat("control class: {0}; window: {1}", WindowGetClassName(control), WindowGetTitle(top)));
UtilityPrint(StringFormat("client point: {0},{1}",
WindowMapScreenPointToClientX(top, x, y), WindowMapScreenPointToClientY(top, x, y)));

Masquer une fenêtre dans la zone de notification​

Réduire dans la zone de notification. TrayRestoreAllWindows() les fait toutes revenir.

TrayMinimizeWindow(ContextGetWindow());

Tout ce que sait le contexte de déclenchement​

Associez ce script à un geste pour voir ce que son script peut lire.

UtilityPrint(StringFormat("action={0} gesture={1}", ContextGetActionName(), ContextGetGestureName()));
UtilityPrint(StringFormat("app={0} window={1}", ContextGetApplicationName(), WindowGetTitle(ContextGetWindow())));
UtilityPrint(StringFormat("box x={0} y={1}", ContextGetBoundingBoxX(), ContextGetBoundingBoxY())
+ StringFormat(" w={0} h={1}", ContextGetBoundingBoxWidth(), ContextGetBoundingBoxHeight()));
UtilityPrint(StringFormat("points={0} button={1}", ContextGetPointCount(), ContextGetStrokeButton()));

Dans quelle direction est allé le tracé ?​

Comparez le premier et le dernier point, et retenez l'axe dominant.

n = ContextGetPointCount();
if (n > 1) {
dx = ContextGetPointX(n - 1) - ContextGetPointX(0);
dy = ContextGetPointY(n - 1) - ContextGetPointY(0);
if (MathAbs(dx) > MathAbs(dy)) {
if (dx > 0) dir = "right"; else dir = "left";
} else {
if (dy > 0) dir = "down"; else dir = "up";
}
UtilityPrint("The stroke went " + dir);
}

Brancher selon le bouton du tracé​

ContextGetStrokeButton renvoie une valeur MouseButton.*, ou -1 en dehors d'un déclencheur de geste ou de bouton de souris.

b = ContextGetStrokeButton();
if (b == MouseButton.Secondary) {
WindowMinimize(ContextGetWindow());
} else if (b == MouseButton.Middle) {
WindowClose(ContextGetWindow());
} else if (b == -1) {
UtilityPrint("Not triggered by a mouse button");
}

Capturer la zone que vous avez entourée​

Enregistre le rectangle englobant du geste au format PNG dans Images.

path = ShellExpandEnvironmentVariables("%USERPROFILE%\\Pictures\\gesture-capture.png");
ok = CaptureSaveRegion(path, ContextGetBoundingBoxX(), ContextGetBoundingBoxY(),
ContextGetBoundingBoxWidth(), ContextGetBoundingBoxHeight());
if (ok) ShellShowToast("Captured", path);

Laisser passer un dessin non reconnu​

Si un geste a été tracé au-dessus d'une application de dessin, rejoue le tracé dans l'application sous forme de glissement normal.

if (StringToLower(ContextGetApplicationName()) == "mspaint.exe") {
ContextRelayGesture();
}

Cliquer quelque part, puis remettre le curseur en place​

Enregistrez la position du curseur dans des variables, cliquez, puis revenez.

x = MouseGetCursorX();
y = MouseGetCursorY();
MouseClick(20, 20, MouseButton.Primary);
UtilityWait(50);
MouseMoveTo(x, y);

Cliquer sur un point dans une fenêtre​

Les coordonnées client restent justes où que la fenêtre ait été déplacée.

w = WindowFindByTitle("Calculator");
if (w) {
WindowSetActive(w);
MouseClickAtClientPoint(w, 40, 60, MouseButton.Primary);
}

Un glissement scripté​

Appuyer, déplacer par étapes, relâcher. Les fonctions intégrées distinctes d'appui, de déplacement et de relâchement existent pour cela.

x = MouseGetCursorX();
y = MouseGetCursorY();
MouseButtonDown(MouseButton.Primary);
for (i = 1; i <= 20; i = i + 1) {
MouseMoveTo(x + i * 10, y);
UtilityWait(10);
}
MouseButtonUp(MouseButton.Primary);

Faire défiler par crans​

Un cran de molette vaut 120. Une valeur négative fait défiler vers le bas ou vers la gauche.

MouseScrollVertical(-3 * 120); // three notches down
MouseScrollHorizontal(120); // one notch right

Confiner le curseur à une fenêtre pendant 5 secondes​

MouseLockToRect s'applique à tout le système jusqu'à MouseUnlock : associez-les donc toujours.

w = ContextGetWindow();
MouseLockToRect(WindowGetX(w), WindowGetY(w), WindowGetWidth(w), WindowGetHeight(w));
UtilityWait(5000);
MouseUnlock();

Combinaisons de touches​

Préfixes de modificateurs ^ Ctrl, + Maj, % Alt et @ Win, puis une touche.

KeyboardPressKeyCombo("^c"); // Ctrl+C
KeyboardPressKeyCombo("^+{ESC}"); // Ctrl+Shift+Esc
KeyboardPressKeyCombo("@{LEFT}"); // Win+Left
KeyboardPressKeyCombo("%{F4}"); // Alt+F4

Taper une signature​

KeyboardTypeText tape des caractères. Envoyez Entrée sous forme de combinaison de touches entre les lignes, pour que chaque application reçoive un véritable appui sur la touche Entrée.

KeyboardTypeText("Best regards,");
KeyboardPressKeyCombo("{ENTER}");
KeyboardTypeText("Sam");

Maj+clic​

Maintenez une touche autour d'une action de souris, et relâchez-la dans le même script. Une touche laissée enfoncée le reste.

KeyboardKeyDown(VirtualKey.ShiftKey);
MouseClick(MouseGetCursorX(), MouseGetCursorY(), MouseButton.Primary);
KeyboardKeyUp(VirtualKey.ShiftKey);

Touches multimédias​

Envoyez des touches multimédias et de volume par leur nom VirtualKey.

KeyboardPressKey(VirtualKey.MediaPlayPause);
UtilityWait(200);
KeyboardPressKey(VirtualKey.MediaNextTrack);

Changer de comportement tant que Ctrl est maintenue​

Vérifiez l'état actuel d'une touche pour donner deux significations à un même geste.

w = ContextGetWindow();
if (KeyboardIsKeyDown(VirtualKey.ControlKey)) {
WindowClose(w);
} else {
WindowMinimize(w);
}

Mettre en majuscules le texte sélectionné​

Copiez la sélection, modifiez-la, recollez-la et restaurez ce qui se trouvait auparavant dans le Presse-papiers.

ClipboardSave();
ClipboardClear();
KeyboardPressKeyCombo("^c");
UtilityWait(100);
text = ClipboardGetText();
if (text) {
ClipboardPasteReplacementText(StringToUpper(text));
UtilityWait(100);
}
ClipboardRestore();

Copiez la sélection et ouvrez une URL de recherche. Les espaces deviennent +. Pour encoder aussi tous les autres caractères, utilisez StringUrlEncode, comme le fait Rechercher sur le web le texte sélectionné.

ClipboardSave();
KeyboardPressKeyCombo("^c");
UtilityWait(100);
q = StringTrim(ClipboardGetText());
ClipboardRestore();
if (q) {
ShellRun("https://www.bing.com/search?q=" + StringReplace(q, " ", "+"));
}

Enregistrer une image copiée dans un fichier​

Écrit l'image du Presse-papiers sur le disque et indique le résultat.

path = ShellExpandEnvironmentVariables("%USERPROFILE%\\Desktop\\clipboard.png");
if (ClipboardSaveImage(path)) ShellShowToast("Saved", path);
else UtilityPrint("No image on the clipboard");

Ajouter à un fichier journal​

Crée le fichier avec un en-tête la première fois, puis ajoute une ligne à chaque exécution.

log = ShellExpandEnvironmentVariables("%TEMP%\\input-observer-gestures.log");
if (!FileExists(log)) FileCreate(log, "gesture\tapplication\n");
FileAppendText(log, StringFormat("{0}\t{1}\n", ContextGetGestureName(), ContextGetApplicationName()));

Lire un fichier et compter ses lignes​

FileReadText renvoie le fichier entier sous forme de Text, découpé ensuite sur \n.

path = "C:\\Windows\\System32\\drivers\\etc\\hosts";
text = FileReadText(path);
n = StringSplit(text, "\n");
comments = 0;
for (i = 0; i < n; i = i + 1) {
if (StringStartsWith(StringTrim(StringGetSplitPartAt(i)), "#")) comments = comments + 1;
}
UtilityPrint(StringFormat("{0} lines, {1} comments", n, comments));
UtilityPrint(StringFormat("{0} bytes, modified {1}", FileGetSize(path), FileGetModifiedDate(path)));

Compter les types de fichiers d'un dossier​

Énumère un dossier sans récursivité et compte les correspondances sans tenir compte de la casse.

folder = ShellExpandEnvironmentVariables("%USERPROFILE%\\Downloads");
n = FolderEnumerateAll(folder, false);
pdf = 0; zip = 0;
for (i = 0; i < n; i = i + 1) {
p = StringToLower(FolderGetEnumeratedPathAt(i));
if (StringEndsWith(p, ".pdf")) pdf = pdf + 1;
else if (StringEndsWith(p, ".zip")) zip = zip + 1;
}
UtilityPrint(StringFormat("{0} PDFs, {1} ZIPs", pdf, zip) + StringFormat(" of {0} entries", n, ""));

Sauvegarder un fichier avant de le modifier​

Copiez en écrasant la copie existante, puis remplacez le contenu.

path = ShellExpandEnvironmentVariables("%USERPROFILE%\\notes.txt");
if (FileExists(path)) {
FileCopy(path, path + ".bak", true);
FileEditText(path, StringToUpper(FileReadText(path)));
}

Surveiller un dossier​

Combinez les indicateurs FileNotify avec |. Le script de la surveillance est un Text : ses guillemets internes sont donc échappés. Il lit ce qui s'est passé via ContextGetWatch*.

FolderWatchCreate("downloads",
ShellExpandEnvironmentVariables("%USERPROFILE%\\Downloads"),
false,
FileNotify.FileName | FileNotify.LastWrite,
"UtilityPrint(ContextGetWatchAction() + \": \" + ContextGetWatchPath());");
// later: FolderWatchDelete("downloads");

Un minuteur répétitif qui compte​

Le script d'un minuteur a ses propres variables : Storage transmet donc le compte d'un déclenchement à l'autre. Se déclenche 5 fois, à une seconde d'intervalle.

StorageSetValue("ticks", 0);
TimerCreate("counter", 1000, 1000, 5,
"t = StorageGetValue(\"ticks\") + 1; StorageSetValue(\"ticks\", t); UtilityPrint(StringFormat(\"tick {0}\", t, \"\"));");

Script de minuteur tiré d'un extrait, sans échappement​

Conservez un long script de minuteur dans un extrait et passez son texte : il n'y a alors aucun guillemet imbriqué à échapper.

// Fires once, 10 minutes from now (repeat count 1).
TimerCreate("stretch-reminder", 600000, 1000, 1, SnippetGetScript("Stretch reminder"));

Lister et arrêter des minuteurs​

Énumérez les minuteurs nommés, et supprimez-en un ou tous.

n = TimerEnumerateAll();
for (i = 0; i < n; i = i + 1) UtilityPrint(TimerGetEnumeratedNameAt(i));
TimerDelete("counter");
// TimerDeleteAll();

Une bascule qui persiste entre les exécutions​

StorageGetValue d'une clé jamais définie vaut l'Integer 0, qui est faux : la première exécution active donc le mode. La valeur dure jusqu'à la fermeture d'Input.Observer ; les fonctions intégrées Persistent la conservent d'un redémarrage à l'autre.

on = !StorageGetValue("quietMode");
StorageSetValue("quietMode", on);
MultimediaSetMute(AudioEndpoint.Playback, on);
if (on) ShellShowToast("Quiet mode", "On"); else ShellShowToast("Quiet mode", "Off");

Un compteur qui survit à un redémarrage​

Les fonctions intégrées Storage*Persistent* conservent les valeurs dans storage.toml, à côté de la configuration : elles sont donc toujours là après un redémarrage d'Input.Observer. Texte brut, jamais chiffré : n'y conservez pas de mots de passe. Les Window ne peuvent pas être conservées ; un handle n'a plus de sens après un redémarrage. Si storage.toml existe mais ne peut pas être lu au démarrage d'Input.Observer, StorageSetPersistentValue renvoie false : la valeur n'est conservée que jusqu'à la fermeture d'Input.Observer, et rien n'est enregistré avant le prochain démarrage.

n = StorageGetPersistentValue("gestures.used") + 1; // 0 the first time ever
StorageSetPersistentValue("gestures.used", n);
UtilityPrint(StringFormat("{0} gestures since this counter started", n, ""));

Une liste conservée dans Storage​

Pas de tableaux, mais des clés numérotées construites avec StringFormat en tiennent lieu.

count = StorageGetValue("recent.count");
StorageSetValue(StringFormat("recent.{0}", count, ""), WindowGetTitle(ContextGetWindow()));
StorageSetValue("recent.count", count + 1);

for (i = 0; i <= count; i = i + 1) {
UtilityPrint(StorageGetValue(StringFormat("recent.{0}", i, "")));
}

Ne laisser qu'une action à la fois exécuter une section​

Un verrou nommé empêche deux exécutions qui se chevauchent de s'entremêler. Comparez le résultat à LockResult, et libérez le verrou une fois terminé.

r = UtilityLockAcquire("clipboard-work", 5);
if (r == LockResult.Acquired) {
ClipboardSave();
// ...work that must not overlap another run...
ClipboardRestore();
UtilityLockRelease("clipboard-work");
} else {
UtilityPrint("Another action is busy with the clipboard");
}

Poser une question​

Les boutons et l'icône sont des noms Text. Le résultat est le nom du bouton cliqué.

answer = UIShowMessageBox("Save the layout before closing?", "Input.Observer", "YesNoCancel", "Question");
if (answer == "Yes") {
UtilityPrint("saving");
} else if (answer == "No") {
UtilityPrint("discarding");
} else {
UtilityPrint("cancelled");
}

Augmenter le volume avec un affichage à l'écran​

Le volume est un Real de 0.0 à 1.0. UIShowDisplayMessage prend 19 arguments positionnels.

v = MathMin(MultimediaGetVolume(AudioEndpoint.Playback) + 0.05, 1.0);
MultimediaSetVolume(AudioEndpoint.Playback, v);
UIShowDisplayMessage(
"Volume", StringFormat("{0}%", MathRound(v * 100), ""),
1200, // durationMs
0.9, // opacity (Real)
Location.BottomCenter, // or a "x,y" Text point
"Segoe UI", 14, true, false, // title font, size, bold, italic
"Segoe UI", 12, false, false, // message font, size, bold, italic
"#1F1F1F", "#F7F7F5", // fore / back color: name, #RRGGBB or "R,G,B"
12, // padding
false, // usePrimaryScreen
TextAlign.Center, TextAlign.Center);

Un message affiché qui se met à jour en direct​

Conservez l'identifiant de session et passez-le à UIUpdateDisplayMessage avec les mêmes 19 arguments.

id = UIShowDisplayMessage("Working", "0%", 10000, 0.95, Location.TopRight,
"Segoe UI", 12, true, false, "Segoe UI", 11, false, false,
"black", "255,255,255", 10, true, TextAlign.Left, TextAlign.Left);
for (p = 0; p <= 100; p = p + 20) {
UIUpdateDisplayMessage(id, "Working", StringFormat("{0}%", p, ""), 10000, 0.95, Location.TopRight,
"Segoe UI", 12, true, false, "Segoe UI", 11, false, false,
"black", "255,255,255", 10, true, TextAlign.Left, TextAlign.Left);
UtilityWait(400);
}
UICloseDisplayMessage(id);

Une notification Windows​

Un titre et un message, affichés sous forme de notification toast.

ShellShowToast("Input.Observer", StringFormat("Profile: {0}", GestureProfileGetActiveId(), ""));

Activer ou désactiver le micro​

Le point de terminaison Capture est le périphérique d'enregistrement par défaut.

MultimediaToggleMute(AudioEndpoint.Capture);
if (MultimediaGetMute(AudioEndpoint.Capture)) ShellShowToast("Microphone", "Muted");
else ShellShowToast("Microphone", "Live");

Lire un son​

Fichiers WAV et MP3 à partir d'un chemin.

MultimediaPlayWavFile("C:\\Windows\\Media\\chimes.wav");

Lancer une application ou basculer vers elle​

Active l'application si elle est déjà en cours d'exécution, sinon la démarre.

ShellRunOrActivate("notepad.exe");

Exécuter un programme avec un verbe et un style de fenêtre​

Le verbe est une constante ShellVerb ou n'importe quel verbe sous forme de Text. Le style de fenêtre est une constante WindowStyle.

ShellRunProgram("notepad.exe", "C:\\Temp\\todo.txt", ShellVerb.Open, WindowStyle.Maximized, false);
ShellRunProgram("C:\\Temp\\report.pdf", "", "print", WindowStyle.Hidden, false); // Text verb

Exécuter et attendre la fin​

Avec waitForExit à true, le thread du script est bloqué jusqu'à la fermeture du programme. Les entrées continuent de circuler pendant ce temps. L'arrêt de toutes les actions met fin à l'attente : le programme continue de s'exécuter et l'appel renvoie false.

ShellRunProgram("notepad.exe", "", ShellVerb.Open, WindowStyle.Normal, true);
ShellShowToast("Notepad", "was closed");

Développer des variables d'environnement​

Construit un chemin qui fonctionne sur la machine de chaque utilisateur.

UtilityPrint(ShellExpandEnvironmentVariables("%APPDATA%\\Input.Observer"));
UtilityPrint(ShellExpandEnvironmentVariables("%COMPUTERNAME% / %USERNAME%"));

Passer la main à AutoHotkey​

Exécute du code AutoHotkey hors processus et renvoie son code de sortie, ou -1 si AutoHotkey n'est pas configuré.

rc = AutoHotkeyExecuteScript("SoundBeep 750, 200");
if (rc == -1) UtilityPrint("AutoHotkey isn't set up");

Lister les écrans​

Nom, limites complètes, zone de travail et PPP de chaque écran, par index.

n = DisplayMonitorEnumeratedAll();
for (i = 0; i < n; i = i + 1) {
UtilityPrint(StringFormat("#{0} {1}", i, DisplayMonitorGetEnumeratedFriendlyNameAt(i)));
UtilityPrint(StringFormat(" bounds {0} x {1}", DisplayMonitorGetEnumeratedWidthAt(i, false), DisplayMonitorGetEnumeratedHeightAt(i, false))
+ StringFormat(", work area {0} x {1}", DisplayMonitorGetEnumeratedWidthAt(i, true), DisplayMonitorGetEnumeratedHeightAt(i, true))
+ StringFormat(", {0} dpi", DisplayMonitorGetEnumeratedDpiAt(i), ""));
}

Envoyer une fenêtre sur un écran précis​

Par index issu de l'énumération, avec repli sur l'écran suivant lorsque cet écran n'existe pas.

w = ContextGetWindow();
if (DisplayMonitorEnumeratedAll() > 1) {
WindowSendToMonitorIndex(w, 1, false);
} else {
WindowSendToNextScreen(w, false);
}

Passer au profil de gestes suivant​

Trouvez l'index du profil actif, ajoutez un et revenez au début avec l'idiome du reste.

n = GestureProfileEnumerateAll();
if (n > 0) {
active = GestureProfileGetActiveId();
next = 0;
for (i = 0; i < n; i = i + 1) {
if (GestureProfileGetEnumeratedIdAt(i) == active) next = i + 1;
}
next = next - (next / n) * n; // next % n
GestureProfileSwitch(GestureProfileGetEnumeratedIdAt(next));
ShellShowToast("Gesture profile", GestureProfileGetEnumeratedNameAt(next));
}

État du moteur​

Lisez si le moteur est désactivé ou en mode sans échec, puis mettez-le en pause. Réactivez-le depuis le menu de la zone de notification.

UtilityPrint(StringFormat("disabled={0} safeMode={1}", EngineIsDisabled(), EngineIsSafeMode()));
if (!EngineIsDisabled()) {
EngineDisable();
ShellShowToast("Input.Observer", "Paused. Re-enable it from the tray menu.");
}

Laisser passer le prochain glissement du bouton droit​

Ignore une fois la capture de geste : le prochain glissement du bouton droit va donc à l'application.

EngineDisableNextGesture();

Des extraits comme fonctions réutilisables​

Transmettez les arguments et les résultats via Storage. L'extrait s'exécute jusqu'au bout avant la ligne suivante.

// Snippet "Tile window" reads tile.index and positions ContextGetWindow() accordingly.
StorageSetValue("tile.index", 2);
SnippetExecuteScript("Tile window");
UtilityPrint(StringFormat("snippet reported: {0}", StorageGetValue("tile.result"), ""));

Communiquer avec un plugin​

Envoie une commande Text à un plugin connecté et attend sa réponse Text jusqu'à l'expiration du délai.

reply = PluginSendMessage("MyRenderer", "theme dark", 2);
UtilityPrint("Plugin replied: " + reply);

Poser une question à un périphérique série​

Ouvrez le port, écrivez une ligne, attendez la réponse jusqu'à 2 secondes et fermez le port. La parité et les bits d'arrêt sont des constantes.

if (SerialOpenPort("COM3", 9600, SerialParity.None, 8, SerialStopBits.One, "\n")) {
SerialWriteTextLine("COM3", "PING", 9600);
reply = SerialGetTextLine("COM3", 2, 9600);
SerialClosePort("COM3");
if (reply) UtilityPrint("Device: " + reply); else UtilityPrint("No reply");
}

Associer les boutons d'un périphérique série à des touches multimédias​

Un moniteur exécute son script pour chaque ligne reçue. ContextGetSerialTextLine est la ligne.

SerialMonitorCreate("pad", "COM3", 115200, SerialParity.None, 8, SerialStopBits.One, "\n",
"line = StringTrim(ContextGetSerialTextLine()); if (line == \"B1\") KeyboardPressKey(VirtualKey.MediaPlayPause); else if (line == \"B2\") KeyboardPressKey(VirtualKey.MediaNextTrack);");

Lister les ports COM​

Les ports qui existent à cet instant, comme celui qu'un Arduino vient d'obtenir en étant branché. Voir Périphériques série et Arduino.

n = SerialEnumeratePorts();
if (n == 0) UtilityPrint("No COM ports. Is the board plugged in?");
for (i = 0; i < n; i = i + 1) {
UtilityPrint(SerialGetEnumeratedPortAt(i));
}

Garder ouvert le port d'un Arduino et lui envoyer des commandes​

Ouvrez le port une seule fois, pour qu'une carte qui redémarre à l'ouverture de son port ne manque aucune commande, puis envoyez une ligne et lisez la réponse.

// Load global event: open the port once, at the sketch's speed. An Uno or Nano
// restarts every time its port opens, so a port opened per command would lose
// the command while the board boots.
if (!SerialOpenPort("COM4", 115200, SerialParity.None, 8, SerialStopBits.One, "")) {
UtilityPrint("COM4 isn't available: unplugged, or open in the Arduino IDE's Serial Monitor?");
}

// Any gesture or hotkey: send a command line and read the board's reply.
// (The sketch reads a line with Serial.readStringUntil('\n') and answers OK.)
if (SerialWriteTextLine("COM4", "LED 255 0 0", 115200)) {
reply = SerialGetTextLine("COM4", 1, 115200);
if (reply != "OK") UtilityPrint(StringFormat("Board said: {0}", reply, ""));
}

Transformer un bouton rotatif Arduino en réglage du volume​

Une lecture de potentiomètre de 0 à 1023 sur chaque ligne devient le volume de lecture.

// Arduino side: a potentiometer on A0, one reading per line.
// void setup() { Serial.begin(115200); }
// void loop() { Serial.println(analogRead(A0)); delay(50); }
// Empty text as the terminator means CR LF, which Serial.println sends.
SerialMonitorCreate("knob", "COM4", 115200, SerialParity.None, 8, SerialStopBits.One, "",
"line = ContextGetSerialTextLine(); if (StringIsNumber(line, true)) MultimediaSetVolume(AudioEndpoint.Playback, StringToNumber(line, true) / 1023.0);");