Merge pull request #82 from k0kubun/remap-timeout

Add timeout_millis for nested remap
pull/86/head
Takashi Kokubun 2 years ago committed by GitHub
commit 18b68bc001
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,9 +1,11 @@
use crate::config::key_press::KeyPress; use crate::config::key_press::KeyPress;
use std::collections::HashMap; use std::collections::HashMap;
use crate::config::remap::Remap;
use serde::de; use serde::de;
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer};
use std::fmt::Debug; use std::fmt::Debug;
use std::time::Duration;
// Values in `keymap.remap` // Values in `keymap.remap`
#[derive(Clone, Debug, Deserialize)] #[derive(Clone, Debug, Deserialize)]
@ -11,7 +13,7 @@ use std::fmt::Debug;
pub enum Action { pub enum Action {
KeyPress(KeyPress), KeyPress(KeyPress),
#[serde(deserialize_with = "deserialize_remap")] #[serde(deserialize_with = "deserialize_remap")]
Remap(HashMap<KeyPress, Vec<Action>>), Remap(Remap),
#[serde(deserialize_with = "deserialize_launch")] #[serde(deserialize_with = "deserialize_launch")]
Launch(Vec<String>), Launch(Vec<String>),
#[serde(deserialize_with = "deserialize_set_mark")] #[serde(deserialize_with = "deserialize_set_mark")]
@ -22,17 +24,15 @@ pub enum Action {
EscapeNextKey(bool), EscapeNextKey(bool),
} }
fn deserialize_remap<'de, D>(deserializer: D) -> Result<HashMap<KeyPress, Vec<Action>>, D::Error> fn deserialize_remap<'de, D>(deserializer: D) -> Result<Remap, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
let mut action = HashMap::<String, HashMap<KeyPress, Actions>>::deserialize(deserializer)?; let action = RemapActions::deserialize(deserializer)?;
if let Some(remap) = action.remove("remap") { return Ok(Remap {
if action.is_empty() { remap: action.remap.into_iter().map(|(k, v)| (k, v.into_vec())).collect(),
return Ok(remap.into_iter().map(|(k, v)| (k, v.into_vec())).collect()); timeout: action.timeout_millis.map(|ms| Duration::from_millis(ms)),
} });
}
Err(de::Error::custom("not a map with a single \"remap\" key"))
} }
fn deserialize_launch<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error> fn deserialize_launch<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
@ -88,7 +88,7 @@ where
} }
// Used only for deserializing Vec<Action> // Used only for deserializing Vec<Action>
#[derive(Clone, Deserialize)] #[derive(Clone, Debug, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
pub enum Actions { pub enum Actions {
Action(Action), Action(Action),
@ -103,3 +103,10 @@ impl Actions {
} }
} }
} }
// Used only for deserializing Remap with Vec<Action>
#[derive(Debug, Deserialize)]
pub struct RemapActions {
pub remap: HashMap<KeyPress, Actions>,
pub timeout_millis: Option<u64>,
}

@ -6,6 +6,7 @@ pub mod key_press;
mod keymap; mod keymap;
mod modmap; mod modmap;
mod remap;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;

@ -0,0 +1,10 @@
use crate::config::action::Action;
use crate::config::key_press::KeyPress;
use std::collections::HashMap;
use std::time::Duration;
#[derive(Clone, Debug)]
pub struct Remap {
pub remap: HashMap<KeyPress, Vec<Action>>,
pub timeout: Option<Duration>,
}

@ -110,6 +110,7 @@ fn test_keymap_remap() {
C-s: C-s:
remap: remap:
x: C-z x: C-z
timeout_millis: 1000
"}) "})
} }

