Skip to content

feat(x11-capture): implement X11 input capture backend#457

Open
lgobatto wants to merge 1 commit into
feschber:mainfrom
hekivo:pr/x11-input-capture
Open

feat(x11-capture): implement X11 input capture backend#457
lgobatto wants to merge 1 commit into
feschber:mainfrom
hekivo:pr/x11-input-capture

Conversation

@lgobatto

Copy link
Copy Markdown

Summary

Replaces the X11InputCapture stub (which always returned NotImplemented and fell through to the Dummy backend) with a working implementation. With this change, lan-mouse on X11/Xorg sessions captures mouse and keyboard properly, allowing the cursor to cross back to the host by moving to the screen edge — no release keybind required.

Fixes the root cause of #125 and #315 (Xorg users stuck on the client, needing manual release to return).

How it works

A dedicated OS thread runs the X11 event loop alongside the async runtime — the same pattern used by the Windows backend.

Phase 1 — edge detection (no active client):
Polls XQueryPointer at ~1 ms. When the cursor crosses a screen edge toward a configured client, calls XGrabPointer + XGrabKeyboard and sends CaptureEvent::Begin.

Phase 2 — forwarding (active client):
Drains XNextEvent. MotionNotify computes a relative delta from the locked entry point and warps the cursor back. ButtonPress/ButtonRelease and KeyPress/KeyRelease are forwarded as input events. X11 keycodes are converted to Linux evdev by subtracting 8.

Key subtlety: The right/bottom boundary check uses >= w-1 / >= h-1 instead of >= w / >= h. X11 clamps cursor coordinates to [0, w-1] × [0, h-1] — the larger values are never returned by XQueryPointer on a single monitor, so the original >= w condition was dead code and the return journey never triggered.

Changes

File Change
input-capture/src/x11.rs Full implementation replacing the stub
input-capture/src/error.rs Replace NotImplemented with OpenDisplayFailed variant

13 unit tests cover boundary detection, coordinate clamping, and button mapping.

Tested on

  • Host: Zorin OS 17 (X11) — cursor capture and forwarding to client ✅
  • Client: Linux Mint 21 (X11/Xorg) — cursor crosses back to host by moving to screen edge ✅
  • Keyboard forwarding ✅ · Mouse buttons ✅ · Release keybind as fallback ✅

Tested with one host + one client; other X11 distros and multi-client setups have not been validated yet.

Replaces the stub that always returned `NotImplemented` with a working
implementation using XQueryPointer polling + XGrabPointer/XGrabKeyboard.

Architecture mirrors the Windows backend: a dedicated OS thread runs the
X11 event loop and communicates with the async runtime via two channels
(std::sync::mpsc for requests, tokio::sync::mpsc for events).

Phase 1 (no active client): polls XQueryPointer at ~1 ms to detect when
the cursor crosses a screen edge towards a configured client, then calls
XGrabPointer + XGrabKeyboard and sends CaptureEvent::Begin.

Phase 2 (active client): drains XNextEvent. MotionNotify events compute
a relative delta from the locked entry point and warp the cursor back;
ButtonPress/Release and KeyPress/Release are forwarded as input events.
X11 keycodes are translated to Linux evdev by subtracting 8.

The right/bottom boundary detection uses `>= w-1` / `>= h-1` rather
than `>= w` / `>= h` because X11 clamps cursor coordinates to the range
[0, w-1] × [0, h-1] — the larger values are never returned by
XQueryPointer on a single monitor.

13 unit tests cover boundary detection, coordinate clamping, and button
mapping.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant