WezTerm Copy Mode 键位表深度解析:从默认键表到完全自定义的纯键盘选择方案
2026/9/13 12:36:03 网站建设 项目流程

WezTerm Copy Mode 键位表深度解析:从默认键表到完全自定义的纯键盘选择方案

【免费下载链接】weztermA GPU-accelerated cross-platform terminal emulator and multiplexer written by @wez and implemented in Rust项目地址: https://gitcode.com/GitHub_Trending/we/wezterm

Copy Mode(复制模式)是 WezTerm 提供的一种基于键盘的文本选择模式,它让你无需触碰鼠标即可在滚动缓冲区(scrollback)中定位光标、以单元格/行/矩形方式框选文本并复制。本文以仓库中 docs/examples/default-copy-mode-key-table.markdown 提供的默认copy_mode键表为骨架,逐键位拆解其动作语义,并借助源码中的CopyModeAssignment枚举与键表加载机制,说明如何通过key_tables.copy_mode深度定制这套 Vim 风格的按键体系。读完本文,你将掌握 Copy Mode 的完整默认按键、每种动作的精确行为,以及用 Lua 配置自定义/扩展现有键表的方法。

Copy Mode 是什么

Copy Mode 允许你仅使用键盘完成区域选择与复制,其定位与 WezTerm 的 Quick Select 模式不同:Quick Select 面向“快速匹配常见模式”,而 Copy Mode 面向“基于键盘控制描述任意选择区域”。被高亮/选中文本的颜色可通过 外观配置中的自定义颜色 调整。

  • 通过ActivateCopyMode键分配进入 Copy Mode,默认绑定为CTRL-SHIFT-X(参见 config/src/keyassignment.rs 中ActivateCopyMode枚举项)。
  • 进入后,标签页标题会添加"Copy Mode"前缀,标签行为改变:键盘输入改为控制光标,并在需要时滚动视口,风格接近 Vim 编辑器。
  • 将光标移动到选择区域起点,按v进入选择模式(默认关闭),再移动到终点,按CTRL-SHIFT-CCopy)即可复制到剪贴板。

完整默认 copy_mode 键表逐键解读

下述 Lua 代码即仓库中 docs/examples/default-copy-mode-key-table.markdown 的完整内容,它定义了key_tables.copy_mode下全部默认键位:

