Skip to content

web: an Apple Pencil is the mouse, not a finger - #600

Merged
foxnne merged 2 commits into
mainfrom
web/stylus-is-mouse
Oct 19, 2026
Merged

foxnne merged 2 commits into
mainfrom
web/stylus-is-mouse

Conversation

@foxnne

@foxnne foxnne commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator

Fixes #568

What changes

On the web, an Apple Pencil is now the mouse, not a finger. iPad Safari sends a pencil as a
TouchEvent whose touch has touchType === "stylus", and web/web.js turned every touch into
a dvui touch button, so dvui.pointerKind() said .touch while drawing with a pencil: nothing
stayed hovered after a lift, and canvases panned as they do for a finger. Now a stylus touch goes
in as mouse motion to its position (in drawing-buffer pixels, as mousemove does) followed by a
left-button press or release, with the event's modifiers. It takes no touch slot. dvui then
reports .mouse, the same answer native gives once SDL's pen touches are excluded
(#563, backend/src/touch_slots.zig). Fingers, and touches with no touchType (browsers
other than Safari), are unchanged.

touchcancel now ends a touch the way touchend does. It had no handler, so a touch the system
took (a gesture, an alert) left its button held. A pencil's held mouse button would be worse,
because it keeps dragging until the next press.

The change is in fizzy's own web backend, not dvui-dev: fizzy builds dvui in custom mode and
links web/web.js + src/backend/WebBackend.zig (docs/DEPENDENCIES.md), so no dvui commit and
no repin are needed.

Considered and dropped: moving to Pointer Events and pointerType ("pen"/"touch"/
"mouse"). That would also cover Android styluses and pencil hover, but it replaces all of the
mouse and touch input paths (capture, the compatibility mouse events, the on-screen-keyboard
oskCheck that iOS only allows inside a touch handler) for a pencil fix. Worth doing as its own
change if Android stylus support is wanted.

SDK impact

  • None

Verified

  • A Node harness (not in the repo; fizzy has no JS test setup) loads web/web.js, runs
    Dvui.run with a stub canvas and wasm exports, and fires fake touch events at the handlers.
    A stylus start/move/end sends mouse motion at pixel coordinates, then a left press or release
    with the modifiers; a stylus takes no touch slot; a cancelled stylus releases the button.
    Finger and no-touchType touches still send touch press/motion/release at normalised
    coordinates; a cancelled finger releases its touch button. On main's web.js the stylus
    cases fail (they send touch events).
  • zig build, zig build test, zig build test-integration, zig build check-web,
    zig build test-sdk-version, zig build check-tests-reached on macOS, and
    scripts/check-examples.sh with EXAMPLES_DIR (example-app zig-0.17, example-plugin main:
    example-plugin has no zig-0.17 branch any more, so the script's default clone fails on main). scripts/check-fmt.sh flags only backend/src/platform/win32_titlebar.zig, which is
    unformatted on main too (main's Format job fails since windows: a dragged view is carried outside its window #463); this PR touches no Zig.
  • Web, by hand: on an iPad with an Apple Pencil in Safari, open this branch's build
    (zig build web, scripts/serve-web.sh, the Mac's address on :8765). Tap a tab or tree row
    with the pencil and lift: it stays lit (it went dark before). In a pixi canvas, a pencil stroke
    draws rather than pans. A finger tap on a tab still leaves it unlit.
  • macOS / Windows / Linux: not affected (web only).

Follow-ups

  • Pointer Events (pointerType) for Android styluses and pencil hover, if wanted.

🤖 Generated with Claude Code

iPad Safari sends a pencil as a TouchEvent whose touch has touchType
"stylus", and web.js made every touch a dvui touch button, so
dvui.pointerKind() said .touch while drawing with a pencil. A stylus
touch now goes in as mouse motion plus a left press or release, so it
reads .mouse as a native pen does (#563). touchcancel now ends a touch
like touchend, so a cancelled touch or pencil no longer stays held.

Fixes #568

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@foxnne
foxnne marked this pull request as ready for review October 18, 2026 23:41
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@foxnne
foxnne enabled auto-merge (squash) October 19, 2026 01:31
@foxnne
foxnne merged commit 09ff3b6 into main Oct 19, 2026
11 checks passed
@foxnne
foxnne deleted the web/stylus-is-mouse branch October 19, 2026 01:48
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.

web: an Apple Pencil counts as touch; treat a stylus as a pen

1 participant