use crate::action::Action;
use crate::event::Event;
use crate::event::{KeyEvent, KeyValue};
use crate::tests::assert_actions;
use evdev::KeyCode as Key;
use indoc::indoc;
use std::time::Duration;
#[test]
fn test_exact_match_true_nested() {
assert_actions(
indoc! {"
keymap:
- exact_match: true
remap:
C-x:
remap:
h: C-a
"},
vec![
Event::key_press(Key::KEY_LEFTCTRL),
Event::key_press(Key::KEY_X),
Event::key_release(Key::KEY_X),
Event::key_release(Key::KEY_LEFTCTRL),
Event::key_press(Key::KEY_LEFTSHIFT),
Event::key_press(Key::KEY_H),
],
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_LEFTSHIFT, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_H, KeyValue::Press)),
],
)
}
#[test]
fn test_exact_match_false_nested() {
assert_actions(
indoc! {"
keymap:
- exact_match: false
remap:
C-x:
remap:
h: C-a
"},
vec![
Event::key_press(Key::KEY_LEFTCTRL),
Event::key_press(Key::KEY_X),
Event::key_release(Key::KEY_X),
Event::key_release(Key::KEY_LEFTCTRL),
Event::key_press(Key::KEY_LEFTSHIFT),
Event::key_press(Key::KEY_H),
],
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_LEFTSHIFT, KeyValue::Press)),
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::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::key_press(Key::KEY_LEFTCTRL),
Event::key_press(Key::KEY_X),
Event::key_release(Key::KEY_X),
Event::key_release(Key::KEY_LEFTCTRL),
Event::key_press(Key::KEY_H),
],
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::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
],
);
assert_actions(
config,
vec![
Event::key_press(Key::KEY_LEFTCTRL),
Event::key_press(Key::KEY_X),
Event::key_release(Key::KEY_X),
Event::key_release(Key::KEY_LEFTCTRL),
Event::key_press(Key::KEY_K),
],
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::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::key_press(Key::KEY_LEFTCTRL),
Event::key_press(Key::KEY_X),
Event::key_release(Key::KEY_X),
Event::key_release(Key::KEY_LEFTCTRL),
Event::key_press(Key::KEY_H),
],
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::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
],
);
assert_actions(
config,
vec![
Event::key_press(Key::KEY_LEFTCTRL),
Event::key_press(Key::KEY_X),
Event::key_release(Key::KEY_X),
Event::key_release(Key::KEY_LEFTCTRL),
Event::key_press(Key::KEY_C),
],
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::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
],
)
}
#[test]
fn test_merge_nested_sibling_remaps() {
let config = indoc! {"
keymap:
- remap:
capslock:
- remap:
a: b
- remap:
c: d
"};
assert_actions(
config,
vec![
Event::key_press(Key::KEY_CAPSLOCK),
Event::key_release(Key::KEY_CAPSLOCK),
Event::key_press(Key::KEY_A),
Event::key_release(Key::KEY_A),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_CAPSLOCK, KeyValue::Release)),
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::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
],
);
assert_actions(
config,
vec![
Event::key_press(Key::KEY_CAPSLOCK),
Event::key_release(Key::KEY_CAPSLOCK),
Event::key_press(Key::KEY_C),
Event::key_release(Key::KEY_C),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_CAPSLOCK, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_D, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_D, KeyValue::Release)),
Action::Delay(Duration::from_nanos(0)),
Action::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_C, KeyValue::Release)),
],
);
}
#[test]
fn test_merge_nested_sibling_remaps_precedence_to_first() {
assert_actions(
indoc! {"
keymap:
- remap:
CAPSLOCK:
- remap:
a: b
- remap:
a: c
"},
vec![
Event::key_press(Key::KEY_CAPSLOCK),
Event::key_release(Key::KEY_CAPSLOCK),
Event::key_press(Key::KEY_A),
Event::key_release(Key::KEY_A),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_CAPSLOCK, KeyValue::Release)),
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::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
],
);
}
#[test]
fn test_event_canceling_remap_gets_emitted() {
assert_actions(
indoc! {"
keymap:
- remap:
a:
remap:
c: d
"},
vec![
Event::key_press(Key::KEY_A),
Event::key_release(Key::KEY_A),
Event::key_press(Key::KEY_K),
Event::key_release(Key::KEY_K),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_K, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_K, KeyValue::Release)),
],
)
}
#[test]
fn test_the_event_canceling_remap_gets_emitted_when_same_as_trigger_key_when_implicit() {
assert_actions(
indoc! {"
keymap:
- remap:
a:
remap:
c: d
"},
vec![
Event::key_press(Key::KEY_A),
Event::key_release(Key::KEY_A),
Event::key_press(Key::KEY_A),
Event::key_release(Key::KEY_A),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
],
)
}
#[test]
fn test_the_event_canceling_remap_gets_emitted_when_same_as_trigger_key_when_explicit() {
assert_actions(
indoc! {"
keymap:
- remap:
a:
remap:
c: d
a: a
"},
vec![
Event::key_press(Key::KEY_A),
Event::key_release(Key::KEY_A),
Event::key_press(Key::KEY_A),
Event::key_release(Key::KEY_A),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
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::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
],
)
}
#[test]
fn test_modifier_canceling_remap_gets_emitted() {
assert_actions(
indoc! {"
keymap:
- remap:
a:
remap:
c: d
"},
vec![
Event::key_press(Key::KEY_A),
Event::key_release(Key::KEY_A),
Event::key_press(Key::KEY_LEFTCTRL),
Event::key_release(Key::KEY_LEFTCTRL),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
],
)
}
#[test]
fn test_event_canceling_remap_is_used_for_matching() {
assert_actions(
indoc! {"
keymap:
- remap:
a:
remap:
c: d
k: l
"},
vec![
Event::key_press(Key::KEY_A),
Event::key_release(Key::KEY_A),
Event::key_press(Key::KEY_K),
Event::key_release(Key::KEY_K),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_L, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_L, KeyValue::Release)),
Action::Delay(Duration::from_nanos(0)),
Action::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_K, KeyValue::Release)),
],
)
}
#[test]
fn test_modifier_canceling_remap_is_used_for_matching() {
assert_actions(
indoc! {"
keymap:
- remap:
a:
remap:
c: d
ctrl-k: l
"},
vec![
Event::key_press(Key::KEY_A),
Event::key_release(Key::KEY_A),
Event::key_press(Key::KEY_LEFTCTRL),
Event::key_press(Key::KEY_K),
Event::key_release(Key::KEY_K),
Event::key_release(Key::KEY_LEFTCTRL),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_L, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_L, KeyValue::Release)),
Action::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
Action::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_K, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
],
)
}
#[test]
fn test_cancel_by_timeout_emits_nothing() {
assert_actions(
indoc! {"
keymap:
- remap:
a:
remap:
c: d
"},
vec![
Event::key_press(Key::KEY_A),
Event::key_release(Key::KEY_A),
Event::OverrideTimeout,
Event::key_press(Key::KEY_C),
Event::key_release(Key::KEY_C),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_C, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_C, KeyValue::Release)),
],
)
}
#[test]
fn test_cancel_by_timeout_with_timeout_key() {
assert_actions(
indoc! {"
keymap:
- remap:
a:
timeout_key: t
remap:
c: d
"},
vec![
Event::key_press(Key::KEY_A),
Event::key_release(Key::KEY_A),
Event::OverrideTimeout,
Event::key_press(Key::KEY_C),
Event::key_release(Key::KEY_C),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_C, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_C, KeyValue::Release)),
],
)
}
#[test]
fn test_cancel_by_timeout_with_explicit_timeout() {
assert_actions(
indoc! {"
keymap:
- remap:
a:
timeout_key: t
timeout_millis: 100
remap:
c: d
"},
vec![
Event::key_press(Key::KEY_A),
Event::key_release(Key::KEY_A),
Event::OverrideTimeout,
Event::key_press(Key::KEY_C),
Event::key_release(Key::KEY_C),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_T, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_T, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_C, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_C, KeyValue::Release)),
],
)
}
#[test]
fn test_cancel_by_key_with_defined_timeout_key() {
assert_actions(
indoc! {"
keymap:
- remap:
a:
timeout_key: t
timeout_millis: 100
remap:
c: d
"},
vec![
Event::key_press(Key::KEY_A),
Event::key_release(Key::KEY_A),
Event::key_press(Key::KEY_K),
Event::key_release(Key::KEY_K),
Event::key_press(Key::KEY_C),
Event::key_release(Key::KEY_C),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_T, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_T, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_K, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_K, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_C, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_C, KeyValue::Release)),
],
)
}
#[test]
fn test_cancel_by_key_with_defined_timeout_key_but_no_match() {
assert_actions(
indoc! {"
keymap:
- remap:
a:
timeout_key: t
timeout_millis: 100
remap:
ctrl-c: d
"},
vec![
Event::key_press(Key::KEY_A),
Event::key_release(Key::KEY_A),
Event::key_press(Key::KEY_C),
Event::key_release(Key::KEY_C),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_C, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_C, KeyValue::Release)),
],
)
}
#[test]
fn test_mixing_keypress_and_remap_in_keymap_action() {
assert_actions(
indoc! {"
keymap:
- remap:
f12:
- d
- remap:
a: b
"},
vec![
Event::key_press(Key::KEY_F12),
Event::key_release(Key::KEY_F12),
Event::key_press(Key::KEY_A),
Event::key_release(Key::KEY_A),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_D, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_D, KeyValue::Release)),
Action::Delay(Duration::from_nanos(0)),
Action::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_F12, KeyValue::Release)),
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::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
],
)
}
#[test]
fn test_mixing_no_keypress_and_remap_in_keymap_action() {
assert_actions(
indoc! {"
keymap:
- remap:
f12: []
- remap:
f12:
- remap:
a: b
"},
vec![
Event::key_press(Key::KEY_F12),
Event::key_release(Key::KEY_F12),
Event::key_press(Key::KEY_A),
Event::key_release(Key::KEY_A),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_F12, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
],
)
}
#[test]
fn test_nested_remap_inexact_when_union_of_modifiers() {
assert_actions(
indoc! {"
keymap:
- remap:
c-x:
remap:
alt-W: A
control-W: B
"},
vec![
Event::key_press(Key::KEY_LEFTALT),
Event::key_press(Key::KEY_LEFTCTRL),
Event::key_press(Key::KEY_X),
Event::key_press(Key::KEY_W),
],
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_A, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Release)),
Action::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTALT, KeyValue::Press)),
Action::Delay(Duration::from_nanos(0)),
],
)
}