use evdev::EventType;
use evdev::InputEvent;
use evdev::KeyCode as Key;
use indoc::indoc;
use nix::sys::timerfd::{ClockId, TimerFd, TimerFlags};
use std::path::Path;
use std::time::Duration;
use crate::client::{Client, WMClient};
use crate::device::InputDeviceInfo;
use crate::{
action::Action,
config::{keymap::build_keymap_table, Config},
event::{Event, KeyEvent, KeyValue, RelativeEvent},
event_handler::EventHandler,
};
struct StaticClient {
current_application: Option<String>,
}
impl Client for StaticClient {
fn supported(&mut self) -> bool {
true
}
fn current_window(&mut self) -> Option<String> {
None
}
fn current_application(&mut self) -> Option<String> {
self.current_application.clone()
}
}
pub fn get_input_device_info<'a>() -> InputDeviceInfo<'a> {
InputDeviceInfo {
name: "Some Device",
path: Path::new("/dev/input/event0"),
vendor: 0x1234,
product: 0x5678,
}
}
#[test]
fn test_basic_modmap() {
assert_actions(
indoc! {"
modmap:
- remap:
a: b
"},
vec![
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_A, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_A, KeyValue::Release)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_B, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_B, KeyValue::Release)),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_B, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_B, KeyValue::Release)),
Action::KeyEvent(KeyEvent::new(Key::KEY_B, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_B, KeyValue::Release)),
],
)
}
const _POSITIVE: i32 = 1;
const _NEGATIVE: i32 = -1;
const _REL_X: u16 = 0;
const _REL_Y: u16 = 1;
const _REL_Z: u16 = 2;
const _REL_RX: u16 = 3;
const _REL_RY: u16 = 4;
const _REL_RZ: u16 = 5;
const _REL_HWHEEL: u16 = 6;
const _REL_DIAL: u16 = 7;
const _REL_WHEEL: u16 = 8;
const _REL_MISC: u16 = 9;
const _REL_RESERVED: u16 = 10;
const _REL_WHEEL_HI_RES: u16 = 11;
const _REL_HWHEEL_HI_RES: u16 = 12;
#[test]
fn test_relative_events() {
assert_actions(
indoc! {"
modmap:
- remap:
XRIGHTCURSOR: b
"},
vec![Event::RelativeEvent(
get_input_device_info(),
RelativeEvent::new_with(_REL_X, _POSITIVE),
)],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_B, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_B, KeyValue::Release)),
],
)
}
#[test]
fn verify_disguised_relative_events() {
use crate::event_handler::DISGUISED_EVENT_OFFSETTER;
const _: () = assert!(0x2e7 < DISGUISED_EVENT_OFFSETTER);
const _: () = assert!(DISGUISED_EVENT_OFFSETTER <= u16::MAX - 26);
}
#[test]
fn test_mouse_movement_event_accumulation() {
assert_actions(
indoc! {""},
vec![
Event::RelativeEvent(get_input_device_info(), RelativeEvent::new_with(_REL_X, _POSITIVE)),
Event::RelativeEvent(get_input_device_info(), RelativeEvent::new_with(_REL_Y, _POSITIVE)),
],
vec![Action::MouseMovementEventCollection(vec![
RelativeEvent::new_with(_REL_X, _POSITIVE),
RelativeEvent::new_with(_REL_Y, _POSITIVE),
])],
)
}
#[test]
#[ignore]
fn test_cursor_behavior_1() {
use crate::device::InputDevice;
use crate::device::{get_input_devices, output_device};
let mut input_devices = match get_input_devices(&[String::from("/dev/input/event25")], &[], true, false) {
Ok(input_devices) => input_devices,
Err(e) => panic!("Failed to prepare input devices: {e}"),
};
let mut output_device =
match output_device(input_devices.values().next().map(InputDevice::bus_type), true, 0x1234, 0x5678) {
Ok(output_device) => output_device,
Err(e) => panic!("Failed to prepare an output device: {e}"),
};
for input_device in input_devices.values_mut() {
let _unused = input_device.fetch_events().unwrap();
}
for _ in 0..400 {
output_device
.emit(&[
InputEvent::new_now(EventType::RELATIVE.0, _REL_X, _POSITIVE),
InputEvent::new(EventType::SYNCHRONIZATION.0, 0, 0),
InputEvent::new_now(EventType::RELATIVE.0, _REL_Y, _NEGATIVE),
])
.unwrap();
std::thread::sleep(Duration::from_millis(5));
}
}
#[test]
#[ignore]
fn test_cursor_behavior_2() {
use crate::device::InputDevice;
use crate::device::{get_input_devices, output_device};
let mut input_devices = match get_input_devices(&[String::from("/dev/input/event25")], &[], true, false) {
Ok(input_devices) => input_devices,
Err(e) => panic!("Failed to prepare input devices: {e}"),
};
let mut output_device =
match output_device(input_devices.values().next().map(InputDevice::bus_type), true, 0x1234, 0x5678) {
Ok(output_device) => output_device,
Err(e) => panic!("Failed to prepare an output device: {e}"),
};
for input_device in input_devices.values_mut() {
let _unused = input_device.fetch_events().unwrap();
}
for _ in 0..400 {
output_device
.emit(&[
InputEvent::new_now(EventType::RELATIVE.0, _REL_X, _POSITIVE),
InputEvent::new_now(EventType::RELATIVE.0, _REL_Y, _NEGATIVE),
])
.unwrap();
std::thread::sleep(Duration::from_millis(5));
}
}
#[test]
fn test_interleave_modifiers() {
assert_actions(
indoc! {"
keymap:
- remap:
M-f: C-right
"},
vec![
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTALT, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), 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::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
],
)
}
#[test]
fn test_exact_match_true() {
assert_actions(
indoc! {"
keymap:
- exact_match: true
remap:
M-f: C-right
"},
vec![
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTALT, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTSHIFT, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_F, KeyValue::Press)),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTALT, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTSHIFT, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_F, KeyValue::Press)),
],
)
}
#[test]
fn test_exact_match_false() {
assert_actions(
indoc! {"
keymap:
- exact_match: false
remap:
M-f: C-right
"},
vec![
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTALT, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTSHIFT, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_F, KeyValue::Press)),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTALT, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTSHIFT, 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::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
],
)
}
#[test]
fn test_exact_match_default() {
assert_actions(
indoc! {"
keymap:
- remap:
M-f: C-right
"},
vec![
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTALT, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTSHIFT, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_F, KeyValue::Press)),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTALT, KeyValue::Press)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTSHIFT, 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::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
],
)
}
#[test]
fn test_exact_match_true_nested() {
assert_actions(
indoc! {"
keymap:
- exact_match: true
remap:
C-x:
remap:
h: C-a
"},
vec![
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_X, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_X, KeyValue::Release)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTSHIFT, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), 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_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::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_X, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_X, KeyValue::Release)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTSHIFT, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), 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_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_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(
get_input_device_info(),
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::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(
get_input_device_info(),
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::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
],
);
}
#[test]
fn test_device_override() {
let config = indoc! {"
keymap:
- name: event1
device:
only: [event1]
remap:
a: C-c
- name: event0
remap:
a: C-b
"};
assert_actions(
config,
vec![Event::KeyEvent(
InputDeviceInfo {
name: "Some Device",
path: Path::new("/dev/input/event0"),
vendor: 0x1234,
product: 0x5678,
},
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::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
],
);
assert_actions(
config,
vec![Event::KeyEvent(
InputDeviceInfo {
name: "Other Device",
path: Path::new("/dev/input/event1"),
vendor: 0x1234,
product: 0x5678,
},
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::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(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_X, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_X, KeyValue::Release)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
Event::KeyEvent(get_input_device_info(), 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::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
],
);
assert_actions(
config,
vec![
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_X, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_X, KeyValue::Release)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
Event::KeyEvent(get_input_device_info(), 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::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(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_X, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_X, KeyValue::Release)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
Event::KeyEvent(get_input_device_info(), 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::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
],
);
assert_actions(
config,
vec![
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_X, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_X, KeyValue::Release)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
Event::KeyEvent(get_input_device_info(), 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::Delay(Duration::from_nanos(0)),
Action::KeyEvent(KeyEvent::new(Key::KEY_LEFTCTRL, KeyValue::Release)),
],
)
}
#[test]
fn test_mixing_keypress_and_remap_in_keymap_action() {
assert_actions(
indoc! {"
keymap:
- remap:
f12:
- d
- remap:
a: b
"},
vec![
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_F12, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_F12, KeyValue::Release)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_A, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_A, KeyValue::Release)),
],
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::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_F12, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_F12, KeyValue::Release)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_A, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_A, KeyValue::Release)),
],
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_no_keymap_action() {
assert_actions(
indoc! {"
keymap:
- remap:
f12: []
"},
vec![
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_F12, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_F12, KeyValue::Release)),
],
vec![
Action::KeyEvent(KeyEvent::new(Key::KEY_F12, KeyValue::Release)),
],
);
assert_actions(
indoc! {"
keymap:
- remap:
f12: null
"},
vec![
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_F12, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_F12, KeyValue::Release)),
],
vec![Action::KeyEvent(KeyEvent::new(Key::KEY_F12, KeyValue::Release))],
)
}
#[test]
fn test_any_key() {
assert_actions(
indoc! {"
keymap:
- remap:
a: b
ANY: null
"},
vec![
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_A, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_A, KeyValue::Release)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_C, KeyValue::Press)),
Event::KeyEvent(get_input_device_info(), KeyEvent::new(Key::KEY_C, KeyValue::Release)),
],
vec![
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)),
Action::KeyEvent(KeyEvent::new(Key::KEY_C, KeyValue::Release)),
],
);
}
pub fn assert_actions(config_yaml: &str, events: Vec<Event>, actions: Vec<Action>) {
assert_actions_with_current_application(config_yaml, None, events, actions);
}
pub 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),
WMClient::new("static", Box::new(StaticClient { current_application })),
);
let mut actual: Vec<Action> = vec![];
actual.append(&mut event_handler.on_events(&events, &config).unwrap());
assert_eq!(format!("{actions:?}"), format!("{:?}", actual));
}