mcpField
W
winapp-ui-automation

winapp-ui-automation

github.com/microsoftテスト・品質1.3k61 回インストール今日更新
リポジトリ

winapp-ui-automation について

winapp-ui-automationは、実行中のWindowsアプリのUIをコマンドラインから調査・操作するためのスキルです。複数のUIフレームワークに対応し、並行するデスクトップ操作も調整します。

主な機能

  1. 01UI要素の検査と検索
  2. 02クリック、呼び出し、値の入力
  3. 03UI状態の変化待ち
  4. 04スクリーンショットと録画
  5. 05並行するUIワークフローの調整

活用シーン

  1. 01開発中のUI状態の確認
  2. 02Windowsアプリのテストフロー自動化
  3. 03画面上の動作を基にした問題調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/microsoft/winappcli --skill winapp-ui-automation

インストール後、Claude Code で/winapp-ui-automationを入力して読み込まれたか確認します。

同梱ファイルreferences/ui-json-envelope.md

詳細

winappを自分で実行できない場合(シェルがない、またはコマンドが拒否される場合)は、手順を説明するだけでなく、ユーザーのプロジェクト向けの正確なwinappコマンドを提示してください。

使用する場面

  • コマンドラインから、実行中のWindowsアプリのUIを調べる場合
  • AIエージェントがWindowsアプリを操作する場合(ボタンのクリック、テキストの読み取り、スクリーンショットの撮影)
  • 開発中またはテスト中にUIの状態を確認する場合
  • PlaywrightやSeleniumを使わずにUIワークフローを自動化する場合
  • ユーザーが見たり操作したりできる状態に基づいて、WinUI 3、WPF、WinForms、Win32、ElectronアプリのUIをデバッグする場合
  • WinUI 3アプリのXAML内部を調べる場合(値やバインドがそのように解決された理由、要素を生成したXAMLの行、実行中のプロパティ編集、UIレビューコメント)は対象外です。winui-devtoolsを使用してください。

前提条件

WinUI 3のXAMLソース/ツリー、バインド、依存関係プロパティの診断と編集には、 winui-devtoolsスキルとwinapp devtoolsを使用してください。対象がアタッチされているか、--attachによるインジェクションが明示的に許可されている必要があります。PIDだけでは同意を得たことになりません。AutomationIdは両ツールでセレクターとして機能しますが、生成されたスラッグはDevToolsには引き継がれません。フレームワークをまたぐ操作、スクリーンショット、待機、アクセシビリティには引き続きwinapp uiを使用してください。

シナリオを操作しながらWinUIの処理を測定するには、 パフォーマンススキルを使用して、UI操作の前後にキャプチャマーカーを設定してください。

  • UIAモード(任意のアプリ):セットアップは不要です。実行中のWindowsアプリで動作します。
  • 入力を注入する動詞(click、hover、drag、touch、pen、scroll --wheel/--wheel-horizontal、send-keys --via send-input):対象ウィンドウを前面に表示できる、ロックされていない対話型デスクトップが必要です。ロック中またはセキュアデスクトップでは、no_interactive_desktopですぐに失敗します。UIAパターンの動詞(inspect、search、get-*、wait-for、set-value、invoke、scroll --direction/--to)はヘッドレス環境やロック中のセッションでも使用できます。CIではこちらを優先してください。
  • screenshotはこのグループには含まれません。必ず排他的に実行されるため、ほかのUIワークフローの後ろにキューイングされます。また、キャプチャには使用可能な対話型デスクトップが必要な場合があります。エンジンは対象が最小化されている場合に復元し、フレームキャプチャが利用できない場合、または--capture-screenが使用された場合は、対象を前面に表示します。
  • --capture-screenにはウィンドウが1つだけ必要です。-w <hwnd>を指定すると、そのウィンドウの画面領域が対象になります。領域には、その上に見えているものも含まれます。-aで複数のトップレベルウィンドウまたは所有ウィンドウに一致すると、キャプチャ前にinvalid_argumentsでコマンドが失敗します。winapp ui list-windows -a <app>を実行し、-w <hwnd>を指定して再試行してください。
  • ほかのUIワークフローが同時に実行される可能性がある場合は、論理ワークフローごとにワークフローIDを1つ設定してください(下記参照)。設定しなくても問題は起きませんが、コマンドが同じワークフローに属するものとして認識されません。

他の UI ワークフローとの協調

Windows では、フォアグラウンドウィンドウ、キーボードフォーカス、カーソル、入力ストリームはそれぞれ 1 つです。そのため、winapp ui はデスクトップを操作するコマンドに協調的なターン制を適用し、並行するワークフローが互いのフォーカスを奪ったり、相手のメニューを閉じたりできないようにします。これは常に有効です。読み取り専用のコマンドは待機しません。

コマンドをまたいでデスクトップを保持する機能は、オプトインです。ID を指定しない場合、各コマンドは実行終了と同時にデスクトップを解放する単発の操作になります。

# Set once per logical UI workflow — same value for cooperating calls, different values for
# independent workflows (even from the same agent).
$env:WINAPP_UI_WORKFLOW_ID = [guid]::NewGuid().ToString()

