Saltar al contenido principal

Ejemplos

Scripts que funcionan, que abarcan la sintaxis y las áreas de funciones integradas. Filtre por tema o busque en su código y su texto. Los scripts que usan funciones integradas Context* necesitan un disparador de gesto o de tecla de acceso rápido. En la consola de diagnóstico, esas funciones integradas devuelven sus valores vacíos predeterminados.

Hola, consola​

El script más pequeño. UtilityPrint escribe en la consola de diagnóstico, o en el registro de impresión cuando el script no se ejecutó desde la consola.

UtilityPrint("Hello from Input.Observer");

Los cinco tipos de valor​

Una variable de cada tipo, impresa mediante StringFormat, que es la única forma de convertir en Text un valor que no es 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, ""));

Veracidad de cada tipo​

Lo que if considera verdadero para cada tipo: números distintos de cero, Text no vacío, identificadores no nulos.

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");

Cadena else-if​

Clasifica la posición horizontal del cursor en tercios del monitor que está debajo de él.

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");

Bucles de conteo: hacia arriba, hacia abajo y por saltos​

Las tres partes de for son asignaciones o expresiones que usted elige.

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

Bucles anidados: una tabla de multiplicar​

Bucles for anidados que construyen una línea de Text por fila.

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);
}

Bucle while: esperar una ventana, con tiempo de espera​

La condición hace el trabajo del “while”, y el contador lo limita a 5 segundos.

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) con una marca de salida​

Un paso que se asigna a sí mismo (go = go) crea un bucle que solo se detiene cuando su cuerpo borra la marca. La tecla de acceso rápido para detener todo también lo termina siempre.

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 y continue​

Lleve el contador más allá del límite para salir con break. Ponga el resto del cuerpo dentro de un if para seguir con 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);
}
}

Sorpresas de precedencia​

Dos trampas de precedencia de C, y los paréntesis explícitos que las corrigen.

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));

&& y || evalúan ambos lados​

Ambos operandos se ejecutan siempre, lo que importa cuando el lado derecho tiene un efecto o puede fallar.

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));
}

Igualdad entre tipos​

Integer y Real se comparan numéricamente. Cualquier otro par de tipos distintos simplemente no es igual.

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

La aritmética de tipos mixtos da 0​

Las combinaciones que un operador no entiende dan Integer 0 sin error. Imprima un valor cuando un resultado parezca incorrecto.

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);

Comentarios, instrucciones vacías y bloques​

Comentarios de línea y de bloque, un punto y coma suelto y un bloque de nivel superior (que no crea un ámbito).

// 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

División de Integer frente a Real, y división entre cero​

La división entera trunca hacia cero, un operando Real da un resultado Real y dividir entre cero da 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, ""));

Resto sin %​

n - (n / d) * d es el % de C. Con un divisor que es potencia de dos, una máscara hace lo mismo para números no negativos.

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, ""));

Redondeo y funciones integradas matemáticas de Real​

Un Integer que se pasa donde una función integrada declara Real se convierte en Real. El redondeo aleja las mitades de cero.

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

Limitar un valor a un intervalo​

MathClamp (como MathMin/MathMax) acepta cualquiera de los dos tipos numéricos y devuelve el ganador tal como era.

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

Números aleatorios y un volado​

MathRandom incluye ambos extremos del intervalo.

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

Longitud del trazo de un gesto​

Suma la distancia en línea recta entre puntos consecutivos del gesto. La suma de cuadrados Integer se convierte en Real al pasar a 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)));

Mover el mouse en círculo​

Grados a radianes, trigonometría con Real y MathRound de vuelta a coordenadas de píxel 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);

Dar formato a un Real sin seis decimales​

Escale y redondee para obtener un porcentaje, o para separar un valor en parte entera y centésimas y mostrar dos decimales. Funciona con valores no negativos.

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

Máscaras de marcas: activar, borrar, alternar, comprobar​

Las cuatro operaciones habituales de máscara sobre sus propios valores de marca.

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, ""));

Leer el color del píxel bajo el cursor​

Desempaquete el Integer 0xRRGGBB con desplazamientos y máscaras.

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");
}

