Skip to content

Commit 2109530

Browse files
author
阿岳
committed
feat: 全局快捷键修复,防止一直占用系统
1 parent 880f327 commit 2109530

File tree

4 files changed

+180
-44
lines changed

4 files changed

+180
-44
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
## 计划概述
2+
3+
为 RecentFilesWindow 页面添加独立的隐私模式开关,当开启时对文件夹名和文件名进行凯撒移位加密显示。
4+
5+
## 实施步骤
6+
7+
1. **添加本地隐私模式状态**
8+
- 在组件中添加 `isLocalPrivacyMode` 状态
9+
10+
- 添加切换按钮到工具栏
11+
12+
2. **创建凯撒移位加密函数**
13+
- 复用现有的 `replaceTextWhenProtect` 函数,但强制使用凯撒模式
14+
15+
- 或者创建专用的文件名加密函数
16+
17+
3. **修改显示逻辑**
18+
- 在平铺视图中对文件名应用加密
19+
20+
- 在嵌套视图的文件夹名和文件名上应用加密
21+
22+
- 只影响显示,不改变实际数据
23+
24+
4. **UI优化**
25+
- 添加隐私模式切换按钮,图标使用遮罩或眼睛图标
26+
27+
- 按钮状态反映当前是否开启隐私模式
28+
29+
## 技术要点
30+
31+
- 使用凯撒移位加密(字符后移一位)
32+
33+
- 复用现有的加密逻辑
34+
35+
- 只在前端渲染层面做改变,不影响数据存储
36+
37+
- 支持中英文字符的合理加密处理