エージェントから操作する際に重要なルールは次のとおりです。

  • **各ツール呼び出しでは、通常、新しいシェルが使われます。**プロセスの祖先関係による代替手段はないため、コマンドは指定した ID によってのみグループ化されます。ID がなければ、各呼び出しはそれぞれ別のワークフローになります。
  • **ID を持つワークフローは、最後のコマンドの実行後 4 秒間、ターンを保持します。**これにより、1 つのスクリプト内で連続して実行されるコマンドに対応できます。推論している間に意図的に期限切れになるため、終了したと伝えられない場合のフォールバックとして扱い、終了手段としては使わないでください。
  • **既知の一連の操作が終わったら winapp ui yield を実行してください。**不要な 4 秒間の猶予が終わるのを待っているワークフローを待たせることなく、デスクトップをすぐに引き渡せます。2 回実行した場合や、猶予期間が過ぎてから実行した場合も、問題なく成功します。
  • **推論の間が空いた後は、セットアップをやり直してください。**別のワークフローがデスクトップを操作した可能性があるため、メニューを再度開く、または移動し直し、要素を再特定してから操作してください。一時的な UI 状態が維持されているとは限りません。
  • **一連の操作がわかっている場合は、何度も呼び出しを往復するより、まとまったスクリプトを 1 つ実行してください。**例:winapp ui invoke View -w $hwnd; winapp ui search "Status bar" -w $hwnd; winapp ui click "Status bar" -w $hwnd; winapp ui yield
  • **record は、それを実行するワークフローとターンを共有するため、同じワークフロー内のクリックや入力は実行中に記録されます。ただし、両方のコマンドに同じ ID が指定されている場合に限ります。**ID を指定しない record は、実行時間の全体にわたって他のすべてのワークフローをブロックします。
  • **順序は、所有者への優先割り当てが先で、その後は FIFO です。**アクティブなワークフローは、すでに待機している他のワークフローより先にコマンドを続けて実行できます。ターンを譲るか猶予期間が過ぎると、待機中のワークフローが到着順に実行されます。
  • **待機時間に制限はなく、キャンセルできます。**1 秒経過すると、デスクトップを使用中のワークフローとその経過時間を示す通知が stderr に表示されます(--json および --quiet では表示されません)。Ctrl+C で終了すると、終了コードは 130、エラーコードは cancelled となり、コマンドは実行されません。
  • **厳密な上限はありません。**長時間のスクリプト、終了しない記録、または失敗を繰り返すループは、完了するか停止されるまで、他のデスクトップを変更するワークフローをブロックする可能性があります。

待機しないコマンド:status、list-windows、inspect、search、get-*、wait-for。 ターンは待ちますが、デスクトップを取得しないコマンド(ヘッドレス/ロックされたセッションに対応):set-value、scroll-into-view、scroll --direction/--to、record。これらはアプリを変更するため、別のワークフローの後ろに並びます。自分のワークフロー内では、他の共有操作と並行して実行されます。これにより、record は記録対象の set-value 呼び出しをキャプチャできます。ただし、自分のワークフロー内で先に実行された DesktopExclusive コマンドの後ろでは待機するため、click の後に set-value を実行すると、記述した順序で実行されます。 デスクトップを排他的に取得するコマンド:invoke、click、drag、hover、scroll --wheel/--wheel-horizontal、touch、pen、focus、send-keys、screenshot。

# Finish a workflow deliberately rather than leaving the desktop reserved for four more seconds.
winapp ui yield

よくあるパターン

特定のコンテナー内を読み取る
winapp ui search "Welcome to MyApp" -a myapp --root MailRow --type Text --class-name TextBlock
winapp ui get-value Subject -a myapp --root MailRow --type TextBox
winapp ui wait-for Subject -a myapp --root MailRow --type Edit --value Ready --timeout 10000
winapp ui search --class-name CalendarSurface -a myapp   # no text selector needed

search、get-property、get-value、wait-for と、選択した 1 つの要素に作用するコマンド(invoke、set-value、click、focus など。ただし send-keys --target は除く)では、--root、--type、--class-name を一緒に、または個別に使用します。 --type と --class-name はセレクターなしでも機能します。その場合、search 以外のコマンドでは一致する要素がちょうど 1 つ必要です。一致が曖昧な場合は、最初の 5 件とそのスラッグが表示されます。--root だけではクエリになりません。set-value では、セレクターに "" を渡します。 click、hover、touch、pen では、フィルターを --at や --path と組み合わせられません。ルートは一意でなければならず、その子孫だけが一致します。wait-for は、最初は要素が存在しない場合も含め、ポーリングのたびにルートを再解決します。型名とリテラルの ClassName 全体の値では、大文字と小文字は区別されません。型の別名は TextBox → Edit と TextBlock → Text のみです。 型の全語彙、境界、エラー動作については、スコープ付きクエリと型指定クエリを参照してください。

検出して操作する
# See what's clickable, then screenshot for context
winapp ui inspect -a myapp --interactive; winapp ui screenshot -a myapp

# Click and verify the page changed
winapp ui invoke btn-settings-a1b2 -a myapp; winapp ui wait-for pn-settingspage-c3d4 -a myapp --timeout 3000; winapp ui screenshot -a myapp

# Fill a form and submit
winapp ui set-value txt-searchbox-e5f6 "hello" -a myapp; winapp ui invoke btn-submit-7a90 -a myapp; winapp ui screenshot -a myapp
表示されているテキストを見つけてクリックする
# Search by text — output shows invokable ancestor
winapp ui search "Save changes" -a myapp
# Output:
#   lbl-savechanges-a1b2 "Save changes" (120,40 80x20)
#         ^ invoke via: btn-save-c3d4 "Save"

# Invoke by text — auto-walks to parent Button
winapp ui invoke 'Save changes' -a myapp
複数ページのアプリを操作する
# Click nav item, wait for page, inspect what's available
winapp ui invoke itm-samples-3f2c -a myapp; winapp ui wait-for pn-samplespage-b4e7 -a myapp; winapp ui inspect -a myapp --interactive
テストで正確なアクションを選択する
winapp ui invoke SettingsCategory -a myapp --action select
winapp ui invoke AgreeCheckbox -a myapp --action toggle-on --json
winapp ui invoke Open -w <dialog-HWND> --type Button --action invoke

自動的なパターン判定と祖先へのフォールバックを避けるには、--action を使用します。既存の自動動作を使う場合は省略します。--root、--type、--class-name を指定すると、フィルターは読み取りクエリと同じ一致ルールに従います。選択したアプリ/ウィンドウ内でちょうど 1 つの要素に一致する必要があり、一致しない場合は操作せずにコマンドが失敗します。また、祖先へのフォールバックはスキップされます。サポートされるアクション、スコープ、冪等な切り替え、失敗からの復旧についてはアクションリファレンスを、アクションの結果についてはJSON エンベロープを参照してください。

