Added
FilterSyntheticKeys(opt-in, off by default). Since 3.3.1 the filter passes every injected keystroke through untouched, which is right on a desktop but leaves a remote-desktop host with nothing to filter: RDP, RustDesk, and VNC deliver the client keyboard's events as synthetic input, so the client's stutter lands in the session unfiltered and a copy running on the remote machine cannot help. Setting"FilterSyntheticKeys": trueon that machine turns the pass-through off so the injected stream is debounced like hardware. Filtering on the machine the keyboard is attached to remains the reliable answer: over a remote session the timing has crossed a network, and this also debounces remappers, text expanders, and Grammarly on the same machine. Key-ups the app re-injects itself are always passed through regardless. Raised by a tester using RustDesk.
Fixed
- Logging no longer runs on the hook threads. With
"LogLevel": "Trace", every filtered key and click was written with a synchronousFile.AppendAllText, an open + write + close that antivirus inspects, from inside the low-level hook callback (and, inBlockReleasemode, while holding the lock the release timers also take). Windows blocks the session's raw input thread until a hook callback returns, up toLowLevelHooksTimeout(300ms by default), and that same thread services the rest of the session's input work including HID device attach, so a slow disk could turn a log line into input lag felt well outside this app. All log lines now go through a single background writer (FilterLog) that the hook threads hand off to without touching the disk: the worst observed cost on the caller went from 0.535ms to 0.017ms, with no dependence on disk state at all. Lines are batched one append per drain, the log file is not held open (soKeyboardHeatmap.execan still read it while the app runs), and if the queue ever overflows the dropped count is reported in the log rather than leaving a silent gap. The on-disk log format is unchanged.
See CHANGELOG.md for details.