De Integer a texto hexadecimal​

Ninguna función integrada da formato hexadecimal, así que separe cuatro bits a la vez y busque cada dígito en 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

Contar los bits activos​

Recorra los 64 bits con desplazamientos y sume cada bit bajo.

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

Casos límite del desplazamiento​

>> conserva el signo, y una cantidad de desplazamiento fuera de 0–63 da 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

Intercambiar dos Integer​

La forma habitual necesita una variable temporal. XOR los intercambia sin ella.

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 de estado de tecla​

KeyboardGetKeyState devuelve el valor de Win32 sin procesar: el bit alto significa que la tecla está presionada y el bit bajo, que está alternada. Las funciones integradas Is* hacen esa misma comprobación por usted.

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)));

Secuencias de escape y rutas de Windows​

Duplique cada barra invertida de una ruta. \t, \n y \r son secuencias de escape, y cualquier otra barra invertida se descarta.

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);

Dar formato a más de dos valores​

StringFormat solo rellena {0} y {1}. Anide una llamada, o una varias con +.

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);

Dividir y recorrer​

StringSplit devuelve el recuento y StringGetSplitPartAt lee cada parte. Las partes entre dos delimitadores contiguos están vacías.

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]

Divisiones anidadas: pares clave=valor​

La división interior reemplaza las partes de la división exterior, así que vuelva a dividir la lista exterior al principio de cada pasada.

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)));
}

Último índice de: una extensión de archivo​

No existe LastIndexOf, así que compruebe cada posición y quédese con la última coincidencia.

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
}

Leer un número que escribió alguien​

false lo lee en el formato regional del usuario (un usuario alemán escribe 1.234,5). Los grupos de dígitos deben seguir entonces ese formato: para un usuario de español (México), 1,234.5 es un número y 1,5 no. StringIsNumber detecta el texto que no es un número, que StringToNumber por sí sola convertiría 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);
}

Iniciar un programa, esperar su ventana y actuar sobre ella​

WindowWaitFor sondea durante el tiempo de espera (60 segundos como máximo) y da una ventana nula si nada coincidió. El patrón es una expresión regular sobre el título que no distingue mayúsculas de minúsculas; el título de un programa sigue el idioma de presentación de Windows, así que busque la parte que no cambia.

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");
}

Extraer un valor de un texto copiado con una expresión regular​

Sintaxis PCRE2, distingue mayúsculas de minúsculas a menos que el patrón empiece con (?i), y reconoce Unicode (\w coincide con letras acentuadas). El grupo 0 es la coincidencia completa; una barra invertida del patrón se escribe \\ dentro de una cadena de script. $1 en un reemplazo es el grupo 1. Las funciones integradas Window*Regex/Shell*Regex usan el mismo motor, siempre sin distinguir mayúsculas de minúsculas.

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"));

Rellenar un número con ceros​

Anteponga caracteres hasta que el Text tenga la longitud suficiente.

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

Invertir un Text​

Recorra el Text hacia atrás, una unidad UTF-16 a la vez. Los caracteres fuera del plano multilingüe básico (la mayoría de los emoji) ocupan dos unidades y saldrían partidos.

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

Contar las palabras del portapapeles​

Convierta las tabulaciones y los saltos de línea en espacios, divida por espacios y cuente las partes que no están vacías.

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, ""));

Comparaciones sin distinguir mayúsculas de minúsculas​

Pase ambos lados a minúsculas, porque todos los operadores y funciones integradas de Text distinguen mayúsculas de minúsculas.

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

El orden del texto es ordinal​

< compara unidades de código UTF-16: todas las letras ASCII mayúsculas van antes que todas las minúsculas.

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

Rellenar una plantilla y pegarla​

StringReplace rellena los marcadores %NAME%. El portapapeles se guarda y se restaura alrededor del pegado.

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();

Unir las líneas del portapapeles en una sola​

Divida por \n. StringTrim también quita el \r de los finales de línea de Windows, así que esto funciona tanto si las líneas terminan con \r\n como solo con \n.

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);

Buscar en la web el texto seleccionado​

