Monaco Editor 中的 Keybinding 机制( 三 )

看下 createSimpleKeybinding 方法做了什么
const enum BinaryKeybindingsMask {CtrlCmd = (1 << 11) >>> 0, // 2048Shift = (1 << 10) >>> 0,// 1024Alt = (1 << 9) >>> 0,// 512WinCtrl = (1 << 8) >>> 0,// 256KeyCode = 0x000000FF// 255}export function createSimpleKeybinding(keybinding: number, OS: OperatingSystem): SimpleKeybinding {const ctrlCmd = (keybinding & BinaryKeybindingsMask.CtrlCmd ? true : false);const winCtrl = (keybinding & BinaryKeybindingsMask.WinCtrl ? true : false);const ctrlKey = (OS === OperatingSystem.Macintosh ? winCtrl : ctrlCmd);const shiftKey = (keybinding & BinaryKeybindingsMask.Shift ? true : false);const altKey = (keybinding & BinaryKeybindingsMask.Alt ? true : false);const metaKey = (OS === OperatingSystem.Macintosh ? ctrlCmd : winCtrl);const keyCode = (keybinding & BinaryKeybindingsMask.KeyCode);return new SimpleKeybinding(ctrlKey, shiftKey, altKey, metaKey, keyCode);}拿上面的例子:keybinding = monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyL,即 keybinding = 2048 | 42 = 2090,然后看上面代码中的:
const ctrlCmd = (keybinding & BinaryKeybindingsMask.CtrlCmd ? true : false);
运算如下:
100000101010 // 2090 -> keybinding
100000000000 // 2048 -> CtrlCmd
----------- // &
100000000000 // 2048 -> CtrlCmd
再看keyCode的运算:
const keyCode = (keybinding & BinaryKeybindingsMask.KeyCode)
100000101010 // 2090 -> keybinding
000011111111 // 255 -> KeyCode
----------- // &
000000101010 // 42 -> KeyL
于是便得到了 ctrlKey,shiftKey,altKey,metaKey,keyCode 这些值,接下来便由这些值生成SimpleKeybinding实例,该实例包含了上面的这些按键信息以及一些操作方法 。
至此,已经完成了 keybinding 的注册,将 keybinding 实例及相关信息存入了 StandaloneKeybindingService 实例的 _dynamicKeybindings 数组中,对应的 command 也注册到了 CommandsRegistry 中 。
5.执行当用户在键盘上按下快捷键时,便会触发 keybinding 对应 command 的执行,执行过程如下:

Monaco Editor 中的 Keybinding 机制

文章插图
回到 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;}

经验总结扩展阅读