Automatyzacja interfejsu użytkownika

Sprawdzanie i interakcja z uruchamianiem aplikacji Windows z poziomu wiersza polecenia. Używane przez agentów sztucznej inteligencji i deweloperów do testowania, debugowania i automatyzacji interfejsu użytkownika.

Przegląd

winapp ui udostępnia polecenia do inspekcji i interakcji z interfejsami użytkownika aplikacji Windows. Używa Windows automatyzacja interfejsu użytkownika (UIA). Współpracuje z dowolną aplikacją Windows — WPF, WinForms, Win32, Electron i WinUI 3. Większość poleceń napędza aplikację za pomocą wzorców interfejsu użytkownika (bez iniekcji danych wejściowych). Wyjątki wprowadzają rzeczywiste dane wejściowe: ui click/ui hoverui drag/używaj symulacji myszy,/ui touchui pen syntetyzują dane wejściowe dotyku i pióra/rysika oraz ui send-keys syntetyzują dane wejściowe klawiatury — w przypadku kontrolek i scenariuszy, których wzorce UIA nie mogą prowadzić.

Important

Wymaganie dotyczące pulpitu interakcyjnego (czasowniki iniekcji danych wejściowych).click, hover, dragtouch, pen, scroll --wheeli send-keys --via send-input syntetyzują dane wejściowe na poziomie systemu operacyjnego, więc potrzebują odblokowanego, interaktywnego pulpitu z oknem docelowym na pierwszym planie. Na zablokowanej stacji roboczej lub bezpiecznym pulpicie (LogonUI/UAC) nie mogą wstrzyknąć i szybko zakończyć się niepowodzeniem no_interactive_desktop (różni się od podniesienia uprawnień/foreground_not_target przypadków). touch / penponadto odrzucanie, gdy okno nie zostanie rozpoznane (no_target); współrzędna poza oknem docelowym jest ostrzeżeniem niekrytycznym (wpis w --jsontrybie tekstowym lub wierszem ostrzegawczym) i iniekcja jest nadal kontynuowana — warnings[] zgodnie z czasownikami myszy. Wszystkie inne — inspect, , search, get-valueinvokeget-propertyset-valuescroll --direction/--towait-forscreenshot — napędza aplikację za pomocą wzorców interfejsu użytkownika i są przyjazne dla sesji bezgłowych/zablokowanych. Preferuj czasowniki wzorca UIA w ciągłej integracji; zarezerwować czasowniki iniekcji dla scenariuszy, które naprawdę potrzebują rzeczywistych danych wejściowych. Przed wstrzyknięciem czasowniki gestu również ponownie rozpoznają element docelowy i odmówić, target_moved jeśli nadal animuje/przenosi się, zamiast lądować dane wejściowe w pustym miejscu.

Szybki start

# 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

Określanie wartości docelowej aplikacji

Według nazwy procesu

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

Według tytułu okna

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

Według identyfikatora PID

winapp ui inspect -a 12345

Przez HWND (stabilny — przetrwa zmiany tabulatora/tytułu)

# 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

Służy -a do odnajdywania w -w celu uzyskania stabilnego określania wartości docelowej. Gdy -a pasuje do wielu okien, polecenie wyświetla je z HWNDs, które chcesz wybrać.

Selektory

Elementy docelowe przy użyciu selektora wyświetlanego w [brackets] danych wyjściowych inspekcji/wyszukiwania. Istnieją trzy typy selektorów:

Selector Znaczenie Example
MinimizeButton AutomationId (wyświetlany, gdy unikatowy — stabilny, preferowany) winapp ui invoke MinimizeButton -a myapp
btn-close-d1a0 Slug semantyczny (pokazany, gdy nie ma unikatowego identyfikatora AutomationId) winapp ui invoke btn-close-d1a0 -a myapp
Submit Wyszukiwanie w postaci zwykłego tekstu względem parametru Name/AutomationId (podciąg bez uwzględniania wielkości liter) winapp ui invoke Submit -a myapp

Selektory AutomationId to identyfikatory zestawu deweloperów (AutomationProperties.AutomationId w języku XAML). Gdy identyfikator AutomationId jest unikatowy w całym drzewie interfejsu inspect użytkownika i search wyświetla go bezpośrednio jako selektor — te zmiany układu przetrwania, lokalizacja i restrukturyzacja drzewa.

Selektory Slug (np. ) są generowane, btn-close-d1a0gdy nie istnieje unikatowy identyfikator AutomationId. Format: prefix-name-hash. Skrót weryfikuje tożsamość elementu, ale może przestarzał po zmianie interfejsu użytkownika.

Sprawdzanie formatu danych wyjściowych

Polecenie inspect wyświetla drzewo elementów z kolorowymi danymi wyjściowymi (selektor w cyjanku, nazwa na zielono, metadane w kolorze szarym):

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

Pierwszym wyrazem w każdym wierszu jest selektor — użyj go z innymi ui poleceniami. Gdy element ma unikatowy identyfikator AutomationId, jest używany bezpośrednio (np. TabView, NewTabButton). Jeśli nie istnieje unikatowy identyfikator AutomationId, jest używany wygenerowany ślimak (np. tab-newtab-5f5b).

Slugi semantyczne

Slugi używają formatu: prefix-normalizedname-hash gdzie:

  • prefiks — 3-literowy skrót typu (btn, txt, chk, cmb, itm, tab, img, lbl, pn, win, grp, lnk, mnu itp.)
  • normalizedname — małe litery alfanumeryczne z identyfikatora AutomationId (preferowane) lub nazwa, maksymalnie 15 znaków
  • hash — skrót 4-znakowy skrót szesnastkowy identyfikatora RuntimeId elementu (weryfikuje tożsamość elementu)

Slugi są bezpieczne za pomocą powłoki (bez znaków specjalnych), unikatowe i mogą być używane bezpośrednio jako argumenty. Skrót zapewnia wykrywanie nieaktualności — jeśli element został zastąpiony, otrzymasz: "Element mógł ulec zmianie. Uruchom ponownie inspekcję".

Elementy bez nazwy lub AutomationId pokazują tylko prefiks + skrót (np. pn-c8a3).

Uściślanie wielu dopasowań

