Automazione dell'interfaccia utente

Esaminare e interagire con l'esecuzione di applicazioni Windows dalla riga di comando. Usato dagli agenti di intelligenza artificiale e dagli sviluppatori per i test, il debug e l'automazione dell'interfaccia utente.

Overview

winapp ui fornisce comandi per l'ispezione e l'interazione con le interfacce utente dell'app Windows. Usa Windows Automazione interfaccia utente (UIA). Funziona con qualsiasi app Windows: macchine virtuali Windows, WinForms, Win32, Electron e WinUI 3. La maggior parte dei comandi guida l'app tramite modelli di interfaccia utente (senza inserimento di input). Le eccezioni inserisce l'input reale: ui click/ui hover/ui dragusare la simulazione del mouse,ui touch/ui pen sintetizzare l'input tocco e penna/stilo e ui send-keys sintetizzare l'input della tastiera, per i controlli e gli scenari che i modelli di interfaccia utente non possono guidare.

Important

Requisito del desktop interattivo (verbi di inserimento di input).click , hover, , dragtouchpen, , scroll --wheel, e send-keys --via send-input sintetizzano l'input a livello di sistema operativo, quindi è necessario un desktop interattivo sbloccato e interattivo con la finestra di destinazione in primo piano. In una workstation bloccata o in un desktop protetto (LogonUI/UAC) non possono inserire e non riuscire rapidamente no_interactive_desktop (distinti dai casi di elevazione/foreground_not_target elevazione). touch / pen rifiutare inoltre quando non viene risolta alcuna finestra (no_target); una coordinata all'esterno della finestra di destinazione è un avviso non irreversibile (una warnings[] voce in --jsono una riga di avviso in modalità testo) e l'inserimento continua, coerente con i verbi del mouse. Tutto il resto, inspect, get-propertysearch, get-valuewait-forset-value, invoke, scroll --direction/--to determina l'app tramite modelli di interfaccia utente ed è compatibile con la sessione headless/bloccata. screenshot è l'eccezione tra i verbi non inseriti: richiede un turno esclusivo e la sua acquisizione può richiedere un desktop interattivo utilizzabile, perché il motore ripristina una destinazione ridotta a icona e torna in primo piano quando l'acquisizione dei fotogrammi non è disponibile o --capture-screen viene usata. Preferisce i verbi uiA-pattern in CI; riservare i verbi di inserimento per scenari che effettivamente necessitano di input reale. Prima di inserire, i verbi di movimento risolvono anche l'elemento di destinazione e rifiutano target_moved se è ancora in fase di animazione/rilocazione, anziché l'input di atterraggio su uno spazio vuoto.

Avvio rapido

Eseguire winapp ui --help per il ciclo principale: inspect -a <app> --interactive per vedere cosa è possibile agire o set-value agire invoke e get-value controllare il risultato. Ogni comando --help mostra esempi. Un comando sconosciuto, ad esempio winapp ui dump, viene chiuso con codice 1 e suggerisce i comandi più vicini (come errore JSON con suggestions quando si passa --json).

# 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

Esecuzione dell'automazione interfaccia utente in Windows Sandbox

Per mantenere l'automazione fuori dal desktop, aggiungere --on sandbox ai comandi di esecuzione e interfaccia utente:

winapp run . --on sandbox --detach
winapp ui inspect --on sandbox -a MyApp
winapp ui invoke --on sandbox SubmitButton -a MyApp

--detach restituisce dopo l'avvio; senza di esso, run attende che l'app venga chiusa. Continuare --on sandbox con ogni comando guest, inclusi quelli che usano un HANDLE DI FINESTRA o PID. Vedere Windows esecuzione sandbox per i requisiti client, brevi modifiche dello stato attivo di configurazione/riconnessione, coordinamento del flusso di lavoro e recapito dell'output dell'host.

Query con ambito e tipizzato

winapp ui search "Welcome to MyApp" -a myapp --root MailRow --type Text --class-name TextBlock
winapp ui get-value Subject -w 123456 --root MailRow --type TextBox
winapp ui get-property Subject -a myapp --root MailRow --type Edit --property Value
winapp ui wait-for Subject -a myapp --root MailRow --type Edit --value "Ready" --timeout 10000
winapp ui invoke Open -w <dialog-HWND> --type Button
winapp ui set-value "Text editor" "hello" -a notepad --type Document

Questi comandi accettano filtri facoltativi nel selettore di elementi: inspect (con un selettore), search, get-valuewait-forinvokeset-valuefocusscrollscreenshotscroll-into-viewhoverget-propertyclick, , , record, , touche .pen drag (due selettori) e send-keys --target non. Il selettore e ogni filtro fornito devono corrispondere allo stesso elemento. I filtri restringeno un selettore, quindi inspect, screenshote record, il cui selettore è facoltativo, non riesce con invalid_arguments quando vengono specificati filtri senza uno. Per touch e pen, i filtri necessitano di un selettore; non possono essere combinati con --at o --path (invalid_arguments):

  • --root <selector> cerca solo discendenti di una radice corrispondente in modo univoco, mai la radice stessa. Usare automationId o slug da inspect per evitare ambiguità. Una radice che corrisponde a più elementi ha esito negativo con ambiguous_selector, anche se una corrispondenza è richiamabile. Una radice mancante non produce corrispondenze. Una volta trovata la radice, le query non eseguono ricerche nelle finestre popup non correlate, anche quando non viene trovata alcuna corrispondenza discendente. Le query non sono limitate dalla inspectprofondità di visualizzazione.
  • --type <control-type> corrisponde a un tipo di controllo UIA, ignorando la distinzione tra maiuscole e minuscole. Gli unici alias sono TextBox → Edit e TextBlock → Text. I nomi sconosciuti (inclusi gli ID numerici e le espressioni con caratteri jolly) hanno esito negativo con invalid_arguments.
  • --class-name <literal> corrisponde all'intera interfaccia utente ClassNamedel provider, ignorando il caso. Non è una sottostringa, un carattere jolly o un'espressione regolare. Usare get-property --property ClassName per individuare il valore del provider. Il nome della classe non deve essere uguale al tipo di controllo UIA.

Le query filtrate usano la visualizzazione controllo dell'interfaccia utente, la stessa visualizzazione visualizzata da inspect. I nodi del provider esposti solo in visualizzazione non elaborata non vengono restituiti; utilizzare inspect per trovare il controllo contenitore e il relativo selettore.

Tutti i 41 tipi ufficiali sono supportati: Button, CalendarCheckBoxEditComboBox, . AppBarHyperlinkImageListItemListMenuMenuBarMenuItemProgressBarRadioButtonScrollBarSliderSpinnerStatusBarTabTabItemTextToolBarToolTipTreeTreeItemCustomGroupThumbDataGridDataItemDocumentSplitButtonWindowPaneHeaderHeaderItemTableTitleBarSeparatorSemanticZoom

wait-for risolve di nuovo il selettore radice in ogni polling, quindi la radice può essere visualizzata dopo l'avvio del comando. Con --gone, una radice assente indica che non esiste un discendente corrispondente; una radice ambigua è un errore, non l'esito positivo. Una ricerca interrotta non è una prova della scomparsa: se un elemento viene rimosso durante la ricerca o sostituito prima di una --value lettura, il successivo poll controlla di nuovo; altri errori di ricerca o lettura non riescono a eseguire il comando. -w <HWND> limita l'individuazione radice all'albero dell'interfaccia utente di tale finestra. Con -a, l'individuazione radice può anche trovare le finestre popup dell'app. Le corrispondenze di AutomationId radice esatte hanno la precedenza sulle corrispondenze di sottostringa in tutte queste finestre; più corrispondenze esatte continuano a non riuscire con ambiguous_selector.

Un slug radice seleziona l'elemento anche quando un'altra finestra ha lo stesso AutomationId. Se la radice selezionata viene sostituita, il suo vecchio slug non corrisponde più; usare un valore automationId o una radice del nome quando si vuole eseguire il polling in seguito a una sostituzione.

Quando sono presenti filtri, ogni comando tranne search ha esito negativo se ambiguous_selector rimane più di un elemento; restringere i filtri o usare un slug univoco. I comandi che agiscono sul numero di elementi corrispondono in ogni finestra in cui eseguano la ricerca, quindi un controllo corrispondente in una finestra di dialogo di proprietà rende ambiguo il selettore. Le corrispondenze esatte di AutomationId mantengono la precedenza rispetto alle corrispondenze di sottostringa, all'interno dell'ambito filtrato. L'omissione di tutte e tre le opzioni mantiene il comportamento esistente della query.

Coordinamento dei flussi di lavoro simultanei dell'interfaccia utente

Windows ha una sola finestra in primo piano, uno stato attivo della tastiera, un cursore e un flusso di input. Quando due winapp ui flussi di lavoro vengono eseguiti nello stesso desktop connesso contemporaneamente, possono rubare lo stato attivo l'uno dall'altro, chiudere un menu l'altro aperto o spostare una destinazione da sotto un clic in sospeso.

L'arbitraggio è sempre attivo. Ogni winapp ui comando che tocca il desktop fisico assume un turno, senza alcuna configurazione e senza alcun modo per disattivarlo, in modo che due agenti non possano mai digitare tra loro le finestre. I comandi di sola lettura mantengono l'esecuzione simultanea. L'unica eccezione è un processo che non è in grado di accedere alla cartella di coordinamento di winapp, ad esempio un sandbox agente che blocca %USERPROFILE%\.winapp: i relativi comandi vengono ancora eseguiti, ma senza turni e stampare un avviso (ad eccezione di --json o --quiet).

La continuità tra i comandi è esplicita. Per impostazione predefinita, ogni comando è un singolo colpo autonomo: attende il suo turno, esegue il suo lavoro e rilascia immediatamente il desktop. Per mantenere il desktop in più comandi, assegnargli tutti gli stessi ID del flusso di lavoro:

# Set once per logical UI workflow
$env:WINAPP_UI_WORKFLOW_ID = [guid]::NewGuid().ToString()

Informazioni utili:

  • Un ID flusso di lavoro assegna un nome a un flusso di lavoro logico , non necessariamente un intero agente e non necessariamente un'app. Usare lo stesso valore per i comandi di cooperazione (una registrazione più i clic che deve acquisire); usare valori diversi per i flussi di lavoro indipendenti, anche quando un agente viene avviato entrambi.
  • Senza ID, ogni comando è un singolo colpo indipendente. Continua ad arbitrarsi, ma non rivede alcuna grazia e consegna il desktop fuori dal momento in cui termina. Due comandi no-id sono flussi di lavoro separati anche quando vengono avviati dalla stessa shell.
  • Gli host fresh-shell e adattivi devono inserire lo stesso valore. Se ogni comando viene eseguito in una nuova shell, ovvero il modo in cui la maggior parte degli strumenti agente chiama il lavoro, l'unica cosa che può raggrupparli è un passaggio esplicito WINAPP_UI_WORKFLOW_ID a ogni chiamata collaborativa.
  • La tolleranza di quattro secondi protegge i picchi stretti, non il ragionamento del modello. Un flusso di lavoro con un ID mantiene il suo turno fino a quando il comando successivo viene avviato entro quattro secondi. Che copre i comandi back-to-back in un unico script; scade intenzionalmente mentre un modello sta pensando. È un fallback per quando non puoi dire che sei finito, quando puoi, esegui winapp ui yield invece di aspettarlo.
  • I flussi di lavoro adattivi devono riacquisire, riconvalidare e riprodurre. Dopo un intervallo di ragionamento un altro flusso di lavoro potrebbe aver usato il desktop, quindi riaprire il menu, risolvere nuovamente l'elemento e quindi agire. Inviare sequenze end-to-end note come uno script stretto anziché tenere il desktop mentre si pensa.
  • L'ordinamento è innanzitutto l'affinità di proprietario, quindi FIFO tra le altre. Mentre un flusso di lavoro è attivo o all'interno della sua tolleranza, può continuare a eseguire comandi, anche se altri flussi di lavoro sono già in attesa. Una volta eseguita winapp ui yield o scaduta la sua tolleranza, i flussi di lavoro in attesa vengono serviti in ordine di arrivo rigoroso. L'attività continua di un flusso di lavoro può quindi ritardare altri indefiniti.
  • Non c'è un cappuccio rigido. Uno script lungo, una registrazione non associato o un ciclo di errore può bloccare altri flussi di lavoro mutevoli.
  • L'annullamento o la terminazione del processo è il ripristino per un flusso di lavoro attivo bloccato. I comandi in attesa stampano uno stato dopo un secondo e possono essere arrestati con Ctrl+C, che esce da 130.
  • Collaborano solo i file binari aggiornati compatibili. Le build precedenti winapp precedono questa funzionalità e non sono coordinate. Il codice che chiama direttamente i pacchetti NuGet Automazione interfaccia utente non è completamente al di fuori di questa garanzia. Il coordinamento risiede nell'interfaccia della riga di comando, non nei pacchetti.

Quali comandi attendono un turno:

Behavior Comandi
Esecuzioni simultanee (mai attese) status, list-windows, inspect, search, get-property, get-value, get-focused, wait-for
Attende il turno, ma non prende mai il desktop set-value, scroll-into-view, scroll --direction/--torecord
Attende il turno e prende il desktop esclusivamente invoke, click, drag, hover, scroll --wheel, touch, pen, focus, send-keys, screenshot

La riga centrale è quella che vale la pena capire. set-value scroll-into-view e--toscroll --direction/guidano i modelli uiA invece che in primo piano, in modo che rimangano amichevoli headless/bloccato-sessione e non impediscano mai a nessuno di usare il desktop. Ma cambiano ciò che viene visualizzato dall'app, in modo che attendano dietro il turno di un altro flusso di lavoro invece di modificare un campo o scorrere un elenco da sotto un clic di qualcun altro.

All'interno di un flusso di lavoro si sovrappongono ad altri lavori condivisi , ovvero il modo in cui un acquisisce record le set-value chiamate che sta registrando. Non ignorano la barriera forward del proprio flusso di lavoro: un comando precedente DesktopExclusive dello stesso flusso di lavoro (un click, a screenshot) li blocca, esattamente come blocca ogni comando successivo, quindi un clic e la mutazione che segue rimangono nell'ordine in cui sono state scritte.

screenshot sempre code per un turno esclusivo. Non ogni acquisizione disturba il desktop, una normale finestra visibile acquisita tramite Windows Acquisizione grafica non, ma il motore ripristina la destinazione se è ridotta a icona e torna in primo piano quando l'acquisizione dei fotogrammi non è disponibile o --capture-screen legge la schermata live. Queste esigenze devono essere rilevate solo una volta che l'acquisizione è in corso, quindi il comando assume il turno in alto invece di indovinare. Quando composita diverse finestre, le acquisisce tutte sotto un unico turno esclusivo, quindi l'immagine salvata è un singolo momento coerente anziché un mix di prima e dopo. La codifica e la scrittura del file vengono eseguite dopo il rilascio del desktop.

--capture-screen ha esattamente una finestra. L'acquisizione dello schermo live registra qualsiasi cosa sia effettivamente davanti e può essere una sola finestra. Se si seleziona una finestra in modo esplicito, -w <hwnd> si ottiene esattamente un'area, ovvero i pixel all'interno dei limiti di tale finestra, inclusi qualsiasi dialogo o sovrapposizione visibile sopra di esso, che è il motivo per leggere lo schermo al primo posto. Quando -a corrisponde a diverse finestre di primo livello o di proprietà non esiste una selezione di questo tipo, quindi il comando ha esito negativo prima invalid_arguments di acquisire qualsiasi elemento anziché combattere in primo piano. Eseguire winapp ui list-windows -a <app> e riprovare con -w <hwnd>o rilasciare --capture-screen per comporre ogni finestra dal relativo contenuto.

record condivide il suo turno, in modo che l'input dello stesso flusso di lavoro possa interleaversi con l'acquisizione, ovvero come si registra un flusso di lavoro che guida un'app. Due avvertenze:

  • Un record oggetto senza ID flusso di lavoro è un proprietario mono-shot, quindi blocca tutti gli altri flussi di lavoro per tutta la durata. Per registrare e fare clic contemporaneamente, assegnare entrambi i comandi allo stesso WINAPP_UI_WORKFLOW_ID.
  • In un host senza supporto per l'acquisizione di fotogrammi, la registrazione esegue il fallback a PrintWindow, il cui ripristino con fotogrammi vuoti può essere in primo piano in qualsiasi momento. C'è il desktop è tenuto per l'intera registrazione e il comando dice così nel suo output; anche l'input dello stesso flusso di lavoro attenderà.