重複する要素を区別する
# Text matches by substring, but an element named exactly the text wins
winapp ui invoke Submit -a myapp      # acts on Button "Submit", not Button "Submit Order"
# When several elements share that name, the error shows slugs for each — pick the right one
winapp ui invoke Save -a myapp
# → Selector matched 2 elements:
#   [0] Button "Save" → btn-save-a1b2
#   [1] Button "Save" → btn-save-c3d4
# Use the slug: winapp ui invoke btn-save-c3d4 -a myapp

主な概念

  • セレクターブラケット:inspect と search の出力では、セレクターが [角括弧] で示されます。他の ui コマンドでは、その括弧内の値を使用します。セレクターは AutomationId(安定しており、開発者が設定)または生成されたスラッグ(例:btn-name-hash)です。
  • AutomationId セレクター:要素に一意の AutomationId がある場合、それがそのままセレクターになります(例:[MinimizeButton])。レイアウトの変更やローカライズ後も維持されるため、安定したターゲット指定に適しています。
  • スラッグセレクター:一意の AutomationId がない場合は、生成されたスラッグが使用されます(例:[btn-close-a2b3])。形式は prefix-name-hash です。UI の変更後に古くなることがあります。
  • プレーンテキスト検索:search と invoke ではプレーンテキストを使用できます。search Minimize は、Name または AutomationId に「Minimize」を含む要素を検索します(部分一致、大文字と小文字は区別しません)。特別な構文は不要です。1 つの要素に作用するコマンドでは、まず AutomationId の完全一致を優先し、次に Name がテキストと完全一致する唯一の要素を選びます(大文字と小文字は区別しません)。search では引き続きすべての一致結果が表示されます。
  • --interactive フラグ:自動深度 8 で、invoke、クリック、値の設定が可能な要素(テキストドキュメントを含む)に絞り込みます。操作可能な対象を最もすばやく確認できます。
  • 呼び出し可能な祖先の表示:検索結果が呼び出し可能でない場合、最も近い呼び出し可能な親がセレクターとともに表示されます。
  • ; による連結:; でコマンドを連結すると、1 回の呼び出しで複数の操作を実行でき、エージェントとの往復を減らせます。
  • -a と -w:アプリを名前/タイトル/PID で見つけるには -a を使用します。安定してウィンドウを指定するには -w <HWND> を使用します。
  • 要素マーカー:切り替え項目の [on]/[off]、[collapsed]/[expanded]、スクロール可能なコンテナーの [scroll:v]/[scroll:h]/[scroll:vh]、[offscreen]、[disabled]、編集可能な要素の value="..."

使用方法

接続して検出する
# Core loop and examples: `winapp ui --help`. Connect and see interactive elements in one call:
winapp ui status -a myapp; winapp ui inspect -a myapp --interactive
要素ツリーを調べる
winapp ui inspect -a myapp --interactive      # elements you can invoke, click, or set-value; auto-depth 8
winapp ui inspect -a myapp --depth 5          # deeper tree at depth 5
winapp ui inspect txt-searchbox-e5f6 -a myapp  # subtree rooted at element
winapp ui inspect btn-settings-a1b2 -a myapp --ancestors  # walk up from element to root
winapp ui inspect -a myapp --hide-offscreen   # hide offscreen elements
要素を検索する
winapp ui search Close -a myapp               # finds elements with "Close" in name or automationId
winapp ui search Button -a myapp              # finds elements with "Button" in name (also matches type names)
winapp ui search image -a myapp               # case-insensitive substring match
スクリーンショット
# App screenshot (may include owned windows in a labeled composite)
winapp ui screenshot -a myapp --output page.png

# Crop to element; capture with popups visible
winapp ui screenshot txt-searchbox-e5f6 -a myapp --output search.png
winapp ui list-windows -a myapp # use the main window's HWND below
winapp ui screenshot -w <hwnd> --capture-screen --output with-popups.png

# Bring window to foreground first (matches what the user is currently seeing)
winapp ui screenshot -a myapp --focus --output focused.png

既定のキャプチャでは、メイン HWND を明示していても所有ウィンドウが含まれ、個別の画像ファイルではなく、ラベル付きの合成画像が 1 つ作成されます。開いているメニュー、フライアウト、ツールチップ、ティーチングチップ内の項目を指定する要素セレクターは、その項目のポップアップウィンドウから切り抜くため、--capture-screen は不要です。スコープと画面上のオーバーレイの配置については、スクリーンショットを参照してください。--on sandbox を指定した場合、報告されるスクリーンショットのパスは、ホスト側で配信される保存先です。WinUI DevTools が接続されているアプリでは、スクリーンショットにツールバー、マーカー、コメントパネル、インスペクターウィンドウは含まれません。

動画を録画する(H.264 MP4)

ウィンドウまたは要素の領域を MP4 に録画します。エージェントやスクリプトでは、正の値を指定する --duration-sec N を推奨します。指定しない場合、録画は停止シグナルを待ちます。npm ヘルパーでは durationSec(整数、1~86400)が必須です。ヘルパーの中止シグナルは強制キャンセルであり、正常な停止ではありません。

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

# Recommended agent evidence: MP4 plus timestamped JPEGs and an NDJSON index
winapp ui record -a myapp --frames --duration-sec 10 --fps 10 --output evidence.mp4 --json

# Include overlays/popups (captures from screen DC; may include occluding windows)
winapp ui record -a myapp --capture-screen --duration-sec 5 --output with-popups.mp4

# Show the mouse pointer and click rings (for demos of click-driven flows)
winapp ui record -a myapp --cursor --duration-sec 10 --output demo.mp4