Slugi z inspect/search danych wyjściowych są unikatowe, ale mogą zmieniać się między zmianami układu — używają ich w zwykłych nazwach typów lub tekście, gdy wiele dopasowań. Gdy selektor jest niejednoznaczny, interfejs wiersza polecenia drukuje wszystkie dopasowania ze swoimi ślimakami, aby można było wybrać właściwy i ponownie uruchomić z tym ślimakiem.

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

Użyj zwykłego tekstu, aby wyszukać elementy — nie jest wymagana żadna specjalna składnia:

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

Gdy wyszukiwanie tekstu pasuje do wielu elementów (np. SettingsExpander, gdzie grupa, przycisk i tekst mają taką samą nazwę), interfejs wiersza polecenia automatycznie wybiera jedyny element wywołujący. Jeśli wiele jest wywoływanych, wyświetla listę wszystkich dopasowań z ślimakami.

W przypadku wyników wyszukiwania niepodwoływalnych (np. textblock wewnątrz przycisku) wyszukiwanie automatycznie wyświetla najbliższy nadrzędny element — element nadrzędny, którego można użyć z elementem invoke. Działa to dla wszystkich selektorów wyszukiwania:

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

Selektor powierzchniowy może być używany bezpośrednio:

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

Komendy

stan

Połącz się z aplikacją i pokaż informacje o połączeniu.

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

Sprawdzić

Wyświetl drzewo elementów interfejsu użytkownika. Dane wyjściowe pokazują semantycznie slugi z wcięciem 2-spacji dla hierarchii:

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

Przykładowe dane wyjściowe (wartość domyślna):

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)

Przykładowe dane wyjściowe (--interactive — tylko elementy, lista płaska):

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)

Elementy mogą pokazywać następujące znaczniki stanu:

  • [on] / [off] / [indeterminate] — stan przełącznika/pola wyboru
  • [collapsed] / [expanded] — stan rozwijania/zwijania drzew, pól kombi, elementów menu
  • [scroll:v] / [scroll:h] / [scroll:vh] — kontener przewijany (pionowy, poziomy lub oba)
  • [offscreen] — element nie jest widoczny na ekranie
  • [disabled] — element nie jest włączony
  • value="..." — bieżąca zawartość tekstowa elementów edytowalnych (gdy różni się od nazwy)

Znajdowanie elementów pasujących do selektora. Dane wyjściowe pokazują semantycznie slugi:

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

Przykładowy wynik:

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

Slugi wyświetlane w danych wyjściowych (np. btn-minimize-d1a0) mogą być używane bezpośrednio z innymi poleceniami:

winapp ui invoke btn-minimize-d1a0 -a notepad

get-property

Odczytywanie wartości właściwości z elementu. Obejmuje stan specyficzny dla wzorca (ToggleState, Value, IsSelected itp.).

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

zrzut ekranu

Przechwyć okno lub element jako PNG. Gdy istnieje wiele okien (np. aplikacja + otwarte okno dialogowe), są one złożone w jeden plik PNG z każdym oknem zeszytymi.

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; foregrounds window)
winapp ui screenshot -a myapp --focus               # bring window to foreground first, then capture (default WGC path)

Gdy okna dialogowe lub wyskakujące okienka są otwarte, wszystkie okna są złożone w jeden plik PNG, dzięki czemu można zobaczyć pełny stan interfejsu użytkownika w jednym obrazie.

Domyślna ścieżka przechwytywania używa Windows. Graphics.Capture (WGC) odczytywanie rzeczywistej powierzchni złożonej DWM — zachowanie zaokrąglonych narożników, przezroczystości i pracy nawet wtedy, gdy okno jest okludnione przez inne windows. Jeśli usługa WGC jest niedostępna (starsze Windows kompilacje), interfejs wiersza polecenia wraca do usługi PrintWindow.

Użyj --capture-screen polecenia , gdy musisz przechwytywać menu podręczne, listy rozwijane, wysuwane lub nakładki etykietek narzędzi, które nie są własnością okna docelowego. --capture-screen odczytuje z kontrolera domeny ekranu i najpierw przenosi okno na pierwszy plan. Użyj --focus polecenia , jeśli chcesz po prostu na pierwszym planie okna bez przełączania trybów przechwytywania (np. aby upewnić się, że zrzut ekranu jest zgodny z tym, co aktualnie patrzy użytkownik).

rekord

Zarejestruj okno docelowe (lub region elementu) na wideo H.264 MP4. Ramki są przechwytywane za pośrednictwem funkcji przechwytywania grafiki Windows (z rezerwowym elementem PrintWindow/screen-DC) i kodowane przyrostowo za pomocą programu Media Foundation, więc nagrania nigdy nie buforują pełnego wideo w pamięci.

Zachowanie domyślne (--duration-sec 0): rejestruje rekordy do momentu zatrzymania. Użyj kombinacji klawiszy Ctrl+C interaktywnie lub (w przypadku programowych/ wywołujących agentów) napisz nowy wiersz do stdin lub zamknij stdin, aby zatrzymać i sfinalizować MP4 bezpiecznie. Prawidłowy, odtwarzany MP4 jest zawsze sfinalizowany na każdym łaskawym zatrzymaniu — bez uszkodzenia.

# Timed: record for 10 s at 15 fps
winapp ui record -a myapp --duration-sec 10 --fps 15 --output demo.mp4

# Unbounded (default): record until Ctrl+C, downscaled to max 1280px longest edge
winapp ui record -a myapp --max-edge 1280 --output capture.mp4

# Programmatic stop (agent/script): pipe a newline; the recorder stops and writes a valid MP4
"" | winapp ui record -a myapp --json --output capture.mp4

# Record a single element's region (fails with element_not_found if the selector doesn't match)
winapp ui record itm-chart-9f8e -a myapp --output chart.mp4

# Include screen overlays / popups (captures from screen DC; brings window to foreground)
winapp ui record -a myapp --capture-screen --duration-sec 5 --output with-popups.mp4

Opcje:

  • --duration-sec N — rekord przez N sekund. Wartość domyślna 0 = rekord do momentu zatrzymania.
  • --fps N — ramki docelowe na sekundę (domyślnie 15).
  • --max-edge N — Skalowanie w dół, tak aby najdłuższa krawędź wynosi najwyżej N pikseli (0 = bez skalowania w dół).
  • --capture-screen — Przechwytywanie z kontrolera domeny ekranu (obejmuje nakładki/wyskakujące okienka; pierwszego planu).
  • --output <path> — ścieżka mp4 danych wyjściowych. Wartość domyślna to recording-<timestamp>-<guid>.mp4 w bieżącym katalogu.

Zatrzymaj mechanizmy:

  • Interakcyjne: Ctrl+C (dowolna platforma).
  • Programowy/agent: napisz nowy wiersz ("") lub zamknij stdin (EOF). Zatrzymanie jest stosowane natychmiast po zakończeniu kodera (przechwycona pierwsza ramka); każdy sygnał zatrzymania, który pojawia się przed pierwszą ramką jest zatrzaśnięty i stosowany natychmiast w gotowości — nie ma okna łaski i nie ma opóźnienia zegara ściany.

Tryby przechwytywania (zgłoszone w polu JSON mode ):

  • wgc— Windows przechwytywania grafiki (ustawienie domyślne; działa, gdy okno jest okludne).
  • printwindow — GDI PrintWindow (powrót, gdy usługa WGC jest niedostępna w tym systemie/sesji; uruchom ponownie polecenie , --capture-screen aby zamiast tego użyć kontrolera domeny ekranu).
  • screen — Kontroler domeny ekranu za pośrednictwem ( --capture-screen obejmuje nakładki/wyskakujące okienka; przenosi okno na pierwszy plan).

Dane wyjściowe JSON (--json):

  • stdout (wynik końcowy): { "path", "frames", "width", "height", "fileSize", "codec": "h264", "mode", "fps", "durationSec" }
  • stderr (zdarzenie liveness, emitowane po rozpoczęciu przechwytywania): { "event": "recording-started", "path", "fps", "durationSec" }

Zdarzenie liveness na stderr pozwala programowym wywołującym wiedzieć, że pętla przechwytywania jest aktywna bez oczekiwania na końcowy wynik. Końcowy wynik JSON w stdout jest pojedynczym czystym obiektem.

Kody błędów:

  • element_not_found — Selektor podany, ale nie znaleziono pasującego elementu; natychmiast kończy się niepowodzeniem (nie zapisano pliku częściowego).
  • ambiguous_selector — Selektor zwykłego tekstu pasował do wielu elementów; użyj sluga z sugestii wyświetlanych w błędzie (lub z inspect danych wyjściowych), aby wskazać określony element.
  • invalid_arguments — Nieprawidłowa wartość opcji (np. --duration-sec -1 lub > 86400).

Znane ograniczenie — wyskakujące okienka: Podczas rejestrowania określonego elementu (selektora), który znajduje się wewnątrz okna podręcznego, które renderuje się we własnym oknie najwyższego poziomu — np. okna wysuwanego WinUI/XAML, porada dydaktyczna, etykietka narzędzia lub menu (Xaml_WindowedPopupClass) — rejestrator może przechwytywać podstawowe okno główne zamiast okna podręcznego, tworząc puste lub przestarzałe ramki. Zarejestruj całe okno (pomiń selektor) lub użyj winapp ui screenshot --capture-screen w przypadku okien podręcznych. Śledzone w 646.

Programowe aktywowanie elementu (kliknij przycisk, przełącz pole wyboru, rozwiń pole kombi).

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

Próbuje wzorce w kolejności: InvokePattern → TogglePattern → SelectionItemPattern → ExpandCollapsePattern.

click

Kliknij element na jego ekranie współrzędnych przy użyciu symulacji myszy. Służy do kontrolek, które nie obsługują InvokePattern (np. nagłówki kolumn, elementy listy).

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

Podobnie jak inne czasowniki wstrzykiwania danych wejściowych, click przenosi element docelowy na pierwszy plan i szybko kończy się niepowodzeniem (no_interactive_desktop na zablokowanym/bezpiecznym pulpicie, foreground_not_target jeśli nie można przenieść fokusu) zamiast klikać nieprawidłowe okno. Usuwa również ponownie element tuż przed przyciskiem w dół: po ustawieniu kursora wykonuje jedno końcowe sprawdzanie położenia, więc stale przesuwający się/animujący element docelowy kończy się niepowodzeniem target_moved zamiast raportowania powodzenia po kliknięciu wylądował na pustym miejscu — zgłoszony sukces oznacza, że cel był nadal w miejscu, gdy przycisk spadł.

przeciągnąć

Naciśnij przycisk myszy w jednym momencie, przejdź do innego, a następnie zwolnij element za drag <from> <to>pomocą polecenia , gdzie każdy punkt końcowy jest selektorem elementów (przeciąga się z/do środka elementu) lub współrzędnych x,yekranu dokładnie zgodnie z raportem.winapp ui inspect Mieszaj i dopasuj swobodnie (selektor→selector, selektor→koordy, współordy→koordy).

Używa z SendInput ruchami pośrednimi, aby aplikacja widziała realistyczny strumień komunikatów WM_MOUSEMOVE . Służy do zmieniania kolejności/zmieniania rozmiaru uchwytów, suwaków, rysunku kanwy i przeciągania i upuszczania.

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

Opcje:

  • --right — przeciągnij prawym przyciskiem myszy zamiast lewego przycisku.
  • --hold-ms <ms> — Przytrzymaj przycisk w dół na początku przed przeniesieniem (ustawienie domyślne: 0). Z <from> == <to> (bez ruchu) wykonuje gest naciśnięcia i trzymania / długiego naciśnięcia .
  • --dwell-ms <ms> — Mieszkaj w miejscu docelowym po przeniesieniu, przed zwolnieniem (wartość domyślna: 0). Pozwala upuścić elementy docelowe /scalać nakładki , które uzbrajają się z trwałego aktywowania (a nie natychmiast pojawia się kursor) zatrzasnąć przed przyciskiem.

Słupki x,y są współrzędnymi ekranu w tym samym raporcie spacji winapp ui inspect/search , a selektor rozpoznaje środek elementu — najpierw sprawdź punkty, aby wybrać punkty.

