Yank Note 系列 10 - 新增自定义快捷键功能

Yank Note 是我编写的一款面向程序员的笔记应用。这里我将会写下一些关于 Yank Note 的文章

自定义快捷键是很多 Yank Note 用户的诉求,很抱歉这个功能鸽了好几年现在才做上。

这有两个原因,一方面是之前的开发阶段,Yank Note 很多地方不完善,有很多优先级更高的事情要做。另一方面则是做自定义快捷键功能要做得比较好,还是不太容易。比如要考虑各种键盘布局,解决快捷键冲突,一个易于使用的可视化配置界面等等。

不过好在 Yank Note 的核心设计考虑了要自定义快捷键的需求,这次做这个功能还算顺利。

可自定义快捷键的有三个部分:工作台、编辑器、应用

工作台

Yank Note 可以通过使用 ctx.action.registerAction 方法来注册一个操作,这个操作可以附带可响应的默认快捷键,如:

js 复制代码
registerAction({
  name: 'base.find-in-repository', // action 名
  keys: [CtrlCmd, Shift, 'f'], // 默认快捷键
  description: t('command-desc.base_find-in-repository'), // 描述
  forUser: true, // 用户是否可以配置
  handler, // 执行方法
})

通过上面的方法,就给工作台注册了一个"仓库中搜索"的 Action,关联的默认快捷键 是CtrlCmd+Shift+F

那么用户自定义快捷键后,怎样生效呢?

Yank Note 针对 Action 暴露了一个口子,可以拦截 action 的获取操作,进行一些定制性的修改。

js 复制代码
ctx.action.tapAction(action => {
    // 可以在这里动态修改快捷键
    // action.keys = 
})

这样,工作台的自定义快捷键就完成了。

编辑器

再说说自定义编辑器快捷键是怎样实现的。Yank Note 使用的是 Monaco 编辑器,也就是 VSCode 内部用的那个编辑器。因此这些快捷键定义好了,需要丢给 Monaco 来处理,具体可以参考这个 github.com/microsoft/m... Issue,里面讨论了在 Monaco 编辑器中怎样更改快捷键的方法。

不过网上关于 Monaco 或者说 VScode 快捷键相关的资料还是不够丰富,我还是选择了看源码。比起看文档,看源码更能了解整个工作流程的细节。下面的结论基本上都是翻了 VSCode 的源码得到的。

在 VSCode 中,Action 和 Command 和 Keybinding 概念是分开的,注册一个 Action 同时可以注册一个带快捷键的 Command,并有附带 Keybingding 规则。相关代码非常多,因为 VSCode 要考虑的情况也非常复杂。而 Yank Note 这次做的自定义快捷键功能包括一个配置面板和一个应用插件,简化了(不考虑)很多情况,相关代码也就一千多行。

让原有快捷键失效

配置快捷键使用 monaco.editor.addKeybindingRules 这个新引入不久的 API,有两种方法可以让一个已定义的快捷键失效:

js 复制代码
editor.addKeybindingRules([
    {
        // 方式一
        keybinding: KeyCode.F1,
        when: '条件表达式',
        command: null,
    },
    {
        // 方式二
        keybinding: KeyCode.F1,
        when: '条件表达式',
        command: '-editor.action.name',
    },
]);

虽然他们都表现为让 F1 快捷键失效,但具体到内部原理还是不一样的。

方式一的工作原理是新添加一个规则,让后面的规则覆盖原来的规则。这里就是按F1匹配到了规则,但是没有可以运行的命令。

方式二则是从原有的规则表中删去匹配到的规则(包含when表达式)。

如果要做一个移除现有命令快捷键的功能,最好不要用方式一,因为方式一会把规则中的已有的都覆盖掉(比如两个命令使用同一个快捷键的情况),无差别禁用。方式二则可以精确的去掉某个快捷键规则,让原有规则中的其他规则还能生效。

更改快捷键

不过更改一个快捷键光是移除还不够的,还需要添加一条新规则。这个规则需要知道命令的 id、快捷键的编码(VSCode 用一个数字来表示快捷键)以及这个规则原有的 when 表达式。

首先,用 editor.getActions 可以获取所有命令的 ID 接着,用 editor._standaloneKeybindingService._getResolver().lookupPrimaryKeybinding 获取一个命令原始的快捷键绑定情况,获得 when 表达式 最后,把 Yank Note 配置的快捷计算为一个 number 类型的编码,组装成规则后调用editor.addKeybindingRules 接口塞进去

这三步都各有各的坑:

  1. 相关 API Monaco 编辑器也没暴露,只能翻源码+自己从实例里面找出来用用;
  2. 快捷键按键规则是一个数字,但这个数字我翻看 VSCode 源码,内部又没咋用(进入内部就解码了),但接口又只能接受这种参数,只能自己参考内部的解码方法写一个编码方法。
  3. 修饰键 KeyMod 中的 CtrlCmdWinCtrl 也让我困惑了一阵子,好在 issue 有人解释 github.com/microsoft/m...
  4. Monaco 支持 Chord 按键序列,Yank Note 不支持

这里就写这么多吧,希望能后面要自定义 Monaco 编辑器快捷键的伙伴做点参考。

应用

应用快捷键是指在 Electron 中注册的快捷键。这里只需要考虑将配置的快捷键转换为 Electron 接受的格式即可,可以参考 www.electronjs.org/docs/latest... 官方文档

更多

上面做了这么多工作,还有一件事没仔细考虑,那就是适应不同的键盘布局。这个问题事实上不那么容易处理。目前 Yank Note 先放过这一部分了。这里有几篇文章写得很好,推荐阅读

以上就是 Yank Note 在做自定义快捷键功能时候相关的一些我觉得值得分享的东西,希望大家能喜欢这个功能。

本文由「Yank Note - 一款强大可扩展的 Markdown 编辑器,为生产力而生」撰写

相关推荐
清沫3 天前
键盘效率提升指南(VSCode+Vim+SurfingKeys)
前端·vim·visual studio code
OLong4 天前
2025年最强React插件,支持大量快捷操作
前端·react.js·visual studio code
一眼万年044 天前
每天都在使用的VS Code Copilot Chat 开源啦!
aigc·ai编程·visual studio code
字节逆旅4 天前
如何将markdown生成pdf
markdown
修仙的人14 天前
开源 | 我将用最优雅的方式在 Vue 中渲染 AI 应用返回的 Markdown 数据
前端·vue.js·markdown
pe7er14 天前
vscode插件Hybrid Mode混合模式不兼容导致vue3项目在vscode爆红、类型推导失效的解决方案
vue.js·visual studio code
黑塞12315 天前
Vscode 编写Markdown支持 plantuml书写
ide·vscode·编辑器·markdown·plantuml
驳是16 天前
入坑 Docusaurus,看这一篇就够了
react.js·前端框架·markdown
是紫焅呢17 天前
I排序算法.go
开发语言·后端·算法·golang·排序算法·学习方法·visual studio code
是紫焅呢17 天前
E结构体基础.go
开发语言·后端·golang·学习方法·visual studio code