Rollback to v0.1.5

pull/53/head
Takashi Kokubun 2 years ago
parent 613555943d
commit 7ab1595836
No known key found for this signature in database
GPG Key ID: 6FFC433B12EE23DD

@ -17,6 +17,7 @@ env:
jobs:
build:
runs-on: ubuntu-latest
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
strategy:
fail-fast: false
matrix:
@ -38,6 +39,7 @@ jobs:
fmt:
runs-on: ubuntu-latest
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
@ -48,22 +50,8 @@ jobs:
- name: cargo fmt
run: cargo fmt -- --check
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- run: cargo test
publish:
runs-on: ubuntu-latest
needs:
- build
- test
if: ${{ startsWith(github.ref, 'refs/tags/') }}
steps:
- uses: actions/checkout@v2

16
Cargo.lock generated

@ -371,15 +371,6 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "indoc"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5a75aeaaef0ce18b58056d306c27b07436fbb34b8816c53094b76dd81803136"
dependencies = [
"unindent",
]
[[package]]
name = "instant"
version = "0.1.12"
@ -779,12 +770,6 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "unindent"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"
[[package]]
name = "waker-fn"
version = "1.1.0"
@ -857,7 +842,6 @@ dependencies = [
"env_logger",
"evdev",
"getopts",
"indoc",
"lazy_static",
"log",
"nix 0.23.1",

@ -11,7 +11,6 @@ license = "MIT"
env_logger = "0.9.0"
evdev = "0.11.3"
getopts = "0.2"
indoc = "1.0"
lazy_static = "1.4.0"
log = "0.4.14"
nix = "0.23.1"

@ -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,34 +1,7 @@
use evdev::Key;
use serde::de::Visitor;
use serde::Deserializer;
use std::error::Error;
use std::fmt;
use std::str::FromStr;
pub fn deserialize_key<'de, D>(deserializer: D) -> Result<Key, D::Error>
where
D: Deserializer<'de>,
{
struct KeyVisitor;
impl<'de> Visitor<'de> for KeyVisitor {
type Value = Key;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("string")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(parse_key(value).map_err(serde::de::Error::custom)?)
}
}
deserializer.deserialize_any(KeyVisitor)
}
pub fn parse_key(input: &str) -> Result<Key, Box<dyn Error>> {
// Everything is case-insensitive
let name = input.to_uppercase();

@ -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)
}
}

@ -48,7 +48,7 @@ impl<'de> Deserialize<'de> for KeyPress {
}
}
fn parse_key_press(input: &str) -> Result<KeyPress, Box<dyn error::Error>> {
pub fn parse_key_press(input: &str) -> Result<KeyPress, Box<dyn error::Error>> {
let keys: Vec<&str> = input.split("-").collect();
if let Some((key, modifiers)) = keys.split_last() {
let mut shift = false;
@ -68,7 +68,7 @@ fn parse_key_press(input: &str) -> Result<KeyPress, Box<dyn error::Error>> {
// TODO: invalidate modifier keys in `key`?
Ok(KeyPress {
key: Key::new(parse_key(key)?.code()),
key: parse_key(key)?,
shift,
control,
alt,

@ -1,7 +1,8 @@
use crate::config::action::Action;
use crate::config::actions::Actions;
use crate::config::application::Application;
use crate::config::key_press::KeyPress;
use serde::de::{value, IntoDeserializer, MapAccess, SeqAccess, Visitor};
use serde::de::{MapAccess, Visitor};
use serde::{Deserialize, Deserializer};
use std::collections::HashMap;
use std::fmt;
@ -12,18 +13,18 @@ use std::fmt::Formatter;
pub struct Keymap {
#[serde(default = "String::new")]
pub name: String,
#[serde(deserialize_with = "deserialize_remap")]
#[serde(deserialize_with = "keymap_remap")]
pub remap: HashMap<KeyPress, Vec<Action>>,
pub application: Option<Application>,
}
pub fn deserialize_remap<'de, D>(deserializer: D) -> Result<HashMap<KeyPress, Vec<Action>>, D::Error>
fn keymap_remap<'de, D>(deserializer: D) -> Result<HashMap<KeyPress, Vec<Action>>, D::Error>
where
D: Deserializer<'de>,
{
struct RemapVisitor;
struct KeymapRemap;
impl<'de> Visitor<'de> for RemapVisitor {
impl<'de> Visitor<'de> for KeymapRemap {
type Value = HashMap<KeyPress, Vec<Action>>;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
@ -48,53 +49,5 @@ where
}
}
deserializer.deserialize_any(RemapVisitor)
}
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: serde::de::Error,
{
let key_press = Deserialize::deserialize(value.into_deserializer())?;
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 = 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 = Deserialize::deserialize(value::MapAccessDeserializer::new(map))?;
Ok(Actions::Action(action))
}
}
deserializer.deserialize_any(ActionsVisitor)
}
deserializer.deserialize_any(KeymapRemap)
}

@ -1,21 +1,18 @@
pub mod action;
mod actions;
pub mod application;
pub mod key;
mod key;
pub mod key_action;
pub mod key_press;
mod keymap;
mod modmap;
#[cfg(test)]
mod tests;
extern crate serde_yaml;
use keymap::Keymap;
use modmap::Modmap;
use serde::Deserialize;
use std::error::Error;
use std::fs;
use std::{error, fs};
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
@ -26,7 +23,8 @@ pub struct Config {
pub keymap: Vec<Keymap>,
}
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)?;
Ok(serde_yaml::from_str(&yaml)?)
let config: Config = serde_yaml::from_str(&yaml)?;
return Ok(config);
}

@ -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)
}
}

@ -10,7 +10,7 @@ use lazy_static::lazy_static;
use log::debug;
use std::collections::HashMap;
use std::error::Error;
use std::time::{Duration, Instant};
use std::time::Instant;
pub struct EventHandler {
device: VirtualDevice,
@ -92,9 +92,7 @@ impl EventHandler {
MultiPurposeKeyState {
held: multi_purpose_key.held,
alone: multi_purpose_key.alone,
alone_timeout_at: Some(
Instant::now() + Duration::from_millis(multi_purpose_key.alone_timeout_millis),
),
alone_timeout_at: Some(Instant::now() + multi_purpose_key.alone_timeout),
},
);
return vec![]; // delay the press

Loading…
Cancel
Save