Podobnie jak send-keys --via send-input, drag wstrzykuje współrzędne systemu operacyjnego na ekranie po doprowadzeniu celu na pierwszy plan. Jeśli nie można skierować fokusu do miejsca docelowego (np. zapobiegania kradzieży fokusu z procesu w tle), polecenie kończy się niepowodzeniem (foreground_not_target) zamiast przeciągania na niewłaściwe okno — fokus lub kliknij okno jako pierwsze. Na zablokowanym/bezpiecznym pulpicie kończy się niepowodzeniem z programem no_interactive_desktop. Każdy punkt końcowy elementu jest rozpoznawany ponownie bezpośrednio przed przeciągnięciem; Jeśli nadal przenosi się/zmienia rozmiar (animowanie elementu docelowego), polecenie kończy się niepowodzeniem target_moved zamiast przeciągania do nieaktywnego punktu. x,y(Nie można ponownie zweryfikować bez punktów końcowych, więc są używane as-is).

Dotyk

Wstrzykiwanie syntetycznych gestów dotykowych przy użyciu interfejsu API wstrzykiwania wskaźnika Windows. Kotwica kontaktu jest selektorem elementów (używa środka elementu) lub jawną współrzędną x,yekranu za pośrednictwem --at (te same raporty spacjiwinapp ui inspect). Użyj go do interakcji naciśnięcia/naciśnięcia i gestów wielodotyku, których symulacja myszy nie może wyrazić.

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)

Opcje:

  • --gesture <g>tap (ustawienie domyślne), double-tap, long-press, swipe, pinch. stretch
  • --at <x,y> — jawny punkt początkowy (współrzędne ekranu). Domyślnie jest to środek elementu selektora.
  • --to-point <x,y> — Punkt końcowy dla elementu swipe. Ma pierwszeństwo przed --direction.
  • --direction <right|left|up|down> — Kierunek przesunięcia (ustawienie domyślne: right). W połączeniu z elementem --distance w celu obliczenia punktu końcowego, gdy --to-point nie zostanie podany.
  • --distance <px> — Rozrzuć palcem na pinch/stretchodległość w pikselach lub machnięcia.
  • --hold-ms <ms> — Przytrzymaj kontakty w dół przed zniesieniem (czas wstrzymania długiego naciśnięcia; wartość domyślna to 500 ms, long-press jeśli nie jest ustawiona).
  • --duration-ms <ms> — Czas ślizgu dla ruchliwych gestów (szybkie przesunięcie/szczypta/rozciągnięcie; wartość domyślna 300).
  • --fingers <n> — liczba kontaktów (1–10; wartość domyślna 1). pinch / stretch zawsze używaj 2.

Bezpieczeństwo iniekcji. touch odmawia wstrzyknięcia, chyba że uchwyt okna docelowego niezerowego zostanie rozwiązany i to okno zawiera pierwszy plan — kończy się niepowodzeniem no_target , gdy nie można rozpoznać okna, foreground_not_target jeśli nie można przenieść fokusu lub no_interactive_desktop na zablokowanym/bezpiecznym pulpicie. Każda współrzędna (środek elementu, jawne --at/--to-pointi wygenerowane punkty waypoints) jest sprawdzana względem prostokąta okna docelowego. Punkt poza oknem jest przedstawiany jako ostrzeżenie niekrytyczne (warnings[]wpis w --jsonlub wiersz ostrzeżenia w trybie tekstowym) i iniekcja nadal następuje — dopasowanie czasowników myszy (drag/scrollclick/hover/), które również wprowadza współrzędne poza oknem. --fingers powyższe 10 jest odrzucane z góry.

Uwaga sprzętowa. Funkcja Touch preferuje nowoczesne urządzenie wskaźnika syntetycznego (CreateSyntheticPointerDevice(PT_TOUCH)) i wraca do starszego InitializeTouchInjection/InjectTouchInput interfejsu API. Jeśli iniekcja jest nieobsługiwana na bieżącym urządzeniu/sesji, polecenie wyświetla rzeczywisty kod błędu Win32 (np. "nieobsługiwany") zamiast zgłaszać fałszywe powodzenie — traktuj wyjście niezerowe jako "nie dostarczono dotyku".

Remote Desktop/sesje maszyn wirtualnych. W przypadku Remote Desktop (RDP) lub niektórych sesji maszyny wirtualnej system operacyjny może zaakceptować syntetyczne dotknięcie (wyjście 0) bez dotarcia do aplikacji docelowej. Po wykryciu touch sesji zdalnej dołącza ostrzeżenie dotyczące niepewności dostarczaniawarnings[] wpis w --jsonsystemie lub wiersz ostrzeżenia w trybie tekstowym. / ✅exit 0 oznacza następnie wywołanie iniekcji powiodło się, a nie , że aplikacja otrzymała dane wejściowe; potwierdź efekt ui screenshot/ui inspect , gdy ma znaczenie.

długopis

Wstrzykiwanie syntetycznych danych wejściowych pióra/rysika — naciśnięcia i pociągnięcia atramentu — przy użyciu interfejsu API Windows syntetycznego wskaźnika (CreateSyntheticPointerDevice(PT_PEN); Windows 10 1809+). Wyceluj w środek elementu, punkt jawny --at lub pełny --path pociągnięcie pisma odk.

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

Opcje:

  • --at <x,y> — Punkt styku pióra (współrzędne ekranu). Domyślnie jest to środek elementu selektora. Ignorowane, gdy --path zostanie podane.
  • --path "<x,y x,y …>" — Ścieżka pociągnięć pisma od pisma od ręcznego jako pary rozdzielane x,y odstępami (ścieżka jednopunktowa jest naciśnięciem).
  • --pressure <0.0–1.0> — Ciśnienie pióra (domyślnie 0,5).
  • --tilt-x <deg> / --tilt-y <deg> — Kąty pochylenia pióra, od −90 do 90 (domyślnie 0).
  • --eraser — Użyj końca gumki pióra zamiast końcówki.
  • --duration-ms <ms> — Łączny czas podróży pociągnięcia w milisekundach dystrybuowany jako interpolowane ramki AKTUALIZACJI w ścieżce (wartość domyślna: ~10 ms w punkcie drogi). Użyj tej funkcji, aby kontrolować, jak szybko pióro wyraźnie porusza się od początku do końca.

Bezpieczeństwo iniekcji. Podobnie jak touch, pen odmawia wstrzykiwania bez zera, pierwszego planu okna docelowego (no_target / foreground_not_target / no_interactive_desktop) i sprawdza każdy punkt pisma odręcznego względem prostokąta okna docelowego, wyświetlając dowolną współrzędną poza oknem jako ostrzeżenie niekrytyczne (warnings[] w --json, lub w wierszu ostrzeżenia w trybie tekstowym) podczas wstrzykiwania — zgodne z czasownikami myszy. Nieprawidłowe --pressure (poza 0.0–1.0) lub przechylenie (na zewnątrz ±90°) są odrzucane z góry.

Remote Desktop/sesje maszyn wirtualnych. Routing piórem jest szczególnie zawodny w przypadku Remote Desktop: wywołanie iniekcji może zgłosić powodzenie (wyjście 0), podczas gdy żadne dane wejściowe pióra nie docierają do aplikacji. Po wykryciu pen sesji zdalnej dołącza ostrzeżenie o niepewności dostarczania (warnings[] w systemie lub wierszu ostrzeżenia w --jsontrybie tekstowym), dzięki czemu ✅ potwierdzenie dostarczenia nie jest mylące. Zweryfikuj przepływy zależne od pióra na lokalnym, interaktywnym pulpicie.

wskaźnik aktywowania

Przenieś wskaźnik myszy na środek elementu, aby wyzwolić efekty aktywowania (etykietki narzędzi, wysuwane, stany wizualne). Używa SendInput do realistycznego ruchu myszy z małym przełącznikiem, a następnie czeka na konfigurowalny czas zamieszkania.

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 hover btn-info-a1b2 -a myapp; winapp ui screenshot -a myapp --capture-screen  # hover then capture tooltip

Opcje:

  • --dwell-time <ms> — czas w milisekundach oczekiwania po umieszczeniu wskaźnika myszy na wyświetlaniu efektów (wartość domyślna: 800, zakres: 0–10000)

send-keys

Wysyłanie syntetycznych danych wejściowych klawiatury — odpowiednik klawiatury do click. UIA nie ma wzorca iniekcji klawiatury, więc to spada do warstwy Win32. Służy do nawigacji za pomocą klawiatury (strzałek, klawiszy Tab, Enter, Esc), skrótów (ctrl+c, alt+f4), i wpisywania w kontrolkach, które wymagają zdarzeń naciśnięć klawiszy, a nie set-valuedo zapisu niepodzielnego.

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

Gramatyka klucza (tokeny rozdzielane odstępami, cudzysłów ciągi wielo tokenów):

  • Nazwane kluczeenterreturn/, esc. capslockprintscreentab/escapespacebackspacedelete/delinserthomeendpageup/pguppagedown/pgdnup/down/left/rightf1f16apps
  • Sekwencje — wiele tokenów jest naciskanych w kolejności: down down enter.
  • Kombi modyfikatoractrl, shiftwinaltsprzężone z +: ctrl+shift+t, . alt+f4
  • Tekst literału — każdy token, który nie jest znanym kluczem, jest wpisany znakiem według znaku: hello. Sąsiadujące wyrazy literału zachowują odstęp między nimi, więc fraza w cudzysłowie, taka jak "Hello world" , jest wpisywana dosłownie (spacja jest zachowywana); literał, który zawiera tylko + tekst C++ lub a+b jest wpisywany jako tekst, a nie analizowany jako kombi.
  • Jawna ucieczka literału — prefiks tokenu z text= , aby wpisać go dosłownie, nawet jeśli zderzy się z nazwą klucza lub modyfikatora: text=enter wpisz wyraz "enter" zamiast naciskać klawisz Enter i text=ctrl+a wpisz ciąg literału. Odzwierciedla ucieczkę vk= ; unikniętą wartość nadal łączą się z sąsiednimi wyrazami literału (text=down low → "w dół niski"). Ponieważ tokeny są rozdzielone odstępami (a sąsiadujące literały ponownie łączą się z jedną spacją text= ), użyj ukośników odwrotnych wewnątrz wartości , aby wpisać odstępy, które nie przetrwałyby w przeciwnym razie: \s → spacji, → tabulatora, \t → nowego wiersza, \n → nowego wiersza, \r\\ → ukośnik literału. \n, \ri \r\n każda wstawia pojedynczy podział wiersza (Enter / VK_RETURN), tak i text=line1\nline2text=line1\r\nline2 wpisz jeden nowy wiersz. Dlatego text=a\s\sb wpisze "a b" (podwójna spacja) i text=\shi utrzymuje wiodącą przestrzeń. Nierozpoznana ucieczka (np. \x) jest pozostawiona dosłownie.
  • Literał całego argumentu (--verbatim) — gdy cały ładunek jest tekstem literału, należy przekazać --verbatim zamiast uciekać przed każdym tokenem za pomocą text=polecenia . Typuje cały argument kluczy dokładnie tak, jak podane — bez nazwanego klucza/kombi/vk=/text= interpretacji — i, w przeciwieństwie do normalnej ścieżki, zachowuje dokładne białe znaki wewnętrzne (bez zwijania \s) bez konieczności . Dlatego send-keys "down down enter" --verbatim wpisze wyrazy i send-keys "a b" --verbatim utrzymuje podwójną spację. Ucieczki ukośnika odwrotnego nie są dekodowane w --verbatim trybie ( \s znak jest wpisywany jako ukośnik odwrotny i znak "s"); należy użyć text= tokenu, gdy potrzebujesz znaku kontrolki z znakiem ucieczki.
  • Nieprzetworzone klucze wirtualnevk=0xNN (szesnastkowe) lub vk=NN (dziesiętne) dla kluczy bez przyjaznej nazwy.

