Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Inspecione e interaja com a execução de aplicativos Windows da linha de comando. Usado por agentes de IA e desenvolvedores para teste de interface do usuário, depuração e automação.
Visão geral
winapp ui fornece comandos para inspecionar e interagir com Windows UIs do aplicativo.
Usa Windows Automação da Interface do Usuário (UIA). Funciona com qualquer aplicativo Windows – WPF, WinForms, Win32, Electron e WinUI 3.
A maioria dos comandos conduz o aplicativo por meio de padrões UIA (sem injeção de entrada). As exceções injetam entrada real: ui click/ui hover/ui dragusam simulação de mouse,ui touch/ui pen sintetizam entrada de toque e caneta/caneta e ui send-keys sintetizam a entrada do teclado – para controles e cenários que os padrões UIA não podem dirigir.
Important
Requisito de área de trabalho interativa (verbos de injeção de entrada).click, hover, drag, , touchpen, , scroll --wheele send-keys --via send-input sintetizar entrada no nível do sistema operacional, para que eles precisem de uma área de trabalho desbloqueada e interativa com a janela de destino em primeiro plano. Em uma estação de trabalho bloqueada ou área de trabalho segura (LogonUI/UAC), eles não podem injetar e falhar rapidamente com no_interactive_desktop (diferente da elevação/foreground_not_target casos).
touch
/
pen recusa adicionalmente quando nenhuma janela é resolvida (no_target); uma coordenada fora da janela de destino é um aviso não fatal (uma warnings[] entrada --jsonem , ou uma linha de aviso no modo de texto) e a injeção ainda continua — consistente com os verbos do mouse. Todo o resto — inspect, search, get-property, , get-value, wait-forset-value, invoke, – scroll --direction/--to conduz o aplicativo por meio de padrões UIA e é amigável à sessão sem cabeça/bloqueada.
screenshot é a exceção entre os verbos que não injetam: ele usa um turno exclusivo e sua captura pode precisar de uma área de trabalho interativa utilizável, pois o mecanismo restaura um destino minimizado e volta para primeiro plano quando a captura de quadros não está disponível ou --capture-screen é usada. Prefira os verbos padrão UIA em CI; reserve os verbos de injeção para cenários que realmente precisam de entrada real. Antes de injetar, os verbos de gesto também resolvem novamente o elemento de destino e se recusam target_moved se ele ainda estiver animando/realocando, em vez de pousar a entrada em espaço vazio.
Início Rápido
# 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
Executando a automação da interface do usuário na área restrita do Windows
Para manter a automação fora da área de trabalho, adicione --on sandbox aos comandos executar e de interface do usuário:
winapp run . --on sandbox --detach
winapp ui inspect --on sandbox -a MyApp
winapp ui invoke --on sandbox SubmitButton -a MyApp
--detach retorna após a inicialização; sem ele, run aguarda a saída do aplicativo. Mantenha --on sandbox todos os comandos convidados, incluindo aqueles que usam um identificador de janela ou PID.
Consulte Windows execução de área restrita para requisitos do cliente, breve configuração/reconexão de alterações de foco, coordenação de fluxo de trabalho e entrega de saída do host.
Consultas com escopo e tipada
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
search, get-propertye get-valuewait-for aceite esses filtros opcionais.
O seletor e cada filtro fornecido devem corresponder ao mesmo elemento:
-
--root <selector>pesquisa somente descendentes de uma raiz correspondente exclusivamente, nunca a raiz em si. Use uma AutomationId ou uma lesma deinspectpara desambiguar. Uma raiz que corresponde a vários elementos falha,ambiguous_selectormesmo que uma correspondência seja invocável. Uma raiz ausente não produz correspondências. Depois que a raiz é encontrada, as consultas não pesquisam janelas pop-up não relacionadas, mesmo quando nenhum descendente corresponde. As consultas não são limitadas pelainspectprofundidade de exibição de 's. -
--type <control-type>corresponde a um tipo de controle UIA, ignorando maiúsculas e minúsculas. Os únicos aliases sãoTextBox→EditeTextBlock→Text. Nomes desconhecidos (incluindo IDs numéricas e expressões curinga) falham cominvalid_arguments. -
--class-name <literal>corresponde a todo o UIAClassNamedo provedor, ignorando maiúsculas e minúsculas. Não é uma subcadeia de caracteres, curinga ou expressão regular. Useget-property --property ClassNamepara descobrir o valor do provedor; o nome da classe não precisa ser igual ao tipo de controle UIA.
As consultas filtradas usam a Exibição de Controle do UIA, a mesma exibição mostrada por inspect.
Nós de provedor expostos somente no Modo de Exibição Bruto não são retornados; use inspect para localizar o controle que contém e seu seletor.
Todos os 41 tipos oficiais têm suporte: Button, , Calendar, CheckBox, , EditComboBox, Hyperlink, Image, ListItem, List, MenuBarMenuStatusBarSpinnerTabSliderTabItemScrollBarTextRadioButtonToolTipTreeToolBarTreeItemGroupMenuItemDocumentCustomProgressBarDataItemDataGridThumbSplitButton, Window, PaneHeader, , HeaderItem, Table, TitleBar, Separator, , SemanticZoom, . . AppBar
wait-for resolve o seletor raiz novamente em cada sondagem, de modo que a raiz possa aparecer após o início do comando. Com --gone, uma raiz ausente significa que não há descendente correspondente; uma raiz ambígua é um erro, não um sucesso.
Uma pesquisa interrompida não é uma prova de desaparecimento: se um elemento for removido durante a pesquisa ou substituído antes de uma --value leitura, a próxima pesquisa verificará novamente; outros erros de pesquisa ou leitura falharão no comando.
-w <HWND> restringe a descoberta raiz à árvore UIA dessa janela. Com -aa descoberta raiz, também é possível encontrar as janelas pop-up do aplicativo. As correspondências AutomationId raiz exatas têm precedência sobre correspondências de subcadeia de caracteres em todas essas janelas; várias correspondências exatas ainda falham com ambiguous_selector.
Uma lesma raiz seleciona esse elemento mesmo quando outra janela tem a mesma AutomationId. Se a raiz selecionada for substituída, sua lesma antiga não corresponderá mais; use uma AutomationId ou raiz de nome quando quiser que a sondagem siga uma substituição.
Quando os filtros estiverem presentes, os comandos que leem um único elemento falharão ambiguous_selector se mais de um elemento permanecer; restringir os filtros ou usar uma lesma exclusiva. As correspondências Exact AutomationId mantêm precedência sobre correspondências de subcadeia de caracteres, dentro do escopo filtrado. Omitir todas as três opções preserva o comportamento de consulta existente.
Coordenando fluxos de trabalho de interface do usuário simultâneos
Windows tem apenas uma janela de primeiro plano, um foco de teclado, um cursor e um fluxo de entrada. Quando dois winapp ui fluxos de trabalho são executados na mesma área de trabalho assinada ao mesmo tempo, eles podem roubar o foco um do outro, ignorar um menu que o outro acabou de abrir ou mover um destino para fora em um clique pendente.
A arbitragem está sempre ativada. Cada winapp ui comando que toca a área de trabalho física toma um rumo, sem configuração e sem nenhuma maneira de desligá-lo, para que dois agentes nunca possam digitar nas janelas um do outro. Os comandos somente leitura continuam sendo executados simultaneamente.
A continuidade entre comandos é aceita. Por padrão, cada comando é um tiro único autocontido: ele aguarda sua vez, faz seu trabalho e libera a área de trabalho imediatamente. Para manter a área de trabalho em vários comandos, forneça a eles todas as mesmas IDs de fluxo de trabalho:
# Set once per logical UI workflow
$env:WINAPP_UI_WORKFLOW_ID = [guid]::NewGuid().ToString()
O que você precisa saber:
- Uma ID de fluxo de trabalho nomeia um fluxo de trabalho lógico , não necessariamente um agente inteiro e não necessariamente um aplicativo. Use o mesmo valor para comandos de cooperação (uma gravação mais os cliques que ele deve capturar); use valores diferentes para fluxos de trabalho independentes, mesmo quando um agente inicia ambos.
- Sem identificação, cada comando é um único tiro independente. Ele ainda arbitra, mas não tem graça e entrega a área de trabalho no momento em que termina. Dois comandos no-id são fluxos de trabalho separados mesmo quando iniciados do mesmo shell.
- Hosts adaptáveis e de shell fresco devem injetar o mesmo valor. Se cada comando for executado em um novo shell , que é como a maioria das chamadas de ferramenta de agente funcionam, a única coisa que pode agrupá-las é uma passagem explícita
WINAPP_UI_WORKFLOW_IDpara cada chamada de cooperação. - A graça de quatro segundos protege rajadas apertadas, não raciocínio de modelo. Um fluxo de trabalho com uma ID mantém sua volta desde que o próximo comando seja iniciado em quatro segundos. Isso abrange comandos back-to-back em um script; expira intencionalmente enquanto um modelo está pensando. É um fallback para quando você não pode dizer que terminou , quando puder, executar
winapp ui yieldem vez de esperar. - Os fluxos de trabalho adaptáveis devem requisir, revalidar e reproduzir. Após uma lacuna de raciocínio, outro fluxo de trabalho pode ter usado a área de trabalho, portanto, reabra o menu, resolva novamente o elemento e, em seguida, aja. Envie sequências de ponta a ponta conhecidas como um script apertado em vez de manter a área de trabalho enquanto você pensa.
- A ordenação é a afinidade de proprietário primeiro e, em seguida, FIFO entre as outras. Embora um fluxo de trabalho esteja ativo ou dentro de sua graça, ele poderá continuar emitindo comandos, mesmo que outros fluxos de trabalho já estejam aguardando. Depois que ele é executado
winapp ui yieldou sua carência expira, os fluxos de trabalho de espera são atendidos em ordem de chegada estrita. A atividade contínua por um fluxo de trabalho pode, portanto, atrasar outras pessoas indefinidamente. - Não há tampa dura. Um script longo, uma gravação não associado ou um loop de falha podem bloquear outros fluxos de trabalho em mutação.
-
Cancelamento ou término do processo é a recuperação de um fluxo de trabalho ao vivo travado. Os comandos de espera imprimem um status após um segundo e podem ser interrompidos com
Ctrl+C, que sai130. - Somente binários atualizados compatíveis cooperam. Builds mais antigos
winappantecedem esse recurso e não são coordenados. O código que chama o Automação da Interface do Usuário pacotes NuGet diretamente está fora dessa garantia totalmente — a coordenação reside na CLI, não nos pacotes.
Quais comandos esperam por uma curva:
| Behavior | Comandos |
|---|---|
| É executado simultaneamente (nunca espera) |
status, list-windows, inspect, search, get-property, get-value, get-focused, , wait-for |
| Aguarda a volta, mas nunca usa a área de trabalho |
set-value, scroll-into-view, , scroll --direction/--torecord |
| Aguarda a volta e usa a área de trabalho exclusivamente |
invoke, click, drag, hover, scroll --wheel, , touch, pen, , focus, send-keys, screenshot |
A linha do meio é a que vale a pena entender.
set-valuee scroll-into-view--toscroll --direction/conduzem padrões UIA em vez do primeiro plano, para que permaneçam sem cabeça/sessão bloqueada amigável e nunca impeçam ninguém de usar a área de trabalho. Mas eles alteram o que o aplicativo mostra, então eles esperam atrás da curva de outro fluxo de trabalho em vez de editar um campo ou rolar uma lista para fora sob o clique de outra pessoa.
Em um fluxo de trabalho, eles se sobrepõem a outro trabalho compartilhado , que é como captura record as set-value chamadas que ele está gravando. Eles não ignoram a barreira de avanço de 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 cada comando posterior, então um clique e a mutação que o segue permanecem na ordem em que você os escreveu.
screenshot sempre faz filas para um turno exclusivo. Nem toda captura perturba a área de trabalho — uma janela visível comum capturada por Windows Captura de Gráficos não — mas o mecanismo restaura o destino se ele é minimizado e volta para primeiro plano quando a captura de quadro não está disponível ou --capture-screen lê a tela ao vivo. Essas necessidades só são exibidas quando a captura está em andamento, de modo que o comando leva a vez para cima em vez de adivinhar. Quando ele compõe várias janelas, ele captura todas elas em uma única curva exclusiva, portanto, a imagem salva é um único momento consistente em vez de uma mistura de antes e depois. A codificação e a gravação do arquivo ocorrem após o lançamento da área de trabalho.
--capture-screenprecisa exatamente de uma janela. A captura de tela ao vivo registra o que realmente está na frente e apenas uma janela pode ser. Selecionar uma janela explicitamente com-w <hwnd>fornece exatamente uma região : os pixels dentro dos limites dessa janela, incluindo qualquer caixa de diálogo ou sobreposição visivelmente sobre ela, que é o motivo para ler a tela em primeiro lugar. Quando-acorresponde a várias janelas de nível superior ou de propriedade, não há essa seleção, portanto, o comando falhainvalid_argumentsantes de capturar qualquer coisa em vez de lutar contra o primeiro plano. Executewinapp ui list-windows -a <app>e tente novamente com-w <hwnd>, ou solte--capture-screenpara compor cada janela de seu próprio conteúdo.
record compartilha sua vez, de modo que a entrada do mesmo fluxo de trabalho pode intercalar com a captura , é assim que você registra um fluxo de trabalho que conduz um aplicativo. Duas ressalvas:
- Uma
recordID sem fluxo de trabalho é um proprietário único, portanto, bloqueia todos os outros fluxos de trabalho durante toda a duração. Para gravar e clicar ao mesmo tempo, dê a ambos os comandos o mesmoWINAPP_UI_WORKFLOW_ID. - Em um host sem suporte à captura de quadros, a gravação volta para PrintWindow, cuja recuperação de quadro em branco pode primeiro plano da janela a qualquer momento. Lá, a área de trabalho é mantida para toda a gravação e o comando diz isso em sua saída; até mesmo a entrada do mesmo fluxo de trabalho aguardará.
Erros que você 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 recriado com segurança ou foi escrito por um mais winapprecente), queue_capacity_exceeded (64 comandos de outros fluxos de trabalho já estão aguardando – o limite conta garçons estrangeiros ativos, não processos iniciados, portanto, entradas pertencentes a comandos que saíram ou foram mortos não ocupam um slot, e os comandos de seu próprio fluxo de trabalho fazem fila um atrás do outro em vez de contra esse limite) ui_turn_busy (yield enquanto seu próprio fluxo de trabalho ainda tem um comando em execução) e cancelled (Ctrl+C enquanto aguarda, saia do código 130).
Liberando a curva mais cedo: winapp ui yield
A graça de quatro segundos é um fallback: mantém a área de trabalho reservada quando você não pode dizer com certeza que você terminou. Quando você pode dizer isso, diga- yield entregue a área de trabalho imediatamente em vez de fazer com que todos esperem uma graça 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
- Os comandos de um tiro não devem definir uma ID de fluxo de trabalho. Sem um, cada comando já libera a área de trabalho no momento em que ela é concluída e não há nada a produzir.
- Fluxos de trabalho de várias etapas devem produzir quando terminarem, especialmente quando outros fluxos de trabalho podem estar aguardando. Ele custa um comando rápido e remove uma parada de quatro segundos de todos os outros.
- É idempotente. Renderizar duas vezes ou depois que a graça já tiver expirado, bem-sucedido e relatórios
{ "released": false }— que é o final normal de um script, não uma falha. - Ele nunca libera a volta de outro fluxo de trabalho. Se alguém tiver a área de trabalho ou ninguém o fizer, será um no-op.
- Ele falhará se
ui_turn_busyseu próprio fluxo de trabalho ainda tiver um comando em execução ou na fila — uma gravação, digamos. Liberação abaixo que entregaria a área de trabalho no meio do comando, portanto, nada é liberado e o comando em execução não é afetado. Aguarde ou interrompa-o e, em seguida, produza novamente. - Ele requer
WINAPP_UI_WORKFLOW_ID. Sem um, ele falha cominvalid_arguments. - Ele não usa nenhum aplicativo e nenhum seletor: ele devolve uma reserva, não uma janela, portanto, ainda funciona depois que o aplicativo é fechado.
Um comando de espera é acordado por quem libera a área de trabalho em vez de sondar para ela, de modo que uma fila não custa quase nada enquanto aguarda e a entrega é imediata. Cada garçom também verifica novamente por conta própria ocasionalmente, que é o que recupera a área de trabalho quando um processo é morto e nunca publica nada: o comando à frente da fila olha a cada meio segundo e os comandos por trás dele — que não podem ser executados antes que a cabeça faça de qualquer maneira — a cada poucos segundos.
Direcionamento de aplicativos
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
Título por 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 guia/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
Uso -a para descoberta, -w para direcionamento estável. Quando -a corresponde a várias janelas, o comando as lista com HWNDs para você escolher.
Seletores
Elementos de destino usando o seletor mostrado na [brackets] saída de inspeção/pesquisa.
Há três tipos de seletores:
| Seletor | Significado | Example |
|---|---|---|
MinimizeButton |
AutomationId (mostrado quando exclusivo — estável, preferencial) | winapp ui invoke MinimizeButton -a myapp |
btn-close-d1a0 |
Lesma semântica (mostrada quando nenhuma AutomationId exclusiva) | winapp ui invoke btn-close-d1a0 -a myapp |
Submit |
Pesquisa de texto sem formatação em relação a Name/AutomationId (subcadeia de caracteres que não diferencia maiúsculas de minúsculas) | winapp ui invoke Submit -a myapp |
Os seletores AutomationId são identificadores de conjunto de desenvolvedores (AutomationProperties.AutomationId em XAML).
Quando uma AutomationId é exclusiva em toda a árvore inspect de interface do usuário e search a mostra diretamente como o seletor , elas sobrevivem a alterações de layout, localização e reestruturação de árvore.
Os seletores de lesma (por exemplo, btn-close-d1a0) são gerados quando nenhuma AutomationId exclusiva existe.
Formato: prefix-name-hash. O hash valida a identidade do elemento, mas pode ficar obsoleto após alterações na interface do usuário.
Inspecionar o formato de saída
O inspect comando mostra a árvore de elementos com saída colorida (seletor em ciano, nome em verde, metadados em cinza):
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 – use-o com outros ui comandos.
Quando um elemento tem uma AutomationId exclusiva, ele é usado diretamente (por exemplo, , TabView). NewTabButton
Quando nenhuma AutomationId exclusiva existe, uma lesma gerada é usada (por exemplo, tab-newtab-5f5b).
Lesmas semânticas
Os lesmas usam o formato: em que prefix-normalizedname-hash :
- prefixo — abreviação 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 (preferencial) ou Name, máximo de 15 caracteres
- hash — hash hex 4-char do RuntimeId do elemento (valida a identidade do elemento)
Os lesmas são shell-safe (sem caracteres especiais), exclusivos e podem ser usados diretamente como argumentos. Sem filtros de consulta, o hash fornece detecção de desatualização – se o elemento tiver sido substituído, você obterá: "O elemento pode ter sido alterado. Executar novamente a inspeção." Para consultas filtradas, consulte Consultas com escopo e tipadas.
Elementos sem nome ou AutomationId mostram apenas prefixo + hash (por exemplo, pn-c8a3).
Desambiguando várias correspondências
As lesmas da inspect/search saída são exclusivas, mas podem ser alteradas entre as alterações de layout– use-as em nomes de tipo simples ou texto quando várias correspondências. Quando um seletor é ambíguo, a CLI imprime todas as correspondências com suas lesmas para que você possa escolher a certa e executar novamente com essa lesma.
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 sem formatação
Use texto sem formatação para pesquisar elementos – nenhuma sintaxe especial necessária:
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 em que Grupo, Botão e Texto compartilham o mesmo nome), a CLI escolhe automaticamente o único elemento invocável. Se vários forem invocáveis, ele listará todas as correspondências com lesmas.
Para resultados de pesquisa nãovogáveis (por exemplo, um TextBlock dentro de um botão), a pesquisa exibe automaticamente o ancestral invocável mais próximo , o elemento pai que você pode usar com invoke.
Isso 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
Comandos
status
Conecte-se a um aplicativo e mostre informações de conexão.
winapp ui status -a notepad
winapp ui status -a notepad --json
inspecionar
Exibir a árvore de elementos da interface do usuário. A saída mostra lesmas semânticas com recuo de 2 espaços 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 # invokable elements only, auto-depth 8
winapp ui inspect -a myapp --hide-disabled # hide disabled elements
winapp ui inspect -a myapp --hide-offscreen # hide offscreen elements
Saída de exemplo (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)
Saída de exemplo (--interactive — somente elementos invocáveis, lista simples):
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 esses marcadores de estado:
-
[on]/[off]/[indeterminate]— estado de alternância/caixa de seleção -
[collapsed]/[expanded]— expandir/recolher estado para árvores, caixas de combinação, itens de menu -
[scroll:v]/[scroll:h]/[scroll:vh]— contêiner rolável (vertical, horizontal ou ambos) -
[offscreen]— o elemento não está visível na tela -
[disabled]— o elemento não está habilitado -
value="..."— conteúdo de texto atual para elementos editáveis (quando diferente de Name)
busca
Encontre elementos que correspondam a um seletor. A saída mostra lesmas semânticas:
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)
Os lesmas 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
Ler valores de propriedade de um elemento. Inclui 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 de propriedades diferenciam maiúsculas de minúsculas. Um nome desconhecido falha em invalid_arguments--json; omita para listar --property as propriedades, incluindo todos os seis atributos de formatação de texto abaixo.
wait-for --property usa os mesmos nomes que diferenciam maiúsculas de 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 seleção ou no cursor atual. As leituras não alteram o foco ou a seleção.
| Property | Valor uniforme (retornado como uma cadeia de caracteres) |
|---|---|
FontWeight |
Peso numérico, como "400" (normal) ou "700" (negrito) |
FontName |
Nome da família de fontes, como "Courier New" |
FontSize |
Tamanho em pontos, como "15.5" |
ForegroundColor |
Decimal Windows COLORREF (0x00BBGGRR), como "3678732" para RGB(12, 34, 56) |
IsItalic |
"True" ou "False" |
StrikethroughStyle |
Estilo de decoração de texto UIA numérico, como "0" (nenhum) ou "1" (único) |
Os números usam formatação invariável (um ponto decimal, independentemente da localidade). Em vez disso, cada atributo pode retornar:
| Value | Significado e próxima etapa |
|---|---|
"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 provedor TextPattern do documento não relata esse atributo. Verifique o suporte de acessibilidade do aplicativo. |
"Unavailable" |
O elemento não tem TextPattern. Use inspect ou search localize seu elemento de texto/documento. |
Ao listar todas as propriedades, as propriedades básicas armazenadas em cache permanecerão disponíveis se nenhum elemento dinâmico puder ser resolvido e um valor de formatação malformado for omitido sem descartar outras propriedades. Essas omissões são registradas como avisos. Solicite uma propriedade de formatação específica para obter um erro em vez de uma omissão.
As falhas do provedor permanecem erros, não "Unavailable". Para stale_element, inspecione o aplicativo novamente e tente novamente com um seletor atual.
O envelope JSON inclui elementId, um digitado elemente com valor de cadeia de caracteres properties.
As propriedades existentes, inclusive BoundingRectangle, mantêm seus formatos.
Por exemplo, a parte de properties formatação é:
{
"FontWeight": "700"
}
captura de tela
Capture 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 elemento, a captura padrão combina várias janelas em um PNG composto lado a lado rotulado, não em arquivos separados.
-a por nome de processo ou PID inclui as janelas do aplicativo e suas janelas de propriedade. Uma correspondência baseada em -a título seleciona uma janela correspondente mais suas próprias janelas; -w seleciona explicitamente uma janela mais suas próprias janelas, não todas as janelas no processo. Uma caixa de diálogo ou dica de ferramenta de propriedade pode, portanto, aparecer como seu próprio painel, mesmo quando você seleciona explicitamente o HWND principal. Um seletor de elementos corta esse elemento em vez de redigir janelas.
--quiet suprime a saída informativa para capturas de janela única e de composição, incluindo o caminho salvo. Os avisos e o diagnóstico de falha de captura permanecem visíveis. Em vez disso, use --json quando precisar do caminho do arquivo e das dimensões como saída estruturada.
Com --on sandbox, --output nomeia o destino do host. Saída sem formatação bem-sucedida e --json relatório que o caminho do host após a imagem é entregue.
O caminho de captura padrão usa Windows. Graphics.Capture (WGC), lendo a superfície real composta por DWM , preservando cantos arredondados, transparência e trabalhando mesmo enquanto a janela é ocluída por outras windows. Se o WGC não estiver disponível (compilações de Windows mais antigas), a CLI retornará ao PrintWindow.
Use --capture-screen -w <hwnd> quando precisar de pop-ups visíveis ou dicas de ferramenta em suas posições na tela, incluindo sobreposições que não pertencem à janela de destino. Ele lê a região da tela dessa janela em vez de compor painéis rotulados e coloca a janela em primeiro plano. Com -a, ele requer exatamente uma janela correspondente; se várias janelas de nível superior ou de propriedade corresponderem, use winapp ui list-windows -a <app> e tente novamente com -w <hwnd>. Use --focus se você quiser apenas colocar em primeiro plano a janela sem alternar os modos de captura (por exemplo, para garantir que a captura de tela corresponda ao que o usuário está examinando no momento).
Como a tela dc captura o que realmente está na frente,
--capture-screenverifica se o destino atingiu o primeiro plano imediatamente antes de capturar e falhar seforeground_not_targetnão o fez (prevenção de roubo de foco, um prompt UAC ou outra janela se ativando). Nenhuma imagem é escrita nesse caso – anteriormente, o comando saiu 0 e devolveu uma imagem da janela errada.ui record --capture-screenaplica a mesma verificação antes do primeiro quadro.
registro
Registre uma janela ou região de elemento em um H.264 MP4. Prefira um positivo --duration-sec para scripts autônomos. 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 exigem um inteiro durationSec de 1 a 86400; seu sinal de anulação é cancelado com força em vez de finalizar normalmente uma gravação.
# 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— Registro por N segundos. Padrão 0 registros até parar. -
--fps N— Quadros de destino por segundo (padrão 15). -
--max-edge N— Downscale so the longest edge is at most N pixels (0 = no downscale). -
--capture-screen— Captura da tela DC (inclui sobreposições/pop-ups; primeiro plano da janela). -
--output <path>— Caminho MP4 de saída. Usarecording-<timestamp>-<guid>.mp4como padrão. -
--overwrite— Substitua as saídas de gravação existentes após a conclusão da nova tomada. Sem ele, as saídas existentes são rejeitadas. -
--frames— Gravar evidência JPEG com carimbo de data/hora para<output-name>.frames. Dá suporte a 1 a 30 fps e--max-edge64-4096 (padrão 1280). Os dados do quadro são limitados a 1 GiB; o MP4 continuará se o limite for atingido.
Artefatos de quadro legíveis pelo agente:
evidence.mp4
evidence.frames/
manifest.json
frames.ndjson
frames/
frame-000000-t000000000012.jpg
frames.ndjsontem uma linha por exemplo com sampleIndex, monotônicaelapsedMs, MP4-relative mediaTimeMs, imageIndexe filechanged. Exemplos idênticos a pixels consecutivos reutilizam o JPEG de qualidade 85 anterior.
manifest.jsonregistra a solicitação, o tempo, o status MP4, as dimensões da imagem e o status (completeoupartialtruncated). O tempo truncado abrange o prefixo retido, enquanto video descreve o MP4 completo.
Escolha um novo caminho de saída, a menos que você pretenda substituir uma gravação --overwritepor .
Sem ele, um vídeo existente ou seu diretório emparelhado .frames bloqueia a gravação, mesmo quando você omite --frames.
O MP4 anterior permanecerá intacto se a nova captura falhar. Na substituição bem-sucedida, o diretório do quadro anterior é mantido como <output-name>.frames.previous-<id>, mesmo que a nova gravação omita --frames. Preserve as evidências parciais e siga o relatado recoveryHint antes de tentar novamente. Se a finalização mp4 falhar, os quadros preservados poderão ser publicados em <output-name>.frames.partial-*. Artefatos de quadro contêm conteúdo de tela não criptografado; manipule-os como capturas de tela ou vídeo.
Com --on sandboxo diretório MP4 e o diretório de quadros são entregues ao host, incluindo saídas padrão quando --output são omitidas. Confira a captura de área restrita para gravações interrompidas e captura de área de trabalho inteira.
Modos de captura (relatados no campo JSON mode ):
-
wgc— Windows Captura de Elementos Gráficos (padrão; funciona enquanto a janela é ocluída). -
printwindow— GDI PrintWindow (fallback quando o WGC não está disponível neste sistema/sessão; execute novamente para--capture-screenusar o DC de tela). -
screen— Tela DC via--capture-screen(inclui sobreposições/pop-ups; traz a janela para o primeiro plano).
Saída JSON (--json):
-
stdout: Resultado final da gravação, incluindo cadência, motivo de parada, opcional
frameArtifactse avisos. -
stderr: Um objeto JSON por linha: um
recording-startedevento após o primeiro quadro, seguido de um erro se a gravação falhar mais tarde. Os caminhos de quadro são incluídos somente quando a saída do quadro está ativa.
Códigos de erro:
-
element_not_found— O seletor não correspondeu. -
ambiguous_selector— O seletor correspondeu a vários elementos; use uma lesma sugerida. -
invalid_arguments— Um valor de opção é inválido. -
output_exists— Uma saída de gravação já existe e não pode ser substituída nas opções solicitadas. -
frame_output_failed— Nenhum artefato pôde ser preservado depois que a saída do quadro falhou. -
partial_output— Apenas um artefato foi concluído; inspecionarpartialOutputerecoveryHint.
Limitação conhecida: Gravar um elemento dentro de um pop-up com janelas pode capturar a janela subjacente. Registre toda a janela ou siga o fluxo de trabalho de sobreposição de captura de tela para uma imagem parada. Consulte o nº 646.
chamar
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 SubmitButton -a myapp
Use --action quando um teste deve executar uma operação específica exatamente no elemento selecionado. Ele nunca tenta outro padrão ou um ancestral faturamento, mesmo que a ação solicitada falhe. Um controle que dá suporte à invocação e à seleção será selecionado, não invocado, com --action select. Com --action, uma lesma tem como destino exatamente um elemento; um seletor AutomationId ou texto sem formatação que corresponde a mais de um elemento falha ao fechar com um código de saída diferente de zero em vez de agir na primeira correspondência, portanto, passe uma lesma de inspect/search quando um nome é ambíguo.
| Action | Operação |
|---|---|
invoke |
InvokePattern.Invoke |
select |
SelectionItemPattern.Select |
toggle |
TogglePattern.Toggle, exatamente uma vez |
toggle-on / toggle-off |
Ler ToggleState; ter êxito sem alterar um estado já correto, caso contrário, alterne e verifique |
expand / collapse |
ExpandCollapsePattern.Expand/Collapse |
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 falhará em vez de continuar a alternar. Uma verificação com falha pode deixar o controle alterado; leia ToggleState antes de decidir o que fazer a seguir.
Sem --action, o comportamento automático existente é inalterado: tente InvokePattern, TogglePattern, SelectionItemPattern e ExpandCollapsePattern (expand), com uma repetição de ancestral invocável quando necessário.
Uma ação sem suporte falha com um código de saída diferente de zero e, com --json, um erro estruturado no stderr. Inspecione o controle selecionado e escolha uma ação compatível com ele ou direcione explicitamente o pai pretendido. JSON de sucesso inclui requestedAction e performedAction; consulte a referência JSON.
clique
Clique em um elemento em suas coordenadas de tela usando a simulação do mouse. Use isso para controles que não dão suporte InvokePattern (por exemplo, cabeçalhos de coluna, 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
Assim como os outros verbos de injeção de entrada,
clicktraz o destino para o primeiro plano e falha rapidamente (no_interactive_desktopem uma área de trabalho bloqueada/segura,foreground_not_targetse o foco não puder ser transferido) em vez de clicar na janela errada. Ele também resolve novamente o elemento pouco antes do botão para baixo: depois de posicionar o cursor, ele faz uma verificação de posição final, de modo que um destino de movimentação/animação continuamente falhatarget_movedem vez de relatar êxito depois que o clique caiu em espaço vazio – um sucesso relatado significa que o destino ainda estava no lugar quando o botão foi para baixo.
arrastar
Pressione o botão do mouse em um ponto, mova para outro e, em seguida, solte com drag <from> <to>, onde cada ponto de extremidade é um seletor de elemento (arrasta de/para o centro do elemento) ou coordenadas x,yde tela exatamente como relatado por .winapp ui inspect Misture e combine livremente (seletor→seletor, seletor→coords, coords→coords).
Usa com movimentos intermediários SendInput para que o aplicativo veja um fluxo realista de WM_MOUSEMOVE mensagens. Use-o para reordenar/redimensionar identificadores, controles deslizantes, desenho de tela e arrastar e soltar.
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 mouse em vez do botão esquerdo. -
--hold-ms <ms>— Mantenha o botão pressionado no início antes de mover (padrão: 0). Com<from> == <to>(sem movimento) isso executa um gesto de pressionar e segurar/pressionar longamente . -
--dwell-ms <ms>— Habitar no destino após a movimentação, antes de liberar (padrão: 0). Permite soltar destinos/mesclar sobreposições que armam de um foco sustentado (em vez do instante em que o cursor chega) trava antes do botão para cima.
Bare
x,ysão coordenadas de tela no mesmo relatório de espaçowinapp ui inspect/searche um seletor é resolvido para o centro do elemento – inspecione primeiro para escolher pontos.
Por exemplo
send-keys --via send-input,draginjeta todo o sistema operacional nas coordenadas da tela depois de colocar o destino em primeiro plano. Se o foco não puder ser trazido para o destino (por exemplo, prevenção de roubo de foco de um processo em segundo plano), o comando falhará (foreground_not_target) em vez de arrastar para a janela errada – concentre-se ou clique na janela primeiro. Em uma área de trabalho bloqueada/segura, falha comno_interactive_desktop. Cada ponto de extremidade de elemento é resolvido imediatamente antes do arrastar; se ainda estiver movendo/redimensionando (um destino de animação), o comando falharátarget_movedem vez de arrastar para um ponto obsoleto. (Pontosx,yde extremidade nus não podem ser verificados novamente, portanto, são usados as-is.)
Toque
Injete gestos de toque sintéticos usando a API de injeção de ponteiro Windows. A âncora de contato é um seletor de elemento (usa o centro do elemento) ou uma coordenada x,yde tela explícita por meio --at de (mesmos relatórios de espaçowinapp ui inspect). Use-o para interações de toque/pressionamento e gestos de vários toques que a simulação do mouse não pode 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-press,swipe,pinch.stretch -
--at <x,y>— Ponto inicial explícito (coordenadas de tela). O padrão é o centro de elementos do seletor. -
--to-point <x,y>— Ponto de extremidade para umswipe. Tem precedência sobre--direction. -
--direction <right|left|up|down>— Direção do dedo (padrão:right). Combinado com--distancea computação do ponto de extremidade quando--to-pointnão é dado. -
--distance <px>— Propagação do dedo para, ou deslize o dedo parapinch/stretcha distância em pixels. -
--hold-ms <ms>— Mantenha os contatos pressionados antes de levantar (tempo de espera de pressionamento longo; o padrão é 500 ms paralong-pressquando não estiver definido). -
--duration-ms <ms>— Deslize o tempo para gestos móveis (deslizar/pinçar/esticar; padrão 300). -
--fingers <n>— Número de contatos (1 a 10; padrão 1).pinch/stretchsempre use 2.
Segurança de injeção.
touchrecusa-se a injetar, a menos que um identificador de janela de destino diferente de zero seja resolvido e essa janela mantenha o primeiro plano , ela falharáno_targetquando nenhuma janela puder ser resolvida,foreground_not_targetse o foco não puder ser transferido ouno_interactive_desktopem uma área de trabalho bloqueada/segura. Cada coordenada (centro de elementos, pontos de passagem explícitos--at/--to-pointe gerados) é verificada no retângulo da janela de destino; um ponto fora da janela é exibido como um aviso não fatal (umawarnings[]entrada--jsonou uma linha de aviso no modo de texto) e a injeção ainda continua — correspondendo aos verbos do mouse (click/drag/hover/scroll), que também injetam coordenadas fora da janela.--fingersacima de 10 é rejeitado antecipadamente.Anotação de hardware. O touch prefere o dispositivo de ponteiro sintético moderno (
CreateSyntheticPointerDevice(PT_TOUCH)) e volta para a API herdadaInitializeTouchInjection/InjectTouchInput. Se a injeção não for suportada no dispositivo/sessão atual, o comando exibirá o código de erro real do Win32 (por exemplo, "sem suporte") em vez de relatar um falso êxito, trate uma saída diferente de zero como "toque não entregue".sessões de Área de Trabalho Remota/VM. Em uma Área de Trabalho Remota (RDP) ou em algumas sessões de VM, o sistema operacional pode aceitar toque sintético (saída 0) sem que ele realmente atinja o aplicativo de destino. Quando uma sessão remota é detectada,
touchacrescenta um aviso de incerteza de entrega – umawarnings[]entrada--jsonou uma linha de aviso no modo de texto. Um ✅/exit 0 significa que a chamada de injeção foi bem-sucedida, não que o aplicativo tenha recebido a entrada; confirme o efeito comui screenshot/ui inspectquando ele é importante.
pen
Injetar entrada de caneta sintética/caneta – toques e traços de tinta – usando a API de ponteiro sintético Windows (CreateSyntheticPointerDevice(PT_PEN); Windows 10 1809+). Direcione um centro de elementos, um ponto explícito --at ou um traço de tinta 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
Opções:
-
--at <x,y>— Ponto de contato de caneta (coordenadas de tela). O padrão é o centro de elementos do seletor. Ignorado quando--pathé dado. -
--path "<x,y x,y …>"— Caminho de traço de tinta como pares separadosx,ypor espaço em branco (um caminho de um ponto é um toque). -
--pressure <0.0–1.0>— Pressão da caneta (padrão 0,5). — Â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 viagem de traço em milissegundos distribuídos como quadros UPDATE interpolados pelo caminho (padrão: ~10 ms por ponto de passagem). Use isso para controlar a velocidade com que a caneta se move visivelmente do início ao fim.
Segurança de injeção. Por exemplo
touch,penrecusa-se a injetar sem uma janela de destino não zero, em primeiro plano (no_target/foreground_not_target/no_interactive_desktop) e verifica cada ponto de tinta no retângulo da janela de destino, exibindo qualquer coordenada fora da janela como um aviso não fatal (warnings[]em--json, ou uma linha de aviso no modo de texto) enquanto ainda injeta — consistente com os verbos do mouse. Inválido--pressure(fora de 0,0 a 1,0) ou inclinação (fora ±90°) são rejeitados antecipadamente.sessões de Área de Trabalho Remota/VM. O roteamento de caneta não é especialmente confiável sobre Área de Trabalho Remota: a chamada de injeção pode relatar êxito (saída 0), enquanto nenhuma entrada de caneta atinge o aplicativo. Quando uma sessão remota é detectada,
penacrescenta um aviso de incerteza de entrega (warnings[]em--json, ou uma linha de aviso no modo de texto) para que não ✅ seja confundido com a entrega confirmada. Valide fluxos dependentes de caneta em uma área de trabalho local e interativa.
Hover
Mova o mouse para o centro de um elemento para disparar efeitos de foco (dicas de ferramenta, submenus, estados visuais). Usa para movimento realista SendInput do mouse com um pequeno movimento e, em seguida, aguarda um tempo de vida 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 para aguardar após passar o mouse para que os efeitos apareçam (padrão: 800, intervalo: 0 a 10000)
send-keys
Enviar entrada de teclado sintético – o equivalente do teclado para click. O UIA não tem nenhum padrão de injeção de teclado, portanto, isso cai para a camada Win32. Use-o para navegação por teclado (setas, Tab, Enter, Esc), atalhos (ctrl+c, alt+f4) e digitação em controles que precisam de eventos por pressionamento de tecla em vez set-valuede gravação atômica.
winapp ui send-keys "down down enter" -a myapp # arrow navigation then commit
winapp ui send-keys "ctrl+a delete" -a myapp # select all, then delete
winapp ui send-keys "Hello world" --target txt-name-a1b2 -a myapp # focus a field, then type text
winapp ui send-keys "text=down text=down text=enter" -a myapp # type the words, don't press the keys
winapp ui send-keys "down down enter" -a myapp --verbatim # same, but type the whole argument literally
winapp ui send-keys "alt+f4" -a myapp # close window via accelerator
winapp ui send-keys "vk=0x5D" -a myapp # a key with no friendly name (Apps/Menu key)
winapp ui send-keys "ctrl+shift+t" -a myapp --via send-input # use OS-wide injection instead of PostMessage
winapp ui send-keys "win+shift+v" -a myapp --via send-input --allow-system-keys # opt in to drive a global hotkey
Gramática de chave (tokens separados por espaço em branco, aspas de cadeias de caracteres de vários tokens):
-
Chaves nomeadas —
enter/return, ,tab,esc/escape, ,space,backspace,delete/delinsert, ,home,end,pageup/pgup,pagedown/pgdn,up/down/left/right,f1–f16,apps, ,printscreen, .capslock -
Sequências — vários tokens são pressionados na ordem:
down down enter. -
Combinações modificadoras —
ctrl, ,shift,altwinunidas com+:ctrl+shift+t,alt+f4. -
Texto literal — qualquer token que não seja uma chave conhecida é digitado caractere por caractere:
hello. Palavras literais adjacentes mantêm o espaço entre elas, de modo que uma frase"Hello world"entre aspas seja digitada verbatim (o espaço é preservado); um literal que contém+apenas comoC++oua+bé digitado como texto, não analisado como uma combinação. -
Escape literal explícito – prefixe um token
text=para digitá-lo verbatim mesmo quando ele colide com um nome de chave ou modificador:text=enterdigita a palavra "enter" em vez de pressionar Enter etext=ctrl+adigita a cadeia de caracteres literal. Espelha avk=fuga; o valor escapado ainda se funde com palavras literais adjacentes (text=down low→ "abaixo"). Como os tokens são divididos em espaço em branco (e literais adjacentes reentram com um único espaço), use escapes de barra invertida dentro de umtext=valor para digitar espaço em branco que de outra forma não sobreviveria:\s→ espaço,\tguia →,\n→ nova linha,\r→ nova linha →\\barra invertida literal.\n,\re\r\ncada um insere uma única quebra de linha (um Enter/VK_RETURN), assimtext=line1\nline2etext=line1\r\nline2ambos digitam uma nova linha. Portanto,text=a\s\sbdigita "a b" (espaço duplo) etext=\shimantém um espaço à esquerda. Uma fuga não reconhecida (por exemplo\x) é deixada verbatim. -
Literal de argumento inteiro (
--verbatim) — quando toda a carga for texto literal, passe--verbatimem vez de escapar de cada token comtext=. Ele digita o argumento de chaves inteiras exatamente como dado — sem interpretação/chave nomeada/ combinação —vk=/text=e, ao contrário do caminho normal, preserva o espaço em branco interno exato (sem recolhimento) sem a necessidade.\sPortantosend-keys "down down enter" --verbatim, digita as palavras esend-keys "a b" --verbatimmantém o espaço duplo. Escapes de barra invertida não são decodificados no--verbatimmodo (um\sé digitado como uma barra invertida e um "s"); use umtext=token quando precisar de um caractere de controle com escape. -
Chaves virtuais brutas —
vk=0xNN(hex) ouvk=NN(decimal) para chaves sem um nome amigável.
Opções:
-
--target <selector>— Concentre esse elemento (via UIA) antes de enviar chaves. Sem ele, as chaves vão para o elemento focado no momento do aplicativo. -
--verbatim— Digite o argumento de chaves inteiras como texto literal (sem chave/combinação/vk=/text=análise) e preserve o espaço em branco exato. A forma de argumento inteiro da escape por tokentext=. -
--via <transport>—post-message(padrão) postagensWM_KEYDOWN/WM_KEYUP/WM_CHARna fila da janela de destino. Ele é direcionado ao HWND e ignora a UIPI (funciona entre níveis de integridade).send-inputinjeta todo o sistema operacional eSendInputvai para a janela de primeiro plano.
Escolhendo um transporte/limites conhecidos:
-
post-messageé o padrão porque ignora a UIPI e não depende da janela em primeiro plano. Limites: ele não pode disparar hotkeys globais registradas por meioWH_KEYBOARD_LLde ganchos de baixo nível (aqueles que tocam a entrada upstream de qualquer fila de janela) e os aplicativos que leem o estado de chave bruta por meioGetAsyncKeyStatepodem não observar modificadores mantidos. Ele resolve e posta automaticamente na janela filho focada do thread de destino (viaGetGUIThreadInfo) após o primeiro plano, de modo que os aplicativos Clássicos Win32/WinForms cujos controles são janelas filho separadas recebem chaves sem direcionar manualmente o controle. Os aplicativos WinUI 3/UWP têm controles XAML sem janelas sem HWND filho, portanto, um publicadoWM_CHAR/WM_KEYDOWNnão tem nada para entrar e é removido — após a mensagem não pode conduzi-los (o comando avisa e sai 0); use .--via send-input(WPF janelas são HWND único e chaves de rota para o elemento focado internamente, portanto, a pós-mensagem funciona lá.) -
send-inputproduz entrada totalmente real (modificadores visíveis paraGetAsyncKeyState, dispara ganchos de baixo nível), mas vai para qualquer janela em primeiro plano e é bloqueada pela UIPI ao injetar de um processo elevado em um destino de menor integridade (AppContainer/AppX). Sesend-inputrelatar uma falha, o destino provavelmente será elevado ou um aplicativo AppX – usepost-messageou execute a CLI em um nível de integridade correspondente. Como proteção de segurança,send-inputverifica se a janela de destino está, na verdade, em primeiro plano imediatamente antes de injetar e falhar (foreground_not_target) em vez de digitar na janela errada se o foco não puder ser trazido para ela – concentre-se ou clique na janela primeiro. Em uma área de trabalho bloqueada ou segura , em vez disso, falhano_interactive_desktopcom (não existe nenhuma janela de primeiro plano para injetar) — desbloqueie a sessão ou use um verbo padrão UIA (set-value,invoke). -
As combinações reservadas pelo sistema (
win+l, ,win+r,ctrl+shift+esc,ctrl+alt+del,alt+tab,alt+f4,ctrl+esclonewin/printscreen, ...) atuam no sistema operacional/shell, em vez de apenas no destino quando enviado em todo o sistema operacional.send-inputrejeita-os por padrão (erros cominvalid_argumentse não envia nada) porque injetá-los no nível do sistema operacional tem efeitos muito além da janela de destino (por exemplo,win+lbloquearia a sessão). Passe--allow-system-keyspara aceitar – isso permite que você conduza uma tecla de acesso global, como o PowerToyswin+shift+vouwin+r(o gancho global de baixo nível observa o fluxo de entrada de todo o sistema operacional, de modo que a combinação injetada a dispare). Exceções que permanecem bloqueadas mesmo com--allow-system-keys:win+lbloqueia a estação de trabalho por meioLockWorkStation()da qual é irrecuperável da automação (interrompe as sessões de CI e área de trabalho remota) ectrl+alt+delé uma SAS (Sequência de Atenção Segura) que Windows descarta da entrada injetada independentemente do sinalizador — ela nunca pode entrar em vigor, portanto, ela erros (invalid_arguments, sair 1) em vez de relatar um êxito enganoso. Outras combinações (alt+f4, ,ctrl+shift+esc,win+r...) se tornam permitidas com o sinalizador — cuidado com o chamador. Como alternativa, para fornecer uma combinação do sistema para um uso--via post-messagede janela específico, que tem escopo de janela e não é afetado (uma postagemwin+lé inofensiva, embora uma postagemalt+f4ainda feche a janela de destino).
Eventos por pressionamento de tecla (KeyDown/TextChanged):
-
Chaves nomeadas e combinações modificadoras (
down,enter, ,ctrl+shift+t,vk=0xNN) disparam um realKeyDown(eKeyUp) em ambos os transportes – eles são entregues como eventos discretosWM_KEYDOWN/WM_KEYUP(ouSendInputde chave virtual). -
O texto digitado literal (
hello) difere por transporte:-
--via send-inputmapeia cada caractere para sua chave virtual (mais Shift) no layout do teclado ativo, de modo que o destino veja um originalKeyDowncom a chave virtual correta seguida pelo sistema operacional compostoWM_CHAR(elevandoTextChanged) — ou seja, um pressionamento de tecla completo por caractere. Caracteres não acessíveis no layout atual (ou precisando de Ctrl/AltGr) retornam para um pacote Unicode para que o caractere exato ainda seja aterrissado. Usesend-inputquando precisar de fidelidade por pressionamento de teclaKeyDown(por exemplo, conduzir um WinUI 3/WPFTextBoxcujos manipuladores são desligadosKeyDown). Para um host de teste do WinUI 3 normal (não elevado), coloque sua janela em primeiro plano (winapp ui focus/clicando nele), poissend-inputé direcionada à janela de primeiro plano. -
--via post-messageposta um únicoWM_CHARpor caractere (ele não postaWM_KEYDOWN/WM_KEYUPpara texto digitado — eles são reservados para chaves/combinações nomeadas), o que não gera um por caractereKeyDown. Ele é redirecionado automaticamente para o controle filho focado da janela, de modo que os controles de edição clássicos do Win32/WinForms controladosWM_CHARaterram o texto (levantandoTextChanged). Ressalva: Os aplicativos WinUI 3/ UWP/XAML (destino primário do winapp) têm controles sem janelas que ignoramWM_CHAR/WM_KEYDOWNpostados, portanto , nem texto literal nem chaves nomeadas (Enter, dígitos, ...) os alcançam, mesmo que o comando relata êxito. Ele emite um aviso quando o destino se parece com XAML e ainda sai 0 (PostMessageé fogo e esquece e não pode confirmar a entrega). Use--via send-inputpara conduzir o WinUI 3/ UWP/WPF aplicativos; reservepost-messagepara controles clássicos do Win32 ou quando você só precisar dele com escopo de janela entre os níveis de integridade.
-
Saída JSON (--json): o resultado hwnd é a janela efetiva para a qual as chaves foram entregues, pois --via post-message esse é o controle filho focado resolvido quando o comando é redirecionado a ele (não necessariamente a janela de nível -w/-a/-e superior), para que a automação possa confirmar exatamente onde a entrada pousou. Quando esse destino efetivo se parece com um host XAML sem janelas, a ressalva de entrega acima também é exibida como uma warnings[] entrada (o mesmo aviso mostrado no console), portanto, uma ✅ saída 0 não é confundida com a entrega confirmada.
set-value
Defina um valor em um elemento editável programaticamente (sem pressionamentos de teclas, sem primeiro plano do aplicativo). Usa uma cadeia de fallback:
- ValuePattern — TextBox, ComboBox, PasswordBox e a maioria dos controles editáveis.
- RangeValuePattern — controles numéricos (Controle deslizante, ProgressBar) quando o valor é analisado como um número.
-
LegacyIAccessible (
IAccessible::put_accValue) – o fallback para controles de edição somente TextPattern que não expõem nenhum ValuePattern (por exemplo, rich-edit/Documentcompose boxes). Isso fecha a lacuna de leitura/gravação em queget-valuepoderia ler esse controle, masset-valuenão pôde.
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 puder definir o valor, set-value falhará com um erro claro apontando send-keys como o último recurso.
Nem todos os editores avançados dão suporte ao conjunto programático. O fallback LegacyIAccessible só funciona em controles cujas implementações de acessibilidade – controles nativos
IAccessible::put_accValuewin32 rich-edit e superfícies de composição Chromium/Electron/WebView2 normalmente funcionam. O WinUI 3RichEditBoxe o WPFRichTextBoxnão dão suporte à configuração de valor programática– por meio do design, eles expõem seu conteúdo a Automação da Interface do Usuário como somente leitura (padrão de texto, sem padrão de valor configurável), portantoset-value, não é possível gravar neles. Usesend-keys(que precisa de uma área de trabalho desbloqueada e em primeiro plano) para elas.
get-value
Leia o valor atual de um elemento. Usa uma cadeia de fallback inteligente: TextPattern (RichEditBox, Document) → ValuePattern (TextBox, Slider) → SelectionPattern (ComboBox, RadioButton, TabView) → Name (rótulos).
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 de leitura com êxito retorna "text": "", não seu rótulo de acessibilidade. O conteúdo somente em espaço em branco também é preservado no JSON.
wait-for --value "" corresponde a um campo vazio, seja ele novo ou limpo após a edição. Para ler o rótulo de acessibilidade, use get-property --property Name.
foco
winapp ui focus txt-textbox-a4b1 -a notepad
Ativa a janela do controle selecionado quando necessário e, em seguida, concentra o controle.
O seletor é necessário; use -a <app> ou -w <HWND> escolha o destino.
Êxito significa que a janela estava em primeiro plano e o controle selecionado foi confirmado HasKeyboardFocus antes do comando retornar. O comando permite até 500 ms para o controle relatar o foco; ele será interrompido se o destino desaparecer ou perder o primeiro plano em vez de tentar retomar o foco. Uma caixa de diálogo de propriedade na frente da janela principal não é suficiente: selecione um controle na caixa de diálogo se esse for o seu destino.
Esse comando precisa de uma área de trabalho interativa desbloqueada e não ignora Windows restrições de ativação. Se falhar, foreground_not_targetative manualmente a janela pretendida e verifique se há uma caixa de diálogo de bloqueio antes de tentar novamente.
Para focus_not_acquired, inspecione a interface do usuário atual e escolha um controle focalizável.
Pois stale_element, redescobrir o destino com inspect ou search.
Mantenha o mesmo --on destino nos comandos de descoberta e repetição.
scroll-into-view
Role um elemento para a área visível.
winapp ui scroll-into-view itm-targetitem-c3d4 -a myapp
wait-for
Aguarde até que um elemento apareça, desapareça ou tenha um valor atingindo um destino.
winapp ui wait-for Button -a myapp --timeout 5000 # wait for any button
winapp ui wait-for btn-submit-7a90 -a myapp --timeout 5000 # wait for specific element
winapp ui wait-for CounterDisplay -a myapp --value "5" --timeout 5000 # wait for element value (smart fallback)
winapp ui wait-for lbl-status -a myapp --property Name --value "Done" --timeout 5000 # wait for specific property
winapp ui wait-for btn-submit-a1b2 --gone -a myapp --timeout 2000 # wait for element to disappear
winapp ui wait-for lbl-status -a myapp --value "Done" --contains # substring match instead of exact equality
Rolar a tela
Role um elemento de contêiner. Localize contêineres roláveis com search scroll marcadores ( [scroll:v] 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>— Role incrementalmente por meio deScrollPattern. -
--to <top|bottom>— Vá para o início/fim por meio deScrollPattern. -
--wheel <notches>— Sintetize a entrada da roda do mouse sobre o centro do elemento viaSendInput, em notches de roda (detents):1= um entalhe para cima/para fora,-1= um entalhe para baixo/para cima,3= três entalhes para cima. (Cada entalhe é o WindowsWHEEL_DELTAde 120 unidades queSendInputconsomem; a CLI dimensiona os entalhes em 120 para você.) BypassesScrollPattern.
--direction,--toe--wheelsão mutuamente exclusivos – passe exatamente um. Como--wheelinjeta a entrada de todo o sistema operacional nas coordenadas da tela, ele coloca o destino em primeiro plano e falha (foreground_not_target) se o foco não puder ser transferido, em vez de rolar a janela errada.
se concentrar
winapp ui get-focused -a myapp
winapp ui get-focused -w <HWND> --json
Mostre o elemento que atualmente tem o foco do teclado no aplicativo selecionado, incluindo controles cuja propriedade do aplicativo está disponível apenas por meio da janela pai.
Com -w, o foco deve pertencer a essa janela, não a outra janela ou a um pop-up de propriedade no mesmo processo. Com -aoutras janelas no processo selecionado estão incluídas.
A saída JSON tem hasFocus:false quando nenhum elemento focalizado pode ser verificado como pertencente ao destino. Se uma consulta de foco ou de propriedade de janela falhar, o comando sairá do zero em vez disso; tentar get-focusednovamente e redescobrir a janela com list-windows se ela tiver fechado.
list-windows
Liste todas as janelas visíveis para um aplicativo, incluindo pop-ups e caixas de diálogo. Por padrão, 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
suspender
Libere a interface do usuário desse fluxo de trabalho mais cedo, em vez de aguardar a carência ociosa de quatro segundos. Requer WINAPP_UI_WORKFLOW_ID; não usa nenhum aplicativo e nenhum seletor. Consulte Liberando a curva mais cedo.
winapp ui yield
winapp ui yield --json # {"released": true} — or false when nothing was held
Suporte à estrutura
| Framework | inspecionar | busca | chamar | set-value | captura de tela |
|---|---|---|---|---|---|
| WPF | ✅ Árvore completa | ✅ Todas as propriedades | ✅ Todos os padrões | ✅ ¹ | ✅ |
| WinForms | ✅ | ✅ | ✅ | ✅ | ✅ |
| Win32 | ✅ | ✅ | ✅ | ✅ | ✅ |
| WinUI 3 | ✅ | ✅ | ✅ | ✅ ¹ | ✅ |
| Electron | ⚠️ Árvore chromium | ⚠️ Limitado | ⚠️ Varia | ⚠️ Varia | ✅ |
| Flutter | ⚠️ Básico | ⚠️ Básico | ❌ Mínimo | ❌ | ✅ |
¹ set-value funciona em qualquer controle expondo ValuePattern/RangeValuePattern, além de controles de edição somente TextPattern cujas implementações IAccessible::put_accValue de acessibilidade (fallback LegacyIAccessible).
WinUI 3 RichEditBox e WPF RichTextBox são exceções – elas expõem apenas o padrão de texto somente leitura (sem padrão de valor configurável), portanto, eles não podem ser definidos programaticamente por design; use send-keys (área de trabalho interativa necessária) para digitá-los.
Usando o mecanismo do seu próprio código
Tudo winapp ui o que faz está disponível como uma biblioteca, para que você possa conduzir a mesma automação de um teste ou ferramenta sem desembolsar para a CLI:
| Package | O que ele adiciona |
|---|---|
Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation |
Inspeção, seletores, interação de padrão UIA, injeção de entrada, capturas de tela |
Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation.Recording |
Gravação de vídeo para MP4, além de pacotes de quadros |
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 tomada de sobrecarga 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. As correspondências Exact AutomationId têm precedência sobre o nome ou as subcadeias de caracteres AutomationId; um nome exclusivo ainda pode selecionar um controle cuja AutomationId é compartilhada.
Para um destino com escopo de aplicativo, essa verificação abrange todas as suas janelas de aplicativo/propriedade. Use -w <HWND> (ou um destino de biblioteca de janela explícita) para restringir o escopo de seleção.
Ele retorna Pattern e PerformedAction com os mesmos significados que o resultado da ação da CLI.
Passe um elemento retornado por inspeção ou seleção, com sua lesma de runtime ou AutomationId exclusiva intacta. As ações explícitas rejeitam uma identidade ausente ou ambígua, em vez de se associar novamente por nome e tipo de controle.
Para leituras com escopo, defina UiSelector.Root como outra UiSelector, ControlType como um nome de tipo e ClassName para a classe de provedor literal. Eles usam os mesmos predicados de consulta que a CLI. Há suporte apenas para um nível raiz: selector.Root.Root deve ser null. Uma raiz aninhada é lançada ArgumentException antes de examinar a janela de destino. Use uma AutomationId raiz exclusiva ou uma lesma em vez de aninhar seletores raiz.
UiControlTypes.GetId(name) resolve os nomes de tipo oficiais e os dois aliases documentados, retornando 0 para um nome inválido.
UiControlTypes.GetName(id) retorna o nome canônico ou Unknown(id) para uma ID não reconhecida.
Ao passar um UiElement restaurado de JSON para GetTextAsync ou GetPropertiesAsync, mantenha-o Selector e WindowHandle. Um seletor de lesma ainda deve identificar o elemento original; se ele não existir mais, essas leituras serão lançadas UiElementNotFoundException em vez de selecionar outro elemento com a mesma AutomationId ou nome. Execute a consulta original novamente para atualizar o resultado. As leituras com escopo também propagam falhas de getters gerais de propriedade UIA e padrões UIA adquiridos em vez de retornar valor nulo ou capturado anteriormente.
A gravação é um pacote separado para que os projetos que inspecionam e conduzem apenas a interface do usuário não efetuem pull no SkiaSharp. O pacote de automação destina-se a ambos net10.0-windows e net10.0-windows10.0.19041.0; este último adiciona Windows Captura de Elementos Gráficos, que é o que permite capturar windows compostos screenshot por GPU ou ccluded. Consulte o README de cada pacote no NuGet para obter a API completa e a compensação da estrutura de destino.
UiTarget.FromWindowHandle é o ponto de entrada para estruturas de teste que já lhe dão uma janela , por exemplo MSTest.Windows.UIAutomation, cuja WindowTest.MainWindow É uma UIA2 AutomationElement que você faz a ponte com MainWindow.Current.NativeWindowHandle.
Solução de problemas
| Erro | Cause | Solução |
|---|---|---|
| "Nenhum aplicativo em execução encontrado" | Aplicativo não em execução ou incompatibilidade de nomes | Verificar o nome do processo ou usar o PID |
| "Correspondência de várias janelas" | Valor ambíguo -a |
Usar -w <HWND> nas opções listadas |
| "tem várias janelas" | O processo tem várias janelas | Usar -w <HWND> para direcionar um específico |
| "Elementos N correspondentes do seletor" | Seletor herdado ambíguo | Usar lesmas de inspect saída ou acréscimo [0]a [1] seletores herdados |
| "O elemento pode ter sido alterado" | O hash do Slug não corresponde ao elemento atual |
inspect Executar novamente ou search obter lesmas novas |
| "não dá suporte a nenhum padrão de invocação" | O elemento não pode ser invocado | Usar inspect no elemento para encontrar um filhovokable |
| "Nenhuma janela UIA encontrada" | O UIA não pode ver o processo | Use list-windows para localizar o HWND e, em seguida, -w |
| "Janela tem tamanho zero" | A janela é minimizada | O aplicativo será restaurado automaticamente |
| Pop-up/menu suspenso não está na captura de tela | A captura padrão é por janela e não inclui sobreposições sem proprietário | Siga o fluxo de trabalho de sobreposição de captura de tela para selecionar uma janela com -w <hwnd> --capture-screen |
foreground_not_target do --capture-screen |
Windows recusou a ativação, então uma captura de tela teria gravado qualquer janela na frente | Clique na janela de destino ou feche a janela de roubo de foco e tente novamente ou solte --capture-screen |
element_not_found durante o registro |
Seletor fornecido, mas sem elemento correspondente |
inspect Executar novamente ou search obter um seletor novo |
| WGC indisponível durante o registro | Falha na inicialização da captura do WGC; nenhum fallback silencioso | Verificar GPU/driver; usar --capture-screen para consentir com a captura de tela-DC |
Padrões comuns
Navegar e verificar
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
Localizar texto e invocar 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
Disambiguar elementos duplicados
winapp ui search '#Image' -a myapp; winapp ui invoke itm-image-a2b3 -a myapp
Captura de tela 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, aguardar e verificar (cadeia única)
winapp ui invoke btn-settings-a1b2 -a myapp; winapp ui wait-for pn-settingspage-c3d4 -a myapp --timeout 3000; winapp ui screenshot -a myapp -o settings.png
Descobrir, clicar e verificar
winapp ui inspect -a myapp --interactive; winapp ui invoke btn-submit-7a90 -a myapp; winapp ui screenshot -a myapp
Interação da caixa de diálogo arquivo
As caixas de diálogo de abertura/salvamento de arquivo são caixas de diálogo padrão Windows com suporte do 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 descobrir as lesmas reais para uma caixa de diálogo específica.
Por que ; o encadeamento (não &&)
O operador do && PowerShell pode congelar quando uma CLI nativa grava no stderr ou usa sequências de escape ANSI. Use ; em vez disso : ele executa cada comando incondicionalmente e evita esse deadlock. Isso também é melhor para fluxos de trabalho do agente: você geralmente deseja que a captura de tela seja executada mesmo se a invocação tiver uma saída diferente de zero.
Padrões de teste de CI
Use comandos winapp ui em pipelines de CI (GitHub Actions, Azure DevOps) para testes de fumaça e validação da interface do usuário.
wait-for com --property e --value atua como uma asserção – ele retorna o código de saída 1 no tempo limite, falhando automaticamente na etapa de CI.
Iniciar e testar em 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
Estado do elemento Assert com wait-for
wait-for --value pesquisa até que o valor de um elemento corresponda à cadeia de caracteres esperada, usando o mesmo fallback get-value inteligente que (TextPattern → ValuePattern → SelectionPattern → Name). Retorna o código de saída 0 na correspondência, saia do código 1 no tempo limite, tornando-o uma declaração amigável à CI. Use --property para verificar uma propriedade UIA específica.
# 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
Afirmar com saída JSON
Use --json com o PowerShell ou jq para declarações mais complexas:
Contrato de código de saída para
searchewait-forno--jsonmodo: quando nenhum elemento corresponde (search) ou o tempo limite de espera (wait-for), o comando grava um envelope de resultado totalmente analisável para stdout ({ "matchCount": 0, ... }ou{ "found": false, "timedOut": true, ... }) e retorna o código de saída 1. Stderr está vazio no--jsonmodo (a saída do agente é suprimida). Ramificar nos campos de envelope ou em$LASTEXITCODE, dependendo do qual é 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 tipado usam type e numéricosx, ye widthheight.
Geometria está em pixels de tela física.
0,0,0,0é Automação da Interface do Usuário retângulo vazio/sem exibição da interface do usuário nesta projeção; isOffscreen é separado, portanto, um elemento offscreen ainda pode ter limites diferentes de zero.
Cada inspect --jsonwindows[] entrada e o status --json resultado incluem windowDpi, scale (windowDpi / 96) dpiAwarenesse coordinateSpace: "physical-screen-pixels". Elas descrevem o contexto de DPI da janela de destino, não a DPI de monitor incondicional: Windows relatórios 96 para uma janela sem conhecimento, DPI do sistema para uma janela com reconhecimento do sistema e DPI do monitor atual para uma janela com reconhecimento por monitor. Se o contexto HWND ou DPI não puder ser lido, o comando falhará em vez de substituir silenciosamente 96. Quando status resolve um processo antes de ter uma janela de nível superior, hwnd é 0 e os campos DPI são omitidos até que exista uma janela. Para todo inspecto processo, a janela de destino selecionada permanece com fail-fast; se um pop-up posterior desaparecer após a leitura de sua árvore, sua windows[] entrada carregará dpiError e omitirá os campos de DPI enquanto as árvores de janela restantes ainda serão retornadas.
Consulte as habilidades winapp-ui-automationreferences/ui-json-envelope.md enviadas para obter exemplos completos de cada envelope.
Exemplo de teste de fumaça 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
Windows developer