A scrcpy-equivalent screen-mirror-and-control tool for Sailfish OS mirror a Sailfish phone to a Linux desktop and drive it with your mouse and keyboard over a single SSH connection, no root required at runtime.
SSH into a Sailfish device gives you a shell but no display, and the SDK emulator can't show real-device behaviour (Android apps, sensors, hardware quirks).
SailCopy makes on-device development, testing, bug recording, and screenshots much smoother and lets you drive the phone from a real keyboard and a big screen.
- Live screen mirror software H.264 (default) or MJPEG. Adaptive frame rate, a static screen costs almost nothing.
- Mouse → touch taps, drags, and off-screen-origin edge-swipe gestures (home / back / peek): drag from the very edge of the window.
- Full keyboard modifiers, AltGr, non-US layouts (the phone's own keymap resolves it).
- Paste to phone (F2) and file push (drag a file onto the window →
scp). - Audio (opt-in) stream the phone's sound to the desktop, dependency-free.
- Root-free at runtime capture via
sg privileged, injection via a POSIX ACL on/dev/uinput. Nodevel-suonce the ACL is granted.
- Desktop: Linux + SDL2, + Zig to cross-compile the agent.
- Phone: Sailfish OS with SSH (developer mode). Tested on a Jolla Phone (2026),
SFOS 5.2.0.16, aarch64. Other devices/OS versions need the capture, injection, and touch
geometry re-checked see
docs/ARCHITECTURE.md.
export PHONE=192.168.1.50 # phone IP, or user@host
./build.sh # build agent + client
./deploy.sh # copy the agent + grant uinput (one devel-su prompt)
./run.sh # launch the clientdeploy.shcopies the agent and grants uinput via a POSIX ACL.SKIP_UINPUT=1skips the grant on later agent updates,INSTALL_PERSIST=1makes the grant reboot-proof (udev rule + systemd unit).run.shopens an in-window connection screen (phone IP, masked password).
Important
Make sure you have Developer Mode, Remote connection enabled and a password setup
The password is fed to SSH over a PTY (never on disk/argv/env) to bring up one SSH master per session, agent re-spawns reuse it.
- Mouse: click = tap, drag = drag , drag from the window edge = edge swipe.
- Keyboard: forwarded raw, the phone's layout applies.
- F1: settings overlay Codec / Height / Quality / Speed / FPS / Audio. QP, Speed and FPS apply live , Codec and Height re-spawn the agent.
- F2: paste the desktop clipboard into the focused phone field (US/SE keymaps built in ,
SAILCOPY_KBD=us). Desktop→phone only (the compositor won't give a windowless client the clipboard). - Drag & drop:
scpa file to the phone's home dir over the SSH master.
The phone's on-screen keyboard doesn't appear while connected expected: Sailfish hides
it whenever a "hardware keyboard" is present, and SailCopy's virtual one counts , it returns
after you disconnect. If it stays hidden after disconnecting, or typing gives AltGr-shifted
garbage, an orphaned agent is stranded on the phone pkill -x sailcopy-agent (then, if
still wedged, systemctl --user restart maliit-server, or reboot). Current builds avoid this
automatically.
More detail & internals: docs/ARCHITECTURE.md.
SailCopy is GPLv3 (LICENSE). It vendors small, permissive libraries, each
under its own license (all GPLv3-compatible):
| Component | Author | License |
|---|---|---|
| minih264 (H.264 encoder) | lieff | Public domain (CC0) |
| tiny_jpeg (JPEG encoder) | Sergio Gonzalez | Public domain |
| stb_image (image decoder) | Sean Barrett | MIT / Unlicense |
| font8x8 (bitmap font) | Daniel Hepper (IBM VGA fonts) | Public domain |
| h264bsd (H.264 decoder) | The Android Open Source Project | Apache-2.0 |
The capture path speaks the lipstick_recorder Wayland protocol (Jolla / Sailfish OS) , its
wire format was referenced from Coderus's screenrecorder.
SailCopy reimplements a minimal wire client no Jolla or Coderus code is bundled.