Skip to content
Blake11Public

About

Use your phone (S Pen ready) as a pressure-sensitive drawing tablet for macOS over the local network. C# / .NET 10.

Topics

Resources

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

155 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ–ŠοΈ PenBridge

Turn your phone into a pressure-sensitive drawing tablet for your Mac, over Wi-Fi.

CI License: MIT .NET 10 Platforms Release Status: beta

PenBridge pairs your Android phone with your Mac. A small menu-bar app on the Mac receives pen input (pressure, tilt, hover and the side button) and turns it into native tablet events, so your drawing app sees a real pen rather than a mouse. Two to four fingers work like a Mac trackpad: scroll, zoom, swipe and Mission Control. The main target device is a Samsung Galaxy S23 Ultra with its S Pen, but any phone works with a finger.

πŸ“Έ Screenshots coming soon.

How it works

flowchart LR
    subgraph Phone["πŸ“± Phone (Android)"]
        direction TB
        Pen["S Pen / finger"] --> Sampler["Sampler<br/>pressure Β· tilt Β· hover Β· buttons"]
        Sampler --> Filter["Pen-first filter<br/>palm rejection"]
    end

    subgraph LAN["πŸ“Ά Local network"]
        direction TB
        Bonjour["Bonjour discovery<br/>_penbridge._tcp"]
        TLS["TLS control channel<br/>J-PAKE pairing (PIN / QR)"]
        UDP["Encrypted UDP pen stream<br/>AES-256-GCM"]
    end

    subgraph Mac["πŸ’» Mac menu-bar server"]
        direction TB
        Tracker["Pen state tracker"] --> Gestures["Trackpad gestures<br/>scroll Β· pinch Β· swipe"]
        Gestures --> Mapping["Display mapping"]
        Mapping --> Inject["CGEvent tablet events"]
    end

    App["🎨 Your drawing app"]

    Filter --> UDP --> Tracker
    Mac -. advertises .-> Bonjour -. found by .-> Phone
    Phone <-. pairing + session key .-> TLS <-.-> Mac
    Inject --> App
Loading
  1. Discover. The Mac advertises itself over Bonjour. The phone finds it, or you enter host and port by hand on networks without mDNS.
  2. Pair once. The Mac shows a 6-digit PIN and a QR code. The phone proves it knows the secret with J-PAKE, and both sides store a device key.
  3. Draw. Each stroke streams as small encrypted UDP datagrams. Every packet carries the full pen state, so a lost packet is corrected by the next one.
  4. Inject. The Mac turns the stream into tablet proximity, down, drag and up events with pressure and tilt, mapped onto the display you choose.
Pairing and connecting, step by step
sequenceDiagram
    autonumber
    participant P as πŸ“± Phone
    participant M as πŸ’» Mac
    M-->>P: Bonjour advert (version, name, cert fingerprint)
    P->>M: TLS connect + hello / version check
    Note over M: Shows PIN + QR
    P->>M: J-PAKE with PIN or QR token
    M->>P: J-PAKE, confirmation bound to the Mac's cert
    Note over P,M: Both store device key, phone pins the cert
    P->>M: Later: reconnect, authenticated with the device key
    M->>P: Per-session input key
    P-)M: Encrypted UDP pen samples
Loading

Features

Everything marked βœ… works end to end, checked on a Galaxy S23 Ultra with a Mac. ⏳ is planned.

Drawing

  • βœ… ✍️ Pressure and tilt from the S Pen, sent as native macOS tablet events
  • βœ… 🫧 Hover: the cursor follows the pen before it touches the screen
  • βœ… πŸ”˜ S Pen side button: right-click while hovering, a right-button drag while the tip touches
  • βœ… πŸ–οΈ Palm rejection: pen first, so fingers and palms are ignored while the pen is near
  • βœ… πŸ‘† Finger cursor mode: one finger moves the cursor like a trackpad, relative to where it is (ADR-0026): tap to click, double-tap to double-click, tap-and-a-half to drag. Switch it to Draw to paint with a finger instead
  • βœ… ⚑ Low latency over UDP, keeping the S Pen's historical samples: about 3 ms median and 8 ms p95 from the phone sending a sample to the Mac injecting it, over Wi-Fi (numbers)

