Monaco Editor 中的 Keybinding 机制( 二 )

会先根据传入的 _keybinding 创建 keybinding 实例,然后连同 command、when 等其他信息存入_dynamicKeybindings 数组中,同时会注册对应的 command,当后面触发 keybinding 时便执行对应的 command 。返回的 toDispose 实例则用于取消对应的 keybinding 和 command 。
回到上面代码中创建 keybinding 实例的地方,createKeybinding 方法会根据传入的 _keybinding 数字和 OS 类型得到实例,大致结构如下(已省略部分属性):
{parts: [{ctrlKey: boolean,shiftKey: boolean,altKey: boolean,metaKey: boolean,keyCode: KeyCode,}],}那么,是怎么通过一个 number 得到所有按键信息的呢?往下看↓↓↓
4. key的转换先看看一开始传入的 keybinding 是什么:
const action = {id: 'test',label: 'test',precondition: 'isChrome == true',keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyL],run: () => {window.alert('chrome: cmd + k');},};传入的 keybinding 就是上面代码中的 keybindings 数组中的元素,monaco.KeyMod.CtrlCmd = 2048,monaco.KeyCode.KeyL = 42 , 对应的数字是 monaco-editor 中定义的枚举值 , 与真实的 keyCode 存在对应关系 。所以注册时传入的 keybinding 参数为: 2048 | 42 = 2090
先简单了解下 JS 中的位运算(操作的是32位带符号的二进制整数 , 下面例子中只用8位简单表示):
按位与(AND)&
对应的位都为1则返回1 , 否则返回0
例如:
00001010// 10
00000110// 6
------
00000010// 2
按位或(OR)|
对应的位 , 只要有一个为1则返回1,否则返回0
00001010// 10
00000110// 6
-------
00001110// 14
左移(Left shift)<<
将二进制数每一位向左移动指定位数,左侧移出的位舍弃,右侧补0
00001010// 10
【Monaco Editor 中的 Keybinding 机制】-------// 10 << 2
00101000// 40
右移 >>
将二进制数每位向右移动指定位数,右侧移出的位舍弃,左侧用原来最左边的数补齐
00001010// 10
-------// 10 >> 2
00000010// 2
无符号右移 >>>
将二进制数每位向右移动指定位数,右侧移出的位舍弃 , 左侧补0
00001010// 10
-------// 10 >> 2
00000010// 2
接下来看下是怎么根据一个数字,创建出对应的 keybinding 实例:
export function createKeybinding(keybinding: number, OS: OperatingSystem): Keybinding | null {if (keybinding === 0) {return null;}const firstPart = (keybinding & 0x0000FFFF) >>> 0;// 处理分两步的keybinding,例如:shift shift,若无第二部分 , 则chordPart = 0const chordPart = (keybinding & 0xFFFF0000) >>> 16;if (chordPart !== 0) {return new ChordKeybinding([createSimpleKeybinding(firstPart, OS),createSimpleKeybinding(chordPart, OS)]);}return new ChordKeybinding([createSimpleKeybinding(firstPart, OS)]);}看下 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实例,该实例包含了上面的这些按键信息以及一些操作方法 。

推荐阅读