mirror of
https://github.com/k0kubun/xremap
synced 2024-11-02 03:40:25 +00:00
Some abstraction for further extension
This commit is contained in:
parent
10845ed7c0
commit
74ee0f36da
18
src/config/action.rs
Normal file
18
src/config/action.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use crate::config::keypress::KeyPress;
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::fmt::{Debug, Formatter};
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum Action {
|
||||||
|
KeyPress(KeyPress),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Action {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Action::KeyPress(key_press) => key_press.fmt(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
use crate::config::keypress::{parse_keypress, KeyPress};
|
use crate::config::action::Action;
|
||||||
|
use crate::config::keypress::KeyPress;
|
||||||
use crate::config::wm_class::WMClass;
|
use crate::config::wm_class::WMClass;
|
||||||
use serde::de::{value, Error, MapAccess, Visitor};
|
use serde::de::{Error, MapAccess, Visitor};
|
||||||
use serde::{Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@ -10,37 +11,37 @@ use std::fmt;
|
|||||||
pub struct Keymap {
|
pub struct Keymap {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
#[serde(deserialize_with = "keymap_remap")]
|
#[serde(deserialize_with = "keymap_remap")]
|
||||||
pub remap: HashMap<KeyPress, Vec<KeyPress>>,
|
pub remap: HashMap<KeyPress, Vec<Action>>,
|
||||||
pub wm_class: Option<WMClass>,
|
pub wm_class: Option<WMClass>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add Action trait
|
fn keymap_remap<'de, D>(deserializer: D) -> Result<HashMap<KeyPress, Vec<Action>>, D::Error>
|
||||||
|
|
||||||
fn keymap_remap<'de, D>(deserializer: D) -> Result<HashMap<KeyPress, Vec<KeyPress>>, D::Error>
|
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
struct KeymapRemap;
|
struct KeymapRemap;
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for KeymapRemap {
|
impl<'de> Visitor<'de> for KeymapRemap {
|
||||||
type Value = HashMap<KeyPress, Vec<KeyPress>>;
|
type Value = HashMap<KeyPress, Vec<Action>>;
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
formatter.write_str("map from string to string, array, or map")
|
formatter.write_str("map from string to strings or maps")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error>
|
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
|
||||||
where
|
where
|
||||||
M: MapAccess<'de>,
|
M: MapAccess<'de>,
|
||||||
{
|
{
|
||||||
let remap: HashMap<String, String> =
|
|
||||||
Deserialize::deserialize(value::MapAccessDeserializer::new(map))?;
|
|
||||||
let mut keymap = HashMap::new();
|
let mut keymap = HashMap::new();
|
||||||
|
|
||||||
for (from, to) in remap.iter() {
|
while let Some(keypress) = map.next_key::<KeyPress>()? {
|
||||||
let from_keymap = parse_keypress(&from).map_err(M::Error::custom)?;
|
let actions = if let Ok(to) = map.next_value::<Action>() {
|
||||||
let to_keymap = parse_keypress(&to).map_err(M::Error::custom)?;
|
vec![to]
|
||||||
keymap.insert(from_keymap, vec![to_keymap]);
|
} else {
|
||||||
|
let error: Box<dyn std::error::Error> = "map values must be strings or maps".into();
|
||||||
|
return Err(error).map_err(M::Error::custom);
|
||||||
|
};
|
||||||
|
keymap.insert(keypress, actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(keymap)
|
Ok(keymap)
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
use crate::config::key::parse_key;
|
use crate::config::key::parse_key;
|
||||||
use evdev::Key;
|
use evdev::Key;
|
||||||
use std::error::Error;
|
use serde::de;
|
||||||
|
use serde::de::Visitor;
|
||||||
|
use serde::{Deserialize, Deserializer};
|
||||||
|
use std::error;
|
||||||
|
use std::fmt::Formatter;
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Hash)]
|
#[derive(Debug, Eq, PartialEq, Hash)]
|
||||||
pub struct KeyPress {
|
pub struct KeyPress {
|
||||||
@ -18,7 +22,33 @@ enum Modifier {
|
|||||||
Windows,
|
Windows,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_keypress(input: &str) -> Result<KeyPress, Box<dyn Error>> {
|
impl<'de> Deserialize<'de> for KeyPress {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct KeyPressVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for KeyPressVisitor {
|
||||||
|
type Value = KeyPress;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
|
||||||
|
formatter.write_str("string or map")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> Result<KeyPress, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
parse_keypress(value).map_err(de::Error::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_any(KeyPressVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_keypress(input: &str) -> Result<KeyPress, Box<dyn error::Error>> {
|
||||||
let keys: Vec<&str> = input.split("-").collect();
|
let keys: Vec<&str> = input.split("-").collect();
|
||||||
if let Some((key, modifiers)) = keys.split_last() {
|
if let Some((key, modifiers)) = keys.split_last() {
|
||||||
let mut shift = false;
|
let mut shift = false;
|
||||||
@ -32,12 +62,18 @@ pub fn parse_keypress(input: &str) -> Result<KeyPress, Box<dyn Error>> {
|
|||||||
Some(Modifier::Control) => control = true,
|
Some(Modifier::Control) => control = true,
|
||||||
Some(Modifier::Alt) => alt = true,
|
Some(Modifier::Alt) => alt = true,
|
||||||
Some(Modifier::Windows) => windows = true,
|
Some(Modifier::Windows) => windows = true,
|
||||||
None => return Err(format!("unknown modifier: {}", modifier).into())
|
None => return Err(format!("unknown modifier: {}", modifier).into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: invalidate modifier keys in `key`?
|
// TODO: invalidate modifier keys in `key`?
|
||||||
Ok(KeyPress { key: parse_key(key)?, shift, control, alt, windows })
|
Ok(KeyPress {
|
||||||
|
key: parse_key(key)?,
|
||||||
|
shift,
|
||||||
|
control,
|
||||||
|
alt,
|
||||||
|
windows,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(format!("empty keypress: {}", input).into())
|
Err(format!("empty keypress: {}", input).into())
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
mod action;
|
||||||
mod key;
|
mod key;
|
||||||
mod keymap;
|
mod keymap;
|
||||||
mod keypress;
|
mod keypress;
|
||||||
|
Loading…
Reference in New Issue
Block a user