Ghostty 在中文输入法下 Ctrl/Alt 键失效:完整修复

环境:macOS 13.7.8(Intel)+ Ghostty 1.4.0 + 豆包拼音输入法
现象:输入法激活时 Ctrl+C 无法中断进程,Ctrl+A/E/B/F/P/N 等编辑键同样失效;同机 Kitty 正常
结论:Ghostty 的 macOS 输入快速路径受输入法影响,用物理键名绑定可完整绕过
覆盖:22 个 Ctrl 组合 + 4 个 Alt 组合,已在 4 台 Mac 上验证

TL;DR #

# ~/.config/ghostty/config

# A–Z 中除 H(Backspace)/I(Tab)/J(LF)/M(CR) 外的全部字母
keybind = ctrl+key_a=text:\x01
keybind = ctrl+key_b=text:\x02
keybind = ctrl+key_c=text:\x03
keybind = ctrl+key_d=text:\x04
keybind = ctrl+key_e=text:\x05
keybind = ctrl+key_f=text:\x06
keybind = ctrl+key_g=text:\x07
keybind = ctrl+key_k=text:\x0b
keybind = ctrl+key_l=text:\x0c
keybind = ctrl+key_n=text:\x0e
keybind = ctrl+key_o=text:\x0f
keybind = ctrl+key_p=text:\x10
keybind = ctrl+key_q=text:\x11
keybind = ctrl+key_r=text:\x12
keybind = ctrl+key_s=text:\x13
keybind = ctrl+key_t=text:\x14
keybind = ctrl+key_u=text:\x15
keybind = ctrl+key_v=text:\x16
keybind = ctrl+key_w=text:\x17
keybind = ctrl+key_x=text:\x18
keybind = ctrl+key_y=text:\x19
keybind = ctrl+key_z=text:\x1a

# Alt 组合:终端里 Alt+B 等是 ESC 前缀序列
keybind = alt+key_b=text:\x1bb
keybind = alt+key_f=text:\x1bf
keybind = alt+key_d=text:\x1bd
keybind = alt+backspace=text:\x1b\x7f

保存后按 ⌘ + ⇧ + , 重载配置。

为什么是 Emacs 风格 #

这批按键不是 Ghostty 定义的,而是 GNU Readline 的默认编辑键。bash/zsh 的 emacs 模式、fish 的多数默认绑定都沿用同一套语义。

终端本身不解释这些按键,它只负责把控制字符写进 pty;具体行为由 shell 或运行中的程序决定。因此修复的本质是:

保证控制字符能穿过输入法,原样到达 shell。

现象 #

在一台 Intel Mac 上,Ghostty 里运行 sleep 100,按 Ctrl+C 完全没有反应;换成 Kitty 打开同一个 shell,立刻正常。

继续测试发现:所有 Ctrl + 字母 组合都失效,而 Ctrl + 非字母 正常。

值得注意的是,这台机器的键盘布局是 ABC(US),只有当前输入源是中文输入法。问题不在布局,而在输入法是否激活。

排查过程 #

1. 排除配置冲突 #

ghostty +list-keybinds | grep -i 'ctrl+c'
ghostty +show-config | grep -i keybind

结果:配置里没有任何自定义绑定,默认键位中复制是 super+c,没有东西拦截 ctrl+c。

2. 确认输入源 #

defaults read ~/Library/Preferences/com.apple.HIToolbox.plist AppleSelectedInputSources

输出中出现 com.bytedance.inputmethod.doubaoime。布局仍是 US,但输入法处于激活状态。

3. 对照已知问题 #

Ghostty 在 macOS 上处理 Ctrl + 字母 时走快速路径,直接使用 AppKit 的 charactersIgnoringModifiers。输入法激活时,该接口返回的是输入法处理后的字符,而不是按键本身,于是 Ctrl+C 不再产生 0x03,进程收不到 SIGINT。

为什么 Kitty 正常 #

Kitty 使用自己的按键处理流程,不依赖 charactersIgnoringModifiers 判断 Ctrl + 字母,所以在输入法激活时仍能正确发送控制字符。

同一台机器、同一个 shell、同一个输入法,只换终端就正常——变量被收敛到终端层。

修复:绑定物理键 #

Ghostty 的 keybind 支持物理键名(key_c 表示物理位置上的 C 键)。物理键绑定不经过布局与输入法的字符翻译,直接把控制序列写进 pty。

为什么 Alt 是 \x1bb #

终端里并不存在独立的 Alt+B 键码。传统做法是发送 ESC(0x1b)后跟字母 b,读行程序据此识别为 Alt 组合。

macos-option-as-alt = true 原本会自动做这个转换,但输入法介入时同样会被打断,所以这里显式绑定。

完整映射表 #

Ctrl 组合(22 个) #

键 字符 Emacs/readline 语义
Ctrl+A 0x01 跳到行首
Ctrl+B 0x02 后退一个字符
Ctrl+C 0x03 中断(SIGINT)
Ctrl+D 0x04 删除字符;空行时为 EOF
Ctrl+E 0x05 跳到行尾
Ctrl+F 0x06 前进一个字符
Ctrl+G 0x07 取消当前命令
Ctrl+K 0x0b 删除到行尾
Ctrl+L 0x0c 清屏
Ctrl+N 0x0e 下一行 / 下一条历史
Ctrl+O 0x0f 接受并跳到下一条历史
Ctrl+P 0x10 上一行 / 上一条历史
Ctrl+Q 0x11 XON(恢复输出)
Ctrl+R 0x12 反向搜索历史
Ctrl+S 0x13 XOFF(暂停输出)
Ctrl+T 0x14 交换两个字符
Ctrl+U 0x15 删除到行首(fish 中为清空整行)
Ctrl+V 0x16 按字面插入下一个字符
Ctrl+W 0x17 删除前一个词
Ctrl+X 0x18 readline 前缀键
Ctrl+Y 0x19 粘贴(yank)
Ctrl+Z 0x1a 挂起(SIGTSTP)

Alt 组合(4 个) #

键 序列 语义
Alt+B ESC b 按词后退
Alt+F ESC f 按词前进
Alt+D ESC d 删除后一个词
Alt+Backspace ESC DEL 删除前一个词

刻意排除的四个键 #

键 字符 对应功能 排除原因
Ctrl+H 0x08 Backspace 绑定会破坏退格
Ctrl+I 0x09 Tab 绑定会破坏补全
Ctrl+J 0x0a 换行(LF) 绑定会破坏回车
Ctrl+M 0x0d 回车(CR) 绑定会破坏回车

这四个是结构键,终端已经在正确发送,不要覆盖。

验证 #

ghostty +list-keybinds | grep -E 'ctrl\+key_|alt\+key_|alt\+backspace'
ghostty +show-config 2>&1 | grep -icE 'error|invalid'   # 期望 0

重载配置后逐项测试:

注意事项 #

参考 #

2026-10-29