Add encrypted LAN mouse and keyboard sharing with four-edge handoff

This commit is contained in:
agrynco committed 2026-11-06 16:28:43 +02:00
1 parent 9b565dd55e
commit e0bfdd9a90
15 files changed
+1093 -104

No files matched your search

+93 -64
View File
@@ -1,79 +1,108 @@
# LAN discovery and pairing preview
# LAN mouse and keyboard preview
This development branch starts the built-in replacement for Mouse Without Borders.
It adds discovery and authenticated pairing inside the existing KSwitcher resident
process. It is **not yet a mouse/keyboard or clipboard transport**. Do not disable
MWB on the strength of this preview.
KSwitcher discovers other enabled KSwitcher instances, pairs them with the same
code on both computers, and shares mouse and keyboard through a screen edge.
The module runs inside the resident process. This preview supports **one active
pair of computers**, with the neighbour on the left, right, above or below.
Several trusted pairs may be saved, but only the selected neighbour is active.
Clipboard and file transfer are not implemented yet.
## Try it on two Windows computers
## Set up two computers
1. Run this development build on both computers, on the same private IPv4 subnet.
2. Open Settings → Tools → KSwitcher computers.
3. Enable discovery on both. The list contains running LAN-enabled KSwitcher
instances, not computers returned by a generic Windows/network scan.
4. Match the computer name and eight-character instance-ID prefix displayed on
the other computer. Select each other in the lists.
5. Generate a code once. Enter that same 32-character code on both computers,
then click Pair on both within two minutes. Spaces, hyphens and uppercase
hexadecimal characters are accepted. A different code never establishes trust.
6. Both sides should report Paired; authenticated presence appears as
“Paired / verified”. An offline pair stays listed so it can be forgotten.
1. Extract this preview into a separate writable folder on each Windows PC.
Exit the regular KSwitcher before starting this copy; only one resident runs
per Windows session. Each copy keeps its own data beside the executable.
2. Open Settings → Tools → KSwitcher computers and enable discovery on both PCs.
Only running LAN-enabled KSwitcher instances appear, not generic network devices.
3. Match the computer name and instance-ID prefix displayed on the other PC.
Select each other, generate one code, enter that same code on both, then click
Pair on both within two minutes. Spaces, hyphens and uppercase hex are accepted.
4. Select the paired neighbour and its position relative to this computer.
Example: B stands to the right of A, so choose **Right on A** and **Left on B**.
For a vertical arrangement choose **Above** on the lower PC and **Below** on
the upper PC. Click **Apply position / enable input** on both.
5. Stop MWB or another mouse/keyboard router on both computers before trying
KSwitcher input sharing, to avoid two tools forwarding the same events.
6. Wait for the authenticated input connection. Move the cursor through the
configured outer screen edge with no keys or buttons held. After the other
computer acknowledges the handoff, both mouse and keyboard control that PC.
Crossing its return edge returns control to the source computer.
Discovery uses UDP 45883 on private IPv4 and link-local interfaces. Windows may
require an inbound firewall allowance for KSwitcher on the private network; the
preview does not modify firewall rules. Networks that block broadcasts, separate
VLANs, public IPv4 and IPv6-only networks are not supported yet. A second build
cannot listen on the same discovery port on the same computer.
The source cursor is parked and hidden beneath a tiny no-activation window. A
small banner identifies remote control; no full-screen layered bitmap is retained.
The destination uses its own keyboard layout and runs its own hotkeys/snippets.
The source suppresses forwarded events before its local hotkeys, snippets and
other low-level hook consumers. Received input is marked so it is not forwarded
again. Source recent-input tracking resets when ownership changes.
Changes in this window apply immediately. Closing the window does not cancel a
pending pairing; use Cancel pairing. Disabling discovery stops its worker and
closes its socket. Forget pair removes local trust; forget it on both computers
for bilateral removal. No input can be sent or received in this milestone.
**Ctrl+Alt+Esc** is emergency return, not the normal switching mechanism. Local
physical input on a remotely controlled PC takes control back as well. Stop input
sharing, disabling discovery, forgetting the active pair, suspension, secure
desktop changes and connection loss cancel remote ownership. TCP heartbeat loss
is detected after two seconds; a handoff request expires after one second.
Held remote keys/buttons are released. Releases blocked by a secure desktop are
retried when the ordinary desktop is available. Source key-ups for keys already
sent remotely are consumed after return, avoiding stray local modifier events.
## Identity, pairing and storage
## Layout and limitations
An instance ID belongs to a KSwitcher data directory, not a hostname/IP address.
It persists when the LAN configuration is first saved. Discovery announcements
contain only protocol/version, instance ID, computer name and a fresh challenge.
Discovered names and addresses are untrusted; they never authorize input.
- Positions are relative to this PC and must be opposite on the two computers.
Inconsistent positions are rejected before input is authorized. Changes apply
immediately and reconnect the input channel.
- Geometry uses the virtual desktop's outer bounding rectangle, including negative
monitor coordinates. Internal monitor boundaries do not transfer control.
Different resolutions map the entry position proportionally. Irregular layouts
can have gaps on an outer edge; this is not a per-monitor arrangement editor.
- Transferring while a key or mouse button is held is intentionally blocked.
Dragging works within the controlled computer; dragging objects across PCs is
not implemented. There is a short return cooldown to avoid bouncing.
- Windows can block SendInput to elevated apps and secure desktops. Run both
applications at suitable privilege levels for the target programs. The preview
does not install a service, bypass UAC or implement remote Ctrl+Alt+Delete.
- This is Windows input injection, not a virtual USB HID device. Raw-input games,
exclusive full-screen applications and special device keys need separate testing.
The generated code has 128 bits of randomness from Windows CNG. It is deliberately
not a guessable short PIN. HMAC-SHA256 proofs bind the source/destination IDs and
fresh nonces; both endpoints confirm the handshake before saving the pair.
Replayed confirmations cannot complete a new attempt. The shared pair key is
separate from the setup code. The code is never transmitted or logged.
## Network, authentication and storage
Local identity, enablement and trust records are stored in DPAPI-protected
`data/lan-pairing.bin`. They are separate from settings export and OpenBao sync.
Do not clone this file between installations: each instance needs its own identity.
Unverified/offline status does not remove a previously saved pair. Discovery is
bounded to 64 visible instances and stale discoveries expire after 12 seconds.
A newly started pairing window lasts two minutes. Presence challenges rotate so
captured replies cannot indefinitely keep a disconnected instance verified.
Discovery broadcasts on private IPv4 and link-local interfaces using UDP 45883.
Input uses TCP 45884. Allow KSwitcher on your private network when Windows asks;
the preview does not change firewall rules. Broadcast-blocked networks, separate
VLANs, public IPv4 and IPv6-only networks are not supported by discovery yet.
A second LAN-enabled KSwitcher cannot use the same ports on one computer.
Disabled discovery starts no worker and opens no sockets. Enabling it adds one
worker thread within KSwitcher; the existing configurator uses local IPC. There
is no new executable, service, WebView or runtime dependency.
The instance ID belongs to a data directory, not a hostname/IP address. Discovered
names and addresses are untrusted. Pairing uses a generated 128-bit code and
mutual HMAC-SHA256 challenge proofs bound to both instance IDs. The code is never
transmitted or logged. The pair key is separate from the setup code.
## Next integration milestone
The input channel authenticates both peers with the saved pair key and fresh
session challenges. Directional AES-256-GCM session keys bind the identities,
nonces and screen positions. Fixed-size authenticated frames use strict sequence
numbers, so tampering, reflection and replay are rejected. Input is not dispatched
until authentication succeeds. This PSK channel does not provide forward secrecy.
Queues and frame sizes are bounded; overflow disconnects rather than dropping a
key-up and leaving a key pressed. The input worker never injects Windows input;
the resident's main thread owns the input state and hooks.
- An authenticated encrypted input channel using the stored pair key, separate
from UDP discovery. Pairing alone must never inject input.
- Left/right/top/bottom screen placement and cursor crossing at the screen edge
from the first input prototype, not hotkey-based normal switching.
- Reuse the resident low-level hooks. Forwarded keys must not expand snippets or
invoke actions on the source PC; received keys run through the destination path.
- Release pressed keys/buttons and return local control on disconnection, timeout,
suspend, lock, disable or process shutdown. Keep an emergency return chord.
- Text/image clipboard transport with bounded sizes and loop suppression follows
reliable input handoff. File transfer and secure-desktop control are later work.
Identity, trust, enablement and screen position stay in DPAPI-protected
`data/lan-pairing.bin`, outside settings export and OpenBao sync. Do not clone this
file between installations. Forget a pair on both PCs for bilateral removal.
Closing the settings window does not cancel pairing or disable sharing.
Disabled discovery has no socket or worker. Input sharing reuses the single LAN
worker; there is no extra resident executable or service. The main input timer
runs only while sharing is enabled. The existing configurator talks to the
resident through local IPC.
## Validation
`KSwitcherLanTests` covers cryptographic test vectors, wrong codes, identity and
protocol substitution, mutual confirmation, replay, expiry, DPAPI persistence,
and no worker while disabled. `--network` additionally exercises real discovery
start/stop/rebind. Settings UI tests cover the child window, disabled actions,
empty list, parent reactivation and unchanged Save state. Two physical computers
are still required to validate discovery across adapters/firewalls and pairing
under real packet loss; this preview does not claim that validation.
Tests cover pairing, encrypted frames, replay/tamper rejection, actual loopback
TCP authentication and bidirectional delivery, all four edges, ownership races,
source suppression, scan codes, clicks/wheel, emergency return, held-key release,
blocked injection, secure desktop recovery, exact one-pixel movement and timeout.
UI tests check all four positions and preserve an edited choice during refresh.
Two physical computers still need an end-to-end trial for their adapters,
firewalls, displays and application privilege levels. The automated TCP tests
use local sockets, and input-state tests use simulated desktop environments;
they do not claim a completed two-machine hardware test.