Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit3bb1da2647

README.md

map

A record-shaped map: Zin.actions / Zin.axes entries organized per device class (kbm | gamepad | touch) with single-parent extends, materialized into an EFFECTIVE map and applied as one binding set at a time. Backs Zin.map.

An .inputMap asset with .inputBinding children is the map, and Zin.scheme is the live set: several maps are live at once and compose, each declaring the group its controls belong to and the groups it suppresses while live. Zin.map.bake(name) writes the map active here out as an .inputMap asset, with synthesis made explicit and editable. man topics/input covers the control model.

Resolution order per action/axis and device class:

  1. the map's own class bindings
  2. the extends parent's (recursively)
  3. synthesis from the kbm shape (touch class only)

A vector kbm binding synthesizes a touchStick; a boolean kbm binding synthesizes a touchButton; a vector-shaped mouseDelta synthesizes a touchDrag; scroll synthesizes a touchPinch; an axis-kind kbm binding and a single-axis mouseDelta are left unsynthesized (ambiguous which touch shape to guess). A synthesized touchButton carries priority = 100 — an authored B.touchButton's default priority (50) always outranks synthesis on the touch-controls overlay, so a hand-tuned scheme's own layout hints win over whatever filled a gap automatically.

A profile record (actions with bindings, axes with binding) is accepted anywhere a map record is — its bindings are treated as the kbm class.

Activation and the <axis>@<class> convention

activate flattens every class's bindings into each action/axis's single bindings list and applies it through Zin.profile, so any device fires the action. For axes — which evaluate exactly one binding — the primary slot is the first of kbm / touch / gamepad present; any OTHER class's binding registers as a class-suffixed sibling axis (look + look@touch). A consumer that wants both device values reads both names; a kbm-only world's primary axis (Zin.axes.value("move")) behaves identically whether or not a touch class exists.

Zin.profile.ensureActive("default") delegates to Zin.map.ensureActive() when the resolved scheme is the builtin default, so it carries every device class rather than kbm alone. Zin.map.ensureActive() / Zin.map.activate win regardless of call order (activate re-registers the flattened profile under the same name and forces a reactivate).

Exports

  • M.materialize(record: any) -> effective map — resolve extends + synthesize, without activating.
  • M.activate(record: any) -> effective map — materialize + apply as the live binding set (registers/activates a Zin.profile).
  • M.effective() -> effective map? — the active map's materialized form.
  • M.activeName() -> string? — the active map's name.
  • M.bindingsFor(eff, name, class) -> bindings? — one action/axis's bindings for one device class.
  • M.ensureActive() -> effective map — keep the current map, else activate @builtin::inputMaps.default.
  • M.bake(name: string) -> AssetRef — write the active effective map as a new .inputMap instance (asset.create("inputMap", name, { record = ... })).
  • M.addTouchButton(actionName, buttonOpts, emitKey?) -> binding — add a touchButton binding to an action's touch class on the live effective map (creating the action if absent) and re-activate. Used by Zin.touchControls.button.
  • M.removeTouchButton(actionName, binding) -> boolean — remove a binding added via addTouchButton and re-activate; drops the action entry once every class is empty.
  • M._reset() — test-only: clear active-map state.

Usage

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

Zin.map.ensureActive()
local eff = Zin.map.effective()
print(eff.actions.jump.classes.touch ~= nil) -- synthesized or explicit

-- Write the active scheme out as a control-asset map:
Zin.map.bake("my_scheme")