VSCode キーバインディングのデバッグ方法

私は普段からMacの操作にEmacsのキーバインディングを利用しています。

せっかくキーバインディングをカスタマイズするなら、エディタはもちろんのこと、ブラウザ操作やメモ帳など、すべてのアプリケーションで同一のキーバインディングを利用できると、コンテキストスイッチがなく快適にアプリケーションの利用に集中できます。

しかし、ある時から(思い当たる節がない)VSCodeだけ意図しないコマンドが実行されてしまいました。
その結果、意図した操作をするために、あろうことか矢印キーを使う羽目になっていました。
どうやらVSCodeのキーバインディングの設定がおかしくなってしまったようです。

今回は、VSCodeのキーバインディングのデバッグ方法を紹介します。

## 前提

VSCode上での表現を確認します。

- キーバインディング(Key Binding)は、キーの入力の組み合わせ
- コマンド(Command)は、キーバインディングによって実行されるもの
- 条件(Condition)は、キーバインディングによってどのコマンドが実行されるか制御されるもの

まとめると、**VSCodeは、キー入力によってキーバインディングを検知すると、条件によってどのコマンドが実行されるかを制御している**ということです。

## ショートカットによってどのコマンドが実行されているか確認する
まずはログからキー入力によってどのコマンドが実行されているかを確認します。

`cmd+shift+p`でコマンドパレットを開き、`Developer: Toggle Keyboard Shortcuts Troubleshooting`を選択し、コンソールを開きます。

このコンソールには、キー入力によってどのコマンドが実行されているかがわかるログが表示されています。

下記は、`ctrl+n` を入力した時のログです。

![スクリーンショット 2021-12-30 13.48.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331354/dc167aef-bc7c-624d-bf3e-1243b50b9119.png)


コメントと改行を付けて、補足します。

```bash
# ctrlのキーダウンのイベントを検知
[2021-12-30 13:34:50.458] [renderer2] [info] [KeybindingService]: / Received  keydown event - modifiers: [ctrl], code: ControlLeft, keyCode: 17, key: Control
# ctrlののキーダウンのイベントを変換
[2021-12-30 13:34:50.460] [renderer2] [info] [KeybindingService]: | Converted keydown event - modifiers: [ctrl], code: ControlLeft, keyCode: 5 ('Ctrl')
# キーイベントは送出できない
[2021-12-30 13:34:50.461] [renderer2] [info] [KeybindingService]: \ Keyboard event cannot be dispatched in keydown phase.

# ctrlとnのキーダウンのイベントを検知
[2021-12-30 13:34:50.593] [renderer2] [info] [KeybindingService]: / Received  keydown event - modifiers: [ctrl], code: KeyN, keyCode: 78, key: n
# ctrlとnのキーダウンのイベンとを変換
[2021-12-30 13:34:50.594] [renderer2] [info] [KeybindingService]: | Converted keydown event - modifiers: [ctrl], code: KeyN, keyCode: 44 ('N')
# ctrlとnのキーダウンのイベンとを解決
[2021-12-30 13:34:50.595] [renderer2] [info] [KeybindingService]: | Resolving ctrl+[KeyN]
# キーバインディングは 条件 editorTextFocus && !suggestWidgetVisible において emacs.cursorDown のコマンドがマッチした 
[2021-12-30 13:34:50.595] [renderer2] [info] [KeybindingService]: \ From 12 keybinding entries, matched emacs.cursorDown, when: editorTextFocus && !suggestWidgetVisible, source: user extension lfs.vscode-emacs-friendly.

# ctrlは他のキーと同時に入力されたため、ctrl単独での入力は無視された
[2021-12-30 13:34:50.811] [renderer2] [info] [KeybindingService]: + Ignoring single modifier ctrl due to it being pressed together with other keys.
```