# Programmatic stop: pipe a newline to stop and finalize the MP4 (for agent/script callers)
"" | winapp ui record -a myapp --json --output capture.mp4
  • 既定の --duration-sec 0 では、Ctrl+C、改行、またはリダイレクトされた stdin の EOF まで録画します。
  • --frames は、マニフェスト、NDJSON インデックス、変更があった JPEG を含む <output-name>.frames を書き込みます。1~30 fps と --max-edge 64~4096(既定値は 1280)に対応し、上限は 1 GiB です。遷移を制限するには elapsedMs を使用します。
  • --cursor はポインターとクリックごとのリングを描画します。リングを表示せずにポインターだけを表示するには、--no-click-highlight を追加します。--frames を指定すると、各 frames.ndjson の行に、画像ピクセル単位の cursor(x、y、visible、inFrame)と clicks(button、kind、elapsedMs、x、y)が追加されます。
  • 既存の録画出力は、既定では拒否されます。新しいパスを使用するか、新しい録画の完了後に置き換えるために --overwrite を明示的に指定してください。以前のフレームディレクトリは削除されず、アーカイブされます。一部失敗した場合は、報告された証拠を保持し、recoveryHint に従ってください。
  • 既定の録画では、開いているメニュー、フライアウト、ツールチップがウィンドウ上にそのまま描画されます。フラグは不要です。これらはウィンドウの境界でクリップされます。他のプロセスのポップアップには --capture-screen が必要です(録画中のメニューとフライアウトを参照)。
  • --capture-screen は画面 DC からキャプチャし、オーバーレイやポップアップを含めます。最初にウィンドウが前面に表示されます。WGC を利用できず、--capture-screen も渡されていない場合、CLI はエラーを返します。画面 DC からのキャプチャに同意するには、--capture-screen を指定して再実行してください。画面 DC は実際に手前に表示されているものをキャプチャするため、キャプチャ直前に対象が前面にあることが 確認 されます。アクティブ化が拒否された場合、コマンドは foreground_not_target で失敗し、誤ったウィンドウの画像を返すのではなく、何も書き込みません。
  • どの要素にも一致しないセレクターを指定すると、すぐに element_not_found で失敗します(ウィンドウ全体を黙って録画することはありません)。
  • 開いているメニュー、フライアウト、ツールチップ、ティーチングチップ内の項目を指定するセレクターは、背後のウィンドウではなく、その項目のポップアップウィンドウから録画します。
  • --json は、最終結果を stdout に、1 行につき 1 つの JSON イベントを stderr に書き込みます。
ホバー(ツールチップ、フライアウト、ホバー状態用)

--dwell-time <ms> は、ホバー後に待機する時間を設定します(既定値:800、範囲:0~10000)。

winapp ui list-windows -a myapp # use the main window's HWND below, not the tooltip's

# Hover to trigger tooltip, then capture it (default 800ms dwell)
winapp ui hover btn-info-a1b2 -a myapp; winapp ui screenshot -w <hwnd> --capture-screen --output tooltip.png

# Longer dwell for apps with slow tooltip timers
winapp ui hover btn-info-a1b2 -a myapp --dwell-time 1200; winapp ui screenshot -w <hwnd> --capture-screen
画面上の点をクリックまたはホバーする

WebView2 ページ内や大きなコントロールの一部など、要素の中央ではなく点を押す必要がある場合は、セレクターの代わりに ui inspect で得た画面座標を使って --at x,y を渡します。--at はセレクターと併用できません。

winapp ui click --at 1520,780 -a myapp            # add --right or --double as needed
winapp ui hover --at 1520,780 -a myapp
キーボード入力を送信する

キーストロークを合成します。clickに相当するキーボード操作です。矢印キー/Tab/Enterによる移動、ショートカット、1文字ずつの入力(set-valueのアトミックな書き込みとは異なります)に使用します。トークンは空白で区切ります。名前付きキー(enter、down、tab、esc、f5)、修飾キーの組み合わせ(ctrl+shift+t)、リテラルテキスト(hello)、生の仮想キー(vk=0xNN)を指定できます。

# Keyboard navigation then commit
winapp ui send-keys "down down enter" -a myapp

# Type the literal words "down down enter" instead of pressing those keys (text= escapes each token)
winapp ui send-keys "text=down text=down text=enter" -a myapp

# Same intent, less typing: --verbatim types the whole argument literally (and keeps exact whitespace)
winapp ui send-keys "down down enter" -a myapp --verbatim

# Shortcut: select all and delete
winapp ui send-keys "ctrl+a delete" -a myapp

# Focus a field, then type text into it
winapp ui send-keys "Hello world" --target txt-name-a1b2 -a myapp

# Transport: --via post-message (default, HWND-targeted, bypasses UIPI) or send-input (OS-wide)
winapp ui send-keys "enter" -a myapp --via send-input

# Fire a global hotkey: win+... is refused by default (acts on the shell); opt in with --allow-system-keys
winapp ui send-keys "win+shift+v" -a myapp --via send-input --allow-system-keys

