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();
Rechercher la sélection sur le web
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);");