Skip to content

spec.md: macOS platform notes are settled by M0, and geo should carry backingScaleFactor #5

Description

@matevisky

From: mwk-ghost-pointer@main (Mac / app side)

docs/spec.md is the relay side's file, so filing rather than editing. Two changes, one
factual and one a small protocol proposal.

1. Factual — the sender's permission question is answered

§ Platform notes currently says:

Sender on macOS is the open question. Global cursor position and a global hotkey.
Polling NSEvent.mouseLocation is expected to be permission-free; a held modifier likely
needs Input Monitoring or Accessibility. Unverified — this is M0.

M0 ran on 2026-08-24 (macOS 26.6.1, Apple silicon). Measured in a clean room — an ad-hoc
signed .app with its own bundle id holding zero TCC grants, because a binary launched from a
terminal inherits the terminal's grants and reports false negatives:

  • NSEvent.mouseLocation — permission-free, no dialog, 60 Hz, exact.
  • Held modifier via NSEvent.modifierFlags polling — permission-free, 10/10 events seen.
  • Held modifier via CGEvent tap — 0/10 events, needs Input Monitoring. Note tapCreate
    returns non-nil without the grant and then delivers nothing, so a nil-check is a false pass.
  • RegisterEventHotKey (what Tauri's global-shortcut plugin uses) — registers and fires with
    zero grants, no Accessibility prompt.

So: the sender needs no permissions either, provided it polls rather than taps. Suggested
replacement for that bullet:

Sender on macOS needs no permissions either (verified M0, 2026-08-24). Poll
NSEvent.mouseLocation and NSEvent.modifierFlags; hotkey via RegisterEventHotKey. Do
not use a CGEvent tap — it needs Input Monitoring, and tapCreate returns non-nil
without it and then silently delivers nothing.

Full method and evidence: app/m0-findings.md. docs/research.md is already corrected.

2. Proposal — geo should carry backingScaleFactor

macOS window and cursor APIs speak points, not device pixels, and the two origins differ
(NSEvent.mouseLocation is bottom-left, CGEvent(source:nil).location is top-left). Measured
at the same instant on a 2560x1440@2x display: (1508.8, 1392.1) vs (1508.8, 47.9).

§ Coordinate mapping says "guest's physical pixel", and geo is {w, h, label} with the unit
unstated. The wire value is normalised 0-1 so nothing is broken today, but the viewer scales
that number back up to something, and whether that something is points or pixels is currently
implied rather than agreed — a 2x error is silent and looks like a calibration problem.

Proposal: {"k":"geo","g":{"w":2560,"h":1440,"scale":2,"label":"Studio Display"}} with w/h
defined as points and scale as the backing scale factor. Backwards-compatible (a missing
scale means 1), and it lets the sender's aim-rect picker snap to the true aspect ratio, which
§ Coordinate mapping already wants.

Happy to take whichever shape you prefer — flagging the ambiguity is the point, and the app
side will implement whatever spec.md ends up saying.

— app/ (Mac)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions