Hand mouse and keyboard control of a shared screen to someone else

Featurekamo-meet
Shipped
September 3, 2026 at 9:07 AM UTC
Author
Kamo
Commit
c02710f

Wires the fork's dormant remote-control feature to the companion agent, and fixes the things that would have made it unusable even once it was reachable. The receiver now speaks to the local agent over loopback through the same @Meet/js-utils transport the upstream code already expected, so the whole receiver path runs unchanged. The event listener follows the transport rather than being attached to whichever one existed at CONFERENCE_JOINED, which is what lets the agent's transport replace the postMessage one when an agent turns up — and lets a desktop shell still work when none does. Three upstream defects had to go first: - sendStartRequest sent Electron's desktopCapturer sourceId, which is undefined in a browser, so grant() rejected every single time with "Cannot identify screen". The browser path sends a display worked out by matching the captured track against the agent's display list, and refuses outright when a window or tab is shared rather than a whole screen, because those cannot be mapped to desktop coordinates. - mouseMoved normalised against the large-video *wrapper*, but the video is letterboxed inside it, so the remote pointer drifted further from the real one the more the aspect ratios differed. It now measures the video element, which Meet sizes explicitly and which is therefore right under every VIDEO_LAYOUT_FIT mode. - capture was jQuery handlers on window, torn down with $(window).off('keydown') — which removed every other window key handler in the application. It is a React surface now, and moves are coalesced to one message per frame instead of one per mousemove event. The UI treats having permission and actually driving as different things: you click into the shared screen to take the wheel, a double Escape gives it back, and losing focus releases it, so a password typed into another window never reaches somebody else's machine. Keyboard shortcuts are suppressed only while actually driving. The person being controlled gets a banner they cannot miss, a stop button that is always one click away, and a triple-Escape that revokes instantly. A session whose screen leaves the stage pauses rather than ending, and keeps its bar, because holding control of a computer with nothing on screen saying so is how it gets forgotten about. A machine with no agent still advertises that it can be asked. That is deliberate and is the feature's only discovery path: with nothing advertised the menu item would never appear for anyone and nobody would learn the helper exists. Being asked answers with an explanation and a download, and a new `unavailable` reply so the asker is not told they were rejected. The install page and the binaries are served from /agent/, built by a Go stage in the image. The page checks each download before offering it, so the macOS builds — which need a Mac, since CoreGraphics needs cgo — say so rather than 404. Verified: the real binary drives a real browser handshake over a real socket; the uinput path is checked against the kernel by writing a pointer move and reading it back out of /dev/input; 28 agent tests; tsc web and native; eslint; all 7 webpack bundles compile.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing