Interleave pressing/releasing of modifier keys. (#208)

* Interleave pressing/releasing of modifier keys.

Pressing new modifier keys before releasing the old ones to avoid
triggering actions in applications that recognize the old keys.

For example, if we bind alt+f to ctrl+right, before this change, the
following key sequence is generated with alt+f:

(user)       send Alt_L      PRESS
(xremap)     send Alt_L      RELEASE
(xremap)     send Control_L  PRESS
(xremap)     send Right      PRESS
(xremap)     send Right      RELEASE
(xremap)     send Control_L  RELEASE
(xremap)     send Alt_L      PRESS
(user)       send Alt_L      RELEASE

The press + release of the alt key (both at the start and end of the
sequence) is causing apps like Firefox to show/focus the menu bar.

After this change, the following key sequence is generated with alt+f:

(user)       send Alt_L      PRESS
(xremap)     send Control_L  PRESS
(xremap)     send Alt_L      RELEASE
(xremap)     send Right      PRESS
(xremap)     send Right      RELEASE
(xremap)     send Alt_L      PRESS
(xremap)     send Control_L  RELEASE
(user)       send Alt_L      RELEASE

So the difference here is that we press the ctrl key before releasing
alt, so will not trigger apps like Firefox to show hide the menu when
alt+f is used, and a single press and release of the alt key will
still show the menu as their normal behavior.

As far as I can observe, this is also the behavior of AutoHotKey on Windows.

* Add test.
pull/209/head
Lae Chen 2 years ago committed by GitHub
parent 5f97804180
commit 8d3d62559e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -343,8 +343,8 @@ impl EventHandler {
missing_modifiers.retain(|key| MODIFIER_KEYS.contains(&key));
// Emulate the modifiers of KeyPress
self.send_keys(&extra_modifiers, RELEASE);
self.send_keys(&missing_modifiers, PRESS);
self.send_keys(&extra_modifiers, RELEASE);
// Press the main key
self.send_key(&key_press.key, PRESS);
@ -353,8 +353,8 @@ impl EventHandler {
self.send_action(Action::Delay(self.keypress_delay));
// Resurrect the original modifiers
self.send_keys(&missing_modifiers, RELEASE);
self.send_keys(&extra_modifiers, PRESS);
self.send_keys(&missing_modifiers, RELEASE);
}
fn with_mark(&self, key_press: &KeyPress) -> KeyPress {

@ -5,7 +5,7 @@ use std::time::Duration;
use crate::{
action::Action,
config::Config,
config::{keymap::build_keymap_table, Config},
event::{Event, KeyEvent, KeyValue},
event_handler::EventHandler,
};
@ -33,9 +33,35 @@ fn test_basic_modmap() {
)
}
#[test]
fn test_interleave_modifiers() {
assert_actions(
indoc! {"
keymap:
- remap:
M-f: C-right
"},
vec![
Event::KeyEvent(KeyEvent::new(Key::KEY_LEFTALT, KeyValue::Press)),
Event::KeyEvent(KeyEvent::new(Key::KEY_F, KeyValue::Press)),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTALT, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTALT, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_RIGHT, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_RIGHT, KeyValue::Release)),
Action::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTALT, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
],
)
}
fn assert_actions(config_yaml: &str, events: Vec<Event>, actions: Vec<Action>) {
let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap();
let config: Config = serde_yaml::from_str(config_yaml).unwrap();
let mut config: Config = serde_yaml::from_str(config_yaml).unwrap();
config.keymap_table = build_keymap_table(&config.keymap);
let mut event_handler = EventHandler::new(timer, "default", Duration::from_micros(0));
let mut actual: Vec<Action> = vec![];
for event in &events {

Loading…
Cancel
Save