# Screen-reader command: hold capslock or insert (Narrator+Ctrl+F12 toggles Narrator developer mode)
winapp ui send-keys "ctrl+capslock+f12" -a myapp --via send-input
  • スクリーンリーダーのコマンドでは、修飾キーとしてcapslockまたはinsertを押し続けます(ctrl+capslock+f12)。また、--via send-inputが必要です。スクリーンリーダーはポストされたキーを受け取らないため、post-messageではエラーになります。スクリーンリーダーが起動していない場合、capslockを押し続けるとCaps Lockがオンまたはオフになり(コマンドが警告します)、これを避けるにはinsertを押し続けてください。
  • 修飾キーで始まり、中間部分に不明な要素があるトークン(ctrl+a+b)は、リテラルテキストではなくエラーになります。入力するにはtext=または--verbatimを使用してください。
  • デフォルトのpost-messageはHWNDを対象とし、整合性レベルをまたいで動作しますが、WH_KEYBOARD_LLグローバルホットキーは実行できません。対象ウィンドウのフォーカスされている子コントロールに自動的に送信先を切り替えるため、従来のWin32/WinFormsの子ウィンドウコントロール(編集ボックスなど)には入力が届きます。WinUI 3/UWP/XAMLのコントロールはウィンドウレスで、ポストされたWM_CHAR/WM_KEYDOWNを無視します。そのため、post-messageではキーもテキストも送信できません(コマンドは警告を出しますが、PostMessageでは送信を確認できないため、終了コードは0のままです)。WinUI 3/UWP/XAMLアプリでは**--via send-input**を使用してください。
  • キー名/修飾キー名と衝突するトークン(例:enter、down、ctrl+a)は、そのキーとして押されます。リテラルテキストとして入力するには、先頭にtext=を付けてください。たとえば、text=enterは単語「enter」を入力します。text=down text=down text=enterのようにtext=トークンを連ねると、フレーズをそのまま入力できます。text=値の中でバックスラッシュを使うと、トークナイザーが通常ならまとめてしまう空白を入力できます。\s→スペース、\t→タブ、\n→改行、\r→CR、\\→バックスラッシュ(例:text=a\s\sb→「a b」)。引数全体がリテラルテキストの場合は、各トークンをエスケープする代わりに--verbatimを指定してください。キー引数全体をそのまま入力し、キー/組み合わせ/vk=/text=として解析せず、空白も正確に保持します。send-keys "down down enter" --verbatimは単語を入力します。(--verbatimはバックスラッシュエスケープをデコードしません。制御文字にはtext=トークンを使用してください。)
  • send-inputは完全な実入力ですが、フォアグラウンドウィンドウに送信され、昇格したプロセスからAppContainer/AppXへの入力注入はUIPIによってブロックされます。システム予約の組み合わせ(win+l、alt+f4、ctrl+shift+esc、ctrl+alt+del、alt+tabなど)は、対象だけでなくOS/シェルに作用するため拒否されます。PowerToysのwin+shift+vやwin+rなどのグローバルホットキーを実行する場合は**--allow-system-keysを指定して許可するか、ウィンドウに直接送信するには(ウィンドウ単位での送信となる)--via post-messageを使用してください。win+lとctrl+alt+delは、--allow-system-keysを指定しても引き続きブロックされます**。win+lはLockWorkStation()を使ってワークステーションをロックするため(自動化から復旧できません)、ctrl+alt+delはセキュアアテンションシーケンス(SAS)であり、フラグの指定にかかわらずWindowsが注入された入力を破棄します。そのため、成功したと誤って報告せず、invalid_argumentsエラーになります。ロック画面またはセキュアデスクトップでは、send-inputはno_interactive_desktopで即座に失敗します。
  • キーストロークごとのイベント:名前付きキー/組み合わせは、どちらの転送方式でも実際のKeyDownを発生させます。リテラルテキストの入力では、--via send-inputは各文字を対応するVK(+Shift)にマッピングするため、各文字で実際のKeyDownと、OSが生成するWM_CHAR(TextChanged)が発生します。下流のロジックがKeyDownを基準に動作する場合(WinUI 3/WPFのTextBoxなど)はこれを使用し、事前に対象ウィンドウをフォアグラウンドにしてください。--via post-messageはフォーカスされている子コントロールに文字ごとのWM_CHARをポストします(TextChangedが発生し、整合性レベルをまたいで従来のWin32コントロールに正しいテキストが入力されます)が、文字ごとのKeyDownは発生しません。また、WinUI 3/UWP/XAMLのコントロールはウィンドウレスのため、名前付きキーもテキストもまったく届きません。その場合は--via send-inputを使用してください。
  • --via send-inputで長いリテラルテキストを入力する場合、自動的に速度が調整されます。テキストを小さな文字チャンクに分け、1回の実行中にチャンクごとに短い間隔を置いて、一度に1つずつSendInputで注入します。これにより、対象が入力キューを処理でき、すべての文字が入力されます。途切れない一度のバーストでは入力キューがあふれ、コマンドが成功を報告しても文字が黙って失われます。この間隔調整は、1回の長いテキスト入力に限られます。短いテキスト、キー名、修飾キーの組み合わせ(ctrl+a deleteのような連続入力を含む)は、遅延を追加せずに注入されます。ペース調整が必要な大きさのデータでは、コマンドが情報警告を出します。各チャンクはその時点でフォアグラウンドにあるウィンドウに入力されるため、send-inputは継続チャンクを送信する前に、対象が引き続きフォアグラウンドを所有していることを再確認します。入力中にフォーカスが対象から外れた場合は**foreground_not_targetで中断**され、入力途中でフォーカスが変わっても、残りのテキストが別のウィンドウに入力されることはありません(alt+tabのようにフォーカスを変更するキーの組み合わせは例外で、フォーカス逸脱とはみなされません)。大量のテキストをまとめて入力する場合は、対応しているコントロールでset-valueを使用してください(アトミックで、キーストロークやフォアグラウンド化は不要です)。
ドラッグ(並べ替え、サイズ変更、スライダー、ドラッグ&ドロップ)

マウスボタンをある位置で押し、別の位置まで移動してから離します。drag <from> <to> を指定します。各端点には要素セレクター(要素の中央を使用)または ui inspect で取得した画面上の x,y 座標を指定します。中間の移動にも SendInput を使用するため、アプリには実際の WM_MOUSEMOVE のイベント列として認識されます。

# Reorder one item onto another (center → center)
winapp ui drag itm-card-9f8e itm-slot-2c1a -a myapp

# Element center → screen coordinates (as reported by `ui inspect`)
winapp ui drag itm-card-9f8e 300,400 -a myapp

# Raw screen coordinates → screen coordinates
winapp ui drag 120,200 480,200 -a myapp

