waybetter/dev-tools/window-resize.ps1
CRT 5c64f2f6f8 dev-tools: the generic development harnesses (perf probes, close check, tab and webview stress)
Moved from wayBetter for X; an app passes its own origin, process name, scripts and fixtures.
2026-09-30 14:48:06 +07:00

48 lines
3.1 KiB
PowerShell

# Resizes a wayBetter app's window (never activated, never while it is the foreground window) for
# ~2 s, then puts it back: a repeatable window-resize workload for resize-perf.mjs `window`.
# powershell -ExecutionPolicy Bypass -File dev-tools/window-resize.ps1 -Process <process name or pattern> [-Ms 2000] [-Amplitude 200]
param([Parameter(Mandatory = $true)][string]$Process, [int]$Ms = 2000, [int]$Amplitude = 200)
Add-Type @"
using System; using System.Runtime.InteropServices;
public static class WinResize {
[StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; }
[DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r);
[DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr h, IntPtr after, int x, int y, int cx, int cy, uint flags);
[DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")] public static extern bool IsZoomed(IntPtr h);
[DllImport("user32.dll")] public static extern bool IsIconic(IntPtr h);
public delegate bool EnumProc(IntPtr h, IntPtr l);
[DllImport("user32.dll")] public static extern bool EnumWindows(EnumProc p, IntPtr l);
[DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint p);
[DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int GetClassName(IntPtr h, System.Text.StringBuilder s, int n);
// The app window itself: MainWindowHandle may be the single-instance or event-loop helper window.
public static IntPtr AppWindow(uint pid) {
IntPtr found = IntPtr.Zero;
EnumWindows((h, l) => { uint p; GetWindowThreadProcessId(h, out p); var c = new System.Text.StringBuilder(64); GetClassName(h, c, 64);
if (p == pid && c.ToString() == "Tauri Window") { found = h; return false; } return true; }, IntPtr.Zero);
return found;
}
}
"@
$proc = Get-Process $Process -ErrorAction Stop | Select-Object -First 1
$hwnd = [WinResize]::AppWindow([uint32]$proc.Id)
if ($hwnd -eq [IntPtr]::Zero) { 'skipped: no app window'; exit 2 }
if ([WinResize]::IsIconic($hwnd)) { 'skipped: minimized'; exit 2 }
if ([WinResize]::GetForegroundWindow() -eq $hwnd) { 'skipped: the app is the foreground window'; exit 2 }
if ([WinResize]::IsZoomed($hwnd)) { 'skipped: maximized'; exit 2 }
$r = New-Object WinResize+RECT
[void][WinResize]::GetWindowRect($hwnd, [ref]$r)
$w = $r.Right - $r.Left; $h = $r.Bottom - $r.Top
# SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER
$flags = 0x0002 -bor 0x0004 -bor 0x0010 -bor 0x0200
$sw = [Diagnostics.Stopwatch]::StartNew()
$steps = 0
while ($sw.ElapsedMilliseconds -lt $Ms) {
$phase = $sw.ElapsedMilliseconds / $Ms
$dw = [int]($Amplitude * [Math]::Sin($phase * [Math]::PI * 2))
[void][WinResize]::SetWindowPos($hwnd, [IntPtr]::Zero, 0, 0, $w - [Math]::Abs($dw), $h - [int]([Math]::Abs($dw) / 2), $flags)
$steps++
Start-Sleep -Milliseconds 8
}
[void][WinResize]::SetWindowPos($hwnd, [IntPtr]::Zero, 0, 0, $w, $h, $flags)
"resized $steps times, restored ${w}x${h} at $([DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds())"