Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit3bb1da2647

README.md

chords

Chord and sequence state machines. Two kinds:

  • sequence — ordered steps with a per-step window and an overall window (Konami-style codes).
  • simultaneous — N bindings pressed inside a tolerance window, order-insensitive (piano-chord / fighter-combo style).

Chords are edge-triggered — fired(name) is true for exactly one frame when the full pattern completes. A continuous combo like "Ctrl+S held" is a button control whose kbm class is B.modKey("Ctrl+S"): a chord recognizes a pattern over time, which is a different question from whether a combination is down right now.

Exports

Lifecycle:

  • M.define(spec: ChordSpec) — define / replace chords.
  • M.remove(name) / M.clear()
  • M.has(name) -> boolean / M.names() -> { string } / M.get(name) -> ChordDef?

Queries:

  • M.fired(name) -> boolean
  • M.progress(name) -> number (0..1)
  • M.cancel(name) — reset state.

Subscriptions:

  • M.onFire(name, callback, opts: OnFireOpts?) -> OnFireHandle
  • M.off(handle: OnFireHandle)

Tick hooks (called by Zin.tick):

  • M._beginTick() — clears per-frame fire flags.
  • M._observeEvent(ev) — advance state machines on an input event.
  • M._advanceTime(dt) — age out stale recognizers.
  • M._dispatchFires() — invoke onFire callbacks for chords that fired this tick.

Types:

  • ChordDef = { kind, context, steps?, stepWindowSec?, windowSec?, bindings?, toleranceSec? }
  • ChordSpec = { [string]: any }
  • OnFireOpts = { context: string?, once: boolean? }
  • OnFireHandle = { id: number, name: string, off: () -> () }

Usage

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

Zin.chords.define({
    konami = {
        kind = "sequence",
        steps = { B.key("ArrowUp"), B.key("ArrowUp"), B.key("ArrowDown"),
                  B.key("ArrowDown"), B.key("ArrowLeft"), B.key("ArrowRight"),
                  B.key("ArrowLeft"), B.key("ArrowRight"),
                  B.key("KeyB"), B.key("KeyA") },
        stepWindowSec = 0.5,
        windowSec     = 4.0,
    },
})

Zin.chords.onFire("konami", function() unlockBonus() end)

Notes

  • Without a tick host (or Zin.autoTick.start()) chords never fire — every state machine is dormant until Zin.tick drives it.
  • A wrong key in a sequence resets to step 0. If the wrong key happens to match step 1, the recogniser restarts from step 1 on the same event (so a long input run can self-recover).
  • For simultaneous chords, the tolerance window starts on the first matched press. If all bindings haven't matched before toleranceSec elapses the state resets — firstPressAt is reset too so the next press starts a fresh window.
  • Subscriber errors are caught and logged via log.warn.