Skip to content

按键映射

VSCode 允许直接从键盘执行大多数任务。

键盘快捷方式编辑器

键盘快捷键方式: 文件|首选项|设置|键盘快捷方式

他提供了交互式的方式来帮助用户修改快捷键,最终设置的快捷键会被保存到 keybindings.json 中。

keybindings.json

尽管方便但是要想设置比较复杂的还是直接编辑 keybindings.json 文件方便。

一个完整的键位映射由以下几部分组成:

  • key: 用于描述哪些键被按下
  • command: 要自信的命令
  • when: 包含布尔表达式来定义执行的条件
JSON
// Keybindings that are active when the focus is in the editor
{ "key": "home",            "command": "cursorHome",                  "when": "editorTextFocus" },
{ "key": "shift+home",      "command": "cursorHomeSelect",            "when": "editorTextFocus" },

// Keybindings that are complementary
{ "key": "f5",              "command": "workbench.action.debug.continue", "when": "inDebugMode" },
{ "key": "f5",              "command": "workbench.action.debug.start",    "when": "!inDebugMode" },

// Global keybindings
{ "key": "ctrl+f",          "command": "actions.find" },
{ "key": "alt+left",        "command": "workbench.action.navigateBack" },
{ "key": "alt+right",       "command": "workbench.action.navigateForward" },

// Global keybindings using chords (two separate keypress actions)
{ "key": "ctrl+k enter",    "command": "workbench.action.keepEditor" },
{ "key": "ctrl+k ctrl+w",   "command": "workbench.action.closeAllEditors" },

key

key 定义被按下的按键,他通常由前缀(modifier)和键(key)组成,允许出现 Ctrl+K Ctrl+C 这样的类 Emacs 的组合键。其中可用的修饰键包括:

平台 修饰键
MacOS Ctrl+ Shift+ Alt+ Cmd+
Windows Ctrl+ Shift+ Alt+ Win+
Linux Ctrl+ Shift+ Alt+ Meta+