È possibile che vengano visualizzati errori: invalid_ui_workflow_id (la variabile è impostata ma vuota o superiore a 256 caratteri), desktop_coordination_unavailable (lo stato di coordinamento è illeggibile e non può essere ricompilato in modo sicuro o è stato scritto da un più recente winapp), queue_capacity_exceeded (64 comandi di altri flussi di lavoro sono già in attesa— il numero di conteggi dei conteggi in tempo reale dei camerieri stranieri, non i processi avviati, quindi le voci appartenenti a comandi che sono stati chiusi o uccisi non occupano uno slot, e la coda dei comandi del flusso di lavoro rispetto a questo limite, ui_turn_busy (yield mentre il proprio flusso di lavoro dispone ancora di un comando in esecuzione) e cancelled (CTRL+C durante l'attesa, il codice 130di uscita).

Rilascio anticipato del turno: winapp ui yield

La tolleranza di quattro secondi è un fallback: mantiene il desktop riservato quando non puoi dire per certo che sei finito. Quando si può dire così, dire così - yield mani il desktop subito invece di fare a tutti gli altri aspettare una grazia nessuno ha bisogno.

$env:WINAPP_UI_WORKFLOW_ID = [guid]::NewGuid().ToString()

winapp ui invoke File -a notepad
winapp ui click "Save As..." -a notepad
winapp ui set-value txt-filename-a1b2 "notes.txt" -a notepad
winapp ui yield                      # done — a waiting workflow starts now, not in four seconds
  • I comandi one-shot non devono impostare affatto un ID del flusso di lavoro. Senza uno, ogni comando rilascia già il desktop al termine, e non c'è nulla da produrre.
  • I flussi di lavoro in più passaggi devono produrre al termine, soprattutto quando altri flussi di lavoro potrebbero essere in attesa. Costa un comando veloce e rimuove uno stallo di quattro secondi da tutti gli altri.
  • È idempotente. Resa due volte, o dopo che la grazia è già scaduta, ha esito positivo e segnala { "released": false } , ovvero la fine normale di uno script, non un errore.
  • Non rilascia mai il turno di un altro flusso di lavoro. Se qualcun altro tiene il desktop, o nessuno lo fa, è un no-op.
  • L'operazione ha esito negativo ui_turn_busy se il proprio flusso di lavoro ha ancora un comando in esecuzione o in coda, ad esempio una registrazione. Rilasciando sotto che avrebbe mano il desktop via mid-command, quindi non viene rilasciato nulla e il comando in esecuzione non è interessato. Attendere o arrestarlo, quindi restituirlo di nuovo.
  • WINAPP_UI_WORKFLOW_IDRichiede . Senza un errore, l'operazione non riesce con invalid_arguments.
  • Non accetta app e nessun selettore: restituisce una prenotazione, non una finestra, quindi funziona ancora dopo la chiusura dell'app.

Un comando in attesa viene svegliato da chiunque rilasci il desktop anziché eseguendo il polling per esso, quindi una coda costa quasi nulla mentre attende e consegna è immediato. Ogni cameriere ricontrolla anche da solo occasionalmente, che è ciò che recupera il desktop quando un processo viene terminato e non pubblica mai nulla: il comando all'inizio della coda cerca ogni mezzo secondo e i comandi dietro di esso , che non possono essere eseguiti prima che la testa funzioni comunque , ogni pochi secondi.

Selezione di app di destinazione

In base al nome del processo

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
winapp ui search Seven -a calculator  # hosted app: uses the frame window that hosts it

Alcune app in pacchetto (ad esempio Calcolatrice) non hanno una finestra personalizzata; un altro processo ospita il frame. Quando il processo corrispondente (per nome o PID) non ha una finestra visibile, -a usa invece il frame che ospita il contenuto. Se non è presente nessuna (ad esempio, l'app è ancora in fase di avvio), -a il processo viene destinazioni, quindi wait-for continua a cercare finché non viene visualizzata la finestra.

In base al titolo della finestra

winapp ui inspect -a "LICENSE - Notepad"
winapp ui inspect -a "Fix WinApp"     # partial title match

Da PID

winapp ui inspect -a 12345

Da HWND (stabile — sopravvive alle modifiche di tabulazioni/titolo)

# 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

Usare -a per l'individuazione, -w per la destinazione stabile. Quando -a corrisponde a più finestre, il comando li elenca con HWND da selezionare.

Selettori

Elementi di destinazione che usano il selettore visualizzato in nell'output [brackets] di ispezione/ricerca. Esistono tre tipi di selettori:

Selettore Meaning Example
MinimizeButton AutomationId (visualizzato quando univoco, stabile, preferito) winapp ui invoke MinimizeButton -a myapp
btn-close-d1a0 Slug semantico (visualizzato quando non è univoco AutomationId) winapp ui invoke btn-close-d1a0 -a myapp
Submit Ricerca in testo normale in Nome/AutomationId (sottostringa senza distinzione tra maiuscole e minuscole) winapp ui invoke Submit -a myapp

I selettori AutomationId sono identificatori del set di sviluppatori (AutomationProperties.AutomationId in XAML). Quando un AutomationId è univoco nell'intero albero inspect dell'interfaccia utente e search lo mostra direttamente come selettore, che sopravvive alle modifiche di layout, alla localizzazione e alla ristrutturazione dell'albero.

I selettori slug (ad esempio, btn-close-d1a0) vengono generati quando non esiste un AutomationId univoco. Formato: prefix-name-hash. L'hash convalida l'identità dell'elemento, ma potrebbe non essere aggiornata dopo le modifiche dell'interfaccia utente.

Esaminare il formato di output

Il inspect comando mostra l'albero degli elementi con output colorato (selettore in ciano, nome in verde, metadati in grigio):

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 prima parola in ogni riga è il selettore, usarla con altri ui comandi. Quando un elemento ha un automationId univoco, viene usato direttamente (ad esempio, TabView, NewTabButton). Quando non esiste alcun AutomationId univoco, viene usato un slug generato ,ad esempio tab-newtab-5f5b.

Slug semantici

I slugs usano il formato: dove: prefix-normalizedname-hash

  • prefisso — abbreviazione di tipo 3 lettere (btn, txt, chk, cmb, itm, tab, img, lbl, pn, win, grp, lnk, mnu e così via)
  • normalizedname : alfanumerico minuscolo da AutomationId (preferito) o Nome, massimo 15 caratteri
  • hash : hash esadecimale a 4 caratteri del RuntimeId dell'elemento (convalida l'identità dell'elemento)

I slug sono indipendenti dalla shell (senza caratteri speciali), univoci e possono essere usati direttamente come argomenti. Senza filtri di query, l'hash fornisce il rilevamento di decadimento: se l'elemento è stato sostituito, si ottiene: "L'elemento potrebbe essere stato modificato. Eseguire di rieseguare l'ispezione." Per le query filtrate, vedere Query con ambito e tipizzato.

Gli elementi senza nome o AutomationId mostrano solo il prefisso + hash (ad esempio, pn-c8a3).

Disambiguare più corrispondenze

I slugs dall'output inspect/search sono univoci, ma possono cambiare le modifiche di layout: usarle su nomi di tipo normale o testo quando più corrispondenze. Quando un selettore è ambiguo, l'interfaccia della riga di comando stampa tutte le corrispondenze con i relativi slug, in modo da poter scegliere quella corretta e rieseguerla con tale 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

Usare il testo normale per cercare elementi: non è necessaria una sintassi speciale:

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

Quando una ricerca di testo corrisponde a più elementi (ad esempio, SettingsExpander dove Group, Button e Text condividono lo stesso nome), l'interfaccia della riga di comando seleziona automaticamente l'unico elemento richiamabile. Se più sono richiamabili, elenca tutte le corrispondenze con i slug.

Per i risultati di ricerca non richiamabili (ad esempio, textBlock all'interno di un pulsante), la ricerca espone automaticamente il predecessore richiamabile più vicino, ovvero l'elemento padre che è possibile usare con invoke. Questa operazione funziona per tutti i selettori di ricerca:

  lbl-savechanges-a1b2 "Save changes" (120,40 80x20)
        ^ invoke via: btn-save-c3d4 "Save"

Il selettore di superficie può essere usato direttamente:

winapp ui invoke btn-save-c3d4 -a myapp    # invoke the parent Button

Comandi

stato

Connettersi a un'app e visualizzare le informazioni di connessione.

winapp ui status -a notepad
winapp ui status -a notepad --json

Ispezionare

Visualizzare l'albero degli elementi dell'interfaccia utente. L'output mostra i slug semantici con rientro a 2 spazi per la gerarchia:

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        # elements you can invoke, click, or set-value; auto-depth 8
winapp ui inspect -a myapp --hide-disabled      # hide disabled elements
winapp ui inspect -a myapp --hide-offscreen     # hide offscreen elements

Output di esempio (impostazione predefinita):

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)

Output di esempio ( ---interactive solo elementi interattivi, elenco flat):

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)

Gli elementi possono mostrare questi marcatori di stato:

  • [on] / [off] / [indeterminate] — Stato attiva/disattiva/casella di controllo
  • [collapsed] / [expanded] — espandere/comprimere lo stato per alberi, caselle combinate, voci di menu
  • [scroll:v] / [scroll:h] / [scroll:vh] — contenitore scorrevole (verticale, orizzontale o entrambi)
  • [offscreen] — l'elemento non è visibile sullo schermo
  • [disabled] — l'elemento non è abilitato
  • value="..." — contenuto di testo corrente per gli elementi modificabili (se diverso da Name)

Trovare elementi corrispondenti a un selettore. L'output mostra i slug semantici:

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

Output di esempio:

  btn-minimize-d1a0 "Minimize" (1222,206 48x48)
  btn-maximize-e2b1 "Maximize" (1270,206 48x48)
  btn-close-d1a2 "Close" (1318,206 48x48)

I slug visualizzati nell'output (ad esempio , btn-minimize-d1a0) possono essere usati direttamente con altri comandi:

winapp ui invoke btn-minimize-d1a0 -a notepad

get-property

Legge i valori delle proprietà da un elemento. Include lo stato specifico del criterio (ToggleState, Value, IsSelected e così via).

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
winapp ui get-property Document -p FontWeight -a myapp --json     # document formatting

Nei nomi delle proprietà viene fatta distinzione tra maiuscole e minuscole. Un nome sconosciuto ha esito negativo con in invalid_arguments--json; omettere --property di elencare le proprietà, inclusi tutti e sei gli attributi di formattazione del testo seguenti. wait-for --property usa gli stessi nomi con distinzione tra maiuscole e minuscole e rifiuta nomi sconosciuti prima del polling.

Formattazione testo intero-documento

La formattazione viene letta nell'intero documento TextPattern dell'elemento, non nella selezione o nel cursore corrente. Le letture non modificano lo stato attivo o la selezione.

Property Valore uniforme (restituito come stringa)
FontWeight Peso numerico, ad esempio "400" (normale) o "700" (grassetto)
FontName Nome della famiglia di caratteri, ad esempio "Courier New"
FontSize Dimensioni in punti, ad esempio "15.5"
ForegroundColor Decimal Windows COLORREF (0x00BBGGRR), ad esempio "3678732" per RGB(12, 34, 56)
IsItalic "True" oppure "False"
StrikethroughStyle Stile di decorazione testo UIA numerico, ad esempio "0" (nessuno) o "1" (singolo)

I numeri usano la formattazione invariante (un separatore decimale, indipendentemente dalle impostazioni locali). Ogni attributo può invece restituire:

Value Significato e passaggio successivo
"Mixed" La formattazione varia all'interno del documento. Non considerarlo come un valore uniforme; questo comando non esegue query su singoli intervalli di testo.
"NotSupported" Il provider TextPattern del documento non segnala questo attributo. Controllare il supporto per l'accessibilità dell'app.
"Unavailable" L'elemento non dispone di TextPattern. Utilizzare inspect o search per trovare il relativo elemento di testo/documento.

Quando si elencano tutte le proprietà, le proprietà di base memorizzate nella cache rimangono disponibili se non è possibile risolvere alcun elemento attivo e un valore di formattazione in formato non valido viene omesso senza rimuovere altre proprietà. Queste omissioni vengono registrate come avvisi. Richiedere una proprietà di formattazione specifica per ottenere un errore anziché un'omissione.

Gli errori del provider rimangono errori, non "Unavailable". Per stale_element, esaminare nuovamente l'app e riprovare con un selettore corrente.

La busta JSON include elementId, un oggetto tipizzato elemente con valori propertiesstringa . Le proprietà esistenti, tra cui BoundingRectangle, mantengono i relativi formati. Ad esempio, la parte di formattazione di properties è:

{
  "FontWeight": "700"
}

schermata

Acquisire una finestra o un elemento come PNG.

winapp ui screenshot -a notepad                     # saves screenshot.png in cwd
winapp ui screenshot -a notepad --output my.png     # custom filename
winapp ui screenshot --quiet -a notepad -o my.png   # save without informational output
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 -w 131906 --capture-screen     # one screen region, with visible overlays in place; foregrounds window
winapp ui screenshot -a myapp --focus               # bring window to foreground first, then capture (default WGC path)

Senza un selettore di elementi, l'acquisizione predefinita combina più finestre in un file PNG composito side-by-side etichettato, non in file separati. -a per nome del processo o PID include le finestre dell'app e le relative finestre di proprietà. Una corrispondenza basata sul -a titolo seleziona una finestra corrispondente più le finestre di proprietà. -w Seleziona in modo esplicito una finestra più le finestre di proprietà, non tutte le finestre del processo. Una finestra di dialogo o una descrizione comando di proprietà può quindi essere visualizzata come un proprio pannello anche quando si seleziona in modo esplicito il HWND principale. Un selettore di elementi ritaglia a tale elemento invece di comporre finestre. Un elemento di un menu, un riquadro a comparsa, una descrizione comando o una descrizione informativa che si apre nella propria finestra popup viene ritagliato da tale popup, non dalla finestra sottostante.

--quiet elimina l'output informativo per acquisizioni a finestra singola e composita, incluso il percorso salvato. Gli avvisi e la diagnostica degli errori di acquisizione rimangono visibili. Usare --json invece quando è necessario il percorso e le dimensioni del file come output strutturato.

Con --on sandbox, --output denomina la destinazione host. Output normale riuscito e --json report che ospitano il percorso dopo il recapito dell'immagine.

Il percorso di acquisizione predefinito usa Windows. Graphics.Capture (WGC), leggendo la superficie composita DWM effettiva, mantenendo angoli arrotondati, trasparenza e funzionamento anche mentre la finestra è bloccata da altri windows. Se WGC non è disponibile (versioni precedenti Windows build) l'interfaccia della riga di comando esegue il fallback a PrintWindow.

Usare --capture-screen -w <hwnd> quando sono necessari popup o descrizioni comando visibili nelle rispettive posizioni sullo schermo, incluse le sovrimpressioni non di proprietà della finestra di destinazione. Legge l'area dello schermo della finestra anziché comporre pannelli etichettati e porta prima la finestra in primo piano. Con -a, richiede esattamente una finestra corrispondente; se diverse finestre di primo livello o di proprietà corrispondono, usare winapp ui list-windows -a <app> e riprovare con -w <hwnd>. Usa --focus se vuoi solo mettere in primo piano la finestra senza cambiare modalità di acquisizione (ad esempio, per garantire che lo screenshot corrisponda a quello che l'utente sta attualmente esaminando).

Poiché il controller di dominio dello schermo acquisisce ciò che è effettivamente davanti, --capture-screenverifica che la destinazione abbia raggiunto il primo piano immediatamente prima dell'acquisizione e abbia esito negativo con foreground_not_target se non è stata eseguita (prevenzione del furto dello stato attivo, un prompt dell'interfaccia utente o un'altra finestra che si attiva). In questo caso non viene scritta alcuna immagine, in precedenza il comando ha chiuso 0 e restituito un'immagine della finestra sbagliata. ui record --capture-screen applica lo stesso controllo prima del primo fotogramma.

registro

Registrare una finestra o un'area dell'elemento in un mp4 H.264. Preferisce un positivo --duration-sec per gli script automatici. Senza una durata, la registrazione continua fino a CTRL+C o, per stdin reindirizzato, una nuova riga o EOF. Gli helper e npm uiRecord richiedono un numero intero durationSec compreso tra 1 e targetRecord 86400; il segnale di interruzione annulla forzatamente anziché finalizzare correttamente una registrazione.

# Record for 10 seconds
winapp ui record -a myapp --duration-sec 10 --fps 15 --output demo.mp4

# Add agent-readable frames
winapp ui record -a myapp --frames --duration-sec 10 --fps 10 --output evidence.mp4 --json

# Stop an unbounded recording through stdin
"" | winapp ui record -a myapp --json --output capture.mp4

# Include screen overlays and popups
winapp ui record -a myapp --capture-screen --duration-sec 5 --output with-popups.mp4

Opzioni:

  • --duration-sec N — Record per N secondi. Record predefinito 0 fino all'arresto.
  • --fps N — Fotogrammi di destinazione al secondo (impostazione predefinita 15).
  • --max-edge N — Ridimensionamento in modo che il bordo più lungo sia al massimo N pixel (0 = nessuna riduzione).
  • --capture-screen - Acquisizione dal controller di dominio dello schermo (include sovrimpressioni/popup; in primo piano la finestra).
  • --output <path> — Percorso MP4 di output. Di default è recording-<timestamp>-<guid>.mp4.
  • --overwrite - Sostituire gli output di registrazione esistenti al termine della nuova operazione. Senza di esso, gli output esistenti vengono rifiutati.
  • --frames — Scrivere prove JPEG con timestamp in <output-name>.frames. Supporta 1-30 fps e --max-edge 64-4096 (impostazione predefinita 1280). I dati dei frame sono limitati a 1 GiB; mp4 continua se viene raggiunto il limite.

Artefatti frame leggibili dall'agente:

evidence.mp4
evidence.frames/
  manifest.json
  frames.ndjson
  frames/
    frame-000000-t000000000012.jpg

frames.ndjson ha una riga per esempio con sampleIndex, monotonico elapsedMs, MP4 relativo mediaTimeMsa , imageIndex, filee changed. I campioni consecutivi identici ai pixel riutilizzano la qualità 85 JPEG precedente.

manifest.json registra la richiesta, l'intervallo, lo stato MP4, le dimensioni dell'immagine e lo stato (complete, partialo truncated). L'intervallo troncato copre il prefisso conservato, mentre video descrive l'MP4 completo.

Scegliere un nuovo percorso di output a meno che non si intenda sostituire una registrazione con --overwrite. Senza di esso, un video esistente o la relativa directory abbinata .frames blocca la registrazione, anche quando si omette --frames. Il mp4 precedente rimane intatto se la nuova acquisizione ha esito negativo. Al termine della sostituzione, la directory dei fotogrammi precedente viene mantenuta come <output-name>.frames.previous-<id>, anche se la nuova registrazione omette --frames. Conservare l'evidenza parziale e seguire l'oggetto segnalato recoveryHint prima di riprovare. Se la finalizzazione di MP4 non riesce, i fotogrammi mantenuti possono essere pubblicati in <output-name>.frames.partial-*. Gli artefatti frame contengono contenuto dello schermo non crittografato; gestirli come screenshot o video.

Con --on sandbox, sia mp4 che la directory dei fotogrammi vengono recapitati all'host, inclusi gli output predefiniti quando --output viene omesso. Vedi Acquisizione sandbox per le registrazioni interrotte e l'acquisizione dell'intero desktop.

Modalità di acquisizione (segnalata nel campo JSON mode ):

  • wgc— Windows Acquisizione grafica (impostazione predefinita; funziona mentre la finestra è bloccata).
  • printwindow — GDI PrintWindow (fallback quando WGC non è disponibile in questo sistema/sessione; esegui nuovamente con --capture-screen per usare il controller di dominio dello schermo).
  • screen — Controller di dominio dello schermo tramite --capture-screen (include sovrimpressioni/popup; porta la finestra in primo piano).

Output JSON (--json):

  • stdout: Risultato della registrazione finale, tra cui cadenza, motivo di arresto, avvisi facoltativi frameArtifactse .
  • stderr: Un oggetto JSON per riga: un recording-started evento dopo il primo fotogramma, seguito da un errore se la registrazione ha esito negativo in un secondo momento. I percorsi dei fotogrammi sono inclusi solo quando l'output del frame è attivo.

Codici di errore:

  • element_not_found — Il selettore non corrisponde.
  • ambiguous_selector — Il selettore corrisponde a più elementi; usare un slug suggerito.
  • invalid_arguments — Un valore di opzione non è valido.
  • output_exists — Esiste già un output di registrazione e non può essere sostituito nelle opzioni richieste.
  • frame_output_failed - Nessun elemento può essere mantenuto dopo che l'output del frame non è riuscito.
  • partial_output — Solo un artefatto completato; ispezionare partialOutput e recoveryHint.

Un selettore di elementi registra l'area dell'elemento dalla finestra in cui viene disegnato. Per una voce di un menu, un riquadro a comparsa, una descrizione comando o una descrizione informativa che si apre nella propria finestra popup, la registrazione mostra il popup anziché la finestra sottostante.

evocare

winapp ui invoke SettingsCategory -a myapp --action select
winapp ui invoke AgreeCheckbox -a myapp --action toggle-on --json
winapp ui invoke SizeComboBox -a myapp --action expand
winapp ui invoke Open -w <dialog-HWND> --root Actions --type Button --class-name Button --action invoke
winapp ui invoke SubmitButton -a myapp

Utilizzare --action quando un test deve eseguire un'operazione specifica sull'elemento selezionato esattamente. Non prova mai un altro modello o un predecessore richiamabile, anche se l'azione richiesta ha esito negativo. Verrà selezionato un controllo che supporta sia la chiamata che la selezione, non richiamato, con --action select. Con --action, un slug punta esattamente a un elemento; un selettore di testo normale o AutomationId che corrisponde a più elementi ha esito negativo chiuso con un codice di uscita diverso da zero anziché agire sulla prima corrispondenza, quindi passare un slug da inspect/search quando un nome è ambiguo.

--root, --typee --class-name restringere la corrispondenza come descritto in Query con ambito e tipizzato, con o senza --action. Usare -w <dialog-HWND> per limitare un'azione a tale finestra di dialogo o -a <app> per includere le finestre dell'app. Una chiamata filtrata conferma la destinazione univoca prima di agire, richiede esattamente un elemento corrispondente e non passa mai a un'altra finestra o a un predecessore richiamabile. Nessuna corrispondenza ha esito negativo con element_not_found; i duplicati hanno esito negativo con ambiguous_selector. Un elemento non aggiornato o una finestra riciclata non riesce senza agire; inspect eseguire di nuovo o search e scegliere un selettore corrente. Senza --action, un oggetto invoke filtrato tenta comunque i criteri in ordine su tale elemento.

Action Operation
invoke InvokePattern.Invoke
select SelectionItemPattern.Select
toggle TogglePattern.Toggle, esattamente una volta
toggle-on / toggle-off Read ToggleState; esito positivo senza modificare uno stato già corretto; in caso contrario, attivare e verificare
expand / collapse ExpandCollapsePattern.Expand/ Collapse

Per toggle-on e toggle-off, uno stato iniziale Indeterminate consente al massimo due transizioni, controllando lo stato dopo ciascuno. Gli altri stati iniziali consentono una transizione. Se lo stato richiesto non viene raggiunto, il comando non riesce anziché continuare a attivare/disattivare. Una verifica non riuscita può lasciare il controllo modificato; leggere ToggleState prima di decidere cosa fare successivamente.

Senza --action e senza filtri, il comportamento automatico è invariato: provare InvokePattern, TogglePattern, SelectionItemPattern, quindi ExpandCollapsePattern (espandi), con un nuovo tentativo richiamabile-predecessore quando necessario.

Un'azione non supportata ha esito negativo con un codice di uscita diverso da zero e, con --json, un errore strutturato in stderr. Esaminare il controllo selezionato e scegliere un'azione supportata o specificare in modo esplicito l'elemento padre desiderato. Success JSON include requestedAction e performedAction. Vedere il riferimento JSON.

click

Fare clic su un elemento in corrispondenza delle coordinate dello schermo usando la simulazione del mouse. Usare questa opzione per i controlli che non supportano InvokePattern (ad esempio, intestazioni di colonna, voci di elenco).

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

Come gli altri verbi di inserimento di input, click porta la destinazione in primo piano e non riesce veloce (no_interactive_desktop su un desktop bloccato/sicuro, foreground_not_target se non è stato possibile trasferire lo stato attivo) anziché fare clic sulla finestra sbagliata. Risolve anche di nuovo l'elemento poco prima del pulsante giù: dopo aver posizionato il cursore esegue un controllo finale della posizione, quindi una destinazione di spostamento/animazione continua non riesce con target_moved anziché segnalare l'esito positivo dopo che il clic è atterrato su uno spazio vuoto. Un esito positivo segnalato indica che la destinazione era ancora in posizione quando il pulsante è andato giù.

Resistenza

Premere il pulsante del mouse in un punto, spostarsi in un altro, quindi rilasciare con drag <from> <to>, dove ogni endpoint è un selettore di elementi (trascina da/al centro dell'elemento) o coordinate x,ydello schermo esattamente come segnalato da winapp ui inspect. Combinare e abbinare liberamente (selettore→selector, selettore→coord, coords→coords).

Usa con spostamenti SendInput intermedi in modo che l'app veda un flusso realistico di WM_MOUSEMOVE messaggi. Usarlo per riordinare/ridimensionare handle, dispositivi di scorrimento, disegno canvas e trascinamento della selezione.

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

Opzioni:

  • --right - Trascinare con il pulsante destro del mouse invece del pulsante sinistro.
  • --hold-ms <ms> — Tenere premuto il pulsante all'inizio prima di spostarsi (impostazione predefinita: 0). Con <from> == <to> (nessun movimento) esegue un movimento di pressione e blocco /pressione prolungata .
  • --dwell-ms <ms> — Attesa nella destinazione dopo lo spostamento, prima del rilascio (impostazione predefinita: 0). Consente di eliminare le destinazioni o unire sovrapposizioni che il braccio da un passaggio del mouse sostenuto (anziché l'istante in cui arriva il cursore) prima del pulsante su.

x,y Le barre sono coordinate dello schermo nello stesso report dello spazio winapp ui inspect/search e un selettore si risolve al centro dell'elemento, ispezionando prima di tutto i punti di selezione.

Come send-keys --via send-input, drag inserisce a livello di sistema operativo le coordinate dello schermo dopo aver portato la destinazione in primo piano. Se lo stato attivo non può essere portato alla destinazione (ad esempio, la prevenzione del furto dello stato attivo da un processo in background), il comando non riesce (foreground_not_target) anziché trascinare sulla finestra sbagliata, ovvero lo stato attivo o fare clic prima sulla finestra. In un desktop bloccato/protetto ha esito negativo con no_interactive_desktop. Ogni endpoint dell'elemento viene risolto immediatamente prima del trascinamento; se è ancora in movimento/ridimensionamento (destinazione di animazione), il comando ha esito negativo e target_moved non viene trascinato in un punto non aggiornato. Gli endpoint bare x,y non possono essere verificati nuovamente, quindi vengono usati as-is.

Toccare

Inserire movimenti di tocco sintetici usando l'API Windows puntatore injection. L'ancoraggio di contatto è un selettore di elementi (usa il centro dell'elemento) o una coordinata x,ydello schermo esplicita tramite --at (stessi report sullo spaziowinapp ui inspect). Usarlo per interazioni con tocco/pressione e movimenti multitocco che la simulazione del mouse non può esprimere.

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)

Opzioni:

  • --gesture <g>— tap (impostazione predefinita), double-tap, long-pressswipe, pinch, , stretch.
  • --at <x,y> — Punto iniziale esplicito (coordinate dello schermo). Il valore predefinito è il centro elementi del selettore.
  • --to-point <x,y> — Punto finale per un oggetto swipe. Ha la precedenza su --direction.
  • --direction <right|left|up|down> — Direzione scorrimento rapido (impostazione predefinita: right). Combinato con --distance per calcolare l'endpoint quando --to-point non viene specificato.
  • --distance <px> : distribuitura di dita per pinch/stretcho distanza di scorrimento rapido in pixel.
  • --hold-ms <ms> — Tenere premuti i contatti prima dell'lifting (tempo di attesa con pressione prolungata; il valore predefinito è 500 ms quando long-press non è impostato).
  • --duration-ms <ms> — Tempo di scorrimento per i movimenti mobili (scorrimento rapido/avvicinamento/tratto; valore predefinito 300).
  • --fingers <n> — Numero di contatti (1-10; valore predefinito 1). pinch / stretch usare sempre 2.

Sicurezza dell'iniezione. touch rifiuta l'inserimento a meno che non venga risolto un handle di finestra di destinazione diverso da zero e che tale finestra contenga il primo piano. L'operazione ha esito negativo quando no_target non è possibile risolvere nessuna finestra, foreground_not_target se non è stato possibile trasferire lo stato attivo o no_interactive_desktop su un desktop bloccato/protetto. Ogni coordinata (centro degli elementi, punti di direzione espliciti --at/--to-pointe generati) viene controllata sul rettangolo della finestra di destinazione. Un punto all'esterno della finestra viene esposto come avviso non irreversibile (una warnings[] voce in --jsono una riga di avviso in modalità testo) e l'inserimento continua a corrispondere ai verbi del mouse (click/drag/hover/scroll), che vengono inseriti anche in coordinate fuori finestra. --fingers sopra 10 viene rifiutato in anticipo.

Nota hardware. Il tocco preferisce il dispositivo di puntatore sintetico moderno (CreateSyntheticPointerDevice(PT_TOUCH)) ed esegue il fallback all'API legacyInitializeTouchInjection/InjectTouchInput. Se l'inserimento non è supportato nel dispositivo/sessione corrente, il comando visualizza il codice di errore Win32 effettivo (ad esempio "non supportato") anziché segnalare un falso esito positivo, considerare un'uscita non zero come "tocco non recapitato".

sessioni Desktop remoto/VM. In una Desktop remoto (RDP) o in alcune sessioni di macchine virtuali il sistema operativo può accettare il tocco sintetico (uscita 0) senza raggiungere effettivamente l'app di destinazione. Quando viene rilevata una sessione remota, touch aggiunge un avviso di incertezza sul recapito , ovvero una warnings[] voce in --jsono una riga di avviso in modalità testo. Un ✅/exit 0 indica quindi che la chiamata di inserimento ha avuto esito positivo, non che l'app abbia ricevuto l'input; confermare l'effetto con ui screenshot/ui inspect quando è importante.

penna

Inserire input penna/stilo sintetico — tocco e tratti input penna — usando l'API Windows puntatore sintetico (CreateSyntheticPointerDevice(PT_PEN); Windows 10 1809+). Scegliere come destinazione un centro elementi, un punto esplicito --at o un tratto input penna 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

Opzioni:

  • --at <x,y> — Punto di contatto penna (coordinate dello schermo). Il valore predefinito è il centro elementi del selettore. Ignorato quando --path viene specificato.
  • --path "<x,y x,y …>" — Percorso tratto input penna come coppie separate da x,y spazi vuoti (un percorso a un punto è un tocco).
  • --pressure <0.0–1.0> — Pressione penna (impostazione predefinita 0,5).
  • --tilt-x <deg> / --tilt-y <deg> — Angoli di inclinazione della penna, da −90 a 90 (impostazione predefinita 0).
  • --eraser — Utilizzare la parte finale della penna invece della punta.
  • --duration-ms <ms> — Tempo totale di spostamento del tratto in millisecondi distribuito come fotogrammi UPDATE interpolati nel percorso (impostazione predefinita: ~10 ms per waypoint). Usare questa opzione per controllare la velocità con cui la penna si sposta visibilmente dall'inizio alla fine.

Sicurezza dell'iniezione. Come touch, pen rifiuta di inserire senza una finestra di destinazione in primo piano () in primo piano (no_target / foreground_not_target / no_interactive_desktop) e controlla ogni punto input penna sul rettangolo della finestra di destinazione, visualizzando qualsiasi coordinata fuori finestra come avviso non irreversibile (warnings[] in o una --jsonriga di avviso in modalità testo) pur continuando a inserire , coerente con i verbi del mouse. Non valido --pressure (all'esterno di 0,0-1,0) o inclinazione (all'esterno di ±90°) viene rifiutato in primo piano.

sessioni Desktop remoto/VM. Il routing penna è particolarmente inaffidabile in Desktop remoto: la chiamata injection può segnalare l'esito positivo (uscita 0) mentre nessun input penna raggiunge l'app. Quando viene rilevata una sessione remota, pen aggiunge un avviso di incertezza del recapito (warnings[] in --jsono una riga di avviso in modalità testo) in modo che non ✅ venga erroneamente eseguito un errore per il recapito confermato. Convalidare i flussi dipendenti dalla penna in un desktop interattivo locale.

passaggio del mouse

Spostare il mouse al centro di un elemento per attivare effetti al passaggio del mouse (descrizioni comando, riquadri a comparsa, stati di visualizzazione). SendInput Usa per lo spostamento realistico del mouse con una piccola pulsazione, quindi attende un tempo di attesa configurabile.

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 list-windows -a myapp                              # use the main window's HWND below
winapp ui hover btn-info-a1b2 -a myapp; winapp ui screenshot -w <hwnd> --capture-screen  # hover then capture tooltip in place

Opzioni:

  • --dwell-time <ms> — Tempo in millisecondi di attesa dopo il passaggio del mouse per visualizzare gli effetti (impostazione predefinita: 800, intervallo: 0-10000)

send-keys

Inviare l'input della tastiera sintetica, ovvero la controparte della tastiera a click. L'interfaccia utente non ha un modello di iniezione da tastiera, quindi questo scende al livello Win32. Usarlo per lo spostamento tramite tastiera (frecce, TAB, INVIO, ESC), tasti di scelta rapida (ctrl+c, alt+f4) e digitazione nei controlli che richiedono eventi per sequenza di tasti anziché set-valuela scrittura atomica.

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
winapp ui send-keys "ctrl+capslock+f12" -a myapp --via send-input  # Narrator command: toggle developer mode

Grammatica della chiave (token separati da spazi vuoti, virgolette stringhe multi-token):

  • Chiavi denominate : enter/return, tabesc/escapespacebackspace,delete/del , insert, home,endpageup/pguppagedown/pgdn , ,up/down/left/rightf1f16apps , . printscreencapslock
  • Sequenze : vengono premuti più token nell'ordine: down down enter.
  • Combinazioni di modifica - ctrl, shift, alt, unite win con +: ctrl+shift+t, alt+f4. Un token che inizia con un modificatore ma ha un segmento sconosciuto prima dell'ultimo (ctrl+a+b) è un errore; usare text= o --verbatim per digitarlo.
  • Comandi dell'utilità per la lettura dello schermo: tenere premutocapslock o insert (alias ins), l'Assistente vocale, NVDA e JAWS chiave: ctrl+capslock+f12 attiva/disattiva la modalità sviluppatore dell'Assistente vocale. Richiede --via send-input, perché le utilità per la lettura dello schermo non ricevono chiavi pubblicate. Se non è in esecuzione alcuna utilità per la lettura dello schermo, tenere premuto capslock Blocca maiuscole e disattiva e il comando avvisa. Tenere premuto insert per evitare questo problema.
  • Testo letterale : qualsiasi token che non è una chiave nota è tipizzato in base al carattere: hello. Le parole letterali adiacenti mantengono lo spazio tra di esse, quindi una frase tra virgolette come "Hello world" è tipizzata verbatim (lo spazio viene mantenuto); un valore letterale che contiene + semplicemente come C++ testo o a+b viene digitato come testo, non analizzato come combinazione.
  • Escape letterale esplicito : anteporre un token a text= per digitarlo verbatim anche quando si scontra con un nome di chiave o modificatore: text=enter digita la parola "invio" anziché premere INVIO e text=ctrl+a digita la stringa letterale. Rispecchia l'escape vk= ; il valore preceduto da escape continuerà a fondersi con parole letterali adiacenti (text=down low → "down low"). Poiché i token sono separati da spazi vuoti (e i valori letterali adiacenti vengono ricreati con un singolo spazio), usare escape barra rovesciata all'interno di un text= valore per digitare spazi vuoti che altrimenti non sopravvivono: \s → spazio, \t tabulazione →, \n → nuova riga, \r → nuova riga, \\ → barra rovesciata letterale. \n, \re \r\n ogni inserisce una singola interruzione di riga (invio / VK_RETURN), quindi text=line1\nline2 e text=line1\r\nline2 entrambi digitano una nuova riga. Quindi text=a\s\sb digita "a b" (spazio doppio) e text=\shi mantiene uno spazio iniziale. Un escape non riconosciuto ,ad esempio \x, viene lasciato verbatim.
  • Valore letterale dell'intero argomento (--verbatim): quando l'intero payload è testo letterale, passare --verbatim anziché eseguire l'escape di ogni token con text=. Digita l'intero argomento chiavi esattamente come specificato , senza interpretazione denominata chiave/combinata/vk=/text= e, a differenza del percorso normale, mantiene gli spazi vuoti interni esatti (senza compressione) senza bisogno di .\s Quindi send-keys "down down enter" --verbatim digita le parole e send-keys "a b" --verbatim mantiene lo spazio doppio. Le sequenze di escape della barra rovesciata non vengono decodificate in --verbatim modalità (un \s oggetto viene digitato come barra rovesciata e "s"). Usare un token quando è necessario un text= carattere di controllo di escape.
  • Chiavi virtuali non elaborate : vk=0xNN (esadecimale) o vk=NN (decimale) per le chiavi senza un nome descrittivo.

Opzioni:

  • --target <selector> — Concentrarsi su questo elemento (tramite UIA) prima di inviare i tasti. Senza di esso, le chiavi passano all'elemento attualmente attivo dell'app.
  • --verbatim — Digitare l'intero argomento chiavi come testo letterale (nessuna chiave/combinata/vk=/text= analisi) e mantenere lo spazio vuoto esatto. Forma di argomento intero dell'escape per token text= .
  • --via <transport>— post-message (impostazione predefinita) inserisceWM_KEYDOWN/WM_KEYUP/WM_CHARnella coda della finestra di destinazione. È destinato a HWND e ignora uiPI (funziona tra i livelli di integrità). send-input inserisce il sistema operativo a livello di sistema operativo tramite SendInput e passa alla finestra in primo piano.

Scelta di un trasporto/limiti noti:

  • post-message è l'impostazione predefinita perché ignora uiPI e non dipende dalla finestra in primo piano. Limiti: non è possibile attivare i tasti di scelta rapida globali registrati tramite WH_KEYBOARD_LL hook di basso livello (quelli che toccano l'input upstream di qualsiasi coda di finestre) e le app che leggono lo stato della chiave non elaborata tramite GetAsyncKeyState potrebbero non osservare modificatori mantenuti. Risolve e invia automaticamente alla finestra figlio attiva del thread di destinazione (tramite GetGUIThreadInfo) dopo la creazione in primo piano, quindi le app Win32/WinForms classiche i cui controlli sono chiavi di ricezione di finestre figlio separate senza impostare manualmente come destinazione il controllo. Le app WinUI 3/UWP hanno controlli XAML senza finestra senza HWND figlio, quindi un post non WM_CHAR/WM_KEYDOWN ha nulla da inserire e viene eliminato. Il post-messaggio non può guidarli (il comando avvisa e esce da 0); usa --via send-input. (macchine virtuali Windows finestre sono single-HWND e indirizzano le chiavi all'elemento con stato attivo internamente, quindi il post-messaggio funziona lì.
  • send-inputproduce input completamente reale (modificatori visibili a GetAsyncKeyState, attiva hook di basso livello) ma passa a qualsiasi finestra in primo piano e viene bloccato da UIPI quando si inserisce da un processo con privilegi elevati in una destinazione di integrità inferiore (AppContainer/AppX). Se send-input segnala un errore, è probabile che la destinazione sia elevata o un'app AppX, usare post-messageo eseguire l'interfaccia della riga di comando a un livello di integrità corrispondente. Come guardia di sicurezza, send-input verifica che la finestra di destinazione sia in primo piano immediatamente prima dell'inserimento e dell'esito negativo (foreground_not_target) anziché digitare nella finestra sbagliata se non è stato possibile spostarlo sullo stato attivo, ovvero lo stato attivo o fare clic prima sulla finestra. In un desktop bloccato o protetto ha esito negativo con no_interactive_desktop (non esiste alcuna finestra in primo piano per inserire) - sbloccare la sessione o usare un verbo uiA-pattern (set-value, invoke).
  • Le combinazioni riservate dal sistema (win+l, win+r, ctrl+shift+escctrl+alt+del, , alt+tab, alt+f4, ctrl+esc, lone win/printscreen, ...) agiscono sul sistema operativo/shell anziché solo sulla destinazione quando viene inviato a livello di sistema operativo. send-input li rifiuta per impostazione predefinita (errori con invalid_arguments e non invia nulla) perché l'inserimento a livello del sistema operativo ha effetti ben oltre la finestra di destinazione (ad esempio win+l , blocca la sessione). Passare --allow-system-keys per acconsentire esplicitamente: consente di guidare un tasto di scelta rapida globale, ad esempio PowerToys win+shift+v o win+r (l'hook di basso livello globale controlla il flusso di input a livello di sistema operativo, in modo che la combinazione inserita venga attivata). Eccezioni che rimangono bloccate anche con --allow-system-keys:win+l blocca la workstation tramite LockWorkStation() la quale non è irreversibile dall'automazione (interrompe sessioni CI e desktop remoto) ed ctrl+alt+del è una sequenza di attenzione sicura (SAS) che Windows elimina l'input inserito indipendentemente dal flag , non può mai avere effetto, quindi errori (invalid_arguments, uscita 1) invece di segnalare un esito positivo fuorviante. Altre combinazioni (alt+f4, ctrl+shift+esc, win+r, ...) diventano consentite con il flag : attenzione del chiamante. In alternativa, per recapitare una combinazione di sistema a una finestra specifica usa --via post-message, che è con ambito finestra e non interessato (un post è innocuo, anche se un post win+lalt+f4 chiude ancora la finestra di destinazione).

Eventi per sequenza di tasti (KeyDown/TextChanged):

  • Le chiavi denominate e le combinazioni di modifica (down, enter, ctrl+shift+t, vk=0xNN) generano un reale KeyDown (e KeyUp) su entrambi i trasporti, che vengono recapitati come eventi discreti WM_KEYDOWN/WM_KEYUP (o SendInput di chiave virtuale).
  • Il testo tipizzato letterale (hello) è diverso dal trasporto:
    • --via send-input esegue il mapping di ogni carattere al tasto virtuale (più MAIUSC) nel layout della tastiera attivo, quindi la destinazione vede un autentico KeyDown con il tasto virtuale corretto seguito dal sistema operativo composto WM_CHAR (generando TextChanged) , ovvero una sequenza di tasti completa per carattere. I caratteri non raggiungibili nel layout corrente (o che richiedono CTRL/ALTGR) rebackno a un pacchetto Unicode, in modo che il carattere esatto venga ancora raggiunto. Usa send-input quando hai bisogno di fedeltà per sequenza di tasti KeyDown (ad esempio, guidando un winUI 3 / macchine virtuali Windows TextBox il cui tasto di manipolazione è disattivato KeyDown). Per un host di test WinUI 3 normale (non con privilegi elevati), portare la finestra in primo piano (winapp ui focus / facendo clic su di esso) perché send-input è destinata alla finestra in primo piano.
    • --via post-message inserisce un singolo WM_CHAR carattere ( non inserisce WM_KEYDOWN/WM_KEYUP per il testo tipizzato , ovvero sono riservati per chiavi/combo denominate), che non genera un per carattere KeyDown. Restituisce automaticamente il controllo figlio con lo stato attivo della finestra, quindi i controlli di modifica basati su Win32/WinForms WM_CHARclassici determinano il suolo del testo (generazione TextChanged). Avvertimento: Le app WinUI 3/UWP/XAML (destinazione primaria di winapp) dispongono di controlli senza finestra che ignorano i messaggi pubblicati, quindi WM_CHAR il testo letterale/WM_KEYDOWNné le chiavi denominate (Invio, cifre, ...) li raggiungono, anche se il comando segnala l'esito positivo. Genera un avviso quando la destinazione è simile a XAML e chiude ancora 0 (PostMessage è attiva e dimentica e non riesce a confermare il recapito). Usa --via send-input per guidare le app WinUI 3/UWP/macchine virtuali Windows; riservare post-message per i controlli Win32 classici o quando è necessaria solo l'ambito finestra tra i livelli di integrità.

Output JSON (--json): il risultato hwnd è la finestra effettiva a cui sono state recapitate le chiavi, perché --via post-message si tratta del controllo figlio con stato attivo risolto quando il comando viene retargetato (non necessariamente la finestra di primo livello-w/-a/-e), in modo che l'automazione possa confermare esattamente dove è atterrato l'input. Quando tale destinazione effettiva è simile a un host XAML senza finestra, anche l'avviso di recapito precedente viene visualizzato come voce warnings[] (lo stesso avviso visualizzato nella console), quindi un'uscita ✅ 0 non viene scambiata per il recapito confermato.

set-value

Impostare un valore su un elemento modificabile a livello di codice (nessuna sequenza di tasti, nessuna app in primo piano). Usa una catena di fallback:

  1. ValuePattern : TextBox, ComboBox, PasswordBox e la maggior parte dei controlli modificabili.
  2. RangeValuePattern : controlli numerici (Slider, ProgressBar) quando il valore viene analizzato come numero.
  3. LegacyIAccessible (IAccessible::put_accValue): il fallback per i controlli di modifica solo TextPattern che espongono nessun valorePattern (ad esempio, caselle rich-edit/ Document compose). In questo modo si chiude il gap di lettura/scrittura in cui get-value è possibile leggere un controllo di questo tipo, ma set-value non è stato possibile.
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

Se nessuno dei tre modelli può impostare il valore, set-value ha esito negativo con un errore chiaro che punta all'ultima send-keys risorsa.

Non tutti gli editor avanzati supportano set a livello di codice. Il fallback LegacyIAccessible funziona solo sui controlli la cui accessibilità implementa IAccessible::put_accValue , ovvero controlli di modifica avanzati Win32 nativi e le superfici di composizione Chromium/Electron/WebView2 in genere. WinUI 3 RichEditBox e macchine virtuali Windows RichTextBox non supportano l'impostazione di valori a livello di codice, esponendo il contenuto a Automazione interfaccia utente come di sola lettura (modello di testo, nessun modello valore impostabile), quindi set-value non può scriverli. Usa send-keys (che richiede un desktop in primo piano sbloccato) per quelli.

get-value

Leggere il valore corrente da un elemento . Usa una catena di fallback intelligente: TextPattern (RichEditBox, Document) → ValuePattern (TextBox, Slider) → SelectionPattern (ComboBox, RadioButton, TabView) → Name (etichette).

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": "..." }
winapp ui get-value SearchBox -a myapp --json
winapp ui wait-for SearchBox -a myapp --value "" --timeout 5000

Un campo di testo vuoto letto correttamente restituisce "text": "", non l'etichetta di accessibilità. Il contenuto solo spazi vuoti viene mantenuto anche in JSON. wait-for --value "" corrisponde a un campo vuoto, sia che sia stato aggiornato o cancellato dopo la modifica. Per leggere invece l'etichetta di accessibilità, usare get-property --property Name.

focus

winapp ui focus txt-textbox-a4b1 -a notepad

Attiva la finestra del controllo selezionato quando necessario, quindi concentra il controllo. Il selettore è obbligatorio; usare -a <app> o -w <HWND> per scegliere la destinazione. Operazione riuscita significa che la finestra è stata in primo piano e il controllo selezionato è stato confermato HasKeyboardFocus prima della restituzione del comando. Il comando consente fino a 500 ms per il controllo di segnalare lo stato attivo; si arresta se la destinazione scompare o perde il primo piano invece di tentare di riprendere lo stato attivo. Una finestra di dialogo di proprietà davanti alla finestra principale non è sufficiente: selezionare un controllo nella finestra di dialogo, se questa è la destinazione.

Questo comando richiede un desktop interattivo sbloccato e non ignora le restrizioni di attivazione Windows. Se ha esito negativo con foreground_not_target, attivare manualmente la finestra desiderata e verificare la presenza di una finestra di dialogo di blocco prima di riprovare. Per focus_not_acquired, esaminare l'interfaccia utente corrente e scegliere un controllo attivabile. Per stale_element, riscoprire la destinazione con inspect o search. Mantenere la stessa --on destinazione per l'individuazione e ripetere i comandi.

scorrimento nella visualizzazione

Scorrere un elemento nell'area visibile.

winapp ui scroll-into-view itm-targetitem-c3d4 -a myapp

wait-for

Attendere che un elemento venga visualizzato, scomparire o avere un valore raggiunto una destinazione.

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

scorrere

Scorrere un elemento contenitore. Trovare contenitori scorrevoli con search scroll : cercare [scroll:v] indicatori (verticali) o [scroll:h] (orizzontali).

# 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

Opzioni:

  • --direction <up|down|left|right> — Scorrere in modo incrementale tramite ScrollPattern.
  • --to <top|bottom> — Passare all'inizio/fine tramite ScrollPattern.
  • --wheel <notches> — Sintetizzare l'input della rotellina del mouse sul centro dell'elemento tramite SendInput, nelle tacche delle ruote (detents): 1 = una notch up/away, -1 = una notch giù/verso l'alto, 3 = tre tacche su. Ogni tacca è l'Windows WHEEL_DELTA di 120 unità che SendInput utilizza. L'interfaccia della riga di comando ridimensiona automaticamente le prestazioni di 120 unità. ScrollPatternIgnora .

--direction, --toe --wheel si escludono a vicenda : passano esattamente uno. Poiché --wheel inserisce l'input a livello di sistema operativo alle coordinate dello schermo, porta prima la destinazione in primo piano e non riesce (foreground_not_target) se non è stato possibile trasferire lo stato attivo, anziché scorrere la finestra errata.

ottenere l'attenzione

winapp ui get-focused -a myapp
winapp ui get-focused -w <HWND> --json

Mostra l'elemento con lo stato attivo della tastiera nell'app selezionata, inclusi i controlli la cui proprietà dell'app è disponibile solo tramite la finestra padre. Con -w, lo stato attivo deve appartenere a tale finestra, non a un'altra finestra o a un popup di proprietà nello stesso processo. Con -a, sono incluse altre finestre nel processo selezionato. L'output JSON ha hasFocus:false quando non è possibile verificare alcun elemento con stato attivo come appartenente alla destinazione. Se una query di stato attivo o di proprietà della finestra ha esito negativo, il comando esce da zero; riprovare get-focusede ritrovare la finestra con list-windows se è stata chiusa.

list-windows

Elencare tutte le finestre visibili per un'app, inclusi popup e finestre di dialogo. Per impostazione predefinita, le finestre senza titolo con dimensioni zero (finestre di sistema invisibili) vengono escluse.

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

rendimento

Rilasciare l'interfaccia utente del flusso di lavoro in anticipo anziché attendere la tolleranza di inattività di quattro secondi. Richiede WINAPP_UI_WORKFLOW_ID; non accetta alcuna app e nessun selettore. Vedi Rilascio anticipato del turno.

winapp ui yield
winapp ui yield --json          # {"released": true} — or false when nothing was held

Supporto del framework

Struttura Ispezionare search evocare set-value schermata
macchine virtuali Windows ✅ Albero completo ✅ Tutte le proprietà ✅ Tutti i modelli ✅ ¹ ✅
WinForms ✅ ✅ ✅ ✅ ✅
Win32 ✅ ✅ ✅ ✅ ✅
WinUI 3 ✅ ✅ ✅ ✅ ¹ ✅
Elettrone ⚠️ Albero chromium ⚠️ Limitato ⚠️ Varia ⚠️ Varia ✅
Flutter ⚠️ Basic ⚠️ Basic ❌ Minimo ❌ ✅

¹ set-value funziona su qualsiasi controllo che espone ValuePattern/RangeValuePattern, oltre ai controlli di modifica solo TextPattern i cui controlli di accessibilità implementano IAccessible::put_accValue (fallback LegacyIAccessible). WinUI 3 RichEditBox e macchine virtuali Windows RichTextBox sono eccezioni: espongono solo il modello Text di sola lettura (nessun modello valore impostabile), quindi non possono essere impostati a livello di codice per progettazione; usare send-keys (desktop interattivo necessario) per digitarli.

Uso del motore dal proprio codice

Tutto winapp ui ciò che è disponibile come libreria, quindi è possibile eseguire la stessa automazione da un test o uno strumento senza shell all'interfaccia della riga di comando:

Package Elementi aggiunti
Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation Ispezione, selettori, interazione con pattern UIA, inserimento di input, screenshot
Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation.Recording Registrazione video in MP4, più bundle di fotogrammi
var services = new ServiceCollection().AddLogging().AddWinAppUiAutomation().BuildServiceProvider();
var ui = services.GetRequiredService<IUiAutomation>();

var target = UiTarget.FromWindowHandle(myWindowHandle);
var save = await ui.FindSingleElementAsync(target, new UiSelector { Query = "Save" }, default);
await ui.InvokeAsync(target, save!, default);

Per le azioni deterministiche, usare l'overload che esegue UiInvokeAction:

var selected = await ui.FindSingleElementAsync(
    target, new UiSelector { Query = "Save" }, requireUnique: true, default);
if (selected is null) throw new InvalidOperationException("Save was not found.");
UiInvokeActionResult result = await ui.InvokeAsync(target, selected, UiInvokeAction.Invoke, default);

requireUnique: true rifiuta testo ambiguo anziché scegliere una corrispondenza richiamabile. Le corrispondenze di AutomationId esatte hanno la precedenza sui nomi o sulle sottostringhe AutomationId; un nome univoco può comunque selezionare un controllo il cui AutomationId è condiviso. Per una destinazione con ambito app, che controlla tutte le relative finestre di proprietà o app. Usare -w <HWND> (o una destinazione della libreria di finestre esplicita) per limitare l'ambito di selezione.

Restituisce Pattern e PerformedAction con gli stessi significati del risultato dell'azione dell'interfaccia della riga di comando. Passare un elemento restituito dall'ispezione o dalla selezione, con il relativo slug di runtime o automationId univoco intatto. Le azioni esplicite rifiutano un'identità mancante o ambigua anziché riassociare in base al nome e al tipo di controllo.

Per le letture con ambito, impostare su UiSelector.Root un altro UiSelector, ControlType su un nome di tipo e ClassName sulla classe del provider letterale. Questi usano gli stessi predicati di query dell'interfaccia della riga di comando. È supportato un solo livello radice: selector.Root.Root deve essere null. Una radice annidata genera un'eccezione ArgumentException prima di cercare la finestra di destinazione. Usare un automationId radice univoco o un slug anziché annidare i selettori radice. UiControlTypes.GetId(name) risolve i nomi ufficiali dei tipi e i due alias documentati, restituendo 0 un nome non valido. UiControlTypes.GetName(id) restituisce il nome canonico o Unknown(id) per un ID non riconosciuto.

Quando si passa un UiElement oggetto ripristinato da JSON a GetTextAsync o GetPropertiesAsync, mantenere il relativo Selector e WindowHandle. Un selettore di slug deve ancora identificare l'elemento originale; se non esiste più, queste letture generano un'eccezione UiElementNotFoundException anziché selezionare un altro elemento con lo stesso AutomationId o nome. Eseguire di nuovo la query originale per aggiornare il risultato. Le letture con ambito propagano anche errori dai getter generali della proprietà UIA e dai modelli dell'interfaccia utente acquisiti invece di restituire null o un valore acquisito in precedenza.

La registrazione è un pacchetto separato in modo che i progetti che controllano e guidano solo l'interfaccia utente non estraggono SkiaSharp. Il pacchetto di automazione è destinato sia net10.0-windows a che net10.0-windows10.0.19041.0a . Quest'ultimo aggiunge Windows Acquisizione grafica, che consente di screenshot acquisire windows occlusi o compositi con GPU. Vedere README di ogni pacchetto in NuGet per l'API completa e il compromesso del framework di destinazione.

UiTarget.FromWindowHandle è il punto di ingresso per i framework di test che già consentono di visualizzare una finestra, ad esempio MSTest.Windows.UIAutomation, il cui WindowTest.MainWindow oggetto è un uiA2 AutomationElement a cui si esegue il bridge con MainWindow.Current.NativeWindowHandle.

Risoluzione dei problemi

Error Motivo Soluzione
"Nessuna app in esecuzione trovata" App non in esecuzione o mancata corrispondenza del nome Controllare il nome del processo o usare PID
"Più finestre corrispondono" Valore ambiguo -a Usare -w <HWND> dalle opzioni elencate
"ha più finestre" Il processo ha più finestre Usare -w <HWND> per specificare come destinazione uno specifico
"Selector matched N elements" Selettore legacy ambiguo Usare i slug dall'output inspect o aggiungere [0], [1] ai selettori legacy
"L'elemento potrebbe essere stato modificato" L'hash slug non corrisponde all'elemento corrente inspect Eseguire nuovamente o search per ottenere nuovi slug
"non supporta alcun modello invoke" Non è possibile richiamare l'elemento Usare inspect sull'elemento per trovare un elemento figlio richiamabile
"Nessuna finestra dell'interfaccia utente trovata" L'interfaccia utente non può visualizzare il processo Usare list-windows per trovare HWND, quindi -w
"La finestra ha dimensioni zero" Finestra ridotta a icona L'app verrà ripristinata automaticamente
Popup/elenco a discesa non incluso nello screenshot L'acquisizione predefinita è per finestra e non include sovrimpressioni non acquisite Seguire il flusso di lavoro di sovrimpressione screenshot per selezionare una finestra con -w <hwnd> --capture-screen
foreground_not_target da --capture-screen Windows rifiutato l'attivazione, quindi un'acquisizione dello schermo avrebbe registrato qualsiasi finestra sia effettivamente davanti Fare clic sulla finestra di destinazione o chiudere la finestra di furto dello stato attivo e riprovare o rilasciare --capture-screen
element_not_found durante il record Selettore specificato ma nessun elemento corrispondente inspect Eseguire di nuovo o search per ottenere un selettore nuovo
WGC non disponibile durante il record L'acquisizione WGC non è riuscita; nessun fallback invisibile all'utente Controllare GPU/driver; usare --capture-screen per fornire il consenso all'acquisizione screen-DC

Modelli comuni

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

Trovare il testo e richiamarne l'elemento padre

# 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

Disambiguare elementi duplicati

winapp ui search '#Image' -a myapp; winapp ui invoke itm-image-a2b3 -a myapp

Screenshot con sovrimpressioni popup

winapp ui list-windows -a myapp # use the main window's HWND below
winapp ui set-value txt-searchbox-e5f6 "query" -a myapp; winapp ui screenshot -w <hwnd> --capture-screen
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

Individuare, fare clic e verificare

winapp ui inspect -a myapp --interactive; winapp ui invoke btn-submit-7a90 -a myapp; winapp ui screenshot -a myapp

Interazione del dialogo file

Le finestre di dialogo di apertura/salvataggio dei file sono finestre di dialogo standard Windows con supporto dell'interfaccia utente:

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

Usare inspect -w <dialog-hwnd> --interactive per individuare i slug effettivi per un dialogo specifico.

Perché ; per il concatenamento (non &&)

L'operatore di PowerShell può bloccarsi quando un'interfaccia della && riga di comando nativa scrive in stderr o usa sequenze di escape ANSI. Usare ; invece : esegue ogni comando in modo incondizionato ed evita questo deadlock. Questo è anche meglio per i flussi di lavoro dell'agente: in genere si vuole che lo screenshot venga eseguito anche se l'invoke ha una uscita diversa da zero.

Modelli di test CI

Usare i comandi winapp ui nelle pipeline CI (GitHub Actions, Azure DevOps) per i test di fumo e la convalida dell'interfaccia utente. wait-for con --property e --value funge da asserzione: restituisce il codice di uscita 1 al timeout, con esito negativo del passaggio CI automaticamente.

Avviare e testare in GitHub Actions

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

Stato dell'elemento Assert con wait-for

wait-for --value esegue il polling fino a quando il valore di un elemento corrisponde alla stringa prevista, usando lo stesso fallback intelligente di get-value (TextPattern → ValuePattern → SelectionPattern → Name). Restituisce il codice di uscita 0 alla corrispondenza, il codice di uscita 1 al timeout, rendendolo un'asserzione compatibile con l'integrazione continua. Usare --property invece per controllare una proprietà UIA specifica.

# 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

Asserzione con output JSON

Usare --json con PowerShell o jq per asserzioni più complesse:

Contratto di codice di uscita per search e wait-for in --json modalità: quando nessun elemento corrisponde (search) o il timeout di attesa (wait-for), il comando scrive una busta dei risultati completamente analizzabile in stdout ({ "matchCount": 0, ... } o { "found": false, "timedOut": true, ... }) e restituisce il codice di uscita 1. Stderr è vuoto in --json modalità (l'output del logger viene eliminato). Diramare i campi della busta, o su $LASTEXITCODE, a seconda del quale è più ergonomico.

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

# Read typed element state while preserving the legacy string property map
$property = winapp ui get-property "Counter Display" -a $pid --json | ConvertFrom-Json
if ($property.element.type -ne "Text") { throw "Unexpected type: $($property.element.type)" }
if ($property.element.isOffscreen) { throw "Counter is offscreen" }

Le buste JSON sono:

  • inspect: { "depth", "interactive", "hideDisabled", "hideOffscreen", "windows": [...] }
  • search: { "matchCount", "hasMore", "matches": [...] }
  • wait-for: { "found", "waitedMs", "element"?, "timedOut" }
  • get-property: { "elementId", "element", "properties": { ... } }

Gli elementi tipizzato usano type e numerici x, y, widthe height. La geometria è in pixel fisici dello schermo. 0,0,0,0è Automazione interfaccia utente rettangolo vuoto/senza visualizzazione dell'interfaccia utente in questa proiezione; isOffscreen è separato, quindi un elemento offscreen può comunque avere limiti diversi da zero.

Ogni inspect --jsonwindows[] voce e il status --json risultato includono windowDpi, scale (windowDpi / 96), dpiAwarenesse coordinateSpace: "physical-screen-pixels". Questi descrivono il contesto DPI della finestra di destinazione, non dpi di monitoraggio incondizionato: Windows segnala 96 per una finestra non consapevole, dpi di sistema per una finestra compatibile con il sistema e dpi di monitoraggio corrente per una finestra in grado di monitorare. Se non è possibile leggere il contesto HWND o DPI, il comando non riesce anziché sostituire automaticamente 96. Quando status risolve un processo prima che abbia una finestra di primo livello, hwnd è 0 e i campi DPI vengono omessi fino a quando non esiste una finestra. Per l'intero inspectprocesso, la finestra di destinazione selezionata rimane in ritardo. Se un popup successivo scompare dopo la lettura dell'albero, la voce windows[] contiene dpiError e omette i campi DPI mentre gli alberi delle finestre rimanenti vengono comunque restituiti.

Per esempi completi di ogni busta, vedi la competenza references/ui-json-envelope.md speditawinapp-ui-automation.

Esempio di test di fumo 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