local wezterm = require 'wezterm' local act = wezterm.action return { key_tables = { copy_mode = { { key = 'Tab', mods = 'NONE', action = act.CopyMode 'MoveForwardWord' }, { key = 'Tab', mods = 'SHIFT', action = act.CopyMode 'MoveBackwardWord', }, { key = 'Enter', mods = 'NONE', action = act.CopyMode 'MoveToStartOfNextLine', }, { key = 'Escape', mods = 'NONE', action = act.Multiple { { CopyMode = 'ScrollToBottom' }, { CopyMode = 'Close' }, }, }, { key = 'Space', mods = 'NONE', action = act.CopyMode { SetSelectionMode = 'Cell' }, }, { key = '$', mods = 'NONE', action = act.CopyMode 'MoveToEndOfLineContent', }, { key = '$', mods = 'SHIFT', action = act.CopyMode 'MoveToEndOfLineContent', }, { key = ',', mods = 'NONE', action = act.CopyMode 'JumpReverse' }, { key = '0', mods = 'NONE', action = act.CopyMode 'MoveToStartOfLine' }, { key = ';', mods = 'NONE', action = act.CopyMode 'JumpAgain' }, { key = 'F', mods = 'NONE', action = act.CopyMode { JumpBackward = { prev_char = false } }, }, { key = 'F', mods = 'SHIFT', action = act.CopyMode { JumpBackward = { prev_char = false } }, }, { key = 'G', mods = 'NONE', action = act.CopyMode 'MoveToScrollbackBottom', }, { key = 'G', mods = 'SHIFT', action = act.CopyMode 'MoveToScrollbackBottom', }, { key = 'H', mods = 'NONE', action = act.CopyMode 'MoveToViewportTop' }, { key = 'H', mods = 'SHIFT', action = act.CopyMode 'MoveToViewportTop', }, { key = 'L', mods = 'NONE', action = act.CopyMode 'MoveToViewportBottom', }, { key = 'L', mods = 'SHIFT', action = act.CopyMode 'MoveToViewportBottom', }, { key = 'M', mods = 'NONE', action = act.CopyMode 'MoveToViewportMiddle', }, { key = 'M', mods = 'SHIFT', action = act.CopyMode 'MoveToViewportMiddle', }, { key = 'O', mods = 'NONE', action = act.CopyMode 'MoveToSelectionOtherEndHoriz', }, { key = 'O', mods = 'SHIFT', action = act.CopyMode 'MoveToSelectionOtherEndHoriz', }, { key = 'T', mods = 'NONE', action = act.CopyMode { JumpBackward = { prev_char = true } }, }, { key = 'T', mods = 'SHIFT', action = act.CopyMode { JumpBackward = { prev_char = true } }, }, { key = 'V', mods = 'NONE', action = act.CopyMode { SetSelectionMode = 'Line' }, }, { key = 'V', mods = 'SHIFT', action = act.CopyMode { SetSelectionMode = 'Line' }, }, { key = '^', mods = 'NONE', action = act.CopyMode 'MoveToStartOfLineContent', }, { key = '^', mods = 'SHIFT', action = act.CopyMode 'MoveToStartOfLineContent', }, { key = 'b', mods = 'NONE', action = act.CopyMode 'MoveBackwardWord' }, { key = 'b', mods = 'ALT', action = act.CopyMode 'MoveBackwardWord' }, { key = 'b', mods = 'CTRL', action = act.CopyMode 'PageUp' }, { key = 'c', mods = 'CTRL', action = act.Multiple { { CopyMode = 'ScrollToBottom' }, { CopyMode = 'Close' }, }, }, { key = 'd', mods = 'CTRL', action = act.CopyMode { MoveByPage = 0.5 }, }, { key = 'e', mods = 'NONE', action = act.CopyMode 'MoveForwardWordEnd', }, { key = 'f', mods = 'NONE', action = act.CopyMode { JumpForward = { prev_char = false } }, }, { key = 'f', mods = 'ALT', action = act.CopyMode 'MoveForwardWord' }, { key = 'f', mods = 'CTRL', action = act.CopyMode 'PageDown' }, { key = 'g', mods = 'NONE', action = act.CopyMode 'MoveToScrollbackTop', }, { key = 'g', mods = 'CTRL', action = act.Multiple { { CopyMode = 'ScrollToBottom' }, { CopyMode = 'Close' }, }, }, { key = 'h', mods = 'NONE', action = act.CopyMode 'MoveLeft' }, { key = 'j', mods = 'NONE', action = act.CopyMode 'MoveDown' }, { key = 'k', mods = 'NONE', action = act.CopyMode 'MoveUp' }, { key = 'l', mods = 'NONE', action = act.CopyMode 'MoveRight' }, { key = 'm', mods = 'ALT', action = act.CopyMode 'MoveToStartOfLineContent', }, { key = 'o', mods = 'NONE', action = act.CopyMode 'MoveToSelectionOtherEnd', }, { key = 'q', mods = 'NONE', action = act.Multiple { { CopyMode = 'ScrollToBottom' }, { CopyMode = 'Close' }, }, }, { key = 't', mods = 'NONE', action = act.CopyMode { JumpForward = { prev_char = true } }, }, { key = 'u', mods = 'CTRL', action = act.CopyMode { MoveByPage = -0.5 }, }, { key = 'v', mods = 'NONE', action = act.CopyMode { SetSelectionMode = 'Cell' }, }, { key = 'v', mods = 'CTRL', action = act.CopyMode { SetSelectionMode = 'Block' }, }, { key = 'w', mods = 'NONE', action = act.CopyMode 'MoveForwardWord' }, { key = 'y', mods = 'NONE', action = act.Multiple { { CopyTo = 'ClipboardAndPrimarySelection' }, { CopyMode = 'ScrollToBottom' }, { CopyMode = 'Close' }, }, }, { key = 'PageUp', mods = 'NONE', action = act.CopyMode 'PageUp' }, { key = 'PageDown', mods = 'NONE', action = act.CopyMode 'PageDown' }, { key = 'End', mods = 'NONE', action = act.CopyMode 'MoveToEndOfLineContent', }, { key = 'Home', mods = 'NONE', action = act.CopyMode 'MoveToStartOfLine', }, { key = 'LeftArrow', mods = 'NONE', action = act.CopyMode 'MoveLeft' }, { key = 'LeftArrow', mods = 'ALT', action = act.CopyMode 'MoveBackwardWord', }, { key = 'RightArrow', mods = 'NONE', action = act.CopyMode 'MoveRight', }, { key = 'RightArrow', mods = 'ALT', action = act.CopyMode 'MoveForwardWord', }, { key = 'UpArrow', mods = 'NONE', action = act.CopyMode 'MoveUp' }, { key = 'DownArrow', mods = 'NONE', action = act.CopyMode 'MoveDown' }, }, }, }

上述配置可直接放入~/.wezterm.lua(或WEZTERM_CONFIG_FILE指向的配置)作为return表返回。需要注意:一旦你定义了copy_mode键表,它将整体替换默认键表(详见下文“自定义方式”),所以完整复制并在此基础上修改是最稳妥的做法。

