至此,已经完成了 keybinding 的注册 , 将 keybinding 实例及相关信息存入了 StandaloneKeybindingService 实例的 _dynamicKeybindings 数组中,对应的 command 也注册到了 CommandsRegistry 中 。
5.执行当用户在键盘上按下快捷键时,便会触发 keybinding 对应 command 的执行 , 执行过程如下:

文章插图
回到 StandaloneKeybindingServices 初始化的时候,在 domNode 上绑定了 keydown 事件监听函数:
(e: KeyboardEvent) => {const keyEvent = new StandardKeyboardEvent(e);const shouldPreventDefault = this._dispatch(keyEvent, keyEvent.target);if (shouldPreventDefault) {keyEvent.preventDefault();keyEvent.stopPropagation();}};
当 keydown 事件触发后,便会执行这个监听函数,首先会实例化一个 StandardKeyboardEvent 实例,该实例包含了一些按键信息和方法 , 大致结构如下(已省略部分属性):{target: HTMLElement,ctrlKey: boolean,shiftKey: boolean,altKey: boolean,metaKey: boolean,keyCode: KeyCode,}
其中 keyCode 是经过处理后得到的,由原始键盘事件的 keyCode 转换为 monoco-editor 中的 keyCode,转换过程主要就是兼容一些不同的浏览器,并根据映射关系得到最终的 keyCode 。准换方法如下:function extractKeyCode(e: KeyboardEvent): KeyCode {if (e.charCode) {// "keypress" events mostlylet char = String.fromCharCode(e.charCode).toUpperCase();return KeyCodeUtils.fromString(char);}const keyCode = e.keyCode;// browser quirksif (keyCode === 3) {return KeyCode.PauseBreak;} else if (browser.isFirefox) {if (keyCode === 59) {return KeyCode.Semicolon;} else if (keyCode === 107) {return KeyCode.Equal;} else if (keyCode === 109) {return KeyCode.Minus;} else if (platform.isMacintosh && keyCode === 224) {return KeyCode.Meta;}} else if (browser.isWebKit) {if (keyCode === 91) {return KeyCode.Meta;} else if (platform.isMacintosh && keyCode === 93) {// the two meta keys in the Mac have different key codes (91 and 93)return KeyCode.Meta;} else if (!platform.isMacintosh && keyCode === 92) {return KeyCode.Meta;}}// cross browser keycodes:return EVENT_KEY_CODE_MAP[keyCode] || KeyCode.Unknown;}
得到了 keyEvent 实例对象后,便通过 this._dispatch(keyEvent, keyEvent.target) 执行 。protected _dispatch(e: IKeyboardEvent,target: IContextKeyServiceTarget): boolean {return this._doDispatch(this.resolveKeyboardEvent(e),target,/*isSingleModiferChord*/ false);}
直接调用了 this._doDispatch 方法,通过 this.resolveKeyboardEvent(e) 方法处理传入的 keyEvent,得到一个包含了许多 keybinding 操作方法的实例 。接下来主要看下 _doDispatch 方法主要干了啥(以下仅展示了部分代码):
private _doDispatch(keybinding: ResolvedKeybinding,target: IContextKeyServiceTarget,isSingleModiferChord = false): boolean {const resolveResult = this._getResolver().resolve(contextValue,currentChord,firstPart);if (resolveResult && resolveResult.commandId) {if (typeof resolveResult.commandArgs === 'undefined') {this._commandService.executeCommand(resolveResult.commandId).then(undefined, (err) =>this._notificationService.warn(err));} else {this._commandService.executeCommand(resolveResult.commandId,resolveResult.commandArgs).then(undefined, (err) =>this._notificationService.warn(err));}}}
主要是找到 keybinding 对应的 command 并执行,_getResolver 方法会拿到已注册的 keybinding,然后通过 resolve 方法找到对应的 keybinding 及 command 信息 。而执行 command 则会从 CommandsRegistry 中找到对应已注册的 command,然后执行 command 的 handler 函数(即keybinding 的回调函数) 。6.卸载先看看一开始的例子中的代码:
const onClick = () => {actionDispose?.dispose();window.alert('已卸载');};
卸载过程如下:
文章插图
回到刚开始注册时:setActionDispose(editorIns.addAction(action)),addAction 方法会返回一个 disposable 对象 , setActionDispose 将该对象保存了起来 。通过调用该对象的 dispose 方法:actionDispose.dispose(),便可卸载该 action,对应的 command 和 keybinding 便都会被卸载 。
四、结语对 Monaco Editor 的 Keybinding 机制进行简单描述,就是通过监听用户的键盘输入,找到对应注册的 keybinding 和 command , 然后执行对应的回调函数 。但仔细探究的话,每个过程都有很多处理逻辑,本文也只是对其做了一个大体的介绍 , 实际上还有许多相关的细节没有讲到,感兴趣的同学可以探索探索 。
推荐阅读
- 堪称植物界中的吸甲醛之王,吊兰是否真的能吸收甲醛?
- 历史中的海兰珠究竟有多受宠 海兰珠生平简介
- 恋爱中的人梦见自己在挂水
- 创造与魔法中的玉米宠物饲料包怎么做
- 恋爱中的人梦见自己在找工作
- 恋爱中的人梦见自己被人咬
- 恋爱中的人梦见自己吓哭了
- 恋爱中的人梦见自己跳绳
- 在小红书上看中的穿搭怎么买 小红书上的衣服怎么买
- 相在名字当中的寓意 复相的寓意