xremap 0.15.7

Dynamic key remap for X and Wayland
Documentation
use nix::sys::time::TimeSpec;
use nix::sys::timerfd::{ClockId, Expiration, TimerFd, TimerFlags, TimerSetTimeFlags};
use std::cell::RefCell;
use std::os::fd::{AsFd, BorrowedFd};
use std::time::{Duration, Instant};

static RESOLUTION: Duration = Duration::from_millis(1);

#[derive(Debug)]
pub struct TimeoutManager {
    timer: TimerFd,
    delays: RefCell<Vec<Instant>>,
}

impl TimeoutManager {
    pub fn new() -> Self {
        Self {
            timer: TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap(),
            delays: RefCell::new(vec![]),
        }
    }

    pub fn set_timeout(&self, delay: Duration) -> nix::Result<()> {
        set_timeout(&mut self.delays.borrow_mut(), delay, &self.timer)
    }

    pub fn need_timeout(&self) -> anyhow::Result<bool> {
        need_timeout(&mut self.delays.borrow_mut(), &self.timer)
    }
}

impl AsFd for TimeoutManager {
    fn as_fd(&self) -> BorrowedFd<'_> {
        self.timer.as_fd()
    }
}

fn set_timeout(delays: &mut Vec<Instant>, delay: Duration, timer: &TimerFd) -> nix::Result<()> {
    set_timer(timer)?;

    delays.push(Instant::now() + delay);

    Ok(())
}

fn need_timeout(delays: &mut Vec<Instant>, timer: &TimerFd) -> anyhow::Result<bool> {
    let now = Instant::now();

    let need_timeout = delays.iter().any(|timeout_inst| timeout_inst <= &now);

    delays.retain(|&timeout_inst| timeout_inst > now);

    if delays.is_empty() {
        timer.unset()?;
    } else {
        set_timer(timer)?;
    }

    Ok(need_timeout)
}

// Could pick the minimal delay to avoid unneeded ticks.
fn set_timer(timer: &TimerFd) -> nix::Result<()> {
    timer.set(Expiration::OneShot(TimeSpec::from_duration(RESOLUTION)), TimerSetTimeFlags::empty())
}