使用者介面自動化

從命令列檢查並互動執行中的 Windows 應用程式。 AI 代理與開發者用於 UI 測試、除錯與自動化。

概觀

winapp ui 提供檢查及與應用程式介面互動的指令Windows 使用Windows 使用者介面自動化(UIA)。 可支援任何 Windows 應用程式——WPF、WinForms、Win32、Electron 和 WinUI 3。 大多數指令是透過 UIA 模式驅動應用程式(沒有輸入注入)。 例外則注入真實輸入:ui click/ui hover/ui drag使用滑鼠模擬、ui touch/ui pen合成觸控與觸控筆輸入,以及ui send-keys合成鍵盤輸入——用於 UIA 模式無法驅動的控制與情境。

Important

互動式桌面需求(輸入動詞)。click、hover、 dragtouchpenscroll --wheel,send-keys --via send-input並合成作業系統層級輸入,因此他們需要一個解鎖且互動式桌面,目標視窗置於前景。 在 鎖定的工作站或安全桌面 (LogonUI/UAC)上,他們無法快速 no_interactive_desktop 注入並失敗(與 elevation 或foreground_not_target case 不同)。 touch / pen當沒有視窗解決no_target時,Repuse 也會拒絕(;目標視窗外的座標為非致命警告(在 下warnings[]有--json條目,或文字模式下的警告行),注入仍會繼續進行——這與滑鼠動詞一致。 其他功能——inspectget-valueinvokewait-forget-propertyset-valuesearch、—— scroll --direction/--to 會驅動應用程式通過 UIA 模式,且適合無頭/鎖定會話。 screenshot 是非注入動詞中的例外:它會進行排他性,且擷取可能需要一個可用的互動式桌面,因為引擎會恢復最小化的目標,並在無法擷取或 --capture-screen 使用時退回前景。 偏好 CI 中 UIA 模式動詞;將注入動詞保留給真正需要真實輸入的情境。 注入前,手勢動詞也會重新 解析目標元素 並拒絕 target_moved ,如果它還在動畫或重新定位,而不是直接將輸入落在空白空間。

快速入門

# 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

在 Windows 沙盒中執行 UI 自動化

為了避免自動化影響桌面,請在執行和 UI 指令中加入 --on sandbox :

winapp run . --on sandbox --detach
winapp ui inspect --on sandbox -a MyApp
winapp ui invoke --on sandbox SubmitButton -a MyApp

--detach 發射後回歸;沒有它,就會 run 等應用程式退出。 保持 --on sandbox 每個訪客指令,包括使用 PID 或視窗 handle 的指令。 請參閱 Windows 沙盒執行,了解客戶端需求、簡短設定/重新連接焦點變更、工作流程協調及主機輸出交付。

有範圍與型別的查詢

winapp ui search "Welcome to MyApp" -a myapp --root MailRow --type Text --class-name TextBlock
winapp ui get-value Subject -w 123456 --root MailRow --type TextBox
winapp ui get-property Subject -a myapp --root MailRow --type Edit --property Value
winapp ui wait-for Subject -a myapp --root MailRow --type Edit --value "Ready" --timeout 10000

search、get-propertyget-valuewait-for接受這些可選的濾波器。 選擇器與所有所附濾波器必須匹配 相同的元素:

  • --root <selector> 搜尋只搜尋唯一匹配根的後代,絕不會搜尋根本身。 使用 AutomationID 或 slug from inspect 來釐清歧義。 一個與多個元素匹配的根節點在 時 ambiguous_selector仍失敗,即使其中一個匹配是可調用的。 缺少根則不產生匹配。 一旦找到根,查詢不會搜尋無關的彈出視窗,即使沒有後代匹配。 查詢不受 的顯示深度限制 inspect。
  • --type <control-type> 與 UIA 控制類型相符,忽略大小寫。 唯一的別名是 TextBox → Edit 和 TextBlock → Text。 未知名稱(包括數字 ID 與萬用字元表達式)與 invalid_arguments失效。
  • --class-name <literal> 與提供者整個 UIA ClassName相符,忽略案件。 它不是子字串、萬用字元或正則表達式。 用 get-property --property ClassName 來發現提供者的值;類別名稱不必等同於 UIA 控制型別。

篩選查詢使用 UIA 的 控制視圖,與 inspect。 僅在 Raw View 中暴露的提供者節點不會回傳;用來 inspect 尋找包含控制項及其選擇器。

所有41種官方類型均支援:Button, , CustomMenuMenuItemMenuBarProgressBarRadioButtonScrollBarSliderSpinnerListTabStatusBarDataGridThumbDataItemGroupTreeItemTreeDocumentToolTipToolBarTextSplitButtonTabItemListItemWindowTableHeaderItemTitleBarHeaderSeparatorSemanticZoomCheckBoxEditAppBarComboBoxHyperlinkImagePaneCalendar

wait-for 每次 輪詢都會重新解析根選擇器,因此根節點可能會在指令開始後出現。 當 --gone時,缺少根表示沒有匹配的後代;歧義根是錯誤,而非成功。 中斷查詢並非消失的證明:若在查找過程中移除或在讀取前 --value 替換元素,下一次輪詢會再次檢查;其他查詢或讀取錯誤則會失敗該指令。 -w <HWND> 限制根發現權限為該視窗的 UIA 樹。 有了 -a,root 發現也能找到應用程式的彈出視窗。 在所有這些視窗中,精確的根 AutomationId 匹配優先於子字串匹配;多個精確匹配仍會失敗。ambiguous_selector

根 slug 即使其他視窗有相同的 AutomationId,也會選擇該元素。 若被替換所選根,舊的根節點不再匹配;當你想讓輪詢跟隨替換時,請使用 AutomationID 或命名根節點。

當有過濾器時,讀取單一元素的指令若剩餘多個元素則失敗 ambiguous_selector ;縮小過濾器範圍或使用唯一單一的 slug。 在篩選範圍內,精確的 AutomationId 匹配會優先於子字串匹配。 省略這三個選項可保留現有的查詢行為。

協調並行 UI 工作流程

Windows 只有一個前景視窗、一個鍵盤焦點、一個游標和一個輸入串流。 當兩個 winapp ui 工作流程同時在同一個登入桌面上運行時,它們可能會搶走彼此的注意力、忽略對方剛開啟的選單,或是將目標從待點擊中移開。

仲裁永遠都在進行中。 每個 winapp ui 觸及實體桌面的指令都會輪流操作,沒有設定也無法關閉,導致兩個代理無法在彼此的視窗中輸入。 唯讀指令會同時執行。

指令間的連續性是選擇加入的。 預設情況下,每個指令都是自成一格的單次冒險:它會等待輪到自己,完成工作,然後立即釋放桌面。 為了讓桌面在多個指令間保持一致,請給它們相同的工作流程 ID:

# Set once per logical UI workflow
$env:WINAPP_UI_WORKFLOW_ID = [guid]::NewGuid().ToString()

您需要知道的事項:

  • 工作流程 id 指的是一個邏輯工作流程 ——不一定是整個代理,也不一定是單一應用程式。 合作指令(錄音加上應捕捉的點擊聲)也用 相同的 值;即使同一位代理同時啟動兩個流程,也要為獨立的工作流程使用 不同的 數值。
  • 沒有ID的話,每個指令都是獨立的一次性冒險。 它仍然會仲裁,但不會有寬容,桌面一結束就立刻交出桌面。 兩個 no-id 指令即使從同一個 shell 啟動,也是不同的工作流程。
  • 新鮮殼與適應性宿主必須注入相同的價值。 如果每個指令都執行在新的 shell 裡——大多數代理工具呼叫就是這樣運作的——唯一能將它們分組的,就是將 WINAPP_UI_WORKFLOW_ID 指令明確傳遞到每個合作呼叫中。
  • 四秒的寬限是保護緊湊的爆發,而不是模型推理。 只要下一個指令在四秒內開始,一個有 id 的工作流程就會輪流。 這涵蓋了連續指令的腳本;它會在模型思考時故意過期。 這是當你無法說自己結束時的備案——當你能說自己結束時,就跑, winapp ui yield 而不是等待。
  • 自適應工作流程必須重新取得、重新驗證並重播。 推理中斷後,可能有其他工作流程使用了桌面,所以請重新開啟選單,重新解析該元素,然後再行動。把已知的端到端序列當作一個緊密的腳本傳送,而不是等著桌面思考。
  • 訂購先是擁有者親和力,然後是FIFO等。 當工作流程處於啟動狀態或在其恩惠範圍內時,即使其他工作流程已經在等待,它仍可能持續發出指令。 一旦執行 winapp ui yield 或寬限期過,等待的工作流程會依嚴格的到達順序服務。 因此,一個工作流程持續進行作業可能會無限期延遲其他工作流程。
  • 沒有硬性上限。 冗長的腳本、無界錄音或失敗迴圈可能會阻擋其他不斷變化的工作流程。
  • 取消或程序終止是 對卡住的即時工作流程的恢復。 等待指令會在一秒後列印狀態,並可用 停止 Ctrl+C,該指令會退出 130。
  • 只有相容的更新版二進位檔才會合作。 舊 winapp 版版本早於此功能,且沒有協調。 直接呼叫 使用者介面自動化 NuGet 套件的程式碼完全不在這項保證範圍內——協調功能存在於 CLI 中,而非套件本身。

哪些指令需要等待回合:

行為 命令
同時進行(永不等待) status、list-windows、inspect、search、get-property、get-value、get-focused、wait-for
等待輪到時,卻從未拿到桌面 set-value, scroll-into-view, , scroll --direction/--torecord
等待輪到時,桌面專屬 invoke、click、drag、hover、scroll --wheel、touch、pen、focus、send-keys、screenshot

中間那排才是值得理解的。 set-value scroll-into-view,並且--toscroll --direction/驅動 UIA 模式而非前景,因此它們對無頭/鎖定會話友善,且不會阻擋任何人使用桌面。 但他們 會 改變應用程式顯示的內容,所以會等到另一個工作流程的輪到,而不是編輯欄位或從別人點擊下滾動清單。

在同一工作流程中,它們與其他 共用 工作重疊——這就是 A record 捕捉 set-value 它正在錄製通話的方式。 它們 不會 忽略自己工作流程的前向障礙:同一工作流程的早期 DesktopExclusive 指令(a click, a screenshot)仍然阻擋它們,就像它阻擋後續指令一樣,因此點擊和隨後的變異會保持你寫的順序。

screenshot 總是排隊等待專屬回合。 並非每次擷取都會干擾桌面——透過 Windows Graphics Capture 擷取的普通可見視窗不會——但引擎會在目標最小化時還原,當無法使用影格擷取或--capture-screen讀取即時畫面時,則會退回前景。 這些任務只在捕獲進行時才會出現,因此指揮部會先行動,而不是猜測。 當它合成多個視窗時,會一次性捕捉所有視窗,因此儲存的影像是一個一致的瞬間,而非前後的混合。 檔案的編碼和寫入是在桌面釋放後進行的。

--capture-screen 只需要一個窗戶。 即時螢幕擷取會記錄實際在前方的畫面,且只能有一個視窗。 明確選擇視窗 -w <hwnd> 會得到一個區域——該視窗範圍內的像素,包括任何顯示在視窗上方的對話框或覆蓋層,這也是閱讀該螢幕的原因。 當 -a 匹配多個頂層或擁有視窗時,沒有這種選擇,因此指令在捕捉任何東西之前會 invalid_arguments 失敗,而不是與前景競爭。 執行 winapp ui list-windows -a <app> 並重試 , -w <hwnd>或直接從 --capture-screen 每個視窗的內容合成。

record 輪流運作,讓相同工作流程的輸入可以與擷取交錯——這就是記錄驅動應用程式工作流程的方式。 有兩個前提:

  • 沒有工作流程 ID 的 A record 是一次性擁有者,因此它會封鎖所有其他工作流程,持續整個過程。 要同時錄製和點擊,請同時給兩個指令。WINAPP_UI_WORKFLOW_ID
  • 在沒有框架擷取支援的主機上,錄影會回流到 PrintWindow,而 PrintWindow 的空白框架恢復可以隨時將視窗預示。 在那裡,桌面會被全程按住,指令也會在輸出中說明;即使是相同的工作流程輸入也會等待。

你可能會看到的錯誤: invalid_ui_workflow_id (變數設定為空或超過 256 字元)、 desktop_coordination_unavailable (協調狀態無法讀取且無法安全重建,或是由較新的 winapp指令寫入)、 queue_capacity_exceeded ( 來自其他 工作流程的 64 個指令已經在等待——限制是存活的外國等待者,而非你已啟動的程序,因此屬於已退出或終止的指令條目不會佔用槽位, 而且你自己的工作流程指令會排在彼此之後,而不是違反這個限制)、 ui_turn_busy (yield 當你自己的工作流程還有執行指令時),以及 cancelled (等待時按 Ctrl+C,退出程式碼 130)。

提前釋放回合: winapp ui yield

四秒寬限是 備用:當你無法確定完成時,桌面會被保留。 能說就說——yield立刻交出桌面,而不是讓其他人等著沒人需要的寬限期。

$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
  • 一次性指令根本不應該設定工作流程 ID。 沒有這個指令,每個指令一結束就會立即釋放桌面,且沒有什麼可讓步的。
  • 多步驟工作流程完成後應該會有成果,尤其當其他工作流程可能還在等待時。 它需要一個快速指令,並消除其他玩家四秒的停滯。
  • 它是 冪位的。 兩次讓步,或在寬限期已過、成功並回報 { "released": false } 後——這是劇本的正常結尾,而非失敗。
  • 它從不釋放其他工作流程的輪值。 如果桌機是別人拿著,或沒有人拿,那就是 no-op。
  • 如果你的工作流程還在執行或排隊指令(例如錄音), 那就失敗 ui_turn_busy 了。 在指令下方放開,桌面會在執行指令中被交出,這樣就不會釋放任何東西,執行指令也不會受影響。 等待或停止,然後再讓步。
  • 它需要 WINAPP_UI_WORKFLOW_ID。 沒有 ,則與 invalid_arguments相符時失敗。
  • 它不使用應用程式或選擇器:會回覆預約,而非視窗,所以應用程式關閉後仍能使用。

等待指令是由釋放桌面的人喚醒,而非輪詢,因此佇列在等待期間幾乎不花什麼成本,交接是即時完成的。 每個服務生也會偶爾自行重新檢查,這也是當程序被終止且從未發佈任何東西時,能恢復桌面的功能:佇列前端的指令每半秒查看一次,而後方的指令——反正也無法在頭執行前執行——每隔幾秒。

目標鎖定應用程式

依程序名稱

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 inspect -a "LICENSE - Notepad"
winapp ui inspect -a "Fix WinApp"     # partial title match

由 PID 撰寫

winapp ui inspect -a 12345

作者:HWND(穩定版 — 分頁/標題變動仍存)

# 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

用於 -a 發現、 -w 穩定鎖定。 當 -a 匹配多個視窗時,指令會列出它們和 HWND 讓你選擇。

選拔委員

目標元素使用檢查/搜尋輸出中 [brackets] 所示的選擇器。 選擇器有三種類型:

Selector 意義 Example
MinimizeButton AutomationId(唯一時顯示 — 穩定且優先) winapp ui invoke MinimizeButton -a myapp
btn-close-d1a0 語意 slug(當沒有唯一 AutomationID 時會顯示) winapp ui invoke btn-close-d1a0 -a myapp
Submit 對 Name/AutomationId(大小寫不區分子串)進行純文字搜尋 winapp ui invoke Submit -a myapp

AutomationId 選擇器 是開發者設定的識別碼(AutomationProperties.AutomationId 在 XAML 中)。 當 AutomationId 在整個 UI 樹 inspect 中是唯一的,並 search 直接顯示為選擇器時,這些 AutomationID 能承受版面變更、本地化和樹狀結構的調整。

當沒有唯一 AutomationID 存在時,會產生 slug selector(例如 btn-close-d1a0)。 格式: prefix-name-hash。 雜湊值會驗證元素身份,但在介面變更後可能會過時。

檢查輸出格式

指令顯示 inspect 元素樹並以顏色輸出(selector 為青色,名稱為綠色,metadata 為灰色):

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

每行 的第一個字 是選擇器——可與其他指令一起使用 ui 。 當元素擁有唯一的 AutomationId,則直接使用(例如, TabView, NewTabButton)。 當沒有唯一的 AutomationId(AutomationId)時,會使用產生的 slug(例如 tab-newtab-5f5b)。

語意字條

Slug 的格式為: prefix-normalizedname-hash 其中:

  • 前綴 — 三字母縮寫(BTN、TXT、CHK、CMB、ITM、TAB、IMG、LBL、PN、WIN、GRP、LNK、MNU 等)
  • normalizedname — 以 AutomationId(偏好)或 Name 為小寫字母數字,最多 15 字元
  • 雜湊 — 元素 RuntimeID 的 4-字十六進位雜湊(驗證元素身份)

slug 是殼層安全的(無特殊字元)、唯一,且可直接用作參數。 沒有查詢過濾器時,雜湊會提供過時偵測——如果元素已被替換,你會得到:「元素可能已變更。 重播檢查。」關於篩選查詢,請參見 「範圍與類型查詢」。

沒有名稱或 AutomationID 的元素僅 pn-c8a3顯示前綴 + 雜湊值(例如 )。

多場比賽的消歧

輸出的 inspect/search 字條是唯一的,但會隨著版面變更而改變——當多個字模匹配時,會用在純字型或文字上。 當選擇器有歧義時,CLI 會用他們的 slug 列印所有匹配,這樣你就可以選對的那個並用那個 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

使用純文字搜尋元素——不需要特殊語法:

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

當文字搜尋匹配多個元素(例如 SettingsExpander 群組、按鈕與文字名稱相同)時,CLI 會自動選擇唯一可調用的元素。 如果多個可調用,則會列出所有帶有字條的匹配。

對於不可調用的搜尋結果(例如按鈕內的 TextBlock ),搜尋會自動顯示最近 可調用的祖 先——你可搭配 invoke使用的父元素。 這適用於所有搜尋選擇器:

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

表面選擇器可直接使用:

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

命令

狀態

連接應用程式並顯示連線資訊。

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

檢查

查看 UI 元素樹。 輸出顯示階層結構的語意字條縮排為2倍空間:

winapp ui inspect -a notepad                    # full window tree, depth 3
winapp ui inspect -a notepad --depth 5          # deeper tree
winapp ui inspect txt-searchbox-e5f6 -a notepad # subtree rooted at element
winapp ui inspect --ancestors btn-close-d1a2 -a notepad  # walk up from element to root
winapp ui inspect -a myapp --interactive        # invokable elements only, auto-depth 8
winapp ui inspect -a myapp --hide-disabled      # hide disabled elements
winapp ui inspect -a myapp --hide-offscreen     # hide offscreen elements

範例輸出(預設):

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)

