okey-cli 0.1.2

An advanced, easy-to-use key remapper for Linux
Documentation
use std::{thread, time::Duration};

use evdev::{EventType, InputEvent};

use crate::{config::schema::Config, core::EventProxy};

pub trait EventProcessor {
    fn process_input(&mut self, event: InputEvent) -> Result<()>;

    fn process(&mut self, buffer: InputBuffer) -> Result<()> {
        for event in buffer.value() {
            self.process_input(*event)?;
        }

        Ok(())
    }
}

impl<P: EventProxy> EventProcessor for KeyAdapter<'_, P> {
    fn process_input(&mut self, event: InputEvent) -> Result<()> {
        self.process_event(event)?;
        self.post_process()
    }
}

#[derive(Debug, Default)]
pub struct EventProxyMock {
    queue: Vec<InputEvent>,
}

impl EventProxyMock {
    pub fn queue(&self) -> &[InputEvent] {
        &self.queue
    }

    pub fn clear(&mut self) {
        self.queue.clear();
    }
}

impl EventProxy for EventProxyMock {
    fn emit(&mut self, events: &[evdev::InputEvent]) -> anyhow::Result<()> {
        self.queue.extend(events);
        Ok(())
    }

    fn wait(&mut self, timeout: u16) -> Result<()> {
        thread::sleep(Duration::from_millis(timeout.into()));
        Ok(())
    }
}

impl<'a, P: EventProxy> KeyAdapter<'a, P> {
    pub fn with_config(config: &str, proxy: &'a mut P) -> Self {
        let mut config: Config = serde_yaml::from_str(config).unwrap();
        let keyboard = config.keyboards.remove(0);
        let defaults = config.defaults.clone();

        KeyAdapter::new(keyboard, defaults, proxy)
    }
}

pub trait EventTarget: Sized {
    fn code(&self) -> KeyCode;
    fn release(self) -> InputBuffer;
    fn press(self) -> InputBuffer;
    fn hold(self) -> InputBuffer;
    fn into_value(self) -> Vec<InputEvent>;

    fn tap(self) -> InputBuffer {
        self.press().release()
    }

    fn tap_hold(self) -> InputBuffer {
        self.press().hold().release()
    }

    fn tap_then(self, next: KeyCode) -> InputBuffer {
        self.tap().then(next)
    }

    fn press_then(self, next: KeyCode) -> InputBuffer {
        self.press().then(next)
    }

    fn hold_then(self, next: KeyCode) -> InputBuffer {
        self.hold().then(next)
    }

    fn release_then(self, next: KeyCode) -> InputBuffer {
        self.release().then(next)
    }

    fn shifted(self) -> InputBuffer {
        let code = self.code();

        let buffer = InputBuffer::new(KeyCode::KEY_LEFTSHIFT)
            .press()
            .hold()
            .then(code)
            .tap_then(KeyCode::KEY_LEFTSHIFT)
            .release();

        InputBuffer::new(code).chain(self).chain(buffer)
    }
}

#[derive(Debug, Clone)]
pub struct InputBuffer {
    current_code: KeyCode,
    buffer: Vec<InputEvent>,
}

impl InputBuffer {
    pub fn new(code: KeyCode) -> Self {
        Self {
            current_code: code,
            buffer: Vec::new(),
        }
    }

    pub fn then(mut self, code: KeyCode) -> Self {
        self.current_code = code;
        self
    }

    pub fn value(&self) -> &[InputEvent] {
        &self.buffer
    }

    pub fn chain<E: EventTarget>(mut self, other: E) -> Self {
        self.buffer.extend(other.into_value());
        self
    }

    pub fn press(code: KeyCode) -> Self {
        Self::new(code).press()
    }

    pub fn release(code: KeyCode) -> Self {
        Self::new(code).release()
    }

    pub fn tap(code: KeyCode) -> Self {
        Self::new(code).tap()
    }

    pub fn tap_hold(code: KeyCode) -> Self {
        Self::new(code).tap_hold()
    }

    pub fn combo_press(first: KeyCode, other: KeyCode) -> Self {
        Self::new(first).press_then(other).press()
    }

    pub fn combo_hold(first: KeyCode, other: KeyCode) -> Self {
        Self::new(first).hold_then(other).hold()
    }

    pub fn combo_release(first: KeyCode, other: KeyCode) -> Self {
        Self::new(first).release_then(other).release()
    }
}

impl EventTarget for InputBuffer {
    fn code(&self) -> KeyCode {
        self.current_code
    }

    fn into_value(self) -> Vec<InputEvent> {
        self.buffer
    }

    fn release(mut self) -> InputBuffer {
        self.buffer.push(release(self.current_code));
        self
    }

    fn press(mut self) -> InputBuffer {
        self.buffer.push(press(self.current_code));
        self
    }

    fn hold(mut self) -> InputBuffer {
        self.buffer.push(hold(self.current_code));
        self
    }
}

pub fn unicode() -> InputBuffer {
    InputBuffer::new(KeyCode::KEY_LEFTCTRL)
        .press_then(KeyCode::KEY_LEFTSHIFT)
        .press_then(KeyCode::KEY_U)
        .press_then(KeyCode::KEY_LEFTCTRL)
        .hold_then(KeyCode::KEY_LEFTSHIFT)
        .hold_then(KeyCode::KEY_U)
        .hold_then(KeyCode::KEY_LEFTCTRL)
        .release_then(KeyCode::KEY_LEFTSHIFT)
        .release_then(KeyCode::KEY_U)
        .release()
}

fn release(code: KeyCode) -> InputEvent {
    InputEvent::new(EventType::KEY.0, code.code(), 0)
}

fn press(code: KeyCode) -> InputEvent {
    InputEvent::new(EventType::KEY.0, code.code(), 1)
}

fn hold(code: KeyCode) -> InputEvent {
    InputEvent::new(EventType::KEY.0, code.code(), 2)
}

pub use anyhow::Result;
pub use evdev::KeyCode;

pub use crate::core::KeyAdapter;