快捷键设置:MVP P0 / P1
- 对应 快捷键产品方案 第 31 节的 P0、P1 范围。
- 入口:设置 → 快捷键设置;旁边的「热键设置」直接打开热键配置。
- 页面通过「快捷键 / 热键」单选框切换,两类列表分别配置,切换时清空搜索与冲突筛选。
- 「编辑 JSON」和「默认 JSON」仅显示当前类别;保存 JSON 保留另一类别的配置,两类仍写入本机 keybindings.json。
- 若 JSON 文件语法损坏,编辑器显示完整原文件并提示修复范围;修复保存会更新全部配置。
- 热键类别单独显示「启用热键」开关;热键录制一段后立即完成,可继续重新录制,Enter 保存。
- 默认也可用
Ctrl+K Ctrl+S打开;macOS 使用Cmd+K Cmd+S。 - 修改立即生效,不需要点击外层「保存设置」。
- 外层设置的取消按钮不会撤销已经保存的快捷键。
查看与编辑
- 页面按绑定逐行显示命令、快捷键、When、Source 和操作。
- 表头保持单行,不自动换行;列内容仍可换行,宽度不足时表格区域可横向滚动。
- 同一命令支持多条绑定;全部删除后仍显示「未绑定」,可以再次添加或恢复默认。
- 搜索支持命令名称、命令 ID、快捷键、生效条件和来源文本。
- Source 的
system表示默认规则,user表示用户规则。 - 「修改」支持同时修改按键和 When。
- 「添加」为命令增加独立绑定。
- 「删除」仅删除当前绑定;默认规则通过用户移除记录屏蔽,不修改默认数据。
- 「恢复默认」清除该命令的全部用户绑定与移除记录。
- 快捷键设置、编辑和 JSON 配置对话框保持固定高度(受窗口高度限制),内容过多时在内部滚动;搜索结果数量和错误提示不会撑高对话框。
- 每次添加或修改快捷键默认进入按键录制;可点击「切换为手动输入」直接编辑文本,也可切回录制,两种方式保留已输入的快捷键。
- 不显示「重新录制」按钮;超时或收满两段后自动等待下一组按键,保留上一组结果供保存,新一组录制完成后替换它。
- 录制/手动输入模式同时作用于通用键位和 Windows、macOS、Linux 平台覆盖;录制模式下聚焦哪个键位输入框,按键就写入哪个字段,手动模式下四个字段均可直接编辑。
- 离开当前键位输入框时保留已捕获的第一段并结束录制;When 始终可手动编辑,再次聚焦任一键位输入框会开始录制。
- Tab 用于离开录制框,需要绑定 Tab 时可切换为手动输入。
- 每组录制最多两段;第一段后停顿 1.8 秒完成,第二段按下后立即完成,并自动开始下一次录制。
- 录制时 Esc 取消;Enter 仅在第二段作为快捷键录入,第一段按 Enter 会保存当前配置并关闭编辑对话框(校验或保存失败时保留对话框和草稿)。
- 超时或收满两段后已自动进入下一组的第一段,此时按 Enter 同样保存当前结果;也可点击「保存」。
- 关闭快捷键编辑对话框后恢复上一级页面原先聚焦的元素;保存重建列表后恢复到对应快捷键行的同一操作按钮,若该行不再符合筛选条件则聚焦搜索框。
- 保存失败会显示错误,并保留原来的有效配置。
默认命令
- 命令面板可通过
Ctrl/Cmd+Shift+P、F1或工具栏「命令」按钮打开。 - 通过 Esc 或点击面板外部关闭后,恢复原先 textarea 或 input 的焦点、光标位置和选区方向;鼠标点击「命令」按钮也保留原先的输入焦点。
- 执行命令前先恢复原先的焦点和选区,让命令使用原来的输入位置;命令自身仍可按其功能转移焦点。
- 命令面板独立回归验证:
npx electron test/electron-smoke.js --command-palette-only,覆盖输入框焦点、光标、选区方向和各关闭路径。
下表的主修饰键在 Windows/Linux 为 Ctrl,在 macOS 为 Cmd。
| 命令 ID | 功能 | 默认快捷键 |
|---|---|---|
file.new |
新建文档 | 主修饰键+N |
file.open |
打开文件 | 主修饰键+O |
file.quickOpen |
快速打开 | 主修饰键+P |
workspace.openRecent |
打开最近的笔记库 | Ctrl+R(所有平台) |
workspace.openInVSCode |
用 VS Code 打开当前仓库 | Alt+Shift+V |
workspace.revealInFileExplorer |
在文件管理器中显示 | Shift+Alt+R |
file.save |
保存文档 | 主修饰键+S |
file.saveAs |
另存为 | 未绑定 |
file.close |
关闭文档 | 主修饰键+W |
workspace.copyPath |
复制文件或文件夹路径 | Shift+Alt+C |
workspace.copyRelativePath |
复制文件或文件夹相对路径 | 主修饰键+K 主修饰键+Shift+C |
editor.insertImage |
插入本地图片 | 主修饰键+Shift+I |
editor.gotoLine |
跳转到行 | 主修饰键+G |
editor.selectionToList |
切换列表 | Alt+Shift+L |
sync.open |
打开同步 | Alt+S |
outline.focus |
聚焦大纲 | 主修饰键+Shift+O |
search.open |
页内查找 | 主修饰键+F |
search.replace |
替换当前文件 | Ctrl+H;macOS:Cmd+Option+F |
search.findInFiles |
在文件中查找 | 主修饰键+Shift+F |
search.replaceInFiles |
在文件中替换 | 主修饰键+Shift+R |
search.next |
下一个匹配 | F3 |
search.previous |
上一个匹配 | Shift+F3 |
tabs.mruNext |
最近使用标签 | Ctrl+Tab |
tabs.mruPrevious |
反向最近使用标签 | Ctrl+Shift+Tab |
tabs.previous |
上一个标签 | Ctrl+PageUp;macOS:Cmd+Shift+[ |
tabs.next |
下一个标签 | Ctrl+PageDown;macOS:Cmd+Shift+] |
view.sidebar |
切换侧边栏 | 未绑定 |
view.editor |
切换编辑器 | 未绑定 |
view.preview |
切换预览 | 未绑定 |
view.outline |
切换大纲 | 未绑定 |
settings.keyboard |
打开快捷键设置 | 主修饰键+K 主修饰键+S |
- 最近标签选择器保留原有控件操作:方向键选择、Enter 确认、Esc 取消、松开 Ctrl 确认。
- 编辑区(含只读搜索页)聚焦时,
Ctrl+↑/Ctrl+↓每次向上 / 向下滚动一个行高,长按连续滚动;光标位置、选区及其方向保持不变,到达顶部或底部时也不移动光标。 - 此滚动操作属于编辑区局部按键行为,各平台均使用 Ctrl;带 Shift、Alt、Cmd 的组合及输入法组合输入不触发该操作,现有用户自定义快捷键仍优先处理。
- 大纲菜单点击入口保留;快捷键由渲染进程统一处理,以便修改和删除默认绑定生效。
- 查找栏的 Enter/Esc、Alt+C/Alt+W、当前文件全部替换(Windows/Linux 为 Ctrl+Alt+Enter,macOS 为 Cmd+Enter),以及文件树、右键菜单等局部控件导航沿用原有实现,不属于本次可配置命令集合。
When 与分发规则
- 支持
!、&&、||、==、!=和括号。 - 比较右侧可使用裸文本或引号包围的文本,例如
editorLanguage == markdown。 - 空条件视为 true,未知 Context Key 的布尔值视为 false。
- 不使用
eval,无效表达式不能保存。 - 当前提供的 Context Keys:
editorFocus、editorTextFocus、editorHasSelection、editorReadonly、editorLanguage。inputFocus、documentOpen、markdownDocument、workspaceEntrySelected。pathCopyAvailable、relativePathCopyAvailable。searchVisible、searchInputFocus。outlineFocus、outlineVisible、sidebarFocus、sidebarVisible。modalOpen、dialogOpen、platform。
platform的值为windows、mac或linux。- 大部分默认规则含
!modalOpen,保存等操作还要求已打开文档。 - 弹窗打开时,仅显式声明弹窗上下文且条件成立的规则可执行。
- 快捷键设置和录制弹窗始终暂停命令分发。
- 普通输入控件保留字符、删除、光标移动及 Ctrl/Cmd+A/C/V/X/Z/Y 等编辑行为。
- 需要在输入控件中覆盖这些按键时,规则必须显式指定
editorFocus、editorTextFocus、inputFocus或searchInputFocus。 - 忽略输入法组合输入、纯修饰键和 AltGraph;优先使用物理
KeyboardEvent.code规范化字母、数字和标点。 - 用户绑定优先于插件绑定,插件绑定优先于系统绑定;同一优先级按条件中的词项数量估计具体程度,再按最后注册者优先。
- 此具体程度规则是确定性启发式,不做完整逻辑蕴含判断。
- 同键或一段键与 Chord 前缀重叠时显示可能冲突,允许保存并保留两者。
- 简单合取条件中的互斥值可判定为无冲突;其余条件保守提示。
- 有效 Chord 的前缀优先等待第二段,不立即执行同前缀的单段绑定。
- 等待超过 1.8 秒、Esc、窗口失焦或控件焦点切换会取消 Chord。
- 第二段按下时重新检查上下文;不匹配时结束等待,当前按键继续交给原控件。
- 操作系统及 Electron 原生菜单保留的按键仍可能被外层拦截,页面对常见组合显示提醒。
存储与实现
- 本地配置存于 Electron
app.getPath('userData')/User/keybindings.json,目录和文件不存在时自动创建,初始内容为[]。 - Windows 默认路径为
%APPDATA%\mynote-client\User\keybindings.json,例如C:\Users\Administrator\AppData\Roaming\mynote-client\User\keybindings.json。 - 实际路径由应用的用户数据目录决定,在快捷键列表和 JSON 编辑窗口中显示;不写入 VS Code 的
Code\User目录。 - 不再读取或写入快捷键
localStorage;按本次约定不迁移旧配置。 - 配置属于本机应用配置,所有笔记库共用,不参与笔记库同步。
- 文件只包含公开 JSON 格式的用户绑定与默认移除规则;重启后重新叠加到系统默认规则。
- 写入采用 UTF-8、LF、两空格缩进;先写同目录临时文件,再替换目标文件。
- 主进程只允许访问固定配置文件,大小上限为 1 MiB;渲染进程不能指定其他路径。
- 启动时无法读取或解析配置会提示错误并暂用默认值,不覆盖原文件。
- 主进程每 500 毫秒检测文件变化,窗口重新获得焦点和打开设置时也会重新读取;有效外部编辑自动更新列表和分发。
- 运行期间外部编辑无效时保留最后有效快捷键;可打开 JSON 编辑器查看原文件并修复。
- 保存时比较最近读取的文件内容,发现外部变更则拒绝覆盖;重新打开编辑器后再修改。
src/main/keybinding-file.js:固定路径文件读写、外部变更通知与 IPC;设置读写使用有大小限制的同步本地文件操作,以保持保存成功后才切换有效规则的行为。src/renderer/keyboard/service.mjs:命令注册、覆盖存储、冲突检查和 Chord 分发。src/renderer/keyboard/when.mjs:条件解析与求值。src/renderer/keyboard/keys.mjs:按键规范化与显示。src/renderer/keyboard/page.mjs:按需加载的设置及录制界面。src/renderer/runtime/keyboard.js:应用命令与实际上下文接入。- P2 的 Profiles、云同步和导入导出未纳入本次。
P1:JSON 配置
- 点击「编辑 JSON」查看和修改磁盘文件;列表与 JSON 共用
User/keybindings.json,不维护另一份存储。 - 「编辑 JSON」旁提供「默认 JSON」按钮,弹出只读窗口展示全部内置及当前已加载插件的默认快捷键 JSON,包括通用键位、平台覆盖和生效条件,不受用户修改或删除规则影响。
- 每条默认配置附带
description命令描述,使用快捷键列表中的中文命令名称(插件使用其注册名称,缺失时回退为命令 ID),查看及复制均包含该字段;该字段仅用于默认配置参考,不属于用户配置格式。 - 默认 JSON 支持选择文本复制及点击「复制 JSON」复制全部内容;复制成功或失败会在窗口内提示,查看和复制不会修改用户配置。
- 复制接口允许最多 1 Mi 个字符,支持完整默认配置等长文本,并保留输入类型、非空及长度校验。
- 每次打开默认 JSON 都读取最新默认规则;窗口内容可滚动,点击「关闭」或按 Esc 退出。
- JSON 配置弹窗的文件路径旁提供「定位文件」链接,点击后在系统文件管理器中打开所在目录并选中
keybindings.json;不保存或关闭当前草稿,定位失败时在弹窗内提示。 - 列表修改后重新打开 JSON 即可看到更新;JSON 保存成功后列表立即刷新。
- JSON 草稿需点击「保存 JSON」才生效;取消不会修改配置。
- 保存前完整校验数组、字段、键位和 When;解析或持久化失败会保留草稿及原有效配置。
- 草稿打开期间配置发生变化时拒绝覆盖,需取消后重新打开。
- 普通规则使用
command、key、可选when、win、mac、linux字段。 command前缀-表示移除匹配的默认绑定;按通用key匹配,可用when和平台覆盖进一步限定。- 插件未加载时,已有默认移除记录可用
{"remove":"绑定 ID"}保留;文件中的负命令移除规则也会保留,插件注册后参与默认绑定过滤。 - 未注册命令的用户规则会保留在 JSON 中,但不显示在列表,也不参与分发或冲突检查;命令注册后自动生效。
- 未知字段会报错,避免拼写错误被静默忽略。
[
{ "command": "-file.save", "key": "ctrl+s" },
{
"command": "file.save",
"key": "ctrl+shift+s",
"mac": "cmd+shift+s",
"linux": "",
"when": "documentOpen && !modalOpen"
}
]
P1:平台覆盖、搜索与冲突视图
key是通用键位,win、mac、linux分别覆盖 Windows、macOS、Linux。- 省略平台字段表示继承通用键位;JSON 空字符串表示在该平台禁用。
- 编辑界面提供三平台输入框及「禁用此平台」复选框;点击复选框或文字均可切换勾选状态。
- 添加绑定或修改内置默认绑定时,平台覆盖默认留空且不勾选禁用;保存后留空的平台继承通用快捷键。
- 修改已保存的用户绑定或插件绑定时回显已有平台覆盖和禁用状态;已有平台覆盖需要单独修改,修改通用键位不会覆盖它们。
- 平台覆盖与通用键位共用当前的按键录制/手动输入模式;录制结果写入当前聚焦的字段。
- 顶部「查看平台」仅改变列表和冲突预览;实际分发始终使用当前操作系统。
- 平台禁用的绑定仍可在列表中修改、删除或恢复默认。
- Command ID 显示在命令名下,并可直接搜索。
- 高级过滤器支持
@command:、@keybinding:、@when:、@source:和@conflict。 - 多个条件同时匹配;带空格的值用引号,例如
@source:user @keybinding:"ctrl+k enter"。 @source:plugin查看所有插件规则;@source:plugin:demo查看指定插件。- 点击「仅查看冲突」进入冲突视图,可叠加搜索和平台选择;再次点击返回全部绑定。
- 冲突行列出对方命令 ID、同键或 Chord 前缀关系、When 和来源,可直接修改或删除。
- 冲突视图沿用 P0 的保守条件重叠判断,不阻止保存。
P1:插件快捷键接口
- 为受信任的本地渲染模块提供
window.mynoteKeyboard.registerPlugin(id, contributions)。 - 此接口负责快捷键贡献注册,不提供插件下载、安装或执行 JSON 代码的能力。
- 命令 ID 必须以
插件ID.为前缀,且全局唯一;命令需提供标题与执行函数。 - 插件绑定只能引用本插件命令,支持与用户 JSON 相同的键位和平台覆盖。
- 注册会先整体校验,失败时不留下部分命令。
- 来源显示为
plugin:插件ID,用户可修改、删除并恢复插件默认绑定。 - 返回的卸载函数移除命令和默认绑定、取消等待中的 Chord,并刷新页面;用户覆盖和移除记录保留。
- 默认绑定 ID 按
plugin.插件ID.数组下标生成;插件更新需保持绑定顺序稳定,以维持用户移除记录的对应关系。
const dispose = window.mynoteKeyboard.registerPlugin('demo', {
commands: [{ id: 'demo.run', title: '运行示例', execute: () => console.log('demo') }],
bindings: [{ command: 'demo.run', key: 'ctrl+alt+j', mac: 'meta+alt+j', when: '!modalOpen' }]
});
// 插件卸载时调用;可重复调用,不影响后续重新注册的插件。
dispose();
src/renderer/keyboard/config.mjs:公开 JSON 格式转换和整体校验。src/renderer/keyboard/filter.mjs:高级搜索过滤。src/renderer/keyboard/json-editor.mjs:JSON 草稿编辑界面,随快捷键设置按需加载。src/renderer/keyboard/default-json.mjs:默认快捷键 JSON 只读查看和复制界面,首次点击按钮时创建弹窗。
全局热键配置
- 「查看平台」旁提供「启用热键」复选框,默认勾选;取消勾选后立即注销全部全局热键,重新勾选后按当前保存的配置恢复注册。
- 开关独立保存在本机
User/hotkeys.json,重启后保留;关闭期间修改快捷键配置不会重新注册热键,已有绑定和应用内快捷键保持可用。 - 重新启用时若发生系统占用或配置无效,开关保持关闭并显示错误;开关文件保存失败时保持此前状态。
- 在「设置 → 快捷键设置」搜索「全局热键」或
window.toggleVisibility,可修改「显示/最小化窗口(全局热键)」。 - 默认仍为
Alt+Shift+S:窗口已聚焦时最小化;其他情况下恢复、显示并聚焦窗口。 - 支持添加多个热键、删除、恢复默认、JSON 编辑和 Windows / macOS / Linux 平台覆盖;平台值为空字符串表示禁用。
- 全局热键在其他应用获得焦点时也能触发,仅支持一段组合键,When 必须留空,不支持 ContextMenu 键。
- 配置保存在本机
User/keybindings.json,保存后立即重新注册;下次启动自动读取,外部文件修改也会重载。 - 新热键被系统或其他应用占用时,保存失败并显示原因,原热键和配置文件保持不变。
- 文件写入失败时撤销新注册;外部配置无效或注册失败时保留上次有效热键,JSON 编辑器仍可打开文件修复。
- 首次运行包含此功能的新代码需要重启应用;此后修改热键无需重启。
- 全局热键由 Electron 主进程独立处理,渲染进程不重复分发。
验证
-
node --test test/hotkey-settings.test.js:总开关注销多个热键、关闭期间读写、重启持久化、重新启用冲突、保存失败回滚和无效配置下关闭。 -
node --test test/window-hotkey.test.js test/keybinding-file.test.js:全局热键注册、替换、系统占用回退、平台禁用、恢复默认、写入失败回滚和无效配置修复。 -
node --test test/keybinding-file.test.js test/keybinding-p1.test.mjs test/keybinding-service.test.mjs test/keyboard-shortcuts.test.mjs test/menu.test.js:磁盘读写、引擎、JSON、平台、插件、过滤器与菜单单元测试。 -
npm run test:smoke:keyboard:真实 Electron 设置入口、录制 Enter Chord、修改、删除、恢复默认、旧查找快捷键停用、磁盘持久化、外部修改、无效 JSON 修复和渲染进程重新加载。 -
npm run test:smoke:完整界面回归。 -
node scripts/renderer/lint.js和npx eslint .:渲染脚本及全量 ESLint。 -
原始产品方案文件超过现有 600 行检查上限;保留其完整内容,因此该文档仍会触发
check:file-length。
P1 验证结果(2026-09-05)
- 16 项相关单元测试通过。
- 快捷键 Electron 回归通过,覆盖原 P0 操作、JSON 无效草稿/保存、双向同步、高级过滤、Chord 冲突详情和跨平台预览。
- 渲染脚本检查和全量 ESLint 通过。
- 修复新增绑定时误清除既有默认移除记录的问题,并增加回归验证。
磁盘配置验证结果(2026-09-05)
- 21 项相关单元测试通过,包括磁盘创建、UTF-8/LF、写失败保护、过期保存保护、外部配置重载和延迟加载插件移除规则。
- Electron 快捷键回归通过,覆盖真实文件写入、外部变更通知、错误文件修复和重新加载后的持久化。
- 粘贴撤销回归第一次在原生重做断言失败,未改动代码重跑后通过。
- 渲染脚本检查和全量 ESLint 通过。
- 原始产品方案文件的 600 行限制问题仍保留。
P0 验证记录(2026-09-05)
- 快捷键专项 Electron 测试、11 项相关单元测试、ESLint 和 Windows 目录打包通过。
- 全量单元测试为 195/196;既有 macOS BCompare 路径测试在 Windows 下返回反斜杠,与预期正斜杠不一致。
- 完整 Electron 回归的文件树滚动可见性检查未通过;在修改前的
9ee4507上使用隔离存储与相同等待时限复现相同失败。 - 完整 lint 被原始方案文档的 600 行限制阻断;渲染脚本检查与 ESLint 单独执行均通过。
