use std::collections::HashMap;
use windows::Win32::Foundation::*;
use windows::Win32::UI::Input::KeyboardAndMouse::*;
use rgpui::{Keystroke, Modifiers, Result};
const MOD_CONTROL: u32 = 0x0002;
const MOD_ALT: u32 = 0x0001;
const MOD_SHIFT: u32 = 0x0004;
const MOD_WIN: u32 = 0x0008;
pub struct WindowsGlobalHotkey {
registrations: HashMap<i32, (HWND, HOT_KEY_MODIFIERS, VIRTUAL_KEY)>,
}
impl WindowsGlobalHotkey {
pub fn new() -> Self {
Self {
registrations: HashMap::new(),
}
}
pub fn register(&mut self, hwnd: HWND, id: i32, keystroke: &Keystroke) -> Result<()> {
let modifiers = self.modifiers_to_win(keystroke.modifiers);
let vk = self.key_to_virtual_key(keystroke);
unsafe {
RegisterHotKey(Some(hwnd), id, modifiers, vk.0 as u32).map_err(|e| {
anyhow::anyhow!("无法注册全局快捷键: {:?} (错误: {:?})", keystroke, e)
})?;
}
self.registrations.insert(id, (hwnd, modifiers, vk));
Ok(())
}
pub fn unregister(&mut self, id: i32) {
if let Some((hwnd, _, _)) = self.registrations.remove(&id) {
unsafe {
let _ = UnregisterHotKey(Some(hwnd), id);
}
}
}
fn modifiers_to_win(&self, modifiers: Modifiers) -> HOT_KEY_MODIFIERS {
let mut mod_flags: u32 = 0;
if modifiers.control {
mod_flags |= MOD_CONTROL;
}
if modifiers.alt {
mod_flags |= MOD_ALT;
}
if modifiers.shift {
mod_flags |= MOD_SHIFT;
}
if modifiers.platform {
mod_flags |= MOD_WIN;
}
HOT_KEY_MODIFIERS(mod_flags)
}
fn key_to_virtual_key(&self, keystroke: &Keystroke) -> VIRTUAL_KEY {
let key = keystroke.key.as_str();
match key {
"f1" => VK_F1,
"f2" => VK_F2,
"f3" => VK_F3,
"f4" => VK_F4,
"f5" => VK_F5,
"f6" => VK_F6,
"f7" => VK_F7,
"f8" => VK_F8,
"f9" => VK_F9,
"f10" => VK_F10,
"f11" => VK_F11,
"f12" => VK_F12,
"space" => VK_SPACE,
"escape" => VK_ESCAPE,
"enter" => VK_RETURN,
"tab" => VK_TAB,
"backspace" => VK_BACK,
"delete" => VK_DELETE,
"insert" => VK_INSERT,
"home" => VK_HOME,
"end" => VK_END,
"pageup" => VK_PRIOR,
"pagedown" => VK_NEXT,
"up" => VK_UP,
"down" => VK_DOWN,
"left" => VK_LEFT,
"right" => VK_RIGHT,
c if c.len() == 1 => {
let ch = c.chars().next().unwrap();
if ch.is_ascii_alphabetic() {
VIRTUAL_KEY(ch.to_ascii_uppercase() as u16)
} else if ch.is_ascii_digit() {
VIRTUAL_KEY(ch as u16)
} else {
VIRTUAL_KEY(ch as u16)
}
}
_ => VIRTUAL_KEY(0),
}
}
}