範例輸出(--interactive — 僅可調用元素,平面列表):

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)

元素可能顯示以下狀態標記:

  • [on] / [off] / [indeterminate] — 切換/勾選框狀態
  • [collapsed] / [expanded] — 樹狀結構、組合框、選單項目的展開/收摺狀態
  • [scroll:v] / [scroll:h] / [scroll:vh] — 可捲動容器(垂直、水平或兩者皆有)
  • [offscreen] — 元素在螢幕上不可見
  • [disabled] — 元素未啟用
  • value="..." — 可用於可編輯元素的當前文字內容(若與名稱不同)

尋找與選擇器相符的元素。 輸出顯示語意條狀:

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

輸出範例:

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

輸出中顯示的 slug(例如 btn-minimize-d1a0)可直接搭配其他指令使用:

winapp ui invoke btn-minimize-d1a0 -a notepad

取得性質

從元素讀取屬性值。 包含特定模式的狀態(ToggleState、Value、IsSelected 等)。

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

物業名稱是區分大小寫的。 未知名稱在以下--json不invalid_arguments符;省--property略以下所有六個文字格式屬性的屬性。 wait-for --property 使用相同的大小寫區分名稱,並在輪詢前拒絕未知名稱。

整文件文字格式化

格式化會跨越元素的整個 TextPattern 文件,而非當前選取或插入點。 閱讀不會改變焦點或選擇。

房產 均勻值(以字串形式回傳)
FontWeight 數值權重,例如 "400" (法線)或 "700" (粗體)
FontName 字型家族名稱,例如 "Courier New"
FontSize 點的大小,例如 "15.5"
ForegroundColor 十進位 Windows COLORREF (0x00BBGGRR),例如 "3678732" RGB(12, 34, 56)
IsItalic "True" 或 "False"
StrikethroughStyle 數值 UIA 文字裝飾風格,例如 "0" (none) 或 "1" (single)

數字使用不變格式(小數點,無論你身處何地)。 每個屬性都可以回傳:

價值 意義與下一步
"Mixed" 文件中的格式會有所不同。 不要把它當作均勻的數值;此指令不會查詢個別文字範圍。
"NotSupported" 文件的 TextPattern 提供者不會回報此屬性。 請查看應用程式的無障礙支援。
"Unavailable" 該元素沒有 TextPattern。 使用 inspect 或 search 尋找其文字/文件元素。

在列出所有屬性時,若無法解析任何活元素,且格式錯誤的值會省略且未丟棄其他屬性,則快取的基本屬性仍可使用。 這些遺漏會被記錄為警告。 請求特定的格式屬性,這樣可以判錯而不是遺漏。

提供者失效仍屬錯誤,而非 "Unavailable"。 對於 stale_element,請再次檢查應用程式,並用目前的選擇器重新嘗試。

JSON 信封包含 elementId、 element以及字properties串值 。 現有的資產,包括 BoundingRectangle,則保留其格式。 例如,格式 properties 化部分為:

{
  "FontWeight": "700"
}

螢幕擷取畫面

擷取視窗或元素為 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)

沒有元素選擇器時,預設擷取會將多個視窗合併成 一個標示並排的複合 PNG 檔案,而非獨立檔案。 -a 程序名稱或 PID 包含應用程式的視窗及其自有視窗。 標題為基礎 -a 的匹配選擇一個匹配的視窗及其擁有的視窗; -w 明確選擇一個視窗加上其擁有的視窗,而非過程中的每個視窗。 因此,擁有的對話框或提示即使你明確選擇主 HWND,仍可能以獨立面板的形式出現。 元素選擇器會裁切到該元素,而不是組合視窗。

--quiet 抑制單視窗及複合擷取的資訊輸出,包括儲存的路徑。 警告與捕捉失敗診斷依然可見。 需要檔案路徑和尺寸作為結構化輸出時,就改用 --json 它。

其中 --on sandbox, --output 為主機目的地。 影像傳送後,成功輸出純路徑並 --json 回報該主機路徑。

預設的擷取路徑是使用 Windows。Graphics.Capture (WGC),讀取實際的 DWM 合成表面——保留圓角、透明度,且即使視窗被其他 windows 遮擋也能正常運作。 如果 WGC 不可用(舊版 Windows 版本),CLI 會退回到 PrintWindow。

當你需要在螢幕上出現可見的彈出視窗或提示時,使用 --capture-screen -w <hwnd> 它們,包括不屬於目標視窗的覆蓋層。 它讀取該視窗的螢幕區域,而不是組合標示面板,並將視窗先移到前景。 當 ,-a需要恰好一個匹配的視窗;若多個頂層或擁有的視窗匹配,則使用winapp ui list-windows -a <app>並重新嘗試 。-w <hwnd> 如果你只想讓視窗前景而不切換擷取模式(例如,確保截圖與使用者目前看到的相符)時,可以使用 --focus 。

因為螢幕 DC 會捕捉到實際在前方的目標, --capture-screen確認目標在捕捉前立即到達前景 ,若未成功則失敗 foreground_not_target (如防搶焦點、無人機提示或另一個視窗自動啟動)。 這種情況下不會寫入圖片——之前指令退出 0,並回傳錯誤視窗的圖片。 ui record --capture-screen 在第一幀前也套用相同的檢定。

資料列

將視窗或元素區域錄製到 H.264 MP4。 對於無人看管的劇本,我會選擇正面 --duration-sec 評價。 若無時長,錄音會持續到按 Ctrl+C 或對於重定向 stdin 時,使用換行或 EOF。 npm uiRecord 和 targetRecord 輔助器需要從 1 到 86400 的整數 durationSec ;他們的中止訊號會強制取消,而非優雅地完成錄音。

# 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

選項:

  • --duration-sec N — 記錄N秒。 預設為 0 紀錄,直到被停止。
  • --fps N — 目標幀數每秒(預設15幀)。
  • --max-edge N — 縮放,使最長邊最多為 N 個像素(0 = 無降縮)。
  • --capture-screen — 從螢幕擷取 DC(包含疊加/彈出視窗;視窗前景)。
  • --output <path> — 輸出MP4路徑。 預設為 recording-<timestamp>-<guid>.mp4。
  • --overwrite — 新錄音結束後更換現有錄音輸出。 沒有它,現有的輸出就會被拒絕。
  • --frames — 將時間戳記的 JPEG 證據寫入 <output-name>.frames。 支援 1-30 fps 和 --max-edge 64-4096(預設 1280)。 幀資料上限為 1 GiB;如果達到上限,MP4 繼續播放。

代理可讀的框架工件:

evidence.mp4
evidence.frames/
  manifest.json
  frames.ndjson
  frames/
    frame-000000-t000000000012.jpg

frames.ndjson每個樣本有一條線,單sampleIndex調、 elapsedMsMP4 相對mediaTimeMs、imageIndex、 、 filechanged。 連續像素相同的取樣會重複使用前一個品質的 85 JPEG。

manifest.json 記錄請求、時間、MP4狀態、影像尺寸及狀態(complete、 partial,或 truncated)。 截斷時序涵蓋保留的前綴,而 video 描述完整的 MP4。

除非你打算用 --overwrite替換錄音,否則請選擇新的輸出路徑。 沒有它,無論是現有影片還是其配對 .frames 目錄都會阻擋錄影,即使你省略 --frames了。 如果新捕獲失敗,之前的MP4會保持完整。 成功替換後,即使新錄製遺--frames漏 ,前一個影格目錄仍會保留為 <output-name>.frames.previous-<id>。 保留部分證據,並依照報告 recoveryHint 再重審。 若 MP4 最終化失敗,保留的影格可以 發佈。<output-name>.frames.partial-* 影格雜訊包含未加密的螢幕內容;像截圖或影片一樣處理。

當 --on sandbox時,MP4 和影格目錄都會送達主機,包括省略時 --output 的預設輸出。 關於中斷錄音與整桌面擷取,請參見 沙盒擷取 。

擷取模式 (於 JSON mode 欄位報告):

  • wgc— Windows 圖形擷取(預設;視窗被遮擋時可使用)。
  • printwindow — GDI PrintWindow(當 WGC 無法在此系統/工作階段使用時,會用 Switch(重跑 --capture-screen 以改用 screen DC)。
  • screen — 螢幕 DC via --capture-screen (包含覆蓋/彈出視窗;將視窗移至前景)

JSON 輸出(--json):

  • STDOUT: 最終錄音結果,包括節奏、停車理由、可選 frameArtifacts性及警告。
  • Stderr: 每行一個 JSON 物件:第一幀後發生 recording-started 事件,若後續錄製失敗則會出錯。 只有當幀輸出處於啟用狀態時,幀路徑才會被納入。

錯誤代碼:

  • element_not_found — 選拔委員未匹配。
  • ambiguous_selector — 選擇器能匹配多個元素;使用建議的彈頭。
  • invalid_arguments — 選擇權值無效。
  • output_exists — 已存在錄製輸出,且無法依請求選項替換。
  • frame_output_failed — 兩個產物在幀輸出失敗後無法保存。
  • partial_output — 僅完成一件文物; partialOutput 檢查 和 recoveryHint。

已知限制: 在視窗彈出視窗中錄製元素可能會捕捉底層視窗。 錄製整個視窗,或依照 截圖疊加的靜 態影像工作流程。 參見 #646。

叫用

winapp ui invoke SettingsCategory -a myapp --action select
winapp ui invoke AgreeCheckbox -a myapp --action toggle-on --json
winapp ui invoke SizeComboBox -a myapp --action expand
winapp ui invoke SubmitButton -a myapp

當測試必須對所選元素執行特定操作時,會使用 --action 。 即使請求的動作失敗,它也不會嘗試其他模式或可調用的祖先。 同時支持調用與選擇的控制項將被選擇,而非調用,且 。--action select 當 時--action,一個 slug 只針對一個元素;若純文字或 AutomationId 選擇器匹配多個元素,則會因非零退出碼而關閉,而非對第一個匹配反應,因此當名稱不明確時,會傳遞 slug/inspectsearch。

動作 Operation
invoke InvokePattern.Invoke
select 選擇項目模式。選擇
toggle TogglePattern.Toggle,恰好一次
toggle-on / toggle-off 請閱讀 ToggleState;成功時不改變已正確狀態,否則切換並驗證
expand / collapse 展開摺疊模式。展開 / 摺疊

對於 toggle-on 和 toggle-off,起始 Indeterminate 狀態最多允許兩次轉移,每次轉換後檢查狀態。 其他起始狀態允許一個過渡。 若未達到請求狀態,指令會失敗,而非繼續切換。 驗證失敗可能導致控制權變更;先閱讀 ToggleState 再決定下一步該怎麼做。

沒有 --action,現有的自動行為不變:嘗試 InvokePattern、TogglePattern、SelectionItemPattern,然後 ExpandCollapsePattern(展開),必要時再嘗試 invokable-ancestor。

不支援的動作若有非零的退出碼,且 --json則在 stderr 上會產生結構化錯誤。 檢查所選控制項並選擇它支援的動作,或明確鎖定預期的父控制項。 成功 JSON 包含 requestedAction 和 performedAction;請參見 JSON 參考文獻。

click

利用滑鼠模擬點擊元素的螢幕座標。 用這個來處理不支援 InvokePattern 的控制項(例如欄位標題、清單項目)。

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

和其他輸入動詞一樣,會 click 把目標帶到前景,但很快就 會失敗 (no_interactive_desktop 在鎖定/安全的桌面上, foreground_not_target 如果無法轉移焦點),而不是點擊錯誤的視窗。 它也會 重新解析按鈕按下前的元素:游標定位後會做最後一次位置檢查,因此持續移動或動畫中的目標失敗 target_moved ,而非點擊落在空格後回報成功——成功表示按鈕按下時目標仍在原地。

拖曳

在某一點按下滑鼠按鈕,移動到另一個點,然後放開,每個drag <from> <to>端點要麼是元素選擇器(從元素中心拖曳),要麼是x,y完全符合報告winapp ui inspect的螢幕座標。 自由混搭(selector→selector、selector→coords、coords→coords)。

使用 SendInput 中間移動,讓應用程式能看到真實的訊息流 WM_MOUSEMOVE 。 用它來調整握把、滑桿、畫布繪圖和拖放功能。

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

選項:

  • --right — 用滑鼠右鍵拖曳,而非左鍵。
  • --hold-ms <ms> — 在移動前按住起點按鈕(預設:0)。 在(無移動)時 <from> == <to> ,會執行 按住/長按 手勢。
  • --dwell-ms <ms> — 移動後停留於目的地,然後放手(預設:0)。 讓放置 目標/合併疊加 層,讓手臂在持續懸停時(而不是游標一到那一刻)就卡住,然後才扣鈕扣。

同一空間x,ywinapp ui inspect/報告中僅search顯示螢幕座標,選擇器會解析到元素中心——先檢查以選擇點。

像是 send-keys --via send-input, drag 在將目標移到前景後,會在整個螢幕座標注入作業系統範圍。 如果無法將焦點導向目標(例如背景程序防止焦點竊取),指令 會失敗(foreground_not_target), 而不是拖錯視窗——先聚焦或點擊視窗。 在鎖定或安全的桌面上,則會失敗。no_interactive_desktop 每個元素端點在 阻力發生前立即重新解析;如果還在移動或調整大小(動畫中的目標),指令會 target_moved 失敗,而不是拖到過時點。 (裸 x,y 端點無法重新驗證,因此會被 as-is。)

觸控

使用 Windows 指標注入 API 注入合成觸控手勢。 接觸錨點可以是元素選擇器(使用元素中心)或透過x,y(相同空間報告)的明確winapp ui inspect。 用它來做滑鼠模擬無法表達的點擊/按鍵互動和多重觸控手勢。

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)