Opcje:

  • --target <selector> — Fokusuj ten element (za pośrednictwem interfejsu użytkownika) przed wysłaniem kluczy. Bez niego klucze przechodzą do aktualnie ukierunkowanego elementu aplikacji.
  • --verbatim — Wpisz cały argument keys jako tekst literału (bez klucza/kombi/vk=/text= analizowania) i zachowaj dokładne odstępy. Cała forma argumentu ucieczki na token text= .
  • --via <transport>post-message (domyślnie) wpisyWM_CHARWM_KEYDOWN/WM_KEYUP/w kolejce okna docelowego. Jest przeznaczony dla HWND i pomija interfejs użytkownika (działa na różnych poziomach integralności). send-input wstrzykuje system operacyjny przez i SendInput przechodzi do okna pierwszego planu.

Wybieranie transportu/znanych limitów:

  • post-message jest wartością domyślną, ponieważ pomija interfejs użytkownika i nie zależy od pierwszego planu okna. Limity: nie może wyzwalać globalnych kluczy dostępu zarejestrowanych za pośrednictwem WH_KEYBOARD_LL punktów zaczepienia niskiego poziomu (te naciśnięcia wejścia nadrzędnego dowolnego kolejki okien) i aplikacje odczytujące stan klucza pierwotnego za pośrednictwem GetAsyncKeyState mogą nie obserwować zatrzymanych modyfikatorów. Automatycznie rozpoznaje i publikuje w docelowym oknie podrzędnym wątku (za pośrednictwem GetGUIThreadInfo) po pierwszym planie, dlatego klasyczne aplikacje Win32/WinForms, których kontrolki są oddzielnymi oknami podrzędnymi, odbierają klucze bez ręcznego określania wartości docelowej kontrolki. Aplikacje WinUI 3 / UWP mają bez okien kontrolki XAML bez podrzędnego HWND, więc wysłana WM_CHAR/WM_KEYDOWN nie ma nic do lądowania i jest porzucona — po komunikacie nie można ich napędzać (polecenie ostrzega i kończy 0); użyj polecenia --via send-input. (WPF okna to single-HWND i klucze trasy do wewnętrznie ukierunkowanego elementu, więc post-message działa tam.)
  • send-inputTworzy w pełni rzeczywiste dane wejściowe (modyfikatory widoczne dla GetAsyncKeyState, uruchamia punkty zaczepienia niskiego poziomu), ale przechodzi do dowolnego okna na pierwszym planie i jest blokowany przez interfejs UIPI podczas wstrzykiwania z procesu z podwyższonym poziomem uprawnień do celu niższej integralności (AppContainer/AppX). Jeśli send-input zgłasza błąd, element docelowy jest prawdopodobnie podwyższony lub aplikacja AppX — użyj polecenia post-messagelub uruchom interfejs wiersza polecenia na zgodnym poziomie integralności. Jako ochroniarz sprawdza, send-input czy okno docelowe znajduje się na pierwszym planie bezpośrednio przed wstrzyknięciem i niepowodzeniem (foreground_not_target), zamiast wpisywać w niewłaściwym oknie , jeśli fokus nie może zostać przeniesiony do niego — fokus lub kliknij okno jako pierwsze. Zamiast tego na zablokowanym lub bezpiecznym pulpicie kończy się niepowodzeniem no_interactive_desktop (nie istnieje okno pierwszego planu do wstrzykiwania) — odblokuj sesję lub użyj czasownika UIA-pattern (set-value, invoke).
  • Kombi zarezerwowane systemu (win+l, win+r, alt+f4ctrl+escalt+tabctrl+shift+escctrl+alt+delsamotne win/printscreen, ...) działają na systemie operacyjnym/powłoce, a nie tylko na obiekcie docelowym podczas wysyłania całego systemu operacyjnego. send-input odrzuca je domyślnie (błędy z invalid_arguments i wysyła nic), ponieważ wstrzykiwanie ich na poziomie systemu operacyjnego ma efekty daleko poza okno docelowe (np. win+l zablokowałoby sesję). Przekaż --allow-system-keys , aby wyrazić zgodę — umożliwia to prowadzenie globalnego klucza dostępu, takiego jak PowerToys' win+shift+v lub win+r (globalny punkt zaczepienia niskiego poziomu obserwuje strumień wejściowy dla całego systemu operacyjnego, więc wstrzyknięte kombi go uruchamia). Wyjątki, które pozostają zablokowane nawet --allow-system-keysza pomocą polecenia :win+l blokuje stację roboczą, za pomocą LockWorkStation() której nie można rozpoznać z automatyzacji (przerywa sesje ciągłej integracji i pulpitu zdalnego) i ctrl+alt+del jest sekwencją bezpiecznej uwagi (SAS), która Windows spada z wstrzykniętych danych wejściowych niezależnie od flagi — nigdy nie może obowiązywać, więc błędy (invalid_argumentswyjście 1) zamiast zgłaszać wprowadzający błąd. Inne kombi (alt+f4, ctrl+shift+esc, , win+r...) stają się dozwolone za pomocą flagi — uważaj, wywołując. Alternatywnie, aby dostarczyć kombi systemowej do określonego okna, użyj --via post-messagepolecenia , który jest zakresem okna i nie ma to wpływu (wysłana win+l jest nieszkodliwa, choć wysłana alt+f4 nadal zamyka okno docelowe).

