Files
claude-code/src/utils/computerUse/win32/windowEnum.ts
T
unraid 3707c3c0ba feat: Windows Computer Use enhancement — PrintWindow, UI Automation, OCR
New Windows-native capabilities:
- windowCapture.ts: PrintWindow API for per-window screenshot (works on
  occluded/background windows)
- windowEnum.ts: EnumWindows for precise window enumeration with HWND
- uiAutomation.ts: IUIAutomation for UI tree reading, element clicking,
  text input, and coordinate-based element identification
- ocr.ts: Windows.Media.Ocr for screen text recognition (en-US + zh-CN)

Updated win32.ts backend to use EnumWindows for listRunning() and added
captureWindowTarget() for window-specific screenshots.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:00:02 +08:00

87 lines
2.7 KiB
TypeScript

/**
* Window enumeration using Win32 EnumWindows API.
* Returns visible windows with their HWND, PID, and title.
*/
export interface WindowInfo {
hwnd: number
pid: number
title: string
}
const ENUM_WINDOWS_PS = `
Add-Type @'
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
public class WinEnum {
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll")]
public static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll", CharSet=CharSet.Unicode)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")]
public static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
public static List<string> results = new List<string>();
public static void Run() {
results.Clear();
EnumWindows(delegate(IntPtr hWnd, IntPtr lParam) {
if (!IsWindowVisible(hWnd)) return true;
int len = GetWindowTextLength(hWnd);
if (len == 0) return true;
StringBuilder sb = new StringBuilder(len + 1);
GetWindowText(hWnd, sb, sb.Capacity);
string title = sb.ToString();
if (string.IsNullOrWhiteSpace(title)) return true;
uint pid = 0;
GetWindowThreadProcessId(hWnd, out pid);
results.Add(hWnd.ToInt64() + "|" + pid + "|" + title);
return true;
}, IntPtr.Zero);
}
}
'@
[WinEnum]::Run()
[WinEnum]::results | ForEach-Object { $_ }
`
/**
* List all visible windows with non-empty titles.
* Returns HWND, PID, and window title for each.
*/
export function listWindows(): WindowInfo[] {
const result = Bun.spawnSync({
cmd: ['powershell', '-NoProfile', '-NonInteractive', '-Command', ENUM_WINDOWS_PS],
stdout: 'pipe',
stderr: 'pipe',
})
const raw = new TextDecoder().decode(result.stdout).trim()
if (!raw) return []
return raw
.split('\n')
.filter(Boolean)
.map(line => {
const trimmed = line.trim()
const firstPipe = trimmed.indexOf('|')
const secondPipe = trimmed.indexOf('|', firstPipe + 1)
if (firstPipe === -1 || secondPipe === -1) return null
const hwnd = Number(trimmed.slice(0, firstPipe))
const pid = Number(trimmed.slice(firstPipe + 1, secondPipe))
const title = trimmed.slice(secondPipe + 1)
if (isNaN(hwnd) || isNaN(pid) || !title) return null
return { hwnd, pid, title }
})
.filter((item): item is WindowInfo => item !== null)
}