diff --git a/src-tauri/src/config/verge.rs b/src-tauri/src/config/verge.rs index 54496252..61e6e58c 100644 --- a/src-tauri/src/config/verge.rs +++ b/src-tauri/src/config/verge.rs @@ -98,6 +98,9 @@ pub struct IVerge { /// hotkey map /// format: {func},{key} pub hotkeys: Option>, + + /// enable global hotkey + pub enable_global_hotkey: Option, /// 切换代理时自动关闭连接 pub auto_close_connection: Option, @@ -279,6 +282,7 @@ impl IVerge { webdav_username: None, webdav_password: None, enable_tray_speed: Some(true), + enable_global_hotkey: Some(true), ..Self::default() } } @@ -345,6 +349,7 @@ impl IVerge { patch!(web_ui_list); patch!(clash_core); patch!(hotkeys); + patch!(enable_global_hotkey); patch!(auto_close_connection); patch!(auto_check_update); @@ -411,6 +416,7 @@ pub struct IVergeResponse { pub enable_silent_start: Option, pub enable_system_proxy: Option, pub enable_proxy_guard: Option, + pub enable_global_hotkey: Option, pub use_default_bypass: Option, pub system_proxy_bypass: Option, pub proxy_guard_duration: Option, @@ -472,6 +478,7 @@ impl From for IVergeResponse { enable_silent_start: verge.enable_silent_start, enable_system_proxy: verge.enable_system_proxy, enable_proxy_guard: verge.enable_proxy_guard, + enable_global_hotkey: verge.enable_global_hotkey, use_default_bypass: verge.use_default_bypass, system_proxy_bypass: verge.system_proxy_bypass, proxy_guard_duration: verge.proxy_guard_duration, diff --git a/src-tauri/src/core/hotkey.rs b/src-tauri/src/core/hotkey.rs index e29d854d..a66bd859 100755 --- a/src-tauri/src/core/hotkey.rs +++ b/src-tauri/src/core/hotkey.rs @@ -45,6 +45,13 @@ impl Hotkey { Ok(()) } + pub fn reset(&self) -> Result<()> { + let app_handle = handle::Handle::global().app_handle().unwrap(); + let manager = app_handle.global_shortcut(); + manager.unregister_all()?; + Ok(()) + } + pub fn register(&self, hotkey: &str, func: &str) -> Result<()> { let app_handle = handle::Handle::global().app_handle().unwrap(); let manager = app_handle.global_shortcut(); @@ -76,7 +83,17 @@ impl Hotkey { } } } else { - f(); + if let Some(window) = app_handle.get_webview_window("main") { + let is_enable_global_hotkey = { Config::verge().latest().enable_global_hotkey} .unwrap(); + 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(); + } + } } } }); @@ -89,7 +106,6 @@ impl Hotkey { let app_handle = handle::Handle::global().app_handle().unwrap(); let manager = app_handle.global_shortcut(); manager.unregister(hotkey)?; - log::debug!(target: "app", "unregister hotkey {hotkey}"); Ok(()) } diff --git a/src-tauri/src/feat.rs b/src-tauri/src/feat.rs index 41d5aeec..f90e7522 100644 --- a/src-tauri/src/feat.rs +++ b/src-tauri/src/feat.rs @@ -209,10 +209,12 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> { let http_enabled = patch.verge_http_enabled; let http_port = patch.verge_port; let enable_tray_speed = patch.enable_tray_speed; + let enable_global_hotkey = patch.enable_global_hotkey; let res: std::result::Result<(), anyhow::Error> = { let mut should_restart_core = false; let mut should_update_clash_config = false; + let mut should_update_verge_config = false; let mut should_update_launch = false; let mut should_update_sysproxy = false; let mut should_update_systray_icon = false; @@ -226,12 +228,13 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> { should_update_systray_tooltip = true; should_update_systray_icon = true; } - + if enable_global_hotkey.is_some() { + should_update_verge_config = true; + } #[cfg(not(target_os = "windows"))] if redir_enabled.is_some() || redir_port.is_some() { should_restart_core = true; } - #[cfg(target_os = "linux")] if tproxy_enabled.is_some() || tproxy_port.is_some() { should_restart_core = true; @@ -286,6 +289,10 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> { CoreManager::global().update_config().await?; handle::Handle::refresh_clash(); } + if should_update_verge_config { + Config::verge().draft().enable_global_hotkey = enable_global_hotkey; + handle::Handle::refresh_verge(); + } if should_update_launch { sysopt::Sysopt::global().update_launch()?; } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 855f7292..1f7f8511 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -6,6 +6,7 @@ mod feat; mod utils; use crate::core::hotkey; use crate::utils::{resolve, resolve::resolve_scheme, server}; +use config::Config; use tauri_plugin_autostart::MacosLauncher; use tauri_plugin_deep_link::DeepLinkExt; @@ -159,6 +160,12 @@ pub fn run() { { log_err!(hotkey::Hotkey::global().register("Control+Q", "quit")); }; + { + let is_enable_global_hotkey = { Config::verge().draft().enable_global_hotkey }.unwrap(); + if !is_enable_global_hotkey { + log_err!(hotkey::Hotkey::global().init()) + } + } } tauri::WindowEvent::Focused(false) => { #[cfg(target_os = "macos")] @@ -169,6 +176,14 @@ pub fn run() { { log_err!(hotkey::Hotkey::global().unregister("Control+Q")); }; + { + let is_enable_global_hotkey = { Config::verge().draft().enable_global_hotkey }.unwrap(); + if !is_enable_global_hotkey { + log_err!(hotkey::Hotkey::global().reset()) + } else { + log_err!(hotkey::Hotkey::global().init()) + } + } } tauri::WindowEvent::Destroyed => { #[cfg(target_os = "macos")] diff --git a/src/components/setting/mods/hotkey-viewer.tsx b/src/components/setting/mods/hotkey-viewer.tsx index 27e2ac4b..b4307af2 100644 --- a/src/components/setting/mods/hotkey-viewer.tsx +++ b/src/components/setting/mods/hotkey-viewer.tsx @@ -1,7 +1,7 @@ import { forwardRef, useImperativeHandle, useState } from "react"; import { useTranslation } from "react-i18next"; import { useLockFn } from "ahooks"; -import { styled, Typography } from "@mui/material"; +import { styled, Typography, Switch } from "@mui/material"; import { useVerge } from "@/hooks/use-verge"; import { BaseDialog, DialogRef, Notice } from "@/components/base"; import { HotkeyInput } from "./hotkey-input"; @@ -29,6 +29,9 @@ export const HotkeyViewer = forwardRef((props, ref) => { const { verge, patchVerge } = useVerge(); const [hotkeyMap, setHotkeyMap] = useState>({}); + const [enableGlobalHotkey, setEnableHotkey] = useState( + verge?.enable_global_hotkey ?? true, + ); useImperativeHandle(ref, () => ({ open: () => { @@ -69,7 +72,10 @@ export const HotkeyViewer = forwardRef((props, ref) => { .filter(Boolean); try { - await patchVerge({ hotkeys }); + await patchVerge({ + hotkeys, + enable_global_hotkey: enableGlobalHotkey, + }); setOpen(false); } catch (err: any) { Notice.error(err.message || err.toString()); @@ -80,13 +86,22 @@ export const HotkeyViewer = forwardRef((props, ref) => { setOpen(false)} onCancel={() => setOpen(false)} onOk={onSave} > + + {t("Enable Global Hotkey")} + setEnableHotkey(e.target.checked)} + /> + + {HOTKEY_FUNC.map((func) => ( {t(func)} diff --git a/src/locales/zh.json b/src/locales/zh.json index 55e85a8e..0581079d 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -328,6 +328,7 @@ "Default Latency Test Info": "仅用于 HTTP 客户端请求测试,不会对配置文件产生影响", "Default Latency Timeout": "测试超时时间", "Hotkey Setting": "热键设置", + "Enable Global Hotkey": "启用全局热键", "open_or_close_dashboard": "打开/关闭面板", "clash_mode_rule": "规则模式", "clash_mode_global": "全局模式", diff --git a/src/services/types.d.ts b/src/services/types.d.ts index 2ce4a891..ff452bc1 100644 --- a/src/services/types.d.ts +++ b/src/services/types.d.ts @@ -711,6 +711,7 @@ interface IVergeConfig { enable_auto_launch?: boolean; enable_silent_start?: boolean; enable_system_proxy?: boolean; + enable_global_hotkey?: boolean; proxy_auto_config?: boolean; pac_file_content?: string; enable_random_port?: boolean;