如何将 TOML 配置文件中的字符反序列化为 crossterm::event::KeyCode?

问题描述

我有一个 .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 })
}

来源:keys.rs in broot