summaryrefslogtreecommitdiff
path: root/scripts/windows_input/Probe.ps1
diff options
context:
space:
mode:
authorakbash <akbash@herdr.dev>2026-09-18 02:13:13 +0300
committerGitHub <noreply@github.com>2026-09-18 01:13:13 +0200
commitb88e8116e9e1f7e2f6e8b211536311cd17feca9a (patch)
tree699535f31233ae1aee63a110bdbf2e989ba0878b /scripts/windows_input/Probe.ps1
parent14351f121f6fc8c84b7c6c6eda78ad210e93cfcb (diff)
test: add local windows input gauntlet (#4298)
* test: add local windows input gauntlet refs #4251 * test: add local windows input gauntlet Harden elevation and channel identity checks, distinguish known host limitations, and surface incomplete cleanup. refs #4251 * test(windows): harden input gauntlet execution refs #4251 * test(windows): make input gauntlet self-contained refs #4251 * test(windows): bound input gauntlet failure paths refs #4251 * test(windows): extend input qualification gauntlet refs #4251 * test(windows): complete input qualification matrix refs #4251 --------- Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> Co-authored-by: Jonathan Liebig <jonathan.liebig@gmail.com>
Diffstat (limited to 'scripts/windows_input/Probe.ps1')
-rw-r--r--scripts/windows_input/Probe.ps170
1 files changed, 70 insertions, 0 deletions
diff --git a/scripts/windows_input/Probe.ps1 b/scripts/windows_input/Probe.ps1
new file mode 100644
index 00000000..ad3a9c2b
--- /dev/null
+++ b/scripts/windows_input/Probe.ps1
@@ -0,0 +1,70 @@
+#Requires -Version 7.0
+param([Parameter(Mandatory)][string] $PlanPath)
+. "$PSScriptRoot/Common.ps1"
+$plan = Read-GauntletJson $PlanPath
+Add-Type -Path "$PSScriptRoot/Native.cs"
+$probe = $null
+try {
+ $probe = [HerdrInputGauntlet.ConsoleProbe]::new($plan.mode)
+ [HerdrInputGauntlet.ConsoleProbe]::Print("`r`nHerdr input gauntlet observer $($plan.nonce)`r`n")
+ if ($plan.mode -eq 'kitty') {
+ $deadline = [DateTime]::UtcNow.AddSeconds(2)
+ while (-not $probe.Hex().Contains('1b5b3f3175') -and [DateTime]::UtcNow -lt $deadline) { Start-Sleep -Milliseconds 50 }
+ }
+ Write-GauntletJson (Join-Path $plan.work 'ready.json') @{
+ nonce = $plan.nonce; pid = $PID; mode = $plan.mode; geometry = [HerdrInputGauntlet.ConsoleProbe]::Geometry()
+ negotiation_hex = $probe.Hex(); kitty_acknowledged = $probe.Hex().Contains('1b5b3f3175')
+ }
+ # Negotiation replies are setup evidence, not input for the first case.
+ $probe.Clear()
+ $closedCount = 0
+ $last = ''
+ while ((Test-GauntletLease $plan.root) -and -not (Test-Path (Join-Path $plan.work 'probe-stop'))) {
+ $request = Read-GauntletJson (Join-Path $plan.work 'request.json')
+ if ($null -ne $request -and $request.id -ne $last) {
+ if ($request.nonce -ne $plan.nonce) { throw 'Unexpected observer nonce' }
+ $last = $request.id
+ $quietReached = $false
+ if ($request.action -eq 'mouse-on') {
+ [HerdrInputGauntlet.ConsoleProbe]::Print("`e[?1003h`e[?1006h")
+ Start-Sleep -Milliseconds 200
+ }
+ if ($request.action -eq 'mouse-off') {
+ [HerdrInputGauntlet.ConsoleProbe]::Print("`e[?1003l`e[?1006l")
+ Start-Sleep -Milliseconds 100
+ }
+ if ($request.action -eq 'set-mode') {
+ $probe.SetKeyboardMode([string]$request.value)
+ Start-Sleep -Milliseconds 200
+ }
+ if ($request.action -eq 'begin' -and -not $probe.ClearIfCount($closedCount)) { throw 'Unexpected input arrived between captures' }
+ if ($request.action -eq 'end') {
+ # Capture trailing duplicates/releases as well as the first expected bytes.
+ $deadline = [DateTime]::UtcNow.AddSeconds(3)
+ $quiet = [DateTime]::UtcNow
+ $count = $probe.Count()
+ do {
+ Start-Sleep -Milliseconds 50
+ $newCount = $probe.Count()
+ if ($newCount -ne $count) { $quiet = [DateTime]::UtcNow; $count = $newCount }
+ } while (([DateTime]::UtcNow - $quiet).TotalMilliseconds -lt 350 -and [DateTime]::UtcNow -lt $deadline)
+ $quietReached = ([DateTime]::UtcNow - $quiet).TotalMilliseconds -ge 350
+ $closedCount = $probe.Count()
+ }
+ Write-GauntletJson (Join-Path $plan.work 'reply.json') @{
+ id = $request.id; nonce = $plan.nonce; action = $request.action
+ hex = $probe.Hex(); records = @($probe.Records()); error = $probe.Error; quiet_reached = $quietReached
+ geometry = [HerdrInputGauntlet.ConsoleProbe]::Geometry()
+ }
+ }
+ Start-Sleep -Milliseconds 25
+ }
+} catch {
+ Write-GauntletJson (Join-Path $plan.work 'probe-error.json') @{ error = $_.ToString(); nonce = $plan.nonce }
+ throw
+} finally {
+ if ($null -ne $probe) {
+ $probe.Dispose()
+ Write-GauntletJson (Join-Path $plan.work 'probe-exit.json') @{ nonce = $plan.nonce; cleanup_errors = @($probe.CleanupErrors) }
+ }
+}