@ -10,6 +10,8 @@ use lazy_static::lazy_static;
use log::{debug, error}; use log::{debug, error};
use nix::sys::signal; use nix::sys::signal;
use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet}; use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet};
use nix::sys::time::TimeSpec;
use nix::sys::timerfd::{Expiration, TimerFd, TimerSetTimeFlags};
use std::collections::HashMap; use std::collections::HashMap;
use std::error::Error; use std::error::Error;
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
@ -17,6 +19,7 @@ use std::time::Instant;
pub struct EventHandler { pub struct EventHandler {
device: VirtualDevice, device: VirtualDevice,
timer: TimerFd,
shift: PressState, shift: PressState,
control: PressState, control: PressState,
alt: PressState, alt: PressState,
@ -25,15 +28,17 @@ pub struct EventHandler {
application_cache: Option<String>, application_cache: Option<String>,
multi_purpose_keys: HashMap<Key, MultiPurposeKeyState>, multi_purpose_keys: HashMap<Key, MultiPurposeKeyState>,
override_remap: Option<HashMap<KeyPress, Vec<Action>>>, override_remap: Option<HashMap<KeyPress, Vec<Action>>>,
override_timeout_key: Option<Key>,
sigaction_set: bool, sigaction_set: bool,
mark_set: bool, mark_set: bool,
escape_next_key: bool, escape_next_key: bool,
} }
impl EventHandler { impl EventHandler {
pub fn new(device: VirtualDevice) -> EventHandler { pub fn new(device: VirtualDevice, timer: TimerFd) -> EventHandler {
EventHandler { EventHandler {
device, device,
timer,
shift: PressState::new(), shift: PressState::new(),
control: PressState::new(), control: PressState::new(),
alt: PressState::new(), alt: PressState::new(),
@ -42,6 +47,7 @@ impl EventHandler {
application_cache: None, application_cache: None,
multi_purpose_keys: HashMap::new(), multi_purpose_keys: HashMap::new(),
override_remap: None, override_remap: None,
override_timeout_key: None,
sigaction_set: false, sigaction_set: false,
mark_set: false, mark_set: false,
escape_next_key: false, escape_next_key: false,
@ -71,9 +77,9 @@ impl EventHandler {
} else if is_pressed(value) { } else if is_pressed(value) {
if self.escape_next_key { if self.escape_next_key {
self.escape_next_key = false self.escape_next_key = false
} else if let Some(actions) = self.find_keymap(config, &key) { } else if let Some(actions) = self.find_keymap(config, &key)? {
for action in &actions { for action in &actions {
self.dispatch_action(action)?; self.dispatch_action(action, &key)?;
} }
continue; continue;
} }
@ -90,6 +96,21 @@ impl EventHandler {
self.device.emit(&[event]) self.device.emit(&[event])
} }
pub fn timeout_override(&mut self) -> Result<(), Box<dyn Error>> {
if let Some(key) = self.override_timeout_key {
self.send_key(&key, PRESS)?;
self.send_key(&key, RELEASE)?;
}
self.remove_override()
}
fn remove_override(&mut self) -> Result<(), Box<dyn Error>> {
self.timer.unset()?;
self.override_remap = None;
self.override_timeout_key = None;
Ok(())
}
fn send_key(&mut self, key: &Key, value: i32) -> std::io::Result<()> { fn send_key(&mut self, key: &Key, value: i32) -> std::io::Result<()> {
let event = InputEvent::new(EventType::KEY, key.code(), value); let event = InputEvent::new(EventType::KEY, key.code(), value);
self.send_event(event) self.send_event(event)
@ -161,7 +182,7 @@ impl EventHandler {
None None
} }
fn find_keymap(&mut self, config: &Config, key: &Key) -> Option<Vec<Action>> { fn find_keymap(&mut self, config: &Config, key: &Key) -> Result<Option<Vec<Action>>, Box<dyn Error>> {
let key_press = KeyPress { let key_press = KeyPress {
key: *key, key: *key,
shift: self.shift.to_modifier_state(), shift: self.shift.to_modifier_state(),
@ -170,10 +191,11 @@ impl EventHandler {
windows: self.windows.to_modifier_state(), windows: self.windows.to_modifier_state(),
}; };
if let Some(override_remap) = &self.override_remap { if let Some(override_remap) = &self.override_remap {
let override_remap = override_remap.clone(); if let Some(actions) = override_remap.clone().get(&key_press) {
self.override_remap = None; self.remove_override()?;
if let Some(actions) = override_remap.get(&key_press) { return Ok(Some(actions.to_vec()));
return Some(actions.to_vec()); } else {
self.timeout_override()?;
} }
} }
for keymap in &config.keymap { for keymap in &config.keymap {
@ -183,21 +205,27 @@ impl EventHandler {
continue; continue;
} }
} }
return Some(actions.to_vec()); return Ok(Some(actions.to_vec()));
} }
} }
None Ok(None)
} }
fn dispatch_action(&mut self, action: &Action) -> Result<(), Box<dyn Error>> { fn dispatch_action(&mut self, action: &Action, key: &Key) -> Result<(), Box<dyn Error>> {
match action { match action {
Action::KeyPress(key_press) => self.send_key_press(key_press)?, Action::KeyPress(key_press) => self.send_key_press(key_press)?,
Action::Remap(remap) => { Action::Remap(action) => {
let mut override_remap: HashMap<KeyPress, Vec<Action>> = HashMap::new(); let mut override_remap: HashMap<KeyPress, Vec<Action>> = HashMap::new();
for (key_press, actions) in remap.iter() { for (key_press, actions) in action.remap.iter() {
override_remap.insert(key_press.clone(), actions.to_vec()); override_remap.insert(key_press.clone(), actions.to_vec());
} }
self.override_remap = Some(override_remap) self.override_remap = Some(override_remap);
if let Some(timeout) = action.timeout {
let expiration = Expiration::OneShot(TimeSpec::from_duration(timeout));
self.timer.unset()?;
self.timer.set(expiration, TimerSetTimeFlags::empty())?;
self.override_timeout_key = Some(key.clone());
}
} }
Action::Launch(command) => self.run_command(command.clone()), Action::Launch(command) => self.run_command(command.clone()),
Action::SetMark(set) => self.mark_set = *set, Action::SetMark(set) => self.mark_set = *set,

@ -11,8 +11,9 @@ use nix::libc::ENODEV;
use nix::sys::inotify::{AddWatchFlags, Inotify}; use nix::sys::inotify::{AddWatchFlags, Inotify};
use nix::sys::select::select; use nix::sys::select::select;
use nix::sys::select::FdSet; use nix::sys::select::FdSet;
use nix::sys::timerfd::{ClockId, TimerFd, TimerFlags};
use std::io::stdout; use std::io::stdout;
use std::os::unix::io::AsRawFd; use std::os::unix::io::{AsRawFd, RawFd};
use std::path::PathBuf; use std::path::PathBuf;
mod client; mod client;
@ -97,7 +98,9 @@ fn main() -> anyhow::Result<()> {
Ok(output_device) => output_device, Ok(output_device) => output_device,
Err(e) => bail!("Failed to prepare an output device: {}", e), Err(e) => bail!("Failed to prepare an output device: {}", e),
}; };
let mut handler = EventHandler::new(output_device); let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty())?;
let timer_fd = timer.as_raw_fd();
let mut handler = EventHandler::new(output_device, timer);
let mut input_devices = match get_input_devices(&device_filter, &ignore_filter, watch_devices) { let mut input_devices = match get_input_devices(&device_filter, &ignore_filter, watch_devices) {
Ok(input_devices) => input_devices, Ok(input_devices) => input_devices,
Err(e) => bail!("Failed to prepare input devices: {}", e), Err(e) => bail!("Failed to prepare input devices: {}", e),
@ -108,7 +111,13 @@ fn main() -> anyhow::Result<()> {
loop { loop {
match 'event_loop: loop { match 'event_loop: loop {
let readable_fds = select_readable(input_devices.values(), &watchers)?; let readable_fds = select_readable(input_devices.values(), &watchers, timer_fd)?;
if readable_fds.contains(timer_fd) {
if let Err(error) = handler.timeout_override() {
println!("Error on remap timeout: {error}")
}
}
for input_device in input_devices.values_mut() { for input_device in input_devices.values_mut() {
if readable_fds.contains(input_device.as_raw_fd()) { if readable_fds.contains(input_device.as_raw_fd()) {
match input_device.fetch_events().map_err(|e| (e.raw_os_error(), e)) { match input_device.fetch_events().map_err(|e| (e.raw_os_error(), e)) {
@ -210,8 +219,13 @@ enum Event {
ReloadDevices, ReloadDevices,
} }
fn select_readable<'a>(devices: impl Iterator<Item = &'a InputDevice>, watchers: &[&Inotify]) -> anyhow::Result<FdSet> { fn select_readable<'a>(
devices: impl Iterator<Item = &'a InputDevice>,
watchers: &[&Inotify],
timer_fd: RawFd,
) -> anyhow::Result<FdSet> {
let mut read_fds = FdSet::new(); let mut read_fds = FdSet::new();
read_fds.insert(timer_fd);
for device in devices { for device in devices {
read_fds.insert(device.as_raw_fd()); read_fds.insert(device.as_raw_fd());
} }

Loading…
Cancel
Save