Repository navigation
API Input and Controls
Lua API / Input and controls
Native hotkeys create user-configurable commands in Minecraft's Controls screen. Named input maps instead separate
game actions from physical keys and mouse buttons; they can observe exact press/release transitions and consume an
event before Minecraft performs its normal movement, inventory, GUI, or world action. Legacy
key_input and mouse_input events remain observational and cannot consume native behavior.
On this page
Registers a keyboard command through ModLoader's native key system and returns a hotkey handle. The command appears in Minecraft's Controls screen, and a player's saved remap is restored on later launches. Use hotkeys for global mod commands that players should configure alongside Minecraft's own keys; use an input map when an action needs context priority, held/released state, mouse input, modifiers, or native-input consumption.
| Field | Required | Meaning |
|---|---|---|
key |
yes | Namespaced key, stored canonically as namespace:hotkey/name. |
label |
yes | User-facing name shown in Controls; at most 128 characters. |
default |
yes | One unmodified keyboard binding such as key.g; key.none starts unbound. |
repeatWhileHeld |
no | Invoke on each ModLoader input tick while held; default false invokes once per press. |
local openBuilder = betamoon.input:hotkey {
key = "mymod:open_builder",
label = "Open Builder",
default = "key.b",
}
openBuilder:on(function(event)
showBuilder()
end)The callback event has key, binding, and keyCode, where binding and keyCode reflect the player's current
Controls assignment. getBinding() returns the current normalized binding, isActive() reports whether the script
registration is live, on(nil) removes the callback, and close() detaches the registration. Hotkey callbacks follow
ModLoader's world-tick polling and do not consume Minecraft input; use a handled input-map action when consumption is
required. A callback error disables that callback and reports the script error without affecting other hotkeys.
ModLoader has no key-unregistration operation. Script unload therefore detaches the callback but retains a dormant
Controls entry for the rest of the Minecraft session. Redeclaring the same canonical key during hot reload reuses that
entry and preserves its current remap. Changing repeatWhileHeld for a retained key requires a Minecraft restart;
the label may change immediately. A changed default is used on a fresh process only when no saved assignment exists;
it never overwrites a player's remap.
Registers an owner-scoped map and returns an active input-map handle. key accepts namespace:name shorthand and is
stored canonically as namespace:input_map/name. Action names use lowercase letters, digits, _, and -.
| Field | Required | Meaning |
|---|---|---|
key |
yes | Namespaced input-map key. |
actions |
yes | Table from local action name to a binding string or { default = binding }. A binding may be a string or array. |
priority |
no | Default context priority, -10000 through 10000; default 0. |
captures |
no | Native families captured by the default context. |
local controls = betamoon.input:map {
key = "mymod:builder",
priority = 10,
actions = {
place = { default = "mouse.left" },
rotate = { default = "key.r" },
cancel = { default = "key.escape" },
zoom = { default = { "mouse.wheel_up", "mouse.wheel_down" } },
},
}controls.key is the canonical key. Duplicate keys, duplicate action names, overlapping bindings, unknown fields,
invalid devices, and maps outside a Lua script raise an error.
Bindings are case-insensitive when declared and are returned in normalized lowercase form.
| Form | Examples |
|---|---|
| Keyboard |
key.r, key.escape, key.space, key.f5
|
| Named mouse buttons |
mouse.left, mouse.right, mouse.middle
|
| Numbered mouse buttons |
mouse.button1 through mouse.button32; button 1 is the left button |
| Wheel |
mouse.wheel, mouse.wheel_up, mouse.wheel_down
|
| Required modifiers |
ctrl+key.r, shift+mouse.left, ctrl+shift+key.s
|
Required modifiers may be held in addition to other modifiers. For example, ctrl+key.r still matches while Shift is
also held. mouse.wheel reports the signed raw wheel delta; directional wheel bindings match only their direction.
Sets the default context's callback for an action and returns controls. Passing nil removes it. A callback runs
only for semantic transitions, not once per render frame or repeatedly while held.
controls:on("place", function(event)
if event.phase == "pressed" then
beginPlacement()
end
return betamoon.callbackResults.handled
end)The callback receives:
| Field | Meaning |
|---|---|
map, action
|
Canonical map key and local action name. |
phase |
pressed or released. Wheel input is a pressed pulse. |
pressed, held, released
|
State snapshot for the current input cycle. A wheel pulse is pressed and released, but not held. |
amount |
1/0 for digital input, or signed raw wheel delta. |
cycle |
Monotonic input-cycle number. |
device, code
|
Physical source. Omitted for a synthesized lifecycle release. |
Return callbackResults.pass or nil to continue to lower contexts and Minecraft. handled and deny both stop
lower input contexts and consume the native event; use handled for an action your game performed and deny for an
action intentionally refused. An error disables only that context and falls back to the next context or native input.
Returns a detached { cycle, pressed, held, released, amount } snapshot. pressed and released last for one input
cycle. held remains stable without invoking Lua repeatedly.
local movement = controls:getState("place")
if movement.held then
updatePreview()
endReturns an array of the action's current normalized binding strings.
Adds another context for the same map and returns a context handle. Options accept priority and captures. Higher
priority runs first; at equal priority, the newest active context runs first. Each context has token, priority,
on(action, callback), isActive(), and close().
local wheel = controls:activate {
priority = 100,
captures = { "movement", "look", "world_actions" },
}
wheel:on("cancel", function()
wheel:close()
return betamoon.callbackResults.handled
end)Capture names are:
| Family | Native behavior suppressed while active |
|---|---|
actions |
Native input for physical events matching this map's actions. |
movement |
Forward/back/strafe/jump/sneak key forwarding. |
look |
Mouse-derived player rotation. |
world_actions |
Attack, use, place, and held block breaking. |
inventory |
Inventory/drop keys, hotbar number keys, and wheel slot selection. |
gui |
Keyboard and mouse events while a GUI screen is open. |
Captures are independent: a spell wheel can suppress movement and look without blocking the inventory or every named action. Closing a context immediately reveals the next context.
Replaces the effective binding with a string or array and returns controls. By default, a physical binding that can
activate together with another action in the same map raises a conflict error. This includes aliases such as
mouse.left/mouse.button1 and modifier subsets such as key.r/ctrl+key.r. { allowConflict = true } permits it.
controls:rebind("rotate", "key.g")
controls:rebind("cancel", { "key.escape", "mouse.right" }, { allowConflict = true })Restores the declaration's default binding and returns controls. Rebinds are runtime values in this release; they
reset when the owning script unloads or reloads.
Input maps and contexts are cleaned up automatically on script unload. Hotkey callbacks are detached while their native Controls entries remain retained as described above. Focus, screen, world, and player replacement synthesize releases before physical state is cleared, preventing stuck held actions. A map supports at most 128 actions and eight effective bindings per action. The client supports up to 256 retained native hotkeys, 256 maps, 256 active contexts, and 1024 semantic transitions in one cycle.
- Installation
- Install scripts
- Getting started
- VS Code and LuaLS
- Examples
- Reload and compatibility
- Troubleshooting
- Changelog
Scripts and shared values
- Script lifecycle
- Packaged Lua mods
- Modules
- References and stacks
- Queries
- Overrides
- Minecraft constants
- Chat and positions
- Structured data
- Script configuration
- Particles
Blocks and items
- Multiblocks
- Blocks
- Block state and placement
- Block shapes and rendering
- Block callbacks
- Block ticks and redstone
- Items
- Fluids
- Item callbacks
- Tools and armor
- Materials
- Textures
Entities
- Entities
- Entity access and movement
- Entity lifecycle and data
- Entity health and loot
- Entity inventories and relationships
- Projectiles and pickups
- Entity presentation and sounds
- Living entities and AI
- Entity parts and sensors
Assets and audio
- Assets
- Models and animations
- Built-in Minecraft models
- Model appearances
- Blockbench workflow
- Audio
- Texture-pack overrides
Events and world actions
World generation
World systems
Inventories and screens
Recipes