Gestures, like a Mac trackpad (ADR-0023, table)

  • βœ… ✌️ Two fingers: scroll with momentum, swipe between pages, pinch to zoom and rotate, tap to right-click, double-tap for smart zoom (following the macOS Smart Zoom setting; with it off, right-click is instant)
  • βœ… 🀟 Three-finger drag: move windows and select text
  • βœ… πŸ–οΈ Four fingers: Mission Control, App ExposΓ©, switch Spaces, show desktop and the Apps launcher
  • βœ… 🎯 Acts at the cursor, which stays put; scroll direction follows the macOS natural-scrolling setting
  • βœ… ✍️ The pen always wins: bringing the pen near cancels a gesture and its momentum

Phone app

  • βœ… πŸ”Ž Finds your Mac by itself on the local network, and connects to the last Mac you used
  • βœ… πŸ“· Pair with a QR code or a PIN; forget a Mac and re-pair it from Settings
  • βœ… πŸ” Reconnects after Wi-Fi drops or when you come back to the app
  • βœ… 🌫️ Faint ink echo: a short trail that fades, so you can see where the pen went
  • βœ… 🟒 Status dot for the connection; tap it for latency, orientation, Disconnect and Change Mac
  • βœ… πŸ”„ Orientation toggle: landscape (default), portrait or auto
  • βœ… βš™οΈ Settings for finger mode, finger pressure, finger hold before drawing and palm size
  • βœ… πŸ–ΌοΈ App icon: an adaptive launcher icon that also works as a themed icon
  • βœ… πŸ™ˆ No telemetry: the app talks to your Mac and nothing else (ADR-0020)

Mac app

  • βœ… 🧭 Menu-bar app with no Dock icon: run at startup, a pause hotkey (βŒƒβŒ₯⌘P), live connection stats, a display picker and Open logs
  • βœ… πŸ” Secure pairing with a PIN or QR code (J-PAKE) in a floating window on the Mac, and encryption on every channel
  • βœ… πŸͺΆ Light on the Mac: a NativeAOT build with about a 20 MB footprint, a 168 ms launch and 0% CPU when idle
  • βœ… πŸ“² Multiple paired phones; one draws at a time
  • βœ… πŸ–ΌοΈ App icon in Finder, the DMG and Login Items, with matching menu-bar glyphs for each state

Settings, on the Mac (Settings…, ⌘,) and from the phone (table)

  • βœ… πŸ—ΊοΈ Display and region mapping: the main display, a chosen one or All displays as one desktop, or a region you drag on a display, optionally locked to the phone's aspect. The phone outlines the area that maps onto the Mac and dims the rest, so strokes are never squashed (ADR-0031)
  • βœ… πŸ–±οΈ Pen or Mouse: absolute like a tablet, or relative like a mouse with its own speed and acceleration
  • βœ… πŸ”˜ Side button actions: right click, middle click, eraser while held, double click or nothing
  • βœ… πŸ“ˆ Pressure curve: tip feel from soft to firm, click threshold and full-pressure point, with a live test pad on the Mac (ADR-0032)
  • βœ… ✌️ Gesture settings: pointer and scroll speed, Smart Zoom (follow macOS, on or off), and switches for pinch, rotate, three-finger drag and four-finger gestures (ADR-0033)
  • βœ… πŸͺŸ Window or region from the menu bar (1.3.0): Display β–Έ Full display / Window… / Region…. Window… maps the pad to a window you click, and the mapping follows it as it moves or resizes. Region… opens an editor like the macOS screenshot tool: move, resize by 8 handles, Done or Cancel (ADR-0035, ADR-0036)
  • βœ… πŸŒ— Tint outside the active area (1.3.0): while the phone is connected, the Mac dims everything outside the region or window. It never catches clicks and can be turned off on the Mac or the phone
  • βœ… 🎚️ Precise sliders: type a value, step it with the arrows or βˆ’/+, and a drag snaps at the default (1.2.1)
  • βœ… πŸ” Edit the Mac from the phone: every Mac setting except drawing the region, synced both ways and applied at once (ADR-0030)
  • βœ… 🎨 Phone surface look: corner ticks and dimmed margins around the mapped area, an optional centre marker, background and marker opacity

