Crates.io | crokey |
lib.rs | crokey |
version | 1.1.0 |
source | src |
created_at | 2022-01-30 17:29:44.993941 |
updated_at | 2024-08-12 08:55:30.449064 |
description | Parse and describe keys - helping incorporate keybindings in terminal applications |
homepage | |
repository | https://github.com/Canop/crokey |
max_upload_size | |
id | 524128 |
size | 76,106 |
Crokey helps incorporate configurable keybindings in crossterm based terminal applications by providing functions
A KeyCombination
is made of 1 to 3 "normal" keys with some optional modifiers (alt, shift, ctrl).
It can be parsed, ergonomically built with the key!
macro, obtained from key events.
With a Combiner
, you can change raw Crossterm key events into key combinations.
When the terminal is modern enough and supports the Kitty protocol, complex combinations with up to three non-modifier keys may be formed, for example Ctrl-Alt-Shift-g-y
or Space-!
.
For standard ANSI terminals, only regular combinations are available, like Shift-o
, Ctrl-Alt-Shift-g
or i
.
The combiner works in both cases:
if you presses the ctrl
, i
, and u
keys at the same time, it will result in one combination (ctrl-i-u
) on a kitty-compatible terminal, and as a sequence of 2 key combinations (ctrl-i
then ctrl-u
assuming you started pressing the i
before the u
) in other terminals.
The print_key
example shows how to deal with that:
let fmt = KeyCombinationFormat::default();
let mut combiner = Combiner::default();
let combines = combiner.enable_combining().unwrap();
if combines {
println!("Your terminal supports combining keys");
} else {
println!("Your terminal doesn't support combining non-modifier keys");
}
println!("Type any key combination");
loop {
terminal::enable_raw_mode().unwrap();
let e = read();
terminal::disable_raw_mode().unwrap();
match e {
Ok(Event::Key(key_event)) => {
if let Some(key_combination) = combiner.transform(key_event) {
match key_combination {
key!(ctrl-c) | key!(ctrl-q) => {
println!("quitting");
break;
}
_ => {
println!("You typed {}", fmt.to_string(key_combination));
}
}
}
},
...
}
}
Those strings are usually provided by a configuration file.
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
assert_eq!(
crokey::parse("alt-enter").unwrap(),
KeyEvent::new(KeyCode::Enter, KeyModifiers::ALT),
);
assert_eq!(
crokey::parse("shift-F6").unwrap(),
KeyEvent::new(KeyCode::F(6), KeyModifiers::SHIFT),
);
Those key combinations are parsed at compile time and have zero runtime cost.
They're efficient and convenient for matching events or defining hardcoded keybindings.
match key_event.into() {
key!(ctrl-c) => {
println!("Arg! You savagely killed me with a {}", fmt.to_string(key_event).red());
break;
}
key!(ctrl-q) => {
println!("You typed {} which gracefully quits", fmt.to_string(key_event).green());
break;
}
_ => {
println!("You typed {}", fmt.to_string(key_event).blue());
}
}
Complete example in /examples/print_key
:
The key!
macro can be called in const contexts:
const quit: KeyCombination = key!(ctrl-q);
use crokey::*;
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
// The default format
let format = KeyCombinationFormat::default();
assert_eq!(format.to_string(key!(shift-a)), "Shift-a");
assert_eq!(format.to_string(key!(ctrl-c)), "Ctrl-c");
// A more compact format
let format = KeyCombinationFormat::default()
.with_implicit_shift()
.with_control("^");
assert_eq!(format.to_string(key!(shift-a)), "A");
assert_eq!(format.to_string(key!(ctrl-c)), "^c");
With the "serde" feature enabled, you can read configuration files in a direct way:
use {
crokey::*,
crossterm::event::KeyEvent,
serde::Deserialize,
std::collections::HashMap,
};
#[derive(Debug, Deserialize)]
struct Config {
keybindings: HashMap<KeyCombination, String>,
}
static CONFIG_HJSON: &str = r#"
{
keybindings: {
a: aardvark
shift-b: babirussa
ctrl-k: koala
alt-j: jaguar
}
}
"#;
let config: Config = deser_hjson::from_str(CONFIG_HJSON).unwrap();
let key: KeyCombination = key!(shift-b);
assert_eq!(
config.keybindings.get(&key).unwrap(),
"babirussa",
);
You can use any Serde compatible format such as JSON or TOML.
Crokey includes and reexports Crossterm, so you don't have to import it and to avoid conflicts.