# Pulsar A LAN remote desktop app built with Flutter + WebRTC. The host shares their screen; the viewer streams it and forwards mouse/keyboard input back. --- ## Architecture ``` Host (desktop) <──WebRTC──> Viewer (any platform) │ │ └────── WebSocket ───────────┘ │ Signalling Server (Node.js / ws) ``` - **Signalling server** — relays WebRTC offer/answer/ICE between peers. In-memory, no auth. - **Host** — captures screen with `getDisplayMedia`, streams it via WebRTC. Desktop/Web only. - **Viewer** — receives the video stream, renders it full-screen, and sends input events back over a WebRTC data channel. - **Input injection** — host injects received events into the OS via platform channels (CGEvent on macOS, SendInput on Windows, XTest on Linux/X11). --- ## Running the backend ```bash cd backend npm install npm start ``` The server listens on `ws://localhost:3000` by default. --- ## Running the Flutter app ```bash flutter pub get flutter run -d macos # or windows, linux ``` ### macOS notes Screen capture requires granting **Screen Recording** permission in `System Settings → Privacy & Security → Screen Recording`. Input injection requires granting **Accessibility** permission in `System Settings → Privacy & Security → Accessibility`. The sandbox is disabled in debug/release entitlements so that CGEvent can post events to other processes. Do not ship this as-is to the Mac App Store. ### Windows notes No extra permissions needed. `SendInput` works out of the box. ### Linux notes Only **X11** is supported for input injection. Wayland sessions will not receive injected events. Make sure `libxtst-dev` is installed before building: ```bash sudo apt install libxtst-dev # Debian / Ubuntu sudo dnf install libXtst-devel # Fedora ``` --- ## Usage 1. Start the signalling server. 2. On the **host** machine: open Pulsar → **Host**. A 6-character room code appears. 3. On the **viewer** machine: open Pulsar → **Connect**, enter the room code. 4. The viewer will display the host's screen. Move the mouse and type to control the host. Both machines must be able to reach the signalling server. For LAN testing, use the host's local IP in the server URL field (e.g. `ws://192.168.1.10:3000`). --- ## Key input mapping caveat Flutter's logical key IDs are not the same as OS virtual key codes. The current implementation uses the low byte of the logical key ID as a rough approximation. This works for standard ASCII keys but may misbehave for function keys, modifiers, and non-Latin layouts. A proper mapping table would be needed for production use.