Skip to content

Fix/kbd occlusion hardening - #40

Merged
kryptocodes merged 11 commits into
mainfrom
fix/kbd-occlusion-hardening
Aug 20, 2026
Merged

kryptocodes merged 11 commits into
mainfrom
fix/kbd-occlusion-hardening

Conversation

@kryptocodes

Copy link
Copy Markdown
Contributor

Summary

Mobile keyboard/input hardening in images/minimal-vnc-desktop, plus health reporting for the embed chain (customer page → portal → liveview).

Keyboard/geometry

  • Occlusion pan and scroll-bottom tracking reach fields behind the keyboard, and survive
    rotation, letterbox and long-press (kbd/fit.js, kbd/tap.js, kbd/viewport-transform.js).
  • A host may only suppress the viewer's own detectors after reporting a real occlusion; an
    embedded fallback measurer that sees no occlusion stays silent. Misconfigured embedders now
    get no help instead of no lift.
  • Legacy {type:'parent-viewport'} is translated to POPCORN_HOST_GEOMETRY, so the deployed
    portal works unmodified. Opt out: attach(frame, { legacyGeometry: false }).

Embed contract

  • PopcornHost.layer() now relayouts a fresh iframe. The liveness guard tripped on the blank
    contentDocument every parsed iframe owns, so the documented recipe was refused.
  • auditLayout() + .on('layout'|'scale'|'health') report structural codes
    (host-geometry-blind/-stale/-disagrees, focus-stolen, no-virtual-keyboard,
    remote-unconfirmed) up the bridge and into the pod-side log.
  • host/test-host.html: ?badlayout=1, &nest=1, ?legacybridge=1, &legacyxlate=0
    reproduce each failure.

Desktop / proxy

  • Copy/paste and select-all work with no focused field.
  • CDP race from the emulation queue's drain limit fixed; drain enabled (proxy/emulate.go).
  • GET /kbdstate HTTP fallback while the /kbd socket connects.
  • Startup/viewport recovery hardened on a slow gateway; scroll cadence and motion quality now
    come from measured RTT, replacing ?motionq=1.

Opt-in

  • ?fbscale=auto|1|2|3 supersampled framebuffer, default 1 = off (costs k² pixels/frame).
  • ?e2e=1 input→paint traces (needs diag=1), capped at 8 per load.
  • README covers the layout contract, health codes, fbscale cost, diag params.

Test count went 0 → 413 plus a real-browser contract check, so most of +7.4k lines is tests
and README.

Validation

node --test kbd/test/*.test.mjs     # 413 pass, 0 fail
cd proxy && go test ./...           # ok

Risk and Rollback

  • New behaviour is off by default: fbscale=1, e2e/diag opt-in.
  • Behaviour change: geometry suppression is conditional, so an embedder reporting
    occludedBottom: 0 will now see the viewer's detectors run.
  • Legacy geometry translation defaults on to keep the deployed portal working.
  • /kbdstate is read-only, behind the same readiness gate as /kbd, structural state only.
  • Rollback: revert the merge or rebuild from main. No schema or cross-service changes.

Checklist

  • I kept the change focused.
  • I updated tests or documentation when needed.
  • I did not include secrets, credentials, private infrastructure details, or production configuration.
  • I noted any license, security, or privacy considerations.

@kryptocodes
kryptocodes merged commit ebe8ca8 into main Aug 20, 2026
11 checks passed
@kryptocodes
kryptocodes deleted the fix/kbd-occlusion-hardening branch August 21, 2026 22:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant