问题描述
我有一个 .toml
配置文件,其中包含一些表示为字符的键绑定,我需要将该文件反序列化为一个结构,其中每个字段都是一个 crossterm::event::KeyCode
。我正在使用 toml
板条箱来解析字符串。我的想法是,也许有一种方法可以将字符串解析键反序列化为 char
,然后将它们映射到 KeyCode
。
config.toml:
key_0 = 'x'
key_bindings.rs:
use crossterm::event::KeyCode;
use serde::Deserialize;
#[derive(Deserialize,Debug)]
pub struct KeyBindings {
pub key_0: KeyCode,}
如何将 config.toml 文件反序列化为 KeyBindings
结构?
解决方法
据我所知,从字符串到 crossterm 键的解析都没有一个箱子,甚至没有一个规范化的格式。
您还必须处理 Crossterm 和您的应用程序的具体细节。这尤其取决于您想如何使用密钥。例如,如果您想参数化从事件到操作的映射,您可能需要稍微转换键,使其与 Crossterm 可能产生的内容相匹配。
您可能会使用这样的函数:
/// parse a string as a keyboard key definition.
///
/// About the case:
/// The char we receive as code from crossterm is usually lowercase
/// but uppercase when it was typed with shift (i.e. we receive
/// "g" for a lowercase,and "shift-G" for an uppercase)
pub fn parse_key(raw: &str) -> Result<KeyEvent,ConfError> {
fn bad_key(raw: &str) -> Result<KeyEvent,ConfError> {
Err(ConfError::InvalidKey {
raw: raw.to_owned(),})
}
let tokens: Vec<&str> = raw.split('-').collect();
let last = tokens[tokens.len() - 1].to_ascii_lowercase();
let mut code = match last.as_ref() {
"esc" => Esc,"enter" => Enter,"left" => Left,"right" => Right,"up" => Up,"down" => Down,"home" => Home,"end" => End,"pageup" => PageUp,"pagedown" => PageDown,"backtab" => BackTab,"backspace" => Backspace,"del" => Delete,"delete" => Delete,"insert" => Insert,"ins" => Insert,"f1" => F(1),"f2" => F(2),"f3" => F(3),"f4" => F(4),"f5" => F(5),"f6" => F(6),"f7" => F(7),"f8" => F(8),"f9" => F(9),"f10" => F(10),"f11" => F(11),"f12" => F(12),"space" => Char(' '),"tab" => Tab,c if c.len() == 1 => Char(c.chars().next().unwrap()),_ => {
return bad_key(raw);
}
};
let mut modifiers = KeyModifiers::empty();
if code == BackTab {
// Crossterm always sends the shift key with backtab
modifiers.insert(KeyModifiers::SHIFT);
}
for token in tokens.iter().take(tokens.len() - 1) {
match token.to_ascii_lowercase().as_ref() {
"ctrl" => {
modifiers.insert(KeyModifiers::CONTROL);
}
"alt" => {
modifiers.insert(KeyModifiers::ALT);
}
"shift" => {
modifiers.insert(KeyModifiers::SHIFT);
if let Char(c) = code {
if c.is_ascii_lowercase() {
code = Char(c.to_ascii_uppercase());
}
}
}
_ => {
return bad_key(raw);
}
}
}
Ok(KeyEvent { code,modifiers })
}