CopyMode 动作全集:每个动作的真实语义

上面键表中出现的每个动作字符串/表,都对应 config/src/keyassignment.rs 中CopyModeAssignment枚举的一个变体。该枚举即 Copy Mode 支持的全部动作集合,可归纳为以下几类:

光标移动类

动作行为默认键位
MoveLeft/MoveRight/MoveUp/MoveDown向对应方向移动一个单元格/一行h/l/k/j,方向键
MoveForwardWord向前移动一个单词wTabAlt-fAlt-RightArrow
MoveBackwardWord向后移动一个单词bShift-TabAlt-bAlt-LeftArrow
MoveForwardWordEnd移动到下一个单词的末尾e
MoveToStartOfLine移动到本行行首(第 0 列)0Home
MoveToStartOfLineContent移动到本行首个非空白字符处^Alt-m
MoveToEndOfLineContent移动到本行内容末尾$End
MoveToStartOfNextLine移动到下一行行首Enter
MoveByPage(f)按比例滚动,正数向下、负数向上Ctrl-d(0.5)、Ctrl-u(-0.5)
PageUp/PageDown上/下翻一整屏PageUp/PageDownCtrl-b/Ctrl-f

视口与滚动缓冲区定位类

动作行为默认键位
MoveToScrollbackTop跳到滚动缓冲区顶部g
MoveToScrollbackBottom跳到滚动缓冲区底部Shift-G
MoveToViewportTop跳到视口顶部行Shift-H
MoveToViewportMiddle跳到视口中间行Shift-M
MoveToViewportBottom跳到视口底部行Shift-L

选择模式类

动作行为默认键位
SetSelectionMode(Cell)开启单元格(字符级)选择模式vSpace
SetSelectionMode(Line)开启整行选择模式Shift-V
SetSelectionMode(Block)开启矩形块选择模式Ctrl-v
SetSelectionMode(None)关闭选择模式(取消框选)
ClearSelectionMode清除选择模式状态

三种选择模式对应 config/src/keyassignment.rs 中的SelectionMode语义:Cell适合复制任意连续片段,Line适合整行提取,Block(矩形选择)适合对齐的表格/日志列数据;其中矩形选择自20220624-141144-bd1b7c5d版本起提供。

选择端点跳转类

