Bind.Remap(from, to): a declarative one-line key-to-key remap.OnDown(key)/OnUp(key): returntrueto let a key pass through,falseto swallow it. Send your replacement withHID.Down/HID.Up/HID.Press.Input.IsDown(key): test whether a physical key is currently held, which is how you build chords, modifier holds, and layers.
Single-key remap
Bind.Remap takes the key you press and the key you want sent in its place: no
hooks, no state. Caps Lock becomes Escape; your real Escape is untouched.
Bind.Remap returns a handle, so you can toggle a remap at runtime with
:disable() and :enable(). Here a hotkey flips it live, and the handle reports
its state through .enabled.
OnDown / OnUp and decide per event. The remaining
recipes all use that form.
Chords and combos
A chord fires one action only when several keys are held together. Printable keys need to be deferred: if the first key passes through immediately, it has already typed before the second key completes the chord. This example holds J and K until release, emits Escape when both are down, and emits a single key on release when no chord formed.Input.IsDown("LCtrl") and emit a keyboard combo with the +
syntax:
Modifier hold
A modifier hold gives one key two jobs: tap it for its normal value, hold it to change what other keys do. Track when the key went down and whether another key was used while it was held. On release, if nothing else fired and the hold was short, send the tap.usedAsMod prevents a stray Space when you genuinely used the hold, and TAP_MS
keeps a long, lone hold from emitting a late Space.
Hold-to-access layer
A layer is a modifier hold scaled up: hold one key to expose an alternate set of keys, release it to return to normal. Keep the mappings in a table so adding a key is a one-line edit.Input.IsDown(layerKey), every other key behaves
normally the instant you let go. To make it app-aware (active only in one program),
wrap the body in a System.Window() check:
Opposing-key resolution (last pressed wins)
For movement keys mapped to opposite directions, such as left and right or up and down, holding both at once is ambiguous: the two presses cancel and you stop. One way to resolve it deterministically: when two opposing directions are held at once, the most recently pressed one is active. Release the newer key and the older one, still held, takes over again. Record the order in which each key of an opposing pair went down, then send only the winner and suppress its opposite.pressedAt stores when each key last went down,
activeOf picks the larger timestamp, and refresh makes the live output match.
Releasing the newer key calls refresh on the survivor so the older direction
resumes with no extra tap. OnStop releases both outputs when the script stops.
See Platforms for the full capability matrix.