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); ui click é a exceção e usa a simulação real do mouse para controles que não dão suporte InvokePattern.

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

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. 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."

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

Commands

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

captura de tela

Capture uma janela ou elemento como PNG. Quando várias janelas existem (por exemplo, aplicativo + caixa de diálogo aberta), elas são compostas em um único PNG com cada janela costurada.

winapp ui screenshot -a notepad                     # saves screenshot.png in cwd
winapp ui screenshot -a notepad --output my.png     # custom filename
winapp ui screenshot -a notepad --json              # returns file path as JSON
winapp ui screenshot -w 131906                      # target specific HWND (+ its dialogs)
winapp ui screenshot txt-searchbox-e5f6 -a myapp          # crop to element bounds
winapp ui screenshot -a myapp --capture-screen      # capture from screen (includes popups/overlays)

Quando caixas de diálogo ou pop-ups estão abertos, todas as janelas são compostas em um PNG para que você possa ver o estado completo da interface do usuário em uma única imagem.

Use --capture-screen quando precisar capturar menus pop-up, listas suspensas, submenus ou sobreposições de dica de ferramenta. No --capture-screen modo (e ao tentar novamente depois que um quadro em branco é detectado), a janela de destino é trazida para o primeiro plano; as capturas de janela normais não movem a janela.

chamar

Ative programaticamente um elemento (clique no botão, alterne a caixa de seleção, expanda a caixa de combinação).

winapp ui invoke btn-submit-7a90 -a myapp             # by slug from inspect
winapp ui invoke btn-submit-a1b2 -a myapp  # by slug from inspect/search
winapp ui invoke cmb-sizecombobox-b4c5 -a myapp # expand combo box

Tenta padrões em ordem: InvokePattern → TogglePattern → SelectionItemPattern → ExpandCollapsePattern.

click

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

set-value

Defina um valor em um elemento editável (texto para TextBox/ComboBox, número para Controle Deslizante).

winapp ui set-value txt-textbox-a4b1 "Hello world" -a notepad
winapp ui set-value sld-volume-b2c3 75 -a myapp

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": "..." }

foco

Mova o foco do teclado para um elemento.

winapp ui focus txt-textbox-a4b1 -a notepad

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

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

se concentrar

Mostrar o elemento que atualmente tem o foco do teclado.

winapp ui get-focused -a myapp

list-windows

Liste todas as janelas visíveis para um aplicativo, incluindo pop-ups e caixas de diálogo.

winapp ui list-windows -a imageresizer
winapp ui list-windows -a Terminal
winapp ui list-windows                                      # all windows (no filter)

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

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 PrintWindow não captura sobreposições Usar --capture-screen sinalizador

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 set-value txt-searchbox-e5f6 "query" -a myapp; winapp ui screenshot -a myapp --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)" }

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