diff options
author | Wez Furlong <wez@wezfurlong.org> | 2019-12-31 08:25:40 -0800 |
---|---|---|
committer | Wez Furlong <wez@wezfurlong.org> | 2019-12-31 08:27:33 -0800 |
commit | 7f2cb52d535ece13ff7d50012774d43936d69d89 (patch) | |
tree | d432529bb842d8a3317caac928e6f7cfedd983b1 /src/mapping.rs | |
parent | 3219978c3fe2db287cd4dd9aa3a4c67811ae80f2 (diff) |
Add config file parsing and loading
Diffstat (limited to 'src/mapping.rs')
-rw-r--r-- | src/mapping.rs | 109 |
1 files changed, 108 insertions, 1 deletions
diff --git a/src/mapping.rs b/src/mapping.rs index 6fa655e..34a9615 100644 --- a/src/mapping.rs +++ b/src/mapping.rs @@ -1,5 +1,36 @@ -pub use evdev_rs::enums::{EventCode, EV_KEY as KeyCode}; +use anyhow::Context; +pub use evdev_rs::enums::{EventCode, EventType, EV_KEY as KeyCode}; +use serde::Deserialize; use std::collections::HashSet; +use std::path::Path; +use thiserror::Error; + +#[derive(Debug, Clone)] +pub struct MappingConfig { + pub device_name: String, + pub mappings: Vec<Mapping>, +} + +impl MappingConfig { + pub fn from_file<P: AsRef<Path>>(path: P) -> anyhow::Result<Self> { + let path = path.as_ref(); + let toml_data = std::fs::read_to_string(path) + .context(format!("reading toml from {}", path.display()))?; + let config_file: ConfigFile = + toml::from_str(&toml_data).context(format!("parsing toml from {}", path.display()))?; + let mut mappings = vec![]; + for dual in config_file.dual_role { + mappings.push(dual.into()); + } + for remap in config_file.remap { + mappings.push(remap.into()); + } + Ok(Self { + device_name: config_file.device_name, + mappings, + }) + } +} #[derive(Debug, Clone, Eq, PartialEq)] pub enum Mapping { @@ -13,3 +44,79 @@ pub enum Mapping { output: HashSet<KeyCode>, }, } + +#[derive(Debug, Deserialize)] +#[serde(try_from = "String")] +struct KeyCodeWrapper { + pub code: KeyCode, +} + +impl Into<KeyCode> for KeyCodeWrapper { + fn into(self) -> KeyCode { + self.code + } +} + +#[derive(Error, Debug)] +pub enum ConfigError { + #[error("Invalid key `{0}`")] + InvalidKey(String), + #[error("Impossible: parsed KEY_XXX but not into an EV_KEY")] + ImpossibleParseKey, +} + +impl std::convert::TryFrom<String> for KeyCodeWrapper { + type Error = ConfigError; + fn try_from(s: String) -> Result<KeyCodeWrapper, Self::Error> { + match EventCode::from_str(&EventType::EV_KEY, &s) { + Some(code) => match code { + EventCode::EV_KEY(code) => Ok(KeyCodeWrapper { code }), + _ => Err(ConfigError::ImpossibleParseKey), + }, + None => Err(ConfigError::InvalidKey(s)), + } + } +} + +#[derive(Debug, Deserialize)] +struct DualRoleConfig { + input: KeyCodeWrapper, + hold: Vec<KeyCodeWrapper>, + tap: Vec<KeyCodeWrapper>, +} + +impl Into<Mapping> for DualRoleConfig { + fn into(self) -> Mapping { + Mapping::DualRole { + input: self.input.into(), + hold: self.hold.into_iter().map(Into::into).collect(), + tap: self.tap.into_iter().map(Into::into).collect(), + } + } +} + +#[derive(Debug, Deserialize)] +struct RemapConfig { + input: Vec<KeyCodeWrapper>, + output: Vec<KeyCodeWrapper>, +} + +impl Into<Mapping> for RemapConfig { + fn into(self) -> Mapping { + Mapping::Remap { + input: self.input.into_iter().map(Into::into).collect(), + output: self.output.into_iter().map(Into::into).collect(), + } + } +} + +#[derive(Debug, Deserialize)] +struct ConfigFile { + device_name: String, + + #[serde(default)] + dual_role: Vec<DualRoleConfig>, + + #[serde(default)] + remap: Vec<RemapConfig>, +} |