- 参考: [Visual Studio Code Key Bindings](https://code.visualstudio.com/docs/getstarted/keybindings#_troubleshooting-keybindings)

## 実行したいコマンドにショートカットを割り当てる

コマンドパレットから`Preferences: Open Keyboard Shortcuts` を開き、キーバインディングとコマンド、条件を設定します。

ここで設定した値は、`keybindings.json`に反映され、既存のキーバインディングが上書きされます。

コマンドパレットから`Preferences: Open Keyboard Shortcuts(JSON)`を開き、`keybindings.json`を開くと、キーバインディングの設定変更が記載されます。

ちなみに私の設定ファイルは下記のとおりです。

```bash
# ~/Library/Application Support/Code/User/keybindings.json
// 既定値を上書きするには、このファイル内にキー バインドを挿入します
[
  {
    "key": "ctrl+alt+p",
    "command": "editor.action.moveLinesUpAction",
    "when": "editorTextFocus && !editorReadonly"
  },
  {
    "key": "alt+up",
    "command": "-editor.action.moveLinesUpAction",
    "when": "editorTextFocus && !editorReadonly"
  },
  {
    "key": "ctrl+alt+n",
    "command": "editor.action.moveLinesDownAction",
    "when": "editorTextFocus && !editorReadonly"
  },
  {
    "key": "alt+down",
    "command": "-editor.action.moveLinesDownAction",
    "when": "editorTextFocus && !editorReadonly"
  },
  {
    "key": "ctrl+shift+alt+p",
    "command": "editor.action.copyLinesUpAction",
    "when": "editorTextFocus && !editorReadonly"
  },
  {
    "key": "shift+alt+up",
    "command": "-editor.action.copyLinesUpAction",
    "when": "editorTextFocus && !editorReadonly"
  },
  {
    "key": "ctrl+shift+alt+n",
    "command": "editor.action.copyLinesDownAction",
    "when": "editorTextFocus && !editorReadonly"
  },
  {
    "key": "shift+alt+down",
    "command": "-editor.action.copyLinesDownAction",
    "when": "editorTextFocus && !editorReadonly"
  },
  {
    "key": "ctrl+cmd+p",
    "command": "cursorTop",
    "when": "textInputFocus"
  },
  {
    "key": "cmd+up",
    "command": "-cursorTop",
    "when": "textInputFocus"
  },
  {
    "key": "ctrl+cmd+n",
    "command": "cursorBottom",
    "when": "textInputFocus"
  },
  {
    "key": "cmd+down",
    "command": "-cursorBottom",
    "when": "textInputFocus"
  },
  {
    "key": "ctrl+shift+cmd+enter",
    "command": "workbench.action.terminal.focus"
  },
  {
    "key": "ctrl+shift+n",
    "command": "cursorDownSelect",
    "when": "textInputFocus"
  },
  {
    "key": "shift+down",
    "command": "-cursorDownSelect",
    "when": "textInputFocus"
  },
  {
    "key": "ctrl+shift+p",
    "command": "cursorUpSelect",
    "when": "textInputFocus"
  },
  {
    "key": "shift+up",
    "command": "-cursorUpSelect",
    "when": "textInputFocus"
  },
  {
    "key": "ctrl+shift+f",
    "command": "cursorRightSelect",
    "when": "textInputFocus"
  },
  {
    "key": "shift+right",
    "command": "-cursorRightSelect",
    "when": "textInputFocus"
  },
  {
    "key": "ctrl+shift+b",
    "command": "cursorLeftSelect",
    "when": "textInputFocus"
  },
  {
    "key": "shift+left",
    "command": "-cursorLeftSelect",
    "when": "textInputFocus"
  },
  {
    "key": "ctrl+shift+cmd+j",
    "command": "workbench.action.search.toggleQueryDetails",
    "when": "inSearchEditor || searchViewletFocus"
  },
  {
    "key": "shift+cmd+j",
    "command": "-workbench.action.search.toggleQueryDetails",
    "when": "inSearchEditor || searchViewletFocus"
  },
  {
    "key": "shift+cmd+j",
    "command": "editor.action.revealDefinition",
    "when": "editorHasDefinitionProvider && editorTextFocus && !isInEmbeddedEditor"
  },
  {
    "key": "f12",
    "command": "-editor.action.revealDefinition",
    "when": "editorHasDefinitionProvider && editorTextFocus && !isInEmbeddedEditor"
  },
  {
    "key": "shift+cmd+i",
    "command": "workbench.action.navigateBack"
  },
  {
    "key": "ctrl+-",
    "command": "-workbench.action.navigateBack"
  }
]
```

[Visual Studio Code Key Bindings](https://code.visualstudio.com/docs/getstarted/keybindings#_advanced-customization)

## 補足) ショートカットの設定はSetting Syncでバックアップを

今回紹介したキーバインディングの設定などその他の設定を含め、バックアップをとっておくことをおすすめします。

Settings Syncを利用して、サクッとバックアップしておきましょう。
いざというときに、助かります。

- 参考: [Settings Sync in Visual Studio Code](https://code.visualstudio.com/docs/editor/settings-sync)

## まとめ

Mac上でVSCodeを使いEmacsのキーバインディングを利用する場合、複数のレイヤーでキーバインディングの設定が絡んでおり、ボトルネックを特定するのが難しいと感じました。

具体的には、

- Macのシステム設定のキーボードの設定
- Karabiner Elementsの設定
- VSCodeの設定

がキーバインディングに影響を与えています。

今回は、VSCodeとその他のアプリで挙動が異なる原因がわからなかったため、最終的な出力先であるVSCodeの設定を変更するという力技で対応しました。

PCを利用する以上、買い替えなどによって数年おきに開発環境のセットアップをする必要があるため、次やるときはもう少し効率的に設定できると嬉しいです。