diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index f7aed53..cf8f644 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -530,6 +530,7 @@ dependencies = [ "sysproxy", "tauri", "tauri-build", + "tauri-runtime-wry", "tokio", "warp", "which 4.3.0", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 6735c86..ea4e340 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -26,6 +26,7 @@ nanoid = "0.4.0" chrono = "0.4.19" sysinfo = "0.26.2" sysproxy = "0.1" +rquickjs = "0.1.7" serde_json = "1.0" serde_yaml = "0.9" auto-launch = "0.4" @@ -37,9 +38,9 @@ tokio = { version = "1", features = ["full"] } serde = { version = "1.0", features = ["derive"] } reqwest = { version = "0.11", features = ["json"] } tauri = { version = "1.1.1", features = ["global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all"] } -rquickjs = { version = "0.1.7" } -window-shadows = { version = "0.2.0" } +tauri-runtime-wry = { version = "0.12" } window-vibrancy = { version = "0.3.0" } +window-shadows = { version = "0.2.0" } [target.'cfg(windows)'.dependencies] runas = "0.2.1" diff --git a/src-tauri/src/core/hotkey.rs b/src-tauri/src/core/hotkey.rs index 38565bc..f1c848d 100644 --- a/src-tauri/src/core/hotkey.rs +++ b/src-tauri/src/core/hotkey.rs @@ -4,6 +4,7 @@ use once_cell::sync::OnceCell; use parking_lot::Mutex; use std::{collections::HashMap, sync::Arc}; use tauri::{AppHandle, GlobalShortcutManager}; +use tauri_runtime_wry::wry::application::accelerator::Accelerator; pub struct Hotkey { current: Arc>>, // 保存当前的热键设置 @@ -32,10 +33,15 @@ impl Hotkey { let func = iter.next(); let key = iter.next(); - if func.is_some() && key.is_some() { - log_err!(self.register(key.unwrap(), func.unwrap())); - } else { - log::error!(target: "app", "invalid hotkey \"{}\":\"{}\"", key.unwrap_or("None"), func.unwrap_or("None")); + match (key, func) { + (Some(key), Some(func)) => { + log_err!(Self::check_key(key).and_then(|_| self.register(key, func))); + } + _ => { + let key = key.unwrap_or("None"); + let func = func.unwrap_or("None"); + log::error!(target: "app", "invalid hotkey `{key}`:`{func}`"); + } } } *self.current.lock() = hotkeys.clone(); @@ -44,10 +50,20 @@ impl Hotkey { Ok(()) } + /// 检查一个键是否合法 + fn check_key(hotkey: &str) -> Result<()> { + // fix #287 + // tauri的这几个方法全部有Result expect,会panic,先检测一遍避免挂了 + if hotkey.parse::().is_err() { + bail!("invalid hotkey `{hotkey}`"); + } + Ok(()) + } + fn get_manager(&self) -> Result { let app_handle = self.app_handle.lock(); if app_handle.is_none() { - bail!("failed to get hotkey manager"); + bail!("failed to get the hotkey manager"); } Ok(app_handle.as_ref().unwrap().global_shortcut_manager()) } @@ -92,6 +108,11 @@ impl Hotkey { let (del, add) = Self::get_diff(old_map, new_map); + // 先检查一遍所有新的热键是不是可以用的 + for (hotkey, _) in add.iter() { + Self::check_key(hotkey)?; + } + del.iter().for_each(|key| { let _ = self.unregister(key); }); diff --git a/src/components/setting/mods/hotkey-input.tsx b/src/components/setting/mods/hotkey-input.tsx index ddcb870..a14658a 100644 --- a/src/components/setting/mods/hotkey-input.tsx +++ b/src/components/setting/mods/hotkey-input.tsx @@ -1,6 +1,7 @@ +import { useRef, useState } from "react"; import { alpha, Box, IconButton, styled } from "@mui/material"; import { DeleteRounded } from "@mui/icons-material"; -import parseHotkey from "@/utils/parse-hotkey"; +import { parseHotkey } from "@/utils/parse-hotkey"; const KeyWrapper = styled("div")(({ theme }) => ({ position: "relative", @@ -54,10 +55,20 @@ interface Props { export const HotkeyInput = (props: Props) => { const { value, onChange } = props; + const changeRef = useRef([]); + const [keys, setKeys] = useState(value); + return ( { + const ret = changeRef.current.slice(); + if (ret.length) { + onChange(ret); + changeRef.current = []; + } + }} onKeyDown={(e) => { const evt = e.nativeEvent; e.preventDefault(); @@ -66,13 +77,13 @@ export const HotkeyInput = (props: Props) => { const key = parseHotkey(evt.key); if (key === "UNIDENTIFIED") return; - const newList = [...new Set([...value, key])]; - onChange(newList); + changeRef.current = [...new Set([...changeRef.current, key])]; + setKeys(changeRef.current); }} />
- {value.map((key) => ( + {keys.map((key) => (
{key}
@@ -84,7 +95,10 @@ export const HotkeyInput = (props: Props) => { size="small" title="Delete" color="inherit" - onClick={() => onChange([])} + onClick={() => { + onChange([]); + setKeys([]); + }} > diff --git a/src/components/setting/mods/hotkey-viewer.tsx b/src/components/setting/mods/hotkey-viewer.tsx index 22a2dac..41879f1 100644 --- a/src/components/setting/mods/hotkey-viewer.tsx +++ b/src/components/setting/mods/hotkey-viewer.tsx @@ -73,7 +73,7 @@ export const HotkeyViewer = forwardRef((props, ref) => { .filter(Boolean); try { - patchVerge({ hotkeys }); + await patchVerge({ hotkeys }); setOpen(false); } catch (err: any) { Notice.error(err.message || err.toString()); diff --git a/src/utils/parse-hotkey.ts b/src/utils/parse-hotkey.ts index 01addd0..864ef4f 100644 --- a/src/utils/parse-hotkey.ts +++ b/src/utils/parse-hotkey.ts @@ -1,4 +1,26 @@ -const parseHotkey = (key: string) => { +const KEY_MAP: Record = { + '"': "'", + ":": ";", + "?": "/", + ">": ".", + "<": ",", + "{": "[", + "}": "]", + "|": "\\", + "!": "1", + "@": "2", + "#": "3", + $: "4", + "%": "5", + "^": "6", + "&": "7", + "*": "8", + "(": "9", + ")": "0", + "~": "`", +}; + +export const parseHotkey = (key: string) => { let temp = key.toUpperCase(); if (temp.startsWith("ARROW")) { @@ -20,10 +42,7 @@ const parseHotkey = (key: string) => { return "CMD"; case " ": return "SPACE"; - default: - return temp; + return KEY_MAP[temp] || temp; } }; - -export default parseHotkey;