Skip to content

feat(mac): Pen / Draw Mode — single pointer draws instead of scrolling - #51

Draft
crsxmd wants to merge 2 commits into
tranvuongquocdat:mainfrom
crsxmd:pen-mode
Draft

feat(mac): Pen / Draw Mode — single pointer draws instead of scrolling#51
crsxmd wants to merge 2 commits into
tranvuongquocdat:mainfrom
crsxmd:pen-mode

Conversation

@crsxmd

@crsxmd crsxmd commented Aug 2, 2026

Copy link
Copy Markdown

Summary

Adds Pen / Draw Mode, a Touch Control toggle that routes a single pointer straight onto the left mouse button so a stylus draws instead of scrolling.

Closes #45.

The gesture state machine currently treats one pointer as a trackpad: a stroke that travels further than tapMaxDistance before longPressTime elapses becomes a scroll, so drawing pans the canvas. Waiting out the 500 ms long press before every stroke is the only way to get a line today, which is unusable for drawing.

With the toggle on, and for a single pointer only:

  • touch down → leftMouseDown immediately, no long-press wait
  • touch move → leftMouseDragged
  • touch up → leftMouseUp (with mouseEventClickState set, so a tap still reads as a complete click)

Two pointers are dispatched before the mode is consulted, so two-finger scroll and pinch are untouched and panning/zooming a canvas still works.

Off by default. When the toggle is off the only changes on the existing path are one Bool read and two branches that are unreachable unless the mode has been enabled, so every current gesture behaves exactly as before.

This is direct-pointer input only. The touch payload carries x, y, action, pointerCount and no pressure or tilt, so this deliberately does not close out the planned full stylus support — it is the small, Mac-only half of #45 that needs no wire-protocol or Android change.

Relationship to open PRs

Also fixed

releaseHeldMouseButtonIfNeeded() posts the matching leftMouseUp whenever a stroke can end without its touch-up: client disconnect, stopServer(), touch input switched off, a second finger landing mid-stroke, and a fresh pen down that finds a previous stroke still open. Without it, pulling the USB cable mid-stroke leaves the left button physically down and every later cursor move drags across the Mac until a real mouse is clicked.

It guards on .penDrawing || .dragging, so it also covers the pre-existing long-press drag case (same ground as #46).

Known limitations

  • No pressure or tilt (protocol carries neither) — see Add stylus pressure, tilt, and hover support #33.
  • While the mode is on, one-finger scroll, momentum and tap-and-hold right click are unavailable. Tap and double tap still work. The Settings panel says so in an orange note.
  • Stroke smoothness is bounded by the client: MainActivity runs one-finger moves through InputPredictor.predictPosition(12f) and reads only event.x/y rather than getHistorical*, so fast strokes can overshoot slightly at sharp corners. Left alone deliberately to keep this PR Mac-only.

Testing

Verified:

  • swift build clean, no warnings
  • scripts/build_mac.sh produces the universal bundle; installed and launched on macOS 26.5.2, Apple Silicon
  • Toggle appears under Touch Control and persists across restarts (defaults read com.sidescreen.app SideScreen_penModeEnabled)
  • Default-off path re-read line by line: no existing line removed or moved, all new code unreachable with the toggle off

Not yet verified, which is why this is a draft:

  • Cable-pull mid-stroke actually leaving the button released

Verified on hardware (Xiaomi Pad 6, USB, macOS 26.5.2):

  • Long continuous strokes draw as expected instead of scrolling
  • Two-finger scroll and pinch still work with the mode on
  • Double tap opens items (this needed the follow-up commit: a press declares its click count when posted, so pen mode has to decide at contact rather than on release)

Hardware here is a Xiaomi Pad 6 over USB. The reporter of #45 offered to test builds — happy to have this exercised on a Redmi Pad Pro before it is marked ready.

UI

The toggle sits under Touch Control directly below "Enable Touch Input", disabled when touch input is off, with a note listing what the mode turns off. Screenshot to follow before this leaves draft.

The gesture state machine treats a single pointer as a trackpad: a stroke
that moves more than tapMaxDistance before longPressTime elapses becomes a
scroll, so drawing with a stylus pans the canvas instead of leaving a line.

Pen / Draw Mode routes a single pointer straight onto the left button —
down presses immediately, move drags, up releases — so a stroke draws. Two
pointers are dispatched before the mode is consulted, leaving two-finger
scroll and pinch untouched for panning and zooming. Off by default.

Also releases a held left button on every path where a stroke can end
without its touch-up: client disconnect, stopServer, touch input turned
off, and a second finger landing mid-stroke. That could already strand the
button down with long-press dragging; pen mode makes a held button the
normal state of every stroke, so it would happen constantly.

Direct-pointer input only — the touch protocol carries no pressure or
tilt, so this does not close out the planned stylus support.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 2, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the tranvuongquocdat2-7001's projects Team on Vercel.

A member of the Team first needs to authorize it.

A press has to declare its click count when it is posted, and pen mode
presses on contact, so it cannot decide on release the way the trackpad
path does. penDown now compares the contact against the previous tap
using the existing doubleTapMaxTime/doubleTapMaxDistance thresholds and
posts click 2 when it lands inside both; penUp releases with the same
count. Only a contact that stays within tapMaxDistance for less than
tapMaxTime can anchor the next double tap, so a drawn stroke ending near
an earlier tap cannot chain into one.

Without this, tapping twice sent two independent clicks and opening a
file in Finder or expanding a window was impossible with the mode on.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Synthesize touch drag as mouse drag – enable stylus/finger drawing

1 participant