|
|
|
@ -3,6 +3,7 @@ use indoc::indoc;
|
|
|
|
|
use nix::sys::timerfd::{ClockId, TimerFd, TimerFlags};
|
|
|
|
|
use std::time::Duration;
|
|
|
|
|
|
|
|
|
|
use crate::client::{Client, WMClient};
|
|
|
|
|
use crate::{
|
|
|
|
|
action::Action,
|
|
|
|
|
config::{keymap::build_keymap_table, Config},
|
|
|
|
@ -10,6 +11,20 @@ use crate::{
|
|
|
|
|
event_handler::EventHandler,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct StaticClient {
|
|
|
|
|
current_application: Option<String>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Client for StaticClient {
|
|
|
|
|
fn supported(&mut self) -> bool {
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn current_application(&mut self) -> Option<String> {
|
|
|
|
|
self.current_application.clone()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_basic_modmap() {
|
|
|
|
|
assert_actions(
|
|
|
|
@ -197,11 +212,182 @@ fn test_exact_match_false_nested() {
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_application_override() {
|
|
|
|
|
let config = indoc! {"
|
|
|
|
|
keymap:
|
|
|
|
|
|
|
|
|
|
- name: firefox
|
|
|
|
|
application:
|
|
|
|
|
only: [firefox]
|
|
|
|
|
remap:
|
|
|
|
|
a: C-c
|
|
|
|
|
|
|
|
|
|
- name: generic
|
|
|
|
|
remap:
|
|
|
|
|
a: C-b
|
|
|
|
|
"};
|
|
|
|
|
|
|
|
|
|
assert_actions(
|
|
|
|
|
config,
|
|
|
|
|
vec![Event::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Press))],
|
|
|
|
|
vec![
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_B, KeyValue::Press)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_B, KeyValue::Release)),
|
|
|
|
|
Action::Delay(Duration::from_nanos(0)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
assert_actions_with_current_application(
|
|
|
|
|
config,
|
|
|
|
|
Some(String::from("firefox")),
|
|
|
|
|
vec![Event::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Press))],
|
|
|
|
|
vec![
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_C, KeyValue::Press)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_C, KeyValue::Release)),
|
|
|
|
|
Action::Delay(Duration::from_nanos(0)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_merge_remaps() {
|
|
|
|
|
let config = indoc! {"
|
|
|
|
|
keymap:
|
|
|
|
|
- remap:
|
|
|
|
|
C-x:
|
|
|
|
|
remap:
|
|
|
|
|
h: C-a
|
|
|
|
|
- remap:
|
|
|
|
|
C-x:
|
|
|
|
|
remap:
|
|
|
|
|
k: C-w
|
|
|
|
|
"};
|
|
|
|
|
|
|
|
|
|
assert_actions(
|
|
|
|
|
config,
|
|
|
|
|
vec![
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_X, KeyValue::Press)),
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_X, KeyValue::Release)),
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_H, KeyValue::Press)),
|
|
|
|
|
],
|
|
|
|
|
vec![
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_X, KeyValue::Release)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Press)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
|
|
|
|
|
Action::Delay(Duration::from_nanos(0)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
assert_actions(
|
|
|
|
|
config,
|
|
|
|
|
vec![
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_X, KeyValue::Press)),
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_X, KeyValue::Release)),
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_K, KeyValue::Press)),
|
|
|
|
|
],
|
|
|
|
|
vec![
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_X, KeyValue::Release)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_W, KeyValue::Press)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_W, KeyValue::Release)),
|
|
|
|
|
Action::Delay(Duration::from_nanos(0)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
|
|
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_merge_remaps_with_override() {
|
|
|
|
|
let config = indoc! {"
|
|
|
|
|
keymap:
|
|
|
|
|
- remap:
|
|
|
|
|
C-x:
|
|
|
|
|
remap:
|
|
|
|
|
h: C-a
|
|
|
|
|
- remap:
|
|
|
|
|
C-x:
|
|
|
|
|
remap:
|
|
|
|
|
h: C-b
|
|
|
|
|
c: C-q
|
|
|
|
|
"};
|
|
|
|
|
|
|
|
|
|
assert_actions(
|
|
|
|
|
config,
|
|
|
|
|
vec![
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_X, KeyValue::Press)),
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_X, KeyValue::Release)),
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_H, KeyValue::Press)),
|
|
|
|
|
],
|
|
|
|
|
vec![
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_X, KeyValue::Release)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Press)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
|
|
|
|
|
Action::Delay(Duration::from_nanos(0)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
assert_actions(
|
|
|
|
|
config,
|
|
|
|
|
vec![
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_X, KeyValue::Press)),
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_X, KeyValue::Release)),
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
|
|
|
|
|
Event::KeyEvent(KeyEvent::new(Key::KEY_C, KeyValue::Press)),
|
|
|
|
|
],
|
|
|
|
|
vec![
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_X, KeyValue::Release)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_Q, KeyValue::Press)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_Q, KeyValue::Release)),
|
|
|
|
|
Action::Delay(Duration::from_nanos(0)),
|
|
|
|
|
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
|
|
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn assert_actions(config_yaml: &str, events: Vec<Event>, actions: Vec<Action>) {
|
|
|
|
|
assert_actions_with_current_application(config_yaml, None, events, actions);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn assert_actions_with_current_application(
|
|
|
|
|
config_yaml: &str,
|
|
|
|
|
current_application: Option<String>,
|
|
|
|
|
events: Vec<Event>,
|
|
|
|
|
actions: Vec<Action>,
|
|
|
|
|
) {
|
|
|
|
|
let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).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 event_handler = EventHandler::new(
|
|
|
|
|
timer,
|
|
|
|
|
"default",
|
|
|
|
|
Duration::from_micros(0),
|
|
|
|
|
WMClient::new("static", Box::new(StaticClient { current_application })),
|
|
|
|
|
);
|
|
|
|
|
let mut actual: Vec<Action> = vec![];
|
|
|
|
|
for event in &events {
|
|
|
|
|
actual.append(&mut event_handler.on_event(event, &config).unwrap());
|
|
|
|
|