選項:

  • --gesture <g> — tap (預設), double-tap, long-press, , swipe, pinch, stretch, .
  • --at <x,y> — 明確的起始點(螢幕座標)。 預設是選擇器的元素中心。
  • --to-point <x,y> — 終點為 swipe。 優先權高於 --direction。
  • --direction <right|left|up|down> — 滑動方向(預設: right)。 結合 --distance 計算未給出的 --to-point 終點。
  • --distance <px> — 手指展開,或 pinch/stretch以像素為單位的滑動距離。
  • --hold-ms <ms> — 在抬起前保持觸點向下(長按時間;未設定時預設為500毫秒 long-press )。
  • --duration-ms <ms> — 移動手勢滑動時間(滑動/捏合/伸展;預設300秒)。
  • --fingers <n> — 聯絡次數(1–10;預設1)。 pinch / stretch 一定要用兩個。

注射安全。 touch除非有非零目標視窗的 handle 解決且該視窗佔據前景,否則拒絕注入——當無法解析視窗、no_target無法轉移焦點,或foreground_not_target在鎖定/安全的桌面上時,注入會no_interactive_desktop失敗。 每個座標(元素中心、明確--at/--to-point的 、產生的路徑點)都會與目標視窗矩形進行檢查;視窗外的點會以非致命警告的形式呈現(warnings[]在 --json、 或文字模式下為警告線),注入仍會繼續進行——與滑鼠動詞( )click/drag/hover/scroll匹配,這些動詞同樣會在視窗外的座標注入。 --fingers 超過10分的學生一開始就被拒絕。

硬體說明。 Touch 偏好現代合成指標裝置(CreateSyntheticPointerDevice(PT_TOUCH)),並回退到舊有 InitializeTouchInjection/InjectTouchInput API。 如果目前裝置/會話不支援注入,指令會顯示 實際的 Win32 錯誤代碼 (例如「未支援」),而非回報錯誤成功——將非零的退出視為「未送達觸控」。

遠端桌面 / VM 會話。 在遠端桌面(RDP)或某些虛擬機會話中,作業系統可能會接受合成觸控(出口 0),但實際上不會直接到達目標應用程式。 當偵測到遠端會話時, touch 會附加一個 傳遞不確定性警告 ——在文字模式下的 warnings[] 條目 --json或警告行。 ✅/exit 0 表示注入呼叫成功,而非應用程式是否接收到輸入;在關鍵時刻確認效果ui screenshot/ui inspect。

筆

使用 Windows 合成指標 APICreateSyntheticPointerDevice(PT_PEN)(;Windows 10 1809+)。 目標鎖定元素中心、明確 --at 點或整 --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

選項:

  • --at <x,y> — 筆觸點(螢幕座標)。 預設是選擇器的元素中心。 給了他卻被 --path 忽略。
  • --path "<x,y x,y …>" — 以空白分隔 x,y 的筆劃路徑表示(一點路徑為點綴)。
  • --pressure <0.0–1.0> — 筆壓(預設0.5)。
  • --tilt-x <deg> / --tilt-y <deg> — 筆傾斜角度,−90 至 90(預設 0)。
  • --eraser — 用橡皮擦的筆頭代替筆尖。
  • --duration-ms <ms> — 總行程行程時間(以毫秒計,以插值UPDATE幀分布於路徑上)(預設:每個航點約10毫秒)。 用這個來控制筆從開始到結束的視覺移動速度。

注射安全。 例如touch,pen拒絕在沒有非零且前景的目標視窗no_target / foreground_not_target / no_interactive_desktop()的情況下注入,並且會將每個墨水點與目標視窗矩形進行檢查,將任何視窗外座標顯示為非致命警告(warnings[]在 ,--json或文字模式下的警告行),同時仍持續注入——這與滑鼠動詞一致。 無效 --pressure (0.0–1.0 外)或傾斜(外側±90°)會在前方被拒絕。

遠端桌面 / VM 會話。 筆路由在 遠端桌面 上尤其不可靠:注入呼叫可以回報成功(出口 0),但沒有任何筆輸入進入應用程式。 當偵測到遠端會話時, pen 會附加一個 交付不確定性警告 (warnings[] 在 , --json或文字模式下的警告行),以避免 a ✅ 被誤認為已確認的送達。 在 本地互動桌面上驗證依賴筆的流程。

懸停

將滑鼠移到元素中心即可觸發懸停效果(提示、飛出、視覺狀態)。 用 SendInput 來做真實滑鼠移動,稍微晃動一下,然後等待可設定的停留時間。

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

選項:

  • --dwell-time <ms> — 懸停後等待效果出現的時間(默示:800,範圍:0–10000)

發送金鑰

傳送合成鍵盤輸入——即鍵盤 click上的對應輸入。 UIA 沒有鍵盤注入模式,因此這會降落到 Win32 層。 用它來操作鍵盤(方向鍵、Tab、Enter、Esc)、快捷鍵(ctrl+c、 alt+f4),以及輸入需要每次按鍵事件而非 set-value原子寫入的控制項。

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

金鑰文法 (空白分隔詞符,引用多詞符字串):

  • 命名鍵 — enter/return, tab, esc/escapespace, backspace,delete/del , insert, homeendpageup/pguppagedown/pgdnup/down/left/rightf1f16–, apps, printscreen, 。 capslock
  • 序列 — 按多個標記依序按下: down down enter。
  • 修飾組合 — ctrl, shift, alt, 與 win : +ctrl+shift+talt+f4, 。
  • 字面文字 ——任何非已知鍵的標記都會逐字元輸入: hello。 相鄰的字面詞會保持它們之間的空格,例如引用的片語 "Hello world" 如是逐字打字(空間被保留);僅包含 + such as C++ 或 a+b 的字面文字則以文字形式打字,而非組合解析。
  • 明確的字面轉義 — 在標記前加上 text= 前綴,即使與鍵或修飾鍵名稱碰撞,仍能逐字輸入: text=enter 輸入「enter」而非按 Enter,並 text=ctrl+a 輸入字面字串。 這與逃脫的情形相呼 vk= 應;逃脫的價值仍會與相鄰的字面詞text=down low 彙(→「低沉」)結合。 由於標記是空白分割(相鄰的文字會用一個空格重新連接),所以在 值內 text= 使用反斜線跳槽 來輸入原本無法保留的空白:→ \s 空格、 \t → tab、 \n → 換行、 \r → 換行, \\ →字面反斜線。 \n、、\r\r\n且各自插入一個換行符(Enter / VK_RETURN),因此text=line1\nline2與text=line1\r\nline2兩者皆輸入一個換行。 所以 text=a\s\sb 輸入「a b」(雙行距),並 text=\shi 保留前置空格。 未被識別的逃逸(例如 \x)則會逐字保留。
  • 整參數文字(--verbatim)— 當整個有效載荷為文字文字時,--verbatim通過而非每個符號都跳脫。text= 它會完全按照給定的方式輸入整個金鑰參數——沒有命名金鑰/組合/vk=/text=詮釋——而且與一般路徑不同,它保留了精確的內部空白空間(不會崩潰),不需要 。\s 所以 send-keys "down down enter" --verbatim 輸入文字,並 send-keys "a b" --verbatim 保留雙倍行距。 反斜線逃脫 在模式下不會 解 --verbatim 碼(a \s 是反斜線和「s」型);需要逃脫控制字元時使用 text= 標記。
  • 原始虛擬金鑰 — vk=0xNN (十六進位)或 vk=NN (十進位)用於沒有友善名稱的金鑰。