接受的按键包括:

  • f1 ~ f19a-z0-9
  • `,-=[]\;,'./``
  • left up right down pageup pagedown end home
  • tab enter escape space backspace delete
  • pausebreak capslock insert

command

命令中包含要执行的命令字符串,可以在通过右键复制命令 ID 来获取命令字符串:

copy command

对于需要参数的命令,可以使用 args 来指定:

JSON
// type 将接受 {"text": "Hello World"} 作为参数
{
  "key": "enter",
  "command": "type",
  "args": { "text": "Hello World" },
  "when": "editorTextFocus"
}

VSCode 提供了一个比较特殊的 runCommands 来运行多条命令,其他命令以参数形式提供:

JSON
{
  "key": "ctrl+alt+c",
  "command": "runCommands",
  "args": {
    "commands": [
      "editor.action.copyLinesDownAction",
      "cursorUp",
      "editor.action.addCommentLine",
      "cursorDown"
    ]
  }
}

when

when 子句来定义应用快捷键的上下文。他会根据后面的布尔表达式的结果来确定是否应用快捷键对应的命令。

布尔表达式可以由运算符参与运算:

运算符 说明 示例
== 相等 "editorLangId == typescript"
不等 "resourceExtname != .js"
> ≥ < ≤ 比较 "gitOpenRepositoryCount >= 1"
\|\| "isLinux \|\| isWindows"
&& "textInputFocus && !editorReadonly"
! "!editorReadonly"
=~ 正则匹配 "resourceScheme =~ /^untitled$ \| ^file$/"
in/not in 成员检测 "resourceFilename in supportedFolders"

键盘映射扩展 Vim

扩展中提供了对其他键盘映射的支持,其中比较重要的就是 vim 模拟。VSCode 中可以通过安装vim 插件来引入 vim-mode,不过他与真正的 vim 还有些区别而且配置与 vim 也大相径庭,要想好用需要进行一些比较复杂的配置。

按键映射

在 VSCode 中模拟 vim 最重要也是最麻烦的就是按键映射。由于存在 vim 插件和 vscode 内置按键映射体系所以配置起来会比较麻烦。

模拟 vim 按键映射

vim 插件提同样提供了四种类型的按键映射方法:

  • vim.insertModeKeyBindings: Insert 模式下映射
  • vim.normalModeKeyBindings: Normal 模式下映射
  • vim.visualModeKeyBindings: Visual 模式下映射
  • vim.operatorPendingModeKeyBindings: 操作映射

他们还有一个非递归版本:

  • vim.insertModeKeyBindingsNonRecursive: Insert 模式下映射(非递归)
  • vim.normalModeKeyBindingsNonRecursive: Normal 模式下映射(非递归)
  • vim.visualModeKeyBindingsNonRecursive: Visual 模式下映射(非递归)
  • vim.operatorPendingModeKeyBindingsNonRecursive: 操作映射(非递归)

注意他们被定义在 settings.json 中,每一个按键绑定可以包含:

  • before: 数组,其中包含触发按键
  • after: 数组,其中包含映射按键
  • commands: 数组,可以包含的 vim 命令、vscode 中的命令
  • silent: 布尔值,表示是否静默
JSON
{
  "vim.insertModeKeyBindings": [
    {
      "before": ["j", "j"],
      "after": ["<Esc>"]
    }
  ],
  "vim.normalModeKeyBindingsNonRecursive": [
    {
      "before": ["<leader>", "d"],
      "after": ["d", "d"]
    },
    {
      "before": ["<C-n>"],
      "commands": [":nohl"]
    },
    {
      "before": ["K"],
      "commands": ["lineBreakInsert"],
      "silent": true
    }
  ],
  "vim.leader": "<space>",
  "vim.handleKeys": {
    "<C-a>": false,
    "<C-f>": false
  }
}

使用 vscode 内置的映射

插件建议首先应当考虑使用模拟 vim 按键映射的方式来创建映射,不过有时候直接使用 vscode 内置的 keybindings.json 来编辑映射是非常方便的,并且 vim 映射并不支持 Alt + keyCtrl+Shift+key 这样的组合键。它通常用于将 VSCode 中的快捷键映射到 vim 模式下:

JSON
{
  "key": "ctrl+shift+y",
  "command": "vim.remap",
  "when": "inputFocus && vim.mode == 'Normal'",
  "args": {
    "after": ["y", "y"]
  }
}

上面就是一个典型的映射方式,其中比较特殊的就是使用 when 指定映射规则,inputFocus 表示光标激活,vim.mode == 'Normal' 即处于 Normal 模式,目前支持的模式包括:

  • Normal
  • Insert
  • Visual
  • VisualBlock
  • VisualLine
  • SearchInProgressMode
  • CommandlineInProgress
  • Replace
  • EasyMotionMode
  • EasyMotionInputMode
  • SurroundInputMode
  • OperatorPendingMode
  • Disabled

vim 设置

vim 插件提供了几个 vim 设置来规定一些行为:

setting desc default
vim.autoindent 创建新行时继承缩进 true
vim.hlsearch 突出显示搜索匹配的的文本 false
vim.ignorecase 搜索忽略大小写 true
vim.incsearch 输入搜索时显示下一个匹配项 true
vim.leader 定义 leader 的按键 '\\'
vim.showmodename 在状态栏显示 mode true
vim.smartcase 如果搜索字符串时包含大写,则覆盖忽略大小写设置 true
vim.textwidth 使用 gq 自动换行的宽度 80
vim.timeout 重新映射命令的超时时间 1000
vim.whichwrap 当光标位于行中第一个/最后一个字符上时允许移动光标的上一行/下一行 'b,s'

插件

vim插件重写了一些著名的 vim 插件。

vim-easymotion

用于快速光标移动。

用户配置

JSON
{
  "vim.leader": " ", // Leader 设置为空格
  "vim.easymotion": true, // 开启 easymotion 插件 <leader>jw{char} <leader>jl
  "vim.sneak": true, // 开启 sneak 插件 s{char}{char}
  "vim.sneakUseIgnorecaseAndSmartcase": true,
  "vim.useCtrlKeys": false, // 禁用 vim 的 ctrl 按键,允许 Ctrl+s 之类键位可用
  "vim.foldfix": true, // 允许 jk 跳过折叠
  "vim.useSystemClipboard": true, // 使用系统剪切板
  // Normal 下按键绑定
  "vim.normalModeKeyBindingsNonRecursive": [
    {
      "before": [":"],
      "commands": ["workbench.action.showCommands"],
      "silent": true
    },
    // ============== 窗口管理 ============================
    // 聚焦到 1-5 编辑器组
    {
      "before": ["<leader>", "1"],
      "commands": ["workbench.action.focusFirstEditorGroup"],
      "silent": true
    },
    {
      "before": ["<leader>", "2"],
      "commands": ["workbench.action.focusSecondEditorGroup"],
      "silent": true
    },
    {
      "before": ["<leader>", "3"],
      "commands": ["workbench.action.focusThirdEditorGroup"],
      "silent": true
    },
    {
      "before": ["<leader>", "4"],
      "commands": ["workbench.action.focusFourthEditorGroup"],
      "silent": true
    },
    {
      "before": ["<leader>", "5"],
      "commands": ["workbench.action.focusFifthEditorGroup"],
      "silent": true
    },
    // 关闭编辑器组以及其中的编辑组
    {
      "before": ["<leader>", "w", "d"],
      "commands": ["workbench.action.closeEditorsAndGroup"],
      "silent": true
    },
    // 最大化组
    {
      "before": ["<leader>", "w", "c"],
      "commands": ["workbench.action.maximizeEditor"],
      "silent": true
    },
    // 关闭其他编辑器
    {
      "before": ["<leader>", "w", "o"],
      "commands": ["workbench.action.closeEditorsInOtherGroups"],
      "silent": true
    },
    // 聚焦下上右左编辑器组
    {
      "before": ["<leader>", "w", "j"],
      "commands": ["workbench.action.focusBelowGroup"],
      "silent": true
    },
    {
      "before": ["<leader>", "w", "k"],
      "commands": ["workbench.action.focusAboveGroup"],
      "silent": true
    },
    {
      "before": ["<leader>", "w", "h"],
      "commands": ["workbench.action.focusLeftGroup"],
      "silent": true
    },
    {
      "before": ["<leader>", "w", "l"],
      "commands": ["workbench.action.focusRightGroup"],
      "silent": true
    },
    // 垂直水平分隔编辑器
    {
      "before": ["<leader>", "w", "v"],
      "commands": ["workbench.action.splitEditorRight"],
      "silent": true
    },
    {
      "before": ["<leader>", "w", "s"],
      "commands": ["workbench.action.splitEditorDown"],
      "silent": true
    },
    //================== Buffer ===========================
    // vscode 以编辑器呈现 Buffer
    // 所有组中关闭编辑器,默认关闭 buffer
    {
      "before": ["<leader>", "b", "d"],
      "commands": ["workbench.action.closeEditorInAllGroups"],
      "silent": true
    },
    // 打开组中下一个编辑器
    {
      "before": ["<leader>", "b", "l"],
      "commands": ["workbench.action.openNextRecentlyUsedEditorInGroup"],
      "silent": true
    },
    // 打开组中上一个编辑器
    {
      "before": ["<leader>", "b", "h"],
      "commands": ["workbench.action.openPreviousRecentlyUsedEditorInGroup"],
      "silent": true
    },
    // 切换只读,选项卡处加锁
    {
      "before": ["<leader>", "b", "r"],
      "commands": [
        "workbench.action.files.toggleActiveEditorReadonlyInSession"
      ],
      "silent": true
    },
    // ============== File ===========================
    // 保存文件
    {
      "before": ["<leader>", "b", "w"],
      "commands": ["workbench.action.files.save"],
      "silent": true
    },
    {
      "before": ["<leader>", "e"],
      "commands": ["workbench.files.action.focusFilesExplorer"],
      "silent": true
    },
    // ============== easymotion =======================
    {
      "before": ["<leader>", "j", "w"],
      "after": ["<leader>", "<leader>", "s"]
    },
    {
      "before": ["<leader>", "j", "l"],
      "after": ["<leader>", "<leader>", "<leader>", "b", "d", "j", "k"]
    }
  ]
}

参考