Status:
0.2.0-alpha— Phase 1 close-out. Two daemons on the same LAN discover each other via mDNS and the cursor crosses between machines — no static IP in the config required. Clipboard sync, multi-monitor, and Windows support are next (seeDESIGN.mdand the issues). Not yet a daily driver, but the core KVM works end-to-end on Linux.
Share your keyboard and mouse across machines. A modern, Rust-based virtual KVM that lets you seamlessly move your cursor between computers on the same network.
Website: cross-control.adjoint.uk · the landing page source lives in site/.
The software KVM space is stagnant. Barrier is unmaintained since 2022, Input Leap and Deskflow have broken Wayland support, Synergy went proprietary, and the Rust alternatives (RKVM, LAN Mouse) are either Linux-only or use incompatible protocols.
cross-control takes a different approach:
| Barrier | Input Leap | Synergy | RKVM | LAN Mouse | cross-control | |
|---|---|---|---|---|---|---|
| Active | Dead (2022) | Slow | Yes | Yes | Yes | Yes |
| Wayland | No | Partial | Partial | Yes | Yes | Native |
| Windows | Yes | Yes | Yes | No | Yes | Planned |
| Protocol | Synergy v1 | Synergy v1 | Proprietary | Custom | Custom | QUIC |
| Encryption | Optional TLS | Optional TLS | TLS | TLS | None | TLS 1.3 (always) |
| Discovery | No | No | No | No | No | mDNS |
| License | GPL-2.0 | GPL-2.0 | Proprietary | GPL-3.0 | GPL-3.0 | MIT/Apache-2.0 |
- QUIC transport - Multiplexed streams, built-in TLS 1.3, 0-RTT reconnection. No other KVM uses QUIC.
- Wayland-native - Works on Wayland from day one via evdev/uinput, with enhanced support for wlroots compositors.
- Zero-config discovery - Machines find each other automatically via mDNS/DNS-SD.
- Clipboard sharing - Text, HTML, and images synced when you switch machines.
- Position-based switching - Move your cursor to the screen edge to switch, just like macOS Universal Control.
- Certificate pinning - SSH-style trust-on-first-use authentication. No central authority needed.
- Multi-machine - Star topology supports any number of machines.
- Permissive license - MIT OR Apache-2.0. Use it anywhere.
- Linux (x86_64 or aarch64) — Windows support is planned
- Rust 1.75+ (if building from source)
- User must be in the
inputgroup to access keyboard/mouse devices /dev/uinputmust be accessible for virtual device emulation
curl -fsSL https://raw.githubusercontent.com/Adjoint-uk/cross-control/main/install.sh | bashDownload the latest release from GitHub Releases.
git clone https://github.com/Adjoint-uk/cross-control.git
cd cross-control
cargo install --path crates/cross-control-cli# Add your user to the input group (required for keyboard/mouse access)
sudo usermod -aG input $USER
# Ensure uinput is accessible
sudo modprobe uinput
echo 'KERNEL=="uinput", MODE="0660", GROUP="input"' | sudo tee /etc/udev/rules.d/99-uinput.rules
sudo udevadm control --reload-rules && sudo udevadm trigger
# Log out and back in for group changes to take effectSet up two Linux machines on the same network:
cargo install --path crates/cross-control-clicross-control generate-cert --output ~/.config/cross-control/Note the fingerprint printed for each machine.
Machine A (left workstation at 192.168.1.10):
# ~/.config/cross-control/config.toml
[identity]
name = "workstation"
[[screens]]
name = "laptop"
address = "192.168.1.20:24800"
position = "Right"
fingerprint = "SHA256:..." # laptop's fingerprintMachine B (right laptop at 192.168.1.20):
# ~/.config/cross-control/config.toml
[identity]
name = "laptop"
[[screens]]
name = "workstation"
address = "192.168.1.10:24800"
position = "Left"
fingerprint = "SHA256:..." # workstation's fingerprintcross-control startMove your cursor to the right edge of Machine A's screen. It will appear on Machine B. Move it back to the left edge to return.
Press Ctrl+Shift+Escape to immediately release input and return control to the local machine.
cross-control statusSee docs/setup-guide.md for detailed setup instructions and troubleshooting.
To keep the daemon running across logins, install the systemd user unit:
mkdir -p ~/.config/systemd/user
cp systemd/cross-control.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now cross-control
systemctl --user status cross-control # check it's running
journalctl --user -u cross-control -f # follow logsThe install script offers to do this for you. Two prerequisites, since input
capture/emulation needs device access: your user must be in the input group,
and /dev/uinput must be group-readable/writable (see Linux permissions
setup above). To have the service start before you log in, enable lingering:
sudo loginctl enable-linger $USER. The unit assumes the binary is on
~/.cargo/bin; if you installed elsewhere, adjust ExecStart with
systemctl --user edit cross-control.
No second computer? The loopback example runs two daemons in one process and
drives a full session — handshake, cursor crossing, input forwarding — end to
end on 127.0.0.1:
cargo run -p cross-control-daemon --example loopbackOn a Linux desktop with /dev/uinput access, add --features linux -- --real
to have the receiving daemon inject into a real virtual device so you can watch
the cursor move. This covers everything except the physical input ends
(real evdev capture and a live compositor).
Physical Input Virtual Input
(keyboard/mouse) (on remote machine)
| ^
v |
+-----------+ +------------+ +-------+ +------------+ +-----------+
| Input | -> | Protocol | -> | QUIC | -> | Protocol |->| Input |
| Capture | | Serialize | | Wire | | Deserialize| | Emulation |
+-----------+ +------------+ +-------+ +------------+ +-----------+
(evdev/RawInput) (bincode v2) (quinn) (bincode v2) (uinput/SendInput)
| |
+-----------+ +-----------+
| Clipboard | <------------- Clipboard Sync ------------>| Clipboard |
+-----------+ +-----------+
| |
+-----------+ +-----------+
| Discovery | <------------- mDNS/DNS-SD --------------->| Discovery |
+-----------+ +-----------+
The project is organised as a Cargo workspace with 8 crates:
| Crate | Purpose |
|---|---|
cross-control-types |
Shared types: events, devices, screens, identifiers |
cross-control-protocol |
QUIC transport (quinn), wire format (bincode v2) |
cross-control-input |
Platform-abstracted input capture and emulation |
cross-control-clipboard |
Clipboard synchronisation |
cross-control-discovery |
mDNS/DNS-SD zero-config discovery |
cross-control-daemon |
Core state machine, barrier logic, event routing |
cross-control-cli |
User-facing binary |
cross-control-certgen |
TLS certificate generation |
Configuration lives at ~/.config/cross-control/config.toml:
[daemon]
port = 24800
discovery = true
[identity]
name = "my-workstation"
[[screens]]
name = "laptop"
address = "192.168.1.42:24800"
position = "Right"
fingerprint = "SHA256:..."
# For 3+ machines, define adjacency
[[screen_adjacency]]
screen = "laptop"
neighbor = "tablet"
position = "Right"See examples/config.toml for all configuration options.
cross-control is in early development. Current status:
- Phase 0: Workspace scaffold, shared types, trait definitions, CI
- Phase 1 (
v0.2.0-alpha): Linux-to-Linux end-to-end — evdev capture, QUIC transport, multi-hop switching, mDNS discovery, TOFU pinning, 64 tests - Phase 2 (
v0.5.0-beta): Clipboard sharing, multi-monitor, reconnect, polished setup - Phase 3 (
v0.9.0): Windows + macOS input backends, distro packaging - Phase 4 (
1.0.0): Protocol freeze, ADRs, security model, fuzz testing
See CONTRIBUTING.md for development guidelines.
See SECURITY.md for the security policy and reporting vulnerabilities.
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT license (LICENSE-MIT)
at your option.
Built by Adjoint Ltd