From c8c4574d0f2ed959f575ed0755071a1949ef8da7 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Sun, 14 Aug 2022 13:00:22 -0700 Subject: [PATCH] Replace modifier: true with virtual_modifiers --- README.md | 21 +++++++++++++++++---- src/config/key_action.rs | 6 ------ src/config/mod.rs | 21 +++++++++++++++++++-- src/config/tests.rs | 8 ++++++++ src/event_handler.rs | 18 +++++------------- 5 files changed, 49 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index afbce15..d2caeff 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ * Automatically remap newly connected devices by starting xremap with `--watch`. * Support [Emacs-like key remapping](example/emacs.yml), including the mark mode. * Trigger commands on key press/release events. +* Use a non-modifier key as a virtual modifier key. ## Installation @@ -155,9 +156,6 @@ modmap: remap: # Required # Replace a key with another KEY_XXX: KEY_YYY # Required - # Make it a logical modifier key - KEY_XXX: - modifier: true # Required # Dispatch different keys depending on whether you hold it or press it alone KEY_XXX: held: KEY_YYY # Required @@ -231,7 +229,7 @@ You can use multiple prefixes like `C-M-Shift-a`. You may also suffix them with `_L` or `_R` (case-insensitive) so that remapping is triggered only on a left or right modifier, e.g. `Ctrl_L-a`. -If you set `modifier: true` in `modmap`, you can use it in the `MOD1-` part too. +If you use `virtual_modifiers` explained below, you can use it in the `MOD1-` part too. ### application @@ -278,6 +276,21 @@ swaymsg -t get_tree Locate `app_id` in the output. +### virtual\_modifiers + +You can declare keys that should act like a modifier. + +``` +virtual_modifiers: + - CapsLock +keymap: + - remap: + CapsLock-i: Up + CapsLock-j: Left + CapsLock-k: Down + CapsLock-l: Right +``` + ## License `xremap` is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). diff --git a/src/config/key_action.rs b/src/config/key_action.rs index 3001c65..cd87187 100644 --- a/src/config/key_action.rs +++ b/src/config/key_action.rs @@ -12,16 +12,10 @@ use super::action::{Action, Actions}; pub enum KeyAction { #[serde(deserialize_with = "deserialize_key")] Key(Key), - ModifierKey(ModifierKey), MultiPurposeKey(MultiPurposeKey), PressReleaseKey(PressReleaseKey), } -#[derive(Clone, Debug, Deserialize)] -pub struct ModifierKey { - pub modifier: bool, -} - #[serde_as] #[derive(Clone, Debug, Deserialize)] pub struct MultiPurposeKey { diff --git a/src/config/mod.rs b/src/config/mod.rs index 6d65878..e5e1566 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -16,10 +16,13 @@ use evdev::Key; use keymap::Keymap; use modmap::Modmap; use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify}; -use serde::Deserialize; +use serde::{Deserialize, Deserializer}; use std::{collections::HashMap, error, fs, path::Path, time::SystemTime}; -use self::keymap::{build_keymap_table, KeymapEntry}; +use self::{ + key::parse_key, + keymap::{build_keymap_table, KeymapEntry}, +}; #[derive(Debug, Deserialize)] #[serde(deny_unknown_fields)] @@ -31,6 +34,8 @@ pub struct Config { pub keymap: Vec, #[serde(default = "default_mode")] pub default_mode: String, + #[serde(deserialize_with = "deserialize_virtual_modifiers", default = "Vec::new")] + pub virtual_modifiers: Vec, // Internals #[serde(skip)] @@ -69,3 +74,15 @@ pub fn config_watcher(watch: bool, file: &Path) -> anyhow::Result String { "default".to_string() } + +fn deserialize_virtual_modifiers<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let key_strs = Vec::::deserialize(deserializer)?; + let mut keys: Vec = vec![]; + for key_str in key_strs { + keys.push(parse_key(&key_str).map_err(serde::de::Error::custom)?); + } + return Ok(keys); +} diff --git a/src/config/tests.rs b/src/config/tests.rs index d79d561..3119de7 100644 --- a/src/config/tests.rs +++ b/src/config/tests.rs @@ -66,6 +66,14 @@ fn test_modmap_multi_purpose_key() { "}) } +#[test] +fn test_virtual_modifiers() { + assert_parse(indoc! {" + virtual_modifiers: + - CapsLock + "}) +} + #[test] fn test_modmap_press_release_key() { assert_parse(indoc! {r#" diff --git a/src/event_handler.rs b/src/event_handler.rs index 1694df9..867ba7a 100644 --- a/src/event_handler.rs +++ b/src/event_handler.rs @@ -1,7 +1,7 @@ use crate::client::{build_client, WMClient}; use crate::config::action::Action; use crate::config::application::Application; -use crate::config::key_action::{KeyAction, ModifierKey, MultiPurposeKey, PressReleaseKey}; +use crate::config::key_action::{KeyAction, MultiPurposeKey, PressReleaseKey}; use crate::config::key_press::{KeyPress, Modifier}; use crate::config::keymap::{build_override_table, OverrideEntry}; use crate::config::remap::Remap; @@ -85,7 +85,10 @@ impl EventHandler { // Apply keymap for (key, value) in key_values.into_iter() { - if MODIFIER_KEYS.contains(&key.code()) { + if config.virtual_modifiers.contains(&key) { + self.update_modifier(key, value); + continue; + } else if MODIFIER_KEYS.contains(&key.code()) { self.update_modifier(key, value); } else if is_pressed(value) { if self.escape_next_key { @@ -162,17 +165,6 @@ impl EventHandler { ) -> Result, Box> { let keys = match key_action { KeyAction::Key(modmap_key) => vec![(modmap_key, value)], - KeyAction::ModifierKey(ModifierKey { modifier }) => { - if modifier { - if value == PRESS { - self.modifiers.insert(key); - } else if value == RELEASE { - self.modifiers.remove(&key); - } - } - // Process this key only in xremap - vec![] - } KeyAction::MultiPurposeKey(MultiPurposeKey { held, alone,