選項:

  • --target <selector> — 在發送金鑰前,先聚焦此元素(透過 UIA)。 沒有這個鍵,鍵就會回到應用程式目前聚焦的元素。
  • --verbatim — 將整個鍵參數輸入為文字(無鍵/組合/vk=/text= 解析),並保留精確的空白。 每個標記 text= 跳脫的全參數形式。
  • --via <transport>— post-message (預設)發WM_KEYDOWN/WM_KEYUP/WM_CHAR文至目標視窗的佇列。 它以 HWND 為目標,繞過 UIPI(跨完整性層級運作)。 send-input 透過整個作業系統 SendInput 注入,並進入前景視窗。

選擇交通工具/已知限制:

  • post-message 是預設,因為它繞過 UIPI,且不依賴視窗是否為前景。 限制:它無法觸發透過 WH_KEYBOARD_LL 低階掛鉤(即在任何視窗佇列上游的輸入)註冊的全域熱鍵,且讀取原始鍵狀態的 GetAsyncKeyState 應用程式可能無法觀察到被保留的修飾符。 它會在前景化後自動解析並發佈到目標執行緒 的聚焦子視窗 (透過 GetGUIThreadInfo),因此經典的 Win32/WinForms 應用程式如果控制是獨立子視窗,則能在不手動鎖定控制項的情況下接收鍵。 WinUI 3 / UWP 應用程式有無視窗的 XAML 控制項,沒有子 HWND,因此 post WM_CHAR/WM_KEYDOWN 沒有可落點,會被丟棄——post-message 無法驅動(指令 ward 並退出 0);使用 。--via send-input (WPF 視窗是單一 HWND,並將鍵路由到內部聚焦的元素,因此後置訊息功能在此可行。)
  • send-input 產生完全真實的輸入(修正符可見於 GetAsyncKeyState,並發射低階掛鉤),但會進入前景視窗, 當從高階程序注入較低完整性的目標(AppContainer/AppX)時,UIPI 會阻擋。 如果 send-input 報告失敗,目標很可能是升格或是 AppX 應用程式——使用 post-message,或以相符完整性層級執行 CLI。 作為安全防護者, send-input 會在注入前立即驗證目標視窗是否在前景,並 失敗foreground_not_target(),而非 在無法聚焦時輸入錯誤視窗——先對焦或點擊視窗。 在 鎖定或安全桌面 上,則會 no_interactive_desktop 以(沒有前景視窗可注入)失敗——解鎖會話,或使用 UIA 模式動詞 (set-value, invoke)。
  • 系統保留連擊(win+l, win+r, ctrl+shift+escctrl+alt+delalt+tabalt+f4ctrl+esc, lone win/printscreen、...)在整個作業系統傳送時,作用於作業系統/殼層,而不僅僅是目標。 send-input 預設會拒絕它們 ( invalid_arguments 錯誤且不傳送任何訊息),因為在作業系統層級注入會產生遠超過目標視窗的影響(例如 win+l 會鎖定會話)。 Pass --allow-system-keys to opt in——這讓你能驅動像 PowerToys win+shift+v 的全域快捷鍵,或 win+r (全域低階鉤子會監控整個作業系統的輸入串流,所以注入的組合會觸發它)。 即使有 --allow-system-keys:win+l 仍被阻擋的例外會鎖定工作站LockWorkStation(),無法從自動化中恢復(破壞 CI 與遠端桌面會話),且ctrl+alt+del是安全注意力序列(SAS),Windows 會從注入輸入中移除,無論旗標為何——該序列永遠無法生效,因此會出錯(invalid_arguments退出 1),而非報告誤導性的成功。 其他組合(、alt+f4ctrl+shift+escwin+r...)則可搭配旗幟使用——請注意呼叫者。 或者,將系統組合傳送到特定視窗,使用 --via post-message視窗範圍且不受影響的視窗(post win+l 無害,但 post alt+f4 仍會關閉目標視窗)。

按鍵事件(按鍵/TextChanged):

  • 命名的鑰匙和修飾組合(,downenter , ctrl+shift+t, vk=0xNN) 會在KeyDown運輸車上發射真實KeyUp的(和)——它們以離散WM_KEYDOWN/WM_KEYUP(或SendInput虛擬鑰匙事件)形式呈現。
  • 字面打字文字 (hello)因傳輸方式而異:
    • --via send-input將每個字元映射到其虛擬鍵(加上 Shift)在主動鍵盤配置上,使目標看到一個擁有正確虛擬鍵的真實字元,KeyDown接著是作業系統合成WM_CHAR的(升高TextChanged)——即每個字元只需一次完整按鍵。 目前配置無法存取的字元(或需要 Ctrl/AltGr)會退回到 Unicode 封包,因此仍會顯示相同的字元。 當你需要每個按send-input鍵的精確度時才用KeyDown(例如驅動 WinUI 3 / WPF TextBox 的處理器鍵離)。KeyDown 對於一般(非升高)WinUI 3 測試主機,先把視窗帶到前景(winapp ui focus /點擊它),因為 send-input 它會鎖定前景視窗。
    • --via post-message每個字元會發布一個WM_CHAR(不WM_KEYDOWN/WM_KEYUP針對打字文字發布——這些文字保留給命名鍵/組合鍵),不會為每個字KeyDown元產生一個字元。 它會自動重新定位到視窗 的聚焦子控制項,因此經典的 Win32/WinForms WM_CHAR驅動編輯控制會落在文字(提升 TextChanged)。 注意事項:WinUI 3 / UWP / XAML 應用程式(Winapp 的主要目標)有無視窗控制項,會忽略已發佈WM_CHAR/WM_KEYDOWN的設定——所以無論是文字還是命名按鍵(Enter、數字等)都無法到達它們,儘管指令會回報成功。 當目標看起來像 XAML 但仍然退出 0(PostMessage 是發射後忘記,無法確認投遞)時,它會發出警告。 用--via send-input來驅動 WinUI 3 / UWP / WPF 應用程式;post-message保留給經典的 Win32 控制項,或只有在不同完整性層級需要視窗範圍時使用。

JSON 輸出 (--json): 的結果hwnd是金鑰實際交付的視窗——因為--via post-message這是指令重新定位到該視窗(不一定是頂層-w/-a/視窗)時的解析聚焦子-e,因此自動化能精確確認輸入落點。 當該有效目標看起來像是無視窗的 XAML 主機時,上述交付警告也會以條目形式顯示 warnings[] (與主控台上顯示的警示相同),因此 ✅ 出口 0 不會被誤認為已確認交付。

集合值