# Right-button drag
winapp ui drag itm-card-9f8e itm-trash-0001 -a myapp --right
  • セレクターを指定した場合は、要素の中央から、または要素の中央までドラッグします。x,y は ui inspect/search が報告するものと同じ座標空間上の画面座標です。要素の端点はドラッグの直前に再解決されます。アニメーション中の場合は target_moved エラーで失敗します。ロック画面またはセキュアデスクトップでは、ドラッグは no_interactive_desktop エラーで失敗します。
タッチジェスチャ(タップ、スワイプ、ピンチ、ストレッチ、長押し)

合成タッチ入力を注入します。接触位置の基準点には、要素セレクター(要素の中央)または明示的な画面座標 --at x,y を指定します。最新の合成ポインターデバイスを優先して使用し、使用できない場合は従来のタッチ注入 API にフォールバックします。

# Tap an element center; or tap explicit screen coordinates
winapp ui touch btn-ok-1a2b -a myapp
winapp ui touch -a myapp --at 320,240

# Long-press, swipe, and two-finger pinch/stretch (zoom)
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
winapp ui touch img-map-9f8e -a myapp --gesture stretch --distance 200 --angle 90
  • ジェスチャ:tap(既定)、double-tap、long-press、swipe、pinch、stretch。--fingers は 1~10 を指定します(pinch/stretch は常に 2)。--angle は 0~359 を指定し、pinch/stretch の指の軸を設定します(0 は水平、90 は垂直)。前面に表示されている有効な対象がない場合は実行されません(no_target/foreground_not_target/no_interactive_desktop)。すべての座標を対象ウィンドウに対して検証します。ウィンドウ外の点がある場合、致命的ではない警告が出力されます(--json では warnings[])。その場合も注入は続行されます。これはマウス操作の動詞と同様の動作です。デバイスがタッチ入力の注入に対応していない場合、成功したかのように見せることなく、実際の Win32 エラーがコマンドに表示されます。リモートデスクトップ/VM セッションでは、終了コードが 0 でも入力が配信されるとは限りません。コマンドは配信が不確実であることを示す警告を追加します(--json では warnings[])。スクリーンショットで効果を確認してください。
ペン/スタイラス(タップとインクストローク)

合成ペン入力を注入します(Windows 10 1809 以降)。要素の中央、明示的な --at、またはインクストローク全体を表す --path を指定し、筆圧/傾き/消しゴムを制御します。

# Pen tap at element center; firm tap at explicit coords
winapp ui pen canvas-1a2b -a myapp
winapp ui pen -a myapp --at 320,240 --pressure 0.8

# Draw an ink stroke, or erase along one
winapp ui pen -a myapp --path "100,100 150,120 210,140 260,120"
winapp ui pen -a myapp --path "100,100 260,100" --eraser
  • --pressure は 0.0~1.0、--tilt-x/--tilt-y は ±90° を指定します。消しゴム側を使用するには --eraser を指定します。注入時の安全性は touch と同じです。前面に表示されている有効な対象ウィンドウが必要で、すべてのインク点を検証します(ウィンドウ外の場合は致命的ではない警告 warnings[] が表示されますが、注入は続行されます)。リモートデスクトップ経由では、ペン入力が届かないことが特に多くあります。終了コードが 0 でも、呼び出しが成功しただけでペン入力がアプリに届いていない場合があります。コマンドは配信が不確実であることを示す警告を追加します(--json では warnings[])。ペン操作のフローは、ローカルの対話型デスクトップで検証してください。
要素の状態を読み取る
# Read text/value content (works for RichEditBox, TextBox, ComboBox, Slider, labels)
winapp ui get-value doc-texteditor-53ad -a notepad
winapp ui get-value SearchBox -a myapp
winapp ui get-value CmbTheme -a myapp              # reads ComboBox selected item via SelectionPattern

# Check toggle/selection state, value, scroll position
winapp ui get-property chk-agreecheckbox-b2c3 -a myapp --property ToggleState
winapp ui get-property txt-textbox-a4b1 -a myapp --property Value
winapp ui get-property cmb-modellist-d5e6 -a myapp --property IsSelected

# Read formatting across the whole text document (not the selection)
winapp ui get-property Document -a myapp --property FontWeight --json

# See what has keyboard focus
winapp ui get-focused -a myapp

get-focused では、-a を指定すると選択したプロセスのウィンドウが含まれます。-w を指定すると、その正確なウィンドウのみに絞り込まれ、所有するポップアップは除外されます。コントロール自身がプロセス ID を持たない場合でも、親ウィンドウを通じて対象に属することがあります。フォーカス対象が見つからない場合とクエリエラーの処理については、references/ui-json-envelope.md を参照してください。

空のフィールドまたはクリア済みのフィールドを確認するには、winapp ui wait-for SearchBox -a myapp --value "" を使用してください。 JSON 出力とアクセシビリティラベルを個別に読み取る方法については、空の値の動作を参照してください。

get-property は FontName、FontSize、ForegroundColor、IsItalic、 StrikethroughStyle も受け付けます。--property を省略すると、6 つの書式属性すべてが含まれます。Mixed、NotSupported、Unavailable は異なる状態として扱い、書式の値と見なさないでください。名前では大文字と小文字が区別されます。不明な名前を指定すると invalid_arguments で失敗します。単位と状態の意味については書式設定のリファレンスを、JSON の形式については references/ui-json-envelope.md を参照してください。

値の設定

キーボード入力に備えてコントロールにフォーカスを設定するには、winapp ui focus <selector> -a <app> を使用します (Sandbox で作業する場合は --on sandbox を付けたままにします)。対象コントロールのウィンドウをアクティブにし、成功する前にフォアグラウンドとキーボードフォーカスの両方を確認します。ウィンドウが最小化されている場合は、先に元に戻します。コマンドで対象ウィンドウが最小化されていると報告された場合(Calculator など、一部のアプリは元に戻すまで UI を表示しません)、winapp ui focus -a <app>(セレクターなし)を実行してウィンドウを元に戻してアクティブにし、その後に再試行します。フォーカスを設定する代わりにスクリーンショットを使用しないでください。アクティブ化が拒否された場合は、操作を妨げているダイアログがないか確認し、目的のウィンドウをアクティブにするようユーザーに依頼してください。ループで再試行したり、ローカルデスクトップに切り替えたりしないでください。失敗コードと復旧方法については、フォーカスのリファレンスを参照してください。

