use crate::utils::commands::center_window_on_current_monitor; use global_hotkey::{ hotkey::{Code, HotKey, Modifiers}, GlobalHotKeyEvent, GlobalHotKeyManager, HotKeyState, }; use std::str::FromStr; use tauri::{AppHandle, Listener, Manager}; use std::sync::Arc; pub fn setup(app_handle: tauri::AppHandle) { let app_handle_clone = app_handle.clone(); let manager = Arc::new(GlobalHotKeyManager::new().expect("Failed to initialize hotkey manager")); let manager_clone = manager.clone(); let manager_clone2 = manager.clone(); let rt = app_handle.state::(); let initial_keybind = rt.block_on(crate::api::database::get_keybind(app_handle_clone.clone())) .expect("Failed to get initial keybind"); let initial_shortcut = initial_keybind.join("+"); let initial_shortcut_clone = initial_shortcut.clone(); if let Err(e) = register_shortcut(&manager, &initial_shortcut) { eprintln!("Error registering initial shortcut: {:?}", e); } app_handle.listen("update-shortcut", move |event| { let payload_str = event.payload().to_string(); if let Ok(old_hotkey) = parse_hotkey(&initial_shortcut_clone) { let _ = manager_clone.unregister(old_hotkey); } if let Err(e) = register_shortcut(&manager_clone, &payload_str) { eprintln!("Error re-registering shortcut: {:?}", e); } }); app_handle.listen("save_keybind", move |event| { let payload_str = event.payload().to_string(); if let Ok(old_hotkey) = parse_hotkey(&initial_shortcut) { let _ = manager_clone2.unregister(old_hotkey); } if let Err(e) = register_shortcut(&manager_clone2, &payload_str) { eprintln!("Error registering saved shortcut: {:?}", e); } }); let app_handle_for_hotkey = app_handle.clone(); tauri::async_runtime::spawn(async move { loop { match GlobalHotKeyEvent::receiver().recv() { Ok(event) => { if event.state == HotKeyState::Released { continue; } handle_hotkey_event(&app_handle_for_hotkey); } Err(e) => { eprintln!("Error receiving hotkey event: {:?}", e); } } } }); } fn register_shortcut( manager: &Arc, shortcut: &str, ) -> Result<(), Box> { let hotkey = parse_hotkey(shortcut)?; manager.register(hotkey)?; Ok(()) } fn parse_hotkey(shortcut: &str) -> Result> { let mut modifiers = Modifiers::empty(); let mut code = None; let shortcut = shortcut.replace("\"", ""); for part in shortcut.split('+') { let part = part.trim().to_lowercase(); match part.as_str() { "ctrl" | "control" | "controlleft" => modifiers |= Modifiers::CONTROL, "alt" | "altleft" | "optionleft" => modifiers |= Modifiers::ALT, "shift" | "shiftleft" => modifiers |= Modifiers::SHIFT, "super" | "meta" | "cmd" | "metaleft" => modifiers |= Modifiers::META, key => { let key_code = if key.starts_with("key") { "Key".to_string() + &key[3..].to_uppercase() } else if key.len() == 1 && key.chars().next().unwrap().is_alphabetic() { "Key".to_string() + &key.to_uppercase() } else { key.to_string() }; code = Some(Code::from_str(&key_code) .map_err(|_| format!("Invalid key code: {}", key_code))?); } } } let key_code = code.ok_or_else(|| format!("No valid key code found in shortcut: {}", shortcut))?; Ok(HotKey::new(Some(modifiers), key_code)) } fn handle_hotkey_event(app_handle: &AppHandle) { let window = app_handle.get_webview_window("main").unwrap(); if window.is_visible().unwrap() { window.hide().unwrap(); } else { window.set_always_on_top(true).unwrap(); window.show().unwrap(); window.set_focus().unwrap(); let window_clone = window.clone(); std::thread::spawn(move || { std::thread::sleep(std::time::Duration::from_millis(100)); window_clone.set_always_on_top(false).unwrap(); }); center_window_on_current_monitor(&window); } }