원클릭으로
win-ui-auto
Windows UI automation — inspect elements, click, type, manage windows and apps.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Windows UI automation — inspect elements, click, type, manage windows and apps.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Persistent agent memory via OpenViking — store and retrieve context across sessions using a tiered filesystem database. L0/L1/L2 context layers with semantic search.
Windows Task Scheduler — create, list, manage, and delete scheduled tasks for automated workflows, zero dependencies.
Browser integration — open URLs, read bookmarks and history from Edge/Chrome, get active tabs, list downloads, zero dependencies.
Local AI inference via Ollama — run LLMs on-device, manage models, detect NPU/GPU/DirectML hardware, zero cloud dependencies.
System diagnostics — CPU, RAM, battery, GPU, network, processes, OS info via WMI, zero dependencies.
Read and search Windows Sticky Notes — access your notes via the local SQLite database using built-in winsqlite3.dll, zero dependencies.
| name | win-ui-auto |
| description | Windows UI automation — inspect elements, click, type, manage windows and apps. |
| metadata | {"openclaw":{"emoji":"🖱️","os":["win32"]}} |
Windows UI automation using .NET UI Automation and Win32 APIs. The Windows counterpart to Peekaboo (macOS).
No external dependencies — uses built-in PowerShell, .NET Framework, and Win32 APIs.
| Feature | Peekaboo (macOS) | win-ui-auto (Windows) |
|---|---|---|
| See UI elements | peekaboo see | UI Automation tree walk |
| Click elements | peekaboo click | SetCursorPos + mouse_event |
| Type text | peekaboo type | SendKeys |
| Hotkeys | peekaboo hotkey | SendKeys with modifiers |
| List windows | peekaboo list windows | EnumWindows / UI Automation |
| Focus window | peekaboo window focus | SetForegroundWindow |
| Move/resize | peekaboo window set-bounds | MoveWindow |
| Launch app | peekaboo app launch | Start-Process |
| Screenshot | peekaboo image | win-screenshot skill |
1. List windows → find target window
2. See elements → enumerate UI tree, get element positions
3. Screenshot → capture window (use win-screenshot skill)
4. Analyze image → use OpenClaw image tool to understand layout
5. Click / Type → interact with specific elements
List all visible windows with position and size:
powershell.exe -NoProfile -Command "
Add-Type -AssemblyName UIAutomationClient
Add-Type -AssemblyName UIAutomationTypes
$root = [System.Windows.Automation.AutomationElement]::RootElement
$wc = [System.Windows.Automation.PropertyCondition]::new(
[System.Windows.Automation.AutomationElement]::ControlTypeProperty,
[System.Windows.Automation.ControlType]::Window)
$wins = $root.FindAll([System.Windows.Automation.TreeScope]::Children, $wc)
foreach ($w in $wins) {
$n = $w.Current.Name; $c = $w.Current.ClassName; $r = $w.Current.BoundingRectangle
if ($n.Length -gt 0 -and -not [System.Double]::IsInfinity($r.Width)) {
Write-Host ('{0} | class={1} | {2},{3} {4}x{5}' -f $n,$c,[math]::Round($r.X),[math]::Round($r.Y),[math]::Round($r.Width),[math]::Round($r.Height))
}
}
"
Inspect the UI Automation tree of a specific window. Returns control type, name, automation ID, and bounding rectangle for each element.
powershell.exe -NoProfile -Command "
Add-Type -AssemblyName UIAutomationClient
Add-Type -AssemblyName UIAutomationTypes
$root = [System.Windows.Automation.AutomationElement]::RootElement
$wc = [System.Windows.Automation.PropertyCondition]::new(
[System.Windows.Automation.AutomationElement]::NameProperty, 'WINDOW_TITLE')
$win = $root.FindFirst([System.Windows.Automation.TreeScope]::Children, $wc)
if (-not $win) { Write-Host 'Window not found'; exit 1 }
$all = [System.Windows.Automation.Condition]::TrueCondition
$els = $win.FindAll([System.Windows.Automation.TreeScope]::Descendants, $all)
$i = 0
foreach ($el in $els) {
$ct = $el.Current.ControlType.ProgrammaticName -replace 'ControlType\.',''
$nm = $el.Current.Name
$aid = $el.Current.AutomationId
$r = $el.Current.BoundingRectangle
if (-not [System.Double]::IsInfinity($r.Width) -and $r.Width -gt 0) {
$cx = [math]::Round($r.X + $r.Width/2); $cy = [math]::Round($r.Y + $r.Height/2)
Write-Host ('E{0} {1} | name={2} | id={3} | center={4},{5}' -f $i,$ct,$nm,$aid,$cx,$cy)
}
$i++
if ($i -ge 100) { Write-Host '... (truncated at 100 elements)'; break }
}
"
Replace WINDOW_TITLE with the exact title from the window list. Each element is prefixed with an ID like E0, E1, etc. The center coordinates can be used for clicking.
Show only buttons:
powershell.exe -NoProfile -Command "
Add-Type -AssemblyName UIAutomationClient
Add-Type -AssemblyName UIAutomationTypes
$root = [System.Windows.Automation.AutomationElement]::RootElement
$wc = [System.Windows.Automation.PropertyCondition]::new(
[System.Windows.Automation.AutomationElement]::NameProperty, 'WINDOW_TITLE')
$win = $root.FindFirst([System.Windows.Automation.TreeScope]::Children, $wc)
if (-not $win) { Write-Host 'Window not found'; exit 1 }
$bc = [System.Windows.Automation.PropertyCondition]::new(
[System.Windows.Automation.AutomationElement]::ControlTypeProperty,
[System.Windows.Automation.ControlType]::Button)
$btns = $win.FindAll([System.Windows.Automation.TreeScope]::Descendants, $bc)
foreach ($b in $btns) {
$r = $b.Current.BoundingRectangle
if (-not [System.Double]::IsInfinity($r.Width)) {
$cx = [math]::Round($r.X + $r.Width/2); $cy = [math]::Round($r.Y + $r.Height/2)
Write-Host ('Button: {0} | id={1} | center={2},{3}' -f $b.Current.Name,$b.Current.AutomationId,$cx,$cy)
}
}
"
Other control types: Edit, Text, CheckBox, RadioButton, ComboBox, List, ListItem, Menu, MenuItem, Tab, TabItem, Tree, TreeItem, Hyperlink, Image, Slider, ProgressBar.
Click at specific screen coordinates:
powershell.exe -NoProfile -Command "
Add-Type @'
using System;
using System.Runtime.InteropServices;
public class Mouse {
[DllImport(\"user32.dll\")] public static extern bool SetCursorPos(int X, int Y);
[DllImport(\"user32.dll\")] public static extern void mouse_event(uint f, int dx, int dy, int d, IntPtr e);
public const uint DOWN = 0x02, UP = 0x04;
public static void Click(int x, int y) {
SetCursorPos(x, y);
System.Threading.Thread.Sleep(50);
mouse_event(DOWN, 0, 0, 0, IntPtr.Zero);
mouse_event(UP, 0, 0, 0, IntPtr.Zero);
}
}
'@
[Mouse]::Click(X, Y)
Write-Host 'Clicked at X,Y'
"
Replace X and Y with target coordinates (e.g., from the center output of the See command).
powershell.exe -NoProfile -Command "
Add-Type @'
using System;
using System.Runtime.InteropServices;
public class Mouse {
[DllImport(\"user32.dll\")] public static extern bool SetCursorPos(int X, int Y);
[DllImport(\"user32.dll\")] public static extern void mouse_event(uint f, int dx, int dy, int d, IntPtr e);
public const uint DOWN = 0x02, UP = 0x04;
public static void DoubleClick(int x, int y) {
SetCursorPos(x, y);
System.Threading.Thread.Sleep(50);
mouse_event(DOWN, 0, 0, 0, IntPtr.Zero); mouse_event(UP, 0, 0, 0, IntPtr.Zero);
System.Threading.Thread.Sleep(80);
mouse_event(DOWN, 0, 0, 0, IntPtr.Zero); mouse_event(UP, 0, 0, 0, IntPtr.Zero);
}
}
'@
[Mouse]::DoubleClick(X, Y)
Write-Host 'Double-clicked at X,Y'
"
powershell.exe -NoProfile -Command "
Add-Type @'
using System;
using System.Runtime.InteropServices;
public class Mouse {
[DllImport(\"user32.dll\")] public static extern bool SetCursorPos(int X, int Y);
[DllImport(\"user32.dll\")] public static extern void mouse_event(uint f, int dx, int dy, int d, IntPtr e);
public const uint RDOWN = 0x08, RUP = 0x10;
public static void RightClick(int x, int y) {
SetCursorPos(x, y);
System.Threading.Thread.Sleep(50);
mouse_event(RDOWN, 0, 0, 0, IntPtr.Zero);
mouse_event(RUP, 0, 0, 0, IntPtr.Zero);
}
}
'@
[Mouse]::RightClick(X, Y)
Write-Host 'Right-clicked at X,Y'
"
Send keystrokes to the focused window:
powershell.exe -NoProfile -Command "
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.SendKeys]::SendWait('YOUR_TEXT_HERE')
"
Special characters in SendKeys:
{ENTER} — Enter key{TAB} — Tab key{BACKSPACE} or {BS} — Backspace{DELETE} or {DEL} — Delete{ESCAPE} or {ESC} — Escape{UP}, {DOWN}, {LEFT}, {RIGHT} — Arrow keys{HOME}, {END}, {PGUP}, {PGDN} — Navigation{F1} through {F12} — Function keys+ — Shift, ^ — Ctrl, % — Alt (modifiers)powershell.exe -NoProfile -Command "
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.SendKeys]::SendWait('Line 1{ENTER}Line 2{ENTER}Line 3')
"
Send keyboard shortcuts:
# Ctrl+S (Save)
powershell.exe -NoProfile -Command "
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.SendKeys]::SendWait('^s')
"
# Ctrl+C (Copy)
powershell.exe -NoProfile -Command "
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.SendKeys]::SendWait('^c')
"
# Ctrl+V (Paste)
powershell.exe -NoProfile -Command "
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.SendKeys]::SendWait('^v')
"
# Alt+F4 (Close)
powershell.exe -NoProfile -Command "
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.SendKeys]::SendWait('%{F4}')
"
# Ctrl+Shift+T (Reopen tab)
powershell.exe -NoProfile -Command "
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.SendKeys]::SendWait('^+t')
"
# Win+D (Show desktop)
powershell.exe -NoProfile -Command "
\$shell = New-Object -ComObject Shell.Application
\$shell.ToggleDesktop()
"
Bring a window to the foreground by title:
powershell.exe -NoProfile -Command "
Add-Type @'
using System;
using System.Runtime.InteropServices;
public class WinFocus {
[DllImport(\"user32.dll\")] public static extern IntPtr FindWindow(string cls, string title);
[DllImport(\"user32.dll\")] public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport(\"user32.dll\")] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
'@
$h = [WinFocus]::FindWindow($null, 'WINDOW_TITLE')
if ($h -eq [IntPtr]::Zero) { Write-Host 'Window not found'; exit 1 }
[WinFocus]::ShowWindow($h, 9) # SW_RESTORE
[WinFocus]::SetForegroundWindow($h)
Write-Host 'Focused: WINDOW_TITLE'
"
powershell.exe -NoProfile -Command "
Add-Type @'
using System;
using System.Runtime.InteropServices;
public class WinMove {
[DllImport(\"user32.dll\")] public static extern IntPtr FindWindow(string cls, string title);
[DllImport(\"user32.dll\")] public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int W, int H, bool repaint);
}
'@
$h = [WinMove]::FindWindow($null, 'WINDOW_TITLE')
if ($h -eq [IntPtr]::Zero) { Write-Host 'Window not found'; exit 1 }
[WinMove]::MoveWindow($h, X, Y, WIDTH, HEIGHT, $true)
Write-Host 'Moved window to X,Y WIDTHxHEIGHT'
"
powershell.exe -NoProfile -Command "
Add-Type @'
using System;
using System.Runtime.InteropServices;
public class WinCtl {
[DllImport(\"user32.dll\")] public static extern IntPtr FindWindow(string cls, string title);
[DllImport(\"user32.dll\")] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport(\"user32.dll\")] public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
}
'@
$h = [WinCtl]::FindWindow($null, 'WINDOW_TITLE')
if ($h -eq [IntPtr]::Zero) { Write-Host 'Window not found'; exit 1 }
# Minimize: ShowWindow($h, 6)
# Maximize: ShowWindow($h, 3)
# Restore: ShowWindow($h, 9)
# Close: PostMessage($h, 0x0010, [IntPtr]::Zero, [IntPtr]::Zero)
[WinCtl]::ShowWindow($h, ACTION)
Write-Host 'Done'
"
Action codes: 6 = minimize, 3 = maximize, 9 = restore. For close, use PostMessage with 0x0010 (WM_CLOSE).
# By name
powershell.exe -NoProfile -Command "Start-Process 'notepad'"
# By path
powershell.exe -NoProfile -Command "Start-Process 'C:\Program Files\MyApp\app.exe'"
# With arguments
powershell.exe -NoProfile -Command "Start-Process 'code' -ArgumentList 'C:\projects\myrepo'"
# Open URL in default browser
powershell.exe -NoProfile -Command "Start-Process 'https://example.com'"
# Open file with default app
powershell.exe -NoProfile -Command "Start-Process 'C:\Users\me\doc.pdf'"
powershell.exe -NoProfile -Command "
Get-Process | Where-Object { \$_.MainWindowTitle.Length -gt 0 } |
Select-Object Id, ProcessName, MainWindowTitle | Format-Table -AutoSize
"
# Graceful close by process name
powershell.exe -NoProfile -Command "
Get-Process -Name 'notepad' -ErrorAction SilentlyContinue | ForEach-Object { $_.CloseMainWindow() }
"
# Force kill
powershell.exe -NoProfile -Command "Stop-Process -Name 'notepad' -Force"
powershell.exe -NoProfile -Command "
Add-Type @'
using System;
using System.Runtime.InteropServices;
public class Scroll {
[DllImport(\"user32.dll\")] public static extern void mouse_event(uint f, int dx, int dy, int d, IntPtr e);
public const uint WHEEL = 0x0800;
public static void Up(int clicks) { mouse_event(WHEEL, 0, 0, clicks * 120, IntPtr.Zero); }
public static void Down(int clicks) { mouse_event(WHEEL, 0, 0, -clicks * 120, IntPtr.Zero); }
}
'@
# Scroll down 3 clicks
[Scroll]::Down(3)
"
# 1. List windows
→ Found: "Notepad - myfile.txt" at 100,100 800x600
# 2. Focus window
→ SetForegroundWindow("Notepad - myfile.txt")
# 3. See elements
→ E5 Edit | name= | id=15 | center=500,400
→ E8 MenuItem | name=File | id= | center=120,125
# 4. Click on Edit area
→ Click(500, 400)
# 5. Type text
→ SendKeys("Hello from PCClaw!")
# 6. Save with Ctrl+S
→ SendKeys("^s")
# 7. Screenshot to verify
→ (use win-screenshot skill)
SendKeys requires the target window to be focused. Always focus first, then type.SetCursorPos + mouse_event uses absolute screen coordinates.image tool → click/type.win-screenshot for visual verification and win-clipboard for data transfer.center coordinates from the See command as click targets.