set-value は、フォールバックチェーン(ValuePattern → RangeValuePattern(数値) → TextPattern のみをサポートする編集コントロール向けの LegacyIAccessible put_accValue)を介して、プログラムから値を書き込みます(キー入力なし、フォアグラウンド化なし)。

winapp ui set-value txt-searchbox-e5f6 "hello" -a myapp        # TextBox/ComboBox via ValuePattern
winapp ui set-value sld-volume-b2c3 75 -a myapp                # Slider via RangeValuePattern
winapp ui set-value doc-compose-9f3a "hello" -a myapp          # RichEdit/compose box via LegacyIAccessible
  • LegacyIAccessible のフォールバックは、アクセシビリティ実装が put_accValue をサポートしていれば、ValuePattern を公開しないリッチ編集/作成コントロールにも対応します(ネイティブの Win32 リッチ編集や Chromium/Electron/WebView2 の作成ボックスでは通常サポートされています)。
  • WinUI 3 RichEditBox と WPF RichTextBox は、プログラムによる値設定をサポートしません。設計上、UI Automation の値 API からは読み取り専用になっています(Text pattern はありますが、設定可能な Value pattern はありません)。set-value を実行すると明確なエラーが発生します。これらに入力するには、代わりに send-keys を使用してください(デスクトップのロックが解除され、フォアグラウンドにある必要があります)。なお、get-value では引き続き TextPattern を介して読み取れます。
スクロールコンテナー
# Find scrollable containers — look for [scroll:v] (vertical) or [scroll:h] (horizontal)
winapp ui search scroll -a myapp
# Output:
#   pn-scrollview-bfef Pane "scrollView" [scroll:v] (2127,296 1191x965)
#   pn-scrollviewer-bfb1 Pane "scrollViewer" [scroll:h] (2127,296 1191x216)

# Scroll vertically
winapp ui scroll pn-scrollview-bfef --direction down -a myapp

# Scroll to top/bottom
winapp ui scroll pn-scrollview-bfef --to bottom -a myapp

# Scroll and then inspect for newly visible elements
winapp ui scroll pn-scrollview-bfef --direction down -a myapp; winapp ui search TargetItem -a myapp

# Synthesize real mouse-wheel input over the element (1 = one notch up, -1 = down) — tests wheel handlers (zoom, custom scroll)
winapp ui scroll img-map-a1b2 --wheel -1 -a myapp

# Horizontal (tilt) wheel: 1 = one notch right, -1 = left — pans timelines and other horizontal-wheel handlers
winapp ui scroll pn-timeline-c3d4 --wheel-horizontal 3 -a myapp
UI の状態を待つ
winapp ui wait-for btn-submit-a1b2 -a myapp --timeout 5000
winapp ui wait-for itm-status-c3d4 -a myapp --value "Complete" --timeout 5000

ヒント

  • 最初のコマンドとして inspect に --interactive を指定します。操作可能な要素だけが表示されます
  • ; でコマンドを連結し、往復回数を減らします(&& を使わない理由については、下の注記を参照してください)
  • 出力に表示されるスラッグを使って特定の要素を指定します。スラッグはハッシュ検証され、シェルで安全に使用できます
  • プレーンテキスト検索で要素を見つけます:search Minimize、invoke Submit
  • テキストが複数の要素に一致する場合、そのテキストと名前が完全一致する要素だけが優先されます。それでも複数の要素が一致すると、エラーにそれぞれのスラッグが表示されるので、正しいものを選択します
  • invoke の後に get-property --property ToggleState を使って、チェックボックス/トグルの状態を確認します
  • scroll は最も近いスクロール可能な親要素を自動で見つけます
  • 開いているメニュー、フライアウト、ツールチップ、またはティーチングヒント内の項目を 1 つキャプチャするには、そのセレクターを screenshot または record に渡します。ポップアップウィンドウからキャプチャされます
  • ウィンドウ上にポップアップを表示した状態、またはアプリが所有していないオーバーレイをキャプチャする必要がある場合は、スクリーンショットに従って -w <hwnd> --capture-screen でウィンドウを選択します
  • ツールチップやホバーで表示される UI をそのままキャプチャするには、ホバーに従います
  • --focus を使うと、画面 DC キャプチャに切り替えずにキャプチャ前に対象ウィンドウをフォアグラウンドにできます(既定のキャプチャ経路では Windows.Graphics.Capture を使い、ウィンドウがほかのウィンドウに隠れていても動作します)
  • --hide-disabled と --hide-offscreen を使うと、不要な情報を減らせます
&& ではなく ; を使う理由

コマンドを連結するときは、&& ではなく ; を使います。PowerShell の && 演算子は、ネイティブ CLI が stderr に書き込む場合や ANSI エスケープシーケンスを使用する場合にフリーズすることがあり、パイプラインのデッドロックが発生します。; は各コマンドを無条件に実行するため、この問題を回避できます。エージェントのワークフローにも適しています。通常は、invoke がゼロ以外の終了コードを返した場合でも、何が起きたのかを確認するためにスクリーンショットを実行したいからです。

ファイルダイアログの回避策

ファイルを開く/保存するダイアログは、UIA をサポートする標準の Windows ダイアログです。既存のコマンドを使って操作します:

# 1. Trigger the dialog (e.g., click "Open File" button)
winapp ui invoke btn-openfilebtn-a2b3 -a myapp

# 2. Find the dialog window
winapp ui list-windows -a myapp
# → Shows the main window + the dialog HWND
# Note: untitled zero-size windows are hidden by default; use --show-hidden to include them

