mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-21 16:01:35 +08:00
192 lines
9.3 KiB
Markdown
192 lines
9.3 KiB
Markdown
# Cherry Studio 快捷键系统重构设计文档 v2.1
|
||
|
||
> 最近更新:2025-01-30
|
||
> 维护者:Architecture Team
|
||
|
||
## 目录
|
||
|
||
- [背景与目标](#背景与目标)
|
||
- [核心原则](#核心原则)
|
||
- [架构分层](#架构分层)
|
||
- [关键实现](#关键实现)
|
||
- [数据流](#数据流)
|
||
- [默认快捷键](#默认快捷键)
|
||
- [迁移与兼容性](#迁移与兼容性)
|
||
- [后续演进方向](#后续演进方向)
|
||
|
||
---
|
||
|
||
## 背景与目标
|
||
|
||
旧版快捷键系统存在以下问题:
|
||
|
||
1. 依赖已弃用的 `configManager`,与 v2 架构不兼容;
|
||
2. Redux store 与本地存储重复维护状态;
|
||
3. 处理器通过 `switch-case` 硬编码,可维护性差;
|
||
4. 快捷键定义分散,缺乏统一真相源;
|
||
5. 新增快捷键需要触达多处文件,易错且低效。
|
||
|
||
新版系统要实现:
|
||
|
||
- **单一真相源**:快捷键定义集中管理,保证一致性;
|
||
- **偏好服务优先**:所有运行时状态通过 `preferenceService` 管理;
|
||
- **处理器注册表**:解除 `switch-case` 依赖,改用 Map 注册;
|
||
- **类型安全**:从定义、存储到消费全链路具备 TypeScript 约束;
|
||
- **易扩展**:新增快捷键仅需「定义 → 注册处理器 → 使用」三步;
|
||
- **性能稳定**:支持 100+ 快捷键规模,主/渲染进程高效同步;
|
||
- **多窗口同步**:借助 `preferenceService` 自动推送变更。
|
||
|
||
---
|
||
|
||
## 核心原则
|
||
|
||
1. **关注点分离**
|
||
- 定义层:静态元数据(名称、默认绑定、作用域、分类等);
|
||
- 偏好层:用户可变配置(绑定、启用状态等);
|
||
- 服务层:主进程注册、电焦/失焦时的生命周期管理;
|
||
- UI 层:设置面板、快捷键提示等。
|
||
|
||
2. **复用基础设施**
|
||
- 所有持久化均依赖 `preferenceService`(SQLite + 内存缓存 + IPC);
|
||
- 变更通过订阅自动广播至所有窗口;
|
||
- 新增键位无需改动主进程/渲染进程的底层框架代码。
|
||
|
||
---
|
||
|
||
## 架构分层
|
||
|
||
```
|
||
┌──────────────────────────────────────────────┐
|
||
│ Shortcut 系统 │
|
||
├──────────────────────────────────────────────┤
|
||
│ 📋 Definitions (packages/shared/shortcuts) │
|
||
│ - types.ts:类型、作用域、分类 │
|
||
│ - definitions.ts:静态定义(真相之源) │
|
||
│ - utils.ts:转换/校验工具 │
|
||
│ │
|
||
│ 💾 Preferences (preferenceService) │
|
||
│ - preferenceSchemas.ts 默认值 │
|
||
│ - preferenceTypes.ts 类型导出 │
|
||
│ │
|
||
│ ⚙️ Services │
|
||
│ - src/main/services/ShortcutService.ts │
|
||
│ · 处理器注册表、focus/blur 生命周期 │
|
||
│ · preference 订阅、主进程快捷键注册 │
|
||
│ - 渲染进程 useShortcut/useShortcutDisplay │
|
||
│ │
|
||
│ 🎨 UI │
|
||
│ - 设置页 ShortcutSettings │
|
||
│ - 各功能模块中的 useShortcut/useShortcutDisplay │
|
||
└──────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 关键实现
|
||
|
||
### 1. 静态定义
|
||
|
||
- 所有快捷键在 `packages/shared/shortcuts/definitions.ts` 中集中维护;
|
||
- 包含 `scope`(main / renderer / both)、`category`、`persistOnBlur` 等元信息;
|
||
- `enabledWhen` 支持动态启用(如 mini window 与 quick assistant 开关关联);
|
||
- 新增快捷键步骤:
|
||
1. 在 `preferenceSchemas.ts` 中声明默认值;
|
||
2. 在 `definitions.ts` 中补充静态定义;
|
||
3. 在主/渲染进程相关模块注册处理器或消费 Hook。
|
||
|
||
### 2. 偏好系统
|
||
|
||
- 所有运行时配置通过 `preferenceService` 读写;
|
||
- 默认值与 `PreferenceShortcutType` 结构保持一致;
|
||
- `ShortcutService` / `useShortcuts` 访问偏好时统一调用 `coerceShortcutPreference`,确保 fallback 与类型安全;
|
||
- 批量重置通过 `preferenceService.setMultiple` 实现。
|
||
|
||
### 3. 主进程服务
|
||
|
||
- `ShortcutService` 负责:
|
||
- 生命周期:随着窗口 focus/blur 注册或卸载快捷键;
|
||
- 处理器注册:Map 替换 `switch-case`;
|
||
- 订阅偏好变更:自动重新注册;
|
||
- `persistOnBlur`:例如 `show_main_window` 在窗口失焦时仍可触发;
|
||
- `shortcut.app.show_settings` 会在需要时唤起窗口并调用 `window.navigate('/settings/provider')`,避免重复 blur/focus。
|
||
|
||
### 4. 渲染进程 Hook
|
||
|
||
- `useShortcut`:从偏好获取绑定 → 转为 `react-hotkeys-hook` 字符串 → 注册快捷键;
|
||
- `useShortcutDisplay`:转换为 UI 显示字符串(`⌘` / `Ctrl+` 等);
|
||
- `useAllShortcuts`:批量拉取配置 + diff 默认值,供设置面板使用;
|
||
- 新增 `enableOnContentEditable` 等配置支撑设置页和富文本场景。
|
||
|
||
### 5. 设置界面
|
||
|
||
- `ShortcutSettings` 直接消费 `useAllShortcuts`;
|
||
- 支持录制、清空、重置默认、启用/禁用、冲突检测;
|
||
- 重新绑定时使用 `convertKeyToAccelerator` / `isValidShortcut` / `formatShortcutDisplay`;
|
||
- “重置全部” 通过 `preferenceService.setMultiple` 一次性写入默认配置;
|
||
- 新增表格展示 `hasCustomBinding`,区分用户自定义与继承默认值。
|
||
|
||
---
|
||
|
||
## 数据流
|
||
|
||
### 启动阶段
|
||
|
||
1. `preferenceService.initialize()` 载入缓存;
|
||
2. `shortcutService` 构造时注册处理器与订阅;
|
||
3. 窗口创建后调用 `shortcutService.registerForWindow`,在 `focus` 时注册主进程快捷键。
|
||
|
||
### 运行时变更
|
||
|
||
1. 设置页或其他模块调用 `preferenceService.set` / `setMultiple`;
|
||
2. 主进程订阅触发 → `globalShortcut.unregisterAll()` → 按新配置重注册;
|
||
3. 渲染进程通过 `usePreference`/`useMultiplePreferences` 自动收到更新,UI 即时刷新。
|
||
|
||
---
|
||
|
||
## 默认快捷键
|
||
|
||
| preference key | 默认绑定 | 描述 / 备注 |
|
||
|----------------------------------------|-----------------------------|--------------------------------------|
|
||
| `shortcut.app.show_main_window` | `Cmd/Ctrl + Shift + A` | 主窗口显示(失焦持久) |
|
||
| `shortcut.app.show_mini_window` | `Cmd/Ctrl + E` | Mini 窗口(与 quick assistant 联动) |
|
||
| `shortcut.app.show_settings` | `Cmd/Ctrl + ,` | 设置页入口 |
|
||
| `shortcut.app.toggle_show_assistants` | `Cmd/Ctrl + [` | 助手侧边栏 |
|
||
| `shortcut.app.exit_fullscreen` | `Escape` | 系统级,不可编辑 |
|
||
| `shortcut.app.zoom_in/out/reset` | `Cmd/Ctrl + = / - / 0` | 包含数字键盘变体 |
|
||
| `shortcut.app.search_message` | `Cmd/Ctrl + Shift + F` | 全局搜索 |
|
||
| `shortcut.chat.clear` | `Cmd/Ctrl + L` | 清空消息 |
|
||
| `shortcut.chat.search_message` | `Cmd/Ctrl + F` | 聊天内搜索 |
|
||
| `shortcut.chat.toggle_new_context` | `Cmd/Ctrl + K` | 新上下文 |
|
||
| `shortcut.chat.copy_last_message` | `Cmd/Ctrl + Shift + C` | 复制最后一条 |
|
||
| `shortcut.chat.edit_last_user_message` | `Cmd/Ctrl + Shift + E` | 编辑最后一条用户消息 |
|
||
| `shortcut.topic.new` | `Cmd/Ctrl + N` | 新增话题(默认启用) |
|
||
| `shortcut.topic.rename` | `Cmd/Ctrl + T` | 重命名话题(默认启用,自 2025-01 调整) |
|
||
| `shortcut.topic.toggle_show_topics` | `Cmd/Ctrl + ]` | 话题侧边栏 |
|
||
| `shortcut.selection.*` | 无默认绑定 | 划词助手开关、取词 |
|
||
|
||
> 具体配置以 `preferenceSchemas.ts` 为准,可在设置页查看或调整。
|
||
|
||
---
|
||
|
||
## 迁移与兼容性
|
||
|
||
- 已有用户偏好:沿用旧值;新增键(如 `shortcut.topic.rename`)在数据库不存在时继承新默认;
|
||
- 旧版 Redux store / `configManager` 已彻底移除;
|
||
- `IpcChannel.Shortcuts_Update` 与 `window.api.shortcuts.update` 相关逻辑已弃用;
|
||
- `PreferenceMigrator` 中保留与旧 keys 的映射,确保升级顺畅。
|
||
|
||
---
|
||
|
||
## 后续演进方向
|
||
|
||
1. **冲突检测增强**:主/渲染进程联动校验冲突并提示;
|
||
2. **导入导出**:允许用户批量备份/恢复自定义快捷键;
|
||
3. **多作用域绑定**:同一逻辑支持按窗口类型或上下文切换;
|
||
4. **可视化录制**:增加「录制模式」避免输入框手动录制;
|
||
5. **自动化测试**:补充主进程/渲染进程快捷键单元测试样板。
|
||
|
||
---
|
||
|
||
> 如需扩展或有疑问,请联系架构团队或在仓库中提交 Issue。
|
||
> 设计文档 v2.1 同步最新实现(2025-01),包含 `shortcut.topic.rename` 默认启用、`show_settings` 优化等补充说明。
|