我的 I3-Emacs 集成

2026-05-24 1 阅读 nosolace
平铺窗口管理器非常棒。超灵活的文本编辑器也很棒。有一段时间,我以为我在 exwm 中找到了理想的解决方案……而且我认为它会是这样,除了我使用普通的图形窗口与文本缓冲区一样多(如果不是更多的话),有时这些窗口来自狡猾的程序(例如,steam),这些程序在 EXWM 的花哨输入法方面存在问题。但我还是很喜欢emacs。天哪,它在我的机器上切换浅色和深色模式(仍然)!因此,受到 \(\sqrt{-1}\) 等帖子的启发,我开始在 emacs 和 i3 之间获取一组通用的键绑定,以及一些有关打开终端、分割窗口等的合理默认值。我首先尝试使用 xdotool 和 emacsclient 编写脚本,如上面引用的文章中所示,并且有效……但事实证明太慢了:我看到了最多第二个计时的滞后,该脚本给出了 30 的延迟从调用到退出需要 100 毫秒,这仍然相当慢,但不会破坏交易。我仍然不知道其余的延迟来自哪里。在向 emacs 发送输入和实际注册之间。我不知道这是否是因为我的 emacs 版本、其他软件包、emacsclient 的怪异等等,但这并不能解决问题。另外,仅仅为了注册一个按键而启动整个 shell-plus 似乎很浪费,特别是对于我使用的一些最常用的按键组合。所以我做了唯一理性的事情:我给 i3 打了补丁。我的目标是:不是单方面处理通过 i3 的 bindsym 绑定的命令,而是添加一个选项来检查当前聚焦的窗口以查看它是否是 emacs,如果是,则将按键事件传递给它。请注意,过去曾要求此功能,但 i3 维护者认为它超出了范围。如果不是这种情况,我会让这个补丁变得更加成熟。如果 emacs 决定“不,i3 实际上应该处理这个问题”,它可以使用 i3-msg 将操作路由回来。我成功了,尽管这可能不是世界上最优雅的事情。如果您了解xcb并想给我建议,请!给我发送电子邮件至 web@khz.ac 。相关的i3代码 i3在根x窗口上使用xcb_grab_key()和owner_events = 0来拦截密钥。如果您想继续,src/bindings.c 中的相关代码看起来所有未修补的代码片段都引用 i3 4.25.1。 [第 172 章]第173章 174、第174章第175章 175正文 正文_第 176 章第177章 178、第178章179 } 这段代码并不是非常相关,只是 i3 通过拦截根窗口完全窃取了其他任何人的绑定。如果您认为设置owner_events = 1以允许事件传递,这样我们就不必重新发出...那会很好,但这似乎指示x将事件仅传递到根窗口。这不是我们想要的。在 src/handlers.c 中 i3 的 handle_event() 中,如果它收到 xcb 事件,则会根据其类型将其发送到专用处理程序: 1481 switch (type) { 1482 case XCB_KEY_PRESS: 1483 case XCB_KEY_RELEASE: 1484 handle_key_press(( xcb_key_press_event_t *)event); 1485 突破;第 1486 章我选择保留这种方式,因为 i3 源代码中就是这样。但我应该注意:i3 有非常好的源代码!我发现它非常可读并且在里面工作很愉快。 12 /* 13 * 有一个 KeyPress 或 KeyRelease (两个事件具有相同的字段)。我们 14 * 将此关键代码与我们的绑定表进行比较,并将绑定操作传递给 15 * parse_command()。 16 * 17 */ 18 void handle_key_press ( xcb_key_press_event_t * event ) { 19 const bool key_release = (event->response_type == XCB_KEY_RELEASE); 20 21 last_timestamp = 事件->时间; 22 23 DLOG( "%s %d, state raw = 0x%x\n" , (key_release ? "KeyRelease" : "KeyPress" ), 事件->详细信息, 事件->状态); 24 25 绑定 * 绑定 = get_binding_from_xcb_event(( xcb_generic_event_t *)event); 26 27 /* 如果我们找不到绑定,我们就完成了 */ 28 if (bind == NULL ) { 29 return ; 30 } 31 32 CommandResult * 结果 = run_binding(bind, NULL ); 33 command_result_free(结果); 34 } 值得注意的是,这个函数从 xcb 接收原始的 xcb_key_press_event_t ,(经过一些阅读和实验)我意识到你可以通过 xcb_send_event() 直接重新发出。不幸的是,接收事件的窗口仍然会失去焦点,因为 i3 正在全局拦截关键事件。我还没有解决这个问题;如果你知道怎么做,请告诉我。这看起来是一个合理的改变地方!补丁绑定结构发生变化,我决定修改