Zdarzenia na naciśnięciu klawiszy (KeyDown/ TextChanged):

  • Nazwane klucze i kombi modyfikatora (down, enter, ctrl+shift+t, vk=0xNN) uruchamiają rzeczywiste KeyDown (i KeyUp) w obu transportach — są dostarczane jako dyskretne WM_KEYDOWN/WM_KEYUP (lub SendInput zdarzenia klucza wirtualnego).
  • Tekst wpisany literał (hello) różni się transportem:
    • --via send-input mapuje każdy znak na jego wirtualny klawisz (plus Shift) na aktywny układ klawiatury, więc element docelowy widzi prawdziwy KeyDown z poprawnym kluczem wirtualnym , a następnie skomponowany WM_CHAR przez system operacyjny (podnoszący TextChanged) — tj. jeden pełny naciśnięty klawisz na znak. Znaki nieosiągalne w bieżącym układzie (lub wymagając klawiszy Ctrl/AltGr) wracają do pakietu Unicode, więc dokładny znak nadal ląduje. Użyj send-input polecenia , jeśli potrzebujesz wierności na naciśnięciu KeyDown klawiszy (np. jazdy winUI 3 / WPFTextBox, którego klucz obsługi jest wyłączony KeyDown). W przypadku normalnego (innego niż podwyższony poziom) hosta testowego WinUI 3 przełącz okno na pierwszy plan (winapp ui focus / kliknięcie go), ponieważ send-input jest ono przeznaczone dla okna pierwszego planu.
    • --via post-message publikuje pojedynczy znak WM_CHAR ( nie publikuje WM_KEYDOWN/WM_KEYUP tekstu wpisanego — są one zarezerwowane dla nazwanych kluczy/kombi), które nie zgłaszają znaku na znak KeyDown. Automatycznie retargets do ukierunkowanej kontrolki podrzędnej okna, więc klasyczne kontrolki Edycji Win32/WinForms WM_CHARwylądować tekst (podnoszenie TextChanged). Zastrzeżeniem: Aplikacje WinUI 3/ UWP/ XAML (podstawowy element docelowy aplikacji WinApp) mają kontrolki bez okien ignorowane WM_CHAR/WM_KEYDOWN — więc ani tekst literału , ani nazwane klucze (Enter, cyfry, ...) nie docierają do nich, mimo że polecenie zgłasza sukces. Emituje ostrzeżenie, gdy element docelowy wygląda jak XAML i nadal kończy wartość 0 (PostMessage jest uruchamiany i pomijany i nie może potwierdzić dostarczenia). Służy --via send-input do kierowania aplikacjami WinUI 3/UWP/WPF; zarezerwuj post-message dla klasycznych kontrolek Win32 lub gdy są potrzebne tylko okna obejmujące poziomy integralności.

Dane wyjściowe JSON (--json): wynik hwnd jest skutecznym oknem, do którego zostały dostarczone klucze — w tym --via post-message celu jest to rozpoznana skoncentrowana kontrolka podrzędna, gdy polecenie retargetsuje do niego (niekoniecznie okno najwyższego poziomu-w//-a-e), dzięki czemu automatyzacja może potwierdzić dokładnie, gdzie wylądowały dane wejściowe. Gdy ten skuteczny element docelowy wygląda jak host XAML bez okien, powyższe zastrzeżenie dostarczania jest również widoczne jako warnings[] wpis (ten sam poradnik pokazany w konsoli), więc ✅ wyjście 0 nie jest mylące z potwierdzonym dostarczeniem.

set-value

Ustaw wartość elementu edytowalnego programowo (bez naciśnięć klawiszy, bez pierwszego planu aplikacji). Używa łańcucha rezerwowego:

  1. ValuePattern — kontrolki TextBox, ComboBox, PasswordBox i najbardziej edytowalne.
  2. RangeValuePattern — kontrolki liczbowe (Slider, ProgressBar), gdy wartość jest analizowana jako liczba.
  3. LegacyIAccessible (IAccessible::put_accValue) — powrót do kontrolek edycji tylko textPattern , które nie uwidaczniają elementu ValuePattern (np. pola edycji sformatowanej/ Document redagowania). Spowoduje to zamknięcie luki odczytu/zapisu, w której get-value można odczytać taką kontrolkę, ale set-value nie może.
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

Jeśli żadna z trzech wzorców nie może ustawić wartości, set-value kończy się niepowodzeniem z wyraźnym błędem wskazującym w send-keys ostateczności.

Nie każdy bogaty edytor obsługuje zestaw programowy. Rezerwowy element LegacyIAccessible działa tylko na kontrolkach, których implementacje ułatwień dostępu — natywne kontrolki IAccessible::put_accValue edycji Win32 i Chromium/Electron/WebView2 zwykle wykonują powierzchnie. WinUI 3 RichEditBox i WPF RichTextBox nie obsługują programowego ustawiania wartości — zgodnie z projektem uwidaczniają zawartość automatyzacja interfejsu użytkownika jako tylko do odczytu (wzorzec tekstowy, bez wzorca wartości ustawionej), więc set-value nie można do nich zapisywać. Użyj send-keys (który wymaga odblokowanego, pierwszego planu pulpitu) dla tych.

get-value

Odczytaj bieżącą wartość z elementu. Używa inteligentnego łańcucha rezerwowego: TextPattern (RichEditBox, Document) → ValuePattern (TextBox, Slider) → SelectionPattern (ComboBox, RadioButton, TabView) → Name (etykiety).

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

focus

Przenieś fokus klawiatury do elementu.

winapp ui focus txt-textbox-a4b1 -a notepad

przewiń do widoku

Przewiń element do widocznego obszaru.

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

wait-for

Poczekaj, aż element pojawi się, zniknie lub osiągnie wartość docelową.

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

Przewiń

Przewiń element kontenera. Znajdź kontenery search scroll z możliwością przewijania — poszukaj [scroll:v] (pionowych) lub [scroll:h] (poziomych) znaczników.

# 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

Opcje:

  • --direction <up|down|left|right> — przewijanie przyrostowo za pomocą metody ScrollPattern.
  • --to <top|bottom> — Przejdź do początku/końca za pomocą polecenia ScrollPattern.
  • --wheel <notches> — Syntetyzowanie danych wejściowych kół myszy na środku elementu za pośrednictwem SendInput, w wycięciach kół (wcięciach): 1 = jeden nacięcie w górę/odchyła, -1 = jeden nacięcie w dół/w kierunku, 3 = trzy cale w górę. (Każdy wycięcie jest Windows WHEEL_DELTA z 120 jednostek, które SendInput zużywają; interfejs wiersza polecenia skaluje nacięcie o 120 dla Ciebie). ScrollPatternPomija .

--direction, --toi --wheel wzajemnie się wykluczają — dokładnie jeden. Ze względu --wheel na to, że wstrzykuje dane wejściowe dla całego systemu operacyjnego na współrzędnych ekranu, element docelowy jest pierwszy na pierwszym planie i kończy się niepowodzeniem (foreground_not_target), jeśli nie można przenieść fokusu, a nie przewijania niewłaściwego okna.

uzyskiwanie fokusu

Pokaż element, który obecnie ma fokus klawiatury.

winapp ui get-focused -a myapp

list-windows

Wyświetl listę wszystkich widocznych okien dla aplikacji, w tym wyskakujących okienek i okien dialogowych. Domyślnie okna bez tytułu o zerowym rozmiarze (niewidoczne okna systemowe) są wykluczone.

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

Obsługa struktury

Framework Sprawdzić wyszukać wywołać set-value zrzut ekranu
WPF ✅ Pełne drzewo ✅ Wszystkie właściwości ✅ Wszystkie wzorce ✅ ¹
Windows Forms
Win32
WinUI 3 ✅ ¹
Elektron ⚠✔ Drzewo chromowe ⚠✔ Ograniczone ⚠✔ Różni się ⚠✔ Różni się
Flutter ⚠✔ Podstawowa ⚠✔ Podstawowa ❌ Minimalne

¹ set-value działa na dowolnej kontrolce, która uwidacznia wartośćPattern/RangeValuePattern, oraz kontrolki edycji tylko textPattern, których ułatwienia dostępu implementują IAccessible::put_accValue (legacyIAccessible rezerwowy). WinUI 3 RichEditBox i WPF RichTextBox są wyjątkami — uwidaczniają tylko wzorzec tekstowy tylko do odczytu (bez wzorca wartości możliwej do ustawienia), aby nie można było ustawić ich programowo; należy użyć send-keys (wymagany pulpit interaktywny) do wpisywania w nich.

Troubleshooting

Error Przyczyna Rozwiązanie
"Nie znaleziono uruchomionej aplikacji" Aplikacja nie działa lub niezgodność nazw Sprawdzanie nazwy procesu lub używanie identyfikatora PID
"Dopasowanie wielu okien" Niejednoznaczna -a wartość Użyj -w <HWND> z wymienionych opcji
"ma wiele okien" Proces ma wiele okien Użyj -w <HWND> polecenia , aby kierować do określonego elementu
"Selektor pasował do N elementów" Niejednoznaczny selektor starszej wersji Użyj slugs z inspect danych wyjściowych lub dołącz [0]element , [1] do starszych selektorów
"Element mógł ulec zmianie" Skrót Slug nie pasuje do bieżącego elementu inspect Uruchom ponownie lubsearch, aby uzyskać świeże ślimaki
"nie obsługuje żadnego wzorca wywołania" Nie można wywołać elementu Użyj inspect elementu w celu znalezienia elementu podrzędnego z możliwością wywołania
"Nie znaleziono okna UIA" Interfejs użytkownika nie widzi procesu Użyj list-windows polecenia , aby znaleźć HWND, a następnie -w
"Okno ma zerowy rozmiar" Okno jest zminimalizowane Aplikacja zostanie przywrócona automatycznie
Wyskakujące okienko/lista rozwijana nie są na zrzucie ekranu Przechwytywanie domyślne to okno i nie obejmuje nieumyślnych nakładek Użyj --capture-screen flagi
element_not_found podczas rejestrowania Selektor podany, ale bez pasującego elementu inspect Uruchom ponownie lubsearch, aby uzyskać nowy selektor
Usługa WGC jest niedostępna podczas rejestrowania Nie można przechwycić init przechwytywania WGC; brak cichego powrotu Sprawdź procesor GPU/sterownik; użyj --capture-screen polecenia , aby wyrazić zgodę na przechwytywanie ekranu kontrolera domeny

Typowe wzorce

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

Znajdowanie tekstu i wywoływanie jego elementu nadrzędnego

# 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

Uściślanie zduplikowanych elementów

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

Zrzut ekranu przedstawiający wyskakujące nakładki

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

Odnajdywanie, klikanie i weryfikowanie

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

Interakcja okna dialogowego pliku

Okna dialogowe otwierania/zapisywania plików to standardowe okna dialogowe Windows z obsługą interfejsu użytkownika:

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

Użyj inspect -w <dialog-hwnd> --interactive polecenia , aby odnaleźć rzeczywiste ślimaki dla określonego okna dialogowego.

Dlaczego ; łańcuch (nie &&)

Operator programu PowerShell może blokować się, gdy natywny && interfejs wiersza polecenia zapisuje w programie stderr lub używa sekwencji ucieczki ANSI. Zamiast tego — ; uruchamia każde polecenie bezwarunkowo i unika tego zakleszczenia. Jest to również lepsze w przypadku przepływów pracy agenta: zwykle chcesz, aby zrzut ekranu był uruchamiany nawet wtedy, gdy wywołanie miało wyjście niezerowe.

Wzorce testowania ciągłej integracji

Użyj winapp ui poleceń w potokach ciągłej integracji (GitHub Actions, Azure DevOps) na potrzeby testów weryfikacyjnych kompilacji i weryfikacji interfejsu użytkownika. wait-for z --property i --value działa jako asercja — zwraca kod zakończenia 1 w przypadku przekroczenia limitu czasu, co powoduje automatyczne niepowodzenie kroku ciągłej integracji.

Uruchamianie i testowanie w 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

Stan elementu assert z wait-for

wait-for --value sonduje, dopóki wartość elementu nie pasuje do oczekiwanego ciągu, używając tego samego inteligentnego rezerwowego co get-value (TextPattern → ValuePattern → SelectionPattern → Name). Zwraca kod zakończenia 0 zgodny, kod zakończenia 1 w przypadku przekroczenia limitu czasu — co czyni go asercją przyjazną dla ciągłej integracji. Zamiast tego użyj polecenia --property , aby sprawdzić określoną właściwość UIA.

# 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

Potwierdzanie przy użyciu danych wyjściowych JSON

Używanie z --json programem PowerShell lub jq w celu uzyskania bardziej złożonych asercji:

Kontrakt zakończenia kodu dla search i wait-for w --json trybie: gdy żaden element nie pasuje (search) lub limit czasu oczekiwania (wait-for), polecenie zapisuje w pełni analizowalne koperty wyniku do stdout ({ "matchCount": 0, ... } lub { "found": false, "timedOut": true, ... }) i zwraca kod zakończenia 1. Stderr jest pusty w --json trybie (dane wyjściowe rejestratora są pomijane). Rozgałęzij na polach koperty lub na $LASTEXITCODE, w zależności od tego, co jest bardziej ergonomiczne.

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

Przykład pełnego testu weryfikacyjnego kompilacji

# 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