명령줄에서 실행 중인 Windows 애플리케이션을 검사하고 상호 작용합니다. AI 에이전트 및 개발자가 UI 테스트, 디버깅 및 자동화에 사용합니다.
개요
winapp ui Windows 앱 UI를 검사하고 상호 작용하기 위한 명령을 제공합니다.
UIA(Windows UI 자동화)를 사용합니다. WPF, WinForms, Win32, Electron 및 WinUI 3 등 모든 Windows 앱에서 작동합니다.
대부분의 명령은 UIA 패턴(입력 삽입 없음)을 통해 앱을 구동합니다. 예외는 실제 입력ui click/ui hover/ui drag을 삽입합니다. UIA 패턴이 구동할 수 없는 컨트롤 및 ui touch 시나리오에 대해 마우스 시뮬레이션 /ui penui send-keys 을 사용하고, 터치 및 펜/스타일러스 입력을 합성하고, 키보드 입력을 합성합니다.
Important
대화형 데스크톱 요구 사항(입력 주입 동사).click, hover, drag, touch, pen, scroll --wheel및 send-keys --via send-input OS 수준 입력을 합성하므로 포그라운드에 대상 창이 있는 잠금 해제된 대화형 데스크톱 이 필요합니다.
잠긴 워크스테이션 또는 보안 데스크톱(LogonUI/UAC)에서는 권한 상승/no_interactive_desktop사례와 foreground_not_target 는 별개로 빠르게 삽입하고 실패할 수 없습니다.
touch
/
pen 또한 창이 확인되지 않을 때(no_target) 거부합니다. 대상 창 외부의 좌표는 치명적 이 아닌 경고( warnings[] 텍스트 모드의 --json항목 또는 텍스트 모드의 경고 줄)이며 삽입은 마우스 동사와 일치하여 계속 진행됩니다. UIA inspectwait-forget-propertysearchset-valueinvokeget-valuescroll --direction/--to 패턴을 통해 앱을 구동하고 헤드리스/잠긴 세션에 친숙합니다.
screenshot 는 삽입하지 않는 동사 중 예외입니다. 즉, 전용 회전이 필요하며, 프레임 캡처를 사용할 수 없거나 --capture-screen 사용될 때 엔진이 최소화된 대상을 복원하고 포그라운드로 대체하기 때문에 캡처에 사용 가능한 대화형 데스크톱이 필요할 수 있습니다. CI에서 UIA 패턴 동사를 선호합니다. 실제 입력이 필요한 시나리오에 대한 삽입 동사를 예약합니다. 또한 삽입하기 전에 제스처 동사는 대상 요소를 다시 확인하고 빈 공간에 입력을 착륙시키는 대신 애니메이션 효과를 주거나 재배치하는 경우 이를 거부 target_moved 합니다.
빠른 시작
핵심 루프를 실행 winapp ui --help 합니다. 수행할 수 있는 작업을 invoke 확인하거나 set-value 작업을 get-value 수행하고 결과를 확인 inspect -a <app> --interactive 합니다. 모든 명령의 --help 예제가 표시됩니다. 알 수 없는 명령(예: winapp ui dump코드 1)이 종료되고 가장 가까운 명령(전달할 --json때의 JSON 오류)을 suggestions 제안합니다.
# 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 앱이 종료되기를 기다립니다. PID 또는 창 핸들을 사용하는 명령을 포함하여 모든 게스트 명령을 유지 --on sandbox 합니다.
클라이언트 요구 사항, 간단한 설정/다시 연결 포커스 변경, 워크플로 조정 및 호스트 출력 배달에 대한 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
winapp ui invoke Open -w <dialog-HWND> --type Button
winapp ui set-value "Text editor" "hello" -a notepad --type Document
이러한 명령은 요소 선택기 inspect 에서 선택적 필터를 허용합니다. (선택기 사용), search, get-property, wait-forget-value, invoke, set-value, focusclick, scrollhover, screenshotscroll-into-view, recordtouch, 및 .pen
drag (두 선택기) 및 send-keys --target 하지 않습니다.
선택기와 제공된 모든 필터는 동일한 요소와 일치해야 합니다. 필터는 선택기를 좁히므로 inspectscreenshotrecord선택기가 선택 요소인 경우 필터가 하나도 없으면 실패 invalid_arguments 합니다.
pen필터 touch 에는 선택기가 필요합니다. 필터를 결합하거나 --path (invalid_arguments) 결합 --at 할 수 없습니다.
-
--root <selector>는 고유하게 일치하는 루트의 하위 항목만 검색하고 루트 자체는 검색하지 않습니다. AutomationId 또는 슬러그를inspect사용하여 명확하게 구분합니다. 하나의 일치 항목을 호출할 수 있더라도 여러 요소와ambiguous_selector일치하는 루트가 실패합니다. 누락된 루트는 일치하는 항목을 생성하지 않습니다. 루트가 발견되면 쿼리는 하위 항목이 일치하지 않는 경우에도 관련 없는 팝업 창을 검색하지 않습니다. 쿼리는 '의 표시 깊이로inspect제한되지 않습니다. -
--type <control-type>는 대/소문자를 무시하고 UIA 컨트롤 형식과 일치합니다. 유일한 별칭은TextBox→Edit및TextBlock→Text. 알 수 없는 이름(숫자 ID 및 와일드카드 식 포함)이 실패합니다invalid_arguments. -
--class-name <literal>는 대/소문자를 무시하고 공급자의 전체 UIAClassName와 일치합니다. 부분 문자열, 와일드카드 또는 정규식이 아닙니다. 공급자의 값을 검색하는 데 사용합니다get-property --property ClassName. 클래스 이름은 UIA 컨트롤 형식과 같을 필요가 없습니다.
필터링된 쿼리는 표시된 것과 동일한 뷰인 UIA의 컨트롤 뷰를 inspect사용합니다.
원시 뷰에만 노출된 공급자 노드는 반환되지 않습니다. 를 사용하여 inspect 포함하는 컨트롤과 해당 선택기를 찾습니다.
모든 41개의 공식 형식이 지원됩니다. Button, ,Calendar, CheckBox, ComboBox, ImageToolTipMenuMenuBarListMenuItemListItemHyperlinkProgressBarRadioButtonTabItemEditSliderToolBarTabScrollBarStatusBarSpinnerTreeText,, , SplitButtonDocumentDataItemWindowTableHeaderItemTitleBarHeaderSeparatorSemanticZoomTreeItemGroupAppBarCustomThumbDataGridPane,, ,, .
wait-for 는 모든 폴링에서 루트 선택기를 다시 확인하므로 명령이 시작된 후 루트가 나타날 수 있습니다.
--gone가 없는 루트는 일치하는 하위 항목이 없음을 의미합니다. 모호한 루트는 성공이 아닌 오류입니다.
중단된 조회는 실종 증명이 아닙니다. 조회 중에 요소가 제거되거나 읽기 전에 --value 교체되면 다음 폴링이 다시 확인되고 다른 조회 또는 읽기 오류가 명령에 실패합니다.
-w <HWND> 는 루트 검색을 해당 창의 UIA 트리로 제한합니다. 루트 검색을 사용하면 -a앱의 팝업 창을 찾을 수도 있습니다. 정확한 루트 AutomationId 일치는 모든 창에서 부분 문자열 일치보다 우선합니다. 여러 정확한 일치 항목이 여전히 실패합니다 ambiguous_selector.
루트 슬러그는 다른 창에 동일한 AutomationId가 있는 경우에도 해당 요소를 선택합니다. 선택한 루트를 바꾸면 이전 슬러그가 더 이상 일치하지 않습니다. 대체를 수행하도록 폴링하려는 경우 AutomationId 또는 이름 루트를 사용합니다.
필터가 있으면 두 개 이상의 요소가 남아 있는 경우를 제외한 search 모든 명령이 ambiguous_selector 실패합니다. 필터의 범위를 좁히거나 고유한 슬러그를 사용합니다. 요소 개수에 따라 작동하는 명령은 검색하는 모든 창에서 일치하므로 소유된 대화 상자에서 일치하는 컨트롤도 선택기를 모호하게 만듭니다. 정확한 AutomationId 일치는 필터링된 범위 내에서 부분 문자열 일치보다 우선 순위를 유지합니다. 세 가지 옵션을 모두 생략하면 기존 쿼리 동작이 유지됩니다.
동시 UI 워크플로 조정
Windows 포그라운드 창 하나, 키보드 포커스 1개, 커서 1개, 입력 스트림 1개만 있습니다. 두 winapp ui 워크플로가 동일한 로그인 데스크톱에서 한 번에 실행되면 서로 포커스를 훔치거나, 방금 연 메뉴를 해제하거나, 보류 중인 클릭 아래에서 대상을 이동할 수 있습니다.
중재는 항상 켜집니다. 물리적 데스크톱을 터치하는 모든 winapp ui 명령은 설정 없이 전환할 방법이 없으므로 두 에이전트가 서로의 창에 입력할 수 없습니다. 읽기 전용 명령은 계속 동시에 실행됩니다. 한 가지 예외는 차단 %USERPROFILE%\.winapp되는 에이전트 샌드박스와 같이 winapp의 조정 폴더에 액세스할 수 없는 프로세스입니다. 해당 명령은 계속 실행되지만 번갈아 가며 경고를 인쇄합니다(제외 --json 또는 --quiet제외).
명령 간의 연속성은 옵트인입니다. 기본적으로 각 명령은 자체 포함된 원샷입니다. 턴을 대기하고, 작업을 수행하고, 데스크톱을 즉시 해제합니다. 여러 명령에서 데스크톱을 유지하려면 동일한 워크플로 ID를 모두 제공합니다.
# Set once per logical UI workflow
$env:WINAPP_UI_WORKFLOW_ID = [guid]::NewGuid().ToString()
알아야 할 사항:
- 워크플로 ID는 하나의 논리적 워크플로 이름을 지정 합니다. 즉, 전체 에이전트가 아니고 반드시 하나의 앱이 아닐 수 있습니다. 명령 협조에 동일한 값을 사용합니다(녹음/녹화 및 캡처해야 하는 클릭). 하나의 에이전트가 둘 다 시작하는 경우에도 독립 워크플로에 서로 다른 값을 사용합니다.
- ID가 없으면 모든 명령은 독립적인 원샷입니다. 그것은 여전히 중재, 하지만 그것은 더 은혜 은행 하 고 완료 하는 순간에 바탕 화면을 손. 두 no-id 명령은 동일한 셸에서 시작된 경우에도 별도의 워크플로입니다.
- Fresh-shell 및 적응형 호스트는 동일한 값을 삽입해야 합니다. 각 명령이 대부분의 에이전트 도구 호출 작동 방식인 새 셸에서 실행되는 경우 그룹화할 수 있는 유일한 것은 모든 협력 호출에 명시적으로
WINAPP_UI_WORKFLOW_ID전달되는 것입니다. - 4초 유예는 모델 추론이 아니라 단단한 버스트를 보호합니다. ID가 있는 워크플로는 다음 명령이 4초 이내에 시작되는 한 순서를 유지합니다. 이는 한 스크립트의 백투백 명령을 다룹니다. 모델이 생각하는 동안 의도적으로 만료됩니다. 그것은 당신이 완료 말할 수없는 경우에 대한 대체입니다 - 당신이 할 수있는 경우, 그것을 기다리는 대신 실행
winapp ui yield. - 적응형 워크플로는 다시 검색하고, 유효성을 다시 검사하고, 재생해야 합니다. 추론 간격 후 다른 워크플로가 바탕 화면을 사용했을 수 있으므로 메뉴를 다시 열고 요소를 다시 해결한 다음 작동합니다. 알려진 종단 간 시퀀스를 생각하면서 데스크톱을 유지하는 대신 하나의 타이트한 스크립트로 보냅니다.
- 순서 지정은 먼저 소유자 선호도, 다른 항목 중 FIFO입니다. 워크플로가 활성 상태이거나 유예 상태인 동안 다른 워크플로가 이미 대기 중인 경우에도 명령을 계속 발급할 수 있습니다. 실행
winapp ui yield되거나 유예 기간이 만료되면 대기 워크플로가 엄격한 도착 순서로 제공됩니다. 따라서 한 워크플로의 연속 작업은 다른 워크플로를 무기한 지연할 수 있습니다. - 하드 캡이 없습니다. 긴 스크립트, 바인딩되지 않은 기록 또는 오류 루프는 다른 변경 워크플로를 차단할 수 있습니다.
-
취소 또는 프로세스 종료는 중단된 라이브 워크플로에 대한 복구입니다. 대기 중인 명령은 1초 후에 상태를 출력하고 종료되는
Ctrl+C상태로 중지할 수 있습니다130. - 호환되는 업데이트된 이진 파일만 협력합니다. 이전
winapp빌드는 이 기능보다 이전이며 조정되지 않습니다. UI 자동화 NuGet 패키지를 직접 호출하는 코드는 이 보장을 완전히 벗어나며, 조정은 패키지가 아닌 CLI에 있습니다.
순서를 기다리는 명령은 다음과 같습니다.
| Behavior | 명령어 |
|---|---|
| 동시에 실행(대기 안 됨) |
status, list-windows, inspect, search, get-property, get-value, get-focusedwait-for |
| 턴을 기다리지만 바탕 화면을 가져 가지 않습니다. |
set-value, scroll-into-view, scroll --direction/--torecord |
| 턴을 기다린 후 데스크톱만 사용합니다. |
invoke, click, drag, hover, scroll --wheel, touch, penfocus, send-keysscreenshot |
중간 행은 이해할 만한 가치가 있는 행입니다.
set-value
scroll-into-view
--to
scroll --direction
/전경이 아닌 UIA 패턴을 구동하여 헤드리스/잠긴 세션 친화적인 상태를 유지하고 누구도 데스크톱을 사용하지 못하도록 차단하지 않습니다. 그러나 앱이 표시하는 내용을 변경하므로 필드를 편집하거나 다른 사람의 클릭 아래에서 목록을 스크롤하지 않고 다른 워크플로의 순서 뒤에서 기다립니다.
한 워크플로 내에서 다른 공유 작업과 겹칩니다. 즉, record 기록 중인 호출을 set-value 캡처하는 방법입니다. 그들은 자신의 워크플로의 전방 장벽을 무시 하지 않습니다 : 동일한 워크플로의 이전 DesktopExclusive 명령 (a click, a screenshot)은 이후의 모든 명령을 차단하는 것과 똑같이 여전히 차단하므로 클릭과 그 뒤의 돌연변이는 작성한 순서대로 유지됩니다.
screenshot 은 항상 배타적 턴을 위해 큐에 대기합니다. 모든 캡처가 데스크톱을 방해하지는 않습니다. Windows 그래픽 캡처를 통해 캡처된 일반 표시 창은 그렇지 않지만, 엔진은 최소화된 경우 대상을 복원하고 프레임 캡처를 사용할 수 없거나 --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로 대체되며, 빈 프레임 복구는 언제든지 창을 포그라운드할 수 있습니다. 이 바탕 화면은 전체 녹음에 대해 개최되고 명령은 출력에 그렇게 말한다; 동일한 워크플로 입력도 대기합니다.
다음과 같은 오류가 표시 invalid_ui_workflow_id 될 수 있습니다. (변수가 설정되었지만 비어 있거나 256자 이상), desktop_coordination_unavailable (조정 상태는 읽을 수 없고 안전하게 다시 작성할 수 없거나 최신 winapp워크플로에서 작성됨), queue_capacity_exceeded ( 다른 워크플로의 64개 명령이 이미 대기 중입니다. 제한은 사용자가 시작한 프로세스가 아니라 라이브 외부 웨이터 수를 계산하므로 종료되었거나 사망한 명령에 속하는 항목은 슬롯을 차지하지 않습니다. 및 사용자 고유의 워크플로의 명령은 이 제한이 ui_turn_busy 아닌 서로 뒤에 큐를 대기합니다. (yield 사용자 고유의 워크플로에는 여전히 명령이 실행 중이고), ( cancelled 대기하는 동안 Ctrl+C, 종료 코드 130).
턴을 일찍 릴리스: winapp ui yield
4초 유예는 대체입니다. 완료되었음을 확실히 말할 수 없을 때 데스크톱을 예약된 상태 유지합니다. 이렇게 말할 수 있는 경우, 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를 설정해서는 안 됩니다. 하나도 없으면 각 명령이 완료되는 순간 데스크톱을 이미 릴리스하며 생성할 항목이 없습니다.
- 다단계 워크플로는 완료될 때, 특히 다른 워크플로가 대기 중일 때 생성되어야 합니다. 그것은 하나의 빠른 명령 비용과 다른 사람에서 4 초 실속을 제거합니다.
-
idempotent입니다. 유예가 이미 경과된 후 두 번 양보하면 성공하고 보고
{ "released": false }합니다. 이는 실패가 아니라 스크립트의 정상적인 끝입니다. - 다른 워크플로의 순서는 릴리스되지 않습니다. 다른 사람이 바탕 화면을 보유하거나 아무도하지 않는 경우, 그것은 no-op.
- 사용자 고유의 워크플로에 실행 중인 명령 또는 대기 중인 명령(예: 기록)이 있으면 실패
ui_turn_busy합니다. 그 아래에 놓으면 바탕 화면이 중간 명령으로 사라지므로 아무 것도 해제되지 않고 실행 중인 명령은 영향을 받지 않습니다. 기다리거나 중지한 다음 다시 양보합니다. - 이 작업에는 다음이 필요합니다.
WINAPP_UI_WORKFLOW_ID1이 없으면 .로 실패합니다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 search Seven -a calculator # hosted app: uses the frame window that hosts it
일부 패키지된 앱(예: 계산기)에는 자체 창이 없습니다. 다른 프로세스는 해당 프레임을 호스트합니다. 일치하는 프로세스(이름 또는 PID)에 표시되는 창 -a 이 없으면 콘텐츠를 호스트하는 프레임을 대신 사용합니다. 없는 경우(예: 앱이 여전히 시작 중) -a 프로세스를 대상으로 지정하므로 wait-for 창이 나타날 때까지 계속 찾습니다.
창 제목별
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] 표시된 선택기를 사용하는 대상 요소입니다.
세 가지 유형의 선택기가 있습니다.
| 선택기 | 의미 | Example |
|---|---|---|
MinimizeButton |
AutomationId(고유할 때 표시됨 - 안정적이고 기본 설정) | winapp ui invoke MinimizeButton -a myapp |
btn-close-d1a0 |
의미 체계 슬러그(고유 AutomationId가 없는 경우 표시됨) | winapp ui invoke btn-close-d1a0 -a myapp |
Submit |
Name/AutomationId에 대한 일반 텍스트 검색(대/소문자를 구분하지 않는 부분 문자열) | winapp ui invoke Submit -a myapp |
AutomationId 선택기는 XAML에서 개발자 집합 식별자AutomationProperties.AutomationId 입니다.
AutomationId가 전체 UI 트리 inspect 에서 고유하고 search 선택기로 직접 표시되면 유지되는 레이아웃 변경, 지역화 및 트리 재구성이 유지됩니다.
슬러그 선택기 (예: btn-close-d1a0)는 고유한 AutomationId가 없을 때 생성됩니다.
형식: prefix-name-hash. 해시는 요소 ID의 유효성을 검사하지만 UI가 변경된 후 부실할 수 있습니다.
출력 형식 검사
이 inspect 명령은 색이 지정된 출력을 사용하여 요소 트리를 표시합니다(선택기(청록색 선택기, 녹색 이름, 회색 메타데이터).
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가 있는 경우 직접 사용됩니다(예: TabViewNewTabButton).
고유한 AutomationId가 없으면 생성된 슬러그(예: tab-newtab-5f5b)가 사용됩니다.
의미 체계 슬러그
슬러그는 다음과 같은 형식 prefix-normalizedname-hash 을 사용합니다.
- 접두사 — 3자 형식 약어(btn, txt, chk, cmb, itm, tab, img, lbl, pn, win, grp, lnk, mnu 등)
- normalizedname - AutomationId(기본 설정) 또는 Name의 소문자 영숫자, 최대 15자
- 해시 - 요소 RuntimeId의 4자 16진수 해시(요소 ID 유효성 검사)
슬러그는 셸로부터 안전하며(특수 문자 없음), 고유하며 인수로 직접 사용할 수 있습니다. 쿼리 필터가 없으면 해시는 부실 검색을 제공합니다. 요소가 교체된 경우 다음을 얻을 수 있습니다. "요소가 변경되었을 수 있습니다. 검사를 다시 실행합니다." 필터링된 쿼리는 범위 지정 및 형식화된 쿼리를 참조하세요.
이름이나 AutomationId가 없는 요소는 접두사 + 해시(예: pn-c8a3)만 표시합니다.
여러 일치 항목 구분
출력의 inspect/search 슬러그는 고유하지만 레이아웃 변경에서 변경할 수 있습니다. 여러 항목이 일치할 때 일반 형식 이름 또는 텍스트에 사용합니다. 선택기가 모호한 경우 CLI는 모든 일치 항목을 해당 슬러그와 인쇄하므로 올바른 항목을 선택하고 해당 슬러그로 다시 실행할 수 있습니다.
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 # 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
예제 출력(기본값):
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="..."— 편집 가능한 요소의 현재 텍스트 콘텐츠(Name과 다른 경우)
search
선택기와 일치하는 요소를 찾습니다. 출력은 의미 체계 슬러그를 보여줍니다.
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)
출력에 표시된 슬러그(예: btn-minimize-d1a0)는 다른 명령과 함께 직접 사용할 수 있습니다.
winapp ui invoke btn-minimize-d1a0 -a notepad
get-property
요소에서 속성 값을 읽습니다. 패턴별 상태(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의 6개 텍스트 서식 특성을 포함하여 속성을 나열하지 않으면 --property 알 수 없는 이름이 실패 invalid_arguments 합니다.
wait-for --property 는 대/소문자를 구분하는 동일한 이름을 사용하고 폴링하기 전에 알 수 없는 이름을 거부합니다.
전체 문서 텍스트 서식 지정
서식은 현재 선택 영역이나 캐리트가 아니라 요소의 전체 TextPattern 문서에서 읽습니다. 읽기는 포커스 또는 선택을 변경하지 않습니다.
| Property | 균일한 값(문자열로 반환됨) |
|---|---|
FontWeight |
숫자 가중치(예: "400" 일반) 또는 "700" (굵게) |
FontName |
글꼴 패밀리 이름(예: "Courier New" |
FontSize |
포인트 단위로 크기(예: "15.5" |
ForegroundColor |
10진수 Windows COLORREF(0x00BBGGRR예: "3678732" RGB(12, 34, 56) |
IsItalic |
"True" 또는 "False" |
StrikethroughStyle |
숫자 UIA 텍스트 장식 스타일(예: "0" (없음) 또는 "1" (단일) |
숫자는 고정 서식을 사용합니다(로캘에 관계없이 소수점). 각 특성은 대신 다음을 반환할 수 있습니다.
| Value | 의미 및 다음 단계 |
|---|---|
"Mixed" |
서식은 문서 내에서 다릅니다. 균일한 값으로 처리하지 마세요. 이 명령은 개별 텍스트 범위를 쿼리하지 않습니다. |
"NotSupported" |
문서의 TextPattern 공급자는 이 특성을 보고하지 않습니다. 앱의 접근성 지원을 확인합니다. |
"Unavailable" |
요소에 TextPattern이 없습니다. 텍스트/문서 요소를 사용 inspect 하거나 search 찾습니다. |
모든 속성을 나열할 때 라이브 요소를 확인할 수 없는 경우 캐시된 기본 속성을 계속 사용할 수 있으며 다른 속성을 삭제하지 않고 형식이 잘못된 서식 값을 생략합니다. 이러한 누락은 경고로 기록됩니다. 누락 대신 오류가 발생하도록 특정 서식 지정 속성을 요청합니다.
공급자 오류는 오류가 아닌 오류로 유지됩니다 "Unavailable".
stale_element앱을 다시 검사하고 현재 선택기를 사용하여 다시 시도합니다.
JSON 봉투에는 형식화된 element봉투, 문자열 값이 포함elementId됩니다properties.
기존 속성(포함 BoundingRectangle)은 해당 형식을 유지합니다.
예를 들어 서식 부분은 properties 다음과 같습니다.
{
"FontWeight": "700"
}
screenshot
창 또는 요소를 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 .
--output 를 사용하여 --on sandbox호스트 대상의 이름을 지정합니다. 일반 출력에 성공하고 --json 이미지가 전달된 후 해당 호스트 경로를 보고합니다.
기본 캡처 경로는 Windows 사용합니다. WGC(Graphics.Capture)에서 실제 DWM 복합 표면을 읽습니다. 둥근 모서리, 투명도를 유지하고 다른 windows 창이 가려지는 동안에도 작동합니다. WGC를 사용할 수 없는 경우(이전 Windows 빌드) CLI는 PrintWindow로 대체됩니다.
대상 창에서 소유하지 않은 오버레이를 포함하여 화면의 위치에 표시되는 팝업 또는 도구 설명이 필요한 경우에 사용합니다 --capture-screen -w <hwnd> . 레이블이 지정된 패널을 작성하지 않고 해당 창의 화면 영역을 읽고 창을 포그라운드로 먼저 가져옵니다. 이 -a경우 정확히 하나의 일치하는 창이 필요합니다. 여러 최상위 또는 소유 창이 일치하는 경우 .winapp ui list-windows -a <app>-w <hwnd> 캡처 모드를 전환하지 않고 창을 포그라운드하려는 경우 사용합니다 --focus (예: 스크린샷이 사용자가 현재 보고 있는 것과 일치하는지 확인).
화면 DC는 실제로 앞에
--capture-screen있는 모든 것을 캡처하기 때문에 캡처하기 직전에 대상이 포그라운드에 도달했는지 확인하고, 그렇지 않은 경우 실패합니다(포커스 도용 방지, UAC 프롬프트 또는 다른 창 활성화 자체).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-30fps 및--max-edge64-4096(기본값 1280)을 지원합니다. 프레임 데이터는 1GiB로 제한됩니다. 상한에 도달하면 MP4가 계속됩니다.
에이전트에서 읽을 수 있는 프레임 아티팩트:
evidence.mp4
evidence.frames/
manifest.json
frames.ndjson
frames/
frame-000000-t000000000012.jpg
frames.ndjson에는 샘플sampleIndex당 단조elapsedMs, MP4 상대mediaTimeMs, imageIndexfile및 changed. 연속 픽셀 동일 샘플은 이전 품질-85 JPEG를 다시 사용합니다.
manifest.json는 요청, 타이밍, MP4 상태, 이미지 차원 및 상태(complete또는partialtruncated)를 기록합니다. 잘린 타이밍은 유지된 접두사를 다루며 video 전체 MP4를 설명합니다.
기록을 --overwrite.로 바꾸려는 경우가 아니면 새 출력 경로를 선택합니다.
이 기능이 없으면 생략하는 경우에도 --frames기존 비디오 또는 해당 쌍을 .frames 이루는 디렉터리가 녹화를 차단합니다.
새 캡처가 실패하는 경우 이전 MP4는 그대로 유지됩니다. 교체에 성공하면 새 기록이 생략되더라도 이전 프레임 디렉터리가 그대로 유지 <output-name>.frames.previous-<id>됩니다 --frames. 부분 증거를 보존하고 다시 시도하기 전에 보고된 recoveryHint 내용에 따릅니다. MP4 종료에 실패하면 유지된 프레임을 아래에 <output-name>.frames.partial-*게시할 수 있습니다. 프레임 아티팩트는 암호화되지 않은 화면 콘텐츠를 포함합니다. 스크린샷 또는 비디오와 같이 처리합니다.
이 --on sandbox경우 MP4와 프레임 디렉터리가 모두 생략될 때 --output 기본 출력을 포함하여 호스트에 전달됩니다. 중단된 녹화 및 전체 데스크톱 캡처는 샌드박스 캡처를 참조하세요.
캡처 모드 (JSON mode 필드에 보고됨):
-
wgc— Windows 그래픽 캡처(기본값, 창이 폐색된 동안 작동). -
printwindow— GDI PrintWindow(이 시스템/세션에서 WGC를 사용할 수 없는 경우 대체, 대신 화면 DC를 사용하도록 다시 실행--capture-screen). -
screen— 스크린 DC를 통해--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.
요소 선택기는 해당 요소가 그려지는 창에서 해당 요소의 영역을 기록합니다. 메뉴의 항목, 플라이아웃, 도구 설명 또는 자체 팝업 창에서 열리는 교육 팁의 경우 녹음/녹화에 창 뒤에 있는 창이 아닌 팝업이 표시됩니다.
호출
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
테스트가 선택한 요소에 대해 특정 작업을 수행해야 하는 경우에 사용합니다 --action . 요청된 작업이 실패하더라도 다른 패턴 또는 호출 가능한 상위 항목을 시도하지 않습니다. 호출 및 선택 영역을 모두 지원하는 컨트롤이 호출 --action select되지 않고 선택됩니다.
--action슬러그는 정확히 하나의 요소를 대상으로 합니다. 두 개 이상의 요소와 일치하는 일반 텍스트 또는 AutomationId 선택기는 첫 번째 일치에서 동작하지 않고 0이 아닌 종료 코드로 닫혀 실패하므로 이름이 모호한 경우 inspect/search 부터 슬러그를 전달합니다.
--root, --type범위 지정 및 --class-name형식화된 쿼리에 설명된 대로 일치 항목의 범위를 좁히거나 지정하지 않습니다 --action.
작업을 해당 대화 상자로 제한하거나 -a <app> 앱의 창을 포함하는 데 사용합니다-w <dialog-HWND>. 필터링된 호출은 동작하기 전에 고유 대상을 확인하고, 정확히 하나의 일치하는 요소가 필요하며, 다른 창이나 호출 가능한 상위 항목으로 전환되지 않습니다. 0 일치 항목이 실패하고 element_not_found중복 항목이 실패합니다 ambiguous_selector. 부실 요소 또는 재활용된 창이 동작하지 않고 실패합니다. 다시 실행 inspect 하거나 search 현재 선택기를 선택합니다.
필터링된 호출이 없으면 --action해당 요소에 대한 순서대로 패턴을 시도합니다.
| Action | Operation |
|---|---|
invoke |
InvokePattern.Invoke |
select |
SelectionItemPattern.Select |
toggle |
TogglePattern.Toggle, 정확히 한 번 |
toggle-on / toggle-off |
ToggleState 읽기; 이미 올바른 상태를 변경하지 않고 성공합니다. 그렇지 않으면 토글하고 확인합니다. |
expand / collapse |
ExpandCollapsePattern.Expand / Collapse |
toggle-off
Indeterminate 시작 toggle-on 상태는 최대 두 번의 전환을 허용하고 각 전환 후 상태를 확인합니다. 다른 시작 상태는 하나의 전환을 허용합니다. 요청된 상태에 도달하지 않으면 계속 토글하지 않고 명령이 실패합니다. 확인에 실패하면 컨트롤이 변경될 수 있습니다. 다음에 수행할 작업을 결정하기 전에 읽어 읽습니다 ToggleState .
필터를 사용하지 않고 --action 도 자동 동작은 변경되지 않습니다. InvokePattern, TogglePattern, SelectionItemPattern, ExpandCollapsePattern(확장)을 시도하고 필요한 경우 호출 가능한 상위 항목을 다시 시도합니다.
지원되지 않는 작업은 0이 아닌 종료 코드와 stderr의 구조적 오류로 --json실패합니다. 선택한 컨트롤을 검사하고 지원하는 작업을 선택하거나 의도한 부모를 명시적으로 대상으로 지정합니다. 성공 JSON에는 JSON 참조 및 참조가 포함됩니다 requestedActionperformedAction.
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). 단추 위로 올라가기 전에 지속적인 호버(커서가 도착하는 즉시가 아닌) 래치에서 팔의 대상/병합 오버레이를 삭제 할 수 있습니다.
Bare
x,y는 동일한 공간winapp ui inspect/search보고서의 화면 좌표이며 선택기는 요소의 가운데로 확인됩니다. 먼저 검사하여 점을 선택합니다.
send-keys --via send-input마찬가지로drag대상을 포그라운드로 가져온 후 화면 좌표에 OS 전체를 삽입합니다. 포커스를 대상(예: 백그라운드 프로세스에서 포커스 도용 방지)으로 가져올 수 없는 경우 잘못된 창에서 포커스를 끌거나 창을 먼저 클릭하는 대신 명령이 실패합니다.(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,pinchstretch. -
--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>— 해제하기 전에 연락처를 길게 누릅니다(길게 누르세요. 설정되지 않은 경우 기본값은 500mslong-press임). -
--duration-ms <ms>— 제스처 이동에 대한 글라이드 시간(살짝 밀기/손가락 모으기/스트레치, 기본값 300). -
--fingers <n>— 연락처 수(1~10, 기본값 1)입니다.pinch/stretch항상 2를 사용합니다.
주입 안전성.
touch는 0이 아닌 대상 창 핸들이 확인되고 해당 창이 포그라운드를 보유하지 않는 한 삽입을 거부합니다. 창을 확인할no_target수 없거나 포커스를 전송할 수 없는 경우 또는foreground_not_target잠긴/안전한 데스크톱에서 실패no_interactive_desktop합니다. 모든 좌표(요소 중심, 명시적--at/--to-point및 생성된 웨이포인트)는 대상 창 사각형에 대해 검사됩니다. 창 외부의 지점은 치명적이 아닌 경고(warnings[]텍스트 모드의 항목 또는 텍스트 모드의--json경고 선)로 표시되고 삽입은 여전히 진행됩니다. 이는 마우스 동사(click/drag/hover/scroll)와 일치하며 창 외부 좌표에도 삽입됩니다.--fingers위의 10은 앞에서 거부됩니다.하드웨어 참고 사항입니다. Touch는 최신 가상 포인터 디바이스(
CreateSyntheticPointerDevice(PT_TOUCH))를 선호하며 레거시InitializeTouchInjection/InjectTouchInputAPI로 대체됩니다. 현재 디바이스/세션에서 삽입이 지원되지 않는 경우 명령은 잘못된 성공을 보고하는 대신 실제 Win32 오류 코드 (예: "지원되지 않음")를 표시합니다. 0이 아닌 종료를 "터치가 전달되지 않음"으로 처리합니다.원격 데스크톱/VM 세션 RDP(원격 데스크톱) 또는 일부 VM 세션에서 OS는 실제로 대상 앱에 도달하지 않고 가상 터치(종료 0)를 허용할 수 있습니다. 원격 세션이 검색되면
touch배달 불확실성 경고 (warnings[]입력 항목--json또는 텍스트 모드의 경고 줄)를 추가합니다. /exit 0은 ✅앱이 입력을 받은 것이 아니라 삽입 호출이 성공했음을 의미합니다. 중요한 경우 효과를ui screenshot/ui inspect확인합니다.
펜
Windows 가상 포인터 API를 사용하여 가상 펜/스타일러스 입력(탭 및 잉크 스트로크)을 삽입합니다(CreateSyntheticPointerDevice(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쌍으로 지정합니다(1포인트 경로는 탭). -
--pressure <0.0–1.0>— 펜 압력(기본값 0.5). -
--tilt-x <deg>/--tilt-y <deg>— 펜 기울기 각도 ,90 ~90(기본값 0). -
--eraser— 팁 대신 펜의 지우개 끝을 사용합니다. -
--duration-ms <ms>— 경로 전체에서 보간된 UPDATE 프레임으로 분산된 총 스트로크 이동 시간(밀리초)입니다(기본값: 웨이포인트당 ~10ms). 이를 사용하여 펜이 처음부터 끝까지 눈에 띄게 이동하는 속도를 제어할 수 있습니다.
주입 안전성. 마찬가지로
touch,pen0이 아닌 포그라운드 대상 창(no_target/foreground_not_target/no_interactive_desktop)을 사용하지 않고 삽입을 거부하고 대상 창 사각형에 대해 모든 잉크 지점을 검사하여 마우스 동사와 일치하는 모든 잉크 지점을 치명적이 아닌 경고(warnings[]--json텍스트 모드의 경고 줄)로 표시합니다. 잘못된--pressure(0.0-1.0 외부) 또는 기울기(±90°외부)가 앞에서 거부됩니다.원격 데스크톱/VM 세션 펜 라우팅은 원격 데스크톱 대해 특히 불안정합니다. 삽입 호출은 성공(종료 0)을 보고할 수 있지만 펜 입력은 앱에 도달하지 않습니다. 원격 세션이 감지되면
pen배달 불확실성 경고(warnings[]--json텍스트 모드 또는 텍스트 모드의 경고 줄)를 추가하므로 ✅ 확인된 배달로 오인되지 않습니다. 로컬 대화형 데스크톱에서 펜 종속 흐름의 유효성을 검사합니다.
호버
마우스를 요소의 가운데로 이동하여 가리키기 효과(도구 설명, 플라이아웃, 시각적 상태)를 트리거합니다. 작은 흔들림으로 사실적인 마우스 이동을 사용한 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)
send-keys
가상 키보드 입력 보내기 - 에 대응하는 키보드입니다 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
winapp ui send-keys "ctrl+capslock+f12" -a myapp --via send-input # Narrator command: toggle developer mode
키 문법 (공백으로 구분된 토큰, 따옴표 다중 토큰 문자열):
-
명명된 키 -
enter/return,,tab,esc/escape,space,backspacedelete/del,insert,home, ,endpageup/pgup, ,pagedown/pgdnup/down/left/rightf1, -f16appsprintscreencapslock -
시퀀스 - 여러 토큰을 순서대로
down down enter눌렀습니다. -
한정자 콤보 —
ctrl,shift,alt조인win:+ctrl+shift+t,alt+f4. 한정자로 시작하지만 마지막ctrl+a+b() 앞에 알 수 없는 세그먼트가 있는 토큰은 오류입니다. 사용text=하거나--verbatim입력합니다. -
화면 읽기 권한자 명령 - 내레이터, NVDA 및 JAWS 키
ctrl+capslock+f12( 홀드capslock또는insert(별칭ins), 내레이터 개발자 모드 토글--via send-input화면 읽기 프로그램이 게시된 키를 받지 않기 때문에 필요합니다. 실행 중인 화면 읽기 프로그램이 없으면 CapscapslockLock을 켜거나 끄면 명령이 경고합니다. 이를 방지하려면 길게 누릅니insert다. -
리터럴 텍스트 - 알려진 키가 아닌 토큰은 문자
hello별로 입력됩니다. 인접한 리터럴 단어는 둘 사이의 공간을 유지하므로 따옴표 붙은 구"Hello world"문은 축자로 입력됩니다(공간은 유지됨). 콤보로 구문 분석되지 않고 텍스트로만 포함+되거나C++텍스트로a+b입력되는 리터럴입니다. -
명시적 리터럴 이스케 이프 - 키
text=또는 한정자 이름과text=enter충돌하는 경우에도 토큰을 축자 형식으로 접두사로 지정합니다. Enter 키를 누르는 대신 "enter"라는 단어를 입력하고text=ctrl+a리터럴 문자열을 입력합니다. 이스케이프를vk=미러링합니다. 이스케이프된 값은 여전히 인접한 리터럴 단어(text=down low→ "down low")와 결합됩니다. 토큰은 공백으로 분할되고 인접한 리터럴이 단일 공백으로 다시 조인되므로 값 내에서text=백슬래시 이스케이프를 사용하여 공백,\s→ → 탭 → 줄 바꿈 →\t줄 바꿈 →\n\r리터럴 백슬래시 → 공백을 입력\\합니다.\n,\r각\r\n줄 바꿈(Enter/VK_RETURN)을 삽입하므로text=line1\nline2text=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(\s백슬래시 및 "s"로 형식화됨). 이스케이프된 컨트롤 문자가 필요한 경우 토큰을 사용합니다text=. -
원시 가상 키 (
vk=0xNN(16진수) 또는vk=NN이름 없는 키의 경우 (10진수)
옵션:
-
--target <selector>- 키를 보내기 전에 (UIA를 통해) 이 요소에 초점을 맞춥니다. 키가 없으면 키는 앱의 현재 포커스가 있는 요소로 이동합니다. -
--verbatim— 전체 키 인수를 리터럴 텍스트(키/콤보/vk=/text=구문 분석 없음)로 입력하고 정확한 공백을 유지합니다. 토큰text=별 이스케이프의 전체 인수 형식입니다. -
--via <transport>—post-message(기본값) 대상 창의 큐에 게시WM_KEYDOWN/WM_KEYUP/WM_CHAR합니다. HWND 대상이며 UIPI를 무시합니다(무결성 수준에서 작동).send-input를 통해SendInputOS 전체를 삽입하고 포그라운드 창으로 이동합니다.
전송/알려진 제한 선택:
-
post-message는 UIPI를 무시하고 포그라운드되는 창에 의존하지 않기 때문에 기본값입니다. 제한: 하위 수준 후크(모든 창 큐의 해당 탭 입력 업스트림)를 통해WH_KEYBOARD_LL등록된 전역 바로 가기 키를 트리거할 수 없으며, 원시 키 상태를GetAsyncKeyState읽는 앱은 유지된 한정자를 관찰하지 못할 수 있습니다. 포그라운드 후 자동으로 확인되고 대상 스레드의 포커스가 있는 자식 창 (통해GetGUIThreadInfo)에 게시되므로 컨트롤이 별도의 자식 창인 클래식 Win32/WinForms 앱은 컨트롤을 수동으로 대상으로 지정하지 않고 키를 받습니다. WinUI 3 / UWP 앱에는 자식 HWND가 없는 창 없는 XAML 컨트롤이 있으므로 게시된WM_CHAR/WM_KEYDOWN컨트롤은 착륙할 수 없으며 삭제됩니다. 사후 메시지는 드라이브할 수 없습니다(명령이 경고하고 0을 종료함).--via send-input(WPF 창은 단일 HWND이며 내부적으로 포커스가 있는 요소로 키를 라우팅하므로 사후 메시지가 작동합니다.) -
send-input는 완전히 실제 입력(낮은 수준의 후크에서 볼 수GetAsyncKeyState있는 한정자)을 생성하지만, 상승된 프로세스에서 낮은 무결성(AppContainer/AppX) 대상으로 삽입할 때 포그라운드이고 UIPI에 의해 차단되는 모든 창으로 이동합니다. 실패를 보고하는 경우send-input대상은 상승되거나 AppX 앱일 가능성이 높습니다. 일치하는 무결성 수준에서 CLI를 사용post-message하거나 실행합니다. 안전 경비원send-input으로서 포커스를 가져올 수 없는 경우 잘못된 창에 입력하지 않고 삽입 및 실패하기foreground_not_target직전에 대상 창이 실제로 포그라운드에 있는지 확인합니다. 포커스를 맞추거나 창을 먼저 클릭합니다. 잠긴 데스크톱 또는 보안 데스크톱에서는 대신 세션 잠금을 해제하거나 UIA 패턴 동사(no_interactive_desktop,set-value)를 사용하여(삽입할 포그라운드 창이 없음) 실패invoke합니다. -
시스템 예약 콤보(
win+l, ,win+r,ctrl+shift+esc,ctrl+alt+del,alt+tabalt+f4,ctrl+esc, 고독win/printscreen한 , ...)는 OS 전체에서 전송할 때 대상만 사용하는 것이 아니라 OS/셸에서 작동합니다.send-input는 OS 수준에서 삽입하면 대상 창(예:invalid_arguments세션 잠금)을 벗어나는 효과가 있으므로win+l아무 것도 보내지 않습니다. 옵트인(opt in)을 전달--allow-system-keys하면 PowerToyswin+shift+v와 같은 글로벌 핫키를 구동하거나win+r(글로벌 하위 수준 후크가 OS 차원의 입력 스트림을 감시하여 삽입된 콤보가 실행되도록) 구동할 수 있습니다. 중단된 상태에서도--allow-system-keys차단된 상태로 유지되는 예외:win+l자동화에서 복구할 수 없는 워크스테이션LockWorkStation()을 잠그고(CI 및 원격 데스크톱 세션 중단), 플래그에ctrl+alt+del관계없이 삽입된 입력에서 Windows 삭제하는 SAS(보안 주의 시퀀스)이므로 잘못된 성공을 보고하는 대신 오류(invalid_arguments종료 1)가 발생합니다. 다른 콤보(alt+f4, ,ctrl+shift+esc,win+r...)는 플래그와 함께 허용됩니다. 호출자는 주의해야 합니다. 또는 특정 창에--via post-message시스템 콤보를 제공하려면 창 범위가 지정되고 영향을 받지 않습니다(게시된 경우 대상 창이 계속 닫히더라도 게시된win+lalt+f4항목은 무해합니다).
키 입력당 이벤트(KeyDown/ TextChanged):
-
명명된 키와 한정자 콤보(
down,enter, ,ctrl+shift+tvk=0xNN)는KeyDown실제KeyUp(및)를 발생시키고 불연속WM_KEYDOWN/WM_KEYUP(또는SendInput가상 키 이벤트)으로 전달됩니다. -
리터럴 형식 텍스트 (
hello)는 전송에 따라 다릅니다.-
--via send-input는 각 문자를 활성 키보드 레이아웃의 가상 키(및 Shift)에 매핑하므로 대상은 올바른 가상 키와 OS로 구성된(발생) 즉 문자당 하나의 전체 키 입력으로 정품KeyDown이 표시됩니다.WM_CHARTextChanged현재 레이아웃에서 연결할 수 없는 문자(또는 Ctrl/AltGr 필요)는 유니코드 패킷으로 대체되므로 정확한 문자가 계속 표시됩니다. 키 입력별 충실도(예: 처리기가 키를 해제send-input하는 WinUI 3/WPFKeyDown구동)가KeyDown일반(상승되지 않은) WinUI 3 테스트 호스트의 경우 포그라운드 창을 대상으로 하기 때문에winapp ui focus먼저 해당 창을 포그라운드로 가져옵니다(send-input/클릭). -
--via post-message는 문자당 단일WM_CHAR문자를 게시합니다(형식화된 텍스트에 대해서는 게시WM_KEYDOWN/WM_KEYUP않습니다. 명명된 키/콤보용으로 예약됨). 이는 문자KeyDown별로 발생하지 않습니다. 창의 포커스가 있는 자식 컨트롤로 자동으로 대상을 변경하므로 클래식 Win32/WinFormsWM_CHAR기반 편집 컨트롤이 텍스트를 표시합니다(발생TextChanged). 주의 사항: WinUI 3 / UWP / XAML 앱 (winapp의 기본 대상)에는 게시 된WM_CHAR/ 것을 무시하는WM_KEYDOWN컨트롤이 있으므로 명령이 성공을 보고하더라도 리터럴 텍스트나 명명 된 키 (Enter, digits, ...)가 도달하지 않습니다. 대상이 XAML처럼 보이고 여전히 0을 종료할 때 경고를 내보냅니다(PostMessage화재 및 잊어버리고 배달을 확인할 수 없습니다). WinUI 3/UWP/WPF 앱을 구동하는 데 사용합니다--via send-input. 클래식 Win32 컨트롤에 대한 예약post-message또는 무결성 수준에서 창 범위만 필요한 경우.
-
JSON 출력(--json): 결과는 hwnd 키가 전달된 --via post-message 창입니다. 이는 명령이 대상을 다시 지정할 때 확인된 포커스가 있는 자식 컨트롤이므로(반드시 최상위 -w/-a/-e 창이 아님) 자동화에서 입력이 착륙한 위치를 정확하게 확인할 수 있습니다. 해당 유효 대상이 창 없는 XAML 호스트처럼 보이면 위의 배달 주의 사항도 항목(콘솔에 표시된 것과 동일한 권고)으로 warnings[] 표시되므로 ✅ 종료 0은 확인된 배달로 오인되지 않습니다.
set-value
프로그래밍 방식으로 편집 가능한 요소에 값을 설정합니다(키 입력 없음, 앱 포그라운드 없음). 대체 체인을 사용합니다.
- ValuePattern — TextBox, ComboBox, PasswordBox 및 가장 편집 가능한 컨트롤입니다.
- RangeValuePattern - 값이 숫자로 구문 분석되는 경우 숫자 컨트롤(Slider, ProgressBar)입니다.
-
LegacyIAccessible (
IAccessible::put_accValue) - ValuePattern을 노출하지 않는 TextPattern 전용 편집 컨트롤의 대체(예: 서식 있는 편집/Document작성 상자)입니다. 이렇게 하면 이러한 컨트롤을 읽을 수 있지만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 3RichEditBox및 WPFRichTextBox프로그래밍 방식 값 설정을 지원하지 않습니다. 의도적으로 콘텐츠를 읽기 전용(텍스트 패턴, 설정 가능한 값 패턴 없음)으로 UI 자동화 노출하므로set-value쓸 수 없습니다. 이를send-keys위해 잠금 해제된 포그라운드 데스크톱이 필요합니다.
get-value
요소에서 현재 값을 읽습니다. 스마트 대체 체인을 사용합니다. TextPattern(RichEditBox, Document) → ValuePattern(TextBox, Slider) → 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.
포커스
winapp ui focus txt-textbox-a4b1 -a notepad
필요한 경우 선택한 컨트롤의 창을 활성화한 다음 컨트롤에 초점을 맞춥니다.
선택기가 필요합니다. 대상을 사용 -a <app> 하거나 -w <HWND> 선택합니다.
성공한다는 것은 명령이 반환되기 전에 창이 포그라운드이고 선택한 컨트롤이 확인되었음을 HasKeyboardFocus 의미합니다. 이 명령은 컨트롤이 포커스를 보고할 수 있도록 최대 500ms를 허용합니다. 포커스를 되돌려보지 않고 대상이 사라지거나 포그라운드를 잃으면 중지됩니다. 주 창 앞에 있는 소유 대화 상자로는 충분하지 않습니다. 대상인 경우 대화 상자에서 컨트롤을 선택합니다.
이 명령은 잠금 해제된 대화형 데스크톱이 필요하며 Windows 활성화 제한을 무시하지 않습니다. 오류가 foreground_not_target발생하면 의도한 창을 수동으로 활성화하고 다시 시도하기 전에 차단 대화 상자를 확인합니다.
의 경우 focus_not_acquired현재 UI를 검사하고 포커스 가능한 컨트롤을 선택합니다.
의 경우 stale_element대상을 사용하거나 search을 사용하여 inspect 다시 검색합니다.
검색 및 다시 시도 명령에 대해 동일한 --on 대상을 유지합니다.
보기로 스크롤
요소를 표시되는 영역으로 스크롤합니다.
winapp ui scroll-into-view itm-targetitem-c3d4 -a myapp
wait-for
요소가 나타나거나 사라지거나 값이 대상에 도달할 때까지 기다립니다.
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>— 휠 노치(detents)를 통해SendInput요소의 가운데에 마우스 휠 입력을 합성합니다1. = 1노치 업/어웨이,-1= 1노치 다운/쪽으로,3= 3노치 업. (각 노치는 사용하는 120개 단위WHEEL_DELTA의 WindowsSendInputCLI는 120으로 조정됩니다.) 를 무시합니다ScrollPattern.
--direction은--to(는--wheel) 상호 배타적입니다. 정확히 하나를 전달합니다. 화면 좌표에 OS 차원의 입력을 삽입하기 때문에--wheel대상을 먼저 포그라운드로 가져오고 잘못된 창을 스크롤하는 대신 포커스를 전송할 수 없으면 실패합니다(foreground_not_target) .
집중하기
winapp ui get-focused -a myapp
winapp ui get-focused -w <HWND> --json
부모 창을 통해서만 앱 소유권을 사용할 수 있는 컨트롤을 포함하여 선택한 앱에 현재 키보드 포커스가 있는 요소를 표시합니다.
포커스가 -w다른 창이나 동일한 프로세스의 소유 팝업이 아닌 해당 창에 속해야 합니다. 이 -a경우 선택한 프로세스의 다른 창이 포함됩니다.
JSON 출력에는 hasFocus:false 포커스가 있는 요소가 대상에 속하는 것으로 확인할 수 없는 경우가 있습니다. 포커스 또는 창 소유권 쿼리가 실패하면 명령이 0이 아닌 상태로 종료됩니다. 다시 시도하고 get-focused창이 닫힌 경우 창을 list-windows 다시 재발견합니다.
list-windows
팝업 및 대화 상자를 포함하여 앱에 표시되는 모든 창을 나열합니다. 기본적으로 크기가 0인 제목 없는 창(보이지 않는 시스템 창)은 제외됩니다.
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
yield
4초 유휴 유예를 기다리는 대신 이 워크플로의 UI 턴을 일찍 해제합니다. 필요; WINAPP_UI_WORKFLOW_ID앱 및 선택기를 사용하지 않습니다.
일찍 턴 해제를 참조하세요.
winapp ui yield
winapp ui yield --json # {"released": true} — or false when nothing was held
프레임워크 지원
| 프레임워크 | 검사 | search | 호출 | set-value | screenshot |
|---|---|---|---|---|---|
| WPF | ✅ 전체 트리 | ✅ 모든 속성 | ✅ 모든 패턴 | ✅ ¹ | ✅ |
| 윈폼 | ✅ | ✅ | ✅ | ✅ | ✅ |
| Win32 | ✅ | ✅ | ✅ | ✅ | ✅ |
| WinUI 3 | ✅ | ✅ | ✅ | ✅ ¹ | ✅ |
| Electron | ⚠️ 크롬 트리 | ⚠️ 제한됨 | ⚠️ 다양 | ⚠️ 다양 | ✅ |
| Flutter | ⚠️ 기본 | ⚠️ 기본 | ❌ 최소 | ❌ | ✅ |
1 set-value 은 ValuePattern/RangeValuePattern을 노출하는 모든 컨트롤과 접근성이 구현되는 TextPattern 전용 편집 컨트롤(LegacyIAccessible fallback)에서 작동합니다 IAccessible::put_accValue .
WinUI 3 RichEditBox 및 WPF RichTextBox 예외입니다. 읽기 전용 텍스트 패턴(설정 가능한 값 패턴 없음)만 노출하므로 의도적으로 프로그래밍 방식으로 설정할 수 없습니다. 입력하려면 (대화형 데스크톱 필요)를 사용합니다 send-keys .
사용자 고유의 코드에서 엔진 사용
모든 winapp ui 기능은 라이브러리로 사용할 수 있으므로 CLI로 셸 아웃하지 않고 테스트 또는 도구에서 동일한 자동화를 구동할 수 있습니다.
| Package | 추가되는 내용 |
|---|---|
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> .
CLI 작업 결과와 PerformedAction 동일한 의미로 반환 Pattern 됩니다.
검사 또는 선택에서 반환된 요소를 런타임 슬러그 또는 고유한 AutomationId가 그대로 유지된 상태로 전달합니다. 명시적 작업은 이름 및 컨트롤 형식으로 다시 바인딩하는 대신 누락되거나 모호한 ID를 거부합니다.
범위가 지정된 읽기의 경우 다른 UiSelector읽기, ControlType 형식 이름 및 ClassName 리터럴 공급자 클래스로 설정합니다UiSelector.Root. 이들은 CLI와 동일한 쿼리 조건자를 사용합니다. 단 하나의 루트 수준만 지원 selector.Root.Rootnull됩니다. 대상 창을 조회하기 전에 중첩된 루트가 throw됩니다 ArgumentException . 루트 선택기를 중첩하는 대신 고유한 루트 AutomationId 또는 슬러그를 사용합니다.
UiControlTypes.GetId(name) 는 공식 형식 이름과 문서화된 두 별칭을 확인하여 잘못된 이름을 반환합니다 0 .
UiControlTypes.GetName(id) 는 정식 이름 또는 Unknown(id) 인식할 수 없는 ID를 반환합니다.
복원된 UiElement JSON을 전달하거나 GetPropertiesAsyncJSON GetTextAsync 에 전달하는 경우 해당 Selector 및 WindowHandle를 유지합니다. 슬러그 선택기는 여전히 원래 요소를 식별해야 합니다. 더 이상 존재하지 않는 경우 이러한 읽기는 동일한 AutomationId 또는 이름을 가진 다른 요소를 선택하는 대신 throw UiElementNotFoundException 됩니다. 원래 쿼리를 다시 실행하여 결과를 새로 고칩니다. 범위가 지정된 읽기는 null 또는 이전에 캡처한 값을 반환하는 대신 일반 UIA 속성 getter 및 획득된 UIA 패턴의 오류를 전파합니다.
녹음/녹화는 UI만 검사하고 구동하는 프로젝트가 SkiaSharp에서 끌어오지 않도록 별도의 패키지입니다. 자동화 패키지는 둘 다 net10.0-windows 대상으로 하고net10.0-windows10.0.19041.0, 후자는 Windows 그래픽 캡처를 추가합니다. 그러면 캡처가 폐색되거나 GPU 복합 windows 수 있습니다screenshot. 전체 API 및 대상 프레임워크 절충은 NuGet에서 각 패키지의 추가 기능을 참조하세요.
UiTarget.FromWindowHandle는 이미 창을 제공하는 테스트 프레임워크의 진입점입니다. 예를 들어 MSTest.Windows.UIAutomationWindowTest.MainWindow UIA2 AutomationElement 를 사용하여 연결MainWindow.Current.NativeWindowHandle합니다.
Troubleshooting
| 오류 | 원인 | 솔루션 |
|---|---|---|
| "실행 중인 앱을 찾을 수 없음" | 앱이 실행되지 않거나 이름이 일치하지 않습니다. | 프로세스 이름 확인 또는 PID 사용 |
| "여러 창 일치" | 모호한 -a 값 |
나열된 옵션에서 사용 -w <HWND> |
| "여러 창이 있습니다." | 프로세스에 여러 창이 있습니다. | 특정 대상 지정에 사용 -w <HWND> |
| "선택기가 N 요소와 일치" | 모호한 레거시 선택기 | 출력에서 inspect 슬러그를 사용하거나 레거시 선택기에 추가 [0][1] |
| "요소가 변경되었을 수 있습니다." | 슬러그 해시가 현재 요소와 일치하지 않음 | 다시 실행 inspect 하거나 search 신선한 슬러그를 얻을 수 |
| "호출 패턴을 지원하지 않습니다." | 요소를 호출할 수 없습니다. | 요소를 사용하여 inspect 호출 가능한 자식 찾기 |
| "UIA 창을 찾을 수 없습니다." | UIA에서 프로세스를 볼 수 없습니다. |
list-windows HWND를 찾은 다음,-w |
| "창 크기가 0입니다." | 창 최소화 | 앱이 자동으로 복원됩니다. |
| 스크린샷에 없는 팝업/드롭다운 | 기본 캡처는 창당이며 소유되지 않은 오버레이를 포함하지 않습니다. |
스크린샷 오버레이 워크플로에 따라 다음으로 창을 선택합니다.-w <hwnd> --capture-screen |
foreground_not_target에서 --capture-screen |
Windows 활성화를 거부했기 때문에 화면 캡처는 실제로 앞에 있는 모든 창을 기록했을 것입니다. | 대상 창을 클릭하거나 포커스 도용 창을 닫고 다시 시도하거나 삭제합니다. --capture-screen |
element_not_found 레코드 중 |
선택기가 지정되었지만 일치하는 요소가 없음 | 다시 실행 inspect 하거나 search 새 선택기를 가져옵니다. |
| 레코드 중에 WGC를 사용할 수 없음 | WGC 캡처 init가 실패했습니다. 자동 대체 없음 | GPU/드라이버 확인; 화면 DC 캡처에 동의하는 데 사용 --capture-screen |
일반적인 패턴
탐색 및 확인
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의 && 연산자가 중지할 수 있습니다. 대신 각 ; 명령을 무조건 실행하고 이 교착 상태를 방지합니다. 에이전트 워크플로에 더 적합합니다. 일반적으로 호출에 0이 아닌 종료가 있더라도 스크린샷을 실행하려고 합니다.
CI 테스트 패턴
스모크 테스트 및 UI 유효성 검사에 CI 파이프라인(GitHub Actions, Azure DevOps)에서 winapp 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 요소의 값이 예상 문자열과 일치할 때까지 폴링합니다.(TextPattern → ValuePattern → SelectionPattern → Name)과 동일한 스마트 대체 get-value 를 사용합니다. 일치 시 종료 코드 0을 반환하고, 시간 제한 시 코드 1을 종료하여 CI 친화적인 어설션으로 만듭니다. 대신 특정 UIA 속성을 확인하는 데 사용합니다 --property .
# 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
JSON 출력을 사용하여 어설션
더 복잡한 어설션을 위해 PowerShell 또는 jq와 함께 사용합니다 --json .
모드에서
search종료 코드 계약wait-for--json: 일치하는 요소가 없거나 대기 시간 초과(searchwait-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는 이 프로젝션 isOffscreen 에서 UI 자동화 비어 있거나 표시되지 않는 UI 사각형입니다. 별개이므로 오프스크린 요소에는 0이 아닌 범위가 있을 수 있습니다.
각 inspect --jsonwindows[] 항목과 결과에는 status --jsonwindowDpi, scale (windowDpi / 96), dpiAwareness및 coordinateSpace: "physical-screen-pixels". 이러한 내용은 무조건 모니터 DPI가 아닌 대상 창의 DPI 컨텍스트를 설명합니다. Windows 인식할 수 없는 창에 대해 96을 보고하고, 시스템 인식 창의 경우 시스템 DPI를 보고하고, 모니터별 인식 창에 대한 현재 모니터 DPI를 설명합니다. HWND 또는 DPI 컨텍스트를 읽을 수 없는 경우 96을 자동으로 대체하는 대신 명령이 실패합니다.
status 최상위 창이 있기 전에 프로세스를 확인하면 창 hwnd 이 0 존재할 때까지 DPI 필드가 생략됩니다. 프로세스 전체 inspect의 경우 선택한 대상 창은 장애 조치(fail-fast)로 유지됩니다. 트리를 읽 windows[] 은 후 이후 팝업이 사라지면 나머지 창 트리가 여전히 반환되는 동안 해당 항목이 DPI 필드를 전달 dpiError 하고 생략합니다.
각 봉투의 references/ui-json-envelope.md 전체 예제는 배송된 winapp-ui-automation 기술을 참조하세요.
전체 스모크 테스트 예제
# 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