From 3bb3872e3845c3fcbc955273fddecae1e48dfaf6 Mon Sep 17 00:00:00 2001 From: wonfen Date: Wed, 12 Feb 2025 14:23:42 +0800 Subject: [PATCH] refactor: improve hotkey management, logging, and error handling; fix tray freeze and hotkey failure on silent startup --- src-tauri/src/core/hotkey.rs | 90 +++++++++++++++++++++++++++------- src-tauri/src/feat.rs | 36 ++++++++++++-- src-tauri/src/utils/resolve.rs | 48 +++++++++++++----- 3 files changed, 139 insertions(+), 35 deletions(-) diff --git a/src-tauri/src/core/hotkey.rs b/src-tauri/src/core/hotkey.rs index bd45d02b..fced2414 100755 --- a/src-tauri/src/core/hotkey.rs +++ b/src-tauri/src/core/hotkey.rs @@ -1,11 +1,14 @@ use crate::core::handle; use crate::{config::Config, feat, log_err}; +use crate::utils::resolve; use anyhow::{bail, Result}; use once_cell::sync::OnceCell; use parking_lot::Mutex; use std::{collections::HashMap, sync::Arc}; use tauri::Manager; use tauri_plugin_global_shortcut::{Code, GlobalShortcutExt, ShortcutState}; +use tauri::async_runtime; + pub struct Hotkey { current: Arc>>, // 保存当前的热键设置 } @@ -21,8 +24,22 @@ impl Hotkey { pub fn init(&self) -> Result<()> { let verge = Config::verge(); + let enable_global_hotkey = verge.latest().enable_global_hotkey.unwrap_or(true); + + println!("Initializing hotkeys, global hotkey enabled: {}", enable_global_hotkey); + log::info!(target: "app", "Initializing hotkeys, global hotkey enabled: {}", enable_global_hotkey); + + // 如果全局热键被禁用,则不注册热键 + if !enable_global_hotkey { + println!("Global hotkey is disabled, skipping registration"); + log::info!(target: "app", "Global hotkey is disabled, skipping registration"); + return Ok(()); + } if let Some(hotkeys) = verge.latest().hotkeys.as_ref() { + println!("Found {} hotkeys to register", hotkeys.len()); + log::info!(target: "app", "Found {} hotkeys to register", hotkeys.len()); + for hotkey in hotkeys.iter() { let mut iter = hotkey.split(','); let func = iter.next(); @@ -30,16 +47,28 @@ impl Hotkey { match (key, func) { (Some(key), Some(func)) => { - log_err!(self.register(key, func)); + println!("Registering hotkey: {} -> {}", key, func); + log::info!(target: "app", "Registering hotkey: {} -> {}", key, func); + if let Err(e) = self.register(key, func) { + println!("Failed to register hotkey {} -> {}: {:?}", key, func, e); + log::error!(target: "app", "Failed to register hotkey {} -> {}: {:?}", key, func, e); + } else { + println!("Successfully registered hotkey {} -> {}", key, func); + log::info!(target: "app", "Successfully registered hotkey {} -> {}", key, func); + } } _ => { let key = key.unwrap_or("None"); let func = func.unwrap_or("None"); - log::error!(target: "app", "invalid hotkey `{key}`:`{func}`"); + println!("Invalid hotkey configuration: `{key}`:`{func}`"); + log::error!(target: "app", "Invalid hotkey configuration: `{key}`:`{func}`"); } } } self.current.lock().clone_from(hotkeys); + } else { + println!("No hotkeys configured"); + log::info!(target: "app", "No hotkeys configured"); } Ok(()) @@ -56,49 +85,74 @@ impl Hotkey { let app_handle = handle::Handle::global().app_handle().unwrap(); let manager = app_handle.global_shortcut(); + println!("Attempting to register hotkey: {} for function: {}", hotkey, func); + log::info!(target: "app", "Attempting to register hotkey: {} for function: {}", hotkey, func); + if manager.is_registered(hotkey) { + println!("Hotkey {} was already registered, unregistering first", hotkey); + log::info!(target: "app", "Hotkey {} was already registered, unregistering first", hotkey); manager.unregister(hotkey)?; } let f = match func.trim() { - "open_or_close_dashboard" => feat::open_or_close_dashboard, + "open_or_close_dashboard" => { + println!("Registering open_or_close_dashboard function"); + log::info!(target: "app", "Registering open_or_close_dashboard function"); + || { + println!("=== Hotkey Dashboard Window Operation Start ==="); + log::info!(target: "app", "=== Hotkey Dashboard Window Operation Start ==="); + + // 使用 spawn_blocking 来确保在正确的线程上执行 + async_runtime::spawn_blocking(|| { + println!("Creating window in spawn_blocking"); + log::info!(target: "app", "Creating window in spawn_blocking"); + resolve::create_window(); + }); + + println!("=== Hotkey Dashboard Window Operation End ==="); + log::info!(target: "app", "=== Hotkey Dashboard Window Operation End ==="); + } + }, "clash_mode_rule" => || feat::change_clash_mode("rule".into()), "clash_mode_global" => || feat::change_clash_mode("global".into()), "clash_mode_direct" => || feat::change_clash_mode("direct".into()), - "toggle_system_proxy" => feat::toggle_system_proxy, - "toggle_tun_mode" => feat::toggle_tun_mode, + "toggle_system_proxy" => || feat::toggle_system_proxy(), + "toggle_tun_mode" => || feat::toggle_tun_mode(), "quit" => || feat::quit(Some(0)), - _ => bail!("invalid function \"{func}\""), + _ => { + println!("Invalid function: {}", func); + log::error!(target: "app", "Invalid function: {}", func); + bail!("invalid function \"{func}\""); + } }; let is_quit = func.trim() == "quit"; let _ = manager.on_shortcut(hotkey, move |app_handle, hotkey, event| { if event.state == ShortcutState::Pressed { + println!("Hotkey pressed: {:?}", hotkey); + log::info!(target: "app", "Hotkey pressed: {:?}", hotkey); + if hotkey.key == Code::KeyQ && is_quit { if let Some(window) = app_handle.get_webview_window("main") { if window.is_focused().unwrap_or(false) { + println!("Executing quit function"); + log::info!(target: "app", "Executing quit function"); f(); } } } else { - if let Some(window) = app_handle.get_webview_window("main") { - let is_enable_global_hotkey = Config::verge().latest().enable_global_hotkey.unwrap_or(true); - let is_visible = window.is_visible().unwrap_or(false); - let is_focused = window.is_focused().unwrap_or(false); - - if is_enable_global_hotkey { - f(); - } else if is_focused && is_visible { - f(); - } - } + // 直接执行函数,不做任何状态检查 + println!("Executing function directly"); + log::info!(target: "app", "Executing function directly"); + f(); } } }); - log::debug!(target: "app", "register hotkey {hotkey} {func}"); + println!("Successfully registered hotkey {} for {}", hotkey, func); + log::info!(target: "app", "Successfully registered hotkey {} for {}", hotkey, func); Ok(()) } diff --git a/src-tauri/src/feat.rs b/src-tauri/src/feat.rs index 9ec5c133..923e0e7d 100644 --- a/src-tauri/src/feat.rs +++ b/src-tauri/src/feat.rs @@ -20,15 +20,41 @@ use tauri_plugin_window_state::{AppHandleExt, StateFlags}; // 打开面板 pub fn open_or_close_dashboard() { + println!("Attempting to open/close dashboard"); + log::info!(target: "app", "Attempting to open/close dashboard"); + if let Some(window) = handle::Handle::global().get_window() { + println!("Found existing window"); + log::info!(target: "app", "Found existing window"); + // 如果窗口存在,则切换其显示状态 - if window.is_visible().unwrap_or(false) { - let _ = window.hide(); - } else { - let _ = window.show(); - let _ = window.set_focus(); + match window.is_visible() { + Ok(visible) => { + println!("Window visibility status: {}", visible); + log::info!(target: "app", "Window visibility status: {}", visible); + + if visible { + println!("Attempting to hide window"); + log::info!(target: "app", "Attempting to hide window"); + let _ = window.hide(); + } else { + println!("Attempting to show and focus window"); + log::info!(target: "app", "Attempting to show and focus window"); + if window.is_minimized().unwrap_or(false) { + let _ = window.unminimize(); + } + let _ = window.show(); + let _ = window.set_focus(); + } + } + Err(e) => { + println!("Failed to get window visibility: {:?}", e); + log::error!(target: "app", "Failed to get window visibility: {:?}", e); + } } } else { + println!("No existing window found, creating new window"); + log::info!(target: "app", "No existing window found, creating new window"); resolve::create_window(); } } diff --git a/src-tauri/src/utils/resolve.rs b/src-tauri/src/utils/resolve.rs index 8f3c42d8..7afcf356 100644 --- a/src-tauri/src/utils/resolve.rs +++ b/src-tauri/src/utils/resolve.rs @@ -95,16 +95,19 @@ pub async fn resolve_setup(app: &mut App) { log_err!(tray::Tray::global().init()); log_err!(tray::Tray::global().create_systray()); + log_err!(sysopt::Sysopt::global().update_sysproxy().await); + log_err!(sysopt::Sysopt::global().init_guard_sysproxy()); + + // 初始化热键 + log::trace!(target: "app", "init hotkeys"); + log_err!(hotkey::Hotkey::global().init()); + let silent_start = { Config::verge().data().enable_silent_start }; if !silent_start.unwrap_or(false) { create_window(); } - log_err!(sysopt::Sysopt::global().update_sysproxy().await); - log_err!(sysopt::Sysopt::global().init_guard_sysproxy()); - log_err!(tray::Tray::global().update_part()); - log_err!(hotkey::Hotkey::global().init()); log_err!(timer::Timer::global().init()); } @@ -123,10 +126,18 @@ pub fn resolve_reset() { /// create main window pub fn create_window() { + println!("Starting to create window"); + log::info!(target: "app", "Starting to create window"); + let app_handle = handle::Handle::global().app_handle().unwrap(); if let Some(window) = handle::Handle::global().get_window() { + println!("Found existing window, trying to show it"); + log::info!(target: "app", "Found existing window, trying to show it"); + if window.is_minimized().unwrap_or(false) { + println!("Window is minimized, unminimizing"); + log::info!(target: "app", "Window is minimized, unminimizing"); let _ = window.unminimize(); } let _ = window.show(); @@ -134,14 +145,16 @@ pub fn create_window() { return; } + println!("Creating new window"); + log::info!(target: "app", "Creating new window"); + #[cfg(target_os = "windows")] - let _ = tauri::WebviewWindowBuilder::new( + let window = tauri::WebviewWindowBuilder::new( &app_handle, "main".to_string(), tauri::WebviewUrl::App("index.html".into()), ) .title("Clash Verge") - .visible(false) .inner_size(890.0, 700.0) .min_inner_size(620.0, 550.0) .decorations(false) @@ -152,7 +165,7 @@ pub fn create_window() { .build(); #[cfg(target_os = "macos")] - let _ = tauri::WebviewWindowBuilder::new( + let window = tauri::WebviewWindowBuilder::new( &app_handle, "main".to_string(), tauri::WebviewUrl::App("index.html".into()), @@ -162,11 +175,10 @@ pub fn create_window() { .title_bar_style(tauri::TitleBarStyle::Overlay) .inner_size(890.0, 700.0) .min_inner_size(620.0, 550.0) - .build() - .unwrap(); + .build(); #[cfg(target_os = "linux")] - let _ = tauri::WebviewWindowBuilder::new( + let window = tauri::WebviewWindowBuilder::new( &app_handle, "main".to_string(), tauri::WebviewUrl::App("index.html".into()), @@ -176,8 +188,20 @@ pub fn create_window() { .inner_size(890.0, 700.0) .min_inner_size(620.0, 550.0) .transparent(true) - .build() - .unwrap(); + .build(); + + match window { + Ok(window) => { + println!("Window created successfully, attempting to show"); + log::info!(target: "app", "Window created successfully, attempting to show"); + let _ = window.show(); + let _ = window.set_focus(); + } + Err(e) => { + println!("Failed to create window: {:?}", e); + log::error!(target: "app", "Failed to create window: {:?}", e); + } + } } pub async fn resolve_scheme(param: String) -> Result<()> {