hookmap 0.5.1

Registers hotkeys and simulates keyboard and mouse input.
Documentation
use hookmap_core::button::{Button, ButtonAction};
use hookmap_core::event::{ButtonEvent, NativeEventOperation};

use super::context::Modifiers;
use crate::hook::{ButtonState, Hook};

use std::fmt::Debug;
use std::sync::{
    atomic::{AtomicBool, Ordering},
    Arc,
};

#[derive(Clone)]
pub struct Process<E>(Arc<dyn Fn(E) + Send + Sync>);

impl<E> Debug for Process<E> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_tuple("Process").field(&"Fn").finish()
    }
}

impl<E, F: Fn(E) + Send + Sync + 'static> From<F> for Process<E> {
    fn from(this: F) -> Self {
        Process(Arc::new(this))
    }
}

impl<E, F: Fn(E) + Send + Sync + 'static> From<Arc<F>> for Process<E> {
    fn from(this: Arc<F>) -> Self {
        Process(this)
    }
}

#[derive(Debug, Clone)]
pub(super) enum Condition {
    Any,
    Activation(Arc<AtomicBool>),
    Modifier(Arc<Modifiers>),
}

impl Condition {
    fn is_satisfied(&self, state: &impl ButtonState) -> bool {
        match self {
            Condition::Any => true,
            Condition::Activation(is_active) => is_active.swap(false, Ordering::SeqCst),
            Condition::Modifier(modifiers) => modifiers.is_matched(state),
        }
    }
}

#[derive(Debug, Clone)]
pub(super) enum HotkeyAction<E> {
    Process(Process<E>),
    Activate(Arc<AtomicBool>),
    Noop,
}

impl<E> HotkeyAction<E> {
    pub(super) fn run(&self, event: E) {
        match self {
            HotkeyAction::Process(callback) => callback.0(event),
            HotkeyAction::Activate(is_active) => is_active.store(true, Ordering::SeqCst),
            HotkeyAction::Noop => {}
        }
    }
}

#[derive(Debug)]
pub(super) struct HotkeyHook {
    condition: Condition,
    action: HotkeyAction<ButtonEvent>,
    native_event_operation: NativeEventOperation,
}

impl HotkeyHook {
    pub(super) fn new(
        condition: Condition,
        action: HotkeyAction<ButtonEvent>,
        native_event_operation: NativeEventOperation,
    ) -> Self {
        HotkeyHook {
            condition,
            action,
            native_event_operation,
        }
    }

    pub(super) fn is_executable(&self, state: &impl ButtonState) -> bool {
        self.condition.is_satisfied(state)
    }
}

#[derive(Debug)]
pub(super) struct RemapHook {
    condition: Condition,
    button: Button,
}

impl RemapHook {
    pub(super) fn new(condition: Condition, button: Button) -> Self {
        assert!(!matches!(condition, Condition::Activation(_)));
        RemapHook { condition, button }
    }

    pub(super) fn is_executable(&self, state: &impl ButtonState) -> bool {
        self.condition.is_satisfied(state)
    }
}

#[derive(Debug)]
pub(super) enum ButtonHook {
    Hotkey(Arc<HotkeyHook>),
    Remap(Arc<RemapHook>),
}

impl Hook<ButtonEvent> for ButtonHook {
    fn native_event_operation(&self) -> NativeEventOperation {
        match self {
            ButtonHook::Hotkey(hook) => hook.native_event_operation,
            ButtonHook::Remap(_) => NativeEventOperation::Block,
        }
    }

    fn run(&self, event: ButtonEvent) {
        match self {
            ButtonHook::Hotkey(hook) => hook.action.run(event),
            ButtonHook::Remap(hook) => match event.action {
                ButtonAction::Press => hook.button.press(),
                ButtonAction::Release => hook.button.release(),
            },
        }
    }
}
impl From<Arc<HotkeyHook>> for ButtonHook {
    fn from(hook: Arc<HotkeyHook>) -> Self {
        ButtonHook::Hotkey(hook)
    }
}
impl From<Arc<RemapHook>> for ButtonHook {
    fn from(remap: Arc<RemapHook>) -> Self {
        ButtonHook::Remap(remap)
    }
}

#[derive(Debug)]
pub(super) struct MouseHook<E> {
    condition: Condition,
    process: Process<E>,
    native_event_operation: NativeEventOperation,
}

impl<E> MouseHook<E> {
    pub(super) fn new(
        condition: Condition,
        process: Process<E>,
        native_event_operation: NativeEventOperation,
    ) -> Self {
        assert!(!matches!(condition, Condition::Activation(_)));
        MouseHook {
            condition,
            process,
            native_event_operation,
        }
    }
}

impl<E> MouseHook<E> {
    pub(super) fn is_executable(&self, state: &impl ButtonState) -> bool {
        self.condition.is_satisfied(state)
    }
}

impl<E> Hook<E> for MouseHook<E> {
    fn native_event_operation(&self) -> NativeEventOperation {
        self.native_event_operation
    }

    fn run(&self, event: E) {
        self.process.0(event);
    }
}

impl<E, T: Hook<E>> Hook<E> for Arc<T> {
    fn native_event_operation(&self) -> NativeEventOperation {
        (**self).native_event_operation()
    }

    fn run(&self, event: E) {
        (**self).run(event);
    }
}