如何将 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 })
}

来源:keys.rs in broot