# 3. Target the dialog, type the file path, and confirm
winapp ui set-value txt-1148-c4d5 "C:\path\to\file.png" -w <dialog-hwnd>
winapp ui invoke btn-open-e6f7 -w <dialog-hwnd>

注:標準のファイルダイアログにあるファイル名入力欄の AutomationId は、通常 1148 です。inspect -w <dialog-hwnd> --interactive を使って、実際のスラッグを確認してください。

JSON 出力エンベロープ

ui inspect、ui get-focused、ui search、ui wait-for の --json エンベロープは、v0.3.1 で再構成されました。DPI コンテキストと型付きの get-property 要素は v0.6.3 以降で利用できます。主な変更点は次のとおりです。

  • ui inspect --json では、要素が windows[].elements[] の下にネストされるようになりました(以前はフラットな elements[] でした)。
  • 検査対象の各ウィンドウと ui status --json のターゲットから、windowDpi、scale、dpiAwareness、coordinateSpace: "physical-screen-pixels" が報告されます。これはターゲットウィンドウの DPI コンテキストです。選択されたターゲットの DPI を読み取れない場合、96 を既定値とせず、処理はただちに失敗します。走査中に消えた副次ウィンドウには dpiError が含まれ、4 つのコンテキストフィールドは省略されます。
  • ui get-focused --json のクエリが成功すると、{ "hasFocus": false } または { "hasFocus": true, "element": {...} } が出力されます(以前は null のみでした)。クエリが失敗した場合は、標準の JSON エラーが stderr に出力され、hasFocus の結果は返さず、ゼロ以外の終了コードで終了します。
  • ui search --json は { "matchCount", "hasMore", "matches" } を返し、ui wait-for --json は { "found", "waitedMs", "element"?, "timedOut" } を返します。
  • ui get-property --json は elementId と文字列値の properties マップを保持し、型付きのサニタイズ済み element を追加します。
  • 型付き要素では controlType ではなく type を使用し、物理画面ピクセル単位の数値 x、y、width、height を使用します。0,0,0,0 は UIA の空または UI が表示されていないことを示す矩形です。isOffscreen はこれとは独立しています。
  • 検索および wait-for の要素には、invokableAncestor フィールド(要素形式)が含まれる場合があります。
  • 要素ごとの id、parentSelector、windowHandle は削除されました。公開ハンドルとして selector を使用してください。

例を含む完全なスキーマについては、references/ui-json-envelope.md を参照してください。

Windows Sandbox での自動化

winapp run . --on sandbox --detach
winapp ui inspect --on sandbox -a MyApp
winapp ui screenshot --on sandbox -a MyApp -o .\result.png

後続の UI コマンドを実行する前に --detach を使用し、ゲストの PID またはウィンドウハンドルとともに --on sandbox を指定したままにしてください。連携するゲスト呼び出しには、同じ WINAPP_UI_WORKFLOW_ID を挿入してください。すべての呼び出しが完了したら、winapp ui yield --on sandbox で終了してください。

セットアップ時の同意、接続クライアントの要件、セットアップや再接続中の一時的なフォーカス変更、キャプチャの復旧については、winapp-sandbox を使用してください。既定のファイル名や --frames ディレクトリを含む、アプリのスクリーンショットと録画はホストに返されます。

関連スキル

  • 分離された Windows Sandbox でアプリを実行および自動化するには winapp-sandbox
  • プロジェクトに Windows SDK を追加するには winapp-setup
  • アプリを MSIX としてパッケージ化するには winapp-package

トラブルシューティング

エラー原因解決策
"No running app found"名前が間違っているか、アプリが実行されていませんプロセス名、ウィンドウタイトル、または PID を試してください
"Multiple windows match"-a に複数のウィンドウが一致しています一覧表示された候補から -w <HWND> を使用してください
"Selector matched N elements"テキストクエリに複数の要素が一致していますエラーに表示された候補、または inspect の出力からスラッグを使用してください
"Element may have changed"スラッグのハッシュが現在の要素と一致しませんinspect を再実行して、新しいスラッグを取得してください
"does not support any invoke pattern"要素を呼び出せませんエラーに呼び出し可能な祖先のスラッグが表示されている場合は、それを使用してください
"No UIA window found"UIA でウィンドウを認識できませんlist-windows で HWND を確認し、その後 -w を使用してください
スクリーンショットにポップアップが表示されないデフォルトのキャプチャ方法では、所有者のないオーバーレイが含まれません開いているメニューまたはフライアウト内の項目を 1 つ取得するには、そのセレクターを渡してください。ポップアップを表示したままにするか、所有者のないオーバーレイをキャプチャするには、スクリーンショットに従って -w <hwnd> --capture-screen でウィンドウを選択してください
--capture-screen で foreground_not_target が発生するWindows がアクティブ化を拒否したため(フォーカスの横取り防止、UAC プロンプト、別のウィンドウによるアクティブ化など)、画面キャプチャで誤ったウィンドウが記録される状態です対象のウィンドウをクリックし、フォーカスを奪ったウィンドウを閉じてから再試行してください。または、--capture-screen を外してウィンドウを直接キャプチャしてください
記録中に element_not_found が発生するセレクターは指定されていますが、要素がツリーにありませんinspect または search を再実行して、新しいセレクターを取得してください
記録中に ambiguous_selector が発生するプレーンテキストのセレクターに複数の要素が一致していますエラーメッセージの候補、または inspect の出力からスラッグを使用してください
記録中に WGC を利用できないWGC キャプチャの初期化に失敗しました。暗黙のフォールバックはありませんGPU/ドライバーを確認してください。画面 DC キャプチャを明示的に要求するには --capture-screen を使用してください

CLI リファレンス

現在のコマンドオプションを確認するには winapp <command> --help を実行してください。完全な機械可読形式のコマンドスキーマを確認するには winapp --cli-schema を実行してください。

コメント