Skip to content

Input and keybinds

Status: Partly implemented. Keybinds (cl_keybind_register, consume_click, is_down, cl_keybind_key) and the cancellable client.key event. Mod keybinds are Controls screen entries: the option key.<ns>.<path> under the desc’s category (a translation key, else the text, else the mod’s name), named by the lang entry or label; players rebind them to any key or mouse button (key.mouse.left, key.mouse.4, …), and the binding is saved in options.txt. Clicks come from the real key events (like KeyMapping.click); in-game keybinds are released when a screen opens. Mouse and character events, modifier keys on keybinds, toggle keybinds, reading vanilla keybinds, the clipboard and synthesized input are Planned.

Function table: keybind. Guide: Keybinds. Client only.

Keybinds

typedef struct cl_keybind_desc {
    uint32_t       struct_size;
    cl_str         id;            // "my_mod:zoom" -> the option key.my_mod.zoom
    cl_str         default_key;   // "key.keyboard.z", "key.mouse.4", "key.keyboard.unknown" (unbound)
    cl_str         category;      // "key.category.my_mod" (a lang key) or plain text; "" = the mod's name
    cl_key_context context;       // CL_KEYCTX_IN_GAME (default), CL_KEYCTX_GUI, CL_KEYCTX_ANY
    cl_str         label;         // the name when there is no lang entry key.<ns>.<path>
} cl_keybind_desc;
/* CL_KEYBIND_DESC_INIT */

cl_result cl_keybind_register(const cl_keybind_desc* desc, cl_keybind* out);   // MAIN (client setup)
bool      cl_keybind_consume_click(cl_keybind k);     // client TICK: true once per press
bool      cl_keybind_is_down(cl_keybind k);
cl_result cl_keybind_key(cl_keybind k, char* buf, size_t cap, size_t* out_len);   // the bound key, "key.keyboard.r"

The client.key event

Field
key GLFW key code (65 = A, 256 = Escape), the numbering vanilla stores
scancode the platform scan code
action 1 press, 0 release, 2 repeat
modifiers GLFW modifier bits (1 shift, 2 control, 4 alt)
screen_open whether a screen is open

Cancelling a press consumes it before the game and screens see it. Context: RENDER.

Bindings

C C++ Lua
cl_keybind_register(&d, &k) clight::keybind::add("my_mod:zoom", "key.keyboard.z", [] { ... }, {.category, .label, .context}) → Expected<Keybind> (the function runs once per press) local k = cl.keybind.register{ id = "my_mod:zoom", default_key = "key.keyboard.z", category = "My Mod" }
cl_keybind_consume_click(k) while (k.consume_click()) zoom();, or k.on_press(fn) → Subscription while k:consume_click() do zoom() end
cl_keybind_is_down(k) k.is_down() k:is_down()
cl_keybind_key(k, ...) k.key() → Expected<std::string> k:key()

Example (Lua)

local zoom
cl.on("lifecycle.client_setup", function()
  zoom = cl.keybind.register{ id = "my_mod:zoom", default_key = "key.keyboard.z", label = "Zoom" }
end)

cl.on("tick.client_post", function()
  if zoom then
    while zoom:consume_click() do cl.client.action_bar("Zoom!") end
  end
end)

Planned

Mouse button, scroll, mouse move and character events; keybinds with modifier keys and toggle mode; reading vanilla keybinds (key.jump); the key’s display name; physical key and mouse state; the clipboard (os.clipboard to read); synthesized key presses and movement behind the input.synthesize capability.