Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Inspeccione e interactúe con la ejecución de aplicaciones Windows desde la línea de comandos. Los agentes de IA y los desarrolladores usan para las pruebas, la depuración y la automatización de la interfaz de usuario.
Visión general
winapp ui proporciona comandos para inspeccionar e interactuar con las interfaces de usuario de Windows aplicación.
Usa Windows Automatización de la interfaz de usuario (UIA). Funciona con cualquier aplicación de Windows: WPF, WinForms, Win32, Electron y WinUI 3.
La mayoría de los comandos impulsan la aplicación a través de patrones UIA (sin inyección de entrada). Las excepciones insertan entrada real: ui click/ui hoverui drag/use la simulación del mouse,/ui touchui pen sintetizan la entrada táctil y lápiz/lápiz, y ui send-keys sintetizan la entrada del teclado, para controles y escenarios que los patrones UIA no pueden controlar.
Important
Requisito de escritorio interactivo (verbos de inserción de entrada).click, hover, drag, touchpen, , scroll --wheely send-keys --via send-input sintetizar la entrada de nivel de sistema operativo, por lo que necesitan un escritorio interactivo desbloqueado con la ventana de destino en primer plano. En una estación de trabajo bloqueada o en un escritorio seguro (LogonUI/UAC), no pueden insertar y producir errores rápidos ( no_interactive_desktop distintos de la elevación oforeground_not_target los casos).
touch
/
pen niegue además cuando no se resuelve ninguna ventana (no_target); una coordenada fuera de la ventana de destino es una advertencia no irrecuperable (una warnings[] entrada bajo --jsono una línea de advertencia en modo de texto) y la inyección sigue funcionando, coherente con los verbos del mouse. Todo lo demás , inspect, , get-valueset-valuesearchinvokewait-forget-property, scroll --direction/--to, screenshot controla la aplicación a través de patrones de UIA y es fácil de usar la sesión sin encabezados o bloqueadas. Preferir los verbos de patrón UIA en CI; reserve los verbos de inyección para escenarios que realmente necesitan una entrada real. Antes de insertar, los verbos de gesto también vuelven a resolver el elemento de destino y se niegan con target_moved si todavía se animan o reubican, en lugar de la entrada de aterrizaje en el espacio vacío.
Quick Start
# Connect to any app and see its UI tree
winapp ui inspect -a notepad
# Find specific elements
winapp ui search Button -a notepad
# Activate an element
winapp ui invoke Close -a notepad
# Take a screenshot
winapp ui screenshot -a notepad
Aplicaciones de destino
Por nombre de proceso
winapp ui inspect -a notepad
winapp ui inspect -a slack # auto-picks visible window for multi-process apps
winapp ui inspect -a imageresizer # partial match: finds PowerToys.ImageResizer
Por título de ventana
winapp ui inspect -a "LICENSE - Notepad"
winapp ui inspect -a "Fix WinApp" # partial title match
Por PID
winapp ui inspect -a 12345
Por HWND (estable, sobrevive a los cambios de tabulación o título)
# Discover HWNDs
winapp ui list-windows -a Terminal
→ HWND 985238: "🤖 Testing" (WindowsTerminal, PID 21228)
→ HWND 131906: "Fix WinApp" (WindowsTerminal, PID 21228)
# Target specific window
winapp ui inspect -w 131906
winapp ui screenshot -w 131906
Se usa -a para la detección, -w para destinos estables. Cuando -a coincide con varias ventanas, el comando los enumera con HWND para que elija.
Selectores
Elementos de destino mediante el selector que se muestra en la [brackets] salida de inspección o búsqueda.
Hay tres tipos de selectores:
| Selector | Significado | Example |
|---|---|---|
MinimizeButton |
AutomationId (que se muestra cuando es único, estable, preferido) | winapp ui invoke MinimizeButton -a myapp |
btn-close-d1a0 |
Slug semántico (que se muestra cuando no hay un automationId único) | winapp ui invoke btn-close-d1a0 -a myapp |
Submit |
Búsqueda de texto sin formato en Name/AutomationId (subcadena que no distingue mayúsculas de minúsculas) | winapp ui invoke Submit -a myapp |
Los selectores AutomationId son identificadores del conjunto de desarrolladores (AutomationProperties.AutomationId en XAML).
Cuando un AutomationId es único en todo el árbol inspect de la interfaz de usuario y search lo muestra directamente como selector, estos sobreviven a los cambios de diseño, la localización y la reestructuración del árbol.
Los selectores slug (por ejemplo, btn-close-d1a0) se generan cuando no existe ningún AutomationId único.
Formato: prefix-name-hash. El hash valida la identidad del elemento, pero puede estar obsoleta después de los cambios de la interfaz de usuario.
Inspección del formato de salida
El inspect comando muestra el árbol de elementos con salida coloreado (selector en cian, nombre en verde, metadatos en gris):
TabView Tab (0,-1 1200x48)
TabListView List (4,-1 1100x48)
tab-newtab-5f5b TabItem "New Tab" (14,-1 200x48)
NewTabButton SplitButton "New Tab" [collapsed] (1104,5 96x36)
Found 10 elements (--depth 3). Use the first token as selector, e.g.: winapp ui invoke TabView -a terminal
La primera palabra de cada línea es el selector: úsela con otros ui comandos.
Cuando un elemento tiene un automationId único, se usa directamente (por ejemplo, TabView, NewTabButton).
Cuando no existe ningún automationId único, se usa un slug generado (por ejemplo, tab-newtab-5f5b).
Slugs semánticos
Slugs usa el formato: prefix-normalizedname-hash donde:
- prefijo : abreviatura de tipo de 3 letras (btn, txt, chk, cmb, itm, tab, img, lbl, pn, win, grp, lnk, mnu, etc.)
- normalizedname : alfanumérico en minúsculas de AutomationId (preferido) o Name, max 15 chars
- hash : hash hexadecimal de 4 caracteres del runtimeId del elemento (valida la identidad del elemento)
Los slugs son seguros para shell (sin caracteres especiales), únicos y se pueden usar directamente como argumentos. El hash proporciona detección de obsolescencia, si el elemento se ha reemplazado, obtiene: "Elemento puede haber cambiado. Vuelva a ejecutar la inspección."
Los elementos sin nombre o AutomationId muestran solo el prefijo + hash (por ejemplo, pn-c8a3).
Desambiguación de varias coincidencias
Los slugs de inspect/search la salida son únicos, pero pueden cambiar entre cambios de diseño: úselos en nombres de tipo sin formato o texto cuando haya varias coincidencias. Cuando un selector es ambiguo, la CLI imprime todas las coincidencias con sus slugs para que pueda elegir la derecha y volver a ejecutarla con ese slug.
winapp ui search Button -a myapp # shows: btn-ok-a1b2 "OK", btn-cancel-c3d4 "Cancel"
winapp ui invoke btn-ok-a1b2 -a myapp # invoke using slug (preferred)
winapp ui invoke btn-cancel-c3d4 -a myapp # invoke the other Button by its slug
Búsqueda de texto plano
Use texto sin formato para buscar elementos, sin sintaxis especial necesaria:
winapp ui search Minimize -a notepad # finds elements with "Minimize" in Name or AutomationId
winapp ui search Close -a notepad # case-insensitive substring match
winapp ui invoke Minimize -a notepad # search + invoke in one step (disambiguates if needed)
winapp ui search "Save" -a notepad # find elements containing "Save"
winapp ui search "error" -a myapp # case-insensitive match
Cuando una búsqueda de texto coincide con varios elementos (por ejemplo, SettingsExpander donde Group, Button y Text comparten el mismo nombre), la CLI elige automáticamente el único elemento invocable. Si se invocan varios, se muestran todas las coincidencias con slugs.
Para los resultados de búsqueda no invocables (por ejemplo, un TextBlock dentro de un botón), la búsqueda muestra automáticamente el antecesor invocable más cercano, el elemento primario que puede usar con invoke.
Esto funciona para todos los selectores de búsqueda:
lbl-savechanges-a1b2 "Save changes" (120,40 80x20)
^ invoke via: btn-save-c3d4 "Save"
El selector expuesta se puede usar directamente:
winapp ui invoke btn-save-c3d4 -a myapp # invoke the parent Button
Commands
estado
Conéctese a una aplicación y muestre la información de conexión.
winapp ui status -a notepad
winapp ui status -a notepad --json
Inspeccionar
Vea el árbol de elementos de la interfaz de usuario. La salida muestra los slugs semánticos con sangría de 2 espacios para la jerarquía:
winapp ui inspect -a notepad # full window tree, depth 3
winapp ui inspect -a notepad --depth 5 # deeper tree
winapp ui inspect txt-searchbox-e5f6 -a notepad # subtree rooted at element
winapp ui inspect --ancestors btn-close-d1a2 -a notepad # walk up from element to root
winapp ui inspect -a myapp --interactive # invokable elements only, auto-depth 8
winapp ui inspect -a myapp --hide-disabled # hide disabled elements
winapp ui inspect -a myapp --hide-offscreen # hide offscreen elements
Salida de ejemplo (valor predeterminado):
win-aidevgalleryp-f1a3 "AI Dev Gallery Preview" (94,206 1280x1023)
pn-c8a3 (102,207 1264x1014)
btn-minimize-d1a0 "Minimize" (1222,206 48x48)
btn-maximize-e2b1 "Maximize" (1270,206 48x48)
itm-samples-3f2c "Samples" (102,330 72x62)
Salida de ejemplo ( —--interactive solo elementos invocables, lista plana):
btn-minimize-d1a0 "Minimize" (1222,206 48x48)
btn-maximize-e2b1 "Maximize" (1270,206 48x48)
btn-close-d1a2 "Close" (1318,206 48x48)
itm-home-7b3e "Home" (102,268 72x62)
itm-samples-3f2c "Samples" (102,330 72x62)
itm-models-9a4f "Models" (102,392 72x62)
Los elementos pueden mostrar estos marcadores de estado:
-
[on]/[off]/[indeterminate]: estado de alternancia/casilla -
[collapsed]/[expanded]: estado de expandir o contraer para árboles, cuadros combinados, elementos de menú -
[scroll:v]/[scroll:h]/[scroll:vh]: contenedor desplazable (vertical, horizontal o ambos) -
[offscreen]: el elemento no está visible en la pantalla -
[disabled]: el elemento no está habilitado -
value="..."— contenido de texto actual para elementos editables (cuando es diferente de Name)
search
Buscar elementos que coincidan con un selector. La salida muestra los slugs semánticos:
winapp ui search Button -a notepad # all buttons
winapp ui search Close -a notepad # finds elements with "Close" in name
winapp ui search SearchBox -a notepad # finds elements with "SearchBox" in name or AutomationId
winapp ui search Button --max 10 -a notepad # limit results
Ejemplo de resultado:
btn-minimize-d1a0 "Minimize" (1222,206 48x48)
btn-maximize-e2b1 "Maximize" (1270,206 48x48)
btn-close-d1a2 "Close" (1318,206 48x48)
Los slugs que se muestran en la salida (por ejemplo, btn-minimize-d1a0) se pueden usar directamente con otros comandos:
winapp ui invoke btn-minimize-d1a0 -a notepad
get-property
Lee los valores de propiedad de un elemento. Incluye el estado específico del patrón (ToggleState, Value, IsSelected, etc.).
winapp ui get-property btn-submit-7a90 -a myapp # all properties
winapp ui get-property chk-checkbox-b2c3 -p ToggleState -a myapp # checkbox state
winapp ui get-property txt-textbox-a4b1 -p Value -a myapp # current text value
winapp ui get-property cmb-combobox-d5e6 -p ExpandCollapseState -a myapp # expanded or collapsed
captura de pantalla
Capture una ventana o un elemento como PNG. Cuando existen varias ventanas (por ejemplo, la aplicación y el cuadro de diálogo abierto), se componen en un único PNG con cada ventana cosida.
winapp ui screenshot -a notepad # saves screenshot.png in cwd
winapp ui screenshot -a notepad --output my.png # custom filename
winapp ui screenshot -a notepad --json # returns file path as JSON
winapp ui screenshot -w 131906 # target specific HWND (+ its dialogs)
winapp ui screenshot txt-searchbox-e5f6 -a myapp # crop to element bounds
winapp ui screenshot -a myapp --capture-screen # capture from screen (includes popups/overlays; foregrounds window)
winapp ui screenshot -a myapp --focus # bring window to foreground first, then capture (default WGC path)
Cuando los diálogos o elementos emergentes están abiertos, todas las ventanas se componen en un PNG para que pueda ver el estado completo de la interfaz de usuario en una sola imagen.
La ruta de acceso de captura predeterminada usa Windows. Graphics.Capture (WGC), leyendo la superficie compuesta por DWM real, conservando las esquinas redondeadas, la transparencia y trabajando incluso mientras otras windows ocluyen la ventana. Si WGC no está disponible (compilaciones anteriores Windows), la CLI vuelve a PrintWindow.
Use --capture-screen cuando necesite capturar menús emergentes, listas desplegables, controles flotantes o superposiciones de información sobre herramientas que no sean propiedad de la ventana de destino.
--capture-screen lee desde el controlador de dominio de la pantalla y lleva la ventana al primer plano. Use --focus si solo desea poner en primer plano la ventana sin cambiar los modos de captura (por ejemplo, para asegurarse de que la captura de pantalla coincide con lo que el usuario está viendo actualmente).
registro
Grabe la ventana de destino (o la región de un elemento) en un vídeo MP4 H.264. Los fotogramas se capturan a través de Windows captura de gráficos (con la reserva PrintWindow/screen-DC) y se codifican incrementalmente con Media Foundation, por lo que las grabaciones nunca almacenan en búfer el vídeo completo en la memoria.
Comportamiento predeterminado (--duration-sec 0): registra hasta que se detiene. Use Ctrl+C de forma interactiva o (para llamadores de agente o mediante programación) escriba una nueva línea en stdin o cierre stdin para detener y finalizar el MP4 correctamente. Un MP4 válido y reproducible siempre se finaliza en cualquier parada correcta, sin daños.
# Timed: record for 10 s at 15 fps
winapp ui record -a myapp --duration-sec 10 --fps 15 --output demo.mp4
# Unbounded (default): record until Ctrl+C, downscaled to max 1280px longest edge
winapp ui record -a myapp --max-edge 1280 --output capture.mp4
# Programmatic stop (agent/script): pipe a newline; the recorder stops and writes a valid MP4
"" | winapp ui record -a myapp --json --output capture.mp4
# Record a single element's region (fails with element_not_found if the selector doesn't match)
winapp ui record itm-chart-9f8e -a myapp --output chart.mp4
# Include screen overlays / popups (captures from screen DC; brings window to foreground)
winapp ui record -a myapp --capture-screen --duration-sec 5 --output with-popups.mp4
Opciones:
-
--duration-sec N: registro durante N segundos. Valor predeterminado 0 = registro hasta que se detenga. -
--fps N: fotogramas de destino por segundo (valor predeterminado 15). -
--max-edge N— Escala inferior para que el borde más largo sea como máximo N píxeles (0 = sin escala inferior). -
--capture-screen— Captura desde el controlador de dominio de la pantalla (incluye superposiciones o elementos emergentes; en primer plano la ventana). -
--output <path>: ruta de acceso MP4 de salida. El valor predeterminado esrecording-<timestamp>-<guid>.mp4en el directorio actual.
Mecanismos de detención:
- Interactivo: Ctrl+C (cualquier plataforma).
- Programmatic/agent: escriba una nueva línea (
"") o cierre stdin (EOF). La detención se aplica tan pronto como el codificador esté listo (primer fotograma capturado); cualquier señal de parada que llegue antes de que el primer fotograma se cierre y se aplique inmediatamente a la preparación, no hay ninguna ventana de gracia y ningún retraso en el reloj.
Modos de captura (notificados en el campo JSON mode ):
-
wgc: Windows captura de gráficos (valor predeterminado; funciona mientras la ventana está ocluida). -
printwindow— Impresión de GDIWindow (reserva cuando WGC no está disponible en este sistema o sesión; vuelva a ejecutar con--capture-screenpara usar el controlador de dominio de pantalla en su lugar). -
screen— Dc de pantalla a través--capture-screende (incluye superposiciones o elementos emergentes; lleva la ventana al primer plano).
Salida JSON (--json):
-
stdout (resultado final):
{ "path", "frames", "width", "height", "fileSize", "codec": "h264", "mode", "fps", "durationSec" } -
stderr (evento de ejecución, emitido cuando comienza la captura):
{ "event": "recording-started", "path", "fps", "durationSec" }
El evento de ejecución en stderr permite a los autores de llamadas mediante programación saber que el bucle de captura está activo sin esperar el resultado final. El resultado final JSON en stdout es un único objeto limpio.
Códigos de error:
-
element_not_found— Selector dado pero no se encontró ningún elemento coincidente; produce un error inmediatamente (no hay ningún archivo parcial escrito). -
ambiguous_selector— Un selector de texto sin formato coincide con varios elementos; use un slug de las sugerencias que se muestran en el error (o desdeinspectla salida) para tener como destino un elemento específico. -
invalid_arguments— Valor de opción no válido (por ejemplo,--duration-sec -1o> 86400).
Limitación conocida: ventanas emergentes: Cuando se graba un elemento específico (por selector) que reside dentro de un elemento emergente que se representa en su propia ventana de nivel superior (por ejemplo, un control flotante WinUI/XAML, sugerencia de enseñanza, información sobre herramientas o menú)Xaml_WindowedPopupClass , la grabadora puede capturar la ventana principal subyacente en lugar del elemento emergente, lo que genera fotogramas en blanco o obsoletos. Registre toda la ventana (omita el selector) o use winapp ui screenshot --capture-screen para los elementos emergentes. Se realiza un seguimiento en #646.
Active mediante programación un elemento (haga clic en el botón, active la casilla de alternancia, expanda cuadro combinado).
winapp ui invoke btn-submit-7a90 -a myapp # by slug from inspect
winapp ui invoke btn-submit-a1b2 -a myapp # by slug from inspect/search
winapp ui invoke cmb-sizecombobox-b4c5 -a myapp # expand combo box
Intenta patrones en orden: InvokePattern → TogglePattern → SelectionItemPattern → ExpandCollapsePattern.
click
Haga clic en un elemento en sus coordenadas de pantalla mediante la simulación del mouse. Úselo para los controles que no admiten InvokePattern (por ejemplo, encabezados de columna, elementos de lista).
winapp ui click btn-column1-a3f2 -a myapp # single click by slug
winapp ui click "Column1" -a myapp # single click by text search
winapp ui click btn-column1-a3f2 -a myapp --double # double-click
winapp ui click btn-column1-a3f2 -a myapp --right # right-click
Al igual que los otros verbos de inserción de entrada,
clicklleva el destino al primer plano y produce un error rápido (no_interactive_desktopen un escritorio bloqueado o seguro,foreground_not_targetsi el foco no se pudo transferir) en lugar de hacer clic en la ventana incorrecta. También vuelve a resolver el elemento justo antes del botón hacia abajo: después de colocar el cursor, realiza una comprobación de posición final, por lo que se produce un error en un destino de movimiento y animación continuos entarget_movedlugar de notificar el éxito después de que el clic se haya colocado en un espacio vacío, un éxito notificado significa que el destino todavía estaba en su lugar cuando el botón cayó.
Resistencia
Presione el botón del mouse en un punto, muévalo a otro y, a continuación, suelte con drag <from> <to>, donde cada punto de conexión es un selector de elementos (arrastra desde o hacia el centro del elemento) o coordenadas x,yde pantalla exactamente según lo indicado por .winapp ui inspect Mezclar y coincidir libremente (selector→selector, selector→coords, coords→coords).
Usa SendInput con movimientos intermedios para que la aplicación vea una secuencia realista de WM_MOUSEMOVE mensajes. Úselo para reordenar o cambiar el tamaño de los controladores, los controles deslizantes, el dibujo del lienzo y arrastrar y colocar.
winapp ui drag itm-card-9f8e itm-slot-2c1a -a myapp # reorder: card center → slot center
winapp ui drag itm-card-9f8e 300,400 -a myapp # element center → screen coords (from inspect)
winapp ui drag 120,200 480,200 -a myapp # raw screen coords → screen coords
winapp ui drag itm-card-9f8e itm-trash-0001 -a myapp --right # right-button drag
# Press-and-hold / long-press and drop-target dwell
winapp ui drag tile-photo-7b3c tile-photo-7b3c -a myapp --hold-ms 600 # long-press: from == to, hold 600ms, no move
winapp ui drag itm-card-9f8e pane-left-2c1a -a myapp --dwell-ms 350 # settle on the drop target before releasing
Opciones:
-
--right— Arrastre con el botón derecho del mouse en lugar del botón izquierdo. -
--hold-ms <ms>— Mantenga presionado el botón al principio antes de moverse (valor predeterminado: 0). Con<from> == <to>(sin movimiento), esto realiza un gesto de presión y suspensión / presión larga . -
--dwell-ms <ms>— Mora en el destino después de mover, antes de liberar (valor predeterminado: 0). Permite quitar los destinos o combinar superposiciones que el brazo de un puntero sostenido (en lugar del instante que llega el cursor) se cierre temporal antes del botón hacia arriba.
Bare
x,yson coordenadas de pantalla en el mismo informe de espaciowinapp ui inspect/searchy un selector se resuelve en el centro del elemento: inspeccione primero para seleccionar puntos.
Al igual que
send-keys --via send-input,draginserta el sistema operativo en coordenadas de pantalla después de llevar el destino al primer plano. Si el foco no se puede traer al destino (por ejemplo, la prevención de robo de foco de un proceso en segundo plano), se produce un error en el comando (foreground_not_target) en lugar de arrastrar en la ventana incorrecta: el foco o haga clic en la ventana en primer lugar. En un escritorio bloqueado o seguro, se produce un error conno_interactive_desktop. Cada punto de conexión de elemento se vuelve a resolver inmediatamente antes de la arrastrar; si sigue moviendo o cambiando el tamaño (un destino de animación), se produce un error en el comando contarget_moveden lugar de arrastrar a un punto obsoleto. (Los puntos de conexión sinx,ysistema operativo no se pueden volver a comprobar, por lo que se usan as-is).
Toque
Inserte gestos táctiles sintéticos mediante la API de inyección de puntero Windows. El delimitador de contactos es un selector de elementos (usa el centro del elemento) o una coordenada x,yde pantalla explícita a través --at de (informes de mismo espaciowinapp ui inspect). Úselo para las interacciones de pulsar o presionar y gestos multitáctil que la simulación del mouse no puede expresar.
winapp ui touch btn-ok-1a2b -a myapp # tap at the element center
winapp ui touch -a myapp --at 320,240 # tap at explicit screen coords
winapp ui touch tile-photo-7b3c -a myapp --gesture long-press --hold-ms 600
winapp ui touch -a myapp --at 100,300 --gesture swipe --to-point 400,300
winapp ui touch img-map-9f8e -a myapp --gesture pinch --distance 200 # pinch-to-zoom out (2 fingers)
winapp ui touch img-map-9f8e -a myapp --gesture stretch --distance 200 # stretch-to-zoom in (2 fingers)
Opciones:
-
--gesture <g>—tap(valor predeterminado),double-tap,long-press,swipe,pinch, .stretch -
--at <x,y>— Punto de inicio explícito (coordenadas de pantalla). El valor predeterminado es el centro de elementos del selector. -
--to-point <x,y>— Punto de conexión de unswipeobjeto . Tiene prioridad sobre--direction. -
--direction <right|left|up|down>— Dirección del deslizar el dedo (valor predeterminado:right). Combinado con--distancepara calcular el punto de conexión cuando--to-pointno se da. -
--distance <px>: se extiende el dedo parapinch/stretch, o la distancia de deslizar el dedo en píxeles. -
--hold-ms <ms>— Mantenga presionados los contactos antes de levantar (tiempo de espera de presión larga; el valor predeterminado es de 500 ms paralong-presscuando no se establece). -
--duration-ms <ms>— Tiempo de deslizamiento para mover gestos (deslizar/reducir/estirar; valor predeterminado 300). -
--fingers <n>— Número de contactos (1–10; valor predeterminado 1).pinch/stretchuse siempre 2.
Seguridad de inyección.
touchse niega a insertar a menos que se resuelva un identificador de ventana de destino distinto de cero y esa ventana contenga el primer plano; se produce un error cuandono_targetno se puede resolver ninguna ventana,foreground_not_targetsi no se pudo transferir el foco ono_interactive_desktopen un escritorio bloqueado o seguro. Cada coordenada (centro de elementos, puntos de referencia explícitos--at/--to-pointy generados) se comprueba en el rectángulo de la ventana de destino; un punto fuera de la ventana se muestra como una advertencia no grave (unawarnings[]entrada en--jsono una línea de advertencia en modo de texto) y la inyección continúa, que coincide con los verbos del mouse (drag/scrollclick/hover/), que también se insertan en coordenadas fuera de la ventana.--fingerspor encima de 10 se rechaza por adelantado.Nota de hardware. Touch prefiere el dispositivo de puntero sintético moderno (
CreateSyntheticPointerDevice(PT_TOUCH)) y retroceda a la API heredadaInitializeTouchInjection/InjectTouchInput. Si la inserción no se admite en el dispositivo o sesión actual, el comando muestra el código de error de Win32 real (por ejemplo, "no compatible") en lugar de notificar un falso éxito, tratar una salida distinta de cero como "touch not delivered".Escritorio remoto/sesiones de máquina virtual. En un Escritorio remoto (RDP) o algunas sesiones de máquina virtual, el sistema operativo puede aceptar la entrada táctil sintética (salida 0) sin que llegue realmente a la aplicación de destino. Cuando se detecta una sesión remota,
touchanexa una advertencia de incertidumbre de entrega , unawarnings[]entrada en--jsono una línea de advertencia en modo de texto. Una ✅/exit 0 significa que la llamada de inserción se realizó correctamente, no que la aplicación recibió la entrada; confirme el efecto conui screenshot/ui inspectcuando sea importante.
bolígrafo
Inserte la entrada de lápiz sintético/lápiz ( pulsaciones y trazos de lápiz) mediante la API de puntero sintético () de Windows (CreateSyntheticPointerDevice(PT_PEN); Windows 10 1809+). Dirija un centro de elementos, un punto explícito --at o un trazo de lápiz completo --path .
winapp ui pen canvas-1a2b -a myapp # pen tap at the element center
winapp ui pen -a myapp --at 320,240 --pressure 0.8 # firm pen tap at explicit coords
winapp ui pen -a myapp --path "100,100 150,120 210,140 260,120" # draw an ink stroke
winapp ui pen -a myapp --path "100,100 260,100" --eraser # erase along a stroke
winapp ui pen -a myapp --at 200,200 --tilt-x 30 --tilt-y -15 # tilted pen contact
Opciones:
-
--at <x,y>— Punto de contacto de lápiz (coordenadas de pantalla). El valor predeterminado es el centro de elementos del selector. Se omite cuando--pathse da. -
--path "<x,y x,y …>"— Ruta de trazos de lápiz como pares separados porx,yespacios en blanco (una ruta de acceso de un punto es una pulsación). -
--pressure <0.0–1.0>— Presión del lápiz (valor predeterminado 0,5). -
--tilt-x <deg>/--tilt-y <deg>— Ángulos de inclinación del lápiz, -90 a 90 (valor predeterminado 0). -
--eraser— Use el extremo del borrador del lápiz en lugar de la punta. -
--duration-ms <ms>— Tiempo total de desplazamiento de trazo en milisegundos distribuidos como marcos UPDATE interpolados en la ruta de acceso (valor predeterminado: ~10 ms por punto de acceso). Úselo para controlar la rapidez con la que el lápiz se mueve de principio a fin.
Seguridad de inyección. Al igual
touchque ,pense niega a insertar sin una ventana de destino en primer plano no cero (no_target/no_interactive_desktopforeground_not_target/ ) y comprueba cada punto de entrada de lápiz en el rectángulo de la ventana de destino, que muestra cualquier coordenada fuera de la ventana como una advertencia no irrecuperable (warnings[]en--json, o una línea de advertencia en modo de texto) mientras sigue insertando, coherente con los verbos del mouse. No válido--pressure(fuera de 0,0–1,0) o inclinación (fuera de ±90°) se rechazan por adelantado.Escritorio remoto/sesiones de máquina virtual. El enrutamiento del lápiz es especialmente poco confiable sobre Escritorio remoto: la llamada de inyección puede notificar el éxito (salida 0) mientras que ninguna entrada del lápiz llega a la aplicación. Cuando se detecta una sesión remota,
penanexa una advertencia de incertidumbre de entrega (warnings[]en--jsono una línea de advertencia en modo de texto), por lo que ✅ no se equivoca para la entrega confirmada. Valide los flujos dependientes del lápiz en un escritorio local e interactivo.
mantener el puntero
Mueva el mouse al centro de un elemento para desencadenar efectos de desplazamiento (información sobre herramientas, controles flotantes, estados visuales). Utiliza SendInput para el movimiento realista del mouse con un pequeño botón de alternancia y, a continuación, espera un tiempo de permanencia configurable.
winapp ui hover btn-info-a1b2 -a myapp # hover with default 800ms dwell
winapp ui hover btn-info-a1b2 -a myapp --dwell-time 1200 # longer dwell for slow tooltips
winapp ui hover btn-info-a1b2 -a myapp; winapp ui screenshot -a myapp --capture-screen # hover then capture tooltip
Opciones:
-
--dwell-time <ms>— Tiempo en milisegundos para esperar después de mantener el puntero para que aparezcan efectos (valor predeterminado: 800, intervalo: 0–10000)
send-keys
Enviar entrada de teclado sintético: el homólogo del teclado a click. UIA no tiene ningún patrón de inyección de teclado, por lo que esto cae a la capa win32. Úselo para la navegación por teclado (flechas, Tabulación, Entrar, Esc), métodos abreviados (ctrl+c, alt+f4) y escribir en controles que necesitan eventos de pulsación de tecla en lugar set-valuede escritura atómica.
winapp ui send-keys "down down enter" -a myapp # arrow navigation then commit
winapp ui send-keys "ctrl+a delete" -a myapp # select all, then delete
winapp ui send-keys "Hello world" --target txt-name-a1b2 -a myapp # focus a field, then type text
winapp ui send-keys "text=down text=down text=enter" -a myapp # type the words, don't press the keys
winapp ui send-keys "down down enter" -a myapp --verbatim # same, but type the whole argument literally
winapp ui send-keys "alt+f4" -a myapp # close window via accelerator
winapp ui send-keys "vk=0x5D" -a myapp # a key with no friendly name (Apps/Menu key)
winapp ui send-keys "ctrl+shift+t" -a myapp --via send-input # use OS-wide injection instead of PostMessage
winapp ui send-keys "win+shift+v" -a myapp --via send-input --allow-system-keys # opt in to drive a global hotkey
Gramática clave (tokens separados por espacios en blanco, comillas de cadenas de varios tokens):
-
Claves con nombre:
enter/return,tab, ,/spaceescapeesc,deleteinsertdelhomebackspaceleft//pagedown//pguppgdnpageup/updownright/end, ,f16appsf1, , , .capslockprintscreen -
Secuencias : se presionan varios tokens en orden:
down down enter. -
Combos modificadores :
ctrl,shift,alt,winunidos a+:ctrl+shift+t,alt+f4. -
Texto literal : cualquier token que no sea una clave conocida tiene un carácter de tipo por carácter:
hello. Las palabras literales adyacentes mantienen el espacio entre ellos, por lo que una frase entre comillas como"Hello world"se escribe textualmente (se conserva el espacio); un literal que simplemente contiene+comoC++oa+bse escribe como texto, no analizado como un combo. -
Escape literal explícito : prefijo un token con
text=para escribirlo textualmente incluso cuando entra en conflicto con un nombre clave o modificador:text=enterescribe la palabra "entrar" en lugar de presionar Entrar ytext=ctrl+aescribe la cadena literal. Refleja elvk=escape; el valor de escape todavía se combina con palabras literales adyacentes (text=down low→ "baja"). Dado que los tokens se dividen en espacios en blanco (y los literales adyacentes se vuelven a combinar con un solo espacio), use escapes de barra diagonal inversa dentro de untext=valor para escribir espacios en blanco que no sobrevivirían de otra manera:\s→ espacio,\t→ pestaña,\n→ nueva línea,\r→ nueva línea,\\→ barra diagonal inversa literal.\n,\ry\r\ncada una insertan un único salto de línea (un valor Enter /VK_RETURN), por lo quetext=line1\nline2text=line1\r\nline2y ambos escriben una nueva línea. Por lo tantotext=a\s\sb, escribe "a b" (doble espacio) ytext=\shimantiene un espacio inicial. Un escape no reconocido (por ejemplo,\x) se deja textualmente. -
Literal de argumento completo (
--verbatim): cuando toda la carga es texto literal, pase--verbatimen lugar de escapar cada token context=. Escribe el argumento de claves completa exactamente como se indica ( sin clave con nombre/combinación/vk=/text=interpretación) y, a diferencia de la ruta de acceso normal, conserva el espacio en blanco interno exacto (sin contraer) sin necesidad de .\sPor lo tantosend-keys "down down enter" --verbatim, escribe las palabras ysend-keys "a b" --verbatimmantiene el doble espacio. Los escapes de barra diagonal inversa no se descodifican en--verbatimmodo (se\sescribe como barra diagonal inversa y "s"); use untext=token cuando necesite un carácter de control con escape. -
Claves virtuales sin formato:
vk=0xNN(hexadecimal) ovk=NN(decimal) para las claves sin un nombre descriptivo.
Opciones:
-
--target <selector>: centre este elemento (a través de UIA) antes de enviar claves. Sin ella, las claves van al elemento centrado actualmente de la aplicación. -
--verbatim: escriba el argumento de claves completa como texto literal (sin key/combo/vk=/text=parsing) y conserve el espacio en blanco exacto. Forma de argumento completo del escape por tokentext=. -
--via <transport>—post-message(valor predeterminado) envía entradasWM_CHARWM_KEYDOWN/WM_KEYUP/a la cola de la ventana de destino. Es HWND-targeted y omite UIPI (funciona en niveles de integridad).send-inputinserta todo el sistema operativo a travésSendInputde y va a la ventana de primer plano.
Elección de un transporte o límites conocidos:
-
post-messagees el valor predeterminado porque omite UIPI y no depende de que la ventana esté en primer plano. Límites: no puede desencadenar teclas de acceso rápido globales registradas a travésWH_KEYBOARD_LLde enlaces de bajo nivel (los que pulsan la entrada ascendente de cualquier cola de ventanas) y las aplicaciones que leen el estado de la clave sin procesar a travésGetAsyncKeyStatede pueden no observar modificadores mantenidos. Resuelve y publica automáticamente la ventana secundaria centrada del subproceso de destino (a travésGetGUIThreadInfode ) después del primer plano, por lo que las aplicaciones clásicas win32/WinForms cuyos controles son ventanas secundarias independientes reciben claves sin tener como destino manualmente el control. Las aplicaciones winUI 3/UWP tienen controles XAML sin ventana sin HWND, por lo que un publicadoWM_CHAR/WM_KEYDOWNno tiene nada en el que aterrizar y se quita: el mensaje posterior no puede conducirlos (el comando advierte y sale 0); usa--via send-input. (WPF ventanas son de un solo HWND y las claves de ruta al elemento centrado internamente, por lo que el mensaje posterior funciona allí). -
send-inputgenera una entrada totalmente real (modificadores visibles paraGetAsyncKeyState, desencadena enlaces de bajo nivel), pero va a cualquier ventana en primer plano y está bloqueado por UIPI al insertar desde un proceso con privilegios elevados en un destino de integridad inferior (AppContainer/AppX). Sisend-inputnotifica un error, es probable que el destino sea elevado o una aplicación AppX, usepost-messageo ejecute la CLI en un nivel de integridad coincidente. Como protección de seguridad,send-inputcomprueba que la ventana de destino se encuentra en primer plano inmediatamente antes de insertar y generar un error (foreground_not_target) en lugar de escribir en la ventana incorrecta si no se pudo traer el foco a ella, centrar o hacer clic en la ventana en primer lugar. En un escritorio bloqueado o seguro se produce un error en su lugar conno_interactive_desktop(no existe ninguna ventana de primer plano para insertar en): desbloquee la sesión o use un verbo de patrón UIA (set-value,invoke). -
Los combos reservados por el sistema (
win+l,win+r, ,ctrl+escalt+tabctrl+alt+delctrl+shift+escalt+f4lonewin/printscreen, ...) actúan en el sistema operativo o shell en lugar de solo el destino cuando se envía el sistema operativo en todo el mundo.send-inputlos rechaza de forma predeterminada (errores coninvalid_argumentsy no envía nada) porque insertarlos en el nivel del sistema operativo tiene efectos mucho más allá de la ventana de destino (por ejemplo,win+lbloquearía la sesión). Pasar--allow-system-keyspara participar: esto le permite conducir una tecla de acceso rápido global, como PowerToys'win+shift+vowin+r(el enlace global de bajo nivel supervisa el flujo de entrada de todo el sistema operativo, por lo que el combo insertado lo activa). Excepciones que permanecen bloqueadas incluso con--allow-system-keys:win+lbloquea la estación de trabajo a travésLockWorkStation()de la cual no se puede recuperar de la automatización (interrumpe las sesiones de CI y escritorio remoto), yctrl+alt+deles una secuencia de atención segura (SAS) que Windows quita de la entrada insertada independientemente de la marca , nunca puede surtir efecto, por lo que los errores (invalid_arguments, salida 1) en lugar de notificar un éxito engañoso. Otros combos (alt+f4,ctrl+shift+esc,win+r, ...) se permiten con la marca — el llamador tenga cuidado. Como alternativa, para entregar un combo del sistema a una ventana específica,--via post-messageque tiene ámbito de ventana y no se ve afectado (un publicado es inofensivo, aunque un publicadowin+lalt+f4todavía cierra la ventana de destino).
Eventos por pulsación de tecla (KeyDown /TextChanged):
-
Las teclas con nombre y los combos modificadores (
down,enter,ctrl+shift+t)vk=0xNNactivan un valor realKeyDown(yKeyUp) en ambos transportes, se entregan como eventos discretosWM_KEYDOWN/WM_KEYUP(oSendInputde clave virtual). -
El texto con tipo literal (
hello) difiere según el transporte:-
--via send-inputasigna cada carácter a su tecla virtual (más Mayús) en el diseño de teclado activo, por lo que el destino ve un originalKeyDowncon la tecla virtual correcta seguida de la OS compuestaWM_CHAR(elevandoTextChanged) , es decir, una pulsación de tecla completa por carácter. Los caracteres no accesibles en el diseño actual (o que necesiten Ctrl/AltGr) vuelvan a un paquete Unicode para que el carácter exacto siga aterrizando. Usasend-inputcuando necesites fidelidad de pulsación de teclaKeyDown(por ejemplo, conducir winUI 3 /WPFTextBoxcuyos controladores desactivenKeyDown). En el caso de un host de prueba de WinUI 3 normal (sin privilegios elevados), traiga su ventana al primer plano (winapp ui focus/al hacer clic en él), ya quesend-inputtiene como destino la ventana de primer plano. -
--via post-messagepublica un soloWM_CHARpor carácter ( no publicaWM_KEYDOWN/WM_KEYUPpara el texto escrito; están reservados para teclas o combinaciones con nombre), que no genera un carácter por carácterKeyDown. Se vuelve a colocar automáticamente en el control secundario centrado de la ventana, por lo que los controles de edición controlados por Win32/WinFormsWM_CHARclásicos llegan al texto (elevandoTextChanged). Advertencia: WinUI 3 / UWP / aplicaciones XAML (destino principal de winapp) tienen controles sin ventana que ignoran publicadosWM_CHAR/WM_KEYDOWN, por lo que ni el texto literal ni las claves con nombre (Entrar, dígitos, ...) llegan a ellos, aunque el comando notifica que se ha realizado correctamente. Emite una advertencia cuando el destino es similar a XAML y sigue saliendo de 0 (PostMessagese desencadena y olvida y no puede confirmar la entrega). Usa--via send-inputpara controlar aplicaciones WinUI 3/ UWP o WPF; reservapost-messagepara controles Win32 clásicos o cuando solo lo necesites en los niveles de integridad.
-
Salida JSON (--json): el resultado hwnd es la ventana efectiva a la que se entregaron las claves; para --via post-message esto se trata del control secundario centrado resuelto cuando el comando se vuelve a colocar en él (no necesariamente la ventana de nivel -w//-a-e superior), por lo que la automatización puede confirmar exactamente dónde se encuentra la entrada. Cuando ese destino efectivo es similar a un host XAML sin ventanas, la advertencia de entrega anterior también se muestra como una warnings[] entrada (el mismo aviso que se muestra en la consola), por lo que una ✅ salida 0 no se equivoca para la entrega confirmada.
set-value
Establezca un valor en un elemento editable mediante programación (sin pulsaciones de tecla, sin primer plano de la aplicación). Usa una cadena de reserva:
- ValuePattern : controles TextBox, ComboBox, PasswordBox y la mayoría de los controles editables.
- RangeValuePattern : controles numéricos (Slider, ProgressBar) cuando el valor analiza como un número.
-
LegacyIAccessible (
IAccessible::put_accValue): la reserva para los controles de edición de solo TextPattern que no exponen valuePattern (por ejemplo, cuadros rich-edit/Documentcompose). Esto cierra la brecha de lectura y escritura en la queget-valuepodría leer este control, peroset-valueno pudo hacerlo.
winapp ui set-value txt-textbox-a4b1 "Hello world" -a notepad
winapp ui set-value sld-volume-b2c3 75 -a myapp
winapp ui set-value doc-compose-9f3a "hello" -a myapp # RichEdit/compose box via LegacyIAccessible
Si ninguno de los tres patrones puede establecer el valor, set-value se produce un error claro que apunta a send-keys como último recurso.
No todos los editores enriquecidos admiten conjuntos de programación. La reserva LegacyIAccessible solo funciona en controles cuya accesibilidad implementa: los controles nativos
IAccessible::put_accValuede edición enriquecida win32 y las superficies de redacción Chromium/Electron/WebView2 normalmente lo hacen. WinUI 3RichEditBoxy WPFRichTextBoxno admiten la configuración de valores mediante programación; por diseño, exponen su contenido a Automatización de la interfaz de usuario como de solo lectura (patrón de texto, sin patrón de valor configurable), por lo queset-valueno pueden escribir en ellos. Usesend-keys(que necesita un escritorio en primer plano desbloqueado) para esos.
get-value
Lea el valor actual de un elemento. Usa una cadena de reserva inteligente: TextPattern (RichEditBox, Document) → ValuePattern (TextBox, Slider) → SelectionPattern (ComboBox, RadioButton, TabView) → Name (etiquetas).
winapp ui get-value doc-texteditor-53ad -a notepad # read full document text
winapp ui get-value SearchBox -a myapp # read TextBox content
winapp ui get-value CmbTheme -a myapp # read ComboBox selected item
winapp ui get-value sld-volume-b2c3 -a myapp # read Slider value
winapp ui get-value lbl-title-a1b2 -a myapp --json # JSON: { "elementId": "...", "text": "..." }
enfoque
Mueva el foco del teclado a un elemento.
winapp ui focus txt-textbox-a4b1 -a notepad
scroll-into-view
Desplácese por un elemento hasta el área visible.
winapp ui scroll-into-view itm-targetitem-c3d4 -a myapp
wait-for
Espere a que un elemento aparezca, desaparezca o haga que un valor alcance un destino.
winapp ui wait-for Button -a myapp --timeout 5000 # wait for any button
winapp ui wait-for btn-submit-7a90 -a myapp --timeout 5000 # wait for specific element
winapp ui wait-for CounterDisplay -a myapp --value "5" --timeout 5000 # wait for element value (smart fallback)
winapp ui wait-for lbl-status -a myapp --property Name --value "Done" --timeout 5000 # wait for specific property
winapp ui wait-for btn-submit-a1b2 --gone -a myapp --timeout 2000 # wait for element to disappear
winapp ui wait-for lbl-status -a myapp --value "Done" --contains # substring match instead of exact equality
Pergamino
Desplácese por un elemento contenedor. Busque contenedores desplazables con search scroll : busque [scroll:v] marcadores (verticales) o [scroll:h] (horizontales).
# Find which elements are scrollable and in which direction
winapp ui search scroll -a myapp
# pn-scrollview-bfef Pane "scrollView" [scroll:v] (main content, vertical)
# pn-scrollviewer-bfb1 Pane "scrollViewer" [scroll:h] (horizontal list)
# Scroll the main content down
winapp ui scroll pn-scrollview-bfef --direction down -a myapp
# Jump to top/bottom
winapp ui scroll pn-scrollview-bfef --to bottom -a myapp
# If you target an element that's not scrollable, scroll walks up to find the nearest scrollable parent
winapp ui scroll itm-someitem-a1b2 --direction down -a myapp
# Synthesize real mouse-wheel input over the element (1 = one notch up, -1 = one notch down).
# Use this to test handlers that respond to the wheel directly (zoom, custom scroll) rather than ScrollPattern.
winapp ui scroll img-map-a1b2 --wheel -1 -a myapp
Opciones:
-
--direction <up|down|left|right>— Desplácese incrementalmente a través deScrollPattern. -
--to <top|bottom>— Vaya al principio o al final a través deScrollPattern. -
--wheel <notches>— Sintetiza la entrada de la rueda del mouse sobre el centro del elemento a travésSendInputde , en notillas de rueda (detents):1= una nota arriba/lejos,-1= una notch hacia abajo/hacia,3= tres pulgadas hacia arriba. (Cada notch es el WindowsWHEEL_DELTAde 120 unidades queSendInputconsume; la CLI escala los notches en 120 por usted). OmiteScrollPattern.
--direction,--toy--wheelson mutuamente excluyentes: pasan exactamente uno. Dado--wheelque inserta la entrada en todo el sistema operativo en las coordenadas de la pantalla, lleva primero el destino al primer plano y produce un error (foreground_not_target) si no se pudo transferir el foco, en lugar de desplazarse por la ventana incorrecta.
get-focused
Muestra el elemento que actualmente tiene el foco del teclado.
winapp ui get-focused -a myapp
list-windows
Enumere todas las ventanas visibles para una aplicación, incluidas las ventanas emergentes y los cuadros de diálogo. De forma predeterminada, se excluyen las ventanas sin título con tamaño cero (ventanas del sistema invisible).
winapp ui list-windows -a imageresizer
winapp ui list-windows -a Terminal
winapp ui list-windows # all windows (no filter)
winapp ui list-windows --show-hidden # include invisible zero-size windows
Compatibilidad con marcos
| Marco de referencia | Inspeccionar | search | invoke | set-value | captura de pantalla |
|---|---|---|---|---|---|
| WPF | ✅ Árbol completo | ✅ Todas las propiedades | ✅ Todos los patrones | ✅ ¹ | ✅ |
| WinForms | ✅ | ✅ | ✅ | ✅ | ✅ |
| Win32 | ✅ | ✅ | ✅ | ✅ | ✅ |
| WinUI 3 | ✅ | ✅ | ✅ | ✅ ¹ | ✅ |
| Electrón | ⚠️ Árbol de Chromium | ⚠️ Limitado | ⚠️ Varía | ⚠️ Varía | ✅ |
| Flutter | ⚠️ Básico | ⚠️ Básico | ❌ Mínimo | ❌ | ✅ |
¹ set-value funciona en cualquier control que exponga ValuePattern/RangeValuePattern, además de controles de edición de solo TextPattern cuya accesibilidad implementa IAccessible::put_accValue (reserva LegacyIAccessible).
WinUI 3 RichEditBox y WPF RichTextBox son excepciones: solo exponen el patrón text de solo lectura (no se puede establecer el patrón valor), por lo que no se pueden establecer mediante programación mediante diseño; use send-keys (se requiere escritorio interactivo) para escribir en ellos.
Solución de problemas
| Error | Causa | Solución |
|---|---|---|
| "No se encontró ninguna aplicación en ejecución" | Error de coincidencia de nombres o no en ejecución de la aplicación | Comprobación del nombre del proceso o uso de PID |
| "Coincidencia de varias ventanas" | Valor ambiguo -a |
Uso -w <HWND> de las opciones enumeradas |
| "tiene varias ventanas" | El proceso tiene varias ventanas | Uso -w <HWND> para establecer como destino uno específico |
| "Selector coincidente con N elementos" | Selector heredado ambiguo | Usar slugs de inspect salida, o anexar [0], [1] a selectores heredados |
| "El elemento puede haber cambiado" | El hash slug no coincide con el elemento actual | Volver a ejecutar inspect o search para obtener slugs frescos |
| "no admite ningún patrón de invocación" | No se puede invocar el elemento | Usar inspect en el elemento para buscar un elemento secundario invocable |
| "No se encontró ninguna ventana UIA" | UIA no puede ver el proceso | Use list-windows para buscar el HWND y, a continuación, -w |
| "La ventana tiene un tamaño cero" | La ventana está minimizada | La aplicación se restaurará automáticamente. |
| Menú emergente o desplegable que no está en la captura de pantalla | La captura predeterminada es por ventana y no incluye superposiciones noowned | Usar --capture-screen marca |
element_not_found durante el registro |
Selector especificado, pero sin elemento coincidente | Volver a ejecutar inspect o search para obtener un selector nuevo |
| WGC no disponible durante el registro | Error de inicialización de captura de WGC; no hay reserva silenciosa | Comprobar GPU/controlador; usar --capture-screen para dar su consentimiento a la captura de dc de pantalla |
Patrones comunes
Navegación y comprobación
winapp ui invoke btn-settings-a1b2 -a myapp # click a button
winapp ui wait-for pn-settingspage-c3d4 -a myapp # wait for page to load
winapp ui screenshot -a myapp --output settings.png # verify visually
Buscar texto e invocar a su elemento primario
# Search shows invokable ancestor; invoke auto-walks to it
winapp ui invoke 'Save changes' -a myapp
# Or search first to see what matches, then invoke
winapp ui search "Save changes" -a myapp; winapp ui invoke btn-save-c3d4 -a myapp
Desambiguar elementos duplicados
winapp ui search '#Image' -a myapp; winapp ui invoke itm-image-a2b3 -a myapp
Captura de pantalla con superposiciones emergentes
winapp ui set-value txt-searchbox-e5f6 "query" -a myapp; winapp ui screenshot -a myapp --capture-screen
Navegar, esperar y comprobar (cadena única)
winapp ui invoke btn-settings-a1b2 -a myapp; winapp ui wait-for pn-settingspage-c3d4 -a myapp --timeout 3000; winapp ui screenshot -a myapp -o settings.png
Detectar, hacer clic y comprobar
winapp ui inspect -a myapp --interactive; winapp ui invoke btn-submit-7a90 -a myapp; winapp ui screenshot -a myapp
Interacción del cuadro de diálogo archivo
Los cuadros de diálogo de apertura y guardado de archivos son cuadros de diálogo estándar Windows con compatibilidad con UIA:
# Trigger the dialog, find it, type the path, confirm
winapp ui invoke btn-openfilebtn-a2b3 -a myapp
winapp ui list-windows -a myapp # find dialog HWND
winapp ui set-value txt-1148-c4d5 "C:\path\to\file.png" -w <dialog-hwnd>
winapp ui invoke btn-open-e6f7 -w <dialog-hwnd>
Use inspect -w <dialog-hwnd> --interactive para detectar los slugs reales de un cuadro de diálogo específico.
Por qué ; encadenar (no &&)
El operador de && PowerShell puede inmovilizarse cuando una CLI nativa escribe en stderr o usa secuencias de escape ANSI. Use ; en su lugar: ejecuta cada comando incondicionalmente y evita este interbloqueo. Esto también es mejor para los flujos de trabajo del agente: normalmente quiere que se ejecute la captura de pantalla incluso si la invocación tenía una salida distinta de cero.
Patrones de pruebas de CI
Use wait-for con --property y --value actúa como aserción: devuelve el código de salida 1 en el tiempo de espera y produce un error en el paso de CI automáticamente.
Inicio y prueba en Acciones de GitHub
steps:
- name: Build
run: dotnet build MyApp.csproj -c Debug -p:Platform=x64
- name: Launch and test
run: |
$result = winapp run .\bin\x64\Debug\net8.0-windows10.0.26100.0\win-x64 --detach --json | ConvertFrom-Json
$appPid = $result.ProcessId
# Wait for window to initialize
winapp ui wait-for "Main Window" -a $appPid --timeout 30000
# Run tests — each wait-for exits non-zero on failure
winapp ui invoke "Login" -a $appPid
winapp ui wait-for "Dashboard" -a $appPid --timeout 10000
winapp ui screenshot -a $appPid -o dashboard.png
Estado del elemento Assert con wait-for
wait-for --value sondea hasta que el valor de un elemento coincide con la cadena esperada, usando la misma reserva inteligente que get-value (TextPattern → ValuePattern → SelectionPattern → Name). Devuelve el código de salida 0 en coincidencia, el código de salida 1 en el tiempo de espera, lo que lo convierte en una aserción compatible con CI. Use --property para comprobar una propiedad UIA específica en su lugar.
# Assert: button click updated the counter (smart value fallback — works for TextBlock, TextBox, etc.)
winapp ui invoke "Counter Button" -a $pid
winapp ui wait-for "Counter Display" -a $pid --value "Count: 1" -t 5000
# Assert: text input was accepted
winapp ui set-value "Search Box" "hello world" -a $pid
winapp ui wait-for "Search Box" -a $pid --value "hello world" -t 3000
# Assert: checkbox was toggled (use --property for specific UIA properties)
winapp ui invoke "Dark Mode" -a $pid
winapp ui wait-for "Dark Mode" -a $pid --property ToggleState --value "On" -t 3000
# Assert: navigation happened (new page appeared)
winapp ui invoke "Settings" -a $pid
winapp ui wait-for "Settings Page" -a $pid -t 10000
# Assert: dialog was dismissed (element disappeared)
winapp ui invoke "Close" -a $pid
winapp ui wait-for "Dialog Title" -a $pid --gone -t 5000
Aserción con salida JSON
Use --json con PowerShell o jq para aserciones más complejas:
Contrato de código de salida para
searchywait-foren modo: cuando ningún elemento coincide () o el tiempo de espera agotado (), el comando escribe un sobre de resultado totalmente analizable en--jsonsearch(wait-foro ) y devuelve el{ "matchCount": 0, ... }.{ "found": false, "timedOut": true, ... }Stderr está vacío en--jsonmodo (se suprime la salida del registrador). Bifurcación en los campos de sobre, o en$LASTEXITCODE, dependiendo de cuál sea más ergonómica.
# Assert: search found exactly one match
$result = winapp ui search "Submit" -a $pid --json | ConvertFrom-Json
if ($result.matchCount -ne 1) { throw "Expected 1 Submit button, found $($result.matchCount)" }
# Assert: element has expected properties
# inspect --json returns { windows: [{ hwnd, title, elements: [...] }] };
# each window's elements[] is the nested tree (children rendered via .children).
$tree = winapp ui inspect "Counter Display" -a $pid --json | ConvertFrom-Json
$counter = $tree.windows[0].elements[0]
if ($counter.name -ne "Count: 3") { throw "Counter value wrong: $($counter.name)" }
Ejemplo de prueba de humo completo
# Launch
$app = winapp run .\build-output --detach --json | ConvertFrom-Json
# Verify app loaded
winapp ui wait-for "Main Page" -a $app.ProcessId -t 30000
# Interact and assert
winapp ui invoke "Add Item" -a $app.ProcessId
winapp ui set-value "Item Name" "Test Item" -a $app.ProcessId
winapp ui invoke "Save" -a $app.ProcessId
winapp ui wait-for "Test Item" -a $app.ProcessId -t 5000 # assert item appeared in list
winapp ui wait-for "Save" -a $app.ProcessId --gone -t 3000 # assert save dialog closed
# Visual verification
winapp ui screenshot -a $app.ProcessId -o smoke-test.png