Status

Beta, 1.3.0. 1.3.0 adds a window target that follows the window, a macOS-style region editor, and a tint outside the active area, all from the menu bar's Display submenu (#213, #241, #243). It was checked on the S23 Ultra against the release build of the Mac app. The new tint switch needs a 1.3.0 Mac; older phones simply don't show it. 1.2.1 added typed values, steppers and a snap at the default to every settings slider on the Mac and the phone, and makes a two-finger twist rotate reliably instead of zooming (#212, #214). Phase 5 (1.2.0) is done, and with it the MVP: mapping, pen and gesture settings live in a Settings window on the Mac and can be edited from the phone, and the phone shows the part of its surface that maps onto the Mac. Phase 5 was checked on the S23 Ultra against the release build of the Mac app (#160). The wire protocol is now 1.2; 1.0 and 1.1 phones and Macs still work with 1.2 ones: the phone then has no Mac section and keeps its whole surface active, and the Mac's pen settings still apply. Known issue: on a Mac without a trackpad, a second smart-zoom double tap in Preview zooms into the next block instead of back out, a quirk of Preview with always-visible scroll bars. Set System Settings β†’ Appearance β†’ Show scroll bars to When scrolling to avoid it (#144). Phase 4 (1.1.0) added trackpad-parity gestures (#110), and Phase 3 (1.0.0), the first release, was verified on the S23 Ultra (#66).

Phase Scope Status Release
0 Repo bootstrap: conventions, CI/CD skeleton, toolchain βœ… Done
1 β€” Core (#10) Protocol, security, input processing, network engine and SimClient βœ… Done
2 β€” Mac server (#11) Menu bar, run at startup, pause hotkey, Bonjour, PIN/QR pairing window, Accessibility, CGEvent injector, NativeAOT βœ… Done
3 β€” Android client (#12) Drawing surface, S Pen, palm rejection, finger cursor mode, discovery, QR/PIN pairing, reconnect, on-device checks on the S23 Ultra βœ… Done 1.0.0
4 β€” Gestures (#13) Trackpad-parity gestures: two-finger scroll, momentum, swipe pages, pinch/rotate, tap, smart zoom; three-finger drag; four-finger system gestures. App icon βœ… Done 1.1.0
5 β€” Settings (#14) Settings window on the Mac, edited from the phone too: display/region mapping, Pen/Mouse mode, side button, pressure curve, gesture settings, phone surface look βœ… Done 1.2.0
Windows host (#28) Tray server for Windows: pen injection, gestures, pairing, settings ⏳ Later
Publishing (#177) Google Play, signed and notarized Mac app ⏳ Later
Screen mirroring (#16) The Mac or Windows screen shown under the pen on the phone ⏳ Later
iOS client (#18) iPad/iPhone client with Apple Pencil ⏳ Later
S Pen Air Actions (#19) S Pen remote button and air gestures as configurable shortcuts ⏳ Later
Mac gestures (#193) Interactive four-finger gestures ⏳ Later

The MVP is phases 1–5. Every phase ends with a release on GitHub Releases (ADR-0021): Phase 3 is 1.0.0, the first release, and each later phase bumps the minor version. Bug-fix releases between phases bump the patch (1.1.1 …). After the MVP, each milestone above ships as its own minor release, in no fixed order (ADR-0034). All work is tracked in issues and milestones.

Requirements

Minimum
πŸ’» Mac macOS 14 (Sonoma) or later, Apple Silicon or Intel
πŸ“± Phone Android 10 (API 29) or later
πŸ–ŠοΈ Stylus Optional. Built and tested for the Galaxy S23 Ultra's S Pen; without one, a finger works
πŸ“Ά Network Phone and Mac on the same local network

Getting started

For users

Download both apps from the latest release:

File For
PenBridge-X.Y.Z-macos.dmg (or .zip) the Mac menu-bar app
PenBridge-X.Y.Z-android.apk the phone
SHA256SUMS checking the downloads: shasum -a 256 -c SHA256SUMS --ignore-missing

1. Install the Mac app

The app is ad-hoc signed and not notarized yet (#21), so Gatekeeper warns on first launch:

  1. Open the .dmg and drag PenBridge to Applications.
  2. In Finder, right-click PenBridge β†’ Open β†’ Open. On macOS 15+, if there's no Open button, launch it once, then click Open Anyway in System Settings β†’ Privacy & Security. Or, in Terminal: xattr -dr com.apple.quarantine /Applications/PenBridge.app
  3. Grant Accessibility when PenBridge asks. It needs this to post pen events. After an update you may have to remove PenBridge from the Accessibility list and add it again.

PenBridge lives in the menu bar; there's no Dock icon.

2. Install the phone app

The APK isn't on Google Play, so sideload it:

  1. Download the .apk on the phone and open it.
  2. Allow installs from your browser or Files app when Android asks, then tap Install. If Play Protect warns, choose More details β†’ Install anyway. Or, from a computer: adb install -r PenBridge-X.Y.Z-android.apk

3. Pair and draw

  1. Put the phone and the Mac on the same network.
  2. On the Mac, choose Pair new device… from the PenBridge menu. A window shows a QR code and a 6-digit PIN.
  3. Open PenBridge on the phone. Your Mac shows up in the list: pick it and scan the QR code, or type the PIN.
  4. Draw. Next time, the phone connects to that Mac by itself.

Open a pressure-aware app such as Krita to see pressure and tilt. More details are in docs/releasing.md and macOS signing.

4. Gestures

With the pen away from the screen, use fingers like a trackpad. Gestures act where the cursor is.

Fingers Motion Action
2 Move Scroll, with momentum after a flick
2 Swipe left or right Back and forward between pages (Safari and other apps that support it)
2 Pinch or twist Zoom and rotate
2 Tap Right-click
2 Double-tap Smart zoom (if on in System Settings β†’ Trackpad)
3 Move Drag (move a window, select text)
4 Swipe up / down Mission Control / App ExposΓ©
4 Swipe left / right Switch Space or full-screen app
4 Spread / pinch Show desktop / Apps launcher
  • Zoom, rotate and smart zoom reach only the frontmost app, as on a trackpad.
  • A twist rotates and a pinch zooms: whichever clearly dominates starts first, and the other joins only after a further 15Β° or 25 %. Apps such as Preview follow only the first.
  • Four-finger gestures fire once per gesture through the default Mission Control keyboard shortcuts (βŒƒβ†‘ βŒƒβ†“ βŒƒβ† βŒƒβ†’, and F11 for show desktop), so those need to be on in System Settings β†’ Keyboard β†’ Keyboard Shortcuts β†’ Mission Control.

5. Settings

On the Mac, choose Settings… from the PenBridge menu (⌘,). On the phone, open Settings: while connected, it has a section for the Mac's settings, and changes apply on the Mac at once. Mac settings are the same for every paired phone.

Section Settings Where
Display All displays, the main display or a chosen one; then the area: Full display, Window… (click a window; the mapping follows it) or Region… (drag, move or resize a rectangle; optionally keep the phone's aspect ratio). Tint outside the region dims the rest while the phone is connected Mac and phone (the window and region are picked on the Mac; the phone can reset the region to the full display and toggle the tint)
Pen Pen (absolute) or Mouse (relative, with its own speed and acceleration); side button: right click, middle click, eraser while held, double click or none Mac and phone
Pressure Tip feel (soft to firm), click threshold, full pressure at; try it on the Test pad (Mac) Mac and phone
Gestures Pointer and scroll speed; Smart Zoom (follow macOS, on, off); pinch to zoom, rotate, three-finger drag and four-finger gestures on or off Mac and phone
Surface Background (black, dark grey, light), marker opacity, centre marker on or off; the corner ticks and dimmed margins are always shown phone only
Fingers and pad Finger mode, finger pressure, palm size, pad orientation phone only

The phone draws the outline of the area that maps onto the Mac and dims the rest, so a stroke on the phone keeps its shape on the Mac.

For developers

scripts/bootstrap.sh     # install the toolchain (prints any sudo steps for you)
scripts/doctor.sh        # check .NET, workloads, Xcode, Android SDK and devices
scripts/test.sh          # Core tests: fast, any OS, no workloads needed
dotnet build PenBridge.slnx

scripts/mac-dev-cert.sh  # one-time: stable signing cert, keeps the Accessibility grant
scripts/mac-run.sh       # build, sign and launch the menu-bar app
scripts/android-run.sh   # build and run on the emulator or a phone

Read more

Try without a phone

No phone at hand? tools/PenBridge.SimClient stands in for one: it pairs with the PIN like a real device and streams scripted strokes to the Mac server. It runs from a clone of the repo (see For developers).

scripts/mac-run.sh       # launch the server, grant Accessibility, then choose "Pair new device…"

# in another terminal, with the PIN from the pairing window
dotnet run --project tools/PenBridge.SimClient -- pair --host 127.0.0.1 --pin <PIN>
dotnet run --project tools/PenBridge.SimClient -- draw circle    # or pressure-ramp, tilt-sweep, hover, button-click
dotnet run --project tools/PenBridge.SimClient -- scripts        # list every draw script

Open a pressure-aware app such as Krita first to watch the strokes arrive.

Security at a glance

A paired phone controls your pointer, so PenBridge treats pairing as the front door.

  • πŸ”‘ Only paired devices can inject input. Pairing uses J-PAKE with the PIN or a one-time QR token, so the secret never crosses the network (ADR-0009).
  • 🧷 No man in the middle. Pairing confirmation is bound to the Mac's certificate, and the phone pins that certificate for every later connection.
  • πŸ”’ Everything is encrypted. Control messages go over TLS 1.2+, and every pen datagram is AES-256-GCM with a fresh key per session (ADR-0004, ADR-0013).
  • 🚫 No plaintext fallback. Replayed, tampered or stale packets are dropped, and PINs expire after 2 minutes or 3 wrong tries.

Project layout

PenBridge.slnx
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ PenBridge.Core/       platform-free: protocol, crypto, pairing, mapping, gestures
β”‚   β”œβ”€β”€ PenBridge.Mac/        menu-bar server and CGEvent tablet injector
β”‚   β”œβ”€β”€ PenBridge.Android/    client: drawing surface, S Pen, discovery, pairing
β”‚   └── PenBridge.iOS/        placeholder only
β”œβ”€β”€ tests/PenBridge.Core.Tests/   xUnit v3, runs anywhere
β”œβ”€β”€ tools/PenBridge.SimClient/    fake phone: pairs and draws scripted strokes
β”œβ”€β”€ scripts/                  bootstrap, doctor, test, mac-*, android-*
└── docs/                     architecture, decisions (ADRs), specs, development

FAQ

Does it work with Krita or Photoshop? Krita, yes. It's the reference app, and pressure, tilt, hover and the side button from a real S Pen were checked in it during the on-device verification. PenBridge posts standard macOS tablet events, which other pressure-aware apps read too, but Photoshop hasn't been tested.

How fast is it? Measured on a Galaxy S23 Ultra over Wi-Fi in a 30-second scribble (about 56,000 samples), from the phone sending a sample to the Mac injecting it: about 3 ms median and 8 ms p95. For the first sample of a stroke (pen down), about 4 ms median and 14 ms p95. Wi-Fi adds the occasional spike of around 100 ms.

Why Wi-Fi and not USB? Wireless is the point: no cable between you and the canvas. Pen samples are tiny and sent over UDP to keep latency low. A wired mode isn't on the roadmap today.

What about iPhone and iPad? There's an iOS placeholder project, and an iOS client is planned for later, after the Android MVP.

License

MIT Β© 2026 Paul Ciurea

About

Use your phone (S Pen ready) as a pressure-sensitive drawing tablet for macOS over the local network. C# / .NET 10.

Topics

Resources

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages