一组快捷键,本来应该是肌肉记忆的一部分。按下去,窗口移动、焦点切换、终端打开。

但在 i3 和 Emacs 混用时,事情会卡在一个很小的地方:i3 已经把全局快捷键抓走了,Emacs 即使在前台,也收不到这些按键。

这名用户的选择有点硬。他没有继续绕脚本,而是给 i3 4.25.1 打了一个个人补丁:给绑定新增 --passthrough,当当前窗口是 Emacs 时,把按键事件透传给 Emacs。

我更在意的不是“又有人折腾 Emacs”。真正的问题是:高频桌面操作里,脚本转发和窗口管理器内部转发,哪条路径更可靠。

脚本能用,但输在每一次按键都要绕远路

冲突来自 i3 的默认工作方式。

在 X11 下,i3 通过 xcb_grab_key() 在 root window 上抓全局快捷键。owner_events = 0 的结果是,这些组合键会先被窗口管理器截获。

所以 Emacs 位于前台也没用。只要这组键已经被 i3 绑定,Emacs 就不能直接收到。

社区里常见的绕法,是用 xdotool、emacsclient 和 shell 脚本。i3 抓到按键后,再调用外部工具,把动作送进 Emacs。

这条路不算错。它的好处是不用改 i3。

问题是路径太长。原文给出的测量是,脚本从 invocation 到退出大约 30—100ms;体感上偶尔会到约 1 秒。更长延迟来自哪里,作者没有查明。

这也是我不太买账脚本方案的地方。对一次低频操作来说,几十毫秒没什么。对窗口移动、焦点切换、终端启动这类高频动作来说,尾延迟会直接打断手感。

几条路线的取舍大致是这样:

路线好处现实限制更适合谁
EXWM让 Emacs 统一管理窗口和输入普通图形应用、游戏等场景可能不顺几乎全程待在 Emacs 里的用户
xdotool / emacsclient 脚本不改 i3,配置成本低每次按键要走外部进程,延迟和抖动难控少量快捷键、低频动作
i3 个人补丁在窗口管理器内判断和转发,路径更短要自己维护,且不是上游功能i3 + Emacs 重度用户,且快捷键使用很高频

受影响的人其实很窄。

如果你只是偶尔在 Emacs 里写东西,脚本足够。如果你每天靠 Super 组合键在 Emacs、浏览器、终端、Steam 或其他图形窗口之间来回切,延迟就不再是参数,而是工作流里的砂砾。

--passthrough 把判断放进 i3,而不是交给外部脚本

补丁的核心很直接:让 i3 在处理绑定时,多一个分支。

作者在 i3 的 Binding 结构中增加 passthrough 字段,并改配置解析器,让类似 bindsym --passthrough 的写法成立。

handle_key_press() 找到对应绑定后,i3 不立刻执行原来的命令。它先检查当前聚焦窗口的 class。

如果 class 精确匹配 Emacs,补丁会把原始 xcb_key_press_event_t 的目标窗口改成当前 focus,再用 xcb_send_event() 发过去。

如果当前窗口不是 Emacs,i3 仍按原绑定执行命令。

换句话说,同一组快捷键有了两套归属:

  • Emacs 在前台时,按键交给 Emacs。
  • 普通窗口在前台时,按键仍由 i3 处理。

这个设计比外部脚本干净。它少了 shell、emacsclient、xdotool 这一串中间环节,也更贴近问题发生的位置。

但它不是银弹。

原文也承认,事件转发后窗口仍可能失焦。原因在于 i3 仍然在全局截获按键,透传只是在截获之后补了一条路径。

还有一个边界必须说清楚:这是基于 X11、xcb 和 i3 4.25.1 的个人补丁。不能把它直接理解成 Wayland 方案,也不能泛化到所有窗口管理器。

更现实的一点是,i3 维护者此前已在相关 issue 中认为类似 passthrough 功能超出项目范围。也就是说,这不是“等发行版更新就能用”的功能,而是个人维护分支。

对重度用户来说,这里要算一笔账:每天少掉多少卡顿,能不能抵过以后升级 i3 时维护补丁的成本。

Emacs 只接管该接管的事,越界动作再还给 i3

这个方案有意思的地方,不是把所有事都塞进 Emacs。

按键进入 Emacs 后,作者仍然保留了 i3 的职责边界。比如方向移动窗口时,Emacs 先尝试在自身 frame 内切换或交换窗口。

如果目标方向没有 Emacs 窗口,动作再交回 i3。具体做法是调用 i3-msg focusi3-msg move

这比“让 Emacs 接管一切”更务实。Emacs 管自己内部的窗口,i3 管桌面上的容器和普通图形应用。各司其职,少一点互相抢活。

终端启动也是类似思路。

作者覆盖了两类入口:Super+Return 打开 mistty,Super+Control+Return 打开 alacritty。mistty 偏 Emacs 内部集成,alacritty 处理更复杂的文本渲染场景。

脚本还尽量保留当前工作目录。这个细节不大,但对写代码的人很关键:从项目目录里打开终端,不应该因为动作跨过 Emacs 和 i3 的边界,就丢掉上下文。

最相关的两类人,可以这样判断自己要不要折腾:

  • i3 用户如果只绑定少量全局快捷键,可以继续用脚本,没必要背个人补丁的维护成本。
  • Emacs 重度用户如果把窗口切换、分屏移动、终端启动都压在同一套组合键上,可以考虑研究这种内部透传思路,但要接受焦点问题和升级维护成本。

接下来真正要看两个变量。

一个是失焦问题能否更稳地处理。现在只能说补丁缩短了路径,不能说它解决了所有焦点边界。

另一个是维护成本。i3 升级、配置迁移、补丁冲突,都会把省下来的操作成本再拿回一部分。

所以这件事的结论并不复杂:少量快捷键,脚本够用;整套桌面肌肉记忆都绑在这些键上,改窗口管理器本身反而更合算。