This release adds 6 notable features for engineering teams evaluating rollout.
✓ No known CVEs patched in this version
Summary
AI summarySpud v1.0.0 updates Dual‑Mode Architecture, mDNS Discovery, Wire Protocol, Input Capture on Linux/macOS/Windows, and Screen Size handling across platforms.
Full changelog
Spud v1.0.0
Overview
Spud is a cross-platform remote control application optimised for gaming. A single binary acts as either a client (captures local input and sends it over the network) or a server (receives input and injects it into the local OS). This release supports Linux, macOS, and Windows.
Cross-Platform Features
Dual-Mode Architecture
- One binary runs as either Client or Server, switchable via a top-level tab bar.
- Client sends keyboard, mouse, and scroll events to a remote server.
- Server listens for connections and replays received input via native OS APIs.
GUI
- Built with Iced 0.14 using a custom Material-style theme.
- Client pages: Connection, Capture, Mouse, Security, Advanced.
- Server pages: Status, Network, Security, Advanced.
- Persistent settings saved to the OS config directory (
~/.config/spud/config.tomlon Linux).
Discovery (mDNS / DNS-SD)
- Automatic LAN discovery via mDNS service type
_spud._tcp.local.. - Servers advertise their name, icon, port, and whether auth/encryption are required.
- Clients see a live-updating grid of discovered servers with connect buttons.
- Same-machine filtering prevents a local server from appearing in its own client list.
Security
- TLS 1.3 control plane with self-signed Ed25519 certificates.
- Trust-on-first-use (TOFU) fingerprint verification with SHA-256 SPKI pinning.
- Optional passphrase authentication using Argon2id + HMAC-SHA256 challenge-response.
- Optional UDP encryption using AES-256-GCM with keys exported from the TLS session.
- Replay protection via a 1024-packet RFC 4303-style sliding window.
- Key material implements
Zeroize/ZeroizeOnDropfor memory safety.
Wire Protocol
- TCP + TLS 1.3: control plane (handshake, auth, session init, keepalives).
- UDP: input event plane with compact 5-byte fixed encoding.
- Mouse batching: buffers moves for up to 1 ms or until
max_batch(configurable, default 4). - Redundant history: past batches can be appended to each datagram for lossy networks (configurable, default 0).
- Deduplication: server uses sequence-number bitmaps to ignore duplicate mouse batches and keyboard/wheel events.
- Key repeat: client sends
KeyRepeatandMouseButtonRepeatat a configurable interval (default 500 ms) while keys/buttons are held, preventing stuck keys on packet loss. - Auto-reconnect: client retries for a configurable timeout (default 30 s) on connection loss.
Input Capture (Client)
- Hotkey toggle: configurable key combo to start/stop input capture.
- Fullscreen capture mode: grabs all input system-wide.
- Window capture mode: captures input only while the Spud window is focused (no system-wide grab required).
- Mouse sensitivity: adjustable 0.25x - 3.0x.
- Natural scroll: toggle to invert scroll wheel direction.
- Screen blanking: optionally blanks the client screen while capturing input.
Input Injection (Server)
- Tracks held keys and mouse buttons with configurable hold timeout (default 200 ms).
- Releases stuck keys automatically if a
KeyUpis lost. - Pre-injects a
KeyUpbefore a duplicateKeyDownto avoid OS repeat-stuck behavior. - Sessions time out after 300 s of inactivity.
Linux
Input Capture
- X11 backend (
x11rb):- Passive grab on the root window for the hotkey combo.
- While grabbed:
XGrabKeyboard+XGrabPointer+xfixes_hide_cursor. - Pointer is warped back to screen center when it moves beyond a threshold (pointer jail).
- Scroll wheel mapped from X11 buttons 4-7.
- Wayland backend (
wayland-client):- Uses
zwp_pointer_constraints_v1for pointer locking/confinement. - Uses
zwp_relative_pointer_manager_v1for relative mouse motion. - Optionally uses
zwp_keyboard_shortcuts_inhibit_manager_v1to inhibit compositor shortcuts while grabbed. - Falls back from
lock_pointertoconfine_pointerif the compositor denies the lock. - COSMIC and other compositors supported via standard protocols.
- Uses
- Window capture: uses Iced's built-in event subscriptions; no native grab required.
Input Injection
- Opens
/dev/uinputdirectly usingevdev+kinput. - Creates a virtual device named
"spud virtual input". - Supports absolute and relative mouse movement, keyboard keys, mouse buttons (left, right, middle, back, forward), and scroll wheel.
- Privileged helper: if
/dev/uinputis not accessible, automatically spawns apkexechelper process that runs as root and communicates over a Unix domain socket. - A polkit rule (
linux/50-spud-injection.pkla) can be installed to skip the password prompt for local users in thesudogroup.
Screen Size
- Queried at server startup via X11. Falls back to
1920x1080if X11 is unavailable.
macOS
Input Capture
- Core Graphics Event Tap at HID level (head-insert).
- Listens to: key down/up, mouse down/up, mouse move, scroll wheel.
- Requires Accessibility permission (and Input Monitoring on macOS 10.15+).
- Hotkey toggles grab state; hides/shows cursor via
CGDisplay. - All grabbed events are consumed so they do not reach local applications.
- Mouse deltas come from
MOUSE_EVENT_DELTA_X/Y. - Scroll deltas come from
SCROLL_WHEEL_EVENT_DELTA_AXIS_1/2.
Input Injection
- Mouse: uses raw IOKit HID (
IOHIDPostEvent) so games reading raw input see injected movement.- Absolute moves via
K_IOHID_SET_CURSOR_POSITION. - Relative moves via
K_IOHID_SET_RELATIVE_CURSOR_POSITION. - Drag events inferred from pressed buttons.
- Absolute moves via
- Keyboard: uses
CGEvent::new_keyboard_eventposted toCGEventTapLocation::HID.- Tracks held keys and performs local key-repeat pulsing (KeyUp/KeyDown every 50 ms) to prevent the macOS accent popup menu.
- Scroll: uses
CGEventPostfor correct acceleration behavior.
Screen Size
- Queried at server startup via
CGDisplay::main().bounds().
Windows
Input Capture
- Low-level hooks (
SetWindowsHookExW):WH_KEYBOARD_LLfor global keyboard monitoring.WH_MOUSE_LLfor global mouse monitoring.
- RegisterHotKey fallback: a message-only window with
RegisterHotKeyhandles hotkey toggling when the LL hook is silent (e.g. when the Spud window itself has focus). - 50 ms debounce on hotkey toggle to prevent rapid grab/ungrab loops.
- While grabbed:
ShowCursor(false), all keyboard and mouse events are consumed. - Mouse deltas computed from
MSLLHOOKSTRUCT.pt. - Scroll mapped from
WM_MOUSEWHEELdelta. - Buttons mapped: left (1), right (3), middle (2), X1 (8), X2 (9).
Input Injection
- Uses the
SendInputAPI. - Mouse absolute: normalizes to
0..65535using virtual desktop metrics (multi-monitor aware). - Mouse relative:
MOUSEEVENTF_MOVE. - Buttons:
MOUSEEVENTF_LEFTDOWN/UP,RIGHTDOWN/UP,MIDDLEDOWN/UP,XDOWN/UP. - Wheel:
MOUSEEVENTF_WHEEL/MOUSEEVENTF_HWHEELwith delta multiples of 120. - Keyboard:
- Primary: evdev scancode -> Windows VK lookup table with extended-key flag.
- Fallback:
MapVirtualKeyW. - Ultimate fallback for printable characters:
KEYEVENTF_UNICODE.
Screen Size
- Server reports fallback
1920x1080for session init; absolute injection uses the actual virtual desktop size viaGetSystemMetrics, so multi-monitor setups work correctly.
Known Issues & Limitations
- The Wayland capture backend requires compositor support for
pointer-constraintsandrelative-pointerprotocols; some minimal compositors may not support these. - macOS input capture requires manual permission grants in System Settings before the app can capture input.
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About Spud
All releases →Related context
Related tools
Beta — feedback welcome: [email protected]