Automação de UI

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 de inspect para 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 pela inspectprofundidade 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ão TextBox → Edit e TextBlock → Text. Nomes desconhecidos (incluindo IDs numéricas e expressões curinga) falham com invalid_arguments.
  • --class-name <literal> corresponde a todo o UIA ClassNamedo provedor, ignorando maiúsculas e minúsculas. Não é uma subcadeia de caracteres, curinga ou expressão regular. Use get-property --property ClassName para 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_ID para 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 yield em 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 yield ou 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 sai 130.
  • Somente binários atualizados compatíveis cooperam. Builds mais antigos winapp antecedem 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-screen precisa 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 -a corresponde a várias janelas de nível superior ou de propriedade, não há essa seleção, portanto, o comando falha invalid_arguments antes de capturar qualquer coisa em vez de lutar contra o primeiro plano. Execute winapp ui list-windows -a <app> e tente novamente com -w <hwnd>, ou solte --capture-screen para 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 record ID 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 mesmo WINAPP_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_busy seu 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 com invalid_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

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)

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 se foreground_not_target nã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-screen aplica 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. Usa recording-<timestamp>-<guid>.mp4 como 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-edge 64-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-screen usar 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-started evento 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; inspecionar partialOutput e recoveryHint.

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, click traz o destino para o primeiro plano e falha rapidamente (no_interactive_desktop em uma área de trabalho bloqueada/segura, foreground_not_target se 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 falha target_moved em 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,y são coordenadas de tela no mesmo relatório de espaço winapp ui inspect/search e um seletor é resolvido para o centro do elemento – inspecione primeiro para escolher pontos.

Por exemplo send-keys --via send-input, drag injeta 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 com no_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_moved em vez de arrastar para um ponto obsoleto. (Pontos x,y de 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 um swipe. Tem precedência sobre --direction.
  • --direction <right|left|up|down> — Direção do dedo (padrão: right). Combinado com --distance a computação do ponto de extremidade quando --to-point não é dado.
  • --distance <px> — Propagação do dedo para, ou deslize o dedo para pinch/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 para long-press quando 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 / stretch sempre use 2.

Segurança de injeção. touch recusa-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_target quando nenhuma janela puder ser resolvida, foreground_not_target se o foco não puder ser transferido ou no_interactive_desktop em 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 (uma warnings[] 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. --fingers acima 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, touch acrescenta um aviso de incerteza de entrega – uma warnings[] 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 com ui screenshot/ui inspect quando 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 separados x,y por 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 exemplotouch, pen recusa-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, pen acrescenta 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, altwin unidas 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 como C++ ou a+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=enter digita a palavra "enter" em vez de pressionar Enter e text=ctrl+a digita a cadeia de caracteres literal. Espelha a vk= 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 um text= valor para digitar espaço em branco que de outra forma não sobreviveria: \s → espaço, \t guia →, \n → nova linha, \r → nova linha → \\ barra invertida literal. \n, \re \r\n cada um insere uma única quebra de linha (um Enter/ VK_RETURN), assim text=line1\nline2 e text=line1\r\nline2 ambos digitam uma nova linha. Portanto, text=a\s\sb digita "a b" (espaço duplo) e text=\shi manté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 --verbatim em vez de escapar de cada token com text=. 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.\s Portanto send-keys "down down enter" --verbatim , digita as palavras e send-keys "a b" --verbatim mantém o espaço duplo. Escapes de barra invertida não são decodificados no --verbatim modo (um \s é digitado como uma barra invertida e um "s"); use um text= token quando precisar de um caractere de controle com escape.
  • Chaves virtuais brutas — vk=0xNN (hex) ou vk=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 token text= .
  • --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-input injeta todo o sistema operacional e SendInput vai 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 meio WH_KEYBOARD_LL de 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 meio GetAsyncKeyState podem não observar modificadores mantidos. Ele resolve e posta automaticamente na janela filho focada do thread de destino (via GetGUIThreadInfo) 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 publicado WM_CHAR/WM_KEYDOWN nã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-input produz entrada totalmente real (modificadores visíveis para GetAsyncKeyState, 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). Se send-input relatar uma falha, o destino provavelmente será elevado ou um aplicativo AppX – use post-messageou execute a CLI em um nível de integridade correspondente. Como proteção de segurança, send-input verifica 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, falha no_interactive_desktop com (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+esclone win/printscreen, ...) atuam no sistema operacional/shell, em vez de apenas no destino quando enviado em todo o sistema operacional. send-input rejeita-os por padrão (erros com invalid_arguments e 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+l bloquearia a sessão). Passe --allow-system-keys para aceitar – isso permite que você conduza uma tecla de acesso global, como o PowerToys win+shift+v ou win+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+l bloqueia a estação de trabalho por meio LockWorkStation() da qual é irrecuperável da automação (interrompe as sessões de CI e área de trabalho remota) e ctrl+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 postagem win+l é inofensiva, embora uma postagem alt+f4 ainda 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 real KeyDown (e KeyUp) em ambos os transportes – eles são entregues como eventos discretos WM_KEYDOWN/WM_KEYUP (ou SendInput de chave virtual).
  • O texto digitado literal (hello) difere por transporte:
    • --via send-input mapeia cada caractere para sua chave virtual (mais Shift) no layout do teclado ativo, de modo que o destino veja um original KeyDown com a chave virtual correta seguida pelo sistema operacional composto WM_CHAR (elevando TextChanged) — 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. Use send-input quando precisar de fidelidade por pressionamento de tecla KeyDown (por exemplo, conduzir um WinUI 3/WPF TextBox cujos 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), pois send-input é direcionada à janela de primeiro plano.
    • --via post-message posta um único WM_CHAR por caractere (ele não posta WM_KEYDOWN/WM_KEYUP para texto digitado — eles são reservados para chaves/combinações nomeadas), o que não gera um por caractere KeyDown. Ele é redirecionado automaticamente para o controle filho focado da janela, de modo que os controles de edição clássicos do Win32/WinForms controlados WM_CHARaterram o texto (levantando TextChanged). Ressalva: Os aplicativos WinUI 3/ UWP/XAML (destino primário do winapp) têm controles sem janelas que ignoram WM_CHAR/WM_KEYDOWN postados, 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-input para conduzir o WinUI 3/ UWP/WPF aplicativos; reserve post-message para 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:

  1. ValuePattern — TextBox, ComboBox, PasswordBox e a maioria dos controles editáveis.
  2. RangeValuePattern — controles numéricos (Controle deslizante, ProgressBar) quando o valor é analisado como um número.
  3. LegacyIAccessible (IAccessible::put_accValue) – o fallback para controles de edição somente TextPattern que não expõem nenhum ValuePattern (por exemplo, rich-edit/ Document compose boxes). Isso fecha a lacuna de leitura/gravação em que get-value poderia ler esse controle, mas set-value nã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_accValue win32 rich-edit e superfícies de composição Chromium/Electron/WebView2 normalmente funcionam. O WinUI 3 RichEditBox e o WPF RichTextBox nã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. Use send-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 de ScrollPattern.
  • --to <top|bottom> — Vá para o início/fim por meio de ScrollPattern.
  • --wheel <notches> — Sintetize a entrada da roda do mouse sobre o centro do elemento via SendInput, 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 Windows WHEEL_DELTA de 120 unidades que SendInput consomem; a CLI dimensiona os entalhes em 120 para você.) Bypasses ScrollPattern.

--direction, --toe --wheel são mutuamente exclusivos – passe exatamente um. Como --wheel injeta 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

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
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 search e wait-for no --json modo: 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 --json modo (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