mirror of https://github.com/k0kubun/xremap
Rollback to v0.1.5
parent
613555943d
commit
7ab1595836
@ -0,0 +1,6 @@
|
||||
modmap:
|
||||
- remap:
|
||||
Space:
|
||||
held: Shift_L
|
||||
alone: Space
|
||||
alone_timeout_millis: 500
|
@ -1,14 +1,80 @@
|
||||
use crate::config::key_press::KeyPress;
|
||||
use crate::config::key_press::{parse_key_press, KeyPress};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::config::keymap::deserialize_remap;
|
||||
use serde::Deserialize;
|
||||
use std::fmt::Debug;
|
||||
use crate::config::actions::Actions;
|
||||
use serde::de;
|
||||
use serde::de::{MapAccess, Visitor};
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use std::fmt::{Debug, Formatter};
|
||||
|
||||
// Values in `keymap.remap`
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Action {
|
||||
KeyPress(KeyPress),
|
||||
#[serde(deserialize_with = "deserialize_remap")]
|
||||
Remap(HashMap<KeyPress, Vec<Action>>),
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Action {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct ActionVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for ActionVisitor {
|
||||
type Value = Action;
|
||||
|
||||
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("string or map")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
let key_press = parse_key_press(value).map_err(de::Error::custom)?;
|
||||
Ok(Action::KeyPress(key_press))
|
||||
}
|
||||
|
||||
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
|
||||
where
|
||||
M: MapAccess<'de>,
|
||||
{
|
||||
let key = map.next_key::<String>()?;
|
||||
let action = match key.as_deref() {
|
||||
Some("remap") => {
|
||||
let mut action: HashMap<KeyPress, Vec<Action>> = HashMap::new();
|
||||
let remap = map.next_value::<HashMap<KeyPress, Actions>>()?;
|
||||
for (key_press, actions) in remap.into_iter() {
|
||||
let actions = match actions {
|
||||
Actions::Action(action) => vec![action],
|
||||
Actions::Actions(actions) => actions,
|
||||
};
|
||||
action.insert(key_press, actions);
|
||||
}
|
||||
Action::Remap(action)
|
||||
}
|
||||
Some(action) => return serde_error::<Self::Value, M>(&format!("unexpected action '{}'", action)),
|
||||
None => return serde_error::<Self::Value, M>("missing action"),
|
||||
};
|
||||
if let Some(key) = map.next_key::<String>()? {
|
||||
return serde_error::<Self::Value, M>(&format!(
|
||||
"only one action key is expected but also got: {}",
|
||||
key
|
||||
));
|
||||
}
|
||||
Ok(action)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(ActionVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serde_error<'de, V, M>(message: &str) -> Result<V, M::Error>
|
||||
where
|
||||
M: MapAccess<'de>,
|
||||
{
|
||||
let error: Box<dyn std::error::Error> = message.into();
|
||||
Err(error).map_err(de::Error::custom)
|
||||
}
|
||||
|
@ -0,0 +1,55 @@
|
||||
use crate::config::action::Action;
|
||||
use crate::config::key_press::parse_key_press;
|
||||
use serde::de;
|
||||
use serde::de::{value, MapAccess, SeqAccess, Visitor};
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use std::fmt::Formatter;
|
||||
|
||||
// Used only for deserializing Vec<Action>
|
||||
pub enum Actions {
|
||||
Action(Action),
|
||||
Actions(Vec<Action>),
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Actions {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct ActionsVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for ActionsVisitor {
|
||||
type Value = Actions;
|
||||
|
||||
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("strings or maps")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
let key_press = parse_key_press(value).map_err(de::Error::custom)?;
|
||||
Ok(Actions::Action(Action::KeyPress(key_press)))
|
||||
}
|
||||
|
||||
fn visit_seq<S>(self, seq: S) -> Result<Self::Value, S::Error>
|
||||
where
|
||||
S: SeqAccess<'de>,
|
||||
{
|
||||
let actions: Vec<Action> = Deserialize::deserialize(value::SeqAccessDeserializer::new(seq))?;
|
||||
Ok(Actions::Actions(actions))
|
||||
}
|
||||
|
||||
fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error>
|
||||
where
|
||||
M: MapAccess<'de>,
|
||||
{
|
||||
let action: Action = Deserialize::deserialize(value::MapAccessDeserializer::new(map))?;
|
||||
Ok(Actions::Action(action))
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(ActionsVisitor)
|
||||
}
|
||||
}
|
@ -1,26 +1,102 @@
|
||||
use crate::config::key::deserialize_key;
|
||||
use crate::config::action::serde_error;
|
||||
use crate::config::key::parse_key;
|
||||
use evdev::Key;
|
||||
use serde::Deserialize;
|
||||
use serde::de::{MapAccess, Visitor};
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use std::fmt::Formatter;
|
||||
use std::time::Duration;
|
||||
|
||||
static DEFAULT_ALONE_TIMEOUT_MILLIS: u64 = 1000;
|
||||
|
||||
// Values in `modmap.remap`
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum KeyAction {
|
||||
#[serde(deserialize_with = "deserialize_key")]
|
||||
Key(Key),
|
||||
MultiPurposeKey(MultiPurposeKey),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MultiPurposeKey {
|
||||
#[serde(deserialize_with = "deserialize_key")]
|
||||
pub held: Key,
|
||||
#[serde(deserialize_with = "deserialize_key")]
|
||||
pub alone: Key,
|
||||
#[serde(default = "default_alone_timeout_millis")]
|
||||
pub alone_timeout_millis: u64,
|
||||
pub alone_timeout: Duration,
|
||||
}
|
||||
|
||||
fn default_alone_timeout_millis() -> u64 {
|
||||
1000
|
||||
impl<'de> Deserialize<'de> for KeyAction {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct KeyActionVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for KeyActionVisitor {
|
||||
type Value = KeyAction;
|
||||
|
||||
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("string or map")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
let key = parse_key(value).map_err(serde::de::Error::custom)?;
|
||||
Ok(KeyAction::Key(key))
|
||||
}
|
||||
|
||||
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
|
||||
where
|
||||
M: MapAccess<'de>,
|
||||
{
|
||||
let mut held: Option<Key> = None;
|
||||
let mut alone: Option<Key> = None;
|
||||
let mut alone_timeout_millis: u64 = DEFAULT_ALONE_TIMEOUT_MILLIS;
|
||||
|
||||
while let Some(key) = map.next_key::<String>()? {
|
||||
match &key[..] {
|
||||
"held" => {
|
||||
let value: String = map.next_value()?;
|
||||
held = Some(parse_key(&value).map_err(serde::de::Error::custom)?)
|
||||
}
|
||||
"alone" => {
|
||||
let value: String = map.next_value()?;
|
||||
alone = Some(parse_key(&value).map_err(serde::de::Error::custom)?)
|
||||
}
|
||||
"alone_timeout_millis" => alone_timeout_millis = map.next_value()?,
|
||||
key => {
|
||||
return serde_error::<Self::Value, M>(&format!(
|
||||
"held, alone, or alone_timeout_ms is expected, but got: {}",
|
||||
key
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let held = match held {
|
||||
Some(held) => held,
|
||||
None => {
|
||||
return serde_error::<Self::Value, M>(
|
||||
"held is not specified in a multi-purpose remap of modmap",
|
||||
)
|
||||
}
|
||||
};
|
||||
let alone = match alone {
|
||||
Some(alone) => alone,
|
||||
None => {
|
||||
return serde_error::<Self::Value, M>(
|
||||
"alone is not specified in a multi-purpose remap of modmap",
|
||||
)
|
||||
}
|
||||
};
|
||||
let multi_purpose_key = MultiPurposeKey {
|
||||
held,
|
||||
alone,
|
||||
alone_timeout: Duration::from_millis(alone_timeout_millis),
|
||||
};
|
||||
Ok(KeyAction::MultiPurposeKey(multi_purpose_key))
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(KeyActionVisitor)
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,50 @@
|
||||
use crate::config::application::Application;
|
||||
use crate::config::key::deserialize_key;
|
||||
use crate::config::key::parse_key;
|
||||
use crate::config::key_action::KeyAction;
|
||||
use evdev::Key;
|
||||
use serde::de::{value, Error, MapAccess, Visitor};
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Modmap {
|
||||
#[serde(default = "String::new")]
|
||||
pub name: String,
|
||||
#[serde(deserialize_with = "deserialize_remap")]
|
||||
#[serde(deserialize_with = "modmap_remap")]
|
||||
pub remap: HashMap<Key, KeyAction>,
|
||||
pub application: Option<Application>,
|
||||
}
|
||||
|
||||
fn deserialize_remap<'de, D>(deserializer: D) -> Result<HashMap<Key, KeyAction>, D::Error>
|
||||
fn modmap_remap<'de, D>(deserializer: D) -> Result<HashMap<Key, KeyAction>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize, Eq, Hash, PartialEq)]
|
||||
struct KeyWrapper(#[serde(deserialize_with = "deserialize_key")] Key);
|
||||
struct ModmapRemap;
|
||||
|
||||
let v = HashMap::<KeyWrapper, KeyAction>::deserialize(deserializer)?;
|
||||
Ok(v.into_iter().map(|(KeyWrapper(k), v)| (k, v)).collect())
|
||||
impl<'de> Visitor<'de> for ModmapRemap {
|
||||
type Value = HashMap<Key, KeyAction>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("map from string to string")
|
||||
}
|
||||
|
||||
fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error>
|
||||
where
|
||||
M: MapAccess<'de>,
|
||||
{
|
||||
let remap: HashMap<String, KeyAction> = Deserialize::deserialize(value::MapAccessDeserializer::new(map))?;
|
||||
let mut modmap = HashMap::new();
|
||||
|
||||
for (from, to) in remap.into_iter() {
|
||||
let from_key = parse_key(&from).map_err(M::Error::custom)?;
|
||||
modmap.insert(from_key, to);
|
||||
}
|
||||
|
||||
Ok(modmap)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(ModmapRemap)
|
||||
}
|
||||
|
@ -1,115 +0,0 @@
|
||||
use crate::Config;
|
||||
use indoc::indoc;
|
||||
use serde_yaml::Error;
|
||||
|
||||
#[test]
|
||||
fn test_modmap_basic() {
|
||||
assert_parse(indoc! {"
|
||||
modmap:
|
||||
- name: Global
|
||||
remap:
|
||||
Alt_L: Ctrl_L
|
||||
- remap:
|
||||
Shift_R: Win_R
|
||||
application:
|
||||
only: Google-chrome
|
||||
"})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_modmap_application() {
|
||||
assert_parse(indoc! {"
|
||||
modmap:
|
||||
- remap:
|
||||
Alt_L: Ctrl_L
|
||||
application:
|
||||
not:
|
||||
- Gnome-terminal
|
||||
- remap:
|
||||
Shift_R: Win_R
|
||||
application:
|
||||
only: Google-chrome
|
||||
"})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_modmap_multi_purpose_key() {
|
||||
assert_parse(indoc! {"
|
||||
modmap:
|
||||
- remap:
|
||||
Space:
|
||||
held: Shift_L
|
||||
alone: Space
|
||||
- remap:
|
||||
Muhenkan:
|
||||
held: Alt_L
|
||||
alone: Muhenkan
|
||||
alone_timeout_millis: 500
|
||||
"})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_keymap_basic() {
|
||||
assert_parse(indoc! {"
|
||||
keymap:
|
||||
- name: Global
|
||||
remap:
|
||||
Alt-Enter: Ctrl-Enter
|
||||
- remap:
|
||||
Alt-S: Ctrl-S
|
||||
"})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_keymap_application() {
|
||||
assert_parse(indoc! {"
|
||||
keymap:
|
||||
- remap:
|
||||
Alt-Enter: Ctrl-Enter
|
||||
application:
|
||||
not: Gnome-terminal
|
||||
- remap:
|
||||
Alt-S: Ctrl-S
|
||||
application:
|
||||
only:
|
||||
- Gnome-terminal
|
||||
"})
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_keymap_array() {
|
||||
assert_parse(indoc! {"
|
||||
keymap:
|
||||
- remap:
|
||||
C-w:
|
||||
- Shift-C-w
|
||||
- C-x
|
||||
"})
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_keymap_remap() {
|
||||
assert_parse(indoc! {"
|
||||
keymap:
|
||||
- remap:
|
||||
C-x:
|
||||
remap:
|
||||
s: C-w
|
||||
C-s:
|
||||
remap:
|
||||
x: C-z
|
||||
- remap:
|
||||
M-r:
|
||||
- remap:
|
||||
'1': C-t
|
||||
"})
|
||||
}
|
||||
|
||||
fn assert_parse(yaml: &str) {
|
||||
let result: Result<Config, Error> = serde_yaml::from_str(&yaml);
|
||||
if let Err(e) = result {
|
||||
assert!(false, "{}", e)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue