refactor: refactor hotkey management to use a single state structure with Arc and Mutex

This commit is contained in:
PandaDEV 2025-01-11 01:17:39 +10:00
parent 105213a631
commit 0980b95b72
No known key found for this signature in database
GPG key ID: 13EFF9BAF70EE75C

View file

@ -6,20 +6,21 @@ use global_hotkey::{
GlobalHotKeyManager, GlobalHotKeyManager,
HotKeyState, HotKeyState,
}; };
use parking_lot::Mutex;
use std::str::FromStr; use std::str::FromStr;
use std::sync::Mutex; use std::sync::Arc;
use tauri::{ AppHandle, Manager, Listener }; use tauri::{ AppHandle, Manager, Listener };
use tauri_plugin_aptabase::EventTracker; use tauri_plugin_aptabase::EventTracker;
use tokio::sync::OnceCell;
static HOTKEY_MANAGER: OnceCell<Mutex<Option<GlobalHotKeyManager>>> = OnceCell::const_new(); #[derive(Default)]
static REGISTERED_HOTKEY: OnceCell<Mutex<Option<HotKey>>> = OnceCell::const_new(); struct HotkeyState {
manager: Option<GlobalHotKeyManager>,
registered_hotkey: Option<HotKey>,
}
pub fn setup(app_handle: tauri::AppHandle) { pub fn setup(app_handle: tauri::AppHandle) {
let _ = HOTKEY_MANAGER.set(Mutex::new(None)); let state = Arc::new(Mutex::new(HotkeyState::default()));
let _ = REGISTERED_HOTKEY.set(Mutex::new(None));
let app_handle_clone = app_handle.clone();
let manager = match GlobalHotKeyManager::new() { let manager = match GlobalHotKeyManager::new() {
Ok(manager) => manager, Ok(manager) => manager,
Err(err) => { Err(err) => {
@ -28,49 +29,48 @@ pub fn setup(app_handle: tauri::AppHandle) {
} }
}; };
if let Some(hotkey_manager) = HOTKEY_MANAGER.get() { {
let mut manager_guard = hotkey_manager.lock().unwrap(); let mut hotkey_state = state.lock();
*manager_guard = Some(manager); hotkey_state.manager = Some(manager);
} }
let rt = app_handle.state::<tokio::runtime::Runtime>(); let rt = app_handle.state::<tokio::runtime::Runtime>();
let initial_keybind = rt let initial_keybind = rt
.block_on(crate::db::settings::get_keybind(app_handle_clone.clone())) .block_on(crate::db::settings::get_keybind(app_handle.clone()))
.expect("Failed to get initial keybind"); .expect("Failed to get initial keybind");
if let Err(e) = register_shortcut(&initial_keybind) { if let Err(e) = register_shortcut(&state, &initial_keybind) {
eprintln!("Error registering initial shortcut: {:?}", e); eprintln!("Error registering initial shortcut: {:?}", e);
} }
setup_event_listeners(&app_handle); let state_clone = state.clone();
setup_hotkey_receiver(app_handle);
}
fn setup_event_listeners(app_handle: &AppHandle) {
app_handle.listen("update-shortcut", move |event| { app_handle.listen("update-shortcut", move |event| {
let payload_str = event.payload().replace("\\\"", "\""); let payload_str = event.payload().replace("\\\"", "\"");
let trimmed_str = payload_str.trim_matches('"'); let trimmed_str = payload_str.trim_matches('"');
unregister_current_hotkey(); unregister_current_hotkey(&state_clone);
let payload: Vec<String> = serde_json::from_str(trimmed_str).unwrap_or_default(); let payload: Vec<String> = serde_json::from_str(trimmed_str).unwrap_or_default();
if let Err(e) = register_shortcut(&payload) { if let Err(e) = register_shortcut(&state_clone, &payload) {
eprintln!("Error re-registering shortcut: {:?}", e); eprintln!("Error re-registering shortcut: {:?}", e);
} }
}); });
let state_clone = state.clone();
app_handle.listen("save_keybind", move |event| { app_handle.listen("save_keybind", move |event| {
let payload_str = event.payload().to_string(); let payload_str = event.payload().to_string();
unregister_current_hotkey(); unregister_current_hotkey(&state_clone);
let payload: Vec<String> = serde_json::from_str(&payload_str).unwrap_or_default(); let payload: Vec<String> = serde_json::from_str(&payload_str).unwrap_or_default();
if let Err(e) = register_shortcut(&payload) { if let Err(e) = register_shortcut(&state_clone, &payload) {
eprintln!("Error registering saved shortcut: {:?}", e); eprintln!("Error registering saved shortcut: {:?}", e);
} }
}); });
setup_hotkey_receiver(app_handle);
} }
fn setup_hotkey_receiver(app_handle: AppHandle) { fn setup_hotkey_receiver(app_handle: AppHandle) {
tauri::async_runtime::spawn(async move { std::thread::spawn(move || {
loop { loop {
match GlobalHotKeyEvent::receiver().recv() { match GlobalHotKeyEvent::receiver().recv() {
Ok(event) => { Ok(event) => {
@ -85,35 +85,26 @@ fn setup_hotkey_receiver(app_handle: AppHandle) {
}); });
} }
fn unregister_current_hotkey() { fn unregister_current_hotkey(state: &Arc<Mutex<HotkeyState>>) {
if let Some(registered) = REGISTERED_HOTKEY.get() { let mut hotkey_state = state.lock();
if let Some(old_hotkey) = registered.lock().unwrap().take() { if let Some(old_hotkey) = hotkey_state.registered_hotkey.take() {
if let Some(manager) = HOTKEY_MANAGER.get() { if let Some(manager) = &hotkey_state.manager {
if let Some(manager) = manager.lock().unwrap().as_ref() {
let _ = manager.unregister(old_hotkey); let _ = manager.unregister(old_hotkey);
} }
} }
}
}
} }
fn register_shortcut(shortcut: &[String]) -> Result<(), Box<dyn std::error::Error>> { fn register_shortcut(state: &Arc<Mutex<HotkeyState>>, shortcut: &[String]) -> Result<(), Box<dyn std::error::Error>> {
let hotkey = parse_hotkey(shortcut)?; let hotkey = parse_hotkey(shortcut)?;
let mut hotkey_state = state.lock();
if let Some(manager) = HOTKEY_MANAGER.get() { if let Some(manager) = &hotkey_state.manager {
let manager_guard = manager.lock().unwrap();
if let Some(manager) = manager_guard.as_ref() {
manager.register(hotkey.clone())?; manager.register(hotkey.clone())?;
if let Some(registered) = REGISTERED_HOTKEY.get() { hotkey_state.registered_hotkey = Some(hotkey);
*registered.lock().unwrap() = Some(hotkey);
}
Ok(()) Ok(())
} else { } else {
Err("Hotkey manager not initialized".into()) Err("Hotkey manager not initialized".into())
} }
} else {
Err("Hotkey manager not initialized".into())
}
} }
fn parse_hotkey(shortcut: &[String]) -> Result<HotKey, Box<dyn std::error::Error>> { fn parse_hotkey(shortcut: &[String]) -> Result<HotKey, Box<dyn std::error::Error>> {