Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit3bb1da2647

README.md

gestures

Touch-gesture recognizers over the touch event stream + contact snapshot; backs Zin.gestures. Discrete gestures (tap, double-tap, long-press, swipe) fire subscriptions; continuous gestures (pinch, pan) expose per-tick deltas computed from the two-finger contact state. Advanced by the Zin.tick pipeline — dormant until ticked.

Discrete vs continuous

  • Discrete (tap / double-tap / long-press / swipe) — recognized on a release or hold-duration edge, delivered via on* subscriptions on the tick they fire.
  • Continuous (pinch / pan) — recomputed every tick from the two-finger contact positions; read via pinchDelta() / panDelta(), reset to zero at the start of each tick. The pair is formed from the contacts no on-screen widget is working, the ones Zin.touchControls says its stick and buttons hold having been left out, so a thumb on a movement stick is no part of a pinch.

Config

Zin.gestures.configure overrides recognition thresholds (unspecified fields keep their current values):

FieldDefaultMeaning
tapMaxDuration0.25 spress→release within this = tap candidate
tapMaxMovement16 pxtotal movement below this = tap candidate
doubleTapWindow0.3 stwo taps within this = double-tap
longPressDuration0.5 sheld past this (still) = long-press
swipeMinDistance60 pxrelease travel at/above this = swipe candidate
swipeMinVelocity800 px/srelease velocity at/above this = swipe

Exports

  • M.configure(opts: { [string]: number }) — override recognition thresholds.
  • M.getConfig() -> GestureConfig — current thresholds (a copy).
  • M.onTap(fn) -> number — subscribe to taps; fn(ev) with ev = { x, y, id, duration }.
  • M.onDoubleTap(fn) -> number — subscribe to double-taps; ev = { x, y, id }.
  • M.onLongPress(fn) -> number — subscribe to long-presses (fires once per contact); ev = { x, y, id }.
  • M.onSwipe(fn) -> number — subscribe to swipes (fires on release); ev = { direction, dx, dy, velocity, id }.
  • M.off(handle: number) -> boolean — unsubscribe a handle from any on* function.
  • M.pinchDelta() -> number — this tick's two-finger pinch delta in px (positive = spreading).
  • M.panDelta() -> (number, number) — this tick's two-finger pan delta (dx, dy) in px.
  • M._beginTick() — internal: clear per-tick continuous deltas; wired by Zin.tick.
  • M._observeEvent(ev: any) — internal: builds contact tracks and classifies discrete gestures on release; wired by Zin.tick.
  • M._advanceTime(dt: number) — internal: time-based recognition (long-press) + continuous deltas; wired by Zin.tick.
  • M._setWidgetContacts(ids: { [number]: boolean }) — internal: the contacts an on-screen widget is working; published each tick by Zin.touchControls.
  • M._pairDown() -> boolean — internal: whether two contacts no widget is working are down, which is the pair a two-finger gesture reads.
  • M._dispatchFires() — internal: deliver this tick's discrete gesture fires; wired by Zin.tick.
  • M._reset() — test-only: clear all tracks, fires, deltas, and subscriptions.

Types:

  • GestureConfig = { tapMaxDuration, tapMaxMovement, doubleTapWindow, longPressDuration, swipeMinDistance, swipeMinVelocity } (all number)

Usage

local Gestures = require("@builtin::modules.zinput.gestures")

Gestures.onTap(function(ev)
    print("tap at", ev.x, ev.y)
end)

Gestures.onSwipe(function(ev)
    if ev.direction == "left" then nextPage() end
end)

-- inside a per-frame update:
local zoom = Gestures.pinchDelta()
local dx, dy = Gestures.panDelta()

Notes

  • Pinch and pan deltas are zero unless exactly two contacts are down this tick that no on-screen widget is working.
  • Long-press fires once per contact — the contact must stay within tapMaxMovement for the full longPressDuration and is marked so it never also fires a tap on release.
  • Every qualifying release fires tap; the second tap of a double-tap fires doubleTap and tap on the same tick.
  • Handler errors during dispatch are caught and logged, not propagated.