If you've ever used an external keyboard with your laptop, you know the problem: you rest a wrist on the trackpad, or the laptop shifts slightly, and suddenly you're typing garbage into the built-in keyboard while your hands are on a completely different one. Multiply that by a few hours a day and it's not just annoying — it's a real productivity drain.
That was the problem I set out to solve with KeyFlip, a small GNOME/Linux utility that detects when an external keyboard is connected and disables the laptop's built-in keyboard automatically — with safety fallbacks so you're never accidentally locked out.
What started as a weekend fix for my own workflow turned into a real packaged tool with tray controls, hardware detection, and Fedora support. Here's how it works, and what I learned building it.
The problem, more precisely
On Linux, your keyboard isn't a single monolithic "input device" — it's one of potentially several evdev (or libinput) input devices, each of which the desktop environment treats independently. That means, in theory, disabling one keyboard while leaving another active is completely possible. In practice, getting it reliable is trickier than it sounds:
- You need to correctly distinguish the built-in keyboard from an external one, every time, even if device names or ports change.
- You need to detect connection and disconnection events live, not just at boot.
- If something goes wrong — the external keyboard disconnects unexpectedly, or the detection logic misfires — you cannot end up in a state where the user has no working keyboard at all. That's the difference between a nice-to-have utility and a tool nobody trusts.
That last point ended up shaping most of the design.
Detecting the right device
The first real technical decision was how to identify "the built-in keyboard" versus "an external keyboard" in a way that's stable across reboots, kernel updates, and different laptop models.
Linux exposes input devices through /dev/input/event*, and each device carries metadata you can query — vendor/product IDs, a physical path, and a device name. The built-in keyboard is consistently attached via an internal bus (typically i8042 or a platform bus), while USB or Bluetooth keyboards show up on the USB or Bluetooth bus with their own vendor/product identifiers.
So instead of relying on device names (which vary wildly — "AT Translated Set 2 keyboard" isn't exactly a stable API), KeyFlip identifies the internal keyboard by its bus type and physical path. That's the detail that made detection actually reliable instead of "works on my machine."
Listening for hotplug events, not polling
Early versions of the idea were tempted toward a simple loop: check every N seconds whether an external keyboard is plugged in, and toggle accordingly. That works, technically. It's also wasteful, laggy, and just not how you're supposed to do this on Linux.
The better approach is to hook into udev, which emits events the moment a device is added or removed. GNOME and most modern desktop environments already lean on udev for exactly this kind of hardware awareness, so KeyFlip subscribes to those events instead of polling. The result: near-instant response when you plug in or unplug a keyboard, with essentially no idle overhead.
The part that actually matters: safety fallbacks
Here's the thing about a tool that disables an input device — if it gets it wrong, the failure mode is your keyboard stops working, and now you're stuck using a touchscreen or trackpad on-screen keyboard to fix a utility that's supposed to make your life easier. That's not an acceptable failure mode for something meant to run quietly in the background.
So KeyFlip is built around a few defensive principles:
- Never disable on ambiguous detection. If KeyFlip can't confidently identify the external device as a real keyboard (not a dongle, not a misbehaving peripheral), it does nothing rather than guessing.
-
Immediate re-enable on disconnect. The moment the external keyboard's
udevevent fires as removed, the built-in keyboard is re-enabled — no delay, no dependency on a background poll catching up. - Tray control as a manual override. A GUI/tray icon lets you toggle the behavior directly, so you're never dependent purely on automatic detection if something about your setup is unusual.
- Fail open, not closed. If the utility itself crashes or the daemon isn't running, the built-in keyboard defaults to enabled. A tool like this should never be a single point of failure for basic input.
That fourth point is probably the single most important design decision in the whole project. It's tempting, when you're building something clever, to optimize for the "happy path" experience. But a utility like this earns trust by being boring and safe when things go wrong, not by being maximally clever when things go right.
From script to packaged utility
The initial version was genuinely just a script — good enough to solve my own problem. Getting it to a place where other people could install and trust it meant adding:
- A proper GUI/tray presence, so the state is visible and controllable without a terminal
- Documentation covering setup, supported hardware, and troubleshooting
- Issue tracking, so real bug reports from real hardware could shape the roadmap
- Packaging for Fedora, since that's the distribution I test against most directly
That last step — packaging — ended up teaching me more about the practical side of Linux distribution than the actual input-device logic did. Getting a utility that touches low-level hardware access to install cleanly, request the right permissions, and behave consistently across a real package manager is a different skill set than writing the detection logic itself.
What I'd do differently
If I were starting KeyFlip today, I'd invest in the udev-based detection and the fail-open safety model from day one, rather than arriving at them after a simpler polling-based version. They weren't hard to build — they just weren't obvious until I'd used an early version myself and felt the failure modes firsthand. That's a useful reminder for any tool that touches hardware: the "unhappy path" isn't an edge case, it's the actual design problem.
Try it / contribute
KeyFlip is open source, and I'm actively improving it based on feedback from other Linux users running it on real hardware. If you use an external keyboard with a laptop and want to stop accidentally typing into the wrong one, or you're interested in Linux input-device handling in general, I'd love feedback or contributions.
What's the most annoying small hardware quirk you've fixed with your own tool? I'd love to hear about it in the comments.

Top comments (0)