On Linux/evdev, a correction grabs the keyboard for its duration (the key gate, 0.6.0): your next keystrokes are held and replayed behind the correction, so typing straight through no longer scrambles the result. Windows has no equivalent — the low-level hook observes but never swallows, so a keystroke landing mid-correction can still interleave. Fast typists hit this as an occasionally-mangled word right after a correction.
The raw mechanism exists: a WH_KEYBOARD_LL hook that returns non-zero swallows the event. The hard part is doing that safely:
- Never wedge the keyboard. The gate must be bounded by a hard timeout and released on every exit path — a stuck gate here means the user's keyboard stops working system-wide. This is the reason the feature didn't ship with a naive implementation.
- Windows silently removes low-level hooks that exceed the callback deadline; the hold-and-replay bookkeeping has to stay off the hook thread (the existing enqueue-to-worker pattern).
- Injected events (our own emitter uses
SendInput with a marker in dwExtraInfo) must pass through the gate, or the correction blocks itself — same self-deadlock the evdev gate had to solve (it stands down behind input remappers for exactly this reason).
- Replayed keys lose nothing for plain characters, but a chord pressed mid-correction may not be reproducible — on Linux we accept that one narrow loss and document it. Same call needed here.
Where to look: crates/poltertype-input/src/ — the evdev KeyGate is the reference implementation; the Windows listener/emitter live alongside it. docs/PERMISSIONS.md documents the user-facing behaviour contract.
On Linux/evdev, a correction grabs the keyboard for its duration (the key gate, 0.6.0): your next keystrokes are held and replayed behind the correction, so typing straight through no longer scrambles the result. Windows has no equivalent — the low-level hook observes but never swallows, so a keystroke landing mid-correction can still interleave. Fast typists hit this as an occasionally-mangled word right after a correction.
The raw mechanism exists: a
WH_KEYBOARD_LLhook that returns non-zero swallows the event. The hard part is doing that safely:SendInputwith a marker indwExtraInfo) must pass through the gate, or the correction blocks itself — same self-deadlock the evdev gate had to solve (it stands down behind input remappers for exactly this reason).Where to look:
crates/poltertype-input/src/— the evdevKeyGateis the reference implementation; the Windows listener/emitter live alongside it.docs/PERMISSIONS.mddocuments the user-facing behaviour contract.