Skip to main content

Default map gesture switches

Shared pan, wheel and double-click policy without suppressing user events

SqsMap uses the MapLibre-style dragPan, scrollZoom, doubleClickZoom and keyboard names. Four default navigation switches share a pure Rust policy across native libraries, WASM and scripts. Cross-thread writes and authoritative queries require await, unlike MapLibre's synchronous handlers.

import {map} from 'sqsmap';
await map.dragPan.disable();
await map.scrollZoom.enable();
await map.doubleClickZoom.enable();
const enabled = await map.dragPan.isEnabled();
const policy = await map.sqs.gesturesState();
export default {enabled, policy};

Identical runnable input runs in standalone native one-shot/retained QuickJS and the browser script Worker. Complete HTML/CSS UI includes three controls, initialization, calls and destruction. Applications own UI. The standalone SDK uses view.dragPan and corresponding handlers plus view.gesturesState().

Disabling navigation preserves pointer notifications such as mousedown/click and programmatic camera calls. Disabling a drag cancels its navigation; re-enabling requires a new press. Double-click zooms one level around the clicked position; Shift double-click zooms out. Wheel delta uses logical pixels and keeps the ground anchor under the cursor. Single-pointer dragging does not imply two-finger gesture support.

Only parameterless enable/disable/isEnabled/isActive are accepted. Unknown handlers, options and extra arguments fail explicitly and preserve policy. Snapshots contain four switches, not activity. box selection, rotation and two-finger gestures remain subsequent work.

C uses sqsm_map_gesture_json with method and an empty args array, such as dragPan.disable or sqs.gesturesState. Requests are limited to1KiB. Foreign output is allocated before write commit; failed outputs are zeroed. SQSM_MAP_GESTURE_POLICY=32768, ABI remains1. Native shells honor policy when adapting physical input; an offscreen core does not provide windows or system permissions. Browser capabilities.gesturePolicy reflects matching WASM support; old SDKs/libraries fail explicitly.

Linux egui input frames and browser/Worker results are recorded separately. Mobile hosts, Windows/macOS, full desktop GUI and hardware backends remain pending. Fullscreen/location permissions and UI appearance belong to the host.

Reference: MapLibre DragPanHandler, ScrollZoomHandler, DoubleClickZoomHandler.

Policy change events

Use map.on('sqs.gestureschange', event => ...) to update your own UI. event.gestures is the complete, immutable four-switch policy at that mutation. Later writes never modify historical events. Subscribe, then query the initial state; initial state is not replayed. A successful changed policy emits once. Idempotent and failed writes emit nothing.

import {map} from 'sqsmap';
export const sessionMode = 'persistent';
const subscription = map.on('sqs.gestureschange', event => {
  console.log('Navigation policy changed', event.gestures);
});
console.log('Initial policy', await map.sqs.gesturesState());
export default {ready: true};
// Stopping the retained session releases listeners; unsubscribe() releases early.

Identical event acceptance script runs in real retained native QuickJS and browser main/strict Worker script hosts. Copyable HTML/CSS includes buttons, external writes, UI synchronization, listeners and teardown. The independent SDK supports view.on('sqs.gestureschange', ...) and view.onGesturesChange, whose result is an unsubscribe function. Script map.on returns a subscription with unsubscribe().

C runtime flag SQSM_MAP_GESTURE_EVENTS=65536 advertises notices carried by gestureEvent.gestures in the existing event pump. At 128 discrete notices, changed writes return RESOURCE_LIMIT without committing policy. Drain then retry. WASM/SDK capabilities.gestureEvents reflects actual support. Caller-owned C output survives destruction and is freed once. One-shot native scripts do not provide retained subscriptions. Remaining handlers are still pending.

Recognized input activity

await map.dragPan.isActive(), await map.scrollZoom.isActive() and await map.doubleClickZoom.isActive() differ from isEnabled. Programmatic camera animation is not physical input. A held drag becomes active after recognition; release, cancellation or lost capture ends it. Disabling clears activity immediately. Enabling never resumes an old drag. Editing, offline selection and panel-blocked input are excluded from default navigation.

Current browser/desktop wheel and double-click processing is instantaneous, so queries after processing return false. This differs from some sustained/inertial MapLibre behavior. SqsMap does not invent a timeout to pretend a gesture is active. Query camera animation separately with isMoving/isZooming. Activity queries require await, accept no arguments and do not mutate the map, command watermark or policy notices.

import {map} from 'sqsmap';
const enabled = await map.dragPan.isEnabled();
const active = await map.dragPan.isActive();
export default {enabled, active};

Identical runnable input covers native one-shot/retained QuickJS and browser main/strict Worker queries, including the difference from animation. Complete HTML/CSS includes input listeners, explicit queries, controls and teardown. Independent SDK users call view handlers' isActive(). WASM capability gestureActivity reflects actual bindings.

C runtime flag SQSM_MAP_GESTURE_ACTIVITY=131072 enables sqsm_map_gesture_input_json: only handler and active fields, at most1KiB, with acknowledged handler/active output. Shells report begin after actual recognition and end on release/cancel/focus loss. Delayed begins for disabled handlers acknowledge false. The API records input, does not move the camera or provide windows/UI. Failed output allocation never commits activity; caller-owned buffers survive map destruction. Query handler.isActive through sqsm_map_gesture_json. ABI remains1.

Local desktop acceptance uses actual egui input processing frames; browser acceptance uses physical CDP mouse input and UA capture loss. C checks host-reported input, not operating-system touch observation. Full desktop GUI, Windows/macOS, mobile and hardware devices remain pending. Rotation, box selection and multi-pointer processing remain subsequent tasks.

Focused keyboard navigation

await map.keyboard.enable()/disable()/isEnabled()/isActive() shares policy and historical change notices. Keyboard guide includes actual focus rules, connected pan/zoom shortcuts and explicit MapLibre differences. Shift-left/right rotates15 degrees. enableRotation/disableRotation controls all arrow panning and bearing rotation through the independent keyboardRotation option, preserving zoom. Shift-up/down pitch and globe/3D keyboard input remain pending.