mirror of
https://github.com/k0kubun/xremap
synced 2024-11-02 03:40:25 +00:00
Merge pull request #147 from k0kubun/reimagine-modifiers
Replace modifier: true with virtual_modifiers
This commit is contained in:
commit
b2ff35872c
21
README.md
21
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).
|
||||
|
@ -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 {
|
||||
|
@ -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<Keymap>,
|
||||
#[serde(default = "default_mode")]
|
||||
pub default_mode: String,
|
||||
#[serde(deserialize_with = "deserialize_virtual_modifiers", default = "Vec::new")]
|
||||
pub virtual_modifiers: Vec<Key>,
|
||||
|
||||
// Internals
|
||||
#[serde(skip)]
|
||||
@ -69,3 +74,15 @@ pub fn config_watcher(watch: bool, file: &Path) -> anyhow::Result<Option<Inotify
|
||||
fn default_mode() -> String {
|
||||
"default".to_string()
|
||||
}
|
||||
|
||||
fn deserialize_virtual_modifiers<'de, D>(deserializer: D) -> Result<Vec<Key>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let key_strs = Vec::<String>::deserialize(deserializer)?;
|
||||
let mut keys: Vec<Key> = vec![];
|
||||
for key_str in key_strs {
|
||||
keys.push(parse_key(&key_str).map_err(serde::de::Error::custom)?);
|
||||
}
|
||||
return Ok(keys);
|
||||
}
|
||||
|
@ -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#"
|
||||
|
@ -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<Vec<(Key, i32)>, Box<dyn Error>> {
|
||||
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,
|
||||
|
Loading…
Reference in New Issue
Block a user