defmodule MobTouch do @moduledoc """ Stream the user's raw screen touches to a screen — a Mob plugin. Unlike per-widget `on_tap` (which only fires for a tapped button), this observes **every touch on the app's surface** and reports its coordinates, so you can build drawing, custom gestures, heatmaps, joysticks, and the like. It **observes without consuming**: the touches still reach the app's normal UI, so buttons and scrolling keep working while you stream. No runtime permission. Updates arrive in the screen's `handle_info/2`: handle_info({:touch, %{phase: phase, x: x, y: y, pointer: pointer, timestamp: ms}}, socket) * `phase` — `:down` (finger lands), `:move`, `:up` (finger lifts), or `:cancel` (the OS took the gesture, e.g. a system swipe). * `x`, `y` — **dp** (logical pixels), origin top-left of the app window; the same coordinate space the layout uses. * `pointer` — a stable id per finger across a gesture, so multi-touch is distinguishable. Single-finger use can ignore it. * `timestamp` — unix milliseconds. iOS: a passive `UIGestureRecognizer` on the key window. Android: a `Window.Callback` that observes `dispatchTouchEvent` and forwards it on. Call `stop/1` when you no longer need the stream — the observer stays installed (and keeps the screen's mailbox busy on every touch) until you do. """ @doc """ Start streaming touches to the calling screen. Options: * `:throttle_ms` — the minimum interval between `:move` deliveries (default `16`, ≈ 60 Hz). `:down`/`:up`/`:cancel` are never throttled. Raise it to cut mailbox traffic for coarse gestures; set `0` for every raw move. """ @spec start(Mob.Socket.t(), keyword()) :: Mob.Socket.t() def start(socket, opts \\ []) do throttle_ms = Keyword.get(opts, :throttle_ms, 16) :mob_touch_nif.touch_start(throttle_ms) socket end @doc "Stop streaming touches and remove the observer." @spec stop(Mob.Socket.t()) :: Mob.Socket.t() def stop(socket) do :mob_touch_nif.touch_stop() socket end end