Modules

Keymap

moduleSource

Available on macOS, Linux, Windows

#import "Keymap";

Key bindings that you can load from a text file.

Build a Keymap_Set with add_keymap, register the procedures a binding may name with add_proc, load bindings with load_from_memory or load_from_file, then pass each Event from the Input module to handle_event. It returns true when a binding took it.

After a [1] version line, a binding is a key with optional S-, C- and A- prefixes (shift, control, alt), then either a procedure name or : and a command string. [name] starts the bindings of a keymap.

Example↗
#import "Input";

set: Keymap_Set;
map := add_keymap(*set, "editor");
set.default_keymap = map;
add_proc(map, "save", () { /* runs on C-s */ });
assert(load_from_memory(*set, "[1]\n[editor]\nC-s save\n"));

event: Event;
event.type = .KEYBOARD;
event.key_code = cast(Key_Code) #char "S";
event.key_pressed = 1;
event.ctrl_pressed = true;
assert(handle_event(*set, event));
reset_keymaps(*set);

Procedures#

Keymap actions#

(set: *Keymap_Set, section_name: string) -> *Keymap

Adds an empty keymap named section_name to the set and returns it. The name is what a [section] line in a bindings file refers to.

set: Keymap_Set;
map := add_keymap(*set, "editor");
assert(map.section_name == "editor" && map.enabled);
↗
(keymap: *Keymap)

Clears the bindings of one keymap and frees them. Keeps the registered procedures.

(set: *Keymap_Set, keymap: *Keymap, value: bool)

Turns a keymap on or off. A disabled keymap is skipped by handle_event.

set: Keymap_Set;
map := add_keymap(*set, "game");
enable(*set, map, false);
assert(!map.enabled);
↗
add_proc2 overloadsSource
(keymap: *Keymap, name: string, proc: Key_Press_Proc)
(keymap: *Keymap, name: string, proc: Key_Hold_Proc)

Registers a procedure under name so bindings can refer to it. Pass a plain procedure for a press, or one that takes a bool for a key that is held.

set: Keymap_Set;
map := add_keymap(*set, "game");
add_proc(map, "jump", () { /* ... */ });
add_proc(map, "run", (down: bool) { /* ... */ });
assert(map.procs.count == 2);
↗
(keymap: *Keymap, key: Key_Code, modifier_flags: Event.Modifier_Flags, respect_ignore_modifier_keys: bool, command: string, is_proc: bool) -> (success: bool, error_type: Add_Mapping_Error_Type)

Binds key with the given modifiers to a registered procedure (is_proc) or a command string. Rebinding the same key and modifiers replaces the old binding. Returns whether it worked, and if not, why. Set respect_ignore_modifier_keys to false to have the binding ignore the keymap's ignore_modifier_keys setting.

#import "Input";

set: Keymap_Set;
map := add_keymap(*set, "game");
add_proc(map, "jump", () { /* ... */ });

flags: Event.Modifier_Flags;
ok, reason := add_mapping(map, .SPACEBAR, flags, true, "jump", true);
assert(ok);
ok, reason = add_mapping(map, .ENTER, flags, true, "missing", true);
assert(!ok && reason == .UNKNOWN_COMMAND);
reset_keymaps(*set);
↗
(set: *Keymap_Set, event: Event) -> bool

Runs the binding that matches event in the first enabled keymap that has one. Returns true when one did, so the caller can skip its own handling. Only keyboard and mouse wheel events match.

(source: *Keymap, dest: *Keymap)

Makes dest a copy of source: its bindings, procedures and settings. Command strings are copied.

Keymap text#

(set: *Keymap_Set, memory: string, short_name := "unnamed", full_path := "(no path)") -> bool
(keymap: *Keymap, memory: string, short_name: string, full_path: string, optional := false) -> bool

Reads bindings from memory into the set. Returns false if any line was invalid; the valid ones still apply.

set: Keymap_Set;
map := add_keymap(*set, "game");
set.default_keymap = map;
add_proc(map, "jump", () { /* ... */ });
assert(load_from_memory(*set, "[1]\nSpace jump\nS-F5 jump\n"));
assert(map.mappings.count == 2);
assert(!load_from_memory(*set, "[1]\nNOT_A_KEY jump"));
reset_keymaps(*set);
↗
(set: *Keymap_Set, short_name: string, filename: string, optional := false) -> bool
(keymap: *Keymap, short_name: string, full_path: string, optional := false) -> bool

Reads bindings from a file into the set, in the format of load_from_memory. Returns false when the file cannot be read or has an invalid line. With optional, a missing file is not an error.

set: Keymap_Set;
map := add_keymap(*set, "game");
set.default_keymap = map;
add_proc(map, "jump", () { /* ... */ });
load_from_file(*set, "keys", "keys.txt", optional = true);
↗

This one is only checked to compile, not run.

(set: *Keymap_Set, filename: string)
(keymap: *Keymap, filename: string)

Writes the bindings of the set to a file, so load_from_file can read them back.

Types#

:: #type (bool)

A procedure for a key that is held: called with true when the key goes down, false when it is released.

:: struct

A group of keymaps. handle_event tries each enabled one in turn; default_keymap receives bindings that appear before any [section] line.

keymaps: Bucket_Array(Keymap, 16, true)
default_keymap: *Keymap
:: struct

One section of bindings, plus the procedures they can name.

procs: [..] Proc_Info
mappings: [..] Single_Key_Mapping
command_string_proc: (command: string)
ignore_modifier_keys: := false
section_name: string
enabled: := true
:: struct

One binding: a key, its modifiers, and the procedure or command string it runs.

utf32: u32
respect_ignore_modifier_keys: := true
toggled_on: := false
modifier_flags: Modifier_Flags
command_string: string
proc_index: s32
:: enum

Why add_mapping refused a binding.

NO_INFORMATION_ABOUT_THE_ERROR
NONSENSICAL_MODIFIERS
UNKNOWN_COMMAND
NO_ERROR