use crate::error::WHKError;
use crate::error::WHKError::RegistrationFailed;
use crate::hook;
use crate::hook::{KeyAction, KeyboardEvent};
use crate::hotkey::Hotkey;
use crate::state::KeyboardState;
use crate::VKey;
use crossbeam_channel::Sender;
use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
pub struct HotkeyManager<T> {
hotkeys: HashMap<u16, Vec<Hotkey<T>>>,
paused_ids: Vec<i32>,
paused: Arc<AtomicBool>,
interrupt: Arc<AtomicBool>,
callback_results_channel: Option<Sender<T>>,
}
impl<T> Default for HotkeyManager<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> HotkeyManager<T> {
pub fn new() -> HotkeyManager<T> {
Self {
hotkeys: HashMap::new(),
paused_ids: Vec::new(),
paused: Arc::new(AtomicBool::new(false)),
interrupt: Arc::new(AtomicBool::new(false)),
callback_results_channel: None,
}
}
pub fn register_hotkey(
&mut self,
trigger_key: VKey,
mod_keys: &[VKey],
callback: impl Fn() -> T + Send + 'static,
) -> Result<i32, WHKError> {
let hotkey = Hotkey::new(trigger_key, mod_keys, callback);
let id = hotkey.generate_id();
if self
.hotkeys
.values()
.any(|vec| vec.iter().any(|hotkey| hotkey.generate_id() == id))
{
return Err(RegistrationFailed);
}
self.hotkeys
.entry(trigger_key.to_vk_code())
.or_default()
.push(hotkey);
Ok(id)
}
pub fn unregister_hotkey(&mut self, hotkey_id: i32) {
for vec in self.hotkeys.values_mut() {
vec.retain(|hotkey| hotkey.generate_id() != hotkey_id);
}
self.paused_ids.retain(|id| *id != hotkey_id);
}
pub fn unregister_all(&mut self) {
self.hotkeys.clear();
self.paused_ids.clear();
}
pub fn register_pause_hotkey(
&mut self,
trigger_key: VKey,
mod_keys: &[VKey],
callback: impl Fn() -> T + Send + 'static,
) -> Result<i32, WHKError> {
let paused = Arc::clone(&self.paused);
let wrapped_callback = move || {
let was_paused = paused.load(Ordering::Relaxed);
paused.store(!was_paused, Ordering::Relaxed);
callback()
};
let id = self.register_hotkey(trigger_key, mod_keys, wrapped_callback)?;
self.paused_ids.push(id);
Ok(id)
}
pub fn register_channel(&mut self, channel: Sender<T>) {
self.callback_results_channel = Some(channel);
}
pub fn event_loop(&mut self) {
let hook = hook::start();
while !self.interrupt.load(Ordering::Relaxed) {
if let Ok(event) = hook.recv() {
let (key_code, state) = match event {
KeyboardEvent::KeyDown {
vk_code: key_code,
keyboard_state: state,
} => (key_code, state),
_ => continue,
};
let mut found = false;
if let Some(hotkeys) = self.hotkeys.get_mut(&key_code) {
for hotkey in hotkeys {
if self.paused.load(Ordering::Relaxed)
&& !self.paused_ids.contains(&hotkey.generate_id())
{
continue;
}
if hotkey.is_trigger_state(state) {
if state.is_down(VKey::LWin.to_vk_code()) {
hook.key_action(KeyAction::Replace);
} else {
hook.key_action(KeyAction::Block);
}
let result = hotkey.callback();
if let Some(callback_result_channel) = &self.callback_results_channel {
callback_result_channel.send(result).unwrap();
}
found = true;
break;
}
}
}
if !found {
hook.key_action(KeyAction::Allow);
}
}
}
hook.exit();
}
pub fn interrupt_handle(&self) -> InterruptHandle {
InterruptHandle {
interrupt: Arc::clone(&self.interrupt),
}
}
pub fn pause_handle(&self) -> PauseHandle {
PauseHandle {
pause: Arc::clone(&self.paused),
}
}
}
#[derive(Debug, Clone)]
pub struct InterruptHandle {
interrupt: Arc<AtomicBool>,
}
impl InterruptHandle {
pub fn interrupt(&self) {
use crate::hook::{KeyboardEvent, HOOK_EVENT_TX};
let dummy_event = KeyboardEvent::KeyDown {
vk_code: 0,
keyboard_state: KeyboardState::new(),
};
self.interrupt.store(true, Ordering::Relaxed);
let event_tx = HOOK_EVENT_TX.read().unwrap();
if let Some(ke_tx) = &*event_tx {
ke_tx.send(dummy_event).unwrap();
}
}
}
#[derive(Debug, Clone)]
pub struct PauseHandle {
pause: Arc<AtomicBool>,
}
impl PauseHandle {
pub fn toggle(&self) {
self.pause
.store(!self.pause.load(Ordering::Relaxed), Ordering::Relaxed);
}
pub fn set(&self, state: bool) {
self.pause.store(state, Ordering::Relaxed);
}
pub fn is_paused(&self) -> bool {
self.pause.load(Ordering::Relaxed)
}
}