T3 Code 键盘快捷键(Keybindings)配置完全指南:从配置文件到源码实现
【免费下载链接】t3code项目地址: https://gitcode.com/GitHub_Trending/t3/t3code
T3 Code 在 Web 端与桌面端提供了统一的快捷键定制能力,你可以通过Settings → Keybindings图形界面,或直接编辑环境机器上的~/.t3/userdata/keybindings.json配置文件,为任意命令绑定、调整或移除快捷键。阅读完本文,你将掌握快捷键规则的完整 JSON 语法、when条件表达式的编写方法、规则优先级判定原理,以及mod+w、退出快捷键等特殊行为的处理细节,并能结合源码理解 T3 Code 从配置解析、校验到按键分发的完整链路。
在何处配置快捷键
快捷键配置入口为Settings → Keybindings,Web 与桌面端均可使用。该页面会列出当前版本可用的命令 ID(Command ID)及其默认快捷键,你可以直接在页面上进行以下操作:
- 点击快捷键胶囊(Pill)进入录制状态,按下新的组合键完成绑定;
- 编辑或可视化构建
when条件表达式; - 将自定义过的绑定Reset to default恢复默认值,或直接Remove移除;
- 通过搜索框快速过滤命令,页面会实时给出快捷键冲突警告与未知条件警告。
从源码看,这个页面由 KeybindingsSettings.tsx 实现,其中KeybindingConflictWarning明确提示:"The most recent matching binding wins when both conditions can apply"(当两个条件同时满足时,最近匹配的绑定生效),这与下文将要讲解的优先级规则完全一致。
直接编辑配置文件
除了图形界面,快捷键配置以 JSON 文件形式存放在环境所在机器上,默认路径为:
~/.t3/userdata/keybindings.json该文件是一个规则数组(JSON array of rules),例如:
[ { "key": "mod+g", "command": "terminal.toggle" }, { "key": "mod+shift+g", "command": "terminal.new", "when": "terminalFocus" } ]配置文件由 T3 Code 负责生命周期管理:
- 首次启动时,T3 Code 会用默认规则创建该文件;
- 后续启动时,若产品新增了默认快捷键,T3 Code 会把新默认值追加进去;
- 新默认值不会覆盖你已经自定义过的命令绑定;
- 若某个新默认值与你的自定义快捷键重叠,由规则顺序(详见"优先级"一节)决定最终生效者;
- 无效规则会被忽略;如果整个文件无法解析(例如 JSON 语法错误),T3 Code 将直接回退使用默认配置。
服务端的解析、校验、合并与持久化逻辑集中在 keybindings.ts(server),其文件头注释明确指出该模块负责 "parsing, validation, merge, and persistence of user keybinding configuration";而配置文件解析失败时抛出的KeybindingsConfigError(定义于 packages/contracts/src/keybindings.ts)会携带配置路径configPath与错误详情detail,方便定位问题。
规则(Rule)的基本形态
每条规则由三个字段组成,其中key与command为必填:
| 字段 | 必填 | 说明 |
|---|---|---|
key | 是 | 快捷键组合,例如mod+g |
command | 是 | 要触发的命令 ID,例如terminal.toggle |
when | 否 | 条件表达式,限制该快捷键在什么上下文下生效 |
命令 ID 的合法范围
在 packages/contracts/src/keybindings.ts 中,命令 ID 通过 Schema 严格校验,由两部分组成:
静态命令列表
STATIC_KEYBINDING_COMMANDS,包括:- 界面类:
sidebar.toggle、commandPalette.toggle、filePicker.toggle、projectSearch.toggle、themeEditor.toggle、rightPanel.toggle、rightPanel.toggleMaximized、rightPanel.close、diff.toggle; - 终端类:
terminal.toggle、terminal.split、terminal.splitVertical、terminal.new、terminal.close; - 预览类:
preview.toggle、preview.refresh、preview.focusUrl、preview.zoomIn、preview.zoomOut、preview.resetZoom; - 会话/编辑类:
composer.stash、chat.new、chat.newLocal、editor.openFavorite; - 模型选择器:
modelPicker.toggle以及modelPicker.jump.1~modelPicker.jump.9; - 线程类:
thread.stop、thread.previous、thread.next、thread.copyReference、thread.settle、thread.pin以及thread.jump.1~thread.jump.9。
- 界面类:
项目脚本命令:遵循
SCRIPT_RUN_COMMAND_PATTERN,格式为script.{id}.run,例如script.test.run。其中id必须匹配^[a-z0-9][a-z0-9-]*$(小写字母/数字开头,可含连字符),且最长 24 个字符。
校验相关的长度与数量限制
同一文件还定义了以下硬性约束,写入超限内容将被视为无效规则:
- 快捷键字符串(
key)最长64字符(MAX_KEYBINDING_VALUE_LENGTH); when表达式最长256字符(MAX_KEYBINDING_WHEN_LENGTH);when表达式的嵌套深度最大64层(MAX_WHEN_EXPRESSION_DEPTH);- 整个配置文件最多256条规则(
MAX_KEYBINDINGS_COUNT)。
按键语法(Key Syntax)
使用+连接修饰键(modifier)与按键,例如mod+shift+d或ctrl+l。修饰键分为两类:
mod:跨平台抽象修饰键——在 macOS 上表示Command,在其他平台表示Control;- 平台具体修饰键:
cmd/meta(对应 Command/Windows 键)、ctrl/control、alt/option、shift。
从 parseKeybindingShortcut 的实现可以看到解析细节:字符串会先转为小写、按+切分并 trim 每个 token,然后逐个识别cmd/meta→metaKey、ctrl/control→ctrlKey、shift→shiftKey、alt/option→altKey、mod→modKey;只有最后一个非修饰 token 会被当作按键本身(key),且space会被规范化为空格、esc被规范化为escape。这意味着:
- 每条规则中只能有一个按键(Key),修饰键可以任意组合;
- 大小写不敏感,
Mod+Shift+D与mod+shift+d等价; - 若 token 解析后存在空片段或没有按键部分,该快捷键无效。
mod键在运行时如何映射?桌面与 Web 客户端的匹配逻辑位于 apps/web/src/keybindings.ts 的matchesShortcutModifiers:当平台为 macOS 时modKey参与metaKey期望匹配,否则参与ctrlKey期望匹配;同时要求metaKey、ctrlKey、shiftKey、altKey四者与事件完全一致才命中。
非拉丁键盘布局的兼容处理
同文件中的resolveEventKeys还处理了一个细节:当系统布局输出的是非拉丁字母(如西里尔文、希腊文)或 macOS 上Option修饰产生特殊符号时,会以物理键位event.code(KeyA~KeyZ)作为回退匹配;反之,如果布局已经产生拉丁字母,则只按布局键匹配,避免一个被重映射的物理键同时触发两个字母的快捷键,从而遮蔽非 QWERTY 布局下的系统快捷键。
When 条件表达式
可用的上下文键(context key)当前包括:
| 上下文键 | 含义 |
|---|---|
terminalFocus | 内嵌终端获得焦点 |
terminalOpen | 终端面板处于打开状态 |
previewFocus | 预览区域获得焦点 |
previewOpen | 预览处于打开状态 |
modelPickerOpen | 模型选择器处于打开状态 |
未知的上下文键一律求值为false(见 evaluateWhenNode 中return Boolean(context[node.name])的兜底行为),因此不用担心拼写错误导致报错,但该规则将永远不会匹配。图形界面对此会给出"Unknown condition"警告——在 KeybindingsSettings.tsx 中,未知条件仍可保存,但提示"may not match unless the runtime provides it"。
组合运算符
支持!(非)、&&(与)、||(或)以及括号分组,例如:
{ "key": "mod+j", "command": "terminal.toggle", "when": "terminalOpen && !terminalFocus" }该表达式的含义是:仅当终端已打开且终端未获得焦点时,mod+j才切换终端——即终端获得焦点时按键会原样输入到 shell,而不是触发切换。
服务端解析when表达式的过程见 parseKeybindingWhenExpression:先通过tokenizeWhenExpression分词(识别&&、||、!、(、)与标识符),再递归下降解析为 AST(抽象语法树)。AST 节点类型定义在 packages/contracts/src/keybindings.ts 的KeybindingWhenNode中,仅有四种:identifier(标识符)、not、and、or;客户端运行时evaluateWhenNode对 AST 直接求值。
图形界面中的可视化构建器
在 Settings 页面编辑when时,并不强制手写表达式——WhenExpressionBuilder(KeybindingsSettings.tsx)同时提供:
- 可直接编辑的表达式输入框,带实时语法校验与错误提示;
- 可视化节点编辑器,支持添加/删除条件(Condition)、嵌套分组(Group)、切换
and/or运算符以及取反(Not),修改会同步回写表达式文本。
优先级(Precedence)规则
当多个规则使用相同快捷键时,最后一条"按键与条件同时匹配"的规则生效,即使它属于不同的命令。因此,如果你要让多个命令共享同一快捷键,应把更具体的规则放在更通用的规则之后。
这一行为有明确的源码实现依据:在 resolveShortcutCommand 中,匹配循环从数组末尾向前遍历(for (let index = keybindings.length - 1; index >= 0; index -= 1)),遇到第一个同时满足when条件与按键组合的规则即返回其命令。默认配置中就有典型的"同键不同条件"案例:
{ "key": "mod+w", "command": "terminal.close", "when": "terminalFocus" }, { "key": "mod+w", "command": "rightPanel.close", "when": "!terminalFocus" }终端获得焦点时mod+w关闭终端;其余场景下关闭右侧面板——两条规则靠when条件互斥,不会冲突。
另外值得注意的是客户端解析配置时的前向兼容设计:ResolvedKeybindingsConfig(见 packages/contracts/src/keybindings.ts)在解码时会丢弃客户端无法识别的规则(比如该客户端版本发布后才新增的命令或when节点),而不是让整个配置解析失败,避免"一个快捷键拖垮整条连接"。
具有特殊行为的命令
thread.stop
thread.stop用于中断当前线程中正在进行的回复(running turn)。它没有默认快捷键,需要你在Settings → Keybindings中自行分配。
chat.new 与 chat.newLocal
chat.new:开启新会话。当存在多个项目时,可能会弹出项目选择器让你选择目标项目;chat.newLocal:跳过项目选择器,直接创建新线程。
两者均遵循你在新线程中设定的默认行为(详见 new-thread defaults 一节)。默认配置中两者均已绑定快捷键(mod+n/mod+shift+n等),且带!terminalFocus条件以避免干扰终端输入。
保留快捷键:mod+w 的行为与重新绑定
在桌面端,mod+w具有多级"关闭"语义,按优先级依次是:
- 关闭获得焦点的终端(terminal);
- 关闭当前激活的右侧面板标签页(right-panel tab);
- 当没有可关闭的内容时,关闭窗口。
在浏览器中,mod+w会关闭浏览器标签页(浏览器自身行为,T3 Code 无法拦截)。因此,如果你不希望误关浏览器标签,建议为rightPanel.close和terminal.close重新绑定到一个可用快捷键,例如alt+w。
此外,默认配置中大量规则都带有!terminalFocus条件,目的是避免拦截终端输入——终端获得焦点时,按键(例如mod+l清屏等终端内快捷键)应交给 shell 处理。当你重映射这些命令时,若希望保持相同行为,请保留这一条件。源码注释(见 shouldShowThreadJumpHintsForModifiers)也印证了这一点:内嵌终端拥有焦点时,按键会被 Ghostty 表面编码并直接写入 shell,早于窗口级快捷键处理;因此在终端聚焦时不会展示任何线程跳转快捷键提示。
桌面端退出快捷键
桌面端的退出快捷键为:
- macOS:
Cmd+Q - Windows / Linux:
Ctrl+Q
默认采用Hold(按住)模式,触发条件为按住 1.2 秒,或在 500 毫秒内连续按两次。注意:按住方式依赖系统的键盘重复(keyboard repeat)功能;如果你禁用了键盘重复,请改用双击方式或直接使用应用程序菜单退出。
你可以在Settings → General → Confirmations → Quit shortcut中修改退出模式:
| 模式 | 行为 |
|---|---|
| Hold(默认) | 按住 1.2 秒,或 500ms 内双击 |
| Direct | 单击立即退出 |
| Double press | 仅支持连续按两次退出 |
无论哪种模式,从应用程序菜单选择Quit都会立即退出,不受上述确认模式限制。
默认快捷键一览
完整默认配置定义在 packages/shared/src/keybindings.ts 的DEFAULT_KEYBINDINGS中,以下是常用默认绑定(mod在 macOS 为 Command,其余平台为 Control):
| 快捷键 | 命令 | 条件 |
|---|---|---|
mod+b | sidebar.toggle | — |
mod+j | terminal.toggle | — |
mod+alt+b | rightPanel.toggle | — |
mod+d | terminal.split | terminalFocus |
mod+shift+d | terminal.splitVertical | terminalFocus |
mod+n | terminal.new | terminalFocus |
mod+w | terminal.close | terminalFocus |
mod+w | rightPanel.close | !terminalFocus |
mod+d | diff.toggle | !terminalFocus |
mod+shift+j | preview.toggle | — |
mod+r | preview.refresh | previewFocus |
mod+=/mod++ | preview.zoomIn | previewFocus |
mod+k | commandPalette.toggle | !terminalFocus |
mod+p | filePicker.toggle | !terminalFocus |
mod+shift+f | projectSearch.toggle | !terminalFocus |
mod+s | composer.stash | !terminalFocus |
mod+n/mod+shift+o | chat.new | !terminalFocus |
mod+shift+n | chat.newLocal | !terminalFocus |
mod+shift+m | modelPicker.toggle | !terminalFocus |
mod+o | editor.openFavorite | — |
mod+shift+[/mod+shift+] | thread.previous/thread.next | — |
mod+shift+c | thread.copyReference | !terminalFocus |
mod+shift+s | thread.settle | !terminalFocus |
mod+shift+p | thread.pin | !terminalFocus |
mod+1~mod+9 | thread.jump.1~thread.jump.9 | — |
mod+1~mod+9 | modelPicker.jump.1~modelPicker.jump.9 | modelPickerOpen |
其中线程跳转(thread.jump.N)与模型选择器跳转(modelPicker.jump.N)命令由 packages/contracts/src/keybindings.ts 中的THREAD_JUMP_KEYBINDING_COMMANDS与MODEL_PICKER_JUMP_KEYBINDING_COMMANDS常量批量生成,默认分别绑定到mod+1~mod+9(模型选择器跳转额外要求modelPickerOpen条件,因此与线程跳转不冲突)。界面中按键标签的格式化(如 macOS 下的⌘、⇧、⌥符号)由 formatShortcutLabel 完成。
总结
T3 Code 的快捷键系统是一套"声明式规则 + 严格校验 + 后绑定优先"的完整方案:规则存放在~/.t3/userdata/keybindings.json,由服务端(apps/server/src/keybindings.ts)负责解析、校验、合并与持久化,schema 约束定义在 packages/contracts/src/keybindings.ts,客户端运行时(apps/web/src/keybindings.ts)负责按键分发与优先级判定。理解mod的跨平台映射、when表达式求值与"最后匹配者胜出"的优先级规则,就能在不破坏终端输入的前提下,构建一套贴合自己工作流的快捷键体系。
【免费下载链接】t3code项目地址: https://gitcode.com/GitHub_Trending/t3/t3code
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考