用 程式設定 可編輯元素的值(不使用按鍵,也不使用應用程式前景)。 使用備用鏈條:

  1. ValuePattern — 包含 TextBox、ComboBox、PasswordBox 及大部分可編輯的控制項。
  2. RangeValuePattern — 當數值解析為數字時,用於數值控制(滑桿、進度條)。
  3. LegacyIAccessible (IAccessible::put_accValue) — 僅 TextPattern 編輯控制項的備用,且不暴露 ValuePattern(例如 rich-edit / Document compose box)。 這會彌補讀寫之間的差距,因為 get-value 可以讀取這樣的控制項卻 set-value 無法讀取。
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

若三種模式皆無法設定該值,set-value則會失敗,且最後只能以明顯錯誤指向 。send-keys

並非每個富編輯器都支援程式化集。 LegacyIAccessible 的備用機制只適用於可 IAccessible::put_accValue 及性實作的控制項——原生 Win32 的豐富編輯控制項和 Chromium/Electron/WebView2 的合成表面通常會執行。 WinUI 3 RichEditBox 和 WPF RichTextBox 不支援程式化值設定——設計上它們會將內容暴露給 使用者介面自動化 只讀(文字模式,無法設定值模式),因此set-value無法寫入。 使用 send-keys (需要解鎖且前景的桌面)來處理這些。

取得值

讀取元素的當前值。 使用智慧備援鏈:TextPattern(RichEditBox、文件)→ ValuePattern(TextBox、滑桿)→ SelectionPattern(ComboBox、RadioButton、TabView)→名稱(標籤)。

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

成功讀取的空文字欄位會回傳 "text": "",而非其可及性標籤。 僅留白的內容也會保留在 JSON 中。 wait-for --value "" 匹配一個空欄位,不論是新鮮的還是經過編輯後清理過的欄位。 若要閱讀無障礙標籤,請使用 get-property --property Name。

focus

winapp ui focus txt-textbox-a4b1 -a notepad

需要時啟動所選控制視窗,然後聚焦控制。 必須有選擇器;使用 -a <app> 或 -w <HWND> 選擇目標。 成功表示該視窗位於前景,且已確認所選控制 HasKeyboardFocus 點後指令返回。 該指令允許控制裝置最多有 500 毫秒的時間來回報焦點;當目標消失或失去前景時,遊戲會停止,而不是試圖奪回焦點。 主視窗前有一個擁有的對話框是不夠的:如果你的目標是對話框中的控制項,請選擇那個控制項。

此指令需要解鎖且互動式的桌面,且無法繞過 Windows 啟用限制。 如果失敗, foreground_not_target手動啟動預定視窗並檢查是否有阻擋對話框再重試。 對於 focus_not_acquired,檢查目前的使用者介面並選擇一個可聚焦的控制項。 對於 stale_element,重新發現目標,且 或 inspectsearch。 在發現和重試指令時保持同一 --on 目標。

捲入檢視

將元素捲入可見區域。

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

等著

等待元素出現、消失或某個數值達到目標。

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

捲軸

捲動一個容器元素。 尋找可捲動的容器——尋找search scroll([scroll:v]垂直)或[scroll:h](水平)標記。

# 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

選項:

  • --direction <up|down|left|right> — 透過 逐步捲動 ScrollPattern。
  • --to <top|bottom> — 透過 跳轉至起始/結束 ScrollPattern。
  • --wheel <notches> — 透過 ,在元素中心 SendInput合成滑鼠滾輪輸入,以輪盤凹槽(卡位): 1 = 向上/前進一個凹位, -1 = 向下/向前一個凹槽, 3 = 向上三個凹槽。 (每個凹槽是 120 個 WHEEL_DELTA Windows SendInput 的消耗;CLI 會幫你按 120 個凹槽來調整。)繞道手術ScrollPattern。

--direction、、 --to--wheel 和 互斥——僅通過一個。 因為 --wheel 在螢幕座標注入作業系統全域輸入,它會先將目標帶到前景,如果無法轉移焦點就會 失敗(foreground_not_target), 而不是捲錯視窗。

專注

winapp ui get-focused -a myapp
winapp ui get-focused -w <HWND> --json

顯示目前在所選應用程式中具有鍵盤焦點的元素,包括那些只能透過父視窗擁有的控制項。 當 , -w焦點必須屬於該視窗,而非同一流程中另一個視窗或擁有的彈出視窗。 在 -a中,選取的程序中包含其他視窗。 當無法驗證任何焦點元素屬於目標時,JSON 輸出就有 hasFocus:false 。 若焦點或視窗所有權查詢失敗,指令會以非零方式退出;重試 get-focused,並重新發現 list-windows 視窗是否關閉。

列表視窗

列出應用程式中所有可見的視窗,包括彈出視窗和對話框。 預設情況下,無標題且大小為零的視窗(系統視窗隱形)會被排除在外。

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

暫止

提早釋放這個工作流程的 UI 輪值,而不是等待四秒的閒置時間。 需要 WINAPP_UI_WORKFLOW_ID;不需要應用程式或選擇器。 詳見 「提前釋放回合」。

winapp ui yield
winapp ui yield --json          # {"released": true} — or false when nothing was held

框架支援

Framework 檢查 搜尋 叫用 集合值 螢幕擷取畫面
WPF ✅ 完整樹 ✅ 所有性質 ✅ 所有模式 ✅ ¹ ✅
WinForms ✅ ✅ ✅ ✅ ✅
Win32 ✅ ✅ ✅ ✅ ✅
WinUI 3 ✅ ✅ ✅ ✅ ¹ ✅
電子 ⚠️ Chromium 樹 ⚠️ 限量 ⚠️ 情況各異 ⚠️ 情況各異 ✅
Flutter ⚠️ 基本 ⚠️ 基本 ❌ 極簡 ❌ ✅

¹ set-value 可對任何暴露 ValuePattern/RangeValuePattern 的控制項,以及僅 TextPattern 且其可及性實作 IAccessible::put_accValue 的編輯控制項(LegacyIAccessible 備援)皆可使用。 WinUI 3 RichEditBox 和 WPF RichTextBox 是例外——它們只暴露唯讀文字模式(無可設定值模式),因此設計上無法程式化設定;send-keys使用(需互動式桌面)輸入。

使用你自己程式碼的引擎

Everything winapp ui Does 都以函式庫形式提供,因此你可以從測試或工具中驅動相同的自動化,而不必花錢去使用 CLI:

包裝 它增加了什麼
Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation 檢查、選擇器、UIA 模式互動、輸入注入、截圖
Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation.Recording 錄影至MP4,加上幀包
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);

對於確定性動作,請使用過載 :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 拒絕歧義文字,而非選擇可調用的匹配。 精確的 AutomationId 匹配優先於名稱或 AutomationId 子字串;唯一名稱仍可選擇共享 AutomationID 的控制項。 對於應用程式範圍目標,該檢查涵蓋了所有應用程式或擁有的視窗。 使用 -w <HWND> (或明確視窗函式庫目標)來限制選擇範圍。

它回傳PatternPerformedAction的意義與 CLI 動作的結果相同。 通過檢查或選擇回傳的元素,且其執行時 slug 或唯一 AutomationID 保持完整。 明確的動作會拒絕遺失或模糊的身份,而不是依名稱和控制類型重新綁定。

對於有作用波的讀取,將 設為另一個 UiSelector,ControlType為型別名稱,並ClassName設定UiSelector.Root為 literal 提供者類別。 這些條件使用與 CLI 相同的 查詢謂詞 。 只支援一個根層: selector.Root.Root 必須是 null。 巢狀根投 ArgumentException 擲,然後抬頭望向目標視窗。 使用獨特的根 AutomationID 或 slug,而不是巢狀根選擇器。 UiControlTypes.GetId(name) 解析官方類型名稱及兩個已記錄的別名,並回傳 0 無效名稱。 UiControlTypes.GetName(id) 回傳典範名稱,或 Unknown(id) 對未識別的 ID 進行回傳。

