summaryrefslogtreecommitdiff
path: root/src/mapping.rs
diff options
context:
space:
mode:
authorWez Furlong <wez@wezfurlong.org>2019-12-31 08:25:40 -0800
committerWez Furlong <wez@wezfurlong.org>2019-12-31 08:27:33 -0800
commit7f2cb52d535ece13ff7d50012774d43936d69d89 (patch)
treed432529bb842d8a3317caac928e6f7cfedd983b1 /src/mapping.rs
parent3219978c3fe2db287cd4dd9aa3a4c67811ae80f2 (diff)
Add config file parsing and loading
Diffstat (limited to 'src/mapping.rs')
-rw-r--r--src/mapping.rs109
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>,
+}