Why Controllers Feel Laggy as Keyboards
Press the spacebar on a real keyboard and the key-down event is delivered to the focused app the moment the key crosses the actuation point. The OS doesn't wait to see if you might be starting a keyboard shortcut. There's nothing to wait for — chords on a keyboard are simultaneous presses, identified by which keys are currently held.
Controllers are different. A "chord" on a controller is "press these two buttons within a short window of each other." If you press A, the mapper has to wait briefly to see if B is about to follow — because A alone and A+B can be bound to different actions. Most mappers use a window of 30–80 milliseconds. That window is invisible during productivity use, but very visible during fast-twitch input — and very visible during latency benchmarks.
The Anatomy of Controller-Through-Mapper Latency
| Stage | Approx. cost | Affected by |
|---|---|---|
| Controller hardware → OS HID | 1–8 ms | Controller polling rate, USB vs Bluetooth |
| OS HID → mapper | < 1 ms | macOS run loop scheduling |
| Chord-detection window | 30–80 ms | Mapper config — this is the big one |
| Mapper → CGEvent post | < 1 ms | Mapper code path |
| CGEvent → focused app | 1–4 ms | macOS event tap chain |
If you're chasing real latency improvements, the chord-detection window is where 80% of the savings live. The other stages add up to single-digit milliseconds and there's not much a user-space app can do about them.
What Realtime Input Mode Does
ControllerKeys 1.8.2 introduced realtime input mode as a per-profile setting. When it's on:
- Simple key mappings (one button → one keyboard key, optionally with modifiers) fire key-down on press and key-up on release immediately, with no chord-detection wait.
- Chords (multi-button bindings) still use the standard chord-detection window. Realtime mode coexists with chords.
- Double-tap, long-hold, and repeat mappings still use their respective timing paths. Realtime mode doesn't break them.
- Stick and touchpad input are unaffected — they were never on the chord-detection path.
In practice, realtime mode shaves the entire chord-detection window off any simple key. A button bound to "Tab" feels indistinguishable from pressing Tab on a real keyboard.
How to Enable It
Activate the Target Profile
Realtime mode is per-profile, so make sure the profile you want to make low-latency is the active one. You can flip it on for a single context (a specific app, a streaming setup, a game) and leave your everyday productivity profile on Standard timing.
Open Hardware → Input
In the main window, open the Hardware tab. The Input section is near the top, alongside a Standard / Realtime segmented picker.
Pick Realtime
Switch the picker from Standard to Realtime. A summary panel updates to confirm the change: "Fires eligible key mappings immediately on button press" and "Plain one-button key mappings only. Advanced mappings automatically stay on standard timing."
Test a Simple Mapping
Bind a button to a single keystroke. Press it. It should feel indistinguishable from pressing the key directly on the keyboard.
When to Turn It On vs Leave It Off
Turn It On
- You're using the controller for a fast-twitch game
- You're driving a demo or recording a screencast and any latency is visible
- Most of your bindings are single keys, not chords
- You're running benchmarks against the controller
Leave It Off
- You rely heavily on chords (multi-button bindings)
- Your workflow is comfortable with the default timing
- You can't tell the difference (you're not missing anything if so)
Other Latency Wins (Independent of Realtime Mode)
- USB over Bluetooth. The single biggest hardware-side win. USB controllers poll at 250–1000 Hz; Bluetooth controllers poll at 60–125 Hz with extra jitter from the wireless link. For a Steam Controller, the wireless puck is in between — closer to wired latency than Bluetooth, with the convenience of cable-free use.
- Disable controller LEDs. Some controllers (notably DualSense) batch LED updates with input reports. Setting the LED to a fixed color frees up bandwidth.
- Disable haptics if you don't use them. Same logic — haptic output reports share bandwidth with input reports.
- Don't run Steam in the background. Steam Input registers its own HID hooks that can compete with ControllerKeys for the controller's input stream. Quit Steam when you're using the controller for productivity.
- Wired charging only. If you usually run on Bluetooth, plug in for fast-twitch sessions. The cable adds latency-equivalent of about one chord-detection window's worth of savings.
Why Not Always-On?
The default ChordKeys timing exists because most ControllerKeys users do use chords. If realtime mode were always on, every chord would fire the first button's binding briefly before the second button arrived and corrected it — a flash of the wrong action on every chord press. The default behavior trades a small latency for that correctness.
Making it per-profile gives you both: an "everyday productivity" profile with chord-friendly timing, and a "fast input" profile with the wait turned off, switched automatically by app focus or by a button press.
Get the Fastest Controller-to-Keyboard Mapper on Mac
Realtime input mode is one of about 50 features in ControllerKeys. Layers, chords, sequences, scripts, webhooks, Mac-to-Mac handoff, and per-app profiles round out the rest.