feat: 新增本地UI模型AI拾取与识别实验台

This commit is contained in:
yu committed 2026-11-02 11:55:36 +08:00
1 parent ee60435e2b
commit e956ec9055
27 files changed
+1848 -525

No files matched your search

+65 -15
View File
@@ -150,10 +150,15 @@ function Set-ClickThrough($form) {
}
function Set-HighlightBox([int]$x, [int]$y, [int]$w, [int]$h) {
$hl.Location = New-Object System.Drawing.Point(($x - 2), ($y - 2))
$hl.Size = New-Object System.Drawing.Size(($w + 4), ($h + 4))
$hl.Show()
Set-ClickThrough $hl
$bounds = New-Object System.Drawing.Rectangle(($x - 2), ($y - 2), ($w + 4), ($h + 4))
if (-not $hl.Visible) {
$hl.Bounds = $bounds
$hl.Show()
Set-ClickThrough $hl
} elseif ($hl.Bounds.X -ne $bounds.X -or $hl.Bounds.Y -ne $bounds.Y -or $hl.Bounds.Width -ne $bounds.Width -or $hl.Bounds.Height -ne $bounds.Height) {
# 不重设隐藏;同一元素内移动时不重复改窗口,避免 WinForms 分层窗体重绘闪烁
$hl.Bounds = $bounds
}
}
function Hide-Highlight { $hl.Hide() }
function Get-DeepestAtPoint([double]$px, [double]$py) {
@@ -187,6 +192,19 @@ $prevSpace = $false
$prevPgUp = $false
$prevPgDn = $false
$prevF2 = $false
$cacheX = [int]::MinValue
$cacheY = [int]::MinValue
$cacheEl = $null
$cacheCtrlName = ""
$cacheName = ""
$cachePaneX = 0
$cachePaneY = 0
$cachePaneW = 0
$cachePaneH = 0
$cacheAt = [DateTime]::MinValue
$lastQueryAt = [DateTime]::MinValue
$queryGapMs = 45
$cacheTtlMs = 1800
Write-PickLog "loop start"
while ($true) {
try {
@@ -199,17 +217,49 @@ while ($true) {
if ($stage -eq "hover") {
$ptX = [System.Windows.Forms.Cursor]::Position.X
$ptY = [System.Windows.Forms.Cursor]::Position.Y
$el = Get-DeepestAtPoint $ptX $ptY
$now = [DateTime]::UtcNow
$samePoint = ($ptX -eq $cacheX -and $ptY -eq $cacheY)
$insideCache = $cacheEl -ne $null -and $ptX -ge $cachePaneX -and $ptX -lt ($cachePaneX + $cachePaneW) -and $ptY -ge $cachePaneY -and $ptY -lt ($cachePaneY + $cachePaneH)
$cacheAlive = ($null -ne $cacheEl -and ($now - $cacheAt).TotalMilliseconds -le $cacheTtlMs)
# 鼠标还在当前元素矩形内部时不丢弃缓存;UIA 查询完成后才切换,避免移动过程先隐藏再显示
if (-not $samePoint -and -not $insideCache) { $cacheEl = $null }
if (-not $cacheAlive -and ($now - $lastQueryAt).TotalMilliseconds -ge $queryGapMs) {
$queryX = $ptX
$queryY = $ptY
$lastQueryAt = [DateTime]::UtcNow
try { $queried = Get-DeepestAtPoint $queryX $queryY } catch { $queried = $null; Write-PickLog ("QUERY ERR: " + $_.Exception.Message) }
$afterX = [System.Windows.Forms.Cursor]::Position.X
$afterY = [System.Windows.Forms.Cursor]::Position.Y
if ($afterX -ne $queryX -or $afterY -ne $queryY) {
$queried = $null
Write-PickLog "query stale: cursor moved"
}
if ($null -ne $queried) {
$qc = $queried.Current
$qr = $qc.BoundingRectangle
$cacheEl = $queried
$cacheX = $queryX
$cacheY = $queryY
$cacheAt = [DateTime]::UtcNow
$cacheCtrlName = $qc.ControlType.ProgrammaticName.Replace("ControlType.", "")
$cacheName = [string]$qc.Name
$cachePaneX = [int]$qr.X
$cachePaneY = [int]$qr.Y
$cachePaneW = [int]$qr.Width
$cachePaneH = [int]$qr.Height
} else {
$cacheEl = $null
$cacheCtrlName = ""
$cacheName = ""
}
}
$el = $cacheEl
if ($el) {
$c = $el.Current
$ctrlName = $c.ControlType.ProgrammaticName.Replace("ControlType.", "")
$r = $c.BoundingRectangle
$paneX = [int]$r.X; $paneY = [int]$r.Y; $paneW = [int]$r.Width; $paneH = [int]$r.Height
Set-HighlightBox $paneX $paneY $paneW $paneH
$aiHint = if ($ctrlName -eq "Pane") { " [F2]AI识别" } else { "" }
$infoLabel.Text = "名称: " + $c.Name + " 类型: " + $ctrlName + " [空格]锁定" + $aiHint + " [Esc]取消"
Set-HighlightBox $cachePaneX $cachePaneY $cachePaneW $cachePaneH
$aiHint = if ($cacheCtrlName -eq "Pane") { " [F2]AI识别" } else { "" }
$infoLabel.Text = "名称: " + $cacheName + " 类型: " + $cacheCtrlName + " [空格]锁定" + $aiHint + " [Esc]取消"
} else { Hide-Highlight }
if ($f2 -and -not $prevF2 -and $el -and $ctrlName -eq "Pane") {
if ($f2 -and -not $prevF2 -and $el -and $cacheCtrlName -eq "Pane") {
Write-PickLog "f2 ai"
$walker = [System.Windows.Automation.TreeWalker]::ControlViewWalker
$cur = $el
@@ -218,7 +268,7 @@ while ($true) {
$topTitle = [string]$cur.Current.Name
$cur = $walker.GetParent($cur)
}
$result = @{ aiRequested = $true; cursorX = $ptX; cursorY = $ptY; window = $topTitle; name = [string]$c.Name; controlType = $ctrlName; paneX = $paneX; paneY = $paneY; paneW = $paneW; paneH = $paneH }
$result = @{ aiRequested = $true; cursorX = $ptX; cursorY = $ptY; window = $topTitle; name = $cacheName; controlType = $cacheCtrlName; paneX = $cachePaneX; paneY = $cachePaneY; paneW = $cachePaneW; paneH = $cachePaneH }
break
}
if ($space -and -not $prevSpace -and $el) {
@@ -226,7 +276,7 @@ while ($true) {
$stage = "locked"
$chain = New-Object System.Collections.ArrayList
$walker = [System.Windows.Automation.TreeWalker]::ControlViewWalker
$cur = $el
$cur = $cacheEl
while ($cur -and -not $cur.Equals([System.Windows.Automation.AutomationElement]::RootElement)) {
$c = $cur.Current
$r = $c.BoundingRectangle
Binary file not shown.
@@ -0,0 +1,12 @@
{
"do_normalize": false,
"do_rescale": true,
"do_resize": true,
"feature_extractor_type": "ImageFeatureExtractor",
"resample": 2,
"rescale_factor": 0.00392156862745098,
"size_divisor": 16,
"size": {
"longest_edge": 640
}
}