Implement key parser

pull/39/head
Takashi Kokubun 2 years ago
parent d9127e8a90
commit 2ee85b8773
No known key found for this signature in database
GPG Key ID: 6FFC433B12EE23DD

@ -15,14 +15,14 @@ modmap:
not: jetbrains-idea
remap:
# Use Windows since Alt is annoying in Electron apps (Slack, Nocturn)
KanaHira: Windows
KatakanaHiragana: Windows
- name: Kana -> Alt
wm_class:
only: jetbrains-idea
remap:
# Use Alt since Windows is annoying in IDEA
KanaHira: Alt_L
KatakanaHiragana: Alt_L
keymap:
- name: Global
@ -105,8 +105,9 @@ keymap:
# workaround prefix key bug
M-r:
3: C-M-3
0: C-M-0
remap:
3: C-M-3
0: C-M-0
- name: Chrome, Slack (modified from Default)
wm_class:

@ -15,7 +15,7 @@ modmap:
only: jetbrains-idea
remap:
# Use Alt since Windows is annoying in IDEA
KanaHira: Alt_L
KatakanaHiragana: Alt_L
keymap:
- name: Global

@ -0,0 +1,34 @@
use evdev::Key;
use std::error::Error;
use std::str::FromStr;
pub fn parse_key(input: &str) -> Result<Key, Box<dyn Error>> {
// Everything is case-insensitive
let name = input.to_uppercase();
// Original evdev scancodes should always work
if let Ok(key) = Key::from_str(&name) {
return Ok(key);
}
// You can abbreviate "KEY_" of any "KEY_*" scancodes.
if let Ok(key) = Key::from_str(&format!("KEY_{}", name)) {
return Ok(key);
}
// xremap's custom aliases like k0kubun/karabiner-dsl
let key = match &name[..] {
"CTRL_R" => Key::KEY_RIGHTCTRL,
"CTRL_L" => Key::KEY_LEFTCTRL,
"SHIFT_R" => Key::KEY_RIGHTSHIFT,
"SHIFT_L" => Key::KEY_LEFTSHIFT,
"ALT_R" => Key::KEY_RIGHTALT,
"ALT_L" => Key::KEY_LEFTALT,
_ => Key::KEY_RESERVED,
};
if key != Key::KEY_RESERVED {
return Ok(key);
}
return Err(format!("unknown key '{}'", input).into());
}

@ -1,10 +1,12 @@
mod key;
extern crate serde_yaml;
use serde::de::{value, SeqAccess, Visitor};
use evdev::Key;
use serde::de::{value, Error, MapAccess, SeqAccess, Visitor};
use serde::{de, Deserialize, Deserializer};
use std::collections::HashMap;
use std::error::Error;
use std::{fmt, fs};
use std::{error, fmt, fs};
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
@ -16,7 +18,8 @@ pub struct Config {
#[derive(Debug, Deserialize)]
pub struct Modmap {
pub name: String,
pub remap: HashMap<String, String>,
#[serde(deserialize_with = "modmap_remap")]
pub remap: HashMap<Key, Key>,
pub wm_class: Option<WMClass>,
}
@ -27,21 +30,53 @@ pub struct Keymap {
pub wm_class: Option<WMClass>,
}
// TODO: validate only either `only` or `not` is set
#[derive(Debug, Deserialize)]
pub struct WMClass {
// TODO: validate only either `only` or `not` is set
#[serde(default, deserialize_with = "string_or_vec")]
pub only: Option<Vec<String>>,
#[serde(default, deserialize_with = "string_or_vec")]
pub not: Option<Vec<String>>,
}
pub fn load_config(filename: &str) -> Result<Config, Box<dyn Error>> {
pub fn load_config(filename: &str) -> Result<Config, Box<dyn error::Error>> {
let yaml = fs::read_to_string(&filename)?;
let config: Config = serde_yaml::from_str(&yaml)?;
return Ok(config);
}
fn modmap_remap<'de, D>(deserializer: D) -> Result<HashMap<Key, Key>, D::Error>
where
D: Deserializer<'de>,
{
struct ModmapRemap;
impl<'de> Visitor<'de> for ModmapRemap {
type Value = HashMap<Key, Key>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("map of string to string")
}
fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let remap: HashMap<String, String> =
Deserialize::deserialize(value::MapAccessDeserializer::new(map))?;
let mut key_remap = HashMap::new();
for (from, to) in remap.iter() {
let from_key = key::parse_key(&from).map_err(M::Error::custom)?;
let to_key = key::parse_key(&to).map_err(M::Error::custom)?;
key_remap.insert(from_key, to_key);
}
Ok(key_remap)
}
}
deserializer.deserialize_any(ModmapRemap)
}
fn string_or_vec<'de, D>(deserializer: D) -> Result<Option<Vec<String>>, D::Error>
where
D: Deserializer<'de>,
Loading…
Cancel
Save