當從 JSON 傳還原到 UiElement 或 GetPropertiesAsync時,保持其 Selector 和 WindowHandle。GetTextAsync 字條選擇器仍必須識別原始元素;若該元素已不存在,這些讀取則會拋出 UiElementNotFoundException 而非選擇具有相同 AutomationID 或名稱的其他元素。 重新執行原始查詢以刷新結果。 有範圍讀取也會從一般 UIA 屬性收集器及已取得的 UIA 模式傳遞失敗,而非回傳空值或先前捕捉的值。

錄製是獨立套件,所以只檢查和驅動 UI 的專案不會拉入 SkiaSharp。 自動化套件同時針對 net10.0-windows 和 net10.0-windows10.0.19041.0;後者新增了 Windows 圖形擷取功能,這正是能screenshot擷取遮蔽或 GPU 複合 windows 的關鍵。 請參閱 NuGet 上每個套件的 README,了解完整 API 及目標與框架的權衡。

UiTarget.FromWindowHandle是測試框架的入口,這些框架已經給你一個視窗——例如MSTest.Windows.UIAutomation,該WindowTest.MainWindow視窗是你用 橋接的 MainWindow.Current.NativeWindowHandleUIA2AutomationElement。

Troubleshooting

錯誤 原因 解法
「找不到運行應用程式」 應用程式無法執行或名稱不符 請檢查流程名稱或使用 PID
「多個視窗匹配」 模糊 -a 值 從上述選項中選用-w <HWND>
「有多個視窗」 程序有多個視窗 用 -w <HWND> 來鎖定特定目標
「選擇器匹配 N 元素」 模糊的舊有選擇器 從輸出中擷取 sug inspect[0],或附加[1]到 legacy selector
「元素可能已經改變」 Slug 雜湊值與當前元素不符 重播 inspect 或 search 換新彈頭
「不支援任何召喚模式」 元素無法被召喚 使用 inspect 元素尋找可召喚的孩子
「找不到 UIA 視窗」 UIA 看不到整個流程 然後用 list-windows 來尋找 HWND。 -w
「窗戶是零大小」 視窗被最小化 應用程式會自動還原
截圖中沒有彈出視窗/下拉選單 預設擷取是逐視窗擷取,且不包含未擁有的覆蓋層 依照 截圖覆蓋的工作流程 選擇視窗 -w <hwnd> --capture-screen
foreground_not_target 來自 --capture-screen Windows 拒絕了啟用,所以截圖會記錄到實際在前面的視窗 點擊目標視窗或關閉竊取焦點視窗再試一次,或是放下 --capture-screen
element_not_found 錄製期間 選擇器給出但沒有匹配元素 重播 inspect 或 search 換個新的選擇器
WGC 在錄音期間無法收看 WGC 擷取初始化失敗;沒有無聲的退路 檢查顯示卡/驅動程式;用於 --capture-screen 同意螢幕 DC 擷取

常見模式

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

找到文字並呼叫其父文本

# 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

消歧義重複元素

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

帶有彈出視窗覆蓋層的截圖

winapp ui list-windows -a myapp # use the main window's HWND below
winapp ui set-value txt-searchbox-e5f6 "query" -a myapp; winapp ui screenshot -w <hwnd> --capture-screen
winapp ui invoke btn-settings-a1b2 -a myapp; winapp ui wait-for pn-settingspage-c3d4 -a myapp --timeout 3000; winapp ui screenshot -a myapp -o settings.png

發現、點擊並驗證

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

檔案對話互動

檔案開啟/儲存對話框是支援 UIA 的標準 Windows 對話框:

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

用來 inspect -w <dialog-hwnd> --interactive 找出特定對話中的實際字頭。

為什麼 ; 要用在連鎖(不是 &&)

當原生 CLI 寫入 stderr 或使用 ANSI 轉義序列時,PowerShell && 的運算子可能會當機。 請使用 ; ——它會無條件執行每個指令,避免這種死結。 這對代理工作流程也更好:你通常希望截圖能執行,即使呼叫的退出不是零。

配置區間測試模式

在 CI 管線(GitHub Actions、Azure DevOps)中使用 winapp ui 指令來進行煙霧測試和 UI 驗證。 wait-for 與 --property--value 作為斷言 — 在逾時回傳退出代碼 1,自動失敗 CI 步驟。

在 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

主張元素狀態 wait-for

wait-for --value 輪詢直到元素值與預期字串相符,並使用與 get-value (TextPattern → ValuePattern → SelectionPattern → Name 相同的智慧備援。 匹配時回傳退出代碼 0,超時返回退出代碼 1——使其成為對 CI 友善的斷言。 改用 --property 來查看特定的UIA物業。

# Assert: button click updated the counter (smart value fallback — works for TextBlock, TextBox, etc.)
winapp ui invoke "Counter Button" -a $pid
winapp ui wait-for "Counter Display" -a $pid --value "Count: 1" -t 5000

# Assert: text input was accepted
winapp ui set-value "Search Box" "hello world" -a $pid
winapp ui wait-for "Search Box" -a $pid --value "hello world" -t 3000

# Assert: checkbox was toggled (use --property for specific UIA properties)
winapp ui invoke "Dark Mode" -a $pid
winapp ui wait-for "Dark Mode" -a $pid --property ToggleState --value "On" -t 3000

# Assert: navigation happened (new page appeared)
winapp ui invoke "Settings" -a $pid
winapp ui wait-for "Settings Page" -a $pid -t 10000

# Assert: dialog was dismissed (element disappeared)
winapp ui invoke "Close" -a $pid
winapp ui wait-for "Dialog Title" -a $pid --gone -t 5000

Assert with JSON 輸出

--json搭配 PowerShell 或 jq 來處理更複雜的斷言:

在模式下的searchwait-for--json退出碼合約:當沒有任何元素匹配(search)或等待逾時(wait-for),指令會寫入一個完全可解析的結果包絡到 stdout({ "matchCount": 0, ... }或{ "found": false, "timedOut": true, ... })並回傳退出碼 1。 Stderr 在 --json 模式下為空(記錄器輸出被抑制)。 分支在包絡區,或在 $LASTEXITCODE,視哪個更符合人體工學而定。

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

JSON 包絡包括:

  • inspect: { "depth", "interactive", "hideDisabled", "hideOffscreen", "windows": [...] }
  • search: { "matchCount", "hasMore", "matches": [...] }
  • wait-for: { "found", "waitedMs", "element"?, "timedOut" }
  • get-property: { "elementId", "element", "properties": { ... } }

型別元素使用 type 和 數值 x、 y、 width、 height。 幾何體是以實體螢幕像素計算。 0,0,0,0是 使用者介面自動化 在此投影中空的/無顯示 UI 矩形;isOffscreen是獨立的,因此螢幕外元素仍可有非零界限。

每個inspect --jsonwindows[]項目及其status --json結果包括 windowDpi、 (scalewindowDpi / 96)、dpiAwareness、 coordinateSpace: "physical-screen-pixels"和 。 這些描述的是目標視窗的 DPI 上下文,而非無條件監視器的 DPI:Windows 對未知視窗報告為 96,系統感知視窗為 96,對應系統感知視窗為 DPI,而對每個螢幕感知視窗則為目前監視器 DPI。 如果無法讀取 HWND 或 DPI 上下文,指令會失敗,而不是默默替換 96。 當 status 在程序尚未有頂層視窗前解決時, hwnd 則 和 0 DPI 欄位會被省略,直到有視窗存在。 對於整個 inspect進程 ,所選目標視窗保持快速失敗;若後續彈出視窗在樹狀結構讀取後消失,該 windows[] 項目會攜帶 dpiError 或省略 DPI 欄位,而剩餘的視窗樹則會回傳。

請參閱出貨 winapp-ui-automation 技能, references/ui-json-envelope.md 完整範例為每個信封。

完整煙霧測試範例

# 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