app/src-tauri/capabilities/default.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"global-shortcut:allow-is-registered",
3939
"global-shortcut:allow-register",
4040
"global-shortcut:allow-unregister",
41+
"global-shortcut:allow-unregister-all",
4142
"system-info:allow-all",
4243
{
4344
"identifier": "http:default",

app/src/App.tsx

Lines changed: 5 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { GlobalMenu } from "@/core/service/GlobalMenu";
99
import { Settings } from "@/core/service/Settings";
1010
import { Telemetry } from "@/core/service/Telemetry";
1111
import { Themes } from "@/core/service/Themes";
12+
import { globalShortcutManager } from "@/core/service/controlService/shortcutKeysEngine/GlobalShortcutManager";
1213
import {
1314
activeProjectAtom,
1415
isClassroomModeAtom,
@@ -29,7 +30,6 @@ import { cpuInfo } from "tauri-plugin-system-info-api";
2930
import { DragFileIntoStageEngine } from "./core/service/dataManageService/dragFileIntoStageEngine/dragFileIntoStageEngine";
3031
import { cn } from "./utils/cn";
3132
import { isMac, isWindows } from "./utils/platform";
32-
import { register } from "@tauri-apps/plugin-global-shortcut";
3333
import { KeyBindsUI } from "./core/service/controlService/shortcutKeysEngine/KeyBindsUI";
3434
import { ProjectTabs } from "./ProjectTabs";
3535
import { DropWindowCover } from "./DropWindowCover";
@@ -41,8 +41,6 @@ export default function App() {
4141

4242
const [projects, setProjects] = useAtom(projectsAtom);
4343
const [activeProject, setActiveProject] = useAtom(activeProjectAtom);
44-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
45-
const [___, setIsWindowAlwaysOnTop] = useAtom(isWindowAlwaysOnTopAtom);
4644
const canvasWrapperRef = useRef<HTMLDivElement>(null);
4745
// const [isWide, setIsWide] = useState(false);
4846
const [telemetryEventSent, setTelemetryEventSent] = useState(false);
@@ -51,8 +49,6 @@ export default function App() {
5149
);
5250
const [ignoreMouseEvents, setIgnoreMouseEvents] = useState(false);
5351
const [isClassroomMode, setIsClassroomMode] = useAtom(isClassroomModeAtom);
54-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
55-
const [__, setIsClickThroughEnabled] = useAtom(isClickThroughEnabledAtom);
5652

5753
const contextMenuTriggerRef = useRef<HTMLDivElement>(null);
5854

@@ -137,49 +133,14 @@ export default function App() {
137133
}
138134
});
139135

140-
// TODO: 以后整一个全局快捷键系统
141-
register("Alt+2", async (event) => {
142-
if (event.state === "Pressed") {
143-
setIsClickThroughEnabled((prev) => {
144-
if (!Settings.allowGlobalHotKeys) {
145-
toast.warning("已禁用全局快捷键");
146-
return prev;
147-
}
148-
if (!prev) {
149-
// 开启了穿透点击
150-
Settings.windowBackgroundAlpha = Settings.windowBackgroundOpacityAfterOpenClickThrough;
151-
setIsWindowAlwaysOnTop(true);
152-
getCurrentWindow().setAlwaysOnTop(true);
153-
} else {
154-
// 关闭了穿透点击
155-
Settings.windowBackgroundAlpha = Settings.windowBackgroundOpacityAfterCloseClickThrough;
156-
setIsWindowAlwaysOnTop(false);
157-
getCurrentWindow().setAlwaysOnTop(false);
158-
}
159-
getCurrentWindow().setIgnoreCursorEvents(!prev);
160-
return !prev;
161-
});
162-
}
163-
});
164-
165-
register("Alt+1", async (event) => {
166-
if (event.state === "Pressed") {
167-
if (!Settings.allowGlobalHotKeys) {
168-
toast.warning("已禁用全局快捷键");
169-
return;
170-
}
171-
console.log("开始呼出窗口");
172-
// 呼出软件窗口
173-
const window = getCurrentWindow();
174-
await window.show();
175-
await window.setSkipTaskbar(false);
176-
await window.setFocus();
177-
}
178-
});
136+
// 初始化全局快捷键管理
137+
globalShortcutManager.init();
179138

180139
return () => {
181140
unlisten1?.then((f) => f());
182141
KeyBindsUI.uiStopListen();
142+
// 清理全局快捷键资源
143+
globalShortcutManager.dispose();
183144
};
184145
}, []);
185146

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import { register, unregisterAll, isRegistered, unregister } from "@tauri-apps/plugin-global-shortcut";
2+
import { getCurrentWindow } from "@tauri-apps/api/window";
3+
import { Settings } from "../../Settings";
4+
import { toast } from "sonner";
5+
6+
// 定义全局快捷键类型
7+
interface GlobalShortcut {
8+
key: string;
9+
id: string;
10+
description: string;
11+
onPress: () => Promise<void>;
12+
}
13+
14+
export class GlobalShortcutManager {
15+
private shortcuts: GlobalShortcut[] = [];
16+
private isInitialized = false;
17+
private isClickThroughEnabled = false;
18+
private settingsUnsubscribe: (() => void) | null = null;
19+
20+
constructor() {
21+
this.initializeShortcuts();
22+
}
23+
24+
// 初始化快捷键定义
25+
private initializeShortcuts() {
26+
this.shortcuts = [
27+
{
28+
key: "Alt+2",
29+
id: "toggle-click-through",
30+
description: "开启/关闭窗口穿透点击",
31+
onPress: this.handleToggleClickThrough.bind(this),
32+
},
33+
{
34+
key: "Alt+1",
35+
id: "show-window",
36+
description: "呼出软件窗口",
37+
onPress: this.handleShowWindow.bind(this),
38+
},
39+
];
40+
}
41+
42+
// 初始化服务
43+
public async init() {
44+
if (this.isInitialized) {
45+
return;
46+
}
47+
48+
this.isInitialized = true;
49+
Settings.watch("allowGlobalHotKeys", (v) => {
50+
// v 是变化后的值
51+
if (v) {
52+
this.updateShortcuts();
53+
} else {
54+
unregisterAll();
55+
}
56+
});
57+
}
58+
59+
// 更新快捷键注册状态
60+
public async updateShortcuts() {
61+
// 先注销所有快捷键
62+
await unregisterAll();
63+
for (const shortcut of this.shortcuts) {
64+
await this.registerShortcut(shortcut);
65+
}
66+
}
67+
68+
// 注册单个快捷键
69+
private async registerShortcut(shortcut: GlobalShortcut) {
70+
try {
71+
// 检查是否已注册
72+
const alreadyRegistered = await isRegistered(shortcut.key);
73+
if (alreadyRegistered) {
74+
await unregister(shortcut.key);
75+
}
76+
77+
// 注册快捷键
78+
await register(shortcut.key, async (event) => {
79+
if (event.state === "Pressed") {
80+
await shortcut.onPress();
81+
}
82+
});
83+
} catch (error) {
84+
toast.error(`注册全局快捷键 ${shortcut.key} 失败: ${error}`);
85+
}
86+
}
87+
88+
// 处理穿透点击切换
89+
private async handleToggleClickThrough() {
90+
const window = getCurrentWindow();
91+
92+
if (!this.isClickThroughEnabled) {
93+
// 开启了穿透点击
94+
Settings.windowBackgroundAlpha = Settings.windowBackgroundOpacityAfterOpenClickThrough;
95+
await window.setAlwaysOnTop(true);
96+
} else {
97+
// 关闭了穿透点击
98+
Settings.windowBackgroundAlpha = Settings.windowBackgroundOpacityAfterCloseClickThrough;
99+
await window.setAlwaysOnTop(false);
100+
}
101+
102+
this.isClickThroughEnabled = !this.isClickThroughEnabled;
103+
await window.setIgnoreCursorEvents(this.isClickThroughEnabled);
104+
}
105+
106+
// 处理显示窗口
107+
private async handleShowWindow() {
108+
console.log("开始呼出窗口");
109+
const window = getCurrentWindow();
110+
await window.show();
111+
await window.setSkipTaskbar(false);
112+
await window.setFocus();
113+
}
114+
115+
// 清理资源
116+
public async dispose() {
117+
// 注销所有快捷键
118+
await unregisterAll();
119+
120+
// 移除设置监听器
121+
if (this.settingsUnsubscribe) {
122+
this.settingsUnsubscribe();
123+
this.settingsUnsubscribe = null;
124+
}
125+
126+
this.isInitialized = false;
127+
console.log("全局快捷键管理器已清理");
128+
}
129+
130+
// 获取所有快捷键信息
131+
public getShortcuts() {
132+
return this.shortcuts;
133+
}
134+
}
135+
136+
// 创建单例实例
137+
export const globalShortcutManager = new GlobalShortcutManager();

0 commit comments

Comments
 (0)