如何将 TOML 配置文件中的字符反序列化为 crossterm::event::KeyCode?
How can I deserialize chars in a TOML config file into crossterm::event::KeyCode?
我有一个 .toml
配置文件,其中包含一些以字符表示的键绑定,我需要将该文件反序列化为一个结构,其中每个字段都是一个 crossterm::event::KeyCode
。我正在使用 toml
crate 来解析字符串。我的想法是,也许有一种方法可以将字符串解析键反序列化为 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
结构?
据我所知,既没有用于从字符串解析为交叉项键的 crate,也没有规范化格式。
您还必须处理 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 })
}
我有一个 .toml
配置文件,其中包含一些以字符表示的键绑定,我需要将该文件反序列化为一个结构,其中每个字段都是一个 crossterm::event::KeyCode
。我正在使用 toml
crate 来解析字符串。我的想法是,也许有一种方法可以将字符串解析键反序列化为 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
结构?
据我所知,既没有用于从字符串解析为交叉项键的 crate,也没有规范化格式。
您还必须处理 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 })
}