use core::fmt;
use once_cell::sync::Lazy;
use parking_lot::Mutex;
use winapi::ctypes::*;
use winapi::um::winuser::*;
use crate::oskbd::{KeyEvent, KeyValue};
use kanata_keyberon::key_code::KeyCode;
use kanata_parser::keys::*;
pub const LLHOOK_IDLE_TIME_SECS_CLEAR_INPUTS: u64 = 60;
type HookFn = dyn FnMut(InputEvent) -> bool + Send + Sync + 'static;
pub static HOOK_CB: Lazy<Mutex<Option<Box<HookFn>>>> = Lazy::new(|| Mutex::new(None));
pub struct KeyboardHook {} impl KeyboardHook {
pub fn set_input_cb(
callback: impl FnMut(InputEvent) -> bool + Send + Sync + 'static,
) -> KeyboardHook {
let mut cb_opt = HOOK_CB.lock();
assert!(
cb_opt.take().is_none(),
"Only 1 external listener is allowed!"
);
*cb_opt = Some(Box::new(callback));
KeyboardHook {}
}
}
#[cfg(not(feature = "passthru_ahk"))] impl Drop for KeyboardHook {
fn drop(&mut self) {
let mut cb_opt = HOOK_CB.lock();
cb_opt.take();
}
}
#[derive(Debug, Clone, Copy)]
pub struct InputEvent {
pub code: u32,
pub up: bool,
}
impl fmt::Display for InputEvent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let direction = if self.up { "↑" } else { "↓" };
let key_name = KeyCode::from(OsCode::from(self.code));
write!(f, "{direction}{key_name:?}")
}
}
impl InputEvent {
pub fn from_vk_sc(vk: c_uint, sc: c_uint, up: c_int) -> Self {
let code = if vk == (VK_RETURN as u32) {
match sc {
0x11C => u32::from(VK_KPENTER_FAKE),
_ => VK_RETURN as u32,
}
} else {
vk
};
Self {
code,
up: (up != 0),
}
}
pub fn from_oscode(code: OsCode, val: KeyValue) -> Self {
Self {
code: code.into(),
up: val.into(),
}
}
}
impl TryFrom<InputEvent> for KeyEvent {
type Error = ();
fn try_from(item: InputEvent) -> Result<Self, Self::Error> {
Ok(Self {
code: OsCode::from_u16(item.code as u16).ok_or(())?,
value: match item.up {
true => KeyValue::Release,
false => KeyValue::Press,
},
})
}
}
impl From<KeyEvent> for InputEvent {
fn from(item: KeyEvent) -> Self {
Self {
code: item.code.into(),
up: item.value.into(),
}
}
}