Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Inspecionar e interagir com aplicações Windows em execução a partir da linha de comandos. Usado por agentes e programadores de IA para testes de interface, depuração e automação.
Descrição geral
winapp ui fornece comandos para inspecionar e interagir com Windows interfaces de aplicação.
Utiliza Windows Automatização da Interface de Utilizador (UIA). Funciona com qualquer aplicação Windows — WPF, WinForms, Win32, Electron e WinUI 3.
A maioria dos comandos conduz a aplicação através de padrões UIA (sem injeção de entrada). As exceções injetam input real: ui click/ui hover/ui dragusar simulação de rato,ui touch/ui pen sintetizar input tátil e caneta/stylus, e ui send-keys sintetizar input do teclado — para controlos e cenários que os padrões UIA não conseguem controlar.
Important
Exige um ambiente de trabalho interativo (verbos que injetam entrada).click, hover, drag, touch, pen, scroll --wheel, e send-keys --via send-input sintetizar entrada ao nível do sistema operativo, pelo que precisam de um ambiente de trabalho interativo desbloqueado com a janela de destino em primeiro plano. Numa estação de trabalho bloqueada ou num ambiente de trabalho seguro (LogonUI/UAC), não conseguem injetar e falham rapidamente no_interactive_desktop (diferente da elevação/foreground_not_target casos).
touch
/
pen adicionalmente, recusar quando nenhuma janela se resolve (no_target); uma coordenada fora da janela alvo é um aviso não fatal (uma warnings[] entrada em --json, ou uma linha de aviso em modo texto) e a injeção continua a prosseguir — consistente com os verbos do rato. Tudo o resto — inspect, search, get-propertyget-value, , wait-for, set-value, , invoke, , — scroll --direction/--to impulsiona a aplicação através de padrões UIA e é compatível com headless/sessões bloqueadas.
screenshot é a exceção entre os verbos não injetores: tem um turno exclusivo e a sua captura pode necessitar de um ambiente de trabalho interativo utilizável, porque o motor restaura um alvo minimizado e volta a colocá-lo em primeiro plano quando a captura de frames não está disponível ou --capture-screen é utilizada. Prefere os verbos do padrão UIA em CI; Reserve os verbos de injeção para cenários que realmente precisem de input real. Antes de injetar, os verbos gestuais também reresolvem o elemento alvo e recusam com target_moved se ainda estiver a animar/relocar-se, em vez de aterrar input no espaço vazio.
Início Rápido
Corre winapp ui --help para o ciclo principal: inspect -a <app> --interactive para ver sobre o que podes agir, invoke ou set-value para agir, e get-value para verificar o resultado. Cada comando --help mostra exemplos. Um comando desconhecido, como winapp ui dump, sai com código 1 e sugere os comandos mais próximos (como um erro JSON com suggestions quando 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
Execução de automação de UI no Windows Sandbox
Para evitar a automação do seu ambiente de trabalho, adicione --on sandbox aos comandos run e UI:
winapp run . --on sandbox --detach
winapp ui inspect --on sandbox -a MyApp
winapp ui invoke --on sandbox SubmitButton -a MyApp
--detach regressa após o lançamento; sem ele, run espera que a aplicação saia. Mantenha --on sandbox todos os comandos de convidado, incluindo aqueles que usam PID ou maçaneta de janela.
Consulte execução no Windows Sandbox para requisitos do cliente, breves alterações de foco de configuração/reconexão, coordenação de workflow e entrega de saída do host.
Consultas por âmbito e digitadas
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
Estes comandos aceitam filtros opcionais no seu seletor de elementos: inspect (com um seletor), search, get-property, wait-forget-value, invoke, set-value, , click, , focus, screenshotscrollpenhoverscroll-into-viewrecordtouche .
drag (dois selecionadores) E send-keys --target não.
O seletor e todos os filtros fornecidos devem corresponder ao mesmo elemento. Os filtros estreitam um seletor, por isso inspect, , e record, cujo seletor é opcional, falham quando invalid_arguments dados filtros screenshotsem um. Para touch e pen, os filtros precisam de um seletor; não podem ser combinados com --at ou --path (invalid_arguments):
-
--root <selector>procura apenas descendentes de uma raiz que corresponde de forma única, nunca a raiz em si. Use um AutomationId ou slug deinspectpara desambiguar. Uma raiz que corresponde a múltiplos elementos falha comambiguous_selector, mesmo que uma correspondência seja invocável. Uma raiz em falta não produz correspondências. Uma vez encontrada a raiz, as consultas não procuram janelas pop-up não relacionadas, mesmo quando nenhum descendente corresponde. As consultas não são limitadas pelainspectprofundidade de exibição de . -
--type <control-type>corresponde a um tipo de controlo UIA, ignorando o caso. Os únicos pseudónimos sãoTextBox→EditeTextBlock→Text. Nomes desconhecidos (incluindo IDs numéricos e expressões wildcard) falham cominvalid_arguments. -
--class-name <literal>corresponde a toda a UIAClassNamedo fornecedor, ignorando o caso. Não é uma substringa, imprevisível ou expressão regular. Useget-property --property ClassNamepara descobrir o valor do fornecedor; o nome da classe não precisa de ser igual ao tipo de controlo UIA.
Consultas filtradas utilizam a Vista de Controlo da UIA, a mesma vista mostrada por inspect.
Os nós provedores expostos apenas na Vista Bruta não são devolvidos; use inspect para encontrar o controlo contendo e o seu seletor.
Todos os 41 tipos oficiais são suportados: Button, Calendar, ComboBoxCheckBox, Edit, Hyperlink, Image, ListItem, ListTitleBarSpinnerSliderTabStatusBarThumbGroupDataGridCustomTreeItemTreeDataItemToolTipToolBarTextDocumentTabItemScrollBarSplitButtonHeaderItemHeaderTablePaneSeparatorSemanticZoomMenuMenuItemAppBarMenuBarProgressBarRadioButtonWindowe todos os 411 são suportados: , 411,
wait-for resolve novamente o seletor de raiz em cada sondagem, de modo que a raiz pode aparecer após o início do comando. Com --gone, uma raiz ausente significa que não existe descendente correspondente; uma raiz ambígua é um erro, não um sucesso.
Uma consulta interrompida não é prova de desaparecimento: se um elemento for removido durante a consulta ou substituído antes de uma --value leitura, a próxima consulta verifica novamente; outros erros de consulta ou leitura falham o comando.
-w <HWND> restringe a descoberta de raiz à árvore UIA dessa janela. Com , a -adescoberta de raiz também pode encontrar as janelas pop-up da aplicação. As correspondências raiz exatas do AutomationId têm precedência sobre as correspondências de substrings em todas essas janelas; múltiplas correspondências exatas continuam a falhar com ambiguous_selector.
Um slug raiz seleciona esse elemento mesmo quando outra janela tem o mesmo AutomationId. Se a raiz selecionada for substituída, o seu slug antigo já não corresponde; use um AutomationId ou raiz de nome quando quiser que o polling siga um substituto.
Quando há filtros presentes, todos os comandos, exceto search falham se ambiguous_selector restar mais do que um elemento; estreitar os filtros ou usar um slug único. Comandos que atuam sobre a contagem de elementos correspondem em todas as janelas que pesquisam, por isso um controlo correspondente num diálogo próprio também torna o seletor ambíguo. As correspondências Exatas do AutomationId mantêm precedência sobre as correspondências de substrings, dentro do âmbito filtrado. Omitir as três opções preserva o comportamento de consulta existente.
Coordenação de fluxos de trabalho simultâneos de UI
O Windows tem apenas uma janela em primeiro plano, um foco no teclado, um cursor e um fluxo de entrada. Quando dois winapp ui fluxos de trabalho correm simultaneamente no mesmo ambiente de trabalho com sessão iniciada, podem roubar o foco um do outro, desligar um menu que o outro acabou de abrir ou mover um alvo para fora de um clique pendente.
A arbitragem está sempre ativa. Cada winapp ui comando que toca no ambiente de trabalho físico tem o seu turno, sem configuração nem forma de o desligar, por isso dois agentes nunca conseguem digitar nas janelas um do outro. Comandos de apenas leitura continuam a correr em simultâneo. A única exceção é um processo que não consegue aceder à pasta de coordenação do winapp, como um sandbox de agentes que bloqueia %USERPROFILE%\.winapp: os seus comandos continuam a correr, mas sem se revezar, e imprime um aviso (exceto com --json ou --quiet).
A continuidade entre comandos é opcional. Por defeito, cada comando é um one-shot autónomo: espera a sua vez, faz o seu trabalho e liberta imediatamente o ambiente de trabalho. Para manter o ambiente de trabalho em vários comandos, dê-lhes a todos o mesmo id de workflow:
# Set once per logical UI workflow
$env:WINAPP_UI_WORKFLOW_ID = [guid]::NewGuid().ToString()
O que precisa de saber:
- Um id de workflow nomeia um fluxo lógico — não necessariamente um agente inteiro, nem necessariamente uma aplicação. Use o mesmo valor para comandos de cooperação (uma gravação mais os cliques que deve capturar); Use valores diferentes para fluxos de trabalho independentes, mesmo quando um agente lança ambos.
- Sem identificação, cada comando é um one-shot independente. Ainda arbitra, mas não guarda margem e entrega o ambiente de trabalho assim que termina. Dois comandos no-id são fluxos de trabalho separados mesmo quando lançados a partir do mesmo shell.
- Hospedeiros de casca fresca e adaptativos devem injetar o mesmo valor. Se cada comando correr numa nova shell — que é como funciona a maioria das chamadas de ferramentas de agente — a única coisa que pode agrupá-las é uma passagem explícita
WINAPP_UI_WORKFLOW_IDpara cada chamada cooperante. - A gração de quatro segundos protege explosões apertadas, não o raciocínio do modelo. Um fluxo de trabalho com id mantém a sua vez desde que o próximo comando comece dentro de quatro segundos. Isso cobre comandos consecutivos num script; expira intencionalmente enquanto o modelo está a pensar. É um recurso de recurso para quando não podes dizer que terminaste — quando podes, foge
winapp ui yieldem vez de esperar que passe. - Os fluxos de trabalho adaptativos devem readquirir, revalidar e reproduzir. Depois de uma pausa de raciocínio, outro fluxo de trabalho pode ter usado o ambiente de trabalho, por isso reabre o menu, resolve novamente o elemento e depois age. Envia sequências conhecidas de ponta a ponta como um único script apertado em vez de segurares o ambiente de trabalho enquanto pensas.
- A encomenda é primeiro afinidade com o proprietário, depois FIFO, entre as outras. Enquanto um fluxo de trabalho está ativo ou dentro do seu alcance, pode continuar a emitir comandos, mesmo que outros fluxos de trabalho já estejam à espera. Uma vez que esta é executada
winapp ui yieldou a sua autorização de graça expira, os fluxos de trabalho de espera são servidos por ordem de chegada rigorosa. A atividade contínua de um fluxo de trabalho pode, portanto, atrasar outros indefinidamente. - Não existe um limite rígido. Um script longo, uma gravação ilimitada ou um loop de falha podem bloquear outros fluxos de trabalho mutantes.
-
O cancelamento ou terminação de processos é a recuperação de um fluxo de trabalho ativo bloqueado. Comandos em espera imprimem um estado após um segundo e podem ser parados com
Ctrl+C, que sai130. - Só cooperam binários atualizados compatíveis. As versões mais antigas
winappsão anteriores a esta funcionalidade e não são coordenadas. O código que chama diretamente os pacotes NuGet da Automatização da Interface de Utilizador está totalmente fora desta garantia — a coordenação está na linha de controlo, não nos pacotes.
Quais comandos esperam por um turno:
| Behavior | Commands |
|---|---|
| Corre em simultâneo (nunca espera) |
status, list-windows, inspect, search, get-property, get-value, get-focused, wait-for |
| Espera pela curva, mas nunca toma o ambiente de trabalho |
set-value, scroll-into-view, scroll --direction/--to, record |
| Espera pela curva e fica com o ambiente de trabalho exclusivamente |
invoke, click, hoverdrag, , scroll --wheel, , send-keyspenfocustouchscreenshot |
A fila do meio é a que vale a pena compreender.
set-value, scroll-into-view e--toscroll --direction/conduzem padrões UIA em vez do primeiro plano, para que se mantenham amigáveis para headless/sessões bloqueadas e nunca bloqueiem ninguém de usar o ambiente de trabalho. Mas mudam o que a aplicação mostra, por isso esperam na vez de outro fluxo de trabalho em vez de editar um campo ou deslocar uma lista debaixo do clique de outra pessoa.
Dentro de um fluxo de trabalho, sobrepõem-se a outros trabalhos partilhados — é assim que um record captura as set-value chamadas que está a gravar. Eles não ignoram a barreira direta do seu próprio fluxo de trabalho: um comando anterior DesktopExclusive do mesmo fluxo de trabalho (a click, a screenshot) ainda os bloqueia, exatamente como bloqueia todos os comandos posteriores, por isso um clique e a mutação que o segue mantêm-se na ordem em que os escreveste.
screenshot Está sempre em fila para um turno exclusivo. Nem todas as capturas perturbam o ambiente de trabalho — uma janela visível comum captada através do Windows Graphics Capture não o faz — mas o motor restaura o alvo se este for minimizado, e volta a colocá-lo em primeiro plano quando a captura de frames não está disponível ou --capture-screen lê o ecrã em direto. Essas necessidades só aparecem quando a captura está em andamento, por isso o comando faz a curva à frente em vez de adivinhar. Quando compõe várias janelas, captura-as todas num único turno exclusivo, por isso a imagem guardada é um momento consistente em vez de uma mistura de antes e depois. A codificação e escrita do ficheiro acontecem depois de o ambiente de trabalho ser libertado.
--capture-screenPrecisa exatamente de uma janela. A captura de ecrã ao vivo grava tudo o que está realmente à frente, e só uma janela pode estar. Selecionar uma janela explicitamente com-w <hwnd>dá-lhe exatamente uma região — os píxeis dentro dos limites dessa janela, incluindo qualquer diálogo ou sobreposição visível por cima, que é a razão para ler o ecrã em primeiro lugar. Quando-acorresponde a várias janelas de topo ou propriedade não há essa seleção, por isso o comando falhainvalid_argumentsantes de capturar qualquer coisa em vez de lutar contra o primeiro plano. Executawinapp ui list-windows -a <app>e tenta novamente com-w <hwnd>, ou desliga--capture-screenpara compor cada janela a partir do seu próprio conteúdo.
record partilha a sua vez, por isso a entrada do mesmo fluxo de trabalho pode intercalar-se com a captura — é assim que se grava um fluxo de trabalho que gere uma aplicação. Duas ressalvas:
- Um
recordA sem ID de workflow é um dono de one-shot, por isso bloqueia todos os outros workflows durante toda a sua duração. Para gravar e clicar ao mesmo tempo, dê a ambos os comandos iguaisWINAPP_UI_WORKFLOW_ID. - Num host sem suporte para captura de frames, a gravação recorre ao PrintWindow, cuja recuperação de frames em branco pode colocar a janela em primeiro plano a qualquer momento. Lá, o ambiente de trabalho é mantido durante toda a gravação e o comando indica isso na sua saída; mesmo a entrada com o mesmo fluxo de trabalho espera.
Erros que pode ver: invalid_ui_workflow_id (a variável está definida mas vazia ou com mais de 256 caracteres), desktop_coordination_unavailable (o estado de coordenação é ilegível e não pode ser reconstruído em segurança, ou foi escrito por um mais winapprecente ), queue_capacity_exceeded (64 comandos de outros fluxos de trabalho já estão à espera — o limite conta empregados estrangeiros ativos, não processos que iniciaste, por isso entradas pertencentes a comandos que saíram ou foram desativados não ocupam um slot, e os comandos do teu próprio fluxo de trabalho ficam em fila uns atrás dos outros em vez de contra esse limite), ui_turn_busy (yield enquanto o teu próprio fluxo de trabalho ainda tem um comando a correr), e cancelled (Ctrl+C enquanto esperas, código 130de saída ).
Libertar o turno mais cedo: winapp ui yield
A gração de quatro segundos é um plano B: mantém o ambiente de trabalho reservado quando não se pode afirmar com certeza que terminou. Quando puderes dizê-lo, diz-o — yield entrega imediatamente o ambiente de trabalho em vez de fazeres os outros esperarem por uma gentileza que ninguém precisa.
$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
- Comandos one-shot não devem definir um ID de workflow de todo. Sem uma, cada comando já liberta o ambiente de trabalho assim que termina, e não há nada para ceder.
- Os fluxos de trabalho em múltiplos passos devem dar resultado quando terminarem, especialmente quando outros fluxos de trabalho podem estar à espera. Custa um comando rápido e remove um atraso de quatro segundos a todos os outros.
- É idempotente. Ceder duas vezes, ou depois de a graça já ter expirado, tem sucesso e reporta
{ "released": false }— esse é o fim normal de um guião, não um fracasso. - Nunca liberta a vez de outro fluxo de trabalho. Se outra pessoa segura o ambiente de trabalho, ou ninguém segura, é um no-op.
-
Falha se
ui_turn_busyo teu próprio fluxo de trabalho ainda tiver um comando a correr ou em fila — uma gravação, por exemplo. Libertar por baixo disso devolveria o ambiente de trabalho a meio do comando, por isso nada é libertado e o comando em execução não é afetado. Espera ou para, depois volta a ceder. - Requer
WINAPP_UI_WORKFLOW_ID. Sem uma, falha cominvalid_arguments. - Não aceita aplicação nem seletor: devolve uma reserva, não uma janela, por isso continua a funcionar depois de a aplicação fechar.
Um comando em espera é ativado por quem liberta o ambiente de trabalho em vez de por uma sondagem, por isso uma fila custa quase nada enquanto espera e a transferência é imediata. Cada empregado também verifica de vez em quando por si próprio, o que recupera o ambiente de trabalho quando um processo é encerrado e nunca publica nada: o comando no topo da fila olha a cada meio segundo e os comandos atrás dele — que não podem ser executados antes da cabeça — de poucos em poucos segundos.
Aplicações de Segmentação
Por nome do 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
Algumas aplicações empacotadas (por exemplo, Calculadora) não têm janela própria; outro processo hospeda o seu frame. Quando o processo emparelhado (por nome ou PID) não tem janela visível, -a usa o frame que aloja o seu conteúdo em vez disso. Se não houver nenhuma (por exemplo, a aplicação ainda está a começar), -a direciona o processo, por isso wait-for continua a procurar até aparecer a sua janela.
Por título da janela
winapp ui inspect -a "LICENSE - Notepad"
winapp ui inspect -a "Fix WinApp" # partial title match
Por PID
winapp ui inspect -a 12345
Por HWND (estável — sobrevive a alterações de tab/título)
# Discover HWNDs
winapp ui list-windows -a Terminal
→ HWND 985238: "🤖 Testing" (WindowsTerminal, PID 21228)
→ HWND 131906: "Fix WinApp" (WindowsTerminal, PID 21228)
# Target specific window
winapp ui inspect -w 131906
winapp ui screenshot -w 131906
Usar -a para descoberta, -w para direcionamento estável. Quando -a corresponde a várias janelas, o comando lista-as com HWNDs para escolheres.
Selecionadores
Elementos-alvo usando o seletor mostrado [brackets] na saída de inspecção/pesquisa.
Existem três tipos de selecionadores:
| Selector | Significado | Example |
|---|---|---|
MinimizeButton |
AutomationId (mostrado quando único — estável, preferencial) | winapp ui invoke MinimizeButton -a myapp |
btn-close-d1a0 |
Slug semântico (mostrado quando não existe um Automation Id único) | winapp ui invoke btn-close-d1a0 -a myapp |
Submit |
Pesquisa em texto simples contra Name/AutomationId (substring insensível a maiúsculas minúsculas) | winapp ui invoke Submit -a myapp |
Os seletores AutomationId são identificadores de conjunto de programadores (AutomationProperties.AutomationId em XAML).
Quando um AutomationId é único em toda a árvore da interface e inspectsearch o mostra diretamente como seletor — estes sobrevivem a alterações de layout, localização e reestruturação da árvore.
Os seletores de slug (por exemplo, btn-close-d1a0) são gerados quando não existe um AutomationId único.
Formato: prefix-name-hash. O hash valida a identidade do elemento, mas pode ficar obsoleto após alterações na interface.
Inspeção do formato de saída
O inspect comando mostra a árvore de elementos com saída colorida (seletor em ciano, nome em verde, metadados em cinzento):
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
A primeira palavra em cada linha é o seletor — usa-o com outros ui comandos.
Quando um elemento tem um AutomationID único, é usado diretamente (por exemplo, TabView, NewTabButton).
Quando não existe um AutomationId único, é usado um slug gerado (por exemplo, tab-newtab-5f5b).
Slugs semânticos
As lesmas usam o formato: prefix-normalizedname-hash onde:
- Prefixo — Abreviatura de tipo de 3 letras (BTN, TXT, CHK, CMB, ITM, TAB, IMG, LBL, PN, WIN, GRP, LNK, MNU, ETC.)
- normalizedname — alfanumérico minúsculo de AutomationId (preferido) ou Name, máximo 15 caracteres
- hash — hash hexadecimal de 4 caracteres do RuntimeId do elemento (valida a identidade do elemento)
As lesmas são seguras contra conchas (sem caracteres especiais), únicas e podem ser usadas diretamente como argumentos. Sem filtros de consulta, o hash fornece deteção de estagnação — se o elemento foi substituído, obtém: "O elemento pode ter mudado. Reexecute inspect." Para consultas filtradas, veja Consultas com escopo e digitadas.
Elementos sem nome ou AutomationId mostram apenas prefixo + hash (por exemplo, pn-c8a3).
Desambiguação de múltiplos combates
Os slugs da inspect/search saída são únicos, mas podem mudar por alterações de layout – use-os em vez de nomes de tipos simples ou texto quando há múltiplas correspondências. Quando um seletor é ambíguo, o CLI imprime todas as correspondências com os seus slugs para que possas escolher o certo e voltar a executar com esse 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
Pesquisa de texto simples
Use texto simples para procurar elementos — sem necessidade de sintaxe especial:
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 uma pesquisa de texto corresponde a vários elementos (por exemplo, SettingsExpander onde Group, Button e Text partilham o mesmo nome), a CLI escolhe automaticamente o único elemento invocável. Se vários forem invocáveis, lista todas as correspondências com slugs.
Para resultados de pesquisa não invocáveis (por exemplo, um TextBlock dentro de um Botão), a pesquisa revela automaticamente o ancestral invocável mais próximo — o elemento pai que pode usar com invoke.
Isto funciona para todos os seletores de pesquisa:
lbl-savechanges-a1b2 "Save changes" (120,40 80x20)
^ invoke via: btn-save-c3d4 "Save"
O seletor de superfície pode ser usado diretamente:
winapp ui invoke btn-save-c3d4 -a myapp # invoke the parent Button
Commands
estado
Liga-te a uma aplicação e mostra as informações de ligação.
winapp ui status -a notepad
winapp ui status -a notepad --json
inspecionar
Veja a árvore de elementos da interface. A saída mostra slugs semânticos com indentação de 2 espacios para hierarquia:
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
Exemplo de saída (padrão):
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)
Exemplo de saída (--interactive — apenas elementos acionáveis, lista plana):
btn-minimize-d1a0 "Minimize" (1222,206 48x48)
btn-maximize-e2b1 "Maximize" (1270,206 48x48)
btn-close-d1a2 "Close" (1318,206 48x48)
itm-home-7b3e "Home" (102,268 72x62)
itm-samples-3f2c "Samples" (102,330 72x62)
itm-models-9a4f "Models" (102,392 72x62)
Os elementos podem mostrar estes marcadores de estado:
-
[on]/[off]/[indeterminate]— estado toggle/checkbox -
[collapsed]/[expanded]— expandir/colapsar o estado para árvores, caixas de combo, itens do menu -
[scroll:v]/[scroll:h]/[scroll:vh]— contentor rolável (vertical, horizontal ou ambos) -
[offscreen]— elemento não é visível no ecrã -
[disabled]— elemento não está ativado -
value="..."— conteúdo textual atual para elementos editáveis (quando diferente do Nome)
pesquisa
Encontre elementos que correspondam a um seletor. A saída mostra slugs semânticos:
winapp ui search Button -a notepad # all buttons
winapp ui search Close -a notepad # finds elements with "Close" in name
winapp ui search SearchBox -a notepad # finds elements with "SearchBox" in name or AutomationId
winapp ui search Button --max 10 -a notepad # limit results
Exemplo de saída:
btn-minimize-d1a0 "Minimize" (1222,206 48x48)
btn-maximize-e2b1 "Maximize" (1270,206 48x48)
btn-close-d1a2 "Close" (1318,206 48x48)
Slugs mostrados na saída (por exemplo, btn-minimize-d1a0) podem ser usados diretamente com outros comandos:
winapp ui invoke btn-minimize-d1a0 -a notepad
get-property
Leia os valores das propriedades a partir de um elemento. Inclui o estado específico do padrão (ToggleState, Value, IsSelected, etc.).
winapp ui get-property btn-submit-7a90 -a myapp # all properties
winapp ui get-property chk-checkbox-b2c3 -p ToggleState -a myapp # checkbox state
winapp ui get-property txt-textbox-a4b1 -p Value -a myapp # current text value
winapp ui get-property cmb-combobox-d5e6 -p ExpandCollapseState -a myapp # expanded or collapsed
winapp ui get-property Document -p FontWeight -a myapp --json # document formatting
Os nomes das propriedades são sensíveis às maiúsculas e minúsculas. Um nome desconhecido falha com invalid_arguments under --json; omite --property a lista das propriedades, incluindo os seis atributos de formatação do texto abaixo.
wait-for --property utiliza os mesmos nomes com sensibilidade a maiúsculas minúsculas e rejeita nomes desconhecidos antes da sondagem.
Formatação de texto de documento inteiro
A formatação é lida em todo o documento TextPattern do elemento, não na sua seleção ou cuidado atual. As leituras não alteram o foco nem a seleção.
| Property | Valor uniforme (devolvido como uma cadeia) |
|---|---|
FontWeight |
Peso numérico, como "400" (normal) ou "700" (negrito) |
FontName |
Nome da família fonte, como "Courier New" |
FontSize |
Tamanho em pontos, tais como "15.5" |
ForegroundColor |
Windows Decimal COLORREF (0x00BBGGRR), como para "3678732" RGB(12, 34, 56) |
IsItalic |
"True" ou "False" |
StrikethroughStyle |
Estilo de decoração de texto UIA numérica, como "0" (nenhum) ou "1" (simples) |
Os números usam formatação invariante (um ponto decimal, independentemente da sua localização). Cada atributo pode, em vez disso, devolver:
| Valor | Significado e próximo passo |
|---|---|
"Mixed" |
A formatação varia dentro do documento. Não o trate como um valor uniforme; este comando não consulta intervalos de texto individuais. |
"NotSupported" |
O fornecedor TextPattern do documento não reporta este atributo. Verifique o suporte de acessibilidade da aplicação. |
"Unavailable" |
O elemento não tem TextPattern. Use inspect ou search encontre o seu elemento de texto/documento. |
Ao listar todas as propriedades, as propriedades básicas em cache permanecem disponíveis se nenhum elemento vivo puder ser resolvido, e um valor de formatação mal formado for omitido sem descartar outras propriedades. Estas omissões são registadas como avisos. Solicite uma propriedade de formatação específica para obter um erro em vez de uma omissão.
Falhas do fornecedor continuam a ser erros, não "Unavailable". Para stale_element, inspecione novamente a aplicação e tente novamente com um seletor atual.
O envelope JSON inclui elementId, um tipo elementdigitado , e um valor propertiesem cadeia de caracteres .
As propriedades existentes, incluindo BoundingRectangle, mantêm os seus formatos.
Por exemplo, a parte de formatação é properties :
{
"FontWeight": "700"
}
captura de ecrã
Captura uma janela ou elemento como 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)
Sem um seletor de elementos, a captura por defeito combina várias janelas numa só PNG composta rotulada lado a lado, não em ficheiros separados.
-a por nome de processo ou PID inclui as janelas da aplicação e as janelas próprias da aplicação. Uma correspondência baseada -a em título seleciona uma janela correspondente mais as janelas próprias; -w seleciona explicitamente uma janela mais as janelas próprias, não todas as janelas no processo. Um diálogo ou tooltip próprio pode, portanto, aparecer como um painel próprio mesmo quando seleciona explicitamente o HWND principal. Um seletor de elementos corta para esse elemento em vez de compor janelas. Um elemento num menu, flyout, tooltip ou dica de ensino que abre numa janela popup própria é cortado a partir desse popup, não da janela atrás dele.
--quiet suprime a saída informativa tanto para capturas de janela única como compostas, incluindo o caminho guardado. Os avisos e os diagnósticos de captura e falha permanecem visíveis. Usa-o --json em vez disso quando precisares do caminho do ficheiro e das dimensões como saída estruturada.
Com , --output nomeia --on sandboxo destino anfitrião. Saída simples bem-sucedida e --json reporte esse caminho do host após a entrega da imagem.
O caminho de captura predefinido usa o Windows. Graphics.Capture (WGC), que lê a superfície composta por DWM — preservando cantos arredondados, transparência e funcionando mesmo quando a janela está ocluída por outros windows. Se o WGC não estiver disponível (versões antigas do Windows), a CLI volta ao PrintWindow.
Usa --capture-screen -w <hwnd> quando precisares de pop-ups visíveis ou tooltips nas suas posições no ecrã, incluindo sobreposições que não pertencem à janela alvo. Lê a região do ecrã dessa janela em vez de compor painéis rotulados, e traz a janela para o primeiro plano. Com , requer exatamente uma janela correspondente; se várias janelas de nível superior ou próprias coincidirem -a, use winapp ui list-windows -a <app> e tente novamente com -w <hwnd>. Use --focus se quiser apenas colocar a janela em primeiro plano sem mudar de modo de captura (por exemplo, para garantir que a captura de ecrã corresponde ao que o utilizador está a ver no momento).
Porque a DC do ecrã capta o que está realmente à frente,
--capture-screenverifica que o alvo chegou ao primeiro plano imediatamente antes de capturar e falhaforeground_not_targetse não o fez (prevenção de roubo de foco, um prompt UAC ou outra janela a ativar-se). Nesse caso, nenhuma imagem é escrita — anteriormente o comando saía do 0 e devolvia uma imagem da janela errada.ui record --capture-screenAplica o mesmo teste antes do primeiro frame.
registo
Grave uma janela ou região de elemento num MP4 H.264. Prefiro um positivo --duration-sec para guiões não assistidos. Sem duração, a gravação continua até Ctrl+C ou, para stdin redirecionado, uma nova linha ou EOF. O npm uiRecord e targetRecord os auxiliares requerem um inteiro durationSec de 1 a 86400; o seu sinal de aborto cancela forçadamente em vez de finalizar a gravação de forma elegante.
# 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
Opções:
-
--duration-sec N— Recorde por N segundos. Por defeito 0 registos até ser parado. -
--fps N— Frames-alvo por segundo (por defeito 15). -
--max-edge N— Reduza a escala para que a aresta mais longa seja, no máximo, N píxeis (0 = sem redução de escala). -
--capture-screen— Captura a partir do DC do ecrã (inclui sobreposições/popups; em primeiro plano a janela). -
--output <path>— Caminho de saída MP4. O valor padrão érecording-<timestamp>-<guid>.mp4. -
--overwrite— Substituir as gravações existentes após o término da nova tomada. Sem isso, as saídas existentes são rejeitadas. -
--frames— Escrever provas JPEG com carimbo temporal para<output-name>.frames. Suporta 1-30 fps e--max-edge64-4096 (por defeito 1280). Os dados de frames são limitados a 1 GiB; o MP4 continua se atingir o limite.
Artefactos de frames legíveis por agente:
evidence.mp4
evidence.frames/
manifest.json
frames.ndjson
frames/
frame-000000-t000000000012.jpg
frames.ndjson tem uma linha por amostra com sampleIndex, monótona elapsedMs, MP4-relativa mediaTimeMs, imageIndex, file, e changed. Amostras consecutivas idênticas a píxeis reutilizam o JPEG de qualidade 85 anterior.
manifest.json regista o pedido, o tempo, o estado do MP4, as dimensões da imagem e o estado (complete, partial, ou truncated). A temporização truncada cobre o prefixo mantido, enquanto video descreve o MP4 completo.
Escolha um novo caminho de saída, a menos que pretenda substituir uma gravação por --overwrite.
Sem ele, ou um vídeo existente ou o seu diretório emparelhado .frames bloqueia a gravação, mesmo quando se omite --frames.
O MP4 anterior mantém-se intacto se a nova captura falhar. Após substituição bem-sucedida, o diretório de frames anterior é mantido como <output-name>.frames.previous-<id>, mesmo que a nova gravação omita --frames. Preserve provas parciais e siga o relato recoveryHint antes de rejulgar. Se a finalização do MP4 falhar, os frames preservados podem ser publicados sob <output-name>.frames.partial-*. Artefactos de frames contêm conteúdo de ecrã não encriptado; Trate-os como capturas de ecrã ou vídeo.
Com --on sandbox, tanto o MP4 como o diretório de frames são entregues ao host, incluindo as saídas padrão quando --output é omitido. Veja captura Sandbox para gravações interrompidas e captura de todo o ambiente de trabalho.
Modos de captura (reportados no campo JSON mode ):
-
wgc— Windows Graphics Capture (por defeito; funciona enquanto a janela está ocluída). -
printwindow— GDI PrintWindow (reserva quando o WGC não está disponível neste sistema/sessão; reexecute para--capture-screenusar DC de ecrã em vez disso). -
screen— Screen DC via--capture-screen(inclui sobreposições/popups; traz a janela para o primeiro plano).
Saída JSON (--json):
-
Conclusão: Resultado final da gravação, incluindo cadência, razão de paragem, opcional
frameArtifactse avisos. -
Stderr: Um objeto JSON por linha: um
recording-startedevento após a primeira fotograma, seguido de um erro caso a gravação posterior falhe. Os caminhos de trama são incluídos apenas quando a saída de trama está ativa.
Códigos de erro:
-
element_not_found— O selecionador não correspondeu. -
ambiguous_selector— O seletor correspondia a múltiplos elementos; Usa um projétil sugerido. -
invalid_arguments— O valor de uma opção é inválido. -
output_exists— Já existe uma saída de gravação e não pode ser substituída nas opções solicitadas. -
frame_output_failed— Nenhum dos artefactos pôde ser preservado após a falha da saída do frame. -
partial_output— Apenas um artefacto concluído; inspecionarpartialOutputerecoveryHint.
Um seletor de elementos regista a região desse elemento a partir da janela onde é desenhado. Para um item num menu, flyout, tooltip ou dica de ensino que abre numa janela pop-up própria, a gravação mostra o popup em vez da janela atrás dele.
invocar
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
Usar --action quando um teste tem de realizar uma operação específica exatamente no elemento selecionado. Nunca tenta outro padrão ou um ancestral invocável, mesmo que a ação solicitada falhe. Um controlo que suporte tanto a invocação como a seleção será selecionado, não invocado, com --action select. Com , um slug tem como alvo exatamente um elemento; um seletor de texto simples ou AutomationId que corresponde a mais do que um elemento falha fechado com um código de saída diferente de zero em vez de agir na primeira correspondência, pelo que passa --actionum slug quando inspect/search um nome é ambíguo.
--root, --type, e --class-name restringir a correspondência conforme descrito em consultas com escopo e tipadas, com ou sem --action.
Use -w <dialog-HWND> para restringir uma ação a esse diálogo, ou -a <app> para incluir as janelas da aplicação. Uma invocação filtrada confirma o alvo único antes de agir, requer exatamente um elemento correspondente e nunca muda para outra janela ou um ancestral invocável. Zero correspondências falham com element_not_found; duplicados falham com ambiguous_selector. Um elemento velho ou uma janela reciclada falha sem agir; reexecute inspect ou search escolha um seletor atual.
Sem --action, uma invocação filtrada ainda tenta os padrões por ordem nesse elemento.
| Action | Operation |
|---|---|
invoke |
InvokePattern.Invoke |
select |
SelectionItemPattern.Select |
toggle |
TogglePattern.Toggle, exatamente uma vez |
toggle-on / toggle-off |
ler o ToggleState; ter sucesso sem alterar um estado já correto, caso contrário alternar e verificar |
expand / collapse |
ExpandirPadrãoDeCollapse.Expandir / Colapsar |
Para toggle-on e toggle-off, um estado inicial Indeterminate permite no máximo duas transições, verificando o estado após cada uma. Outros estados iniciais permitem uma transição. Se o estado solicitado não for atingido, o comando falha em vez de continuar a alternar. Uma verificação falhada pode alterar o controlo; lê ToggleState antes de decidir o que fazer a seguir.
Sem --action e sem filtros, o comportamento automático mantém-se inalterado: experimente InvokePattern, TogglePattern, SelectionItemPattern, depois ExpandCollapsePattern (expandir), com uma retentativa do ancestral invocável quando necessário.
Uma ação não suportada falha com um código de saída não nulo e, com --json, um erro estruturado em stderr. Inspecionar o controlo selecionado e escolher uma ação que ele suporte, ou direcionar explicitamente o pai pretendido. Sucesso JSON inclui requestedAction e performedAction; veja a referência JSON.
clicar
Clica num elemento nas coordenadas do ecrã usando simulação de rato. Use isto para controlos que não suportam InvokePattern (por exemplo, cabeçalhos de colunas, itens de lista).
winapp ui click btn-column1-a3f2 -a myapp # single click by slug
winapp ui click "Column1" -a myapp # single click by text search
winapp ui click btn-column1-a3f2 -a myapp --double # double-click
winapp ui click btn-column1-a3f2 -a myapp --right # right-click
Tal como os outros verbos de injeção de input,
clicktraz o alvo para o primeiro plano e falha rapidamente (no_interactive_desktopnum ambiente de trabalho bloqueado/seguro,foreground_not_targetse o foco não puder ser transferido) em vez de clicar na janela errada. Também resolve novamente o elemento mesmo antes do botão para baixo: depois de posicionar o cursor, faz uma última verificação de posição, de modo que um alvo em movimento/animação contínua falha emtarget_movedvez de reportar sucesso após o clique ter aterrado num espaço vazio — um sucesso reportado significa que o alvo ainda estava no lugar quando o botão desceu.
arrastar
Pressiona o botão do rato num ponto, move para outro, depois larga com drag <from> <to>, onde cada extremidade é ou um seletor de elementos (arrasta de/para o centro do elemento) ou coordenadas x,ydo ecrã exatamente conforme reportado por winapp ui inspect. Misture livremente (seletor→seletor, seletor→coordenadas, coordenadas→coordenadas).
Usa SendInput com movimentos intermédios para que a aplicação veja um fluxo realista de WM_MOUSEMOVE mensagens. Usa-o para reordenar/redimensionar alças, sliders, desenho em tela e arrastar e largar.
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
Opções:
-
--right— Arraste com o botão direito do rato em vez do botão esquerdo. -
--hold-ms <ms>— Mantenha o botão pressionado no início antes de se mover (por defeito: 0). Com<from> == <to>(sem movimento), isto executa um gesto de pressionar e manter / pressionar longamente . -
--dwell-ms <ms>— Permanecer no destino após a mudança, antes de libertar (padrão: 0). Vamos deixar cair alvos / sobreposições de fusão que o braço a partir de um hover prolongado (em vez do instante em que o cursor chega) se fecha antes do botão de botão.
Estão nuas
x,ycoordenadas de ecrã no mesmo relatório de espaçowinapp ui inspect/search, e um seletor resolve para o centro do elemento — inspecionar primeiro para escolher os pontos.
Por exemplo
send-keys --via send-input,draginjeta o sistema operativo em coordenadas do ecrã depois de trazer o alvo para o primeiro plano. Se o foco não puder ser direcionado para o alvo (por exemplo, prevenção de roubo de foco num processo em segundo plano), o comando falha (foreground_not_target) em vez de arrastar na janela errada — foca ou clica primeiro na janela. Num ambiente de trabalho bloqueado/seguro, falha comno_interactive_desktop. Cada ponto final do elemento é reresolvido imediatamente antes do arrasto; Se ainda estiver a mover-se/redimensionar (um alvo a animar), o comando falha emtarget_movedvez de arrastar para um ponto estagnado. (Os endpoints nusx,ynão podem ser verificados novamente, por isso são usados as-is.)
Tocar
Injetar gestos táteis sintéticos usando a API de injeção de ponteiros do Windows. A âncora de contacto é ou um seletor de elementos (usa o centro do elemento) ou uma coordenada x,yde ecrã explícita via --at (mesmos relatórios de espaçowinapp ui inspect). Use-o para interações de toque/pressão e gestos multi-touch que a simulação do rato não consegue expressar.
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)
Opções:
-
--gesture <g>—tap(padrão),double-tap,long-pressswipe,pinch, ,stretch. -
--at <x,y>— Ponto de início explícito (coordenadas do ecrã). Por defeito, o centro do elemento do seletor. -
--to-point <x,y>— Ponto final para umswipe. Tem precedência sobre--direction. -
--direction <right|left|up|down>— Direção do deslize (padrão:right). Combinado com--distancepara calcular o ponto final quando--to-pointnão é dado. -
--distance <px>— Dedo aberto parapinch/stretch, ou distância de deslizamento em píxeis. -
--hold-ms <ms>— Manter os contactos pressionados antes de levantar (tempo de espera por pressão longa; por defeito é 500 ms quandolong-pressnão está definido). -
--duration-ms <ms>— Tempo de deslize para gestos de movimento (deslizar/beliscar/esticar; padrão 300). -
--fingers <n>— Número de contactos (1–10; padrão 1).pinch/stretchUsa sempre 2.
Segurança da injeção.
touchrecusa-se a injetar a menos que um handle de janela alvo diferente de zero seja resolvido e essa janela mantenha o primeiro plano — falha quandono_targetnenhuma janela pode ser resolvida,foreground_not_targetse o foco não puder ser transferido, ouno_interactive_desktopnum ambiente de trabalho bloqueado/seguro. Todas as coordenadas (centro do elemento, pontos de passagem explícitos--at/--to-pointe gerados) são verificadas contra o retângulo da janela alvo; um ponto fora da janela é apresentado como um aviso não fatal (umawarnings[]entrada em--json, ou uma linha de aviso em modo texto) e a injeção continua a prosseguir — correspondendo aos verbos do rato (click/drag/hover/scroll), que também injetam em coordenadas fora da janela.--fingersacima de 10 é rejeitado de imediato.Nota de hardware. O Touch prefere o dispositivo moderno de ponteiro sintético (
CreateSyntheticPointerDevice(PT_TOUCH)) e recorre à API legadaInitializeTouchInjection/InjectTouchInput. Se a injeção não for suportada no dispositivo/sessão atual, o comando revela o código de erro Win32 real (por exemplo, "não suportado") em vez de reportar um falso sucesso — trate uma saída não nula como "toque não entregue".Ambiente de Trabalho Remoto / sessões de VM. Numa Ambiente de Trabalho Remoto (RDP) ou em algumas sessões de VM, o sistema operativo pode aceitar toque sintético (saída 0) sem que este chegue realmente à aplicação de destino. Quando uma sessão remota é detetada,
touchacrescenta um aviso de incerteza na entrega — umawarnings[]entrada em--json, ou uma linha de aviso em modo texto. Um /exit 0 significa então que a ✅ de injeção foi bem-sucedida, não que a aplicação tenha recebido a entrada; confirme o efeito quandoui screenshot/ui inspectfor relevante.
pen
Injetar entrada sintética de caneta/caneta — toques e traços de tinta — usando a API sintética do Windows (CreateSyntheticPointerDevice(PT_PEN); Windows 10 1809+). Aponte para um centro de elemento, um ponto explícito --at ou uma pincelada completa --path de tinta.
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
Opções:
-
--at <x,y>— Ponto de contacto da caneta (coordenadas do ecrã). Por defeito, o centro do elemento do seletor. Ignorado quando--pathé dado. -
--path "<x,y x,y …>"— Caminho do traço de tinta como pares separadosx,ypor espaços em branco (um caminho de um ponto é uma toque). -
--pressure <0.0–1.0>— Pressão da caneta (padrão 0,5). -
--tilt-x <deg>/--tilt-y <deg>— Ângulos de inclinação da caneta, −90 a 90 (padrão 0). -
--eraser— Use a extremidade da borracha da caneta em vez da ponta. -
--duration-ms <ms>— Tempo total de percurso do traço em milissegundos distribuídos como frames UPDATE interpolados ao longo do caminho (padrão: ~10 ms por ponto de passagem). Use isto para controlar a velocidade com que a caneta se move visivelmente do início ao fim.
Segurança da injeção. Por exemplo
touch,penrecusa-se a injetar sem uma janela alvo não nula, em primeiro plano (no_target/foreground_not_target/no_interactive_desktop) e verifica cada ponto de tinta contra o retângulo da janela alvo, destacando qualquer coordenada fora da janela como um aviso não fatal (warnings[]em--json, ou uma linha de aviso em modo texto) enquanto ainda injeta — consistente com os verbos do rato. Inválidos--pressure(fora 0,0–1,0) ou inclinados (fora ±90°) são rejeitados à partida.Ambiente de Trabalho Remoto / sessões de VM. O encaminhamento da caneta é especialmente pouco fiável no Ambiente de Trabalho Remoto: a chamada de injeção pode reportar sucesso (saída 0) enquanto nenhuma entrada da caneta chega à aplicação. Quando uma sessão remota é detetada,
penadiciona um aviso de incerteza na entrega (warnings[]em--json, ou uma linha de aviso em modo texto) para que a ✅ não seja confundido com a entrega confirmada. Valide fluxos dependentes da caneta num ambiente de trabalho local e interativo.
pairar
Move o rato para o centro de um elemento para ativar efeitos de hover (dicas de ferramentas, flyouts, estados visuais). Usa SendInput para movimento realista do rato com um pequeno movimento, depois espera por um tempo de permanência configurável.
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
Opções:
-
--dwell-time <ms>— Tempo em milissegundos de espera após o passar o rato para que os efeitos apareçam (padrão: 800, alcance: 0–10000)
chaves de envio
Enviar entrada de teclado sintético — o equivalente do teclado a click. A UIA não tem padrão de injeção de teclado, por isso isto desce para a camada Win32. Use-o para navegação no teclado (setas, Tab, Enter, Esc), atalhos (ctrl+c, alt+f4), e para digitar em controlos que necessitem de eventos por tecla em vez de set-valueescrita atómica de '.
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
Gramática de chaves (tokens separados por espaços em branco, citação de cadeias multi-token):
-
Chaves nomeadas —
enter/return,tab,esc/escapespace,backspace,delete/del,insert, ,home,end,pageup/pgup, ,pagedown/pgdnup/down/left/rightf1, –f16,apps,printscreen, , .capslock -
Sequências — múltiplas fichas são pressionadas por ordem:
down down enter. -
Combinações de modificadores —
ctrl,shift,alt,winunidas a+:ctrl+shift+t,alt+f4. Um token que começa com um modificador mas tem um segmento desconhecido antes do último (ctrl+a+b) é um erro; usetext=ou--verbatimpara escrever. -
Comandos de leitor de ecrã — manter pressionado
capslockouinsert(aliasins), as teclas Narrador, NVDA e JAWS:ctrl+capslock+f12alternam o modo de programador Narrador. Requer--via send-input, porque os leitores de ecrã não recebem as chaves publicadas. Se não houver leitor de ecrã a funcionar, manter pressionadocapslocko botão Caps Lock liga ou desliga e o comando avisa; mantém pressionadoinsertpara evitar isto. -
Texto literal — qualquer token que não seja uma chave conhecida é digitado carácter a caractere:
hello. Palavras literais adjacentes mantêm o espaço entre elas, por isso uma frase citada como"Hello world"é digitada literalmente (o espaço é preservado); um literal que apenas contém+tal comoC++oua+bé digitado como texto, não analisado como um combo. -
Escape literal explícito — prefixa um token com
text=para o digitar literalmente mesmo quando colide com uma chave ou nome modificador:text=enterescreve a palavra "enter" em vez de pressionar Enter, etext=ctrl+adigita a cadeia literal. Espelha avk=fuga; o valor escapado ainda se junta a palavras literais adjacentes (text=down low→ "em baixo"). Como os tokens são divididos em espaços brancos (e os literais adjacentes voltam-se a juntar com um único espaço), use escapes de barra inversa dentro de umtext=valor para escrever espaço em branco que de outra forma não sobreviveria:\sespaço →,\t→ tabulação,\n→ linha nova,\r→ linha nova,\\→ barra diagonal literal.\n,\r, e\r\ncada um insere uma única quebra de linha (um Enter /VK_RETURN), etext=line1\nline2text=line1\r\nline2ambos escrevem uma nova linha. Assim,text=a\s\sbescreve "a b" (espaçamento duplo) etext=\shimantém um espaço à frente. Uma fuga não reconhecida (por exemplo,\x) é deixada literalmente. -
Literal de argumento inteiro (
--verbatim) — quando toda a carga útil é texto literal, passe--verbatimem vez de escapar de cada token comtext=. Tipa todo o argumento das chaves exatamente como dado — sem interpretação de chave/combovk=/text=nomeado — e, ao contrário do caminho normal, preserva o espaço em branco interno exato (sem colapso) sem precisar\sde . Portanto,send-keys "down down enter" --verbatimdigita as palavras esend-keys "a b" --verbatimmantém o espaçamento duplo. As escapadas com barra inversa não são decodificadas no--verbatimmodo (a\sé digitado como barra inversa e um "s"); use umtext=token quando precisar de um carácter de controlo escapado. -
Chaves virtuais brutas —
vk=0xNN(hexadecimal) ouvk=NN(decimal) para chaves sem nome amigo.
Opções:
-
--target <selector>— Foca este elemento (via UIA) antes de enviar as chaves. Sem ele, as chaves vão para o elemento focado da aplicação no momento. -
--verbatim— Digitar todo o argumento das chaves como texto literal (sem chave/combo/vk=/text=análise sintática) e preservar o espaço em branco exato. A forma de argumento inteiro da fuga por fichatext=. -
--via <transport>—post-message(por defeito) publicaWM_KEYDOWN/WM_KEYUP/WM_CHARna fila da janela de destino. É direcionado para HWND e contorna o UIPI (funciona entre níveis de integridade).send-inputinjeta todo o sistema operativo viaSendInpute vai para a janela em primeiro plano.
Escolher um transporte / limites conhecidos:
-
post-messageé o padrão porque contorna o UIPI e não depende da janela estar em primeiro plano. Limites: não pode ativar atalhos globais registados atravésWH_KEYBOARD_LLde hooks de baixo nível (aqueles que tocam a entrada a montante de qualquer fila de janela), e as aplicações que leem o estado bruto da chave podemGetAsyncKeyStatenão observar modificadores retidos. Resolve automaticamente e publica na janela filha focada do thread de destino (viaGetGUIThreadInfo) após o primeiro plano, por isso as aplicações clássicas do Win32/WinForms cujos controlos são janelas filhas separadas recebem chaves sem direcionar manualmente o controlo. As aplicações WinUI 3 / UWP têm controlos XAML sem janelas e sem HWND filho, por isso um postWM_CHAR/WM_KEYDOWNnão tem nada para aterrar e é descartado — post-message não os consegue controlar (o comando avisa e fecha 0); use--via send-input. (As janelas WPF são single-HWND e encaminham as chaves para o elemento interno focado, por isso o pós-mensagem funciona aí.) -
send-inputproduz entrada totalmente real (modificadores visíveis paraGetAsyncKeyState, dispara ganchos de baixo nível) mas vai para a janela que está em primeiro plano e é bloqueada pelo UIPI ao injetar de um processo elevado para um alvo de menor integridade (AppContainer/AppX). Sesend-inputreportar uma falha, é provável que o alvo seja elevado ou uma aplicação do AppX — usepost-message, ou execute a CLI com um nível de integridade correspondente. Como guarda de segurança,send-inputverifica se a janela-alvo está realmente em primeiro plano imediatamente antes de injetar e falha (foreground_not_target) em vez de digitar na janela errada se não puder ser direcionado para ela — focar ou clicar na janela primeiro. Num ambiente de trabalho bloqueado ou seguro , falha antes comno_interactive_desktop(não existe janela de primeiro plano para injetar) — desbloquear a sessão, ou usar um verbo em padrão UIA (set-value,invoke). -
Combos reservados por sistema (
win+l,win+r,ctrl+shift+esc,ctrl+alt+del,alt+tab,alt+f4,ctrl+esc, , lonewin/printscreen, ...) atuam sobre o sistema operativo/shell e não apenas no alvo quando enviados para todo o sistema operativo.send-inputrejeita-os por defeito (erros cominvalid_argumentse não envia nada) porque injetá-los ao nível do sistema operativo tem efeitos muito além da janela de destino (por exemplo,win+lbloqueia a sessão). Passe--allow-system-keyspara optar — isto permite-te controlar um atalho global como o dowin+shift+vPowerToys ouwin+r(o gancho global de baixo nível observa o fluxo de entrada em todo o sistema operativo, por isso o combo injetado dispara-o). Exceções que permanecem bloqueadas mesmo com--allow-system-keys:win+lbloqueiam a estação de trabalho, o queLockWorkStation()é irrecuperável da automação (quebra CI e sessões de ambiente de trabalho remoto), ectrl+alt+delé uma Sequência de Atenção Segura (SAS) que o Windows elimina de entrada injetada independentemente da flag — nunca pode ter efeito, por isso gera erros (invalid_arguments, exit 1) em vez de reportar um sucesso enganoso. Outros combos (alt+f4,ctrl+shift+esc,win+r, ...) passam a ser permitidos com a bandeira — atenção, chamador. Em alternativa, para entregar um combo de sistema a uma janela específica usa--via post-message, que é com escopo de janela e não é afetado (um postwin+lé inofensivo, embora um postalt+f4ainda feche a janela alvo).
Eventos por tecla (KeyDown / TextChanged):
-
Combinações de chaves nomeadas e modificadores (
down,enter,ctrl+shift+t,vk=0xNN) disparam um realKeyDown(eKeyUp) em ambos os transportes — são entregues como eventos discretosWM_KEYDOWN/WM_KEYUP(ouSendInputde chave virtual). -
O texto literalmente digitado (
hello) difere consoante o transporte:-
--via send-inputmapeia cada carácter para a sua tecla virtual (mais Shift) no layout do teclado ativo, de modo que o alvo vê uma tecla genuínaKeyDowncom a tecla virtual correta seguida da tecla compostaWM_CHARpelo sistema operativo (elevaçãoTextChanged) — ou seja, uma tecla completa por carácter. Caracteres que não são acessíveis no layout atual (ou que precisam de Ctrl/AltGr) voltam para um pacote Unicode, por isso o carácter exato ainda aparece. Usesend-inputquando precisar de fidelidade por teclaKeyDown(por exemplo, ao conduzir um WinUI 3 / WPFTextBoxcujos handlers desligamKeyDownas teclas ). Para um host de teste do WinUI 3 normal (não elevado), traz a janela dela para o primeiro plano (winapp ui focus/ clicando), poissend-inputo alvo é a janela em primeiro plano. -
--via post-messagepublica um únicoWM_CHARpor carácter ( não publicaWM_KEYDOWN/WM_KEYUPpara texto digitado — esses são reservados para chaves/combos nomeados), o que não aumenta um texto por caractereKeyDown. Ele redireciona automaticamente para o controlo filho focado da janela, por isso os clássicos controlos de edição baseados no Win32/WinFormsWM_CHARaterram o texto (elevandoTextChanged). Aviso: As aplicações WinUI 3 / UWP / XAML (o alvo principal do winapp) têm controlos sem janelas que ignoram o que foi publicadoWM_CHAR/WM_KEYDOWN— por isso , nem texto literal nem teclas nomeadas (Enter, dígitos, ...) lhes chegam, mesmo que o comando reporte sucesso. Emite um aviso quando o alvo parece XAML e continua a sair do 0 (PostMessageé disparar e esquecer e não consegue confirmar a entrega). Usa--via send-inputpara controlar aplicações WinUI 3 / UWP / WPF; reservapost-messagepara controlos clássicos do Win32 ou quando só precisas de ter um escopo de janela entre níveis de integridade.
-
Saída JSON (--json): o resultado hwnd é a janela efetiva para onde as chaves foram entregues — pois --via post-message esta é o controlo filho focado resolvido quando o comando redireciona para ela (não necessariamente para a janela de nível superior-w/-a/-e), para que a automação possa confirmar exatamente onde a entrada caiu. Quando esse alvo efetivo parece um host XAML sem janelas, a ressalva de entrega acima também aparece como uma warnings[] entrada (o mesmo aviso mostrado na consola), para que uma ✅ saída 0 não seja confundida com uma entrega confirmada.
valor de conjunto
Define um valor num elemento editável programaticamente (sem pressionar teclas, sem primeiro plano da aplicação). Utiliza uma cadeia de recurso:
- ValuePattern — TextBox, ComboBox, PasswordBox e a maioria dos controlos editáveis.
- RangeValuePattern — controlos numéricos (Slider, ProgressBar) quando o valor é analisado como um número.
-
LegacyIAccessible (
IAccessible::put_accValue) — o recurso de recurso para controlos de edição exclusivos do TextPattern que não expõem nenhum ValuePattern (por exemplo, caixas de edição rica /Documentcomposição). Isto fecha a lacuna leitura/escrita ondeget-valuepoderia ler tal controlo masset-valuenão podia.
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 nenhum dos três padrões conseguir definir o valor, set-value falha com um erro claro apontado para send-keys como último recurso.
Nem todos os editores ricos suportam conjuntos programáticos. O LegacyIAccessible funciona apenas em controlos cujas implementações de acessibilidade
IAccessible::put_accValue— os controlos nativos Win32 de edição rica e as superfícies de composição Chromium/Electron/WebView2 normalmente o fazem. O WinUI 3RichEditBoxe o WPFRichTextBoxnão suportam definição de valor programática — por design, expõem o seu conteúdo ao Automatização da Interface de Utilizador como apenas leitura (padrão de texto, sem padrão de valor definible), por issoset-valuenão podem escrever neles. Usesend-keys(que precisa de um ambiente de trabalho desbloqueado e em primeiro plano) para esses.
get-value
Leia o valor atual de um elemento. Utiliza uma cadeia de recurso inteligente: TextPattern (RichEditBox, Document) → ValuePattern (TextBox, Slider) → SelectionPattern (ComboBox, RadioButton, TabView) → Nome (etiquetas).
winapp ui get-value doc-texteditor-53ad -a notepad # read full document text
winapp ui get-value SearchBox -a myapp # read TextBox content
winapp ui get-value CmbTheme -a myapp # read ComboBox selected item
winapp ui get-value sld-volume-b2c3 -a myapp # read Slider value
winapp ui get-value lbl-title-a1b2 -a myapp --json # JSON: { "elementId": "...", "text": "..." }
winapp ui get-value SearchBox -a myapp --json
winapp ui wait-for SearchBox -a myapp --value "" --timeout 5000
Um campo de texto vazio lido com sucesso devolve "text": "", não o seu rótulo de acessibilidade. O conteúdo exclusivo de espaços em branco também é preservado em JSON.
wait-for --value "" Corresponde a um campo vazio, seja fresco ou apagado após edição. Para ler o rótulo de acessibilidade, use get-property --property Name.
focus
winapp ui focus txt-textbox-a4b1 -a notepad
Ativa a janela do controlo selecionado quando necessário e depois foca o controlo.
O seletor é obrigatório; usar -a <app> ou -w <HWND> para escolher o alvo.
O sucesso significa que essa janela estava em primeiro plano e o controlo selecionado confirmado HasKeyboardFocus antes do comando regressar. O comando permite até 500 ms para o controlo reportar o foco; para se o alvo desaparecer ou perder o primeiro plano, em vez de tentar recuperar o foco. Um diálogo próprio em frente à janela principal não chega: seleciona um controlo no diálogo se esse for o teu alvo.
Este comando necessita de um ambiente de trabalho interativo e desbloqueado e não contorna as restrições de ativação do Windows. Se falhar com foreground_not_target, ativa manualmente a janela pretendida e verifica se há um diálogo de bloqueio antes de tentar novamente.
Para focus_not_acquired, inspecione a interface atual e escolha um controlo com foco.
Para stale_element, redescubra o alvo com inspect ou search.
Mantém o mesmo --on alvo nos comandos de descoberta e de retentar.
rolar para a vista
Desloca um elemento para a área visível.
winapp ui scroll-into-view itm-targetitem-c3d4 -a myapp
espera-por
Espere que um elemento apareça, desapareça ou que um valor alcance um alvo.
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
Pergaminho
Desloca um elemento de contentor. Encontre recipientes roláveis com search scroll — procure [scroll:v] marcadores (verticais) ou [scroll:h] (horizontais).
# 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
Opções:
-
--direction <up|down|left|right>— Deslocar incrementalmente viaScrollPattern. -
--to <top|bottom>— Saltar para o início/fim viaScrollPattern. -
--wheel <notches>— Sintetizar a entrada da roda do rato sobre o centro do elemento viaSendInput, em entalhes da roda (detenções):1= um entalhe para cima/para longe,-1= um entalhe para baixo/para cima,3= três entalhes para cima. (Cada entalhe é o WindowsWHEEL_DELTAde 120 unidades queSendInputconsome; a CLI escala os entalhes em 120 para ti.) BypassScrollPattern.
--direction,--to, e--wheelsão mutuamente exclusivos — passam exatamente um. Como--wheelinjeta input em todo o sistema operativo nas coordenadas do ecrã, traz o alvo primeiro para o primeiro plano e falha (foreground_not_target) se o foco não puder ser transferido, em vez de deslocar a janela errada.
Foca-te
winapp ui get-focused -a myapp
winapp ui get-focused -w <HWND> --json
Mostre o elemento que atualmente tem foco no teclado na aplicação selecionada, incluindo os controlos cuja propriedade da aplicação está disponível apenas através da janela principal.
Com , o -wfoco deve pertencer a essa janela, não a outra janela ou a um pop-up próprio no mesmo processo. Com -a, outras janelas no processo selecionado estão incluídas.
A saída JSON ocorre hasFocus:false quando nenhum elemento focado pode ser verificado como pertencente ao alvo. Se uma consulta de foco ou propriedade de janela falhar, o comando sai diferente de zero; retente get-focused, e redescubra a janela com list-windows se estiver fechada.
janelas de lista
Liste todas as janelas visíveis de uma aplicação, incluindo pop-ups e diálogos. Por defeito, janelas sem título com tamanho zero (janelas invisíveis do sistema) são excluídas.
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
Liberte a atualização da interface deste fluxo de trabalho mais cedo em vez de esperar o fim da graça de inatividade de quatro segundos. Requer WINAPP_UI_WORKFLOW_ID; não aceita aplicação nem seletor. Veja Libertar o turno mais cedo.
winapp ui yield
winapp ui yield --json # {"released": true} — or false when nothing was held
Suporte ao Quadro
| Framework | inspecionar | pesquisa | invocar | valor de conjunto | captura de ecrã |
|---|---|---|---|---|---|
| WPF | ✅ Árvore completa | ✅ Todas as propriedades | ✅ Todos os padrões | ✅ ¹ | ✅ |
| WinForms | ✅ | ✅ | ✅ | ✅ | ✅ |
| Win32 | ✅ | ✅ | ✅ | ✅ | ✅ |
| WinUI 3 | ✅ | ✅ | ✅ | ✅ ¹ | ✅ |
| Elétron | ⚠️ Árvore de crómio | ⚠️ Limitado | ⚠️ Varia | ⚠️ Varia | ✅ |
| Flutter | ⚠️ Básico | ⚠️ Básico | ❌ Minimal | ❌ | ✅ |
¹ set-value trabalha em qualquer controlo que exponha ValuePattern/RangeValuePattern, além de controlos de edição apenas TextPattern cuja acessibilidade implementa IAccessible::put_accValue (LegacyIAccessible fallback).
O WinUI 3 RichEditBox e o WPF RichTextBox são exceções — expõem apenas o padrão de Texto de leitura (sem padrão de Valor definido), por isso não podem ser definidos programaticamente por design; use send-keys (é necessário ambiente de trabalho interativo) para digitar neles.
Usar o motor do teu próprio código
Tudo winapp ui o que faz está disponível como biblioteca, por isso podes gerir a mesma automação a partir de um teste ou ferramenta sem teres de pagar à linha de comando:
| Package | O que acrescenta |
|---|---|
Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation |
Inspeção, seletores, interação com padrões UIA, injeção de entrada, capturas de ecrã |
Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation.Recording |
Gravação de vídeo para MP4, além de pacotes de frames |
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);
Para ações determinísticas, use a sobrecarga que toma 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 rejeita texto ambíguo em vez de escolher uma correspondência invocável. Correspondências exatas de AutomationId têm precedência sobre nomes ou substrings AutomationId; um nome único ainda pode selecionar um controlo cujo AutomationId é partilhado.
Para um alvo com escopo de app, essa verificação cobre todas as suas janelas de app/propriedade. Use -w <HWND> (ou um alvo explícito de biblioteca de janela) para restringir o âmbito de seleção.
Ele retorna Pattern e PerformedAction com os mesmos significados do resultado da ação CLI.
Passar um elemento devolvido por inspeção ou seleção, mantendo o seu slug em tempo de execução ou AutomationId único intacto. As ações explícitas rejeitam uma identidade em falta ou ambígua, em vez de serem reagrupadas por nome e tipo de controlo.
Para leituras com escopo, defina UiSelector.Root para outro UiSelector, ControlType para um nome de tipo, e ClassName para a classe literal de fornecedor. Estes usam os mesmos predicados de consulta que a CLI. Apenas um nível raiz é suportado: selector.Root.Root deve ser null. Uma raiz aninhada lança ArgumentException antes de olhar para a janela do alvo. Use um AutomationId ou slug raiz único em vez de aninhar seletores de raize.
UiControlTypes.GetId(name) resolve nomes de tipo oficiais e os dois pseudónimos documentados, retornando 0 para um nome inválido.
UiControlTypes.GetName(id) retorna o nome canónico, ou Unknown(id) para um ID não reconhecido.
Ao passar um UiElement restaurado de JSON para GetTextAsync ou GetPropertiesAsync, mantém o seu Selector e WindowHandle. Um seletor de slug deve ainda identificar o elemento original; se este já não existir, estas leituras lançam UiElementNotFoundException em vez de selecionar outro elemento com o mesmo AutomationId ou nome. Execute novamente a consulta original para atualizar o resultado. As leituras com âmbito também propagam falhas provenientes de obtentores de propriedades UIA gerais e padrões UIA adquiridos, em vez de devolverem valor nulo ou um valor previamente capturado.
A gravação é um pacote separado para que projetos que apenas inspecionam e controlam a interface não puxem o SkiaSharp. O pacote de automação visa tanto net10.0-windows como net10.0-windows10.0.19041.0; este último adiciona o Windows Graphics Capture, que permite screenshot capturar janelas ocluídas ou compostas por GPU. Consulte o README de cada pacote no NuGet para a API completa e o compromisso entre o alvo-framework.
UiTarget.FromWindowHandle é o ponto de entrada para frameworks de teste que já lhe dão uma janela — por exemplo MSTest.Windows.UIAutomation, cujo WindowTest.MainWindow UIA2 AutomationElement se cruza com MainWindow.Current.NativeWindowHandle.
Troubleshooting
| Erro | Motivo | Solution |
|---|---|---|
| "Nenhuma aplicação de corrida encontrada" | A aplicação não está a correr ou não corresponde com nomes | Verifique o nome do processo ou use o PID |
| "Múltiplas janelas coincidem" | Valor ambíguo -a |
Utilização -w <HWND> a partir das opções listadas |
| "tem várias janelas" | O processo tem múltiplas janelas | Usar -w <HWND> para atingir um específico |
| "Seletor correspondeu a N elementos" | Seletor legado ambíguo | Use slugs da inspect saída, ou adicione [0], [1] aos seletores legados |
| "O elemento pode ter mudado" | O slug hash não corresponde ao elemento atual | Repetir inspect ou search comprar bales frescas |
| "não suporta qualquer padrão de invocação" | Elemento não pode ser invocado | Use inspect no elemento para encontrar uma criança invocável |
| "Nenhuma janela UIA encontrada" | A UIA não consegue ver o processo | Use list-windows para encontrar o HWND, então -w |
| "Janela tem tamanho zero" | A janela é minimizada | A aplicação será restaurada automaticamente |
| Popup/menu suspenso que não aparece na captura de ecrã | A captura por defeito é por janela e não inclui sobreposições não proprietárias | Siga o fluxo de trabalho de sobreposição de capturas de ecrã para selecionar uma janela com -w <hwnd> --capture-screen |
foreground_not_target de --capture-screen |
O Windows recusou a ativação, por isso uma captura de ecrã teria registado a janela que está realmente à frente | Clica na janela do alvo ou fecha a janela que rouba o foco e tenta novamente, ou larga --capture-screen |
element_not_found Durante a gravação |
Selecionador dado mas sem elemento correspondente | Repetir inspect ou search obter um seletor novo |
| WGC indisponível durante a gravação | A captura do WGC falhou; sem recuo silencioso | Verifica GPU/driver; usar --capture-screen para consentir na captura de ecrã-DC |
Padrões comuns
Navegue e verifique
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
Encontre texto e invoque o seu pai
# Search shows invokable ancestor; invoke auto-walks to it
winapp ui invoke 'Save changes' -a myapp
# Or search first to see what matches, then invoke
winapp ui search "Save changes" -a myapp; winapp ui invoke btn-save-c3d4 -a myapp
Desambiguar elementos duplicados
winapp ui search '#Image' -a myapp; winapp ui invoke itm-image-a2b3 -a myapp
Captura de ecrã com sobreposições pop-up
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
Navegar, esperar e verificar (single chain)
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
Descobre, clique e verifique
winapp ui inspect -a myapp --interactive; winapp ui invoke btn-submit-7a90 -a myapp; winapp ui screenshot -a myapp
Interação de diálogo de ficheiros
Os diálogos de abertura/gravação de ficheiros são diálogos padrão do Windows com suporte a UIA:
# Trigger the dialog, find it, type the path, confirm
winapp ui invoke btn-openfilebtn-a2b3 -a myapp
winapp ui list-windows -a myapp # find dialog HWND
winapp ui set-value txt-1148-c4d5 "C:\path\to\file.png" -w <dialog-hwnd>
winapp ui invoke btn-open-e6f7 -w <dialog-hwnd>
Use inspect -w <dialog-hwnd> --interactive para identificar as lesmas reais para uma conversa específica.
Porquê ; para encadear (não &&)
O operador do && PowerShell pode congelar quando uma CLI nativa escreve para stderr ou usa sequências de escape ANSI. Use ; em vez disso — executa cada comando incondicionalmente e evita este bloqueio. Isto também é melhor para fluxos de trabalho de agentes: normalmente queres que a captura de ecrã seja executada mesmo que o invoke tenha tido uma saída diferente de zero.
Padrões de Teste de IC
Use comandos winapp ui em pipelines CI (GitHub Actions, Azure DevOps) para testes de fumo e validação da interface.
wait-for com --property e --value atua como uma asserção — devolve o código de saída 1 no timeout, falhando automaticamente o passo CI.
Iniciar e testar no 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
Afirmar o estado do elemento com wait-for
wait-for --value sondagens até que o valor de um elemento corresponda à cadeia esperada, usando o mesmo recurso inteligente que get-value (TextPattern → ValuePattern → SelectionPattern → Name). Devolve o código de saída 0 ao corresponder, o código de saída 1 ao timeout — tornando-o uma afirmação amiga do CI. Use --property para verificar uma propriedade específica da UIA em vez disso.
# 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
Assert com saída JSON
Use --json com PowerShell ou jq para asserções mais complexas:
Contrato de código de saída para
searchewait-forno--jsonmodo: quando nenhum elemento corresponde a (search) ou a espera expira (wait-for), o comando escreve um envelope de resultados totalmente analisável para stdout ({ "matchCount": 0, ... }ou{ "found": false, "timedOut": true, ... }) e retorna o código de saída 1. O Stderr está vazio no--jsonmodo (a saída do logger é suprimida). Desvia nos campos envelope, ou em$LASTEXITCODE, dependendo de qual for mais ergonómico.
# 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" }
Os envelopes JSON são:
-
inspect:{ "depth", "interactive", "hideDisabled", "hideOffscreen", "windows": [...] } -
search:{ "matchCount", "hasMore", "matches": [...] } -
wait-for:{ "found", "waitedMs", "element"?, "timedOut" } -
get-property:{ "elementId", "element", "properties": { ... } }
Os elementos tipados usam type e numéricos x, y, width, e height.
A geometria está nos píxeis físicos do ecrã.
0,0,0,0é o retângulo vazio/sem interface de interface do Automatização da Interface de Utilizador nesta projeção; isOffscreen é separado, pelo que um elemento fora do ecrã pode ainda ter limites não nulos.
Cada inspect --jsonwindows[] entrada e o status --json resultado incluem windowDpi, scale (windowDpi / 96), dpiAwareness, e coordinateSpace: "physical-screen-pixels". Estes descrevem o contexto de DPI da janela de destino, não o DPI do monitor incondicional: o Windows reporta 96 para uma janela não consciente, DPI do sistema para uma janela consciente do sistema, e DPI do monitor atual para uma janela consciente de cada monitor. Se o contexto HWND ou DPI não puder ser lido, o comando falha em vez de substituir silenciosamente 96. Quando status resolve um processo antes de ter uma janela de topo, hwnd é 0 e os campos DPI são omitidos até que exista uma janela. Para todo inspecto processo , a janela-alvo selecionada mantém-se falha-rápida; se um pop-up posterior desaparecer após a sua árvore ter sido lida, a sua windows[] entrada transporta dpiError e omite os campos DPI enquanto as restantes árvores de janelas continuam a ser devolvidas.
Consulte as competências references/ui-json-envelope.md enviadas winapp-ui-automation para exemplos completos de cada envelope.
Exemplo de teste completo de fumo
# 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
Windows developer