From d7859b07a6745141723b9069b5466f3cf64818b5 Mon Sep 17 00:00:00 2001 From: oomeow Date: Thu, 23 Oct 2025 15:54:48 +0800 Subject: [PATCH] fix: parse hotkey (#5167) * fix: incorrectly parse hotkey * refactor: parse hotkey * fix: panic on linux * chore: update * chore: update style * fix: register hotkey error on windows * chore: update style --------- Co-authored-by: Tunglies --- UPDATELOG.md | 4 +- src-tauri/src/core/hotkey.rs | 10 +-- src-tauri/src/core/tray/mod.rs | 9 ++- src/components/setting/mods/hotkey-input.tsx | 6 +- src/components/setting/mods/hotkey-viewer.tsx | 2 +- src/utils/parse-hotkey.ts | 74 ++----------------- 6 files changed, 25 insertions(+), 80 deletions(-) diff --git a/UPDATELOG.md b/UPDATELOG.md index e8a040fbc..1b679ee0e 100644 --- a/UPDATELOG.md +++ b/UPDATELOG.md @@ -38,8 +38,9 @@ - 启用 TUN 前等待服务就绪 - 卸载 TUN 时会先关闭 - 优化应用启动页 -- 优化首页当前节点对 MATCH 规则的支持 +- 优化首页当前节点对MATCH规则的支持 - 允许在 `界面设置` 修改 `悬浮跳转导航延迟` +- 添加热键绑定错误的提示信息 ### 🐞 修复问题 @@ -69,6 +70,7 @@ - 修复自动更新使版本回退的问题 - 修复首页自定义卡片在切换轻量模式时失效 - 修复悬浮跳转导航失效 +- 修复小键盘热键映射错误 ## v2.4.2 diff --git a/src-tauri/src/core/hotkey.rs b/src-tauri/src/core/hotkey.rs index c6c69d271..1a3974383 100755 --- a/src-tauri/src/core/hotkey.rs +++ b/src-tauri/src/core/hotkey.rs @@ -1,8 +1,8 @@ use crate::process::AsyncHandler; use crate::utils::notification::{NotificationEvent, notify_event}; use crate::{ - config::Config, core::handle, feat, logging, logging_error, - module::lightweight::entry_lightweight_mode, singleton_with_logging, utils::logging::Type, + config::Config, core::handle, feat, logging, module::lightweight::entry_lightweight_mode, + singleton_with_logging, utils::logging::Type, }; use anyhow::{Result, bail}; use parking_lot::Mutex; @@ -224,7 +224,7 @@ impl Hotkey { let is_quit = matches!(function, HotkeyFunction::Quit); - let _ = manager.on_shortcut(hotkey, move |app_handle, hotkey_event, event| { + manager.on_shortcut(hotkey, move |app_handle, hotkey_event, event| { let hotkey_event_owned = *hotkey_event; let event_owned = event; let function_owned = function; @@ -271,7 +271,7 @@ impl Hotkey { } } }); - }); + })?; logging!( debug, @@ -402,7 +402,7 @@ impl Hotkey { }); for (key, func) in add.iter() { - logging_error!(Type::Hotkey, self.register(key, func).await); + self.register(key, func).await?; } // Update the current hotkeys after all async operations diff --git a/src-tauri/src/core/tray/mod.rs b/src-tauri/src/core/tray/mod.rs index 0248bc46d..2295c8118 100644 --- a/src-tauri/src/core/tray/mod.rs +++ b/src-tauri/src/core/tray/mod.rs @@ -676,7 +676,14 @@ async fn create_tray_menu( .filter_map(|item| { let mut parts = item.split(','); match (parts.next(), parts.next()) { - (Some(func), Some(key)) => Some((func.into(), key.into())), + (Some(func), Some(key)) => { + // 托盘菜单中的 `accelerator` 属性,在 Linux/Windows 中都不支持小键盘按键的解析 + if key.to_uppercase().contains("NUMPAD") { + None + } else { + Some((func.into(), key.into())) + } + } _ => None, } }) diff --git a/src/components/setting/mods/hotkey-input.tsx b/src/components/setting/mods/hotkey-input.tsx index c4fdd7167..8198f1e95 100644 --- a/src/components/setting/mods/hotkey-input.tsx +++ b/src/components/setting/mods/hotkey-input.tsx @@ -7,7 +7,7 @@ import { parseHotkey } from "@/utils/parse-hotkey"; const KeyWrapper = styled("div")(({ theme }) => ({ position: "relative", - width: 165, + width: 230, minHeight: 36, "> input": { @@ -39,6 +39,7 @@ const KeyWrapper = styled("div")(({ theme }) => ({ }, }, ".item": { + fontSize: "14px", color: theme.palette.text.primary, border: "1px solid", borderColor: alpha(theme.palette.text.secondary, 0.2), @@ -76,11 +77,10 @@ export const HotkeyInput = (props: Props) => { } }} onKeyDown={(e) => { - const evt = e.nativeEvent; e.preventDefault(); e.stopPropagation(); - const key = parseHotkey(evt.key); + const key = parseHotkey(e); if (key === "UNIDENTIFIED") return; changeRef.current = [...new Set([...changeRef.current, key])]; diff --git a/src/components/setting/mods/hotkey-viewer.tsx b/src/components/setting/mods/hotkey-viewer.tsx index 9f0e72808..d034af300 100644 --- a/src/components/setting/mods/hotkey-viewer.tsx +++ b/src/components/setting/mods/hotkey-viewer.tsx @@ -82,7 +82,7 @@ export const HotkeyViewer = forwardRef((props, ref) => { }); setOpen(false); } catch (err: any) { - showNotice("error", err.toString()); + showNotice("error", err.message || err.toString()); } }); diff --git a/src/utils/parse-hotkey.ts b/src/utils/parse-hotkey.ts index cfb82e858..f4a37e446 100644 --- a/src/utils/parse-hotkey.ts +++ b/src/utils/parse-hotkey.ts @@ -1,26 +1,6 @@ +import { KeyboardEvent } from "react"; + const KEY_MAP: Record = { - // 特殊字符映射 - "-": "Minus", - "=": "Equal", - "[": "BracketLeft", - "]": "BracketRight", - "\\": "Backslash", - ";": "Semicolon", - "'": "Quote", - ",": "Comma", - ".": "Period", - "/": "Slash", - // 数字键映射 - "1": "Digit1", - "2": "Digit2", - "3": "Digit3", - "4": "Digit4", - "5": "Digit5", - "6": "Digit6", - "7": "Digit7", - "8": "Digit8", - "9": "Digit9", - "0": "Digit0", // Option + 特殊字符映射 "–": "Minus", // Option + - "≠": "Equal", // Option + = @@ -66,55 +46,11 @@ const mapKeyCombination = (key: string): string => { const mappedKey = KEY_MAP[key] || key; return `${mappedKey}`; }; -export const parseHotkey = (key: string) => { +export const parseHotkey = (keyEvent: KeyboardEvent) => { + const nativeEvent = keyEvent.nativeEvent; + const key = nativeEvent.code; let temp = key.toUpperCase(); - // 处理特殊符号到键位的映射 - switch (temp) { - // 数字键符号 - case "!": - return "DIGIT1"; // shift + 1 - case "@": - return "DIGIT2"; // shift + 2 - case "#": - return "DIGIT3"; // shift + 3 - case "$": - return "DIGIT4"; // shift + 4 - case "%": - return "DIGIT5"; // shift + 5 - case "^": - return "DIGIT6"; // shift + 6 - case "&": - return "DIGIT7"; // shift + 7 - case "*": - return "DIGIT8"; // shift + 8 - case "(": - return "DIGIT9"; // shift + 9 - case ")": - return "DIGIT0"; // shift + 0 - // 其他特殊符号 - case "?": - return "SLASH"; // shift + / - case ":": - return "SEMICOLON"; // shift + ; - case "+": - return "EQUAL"; // shift + = - case "_": - return "MINUS"; // shift + - - case '"': - return "QUOTE"; // shift + ' - case "<": - return "COMMA"; // shift + , - case ">": - return "PERIOD"; // shift + . - case "{": - return "BRACKETLEFT"; // shift + [ - case "}": - return "BRACKETRIGHT"; // shift + ] - case "|": - return "BACKSLASH"; // shift + \ - } - if (temp.startsWith("ARROW")) { temp = temp.slice(5); } else if (temp.startsWith("DIGIT")) {