动作行为默认键位
MoveToSelectionOtherEnd将光标移动到选择的另一端(锚点)o
MoveToSelectionOtherEndHoriz仅在水平方向移动选择另一端(矩形选择时尤为有用)Shift-O
JumpForward{prev_char}向前跳转到指定字符(类似 Vimf/t);prev_char=true表示落在字符前f/t
JumpBackward{prev_char}向后跳转到指定字符(类似 VimF/TF/T
JumpAgain重复上一次字符跳转;
JumpReverse反方向重复上一次字符跳转,

收尾与组合动作

动作行为默认键位
CopyMode:Close退出 Copy Mode
CopyMode:ScrollToBottom先滚回滚动缓冲区底部作为退出时的“复位”步骤
CopyTo('ClipboardAndPrimarySelection')将当前选择同时复制到剪贴板与主选择区y

值得注意的是默认键表中大量使用了act.Multiple { ... }组合:例如y被定义为先CopyToScrollToBottom+Close,即“复制并退出且滚回底部”;EscapeCtrl-cCtrl-gq也都通过Multiple完成“复位视口 + 退出”。这与 docs/copymode.md 中“y复制并退出、Esc/Ctrl-c/Ctrl-g/q退出”的说明完全对应。

Copy Mode 键位速查表

综合 docs/copymode.md 的按键分配表与默认键表,常用操作速查如下:

操作键位
进入 Copy ModeCtrl-Shift-X
复制并退出 Copy Modey
退出 Copy ModeEscCtrl-cCtrl-gq
单元格选择v(再按一次取消)
行选择Shift-V
矩形块选择Ctrl-V
移动光标方向键,或h/j/k/l
向前/后一个单词Alt-右方向/Alt-左方向Alt-f/Alt-bTab/Shift-Tabw/b
移动到单词末尾e
行首 / 行首内容 / 行尾内容0(Home) /^(Alt-m) /$(End)
下一行行首Enter
滚动缓冲区顶部 / 底部g/Shift-G
视口顶部 / 中间 / 底部Shift-H/Shift-M/Shift-L
上/下半屏Ctrl-u/Ctrl-d
上/下整屏PageUp(Ctrl-b) /PageDown(Ctrl-f)
跳转选择另一端点o(水平方向:Shift-O
字符跳转 f/t 与 F/Tf/t向前、F/T向后,;重复、,反向
复制到剪贴板(退出 Copy Mode 后)Ctrl-Shift-C

如何自定义 copy_mode 键表

两种自定义方式

20220624-141144-bd1b7c5d版本起,Copy Mode 的键位由copy_mode这个 Key Table 指定,你可以通过两种方式自定义:

  1. 整体替换:在~/.wezterm.lua中提供自己的copy_mode键表定义(即上文完整配置)。注意这种方式会整体替换默认表,因此需要把想保留的键位一并写入。
  2. 基于默认表扩展:先通过wezterm.gui.default_key_tables()(参见 docs/config/lua/wezterm.gui/default_key_tables.md)取得当前版本的默认键表,再增删条目。这在较新版本中尤其有用,因为早期版本只能整体替换,无法局部覆盖。

查看你本机版本的默认键表

文档中给出的默认键表可能比你安装的版本更新,请用以下命令查看本机实际默认值:

wezterm show-keys --lua --key-table copy_mode

键表与输入解析的底层机制

从源码角度,自定义之所以生效,是因为键表解析发生在 GUI 层:在 wezterm-gui/src/inputmap.rs 中,配置加载完成后,如果keys.by_name里没有copy_mode/search_mode条目,会自动用overlay::copy::copy_key_table()search_key_table()注入默认表;一旦你的配置提供了同名键表,注入就会被跳过,你的定义成为唯一解析来源。

此外,Key Table 机制本身由key_tables配置项承载,配合ActivateKeyTable(含one_shottimeout_millisecondsreplace_current等字段,见 config/src/keyassignment.rs)可构建复杂的键表激活栈;Copy Mode 的进入正是ActivateCopyMode动作触发对应键表的结果。

自定义实例:在默认键表上添加自定义动作

下面演示如何基于默认键表做局部修改——例如在保持全部默认键位不变的前提下,给Ctrl-n增加“向后滚动半屏”的绑定,并给Space追加CopyTo行为(注意这会改变Space的原语义,仅为演示Multiple的组合能力):

local wezterm = require 'wezterm' local act = wezterm.action local config = {} local copy_mode = wezterm.gui.default_key_tables().copy_mode table.insert(copy_mode, { key = 'n', mods = 'CTRL', action = act.CopyMode { MoveByPage = 0.5 } }) -- 演示:让 Space 先开启单元格选择,再追加复制行为(会覆盖默认 Space 语义) for i, entry in ipairs(copy_mode) do if entry.key == 'Space' then entry.action = act.Multiple { { CopyMode = { SetSelectionMode = 'Cell' } }, { CopyTo = 'ClipboardAndPrimarySelection' }, } end end config.keys = { { key = 'X', mods = 'CTRL|SHIFT', action = act.ActivateCopyMode }, } config.key_tables = { copy_mode = copy_mode } return config

要点提示:

  • 先执行table.insert前可先print(wezterm.version)确认版本支持default_key_tables()
  • 修改后的键表同样遵循键表解析规则:栈顶优先匹配,未命中继续向下查找(见 docs/config/key-tables.md 中关于激活栈的说明);
  • 若在复杂键表中被卡住,可重新保存~/.wezterm.lua触发配置重载,键表栈会自动清空,从而恢复默认状态。

常见问题与排查

  • 为什么修改了 copy_mode 后部分按键失效?因为你整体替换了默认键表,遗漏的键位不再生效。请基于wezterm.gui.default_key_tables().copy_mode修改,或对照本文完整默认键表逐条补齐。
  • 如何确认当前键表内容?运行wezterm show-keys --lua --key-table copy_mode即可输出本机生效的键表定义。
  • 进入 Copy Mode 后标题没变化?Copy Mode 激活时标签标题应带"Copy Mode"前缀;若未出现,确认ActivateCopyMode绑定未被其他键分配覆盖。
  • 矩形选择不可用?SetSelectionMode = 'Block'需要20220624-141144-bd1b7c5d及之后的版本;旧版本请升级。

参考路径

  • 默认键表示例:docs/examples/default-copy-mode-key-table.markdown
  • Copy Mode 使用文档:docs/copymode.md
  • Key Table 机制说明:docs/config/key-tables.md
  • 动作枚举源码:config/src/keyassignment.rs
  • 键表默认注入逻辑:wezterm-gui/src/inputmap.rs
  • 默认键表 API 文档:docs/config/lua/wezterm.gui/default_key_tables.md

【免费下载链接】weztermA GPU-accelerated cross-platform terminal emulator and multiplexer written by @wez and implemented in Rust项目地址: https://gitcode.com/GitHub_Trending/we/wezterm

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询