mirror of
https://github.com/saphid/frame-control.git
synced 2026-10-06 10:00:34 +02:00
Home → Keyboard and trackpad, in every version of Frame Control (Mac, Windows, Linux, iPhone, iPad) with nothing to install on the device in your hand. On a phone: a trackpad (drag, tap, two-finger scroll and right-click) and a field that types on the Frame. On a computer: click the pad to pass the mouse and keyboard through; Esc to stop. First-party route: ui/frame_input_agent.py runs on the Frame and talks KDE Connect's LAN protocol (v7) to kdeconnectd as if it were a phone. KDE Connect isn't on the image, but Valve's package repository has it; the agent fetches it and four libraries into ~ (no root, survives updates), starts it, pairs by itself (accepting over D-Bus), and stops it again when the last device disconnects. Each device has its own identity; a stuck KDE Connect is restarted once. Verified against the real Frame (SteamOS 0.4.1): first-time install, pairing, pointer moves from the Mac's server and the iPhone app (Simulator), Mac and iPhone at once, two installs at once, a frozen daemon replaced, and the daemon stopping when the app quits. Reviewed by GPT-6 Astra (xhigh) over seven rounds; all findings fixed except per-event delivery acknowledgement (documented known limit). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
22 lines
1.2 KiB
JavaScript
22 lines
1.2 KiB
JavaScript
// Lets the page read this computer's clipboard through Electron, so sending it
|
|
// to the Frame needs no pbpaste, PowerShell, xclip or wl-clipboard. Also tells
|
|
// the page where a dropped file or folder lives, so a folder can be sideloaded
|
|
// as a title without zipping it (the local server reads it from there).
|
|
// It can open Set Up Connection when the headset can't be reached.
|
|
// It also receives frame-control://install links (docs/web-install.md): only
|
|
// what the link asked for, never an install; the page asks the user first.
|
|
const { contextBridge, ipcRenderer, webUtils } = require("electron");
|
|
|
|
contextBridge.exposeInMainWorld("frameApp", {
|
|
readClipboard: () => ipcRenderer.invoke("clipboard:read"),
|
|
setUpConnection: () => ipcRenderer.invoke("connection:setup"),
|
|
// While the keyboard-and-trackpad panel holds the keyboard, ⌘W, ⌘R and the rest go to the Frame.
|
|
captureKeys: (on) => ipcRenderer.send("keys:capture", !!on),
|
|
pathForFile: (file) => { try { return webUtils.getPathForFile(file) || ""; } catch { return ""; } },
|
|
onInstallLink: (cb) => {
|
|
ipcRenderer.removeAllListeners("install-link");
|
|
ipcRenderer.on("install-link", (_e, req) => cb({ kind: req.kind, target: req.target }));
|
|
ipcRenderer.send("install-link:ready");
|
|
},
|
|
});
|