ClipboardCopySelection espera a que llegue la copia en lugar de adivinar. StringUrlEncode evita que &, #, los espacios y las letras acentuadas rompan la dirección. Codifique solo el término de búsqueda, nunca la URL completa.

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

Un gesto, varias opciones​

UIShowMenu recibe un elemento por línea (- solo es un separador) y devuelve el índice del elemento elegido, contando desde 0 y omitiendo los separadores, o -1 si se descarta el menú. UIShowInputBox devuelve "" al cancelar.

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 fecha de hoy y un nombre de archivo con marca de tiempo​

DateTimeGetNow devuelve texto ISO 8601. DateTimeFormat lo escribe a la manera del usuario, o como un FileStamp que se ordena por tiempo y es seguro en un nombre de archivo.

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 con nombre frente a números sin procesar​

Una constante se compila a su número, así que estas llamadas son idénticas. El hexadecimal coincide con la documentación de 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));

Alternar maximizar en la ventana del gesto​

La acción de gesto más común. ContextGetWindow es la ventana sobre la que empezó el gesto.

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

Fijar una ventana encima​

WindowSetTopmost establece explícitamente “siempre visible”, y WindowToggleTopmost lo invierte. Una propiedad de ventana recuerda qué estado eligió este 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));
}

Recorrer niveles de transparencia de una ventana​

Baja la opacidad por pasos de 255 a 105 y vuelve a 255. Una ventana que no es por capas informa 255.

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

Ajustar la ventana activa a la mitad izquierda de su monitor​

Usa el área de trabajo (true) para que la ventana no cubra la barra de tareas.

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);

Ajustar una ventana a la celda de una cuadrícula de 3×2 bajo el cursor​

Las funciones integradas Region* dividen un rectángulo en celdas, encuentran la celda que contiene un punto y dan sus límites.

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));
}

Lanzar una ventana al siguiente monitor​

El segundo argumento mueve el mouse junto con la ventana.

WindowSendToNextScreen(ContextGetWindow(), true);

Enumerar las ventanas de nivel superior visibles​

Enumerar y luego leer por índice, omitiendo las ventanas ocultas, encubiertas y sin título.

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));

Minimizar todas las ventanas de una aplicación​

Busca el ejecutable con una expresión regular que no distingue mayúsculas de minúsculas. Observe el \\.: un \. de expresión regular escrito dentro de una cadena de script.

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

Cerrar ventanas por patrón de título, después de confirmar​

Una expresión regular sobre los títulos, un recuento en el mensaje y una comprobación de qué botón se presionó.

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));
}
}

Recordar y restaurar la posición de una ventana​

Las propiedades de ventana guardan valores Integer en la propia ventana, entre ejecuciones, hasta que se cierra. Una propiedad que nunca se estableció se lee como 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);
}

Inspeccionar los controles secundarios de una ventana​

Las ventanas secundarias usan la misma caché de ventanas que la enumeración de nivel superior.

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)));
}

Del proceso a la ventana​

Enumere los identificadores de proceso por nombre de ejecutable y luego encuentre la ventana de cada uno.

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)));
}

Describir lo que está bajo el cursor​

El control que está bajo un punto, su ventana de nivel superior y el punto convertido a coordenadas de cliente.

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)));

Ocultar una ventana en la bandeja​

Minimiza al área de notificación. TrayRestoreAllWindows() las devuelve todas.

TrayMinimizeWindow(ContextGetWindow());

Todo lo que sabe el contexto del disparador​

Asócielo a un gesto para ver lo que puede leer su script.

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()));

¿Hacia dónde fue el trazo?​

Compare el primer y el último punto y elija el eje dominante.

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);
}

Bifurcar según el botón del trazo​

ContextGetStrokeButton devuelve un valor MouseButton.*, o -1 fuera de un disparador de gesto o de botón del mouse.

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");
}

Capturar el área que encerró en un círculo​

Guarda el rectángulo delimitador del gesto como PNG en Imágenes.

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

Dejar pasar un dibujo no reconocido​

Si se dibujó un gesto sobre una aplicación de dibujo, reproduce el trazo en la aplicación como un arrastre normal.

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

Hacer clic en algún lugar y devolver el cursor​

Guarde la posición del cursor en variables, haga clic y regrese.

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

Hacer clic en un punto dentro de una ventana​

Las coordenadas de cliente siguen siendo correctas dondequiera que se haya movido la ventana.

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

Un arrastre por script​

Presionar, mover por pasos, soltar. Las funciones integradas separadas de presionar, mover y soltar existen para esto.

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);

Desplazarse por muescas​

Una muesca de la rueda es 120. Un valor negativo desplaza hacia abajo o hacia la izquierda.

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

Confinar el cursor a una ventana durante 5 segundos​

MouseLockToRect se aplica en todo el sistema hasta MouseUnlock, así que úselas siempre en pareja.

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

Combinaciones de teclas​

Prefijos de modificador ^ Ctrl, + Shift, % Alt y @ Win, y luego una tecla.

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

Escribir una firma​

KeyboardTypeText escribe caracteres. Envíe Enter como combinación de teclas entre líneas, para que todas las aplicaciones reciban una pulsación real de la tecla Enter.

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

Shift+clic​

Mantenga presionada una tecla alrededor de una acción del mouse y suéltela en el mismo script. Una tecla que se deja presionada sigue presionada.

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

Teclas multimedia​

Envíe teclas multimedia y de volumen por sus nombres de VirtualKey.

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

Cambiar el comportamiento mientras se mantiene presionada Ctrl​

Compruebe el estado actual de una tecla para dar a un gesto dos significados.

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

Pasar a mayúsculas el texto seleccionado​

Copie la selección, cámbiela, péguela de nuevo y restaure lo que hubiera antes en el portapapeles.

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

Copie la selección y abra una URL de búsqueda. Los espacios se convierten en +. Para codificar también todos los demás caracteres, use StringUrlEncode, como lo hace Buscar en la web el texto seleccionado.

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

Guardar en un archivo una imagen copiada​

Escribe en el disco la imagen del portapapeles e informa el resultado.

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

Agregar a un archivo de registro​

Crea el archivo con un encabezado la primera vez y luego agrega una línea por ejecución.

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

Leer un archivo y contar sus líneas​

FileReadText devuelve todo el archivo como Text, que luego se divide por \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)));

Contar los tipos de archivo de una carpeta​

Enumera una carpeta sin recursividad y cuenta las coincidencias sin distinguir mayúsculas de minúsculas.

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, ""));

Hacer una copia de seguridad de un archivo antes de editarlo​

Copiar sobrescribiendo y luego reemplazar el contenido.

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

Vigilar una carpeta​

Combine marcas FileNotify con |. El script de la vigilancia es Text, así que sus comillas interiores llevan secuencia de escape. Lee lo que ocurrió mediante ContextGetWatch*.

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

Un temporizador repetitivo que cuenta​

El script de un temporizador tiene sus propias variables, así que Storage lleva la cuenta entre activaciones. Se activa 5 veces, con un segundo de separación.

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

Script de temporizador desde un snippet, sin secuencias de escape​

Guarde un script de temporizador largo en un snippet y pase su texto, así no hay comillas anidadas que escapar.

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

Enumerar y detener temporizadores​

Enumere los temporizadores con nombre y elimine uno o todos.

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

Un interruptor que se conserva entre ejecuciones​

StorageGetValue de una clave que nunca se estableció es Integer 0, que es falso, así que la primera ejecución activa el modo. El valor dura hasta que Input.Observer se cierra; las funciones integradas Persistent conservan uno entre reinicios.

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

Un contador que se conserva después de un reinicio​

Las funciones integradas Storage*Persistent* guardan los valores en storage.toml junto a la configuración, así que siguen ahí después de que Input.Observer se reinicia. Es texto sin formato, nunca cifrado: no guarde contraseñas ahí. Las ventanas no se pueden conservar; un identificador no significa nada después de un reinicio. Si storage.toml existe pero no se puede leer cuando Input.Observer se inicia, StorageSetPersistentValue devuelve false: el valor solo se conserva hasta que Input.Observer se cierra, y no se guarda nada hasta el siguiente inicio.

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

Una lista guardada en Storage​

No hay arreglos, pero las claves numeradas creadas con StringFormat funcionan como uno.

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, "")));
}

Permitir que solo una acción ejecute una sección a la vez​

Un bloqueo con nombre impide que dos ejecuciones superpuestas se intercalen. Compruebe el resultado con LockResult y libere el bloqueo cuando termine.

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");
}

Hacer una pregunta​

Los botones y el ícono son nombres Text. El resultado es el nombre del botón en el que se hizo clic.

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");
}

Subir el volumen con indicación en pantalla​

El volumen es un Real de 0.0 a 1.0. UIShowDisplayMessage recibe 19 argumentos posicionales.

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 mensaje en pantalla que se actualiza en vivo​

Conserve el id de sesión y páselo a UIUpdateDisplayMessage con los mismos 19 argumentos.

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);

Una notificación de Windows​

Un título y un mensaje, mostrados como notificación del sistema.

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

Alternar el silencio del micrófono​

El extremo Capture es el dispositivo de grabación predeterminado.

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

Reproducir un sonido​

Archivos WAV y MP3 desde una ruta.

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

Iniciar una aplicación o cambiar a ella​

Activa la aplicación si ya está en ejecución y, si no, la inicia.

ShellRunOrActivate("notepad.exe");

Ejecutar un programa con un verbo y un estilo de ventana​

El verbo es una constante ShellVerb o cualquier verbo como Text. El estilo de ventana es una 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

Ejecutar y esperar a que termine​

Con waitForExit establecido en true, el subproceso del script se bloquea hasta que el programa se cierra. Mientras tanto, la entrada sigue fluyendo. Detener todas las acciones termina la espera: el programa sigue en ejecución y la llamada devuelve false.

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

Expandir variables de entorno​

Construye una ruta que funciona en el equipo de cualquier usuario.

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

Pasar el trabajo a AutoHotkey​

Ejecuta código de AutoHotkey fuera del proceso y devuelve su código de salida, o -1 si AutoHotkey no está configurado.

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

Enumerar los monitores​

Nombre, límites completos, área de trabajo y PPP de cada monitor, por índice.

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), ""));
}

Enviar una ventana a un monitor concreto​

Por índice de la enumeración, con la pantalla siguiente como alternativa cuando ese monitor no existe.

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

Pasar al siguiente perfil de gestos​

Encuentre el índice del perfil activo, súmele uno y vuelva al principio con el patrón del resto.

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));
}

Estado del motor​

Lea si el motor está desactivado o en modo seguro y luego póngalo en pausa. Vuelva a activarlo desde el menú del ícono de la bandeja.

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

Dejar pasar el siguiente arrastre con el botón derecho​

Omite una vez la captura de gestos, para que el siguiente arrastre con el botón derecho llegue a la aplicación.

EngineDisableNextGesture();

Snippets como funciones reutilizables​

Pase argumentos y resultados mediante Storage. El snippet se ejecuta hasta el final antes de la siguiente línea.

// 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"), ""));

Comunicarse con un complemento​

Envía un comando Text a un complemento conectado y espera su respuesta Text durante el tiempo de espera.

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

Hacer una pregunta a un dispositivo serie​

Abra el puerto, escriba una línea, espere hasta 2 segundos la respuesta y cierre el puerto. La paridad y los bits de parada son 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");
}

Asignar los botones de un dispositivo serie a teclas multimedia​

Un monitor ejecuta su script por cada línea recibida. ContextGetSerialTextLine es la línea.

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);");

Enumerar los puertos COM​

Qué puertos existen en este momento, como el que acaba de recibir un Arduino al conectarlo. Consulte Dispositivos serie y 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));
}

Mantener abierto el puerto de un Arduino y enviarle comandos​

Abra el puerto una sola vez, para que una placa que se reinicia al abrirse su puerto no pierda comandos, y luego envíe una línea y lea la respuesta.

// 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, ""));
}

Convertir una perilla de Arduino en un control de volumen​

La lectura de un potenciómetro, de 0 a 1023 en cada línea, se convierte en el volumen de reproducción.

// 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);");