I built a Software KVM in Rust instead of paying for Synergy
The problem
I had a MacBook and a Windows desktop on the same desk. Two mice, two keyboards, arms reaching back and forth all day. I wanted one of each.
The fix is a software KVM, a tool that lets you move your cursor from one machine to the next as if they share a single desktop. I tried the existing options:
- Synergy: paid, constant disconnects
- Barrier: dead fork, same disconnect bug
- Mouse Without Borders: Windows-only
- Hardware KVM: works, but breaks multi-monitor setups
Nothing fit. So I built my own. It's called CursorHop and the core engine is written in Rust.
Why Rust
Three reasons, in order of importance.
1. Latency is the whole game
A software KVM lives or dies by input latency. Any noticeable delay breaks the illusion and the tool feels broken. My target was under 1ms of software overhead, leaving the rest of the budget for network round-trip time.
Rust gives you that budget. No GC pauses. No runtime overhead. Deterministic allocations. For input-path code, nothing else comes close.
2. Memory safety without a runtime
A KVM app runs 24/7 with low-level access to your input devices. A crash here isn't just annoying. It can take down your desktop session.
Rust's ownership model eliminates entire classes of bugs at compile time: use-after-free, data races, null pointer dereferences, buffer overflows. The compiler refuses to build broken code.
3. Native cross-platform binaries
One Rust codebase compiles to Windows and macOS. Binaries are small (under 10MB), start instantly, and don't ship an embedded browser runtime with every install.
Architecture
The hot path looks like this:
-
Capture: OS-specific hooks grab mouse and keyboard events.
SetWindowsHookExon Windows,CGEventTapon macOS. - Encrypt: Events go over the Noise protocol (same family as WireGuard). Mutual auth, forward secrecy, low overhead.
- Transport: UDP over LAN. No TCP handshake tax on every packet.
- Discovery: mDNS. Machines find each other automatically, no IP configuration.
-
Inject: Events replayed on the target machine via
SendInputorCGEventPost.
End-to-end latency is well under 1ms on a wired LAN. 2 to 4ms on Wi-Fi. Humans can't perceive either.
What surprised me
mDNS is still weird in 2026. Different OSes handle multi-interface responses differently, especially when machines have both Wi-Fi and Ethernet active. I ended up writing a minimal mDNS responder because the existing Rust crates had edge cases that bit me.
Mac and Windows key mapping is genuinely hard. Cmd to Ctrl mapping works most of the time, except when it doesn't. Dead keys and international layouts took longer than I'd like to admit.
Clipboard sync is a minefield. Text is easy. Images are okay. Rich content like tables from Excel or styled HTML from a browser is a nightmare because every OS represents it differently. I ended up normalizing to a handful of canonical formats.
Users hate subscriptions more than I expected. I priced CursorHop as a one-time purchase because it's what I'd want as a buyer. The response has been overwhelmingly positive.
Why paid, not open source
This is the question I get most.
Short answer: I want to keep building CursorHop for years, not abandon it in six months. Paid means I can justify spending time on it. Most open-source projects in this specific space have died because nobody wants to handle the long tail of OS quirks alone.
There's a 7-day free trial with core features. Pricing is one-time, starting at $10 for the basic tier and up to $35 for the multi-machine version.
Try it
If you have more than one computer on your desk, try it for a week. I'd genuinely love feedback, especially on edge cases I haven't hit yet.
๐ cursorhop.com
Questions about the Rust architecture, the Noise integration, or the pricing tradeoff? Ask in the comments, I'll answer everything.
Top comments (0)