Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Inspectez et interagissez avec l’exécution d’applications Windows à partir de la ligne de commande. Utilisé par les agents et développeurs d’IA pour les tests, le débogage et l’automatisation de l’interface utilisateur.
Aperçu
winapp ui fournit des commandes permettant d’inspecter et d’interagir avec des interfaces utilisateur d’application Windows.
Utilise Windows UI Automation (UIA). Fonctionne avec n’importe quelle application Windows : WPF, WinForms, Win32, Electron et WinUI 3.
La plupart des commandes pilotent l’application via des modèles UIA (aucune injection d’entrée). Les exceptions injectent une entrée réelle : ui click/ui hover/ui dragutilisez la simulation de souris,ui touch/ui pen synthétisez l’entrée tactile et stylet/stylet, et ui send-keys synthétisez l’entrée clavier pour les contrôles et les scénarios que les modèles UIA ne peuvent pas conduire.
Important
Exigence interactive du bureau (verbes d’injection d’entrée).click, hover, drag, touch, pen, , scroll --wheelet send-keys --via send-input synthétiser l’entrée au niveau du système d’exploitation, de sorte qu’ils ont besoin d’un bureau interactif déverrouillé avec la fenêtre cible au premier plan. Sur une station de travail verrouillée ou un bureau sécurisé (LogonUI/UAC), ils ne peuvent pas injecter et échouer rapidement avec no_interactive_desktop (distincts de l’élévation/foreground_not_target cas).
touch
/
pen refuse également lorsqu’aucune fenêtre ne se résout (no_target) ; une coordonnée en dehors de la fenêtre cible est un avertissement non fatal (une warnings[] entrée sous --json, ou une ligne d’avertissement en mode texte) et l’injection continue de se poursuivre , cohérente avec les verbes de la souris. Tout le reste — inspect, get-propertyset-valuewait-forget-valuesearch, invoke, — scroll --direction/--to pilote l’application via des modèles UIA et est compatible avec les sessions sans tête/verrouillée.
screenshot est l’exception parmi les verbes non injectés : il prend un tour exclusif et sa capture peut avoir besoin d’un bureau interactif utilisable, car le moteur restaure une cible réduite et revient au premier plan lorsque la capture d’images n’est pas disponible ou --capture-screen est utilisée. Préférer les verbes de modèle UIA dans CI ; réservez les verbes d’injection pour les scénarios qui nécessitent réellement une entrée réelle. Avant d’injecter, les verbes de mouvement réexéquent également l’élément cible et refusent avec target_moved s’il est toujours animé/déplacé, plutôt que d’atterrir l’entrée sur l’espace vide.
Démarrage rapide
Exécutez winapp ui --help la boucle principale : inspect -a <app> --interactive pour voir ce que vous pouvez agir, invoke ou set-value pour agir, et get-value pour vérifier le résultat. Chaque commande affiche des --help exemples. Une commande inconnue, telle que winapp ui dump, s’arrête avec le code 1 et suggère les commandes les plus proches (en tant qu’erreur JSON avec suggestions quand vous passez --json).
# Connect to any app and see its UI tree
winapp ui inspect -a notepad
# Find specific elements
winapp ui search Button -a notepad
# Activate an element
winapp ui invoke Close -a notepad
# Take a screenshot
winapp ui screenshot -a notepad
Exécution de l’automatisation de l’interface utilisateur dans Windows bac à sable
Pour conserver l’automatisation de votre bureau, ajoutez --on sandbox aux commandes d’exécution et d’interface utilisateur :
winapp run . --on sandbox --detach
winapp ui inspect --on sandbox -a MyApp
winapp ui invoke --on sandbox SubmitButton -a MyApp
--detach retourne après le lancement ; sans cela, run attend que l’application se termine. Conservez --on sandbox toutes les commandes invitées, y compris celles qui utilisent un code PID ou un handle de fenêtre.
Consultez Windows exécution du bac à sable pour connaître les exigences du client, les modifications de focus d’installation/reconnexion brèves, la coordination des flux de travail et la livraison de sortie de l’hôte.
Requêtes délimitées et typées
winapp ui search "Welcome to MyApp" -a myapp --root MailRow --type Text --class-name TextBlock
winapp ui get-value Subject -w 123456 --root MailRow --type TextBox
winapp ui get-property Subject -a myapp --root MailRow --type Edit --property Value
winapp ui wait-for Subject -a myapp --root MailRow --type Edit --value "Ready" --timeout 10000
winapp ui invoke Open -w <dialog-HWND> --type Button
winapp ui set-value "Text editor" "hello" -a notepad --type Document
Ces commandes acceptent des filtres facultatifs sur leur sélecteur d’élément : inspect (avec un sélecteur), search, , wait-forget-valueget-property, , invoke, set-value, , click, , , hoverscroll-into-viewpenscrollscreenshotrecordtouchfocus
drag (deux sélecteurs) et send-keys --target ne le font pas.
Le sélecteur et chaque filtre fourni doivent correspondre au même élément. Les filtres réduisent un sélecteur, doncinspectscreenshot, et , dont recordle sélecteur est facultatif, échouent avec invalid_arguments quand des filtres donnés n’en ont pas. Pour touch et pen, les filtres ont besoin d’un sélecteur ; ils ne peuvent pas être combinés avec --at ou --path (invalid_arguments) :
-
--root <selector>recherche uniquement les descendants d’une racine correspondant de manière unique, jamais la racine elle-même. Utilisez un AutomationId ou un slug deinspectpour lever l’ambiguïté. Une racine qui correspond à plusieurs éléments échoue avecambiguous_selector, même si une correspondance est invoquable. Une racine manquante ne produit aucune correspondance. Une fois la racine trouvée, les requêtes ne recherchent pas de fenêtres contextuelles non liées, même lorsqu’aucun descendant ne correspond. Les requêtes ne sont pas limitées parinspectla profondeur d’affichage. -
--type <control-type>correspond à un type de contrôle UIA, ignorant le cas. Les seuls alias sontTextBox→EditetTextBlock→Text. Les noms inconnus (y compris les ID numériques et les expressions génériques) échouent avecinvalid_arguments. -
--class-name <literal>correspond à l’ensemble de l’UIAClassNamedu fournisseur, en ignorant le cas. Il ne s’agit pas d’une sous-chaîne, d’un caractère générique ou d’une expression régulière. Permetget-property --property ClassNamede découvrir la valeur du fournisseur ; le nom de la classe n’a pas besoin d’être égal au type de contrôle UIA.
Les requêtes filtrées utilisent la vue contrôle d’UIA, la même vue affichée par inspect.
Les nœuds du fournisseur exposés uniquement en mode Brut ne sont pas retournés ; permet inspect de rechercher le contrôle conteneur et son sélecteur.
Tous les 41 types officiels sont pris en charge : Button, EditHyperlinkCalendarRadioButtonComboBoxScrollBarListListItemProgressBarImageCheckBoxMenuItemMenuMenuBar, Slider, . SpinnerStatusBarTabTabItemTextToolBarToolTipTreeTreeItemCustomGroupThumbDataGridDataItemDocumentSplitButtonWindowPaneHeaderHeaderItemTableTitleBarSeparatorSemanticZoomAppBar
wait-for résout à nouveau le sélecteur racine sur chaque sondage, de sorte que la racine peut apparaître après le démarrage de la commande. Avec --gone, une racine absente signifie qu’il n’y a pas de descendant correspondant ; une racine ambiguë est une erreur, pas la réussite.
Une recherche interrompue n’est pas une preuve de disparition : si un élément est supprimé pendant la recherche ou remplacé avant une --value lecture, le prochain sondage vérifie à nouveau ; d’autres erreurs de recherche ou de lecture échouent à la commande.
-w <HWND> limite la découverte racine à l’arborescence UIA de cette fenêtre. Avec -a, la découverte racine peut également trouver les fenêtres contextuelles de l’application. Les correspondances AutomationId racine exactes sont prioritaires sur les correspondances de sous-chaîne sur toutes ces fenêtres ; plusieurs correspondances exactes échouent toujours avec ambiguous_selector.
Un slug racine sélectionne cet élément même lorsqu’une autre fenêtre a le même AutomationId. Si la racine sélectionnée est remplacée, son ancien slug ne correspond plus ; utilisez une racine AutomationId ou un nom lorsque vous souhaitez que l’interrogation suive un remplacement.
Lorsque des filtres sont présents, chaque commande à l’exception search échoue ambiguous_selector si plusieurs éléments restent ; réduisez les filtres ou utilisez une slug unique. Les commandes qui agissent sur le nombre d’éléments correspondent dans chaque fenêtre qu’ils recherchent, de sorte qu’un contrôle correspondant dans une boîte de dialogue appartenant rend également le sélecteur ambigu. Les correspondances Exact AutomationId conservent la priorité sur les correspondances de sous-chaîne, dans l’étendue filtrée. L’omission des trois options conserve le comportement de requête existant.
Coordination des flux de travail d’interface utilisateur simultanés
Windows n’a qu’une seule fenêtre de premier plan, un focus clavier, un curseur et un flux d’entrée. Lorsque deux winapp ui flux de travail s’exécutent sur le même bureau connecté à la fois, ils peuvent voler le focus les uns des autres, ignorer un menu l’autre simplement ouvert ou déplacer une cible hors sous un clic en attente.
L’arbitrage est toujours activé. Chaque winapp ui commande qui touche le bureau physique prend un tour, sans configuration et sans moyen de le désactiver, de sorte que deux agents ne peuvent jamais taper dans les fenêtres des autres. Les commandes en lecture seule continuent de s’exécuter simultanément. L’une des exceptions est un processus qui ne peut pas accéder au dossier de coordination de winapp, tel qu’un bac à sable de l’agent qui bloque %USERPROFILE%\.winapp: ses commandes s’exécutent toujours, mais sans prendre de tour, et imprimer un avertissement (sauf avec --json ou --quiet).
La continuité entre les commandes est opt-in. Par défaut, chaque commande est une capture unique autonome : elle attend son tour, fait son travail et libère immédiatement le bureau. Pour conserver le bureau sur plusieurs commandes, donnez-leur le même ID de flux de travail :
# Set once per logical UI workflow
$env:WINAPP_UI_WORKFLOW_ID = [guid]::NewGuid().ToString()
Ce que vous devez savoir :
- Un ID de flux de travail nomme un flux de travail logique , pas nécessairement un agent entier, et pas nécessairement une application. Utilisez la même valeur pour coopérer les commandes (un enregistrement plus les clics qu’il doit capturer) ; utilisez des valeurs différentes pour les flux de travail indépendants, même quand un agent lance les deux.
- Sans ID, chaque commande est un seul coup indépendant. Il arbitrat toujours, mais il n’a pas de grâce et de mains le bureau au moment où il se termine. Deux commandes no-id sont des flux de travail distincts, même lorsqu’ils sont lancés à partir du même interpréteur de commandes.
- Fresh-shell et les hôtes adaptatifs doivent injecter la même valeur. Si chaque commande s’exécute dans un nouvel interpréteur de commandes( c’est-à-dire que la plupart des appels d’outil d’agent fonctionnent), la seule chose qui peut les regrouper est un passage explicite
WINAPP_UI_WORKFLOW_IDà chaque appel de coopération. - La grâce à quatre secondes protège les rafales serrées, pas le raisonnement du modèle. Un flux de travail avec un ID conserve son tour tant que la commande suivante démarre dans les quatre secondes. Cela couvre les commandes back-to-back dans un script ; il expire intentionnellement pendant qu’un modèle pense. C’est un secours pour quand vous ne pouvez pas dire que vous avez terminé , quand vous pouvez, exécuter
winapp ui yieldau lieu de l’attendre. - Les flux de travail adaptatifs doivent reacquire, revalider et relire. Après un écart de raisonnement, un autre flux de travail peut avoir utilisé le bureau, rouvrez donc le menu, résolvez l’élément, puis agissez. Envoyez des séquences de bout en bout connues sous la forme d’un script serré plutôt que de tenir le bureau pendant que vous pensez.
- L’ordre est d’abord l’affinité de propriétaire, puis FIFO entre autres. Alors qu’un flux de travail est actif ou à l’intérieur de sa grâce, il peut continuer à émettre des commandes, même si d’autres flux de travail sont déjà en attente. Une fois qu’il s’exécute
winapp ui yieldou sa grâce expire, les flux de travail en attente sont servis dans un ordre d’arrivée strict. L’activité continue d’un flux de travail peut donc retarder indéfiniment les autres. - Il n’y a pas de capuchon. Un script long, un enregistrement non lié ou une boucle d’échec peut bloquer d’autres flux de travail mutants.
-
L’annulation ou l’arrêt du processus est la récupération d’un flux de travail en direct bloqué. Les commandes en attente impriment un état après une seconde et peuvent être arrêtées
130avecCtrl+C, qui se ferme . - Seuls les fichiers binaires mis à jour compatibles collaborent. Les builds plus anciennes
winappprécèdent cette fonctionnalité et ne sont pas coordonnées. Le code appelant directement les packages NuGet UI Automation ne fait pas partie de cette garantie : la coordination réside dans l’interface CLI, et non dans les packages.
Quelles commandes attendent un tour :
| Behavior | Commands |
|---|---|
| S’exécute simultanément (n’attend jamais) |
status, list-windows, inspect, search, get-property, get-value, get-focused, wait-for |
| Attend le tour, mais ne prend jamais le bureau |
set-value, , scroll-into-viewscroll --direction/--to, ,record |
| Attend le tour et prend le bureau exclusivement |
invoke, click, drag, hover, scroll --wheel, touch, pen, focus, send-keys, screenshot |
La ligne centrale est celle qui vaut la peine de comprendre.
set-value, scroll-into-view et scroll --direction/--to de piloter des modèles UIA plutôt que le premier plan, de sorte qu’ils restent conviviaux/verrouillés-session et ne empêchent jamais personne d’utiliser le bureau. Mais ils modifient ce que l’application affiche, donc ils attendent derrière le tour d’un autre flux de travail plutôt que de modifier un champ ou de faire défiler une liste à partir de sous un clic d’une autre personne.
Dans un flux de travail, ils se chevauchent avec d’autres travaux partagés , c’est-à-dire la façon dont un record capture les set-value appels qu’il enregistre. Ils n’ignorent pas la barrière avant de leur propre flux de travail : une commande antérieure DesktopExclusive du même flux de travail (a , a clickscreenshot) les bloque toujours, exactement comme il bloque chaque commande ultérieure, donc un clic et la mutation qui suit il reste dans l’ordre dans lequel vous les avez écrits.
screenshot met toujours en file d’attente un tour exclusif. Toutes les captures ne dérangent pas le bureau , une fenêtre visible ordinaire capturée par Windows Capture graphique ne le fait pas, mais le moteur restaure la cible si elle est réduite et revient au premier plan lorsque la capture d’images n’est pas disponible ou --capture-screen lit l’écran en direct. Ces besoins n’ont besoin qu’une fois la capture en cours, de sorte que la commande prend l’avant plutôt que de deviner. Lorsqu’il composite plusieurs fenêtres, il les capture tous sous un tour exclusif, de sorte que l’image enregistrée est un moment cohérent unique plutôt qu’un mélange de avant et après. L’encodage et l’écriture du fichier se produisent après la publication du bureau.
--capture-screena besoin exactement d’une fenêtre. Capture d’écran en direct enregistre ce qui est en fait en face, et une seule fenêtre peut être. La sélection d’une fenêtre explicitement avec-w <hwnd>lui donne exactement une région : les pixels à l’intérieur des limites de cette fenêtre, y compris toute boîte de dialogue ou superposition visiblement au-dessus de celle-ci, c’est la raison de lire l’écran en premier lieu. Quand-ail correspond à plusieurs fenêtres de niveau supérieur ou appartenant à un tel niveau, il n’existe aucune sélection de ce type, de sorte que la commande échoueinvalid_argumentsavant de capturer quoi que ce soit plutôt que de combattre le premier plan. Exécutez et réessayez avec-w <hwnd>, ou supprimez-lewinapp ui list-windows -a <app>--capture-screenpour compositer chaque fenêtre à partir de son propre contenu.
record partage son tour, de sorte que l’entrée de même flux de travail peut interagir avec la capture , c’est-à-dire la façon dont vous enregistrez un flux de travail qui pilote une application. Deux mises en garde :
- Un
recordid de flux de travail sans ID de flux de travail est un propriétaire unique, il bloque donc tous les autres flux de travail pendant toute sa durée. Pour enregistrer et cliquer en même temps, donnez les deux commandes identiquesWINAPP_UI_WORKFLOW_ID. - Sur un hôte sans prise en charge de capture d’images, l’enregistrement revient à PrintWindow, dont la récupération d’images vides peut précéder la fenêtre à tout moment. Le bureau est conservé pour l’enregistrement entier et la commande indique ainsi dans sa sortie ; même une entrée de flux de travail identique attend.
Erreurs que vous pouvez voir : invalid_ui_workflow_id (la variable est définie mais vide ou plus de 256 caractères), desktop_coordination_unavailable (l’état de coordination n’est pas lisible et ne peut pas être reconstruit en toute sécurité ou a été écrit par une version plus récente winapp), queue_capacity_exceeded (64 commandes provenant d’autres flux de travail sont déjà en attente , la limite compte les serveurs étrangers en direct, et non les processus que vous avez démarrés, donc les entrées appartenant aux commandes qui ont quitté ou qui ont été tuées n’occupent pas d’emplacement, et les commandes de votre propre flux de travail se trouvent en file d’attente plutôt que par rapport à cette limite), ui_turn_busy (yield tandis que votre propre flux de travail a toujours une commande en cours d’exécution) et cancelled (Ctrl+C en attente, code 130de sortie).
Libération anticipée du tour : winapp ui yield
La grâce à quatre secondes est un secours : elle conserve le bureau réservé lorsque vous ne pouvez pas dire pour certains que vous avez terminé. Lorsque vous pouvez le dire, dites-le - yield mains le bureau immédiatement au lieu de faire attendre que tout le monde attend une grâce dont personne n’a besoin.
$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
- Les commandes one-shot ne doivent pas définir d’ID de flux de travail du tout. Sans un seul, chaque commande libère déjà le bureau au moment où elle se termine, et il n’y a rien à générer.
- Les flux de travail à plusieurs étapes doivent être générés lorsqu’ils se terminent, en particulier lorsque d’autres flux de travail peuvent être en attente. Il coûte une commande rapide et supprime un décrochage de quatre secondes de tout le monde.
- C’est idempotent. Rendement deux fois, ou après l’expiration de la grâce, réussit et signale
{ "released": false }, c’est-à-dire la fin normale d’un script, pas une défaillance. - Il ne libère jamais le tour d’un autre flux de travail. Si quelqu’un d’autre tient le bureau, ou personne ne le fait, c’est un no-op.
- Elle échoue si
ui_turn_busyvotre propre workflow a toujours une commande en cours d’exécution ou mise en file d’attente , par exemple un enregistrement. La libération en dessous de ce qui ferait passer le bureau à la mi-commande, donc rien n’est libéré et la commande en cours d’exécution n’est pas affectée. Attendez-le ou arrêtez-le, puis retournez à nouveau. - Il nécessite
WINAPP_UI_WORKFLOW_ID. Sans l’un d’eux, il échoue avecinvalid_arguments. - Il ne prend pas d’application et aucun sélecteur : il renvoie une réservation, et non une fenêtre, de sorte qu’elle fonctionne toujours une fois l’application fermée.
Une commande en attente est réveillée par toute personne qui libère le bureau plutôt que par l’interrogation de celui-ci, donc une file d’attente ne coûte presque rien pendant qu’elle attend et que le transfert est immédiat. Chaque serveur effectue également une nouvelle vérification occasionnellement, c’est-à-dire ce qui récupère le bureau lorsqu’un processus est tué et ne publie jamais quoi que ce soit : la commande à la tête de la file d’attente semble toutes les demi-secondes, et les commandes derrière elle , qui ne peuvent pas s’exécuter avant que la tête ne le fasse de toute façon — toutes les quelques secondes.
Ciblage d’applications
Par nom de processus
winapp ui inspect -a notepad
winapp ui inspect -a slack # auto-picks visible window for multi-process apps
winapp ui inspect -a imageresizer # partial match: finds PowerToys.ImageResizer
winapp ui search Seven -a calculator # hosted app: uses the frame window that hosts it
Certaines applications empaquetées (par exemple Calculatrice) n’ont aucune fenêtre propre ; un autre processus héberge son frame. Lorsque le processus mis en correspondance (par nom ou PID) n’a pas de fenêtre visible, -a utilise plutôt le cadre qui héberge son contenu. S’il n’y a aucun (par exemple, l’application démarre toujours), -a cible le processus, donc continue à regarder jusqu’à ce que wait-for sa fenêtre apparaisse.
Par titre de la fenêtre
winapp ui inspect -a "LICENSE - Notepad"
winapp ui inspect -a "Fix WinApp" # partial title match
Par PID
winapp ui inspect -a 12345
Par HWND (stable — survive aux modifications de tabulation/titre)
# 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
Utilisation -a pour la découverte, -w pour le ciblage stable. Quand -a elle correspond à plusieurs fenêtres, la commande les répertorie avec des HWND pour que vous choisissiez.
Sélecteurs
Éléments cibles utilisant le sélecteur affiché dans [brackets] la sortie inspect/search.
Il existe trois types de sélecteurs :
| Selector | Sens | Example |
|---|---|---|
MinimizeButton |
AutomationId (indiqué lorsqu’il est unique — stable, préféré) | winapp ui invoke MinimizeButton -a myapp |
btn-close-d1a0 |
Slug sémantique (affichée lorsqu’aucun AutomationId unique) | winapp ui invoke btn-close-d1a0 -a myapp |
Submit |
Recherche en texte brut sur Name/AutomationId (sous-chaîne ne respectant pas la casse) | winapp ui invoke Submit -a myapp |
Les sélecteurs AutomationId sont des identificateurs de jeu de développeurs (AutomationProperties.AutomationId en XAML).
Lorsqu’un AutomationId est unique sur l’ensemble de l’arborescence de l’interface utilisateur et inspectsearch qu’il s’affiche directement en tant que sélecteur, ces modifications de disposition survivent aux modifications de disposition, à la localisation et à la restructuration des arborescences.
Les sélecteurs slug (par exemple, btn-close-d1a0) sont générés lorsqu’aucun AutomationId unique n’existe.
Format : prefix-name-hash. Le hachage valide l’identité de l’élément, mais peut être obsolète après les modifications de l’interface utilisateur.
Inspecter le format de sortie
La inspect commande affiche l’arborescence d’éléments avec une sortie colorée (sélecteur en cyan, nom en vert, métadonnées en gris) :
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
Le premier mot de chaque ligne est le sélecteur : utilisez-le avec d’autres ui commandes.
Lorsqu’un élément a un AutomationId unique, il est utilisé directement (par exemple, TabView, NewTabButton).
Lorsqu’aucun AutomationId unique n’existe, une slug générée est utilisée (par exemple tab-newtab-5f5b).
Slugs sémantiques
Les slugs utilisent le format : où : prefix-normalizedname-hash
- préfixe — abréviation de type 3 lettres (btn, txt, chk, cmb, itm, tab, img, lbl, pn, win, grp, lnk, mnu, etc.)
- normalizedname — alphanumérique minuscule à partir d’AutomationId (préféré) ou Name, max 15 chars
- hash — Hachage hexadécimal 4 caractères du RuntimeId de l’élément (valide l’identité de l’élément)
Les slugs sont sécurisés par l’interpréteur de commandes (aucun caractère spécial), uniques et peuvent être utilisés directement comme arguments. Sans filtres de requête, le hachage fournit une détection d’obsolescence : si l’élément a été remplacé, vous obtenez : « L’élément peut avoir changé. Réexécutez l’inspection. Pour les requêtes filtrées, consultez Requêtes délimitées et typées.
Les éléments sans nom ou AutomationId n’affichent que le préfixe + hachage (par exemple pn-c8a3).
Ambiguïté de plusieurs correspondances
Les slugs de sortie sont uniques, mais peuvent changer entre les modifications de inspect/search disposition : utilisez-les sur des noms de type brut ou du texte lorsque plusieurs correspondances sont effectuées. Lorsqu’un sélecteur est ambigu, l’interface CLI imprime toutes les correspondances avec leurs slugs afin que vous puissiez choisir celle qui convient et réexécuter avec ce slug.
winapp ui search Button -a myapp # shows: btn-ok-a1b2 "OK", btn-cancel-c3d4 "Cancel"
winapp ui invoke btn-ok-a1b2 -a myapp # invoke using slug (preferred)
winapp ui invoke btn-cancel-c3d4 -a myapp # invoke the other Button by its slug
Recherche en texte brut
Utilisez du texte brut pour rechercher des éléments , aucune syntaxe spéciale n’est nécessaire :
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
Lorsqu’une recherche de texte correspond à plusieurs éléments (par exemple, SettingsExpander où Group, Button et Text partagent tous le même nom), l’interface CLI sélectionne automatiquement le seul élément appelant. Si plusieurs sont invoquables, il répertorie toutes les correspondances avec des slugs.
Pour les résultats de recherche non appelants (par exemple, un TextBlock à l’intérieur d’un bouton), la recherche surface automatiquement l’ancêtre appelant le plus proche , l’élément parent avec invokelequel vous pouvez utiliser .
Cela fonctionne pour tous les sélecteurs de recherche :
lbl-savechanges-a1b2 "Save changes" (120,40 80x20)
^ invoke via: btn-save-c3d4 "Save"
Le sélecteur surface peut être utilisé directement :
winapp ui invoke btn-save-c3d4 -a myapp # invoke the parent Button
Commands
status
Connectez-vous à une application et affichez les informations de connexion.
winapp ui status -a notepad
winapp ui status -a notepad --json
Inspecter
Affichez l’arborescence des éléments d’interface utilisateur. La sortie affiche des slugs sémantiques avec mise en retrait de 2 espaces pour la hiérarchie :
winapp ui inspect -a notepad # full window tree, depth 3
winapp ui inspect -a notepad --depth 5 # deeper tree
winapp ui inspect txt-searchbox-e5f6 -a notepad # subtree rooted at element
winapp ui inspect --ancestors btn-close-d1a2 -a notepad # walk up from element to root
winapp ui inspect -a myapp --interactive # elements you can invoke, click, or set-value; auto-depth 8
winapp ui inspect -a myapp --hide-disabled # hide disabled elements
winapp ui inspect -a myapp --hide-offscreen # hide offscreen elements
Exemple de sortie (par défaut) :
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)
Exemple de sortie ( —--interactive éléments actionnables uniquement, liste plate) :
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)
Les éléments peuvent afficher ces marqueurs d’état :
-
[on]/[off]/[indeterminate]— activer/cocher l’état -
[collapsed]/[expanded]— développer/réduire l’état des arborescences, zones de liste modifiable, éléments de menu -
[scroll:v]/[scroll:h]/[scroll:vh]— conteneur à défilement (vertical, horizontal ou les deux) -
[offscreen]— l’élément n’est pas visible à l’écran -
[disabled]— l’élément n’est pas activé -
value="..."— contenu de texte actuel pour les éléments modifiables (lorsqu’ils sont différents de Name)
search
Recherchez des éléments correspondant à un sélecteur. La sortie affiche des slugs sémantiques :
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
Exemple de sortie :
btn-minimize-d1a0 "Minimize" (1222,206 48x48)
btn-maximize-e2b1 "Maximize" (1270,206 48x48)
btn-close-d1a2 "Close" (1318,206 48x48)
Les slugs affichés dans la sortie (par exemple, btn-minimize-d1a0) peuvent être utilisés directement avec d’autres commandes :
winapp ui invoke btn-minimize-d1a0 -a notepad
get-property
Lit les valeurs de propriété à partir d’un élément. Inclut l’état spécifique au modèle (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
Les noms de propriété respectent la casse. Un nom inconnu échoue avec invalid_arguments sous --json; omettez --property de répertorier les propriétés, y compris les six attributs de mise en forme de texte ci-dessous.
wait-for --property utilise les mêmes noms sensibles à la casse et rejette les noms inconnus avant l’interrogation.
Mise en forme de texte de document entier
La mise en forme est lue dans l’intégralité du document TextPattern de l’élément, et non dans sa sélection ou son insertion actuelle. Les lectures ne modifient pas le focus ou la sélection.
| Propriété | Valeur uniforme (retournée sous forme de chaîne) |
|---|---|
FontWeight |
Poids numérique, tel que "400" (normal) ou "700" (gras) |
FontName |
Nom de la famille de polices, par exemple "Courier New" |
FontSize |
Taille en points, par exemple "15.5" |
ForegroundColor |
Decimal Windows COLORREF (0x00BBGGRR), par exemple "3678732" pour RVB(12, 34, 56) |
IsItalic |
"True" ou "False" |
StrikethroughStyle |
Style de décoration de texte UIA numérique, tel que "0" (aucun) ou "1" (unique) |
Les nombres utilisent une mise en forme invariante (un point décimal, quel que soit vos paramètres régionaux). Chaque attribut peut retourner à la place :
| Value | Signification et étape suivante |
|---|---|
"Mixed" |
La mise en forme varie dans le document. Ne le traitez pas comme une valeur uniforme ; cette commande n’interroge pas les plages de texte individuelles. |
"NotSupported" |
Le fournisseur TextPattern du document ne signale pas cet attribut. Vérifiez la prise en charge de l’accessibilité de l’application. |
"Unavailable" |
L’élément n’a pas de TextPattern. Utilisez ou search recherchez inspect son élément texte/document. |
Lorsque vous répertoriez toutes les propriétés, les propriétés de base mises en cache restent disponibles si aucun élément actif ne peut être résolu et qu’une valeur de mise en forme incorrecte est omise sans ignorer d’autres propriétés. Ces omissions sont enregistrées en tant qu’avertissements. Demandez une propriété de mise en forme spécifique pour obtenir une erreur au lieu d’une omission.
Les défaillances du fournisseur restent des erreurs, et non "Unavailable". Pour stale_element, inspectez à nouveau l’application et réessayez avec un sélecteur actuel.
L’enveloppe JSON inclut elementId, un typé elementet une propertiesvaleur de chaîne .
Les propriétés existantes, y compris BoundingRectangle, conservent leurs formats.
Par exemple, la partie mise en forme de properties :
{
"FontWeight": "700"
}
capture d'écran
Capturez une fenêtre ou un élément en tant que 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)
Sans sélecteur d’élément, la capture par défaut combine plusieurs fenêtres en une seule png composite côte à côte, et non des fichiers distincts.
-a par nom de processus ou PID inclut les fenêtres de l’application et leurs fenêtres détenues. Une correspondance basée sur -a un titre sélectionne une fenêtre correspondante plus ses fenêtres détenues ; -w sélectionne explicitement une fenêtre ainsi que ses fenêtres détenues, pas toutes les fenêtres du processus. Une boîte de dialogue ou une info-bulle appartenant peut donc apparaître en tant que son propre panneau, même lorsque vous sélectionnez explicitement le HWND principal. Un sélecteur d’élément rogne vers cet élément au lieu de composer des fenêtres. Un élément d’un menu, d’un menu volant, d’une info-bulle ou d’une info-bulle qui s’ouvre dans sa propre fenêtre contextuelle est rogné à partir de cette fenêtre contextuelle, et non à partir de la fenêtre derrière elle.
--quiet supprime la sortie d’information pour les captures à fenêtre unique et composite, y compris le chemin d’accès enregistré. Les avertissements et les diagnostics d’échec de capture restent visibles. Utilisez --json plutôt lorsque vous avez besoin du chemin d’accès et des dimensions du fichier en tant que sortie structurée.
Avec --on sandbox, --output nomme la destination de l’hôte. Sortie simple réussie et --json rapportez le chemin d’accès de l’hôte après la remise de l’image.
Le chemin de capture par défaut utilise Windows. Graphics.Capture (WGC), en lisant la surface composite DWM réelle , préservant les angles arrondis, la transparence et le travail même si la fenêtre est obstruée par d’autres windows. Si WGC n’est pas disponible (versions antérieures Windows), l’interface CLI revient à PrintWindow.
Utilisez --capture-screen -w <hwnd> quand vous avez besoin de fenêtres contextuelles visibles ou d’info-bulles dans leurs positions à l’écran, y compris les superpositions qui ne sont pas détenues par la fenêtre cible. Il lit la région d’écran de cette fenêtre plutôt que de composer des panneaux étiquetés et amène la fenêtre au premier plan. Avec -a, il nécessite exactement une fenêtre correspondante ; si plusieurs fenêtres de niveau supérieur ou appartenant à la correspondance, utilisez winapp ui list-windows -a <app> et réessayez avec -w <hwnd>. Utilisez --focus si vous souhaitez simplement précéder la fenêtre sans changer de mode de capture (par exemple, pour vous assurer que la capture d’écran correspond à ce que l’utilisateur examine actuellement).
Étant donné que le contrôleur de domaine d’écran capture ce qui se trouve en face,
--capture-screenvérifie que la cible a atteint le premier plan immédiatement avant la capture et échoue siforeground_not_targetelle ne l’a pas fait (prévention du vol de focus, invite UAC ou une autre fenêtre s’activant elle-même). Aucune image n’est écrite dans ce cas - auparavant la commande a quitté 0 et remis une image de la fenêtre incorrecte.ui record --capture-screenapplique la même vérification avant le premier frame.
enregistrement
Enregistrez une fenêtre ou une région d’élément dans un FICHIER MP4 H.264. Préférez un positif --duration-sec pour les scripts sans assistance. Sans durée, l’enregistrement continue jusqu’à Ctrl+C ou, pour une stdin redirigée, une nouvelle ligne ou EOF. Les npm uiRecord et les assistances nécessitent un entier durationSec compris entre 1 et targetRecord 86400 ; leur signal d’abandon annule forcement au lieu de finaliser correctement un enregistrement.
# 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
Options :
-
--duration-sec N— Enregistrement pendant N secondes. 0 enregistrements par défaut jusqu’à ce qu’ils s’arrêtent. -
--fps N— Images cibles par seconde (par défaut 15). -
--max-edge N— Mise à l’échelle descendante afin que le bord le plus long soit au maximum N pixels (0 = pas de mise à l’échelle descendante). -
--capture-screen— Capture à partir du contrôleur de domaine d’écran (inclut des superpositions/fenêtres contextuelles ; des premier plan de la fenêtre). -
--output <path>— Chemin MP4 de sortie. La valeur par défaut estrecording-<timestamp>-<guid>.mp4. -
--overwrite— Remplacez les sorties d’enregistrement existantes une fois la nouvelle prise terminée. Sans cela, les sorties existantes sont rejetées. -
--frames— Écrire des preuves JPEG horodatées dans<output-name>.frames. Prend en charge 1-30 fps et--max-edge64-4096 (par défaut 1280). Les données de trame sont limitées à 1 Gio ; le MP4 continue si la limite est atteinte.
Artefacts d’images lisibles par agent :
evidence.mp4
evidence.frames/
manifest.json
frames.ndjson
frames/
frame-000000-t000000000012.jpg
frames.ndjson a une ligne par échantillon avec sampleIndex, monotonique elapsedMs, MP4 relatif mediaTimeMs, imageIndex, file, et changed. Les exemples identiques aux pixels consécutifs réutilisent la qualité précédente-85 JPEG.
manifest.json enregistre la requête, le minutage, l’état MP4, les dimensions de l’image et l’état (complete, partialou truncated). Le minutage tronqué couvre le préfixe conservé, tandis que video décrit le MP4 complet.
Choisissez un nouveau chemin de sortie, sauf si vous envisagez de remplacer un enregistrement --overwritepar .
Sans elle, une vidéo existante ou son répertoire jumelé .frames bloque l’enregistrement, même lorsque vous omettez --frames.
Le MP4 précédent reste intact si la nouvelle capture échoue. En cas de remplacement réussi, le répertoire d’images précédent est conservé en tant que <output-name>.frames.previous-<id>, même si le nouvel enregistrement omet --frames. Conservez les preuves partielles et suivez le rapport recoveryHint avant de réessayer. En cas d’échec de la finalisation MP4, les images conservées peuvent être publiées sous <output-name>.frames.partial-*. Les artefacts de trame contiennent du contenu d’écran non chiffré ; gérez-les comme des captures d’écran ou des vidéos.
Avec --on sandbox, le MP4 et le répertoire frame sont remis à l’hôte, y compris les sorties par défaut lorsqu’elles --output sont omises. Consultez la capture de bac à sable pour les enregistrements interrompus et la capture de bureau entière.
Modes de capture (signalés dans le champ JSON mode ) :
-
wgc— Windows Capture graphique (par défaut ; fonctionne pendant que la fenêtre est obstruée). -
printwindow— GDI PrintWindow (secours lorsque WGC n’est pas disponible sur ce système/session ; réexécutez-le pour--capture-screenutiliser le contrôleur de domaine d’écran à la place). -
screen— Écran DC via--capture-screen(inclut des superpositions/fenêtres contextuelles ; amène la fenêtre au premier plan).
Sortie JSON (--json) :
-
stdout : Résultat final de l’enregistrement, y compris la cadence, la raison d’arrêt, les avertissements facultatifs
frameArtifactset les avertissements. -
stderr : Un objet JSON par ligne : un
recording-startedévénement après la première image, suivi d’une erreur si l’enregistrement échoue ultérieurement. Les chemins d’images sont inclus uniquement lorsque la sortie d’image est active.
Codes d’erreur :
-
element_not_found— Le sélecteur ne correspond pas. -
ambiguous_selector— Le sélecteur a mis en correspondance plusieurs éléments ; utiliser un slug suggéré. -
invalid_arguments— Une valeur d’option n’est pas valide. -
output_exists— Une sortie d’enregistrement existe déjà et ne peut pas être remplacée sous les options demandées. -
frame_output_failed— Aucun artefact n’a pu être conservé après l’échec de la sortie de l’image. -
partial_output— Un seul artefact est terminé ; inspecterpartialOutputetrecoveryHint.
Un sélecteur d’élément enregistre la région de cet élément à partir de la fenêtre dans laquelle il est dessiné. Pour un élément d’un menu, d’un menu volant, d’une info-bulle ou d’une info-bulle qui s’ouvre dans sa propre fenêtre contextuelle, l’enregistrement affiche la fenêtre contextuelle plutôt que la fenêtre située derrière elle.
Invoquer
winapp ui invoke SettingsCategory -a myapp --action select
winapp ui invoke AgreeCheckbox -a myapp --action toggle-on --json
winapp ui invoke SizeComboBox -a myapp --action expand
winapp ui invoke Open -w <dialog-HWND> --root Actions --type Button --class-name Button --action invoke
winapp ui invoke SubmitButton -a myapp
Utilisez --action quand un test doit effectuer une opération spécifique sur exactement l’élément sélectionné. Il n’essaie jamais un autre modèle ou un ancêtre invoquable, même si l’action demandée échoue. Un contrôle prenant en charge à la fois l’appel et la sélection sera sélectionné, non appelé, avec --action select. Avec --action, un slug cible exactement un élément ; un sélecteur De texte brut ou AutomationId qui correspond à plusieurs éléments échoue avec un code de sortie différent de zéro au lieu d’agir sur la première correspondance, donc passez une suggestion à partir d’un inspect/search nom ambigu.
--root, --typeet --class-name affiner la correspondance comme décrit dans les requêtes étendues et typées, avec ou sans --action.
Permet -w <dialog-HWND> de restreindre une action à cette boîte de dialogue ou -a <app> d’inclure les fenêtres de l’application. Un appel filtré confirme la cible unique avant d’agir, nécessite exactement un élément correspondant et ne passe jamais à une autre fenêtre ou à un ancêtre invoquable. Zéro correspondance échoue avec element_not_found; les doublons échouent avec ambiguous_selector. Un élément obsolète ou une fenêtre recyclée échoue sans agir ; réexécutez inspect ou search choisissez un sélecteur actuel.
Sans --action, un appel filtré tente toujours les modèles dans l’ordre sur cet élément.
| Action | Opération |
|---|---|
invoke |
InvokePattern.Invoke |
select |
SelectionItemPattern.Select |
toggle |
TogglePattern.Toggle, exactement une fois |
toggle-on / toggle-off |
Lire ToggleState ; réussir sans modifier un état déjà correct, sinon basculez et vérifiez |
expand / collapse |
ExpandCollapsePattern.Expand / Collapse |
Pour toggle-on et toggle-off, un état de démarrage Indeterminate autorise au maximum deux transitions, en vérifiant l’état après chacun. D’autres états de départ autorisent une transition. Si l’état demandé n’est pas atteint, la commande échoue plutôt que de continuer à basculer. Une vérification ayant échoué peut laisser le contrôle modifié ; lisez ToggleState avant de décider de ce qu’il faut faire ensuite.
Sans --action filtres, le comportement automatique est inchangé : essayez InvokePattern, TogglePattern, SelectionItemPattern, puis ExpandCollapsePattern (expand), avec une nouvelle tentative invokable-ancêtre si nécessaire.
Une action non prise en charge échoue avec un code de sortie différent de zéro et, avec --json, une erreur structurée sur stderr. Inspectez le contrôle sélectionné et choisissez une action qu’il prend en charge, ou ciblez explicitement le parent prévu. Réussite json inclut requestedAction et performedAction; consultez la référence JSON.
click
Cliquez sur un élément à ses coordonnées d’écran à l’aide de la simulation de souris. Utilisez-le pour les contrôles qui ne prennent pas en charge InvokePattern (par exemple, les en-têtes de colonne, les éléments de liste).
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
Comme les autres verbes d’injection d’entrée,
clickplace la cible au premier plan et échoue rapidement (no_interactive_desktopsur un bureau verrouillé/sécurisé,foreground_not_targetsi le focus n’a pas pu être transféré) plutôt que de cliquer sur la fenêtre incorrecte. Il réexécise également l’élément juste avant le bouton vers le bas : après avoir positionné le curseur, il effectue une vérification finale de position, de sorte qu’une cible en déplacement/animation continue échoue autarget_movedlieu de signaler la réussite après que le clic a atterri sur l’espace vide , un succès signalé signifie que la cible était toujours en place lorsque le bouton est tombé en panne.
Traînée
Appuyez sur le bouton de la souris à un point, passez à un autre, puis relâchez avec drag <from> <to>, où chaque point de terminaison est un sélecteur d’élément (fait glisser depuis/vers le centre de l’élément) ou des x,ycoordonnées d’écran exactement comme indiqué par winapp ui inspect. Mélanger et faire correspondre librement (sélecteur→selector, sélecteur→coords, coords→coords).
Utilise SendInput avec des déplacements intermédiaires afin que l’application voit un flux réaliste de WM_MOUSEMOVE messages. Utilisez-le pour réorganiser/redimensionner des poignées, curseurs, dessin de canevas et glisser-déplacer.
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
Options :
-
--right— Faites glisser avec le bouton droit de la souris au lieu du bouton gauche. -
--hold-ms <ms>— Maintenez le bouton enfoncé au début avant de déplacer (valeur par défaut : 0). Avec<from> == <to>(aucun mouvement), cela effectue un mouvement de pression et de longue pression . -
--dwell-ms <ms>— Demeurez à la destination après le déplacement, avant de libérer (par défaut : 0). Permet de supprimer des cibles / fusionner des superpositions qui bras à partir d’un pointage soutenu (plutôt que l’instant où le curseur arrive) latch avant le bouton vers le haut.
Les coordonnées d’écran sont des
x,ycoordonnées d’écran dans le même rapport d’espacewinapp ui inspect/search, et un sélecteur se résout au centre de l’élément. Examinez d’abord les points sélectionnés.
Comme
send-keys --via send-input,draginjecte les coordonnées du système d’exploitation à l’écran après avoir amené la cible au premier plan. Si le focus ne peut pas être apporté à la cible (par exemple, la prévention du vol de focus à partir d’un processus en arrière-plan), la commande échoue (foreground_not_target) au lieu de faire glisser sur la fenêtre incorrecte ( focus ou cliquez d’abord sur la fenêtre. Sur un bureau verrouillé/sécurisé, il échoue avecno_interactive_desktop. Chaque point de terminaison d’élément est résolu immédiatement avant le glissement ; s’il est toujours en déplacement/redimensionnement (cible d’animation), la commande échouetarget_movedau lieu de faire glisser vers un point obsolète. (Les points de terminaison nusx,yne peuvent pas être vérifiés à nouveau. Ils sont donc utilisés as-is.)
Tactile
Injectez des mouvements tactiles synthétiques à l’aide de l’API d’injection de pointeur Windows. L’ancre de contact est un sélecteur d’élément (utilise le centre de l’élément) ou une coordonnée x,yd’écran explicite via --at (mêmes rapports d’espacewinapp ui inspect). Utilisez-le pour appuyer/appuyer sur des interactions et des mouvements tactiles multiples que la simulation de souris ne peut pas exprimer.
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)
Options :
-
--gesture <g>—tap(par défaut),double-tap, ,long-pressswipe,pinchstretch. -
--at <x,y>— Point de départ explicite (coordonnées de l’écran). La valeur par défaut est le centre d’éléments du sélecteur. -
--to-point <x,y>— Point de terminaison d’unswipe. Est prioritaire sur--direction. -
--direction <right|left|up|down>— Direction du balayage (valeur par défaut :right). Combiné avec--distancepour calculer le point de terminaison lorsqu’il--to-pointn’est pas donné. -
--distance <px>— Propagation du doigt pourpinch/stretch, ou distance de balayage en pixels. -
--hold-ms <ms>— Maintenez les contacts enfoncés avant de lever (temps d’attente de longue pression ; la valeur par défaut est de 500 ms quandlong-presselle n’est pas définie). -
--duration-ms <ms>— Temps de glissement pour les mouvements de déplacement (balayage/pincement/étirement ; valeur par défaut 300). -
--fingers <n>— Nombre de contacts (1 à 10 ; valeur par défaut 1).pinch/stretchutilisez toujours 2.
Sécurité des injections.
touchrefuse d’injecter à moins qu’une poignée de fenêtre cible non nulle ne soit résolue et que cette fenêtre conserve le premier plan . Elle échoueno_targetquand aucune fenêtre ne peut être résolue,foreground_not_targetsi le focus n’a pas pu être transféré ouno_interactive_desktopsur un bureau verrouillé/sécurisé. Chaque coordonnée (centre d’éléments, points de route explicites--at/--to-pointet générés) est cochée sur le rectangle de la fenêtre cible ; un point en dehors de la fenêtre est exposé comme un avertissement non fatal (unewarnings[]entrée en--json, ou une ligne d’avertissement en mode texte) et l’injection continue de correspondre aux verbes de la souris (click/drag/hover/scroll), qui injectent également à des coordonnées hors fenêtre.--fingersau-dessus de 10 est rejeté à l’avant.Remarque matérielle. Touch préfère l’appareil de pointeur synthétique moderne (
CreateSyntheticPointerDevice(PT_TOUCH)) et revient à l’API héritéeInitializeTouchInjection/InjectTouchInput. Si l’injection n’est pas prise en charge sur l’appareil/session actuel, la commande met en évidence le code d’erreur Win32 réel (par exemple, « non pris en charge ») plutôt que de signaler un faux succès : traitez une sortie non nulle comme « tactile non livré ».sessions Bureau à distance/machine virtuelle. Dans un Bureau à distance (RDP) ou certaines sessions de machine virtuelle, le système d’exploitation peut accepter une interaction tactile synthétique (sortie 0) sans atteindre réellement l’application cible. Lorsqu’une session à distance est détectée,
touchajoute un avertissement d’incertitude de remise , unewarnings[]entrée dans--jsonou une ligne d’avertissement en mode texte. Un ✅/exit 0 signifie ensuite que l’appel d’injection a réussi, et non que l’application a reçu l’entrée ; confirmez l’effet lorsqu’ilui screenshot/ui inspectimporte.
stylo
Injecter une entrée de stylet/stylet synthétique — appuis et traits d’encre — à l’aide de l’API de pointeur synthétique Windows (CreateSyntheticPointerDevice(PT_PEN) ; Windows 10 1809+). Ciblez un centre d’éléments, un point explicite --at ou un trait d’encre complet --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
Options :
-
--at <x,y>— Point de contact du stylet (coordonnées de l’écran). La valeur par défaut est le centre d’éléments du sélecteur. Ignoré lorsqu’il--pathest donné. -
--path "<x,y x,y …>"— Chemin du trait d’entrée manuscrite sous forme de paires séparéesx,ypar des espaces blancs (un chemin d’accès à un point est un appui). -
--pressure <0.0–1.0>— Pression du stylet (par défaut 0,5). -
--tilt-x <deg>/--tilt-y <deg>— Angles d’inclinaison du stylet, −90 à 90 (valeur par défaut 0). -
--eraser— Utilisez la fin de la gomme du stylet au lieu de la pointe. -
--duration-ms <ms>— Temps de déplacement total des traits en millisecondes distribués sous forme d’images UPDATE interpolées sur le chemin d’accès (valeur par défaut : ~10 ms par point de route). Utilisez-le pour contrôler la vitesse à laquelle le stylet passe visiblement du début à la fin.
Sécurité des injections. Comme
touch,penrefuse d’injecter sans zéro, fenêtre cible foregrounded (no_target/foreground_not_target/no_interactive_desktop) et vérifie chaque point d’entrée manuscrite sur le rectangle de la fenêtre cible, en exposant n’importe quelle coordonnée hors fenêtre comme un avertissement non fatal (warnings[]en--json, ou une ligne d’avertissement en mode texte) tout en continuant à injecter , cohérent avec les verbes de la souris. Les valeurs non valides--pressure(en dehors de 0,0 à 1,0) ou d’inclinaison (en dehors de ±90°) sont rejetées vers le haut.sessions Bureau à distance/machine virtuelle. Le routage du stylet est particulièrement peu fiable sur Bureau à distance : l’appel d’injection peut signaler la réussite (sortie 0) alors qu’aucune entrée de stylet n’atteint l’application. Lorsqu’une session à distance est détectée,
penajoute un avertissement d’incertitude de remise (warnings[]en--json, ou une ligne d’avertissement en mode texte) afin qu’une ✅ remise confirmée ne soit pas erronée. Valider les flux dépendants du stylet sur un bureau local et interactif.
flotter
Déplacez la souris vers le centre d’un élément pour déclencher des effets de pointage (info-bulles, menu volants, états visuels). Utilisations SendInput pour le mouvement réaliste de la souris avec un petit perruquement, puis attend une durée de vie configurable.
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
Options :
-
--dwell-time <ms>— Durée en millisecondes d’attente après le pointage des effets à afficher (valeur par défaut : 800, plage : 0 à 10000)
send-keys
Envoyer une entrée de clavier synthétique ( équivalent du clavier vers click. UIA n’a pas de modèle d’injection de clavier, donc cela tombe dans la couche Win32. Utilisez-le pour la navigation au clavier (flèches, Tab, Entrée, Échap), raccourcis (ctrl+c, alt+f4et saisie dans des contrôles nécessitant des événements par séquence de touches plutôt que set-valuel’écriture atomique.
winapp ui send-keys "down down enter" -a myapp # arrow navigation then commit
winapp ui send-keys "ctrl+a delete" -a myapp # select all, then delete
winapp ui send-keys "Hello world" --target txt-name-a1b2 -a myapp # focus a field, then type text
winapp ui send-keys "text=down text=down text=enter" -a myapp # type the words, don't press the keys
winapp ui send-keys "down down enter" -a myapp --verbatim # same, but type the whole argument literally
winapp ui send-keys "alt+f4" -a myapp # close window via accelerator
winapp ui send-keys "vk=0x5D" -a myapp # a key with no friendly name (Apps/Menu key)
winapp ui send-keys "ctrl+shift+t" -a myapp --via send-input # use OS-wide injection instead of PostMessage
winapp ui send-keys "win+shift+v" -a myapp --via send-input --allow-system-keys # opt in to drive a global hotkey
winapp ui send-keys "ctrl+capslock+f12" -a myapp --via send-input # Narrator command: toggle developer mode
Grammaire de clé (jetons séparés par des espaces blancs, guillemets chaînes à plusieurs jetons) :
-
Clés nommées —
enter/return, , ,tab,esc/escapespacebackspacedelete/delinserthomeendpageup/pguppagedown/pgdnup/down/left/rightf1f16appsprintscreencapslock -
Séquences : plusieurs jetons sont appuyés dans l’ordre :
down down enter. -
Combos modificateurs —
ctrl,shift,altwinjoint avec+:ctrl+shift+t,alt+f4. Un jeton qui commence par un modificateur, mais qui a un segment inconnu avant le dernier (ctrl+a+b) est une erreur ; utiliseztext=ou--verbatimtapez-le. -
Commandes de lecteur d’écran : maintenez
capslockouinsert(aliasins), la touche Narrateur, NVDA et JAWS :ctrl+capslock+f12bascule le mode développeur du Narrateur. Nécessite--via send-input, car les lecteurs d’écran ne reçoivent pas de clés publiées. Si aucun lecteur d’écran n’est en cours d’exécution, maintenezcapslockla touche Maj enfoncée ou désactivée et la commande avertit ; maintenezinsertla touche enfoncée pour éviter cela. -
Texte littéral : tout jeton qui n’est pas une clé connue est typé par caractère :
hello. Les mots littéraux adjacents conservent l’espace entre eux, de sorte qu’une expression entre guillemets comme"Hello world"celle-ci est typée (l’espace est conservé) ; littéral qui contient simplement des caractères+tels queC++dua+btexte, et non analysés en tant que liste déroulante. -
Échappement littéral explicite : préfixer un jeton pour
text=le taper au détail même lorsqu’il entre en collision avec une clé ou un nom de modificateur :text=entertapez le mot « entrée » au lieu d’appuyer sur Entrée ettext=ctrl+atapez la chaîne littérale. Reflète l’échappementvk=; la valeur échappée fusionne toujours les mots littéraux adjacents (text=down low→ « bas bas »). Étant donné que les jetons sont fractionnés d’espaces blancs (et les littéraux adjacents re-joint avec un espace unique), utilisez des barres obliques inverses à l’intérieur d’unetext=valeur pour taper des espaces blancs qui ne survivraient pas autrement :\s→ espace,\t→ onglet,\n→ nouvelle ligne,\r→ nouvelle ligne,\\→ barre oblique inverse littérale.\n,\ret\r\nchaque insertion d’un saut de ligne unique (un entrée /VK_RETURN), ainsitext=line1\nline2quetext=line1\r\nline2les deux tapez une nouvelle ligne. Ainsitext=a\s\sb, les types « a b » (espace double) ettext=\shiconservent un espace de début. Une échappement non reconnue (par exemple\x) est détaillée à gauche. -
Littéral d’argument entier (
--verbatim) : lorsque la charge utile entière est du texte littéral, passez--verbatimau lieu d’échapper à chaque jeton avectext=. Il tape l’argument des clés entières exactement comme indiqué ( aucune clé nommée/combo/vk=/text=interprétation) et, contrairement au chemin normal, conserve l’espace blanc interne exact (pas de réduction) sans avoir besoin de .\sAinsisend-keys "down down enter" --verbatim, entrez les mots etsend-keys "a b" --verbatimconservez l’espace double. Les échappements de barre oblique inverse ne sont pas décodés en--verbatimmode (une\sbarre oblique inverse est tapée comme barre oblique inverse et « s ») ; utilisez untext=jeton lorsque vous avez besoin d’un caractère de contrôle d’échappement. -
Clés virtuelles brutes (
vk=0xNNhexadécimales) ouvk=NN(décimales) pour les clés sans nom convivial.
Options :
-
--target <selector>— Concentrez cet élément (via UIA) avant d’envoyer des clés. Sans cela, les clés vont à l’élément actuellement axé sur l’application. -
--verbatim— Tapez l’argument des clés entiers en tant que texte littéral (aucune clé/combo/vk=/text=analyse) et conservez l’espace blanc exact. Forme d’argument entier de l’échappement par jetontext=. -
--via <transport>—post-message(valeur par défaut) publieWM_KEYDOWN/WM_KEYUP/WM_CHARdans la file d’attente de la fenêtre cible. Il est ciblé par HWND et contourne l’UIPI (fonctionne entre les niveaux d’intégrité).send-inputinjecte le système d’exploitation à l’échelleSendInputdu système d’exploitation et passe à la fenêtre de premier plan.
Choix d’un transport / limites connues :
-
post-messageest la valeur par défaut, car elle contourne l’UIPI et ne dépend pas de la fenêtre au premier plan. Limites : il ne peut pas déclencher des touches d’accès rapide globales inscrites viaWH_KEYBOARD_LLdes crochets de bas niveau (ceux qui appuient sur l’entrée en amont de n’importe quelle file d’attente de fenêtres) et les applications qui lisent l’état de clé brute viaGetAsyncKeyStatepeuvent ne pas observer les modificateurs conservés. Il résout et publie automatiquement la fenêtre enfant ciblée du thread cible (viaGetGUIThreadInfo) après le premier plan, de sorte que les applications Win32/WinForms classiques dont les contrôles sont des clés de réception enfants distinctes des fenêtres enfants sans cibler manuellement le contrôle. Les applications WinUI 3 / UWP ont des contrôles XAML sans fenêtre sans HWND enfant, donc un message publiéWM_CHAR/WM_KEYDOWNn’a rien à se connecter et est supprimé - post-message ne peut pas les conduire (la commande avertit et quitte 0) ; utilisez--via send-input. (les fenêtres WPF sont des clés HWND uniques et routent vers l’élément centré en interne. Par conséquent, le post-message fonctionne là.) -
send-inputproduit une entrée entièrement réelle (modificateurs visibles parGetAsyncKeyState, déclenche des crochets de bas niveau) mais accède à la fenêtre au premier plan et est bloquée par l’UIPI lors de l’injection d’un processus élevé dans une cible d’intégrité inférieure (AppContainer/AppX). Sisend-inputelle signale un échec, la cible est probablement élevée ou une application AppX : utilisezpost-messageou exécutez l’interface CLI au niveau d’intégrité correspondant. En tant que protection de sécurité,send-inputvérifie que la fenêtre cible est en fait au premier plan immédiatement avant d’injecter et d’échouer (foreground_not_target) plutôt que de taper dans la fenêtre incorrecte si le focus n’a pas pu être mis en place , le focus ou cliquer sur la fenêtre en premier. Sur un bureau verrouillé ou sécurisé , il échoue plutôt avecno_interactive_desktop(aucune fenêtre de premier plan n’existe pour l’injecter) - déverrouiller la session, ou utiliser un verbe de modèle UIA (set-value,invoke). -
Les combos réservés par le système (
win+l, ,win+r,ctrl+shift+escctrl+alt+delalt+tabalt+f4ctrl+esc, , seulwin/printscreen, ...) agissent sur le système d’exploitation/shell plutôt que simplement sur la cible quand le système d’exploitation est envoyé à l’échelle du système d’exploitation.send-inputles rejette par défaut (erreurs avecinvalid_argumentset n’envoie rien), car l’injection au niveau du système d’exploitation a des effets bien au-delà de la fenêtre cible (par exemple,win+lverrouillerait la session).--allow-system-keysPassez à choisir : cela vous permet de piloter une touche d’accès globale telle que PowerToys'win+shift+vouwin+r(le crochet global de bas niveau surveille le flux d’entrée à l’échelle du système d’exploitation, de sorte que le combo injecté le déclenche). Exceptions qui restent bloquées même avec--allow-system-keys:win+lverrouille la station de travail par le biaisLockWorkStation()de laquelle l’automatisation est irrécupérable (interrompt les sessions CI et bureau à distance), etctrl+alt+delest une séquence d’attention sécurisée (SAP) qui Windows chute de l’entrée injectée indépendamment de l’indicateur , elle ne peut jamais prendre effet, de sorte qu’elle génère des erreurs (invalid_argumentssortie 1) au lieu de signaler une réussite trompeuse. D’autres combos (alt+f4, ,ctrl+shift+escwin+r, ...) deviennent autorisés avec l’indicateur — attention à l’appelant. Vous pouvez également fournir une liste déroulante système à une utilisation--via post-messagespécifique de fenêtre, qui est délimitée par la fenêtre et non affectée (une publicationwin+lest inoffensive, bien qu’une publicationalt+f4ferme toujours la fenêtre cible).
Événements par séquence de touches (KeyDown / TextChanged) :
-
Les touches nommées et les combos modificateurs (
down, ,enterctrl+shift+t,vk=0xNN) déclenchent un réelKeyDown(etKeyUp) sur les deux transports , ils sont remis sous forme d’événements discretsWM_KEYDOWN/WM_KEYUP(ouSendInputde clés virtuelles). -
Le texte tapé littéral (
hello) diffère par transport :-
--via send-inputmappe chaque caractère à sa touche virtuelle (plus Maj) sur la disposition du clavier actif, de sorte que la cible voit une véritable toucheKeyDownvirtuelle avec la clé virtuelle correcte suivie du système d’exploitation composéWM_CHAR(leverTextChanged) ( c’est-à-dire une séquence de touches complète par caractère). Les caractères ne sont pas accessibles sur la disposition actuelle (ou nécessitent Ctrl/AltGr) de revenir à un paquet Unicode afin que le caractère exact persiste. Utilisezsend-inputquand vous avez besoin d’une fidélité par séquenceKeyDownde touches (par exemple, conduire un WinUI 3 / WPFTextBoxdont les gestionnaires sont désactivésKeyDown). Pour un hôte de test WinUI 3 normal (sans élévation de privilèges), placez sa fenêtre au premier plan (winapp ui focus/cliquez dessus) carsend-inputcible la fenêtre de premier plan. -
--via post-messagepublie un seulWM_CHARcaractère (il ne publieWM_KEYDOWN/WM_KEYUPpour le texte typé , ceux-ci sont réservés aux clés/combos nommés), ce qui ne déclenche pas de caractère par caractèreKeyDown. Il recible automatiquement le contrôle enfant ciblé de la fenêtre. Par conséquent, les contrôles d’édition win32/WinFormsWM_CHARclassiques atterrissent le texte (levéeTextChanged). Caveat: Les applications WinUI 3 / UWP / XAML (cible principale de winapp) ont des contrôles sans fenêtre qui ignorent les messages publiésWM_CHAR/WM_KEYDOWN. Par conséquent , ni le texte littéral ni les clés nommées (Entrée, chiffres, ...) les atteignent, même si la commande signale la réussite. Il émet un avertissement lorsque la cible ressemble à XAML et quitte toujours 0 (PostMessageest fire-and-forget et ne peut pas confirmer la remise). Permet--via send-inputde piloter des applications WinUI 3 / UWP / WPF ; réservezpost-messagedes contrôles Win32 classiques ou lorsque vous n’en avez besoin qu’à l’étendue des fenêtres entre les niveaux d’intégrité.
-
Sortie JSON (--json) : le résultat est la fenêtre hwnd à laquelle les clés ont été remises. Pour cela, il s’agit --via post-message du contrôle enfant ciblé résolu lorsque la commande y recible (pas nécessairement la fenêtre de niveau -w/-a/-e supérieur), l’automatisation peut confirmer exactement où l’entrée a atterri. Lorsque cette cible effective ressemble à un hôte XAML sans fenêtre, la mise en garde de remise ci-dessus est également exposée comme une warnings[] entrée (le même avis indiqué sur la console), donc une ✅ sortie 0 n’est pas erronée pour la remise confirmée.
set-value
Définissez une valeur sur un élément modifiable par programmation (aucune séquence de touches, aucun premier plan d’application). Utilise une chaîne de secours :
- ValuePattern : TextBox, ComboBox, PasswordBox et la plupart des contrôles modifiables.
- RangeValuePattern : contrôles numériques (Slider, ProgressBar) lorsque la valeur est analysée sous la forme d’un nombre.
-
LegacyIAccessible (
IAccessible::put_accValue) : le secours pour les contrôles de modification TextPattern uniquement qui n’exposent aucun ValuePattern (par exemple, rich-edit/Documentcompose boxes). Cela ferme l’écart de lecture/écriture oùget-valuepeut lire un tel contrôle, maisset-valuene peut pas le faire.
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
Si aucun des trois modèles ne peut définir la valeur, set-value échoue avec une erreur claire pointant vers send-keys le dernier recours.
Tous les éditeurs enrichis ne prennent pas en charge le jeu de programmes. La secours LegacyIAccessible fonctionne uniquement sur les contrôles dont l’accessibilité
IAccessible::put_accValueest implémentée : les contrôles d’édition enrichi Win32 natifs et les surfaces de composition Chromium/Electron/WebView2 font généralement. WinUI 3RichEditBoxet WPFRichTextBoxne prennent pas en charge le paramètre de valeur programmatique , par conception, ils exposent leur contenu à UI Automation en lecture seule (modèle de texte, aucun modèle valeur settable), afin deset-valuene pas les écrire. Utilisezsend-keys(qui a besoin d’un bureau déverrouillé et déverrouillé) pour ceux-ci.
get-value
Lisez la valeur actuelle à partir d’un élément. Utilise une chaîne de secours intelligente : TextPattern (RichEditBox, Document) → ValuePattern (TextBox, Slider) → SelectionPattern (ComboBox, RadioButton, TabView) → Name (étiquettes).
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
Un champ de texte vide lu avec succès retourne "text": "", et non son étiquette d’accessibilité. Le contenu en espace blanc uniquement est également conservé dans JSON.
wait-for --value "" correspond à un champ vide, qu’il soit frais ou effacé après modification. Pour lire l’étiquette d’accessibilité à la place, utilisez get-property --property Name.
mise au point
winapp ui focus txt-textbox-a4b1 -a notepad
Active la fenêtre du contrôle sélectionné si nécessaire, puis concentre le contrôle.
Le sélecteur est requis ; utilisez -a <app> ou -w <HWND> choisissez la cible.
La réussite signifie que la fenêtre était au premier plan et que le contrôle sélectionné a été confirmé HasKeyboardFocus avant que la commande ne soit retournée. La commande autorise jusqu’à 500 ms pour que le contrôle signale le focus ; elle s’arrête si la cible disparaît ou perd le premier plan plutôt que d’essayer de reprendre le focus. Une boîte de dialogue appartenant devant la fenêtre principale n’est pas suffisante : sélectionnez un contrôle dans la boîte de dialogue si c’est votre cible.
Cette commande a besoin d’un bureau déverrouillé et interactif et ne contourne pas les restrictions d’activation Windows. En cas d’échec avec foreground_not_target, activez manuellement la fenêtre prévue et recherchez une boîte de dialogue bloquante avant de réessayer.
Pour focus_not_acquired, inspectez l’interface utilisateur actuelle et choisissez un contrôle focusable.
Pour stale_element, redécouvrir la cible avec inspect ou search.
Conservez la même --on cible lors de la découverte et des commandes de nouvelle tentative.
défilement dans la vue
Faites défiler un élément dans la zone visible.
winapp ui scroll-into-view itm-targetitem-c3d4 -a myapp
wait-for
Attendez qu’un élément apparaisse, disparaisse ou qu’une valeur atteigne une cible.
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
Faire défiler
Faites défiler un élément conteneur. Recherchez des conteneurs à défilement avec : search scroll recherchez [scroll:v] des marqueurs (verticaux) ou [scroll:h] (horizontaux).
# 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
Options :
-
--direction <up|down|left|right>— Faites défiler incrémentiellement viaScrollPattern. -
--to <top|bottom>— Passez au début/à la fin viaScrollPattern. -
--wheel <notches>— Synthétiser l’entrée de la roulette de la souris sur le centre de l’élément viaSendInput, en pouces de roue (detents) :1= un notch up/away,-1= un notch vers le bas/vers le bas,3= trois pouces vers le haut. (Chaque notch est la WindowsWHEEL_DELTAde 120 unités quiSendInputconsomment ; l’interface CLI met à l’échelle les pouces de 120 pour vous.) ContourneScrollPattern.
--direction,--toet--wheelsont mutuellement exclusifs — passent exactement un. Comme--wheelinjecte une entrée à l’échelle du système d’exploitation aux coordonnées de l’écran, elle amène la cible au premier plan et échoue (foreground_not_target) si le focus n’a pas pu être transféré, plutôt que de faire défiler la fenêtre incorrecte.
get-focus
winapp ui get-focused -a myapp
winapp ui get-focused -w <HWND> --json
Affichez l’élément qui possède actuellement le focus clavier dans l’application sélectionnée, y compris les contrôles dont la propriété de l’application est disponible uniquement via leur fenêtre parente.
Avec -w, le focus doit appartenir à cette fenêtre, pas à une autre fenêtre ou à une fenêtre contextuelle détenue dans le même processus. Avec -a, d’autres fenêtres du processus sélectionné sont incluses.
La sortie JSON a hasFocus:false quand aucun élément prioritaire ne peut être vérifié comme appartenant à la cible. Si une requête focus ou de propriété de fenêtre échoue, la commande quitte à la place non zéro ; réessayez get-focusedet redécouvrez la fenêtre si list-windows elle est fermée.
list-windows
Répertorier toutes les fenêtres visibles d’une application, y compris les fenêtres contextuelles et les dialogues. Par défaut, les fenêtres sans titre avec une taille nulle (fenêtres système invisibles) sont exclues.
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
rendement
Relâchez l’interface utilisateur de ce flux de travail tôt au lieu d’attendre la grâce inactive de quatre secondes. Nécessite WINAPP_UI_WORKFLOW_ID; ne prend aucune application et aucun sélecteur. Voir Libérer le tour tôt.
winapp ui yield
winapp ui yield --json # {"released": true} — or false when nothing was held
Prise en charge du framework
| Cadre | Inspecter | search | Invoquer | set-value | capture d'écran |
|---|---|---|---|---|---|
| WPF | ✅ Arborescence complète | ✅ Toutes les propriétés | ✅ Tous les modèles | ✅ ¹ | ✅ |
| WinForms | ✅ | ✅ | ✅ | ✅ | ✅ |
| Win32 | ✅ | ✅ | ✅ | ✅ | ✅ |
| WinUI 3 | ✅ | ✅ | ✅ | ✅ ¹ | ✅ |
| Électron | ⚠️ Arbre chromium | ⚠️ Limité | ⚠️ Varie | ⚠️ Varie | ✅ |
| Flutter | ⚠️ Basique | ⚠️ Basique | ❌ Minimal | ❌ | ✅ |
¹ set-value fonctionne sur n’importe quel contrôle exposant ValuePattern/RangeValuePattern, ainsi que les contrôles de modification TextPattern uniquement dont l’accessibilité est implémentée IAccessible::put_accValue (secours LegacyIAccessible).
WinUI 3 RichEditBox et WPF RichTextBox sont des exceptions : ils exposent uniquement le modèle texte en lecture seule (aucun modèle de valeur settable), de sorte qu'ils ne peuvent pas être définis par programmation par conception ; utilisez send-keys (bureau interactif requis) pour les taper.
Utilisation du moteur à partir de votre propre code
Tout winapp ui est disponible en tant que bibliothèque. Vous pouvez donc générer la même automatisation à partir d’un test ou d’un outil sans l’interpréteur de commandes :
| Package | Ce qu’il ajoute |
|---|---|
Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation |
Inspection, sélecteurs, interaction de modèle UIA, injection d’entrée, captures d’écran |
Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation.Recording |
Enregistrement vidéo dans MP4, plus bundles d’images |
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);
Pour les actions déterministes, utilisez la surcharge en cours 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 rejette le texte ambigu au lieu de choisir une correspondance invoqueable. Les correspondances AutomationId exactes sont prioritaires sur les sous-chaînes Nom ou AutomationId ; Un nom unique peut toujours sélectionner un contrôle dont AutomationId est partagé.
Pour une cible délimitée par l’application, cette vérification couvre toutes ses fenêtres d’application/propriété. Utilisez -w <HWND> (ou une cible de bibliothèque de fenêtre explicite) pour restreindre l’étendue de sélection.
Elle retourne Pattern et PerformedAction a les mêmes significations que le résultat de l’action CLI.
Transmettez un élément retourné par inspection ou sélection, avec son slug runtime ou son AutomationId unique intact. Les actions explicites rejettent une identité manquante ou ambiguë plutôt que de se rebiner par nom et par type de contrôle.
Pour les lectures délimitées, définissez UiSelector.Root sur un autre UiSelector, ControlType sur un nom de type et ClassName sur la classe de fournisseur littéral. Celles-ci utilisent les mêmes prédicats de requête que l’interface CLI. Un seul niveau racine est pris en charge : selector.Root.Root doit être null. Une racine imbriquée lève ArgumentException avant de rechercher la fenêtre cible. Utilisez un AutomationId ou un slug racine unique au lieu d’imbriquer des sélecteurs racines.
UiControlTypes.GetId(name) résout les noms de type officiels et les deux alias documentés, en retournant 0 un nom non valide.
UiControlTypes.GetName(id) retourne le nom canonique, ou Unknown(id) pour un ID non reconnu.
Lors de la transmission d’une UiElement restauration à partir de JSON vers GetTextAsync ou GetPropertiesAsync, conservez son Selector et WindowHandle. Un sélecteur slug doit toujours identifier l’élément d’origine ; s’il n’existe plus, ces lectures lèvent UiElementNotFoundException au lieu de sélectionner un autre élément avec le même AutomationId ou le même nom. Réexécutez la requête d’origine pour actualiser le résultat. Les lectures délimitées propagent également les échecs des getters de propriétés UIA générales et des modèles UIA acquis plutôt que de retourner null ou une valeur capturée précédemment.
L’enregistrement est un package distinct afin que les projets qui inspectent et ne tirent pas l’interface utilisateur du lecteur dans SkiaSharp. Le package d’automatisation cible à la fois net10.0-windows et net10.0-windows10.0.19041.0; ce dernier ajoute Windows Capture graphique, ce qui permet screenshot de capturer les windows composites gpu ou obluded. Consultez le fichier README de chaque package sur NuGet pour obtenir l’API complète et le compromis de l’infrastructure cible.
UiTarget.FromWindowHandle est le point d’entrée pour les frameworks de test qui vous donnent déjà une fenêtre ( par exemple MSTest.Windows.UIAutomation, dont WindowTest.MainWindow est un UIA2 AutomationElement avec lequel MainWindow.Current.NativeWindowHandlevous pontez .
Résolution des problèmes
| Error | Cause | Solution |
|---|---|---|
| « Aucune application en cours d’exécution trouvée » | L’application n’est pas en cours d’exécution ou ne correspond pas au nom | Vérifier le nom du processus ou utiliser le PID |
| « Correspondance de plusieurs fenêtres » | Valeur ambiguë -a |
Utiliser -w <HWND> à partir des options répertoriées |
| « a plusieurs fenêtres » | Le processus comporte plusieurs fenêtres | Utiliser -w <HWND> pour cibler une cible spécifique |
| « Sélecteur correspondant aux éléments N » | Sélecteur hérité ambigu | Utiliser des slugs à partir de la inspect sortie, ou ajouter [0], [1] aux sélecteurs hérités |
| « L’élément a peut-être changé » | Le hachage Slug ne correspond pas à l’élément actuel | Réexécuter inspect ou search pour obtenir des slugs frais |
| « ne prend pas en charge un modèle d’appel » | L’élément ne peut pas être appelé | Utiliser inspect sur l’élément pour rechercher un enfant appelant |
| « Aucune fenêtre UIA trouvée » | UIA ne peut pas voir le processus | Permet list-windows de rechercher le HWND, puis -w |
| « La fenêtre a une taille nulle » | La fenêtre est réduite | L’application sera restaurée automatiquement |
| Fenêtre contextuelle/liste déroulante non dans la capture d’écran | La capture par défaut est par fenêtre et n’inclut pas de superpositions non noyées | Suivez le flux de travail de superposition de capture d’écran pour sélectionner une fenêtre avec -w <hwnd> --capture-screen |
foreground_not_target à partir de --capture-screen |
Windows refusé l’activation, donc une capture d’écran aurait enregistré la fenêtre en face | Cliquez sur la fenêtre cible ou fermez la fenêtre de vol de focus et réessayez ou supprimez --capture-screen |
element_not_found pendant l’enregistrement |
Sélecteur donné, mais aucun élément correspondant | Réexécuter inspect ou search obtenir un nouveau sélecteur |
| WGC indisponible pendant l’enregistrement | Échec de la capture WGC ; pas de secours silencieux | Vérifiez GPU/pilote ; utiliser --capture-screen pour donner son consentement à la capture de contrôleur de domaine d’écran |
Modèles courants
Naviguer et vérifier
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
Rechercher du texte et appeler son parent
# 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
Désambiguer les éléments dupliqués
winapp ui search '#Image' -a myapp; winapp ui invoke itm-image-a2b3 -a myapp
Capture d’écran avec superpositions contextuelles
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
Naviguer, attendre et vérifier (chaîne unique)
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
Découvrir, cliquer et vérifier
winapp ui inspect -a myapp --interactive; winapp ui invoke btn-submit-7a90 -a myapp; winapp ui screenshot -a myapp
Interaction entre la boîte de dialogue fichier
Les dialogues d’ouverture/d’enregistrement de fichiers sont des boîtes de dialogue standard Windows avec prise en charge de l’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>
Permet inspect -w <dialog-hwnd> --interactive de découvrir les slugs réels d’une boîte de dialogue spécifique.
Pourquoi ; le chaînage (pas &&)
L’opérateur powerShell && peut figer lorsqu’une interface CLI native écrit dans stderr ou utilise des séquences d’échappement ANSI. Utilisez ; plutôt : elle exécute chaque commande de manière inconditionnelle et évite ce blocage. Cela est également préférable pour les flux de travail de l’agent : vous souhaitez généralement que la capture d’écran s’exécute même si l’appel avait une sortie non nulle.
Modèles de test CI
Utilisez winapp ui commandes dans les pipelines CI (GitHub Actions, Azure DevOps) pour les tests de fumée et la validation de l’interface utilisateur.
wait-for avec --property et --value agit comme une assertion : elle retourne le code de sortie 1 lors du délai d’expiration, en cas d’échec automatique de l’étape CI.
Lancer et tester dans 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
État de l’élément Assert avec wait-for
wait-for --value interroge jusqu’à ce que la valeur d’un élément corresponde à la chaîne attendue, en utilisant la même secours intelligente que get-value (TextPattern → ValuePattern → SelectionPattern → Name). Retourne le code de sortie 0 lors de la correspondance, le code de sortie 1 sur le délai d’expiration, ce qui en fait une assertion conviviale pour l’intégration continue. Permet --property de vérifier une propriété UIA spécifique à la place.
# 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
Assertion avec la sortie JSON
Utilisez --json PowerShell ou jq pour des assertions plus complexes :
Contrat de code de sortie pour
searchetwait-foren--jsonmode : quand aucun élément ne correspond (search) ou le délai d’attente (wait-for), la commande écrit une enveloppe de résultat entièrement analysée dans stdout ({ "matchCount": 0, ... }ou{ "found": false, "timedOut": true, ... }) et retourne le code de sortie 1. Stderr est vide en--jsonmode (la sortie de l’enregistreur d’événements est supprimée). Branchez sur les champs d’enveloppe, ou sur$LASTEXITCODE, selon ce qui est plus ergonomique.
# 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" }
Les enveloppes JSON sont les suivantes :
-
inspect:{ "depth", "interactive", "hideDisabled", "hideOffscreen", "windows": [...] } -
search:{ "matchCount", "hasMore", "matches": [...] } -
wait-for:{ "found", "waitedMs", "element"?, "timedOut" } -
get-property:{ "elementId", "element", "properties": { ... } }
Les éléments typés utilisent type et numériques x, y, widthet height.
La géométrie est en pixels d’écran physiques.
0,0,0,0est le rectangle vide/sans affichage de l'interface utilisateur de UI Automation dans cette projection ; isOffscreen il est séparé, de sorte qu'un élément hors écran peut toujours avoir des limites non nulles.
Chaque inspect --jsonwindows[] entrée et le status --json résultat incluent windowDpi, scale (windowDpi / 96), dpiAwarenesset coordinateSpace: "physical-screen-pixels". Ceux-ci décrivent le contexte PPP de la fenêtre cible, et non l'analyse inconditionnelle DPI : Windows signale 96 pour une fenêtre sans connaissance, un ppp système pour une fenêtre prenant en charge le système et un PPP moniteur actuel pour une fenêtre prenant en charge chaque moniteur. Si le contexte HWND ou PPP ne peut pas être lu, la commande échoue plutôt que de remplacer silencieusement 96. Lorsque vous status résolvez un processus avant qu’il n’ait une fenêtre de niveau supérieur, hwnd il est 0 et les champs PPP sont omis jusqu’à ce qu’une fenêtre existe. Pour le processus inspect, la fenêtre cible sélectionnée reste défaillante ; si une fenêtre contextuelle ultérieure disparaît une fois que son arborescence a été lue, son windows[] entrée porte dpiError et omet les champs PPP tandis que les arborescences restantes de fenêtres sont toujours retournées.
Consultez les compétences references/ui-json-envelope.md livrées pour obtenir des exemples complets winapp-ui-automation de chaque enveloppe.
Exemple de test de fumée complet
# Launch
$app = winapp run .\build-output --detach --json | ConvertFrom-Json
# Verify app loaded
winapp ui wait-for "Main Page" -a $app.ProcessId -t 30000
# Interact and assert
winapp ui invoke "Add Item" -a $app.ProcessId
winapp ui set-value "Item Name" "Test Item" -a $app.ProcessId
winapp ui invoke "Save" -a $app.ProcessId
winapp ui wait-for "Test Item" -a $app.ProcessId -t 5000 # assert item appeared in list
winapp ui wait-for "Save" -a $app.ProcessId --gone -t 3000 # assert save dialog closed
# Visual verification
winapp ui screenshot -a $app.ProcessId -o smoke-test.png
Windows developer