| Crates.io | keymap |
| lib.rs | keymap |
| version | 1.0.0-rc.3 |
| created_at | 2023-07-30 08:24:26.630699+00 |
| updated_at | 2025-07-11 16:29:35.583285+00 |
| description | A lightweight key mapping library with compile-time validated derive macros and declarative configuration for multiple backends. |
| homepage | |
| repository | https://github.com/rezigned/keymap-rs |
| max_upload_size | |
| id | 929807 |
| size | 120,768 |
keymap-rs is a lightweight and extensible key mapping library for Rust that simplifies input processing for terminal user interfaces (TUIs), WebAssembly (WASM) applications, and more. It parses keymaps from derive macros or configuration files and maps them to actions from various input backends, including crossterm, termion, and wasm.
a), combinations (ctrl-b), and multi-key sequences (ctrl-b n).@upper â Uppercase letters@lower â Lowercase letters@alpha â All alphabetic characters@alnum â Alphanumeric characters@any â Match any keykeymap_derive macro validates key syntax at compile time, preventing runtime errors.crossterm, termion, and wasm.See keymap-rs in action with the WASM example:
Add keymap to your Cargo.toml, enabling the feature for your chosen backend:
cargo add keymap --feature {crossterm | termion | wasm}
The easiest way to get started is with the keymap::KeyMap derive macro.
Define your actions:
use keymap::KeyMap;
/// Application actions.
#[derive(KeyMap, Debug, PartialEq, Eq)]
pub enum Action {
/// Quit the application.
#[key("q", "esc")]
Quit,
/// Move left.
#[key("left", "h")]
Left,
/// Move right.
#[key("right", "l")]
Right,
/// Jump.
#[key("space")]
Jump,
}
Use the generated keymap:
The KeyMap derive macro generates an associated keymap_config() method that returns a Config<Action>.
// Retrieve the config
let config = Action::keymap_config();
// `key` is a key code from the input backend, e.g., `crossterm::event::KeyCode`
match config.get(&key) {
Some(action) => match action {
Action::Quit => break,
Action::Jump => println!("Jump!"),
_ => println!("Action: {action:?} - {}", action.keymap_item().description),
}
_ => {}
}
You can also load keymaps from external files (e.g., config.toml). This is useful for user-configurable keybindings.
Example config.toml:
# Override or add new keybindings
Jump = { keys = ["j", "up"], description = "Jump with 'j' or up arrow!" }
Quit = { keys = ["@any"], description = "Quit on any key press." }
You have two ways to load this configuration:
Config<T>: Load from File OnlyThis deserializes only the keybindings from the configuration file, ignoring any #[key("...")] attributes on your enum.
// This config will only contain 'Jump' and 'Quit' from the TOML file.
let config: Config<Action> = toml::from_str(config_str).unwrap();
| Key | Action |
|---|---|
"j", "up" |
Jump |
@any |
Quit |
DerivedConfig<T>: Merge Derived and File ConfigsThis merges the keybindings from the #[key("...")] attributes with the ones from the configuration file. Keys from the external file will override any conflicting keys defined in the enum.
// This config contains keys from both the derive macro and the TOML file.
let config: DerivedConfig<Action> = toml::from_str(config_str).unwrap();
| Key | Action |
|---|---|
"j", "up" |
Jump |
"h", "left" |
Left |
"l", "right" |
Right |
@any |
Quit |
"q", "esc", "space" are ignored |
The keymap_derive macro validates all key strings at compile time, so you get immediate feedback on invalid syntax.
Invalid Key Example:
#[derive(keymap::KeyMap)]
enum Action {
// "enter2" is not a valid key.
#[key("enter2", "ctrl-b n")]
Invalid,
}
Compiler Error:
This code will fail to compile with a clear error message:
error: Invalid key "enter2": Parse error at position 5: expect end of input, found: 2
--> keymap_derive/tests/derive.rs:7:11
|
7 | #[key("enter2", "ctrl-b n")]
| ^^^^^^^^
You can also parse key strings directly into a KeyMap or a backend-specific key event.
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use keymap::{backend::crossterm::parse, Key, KeyMap, Modifier};
// Parse into a generic KeyMap
assert_eq!(
"ctrl-l".parse::<KeyMap>(),
Ok(KeyMap::new(Some(Modifier::Ctrl), Key::Char('l')))
);
// Or use the backend-specific parser
assert_eq!(
parse("ctrl-l").unwrap(),
KeyEvent::new(KeyCode::Char('l'), KeyModifiers::CONTROL)
);
For complete, runnable examples, check out the /examples directory, which includes demos for:
crosstermtermionwasmThis project is licensed under the MIT License.
Contributions, issues, and feature requests are welcome! Feel free to open an issue or submit a pull request.