use crate::state::KeyboardState;
use crate::VKey;
use std::fmt;
use std::hash::{DefaultHasher, Hash, Hasher};
pub struct Hotkey<T> {
trigger_key: VKey,
modifiers: Vec<VKey>,
callback: Box<dyn Fn() -> T + Send + 'static>,
}
impl<T> Hotkey<T> {
pub fn new(
trigger_key: VKey,
modifiers: &[VKey],
callback: impl Fn() -> T + Send + 'static,
) -> Hotkey<T> {
Self {
trigger_key,
modifiers: modifiers.to_vec(),
callback: Box::new(callback),
}
}
pub fn callback(&self) -> T {
(self.callback)()
}
pub fn is_trigger_state(&self, keyboard_state: KeyboardState) -> bool {
let state = self.generate_keyboard_state();
let mut keys = self.modifiers.clone();
keys.push(self.trigger_key);
for key in &keys {
if !keyboard_state.is_down(key.to_vk_code()) {
return false;
}
}
state.is_down(VKey::Shift.to_vk_code()) == keyboard_state.is_down(VKey::Shift.to_vk_code())
&& state.is_down(VKey::Control.to_vk_code())
== keyboard_state.is_down(VKey::Control.to_vk_code())
&& state.is_down(VKey::Menu.to_vk_code())
== keyboard_state.is_down(VKey::Menu.to_vk_code())
&& state.is_down(VKey::LWin.to_vk_code())
== keyboard_state.is_down(VKey::LWin.to_vk_code())
}
pub fn generate_id(&self) -> i32 {
let mut hasher = DefaultHasher::new();
self.trigger_key.hash(&mut hasher);
self.modifiers.hash(&mut hasher);
let hash = hasher.finish();
(hash & 0xFFFF_FFFF) as i32
}
pub fn generate_keyboard_state(&self) -> KeyboardState {
let mut keyboard_state = KeyboardState::new();
keyboard_state.keydown(self.trigger_key.to_vk_code());
for key in &self.modifiers {
keyboard_state.keydown(key.to_vk_code());
}
keyboard_state
}
}
impl fmt::Debug for Hotkey<()> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Hotkey")
.field("trigger_key", &self.trigger_key)
.field("modifiers", &self.modifiers)
.field("callback", &"<callback>")
.finish()
}
}
impl PartialEq for Hotkey<()> {
fn eq(&self, other: &Self) -> bool {
self.generate_keyboard_state() == other.generate_keyboard_state()
}
}
impl Eq for Hotkey<()> {}