0 诡异的退格键

最近在用glfw和dear imgui写一个简单的deepseek客户端,又遇到了“喜闻乐见”的输入法问题。最令人恼火的就是退格键不能被正确处理。就像下面这个视频展示的,预编辑的时候,按下退格键不仅会删除预编辑的内容,还会删除已经输入的内容,体验稀烂。

在Linux版本的Minecraft上也会有这样的问题,问题的根源同样是glfw1

另外,在Wayland下,因为没有实现wayland的输入法协议,glfw直接用不了输入法。

1 临时解决办法

强制使用X11

目前Wayland下面的输入法问题可以说是一团糟,一切都处于过渡状态。解决输入法用不了的最好办法,就是不要用Wayland。在glfwInit()之前,强制glfw选定X11平台。

#ifdef __linux__
    glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_X11);
#endif

给glfw打补丁

GLFW处理XIM协议2的方法不太正确,没有正确过滤掉部分键盘事件(比如输入时的退格键)。下载这个补丁,用patch命令打到glfw 3.4的源代码上。这个补丁的改动很小,就是让glfw无视被过滤掉的事件。类似的解决方案早有人在MC的bug report里给出,不知为何glfw至今未改正。

@@ -1242,6 +1245,9 @@ static void processEvent(XEvent *event)
 
         case KeyPress:
         {
+            if (filtered) {
+                return;
+            }
             const int key = translateKey(keycode);
             const int mods = translateState(event->xkey.state);
             const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));

2 Linux混乱不堪的输入法

Linux下输入法问题繁多,很大程度是因为缺少稳定、统一的协议。其次,主要开发者中,中国人和日本人少,大部分开发者不用输入法,对这个问题不太重视。最早X11制定了XIM协议,Tedyin的博客3给出了一个很好的例子解释这个协议,建议阅读。XIM协议看起来简洁明了,而且也能用,但据说在特定条件下会导致程序卡死4。社区后来不知出于什么原因,没有进一步改进XIM协议,而是由GTK和Qt分别开发自己的IM Module——从此天下大乱,装个输入法都要手动配几个莫名其妙的环境变量。GLFW既不是GTK,也不是Qt,就更麻烦。

再后来,为了方便输入法开发,又出现了ibus和fcitx。ibus据说在非GNOME环境下表现不佳(但是我没查到具体的问题),且其GNOME下的拼音输入也有不少bug5。在国内社区持续的推广下,现在fcitx是中文输入的主流。

与此同时,Wayland正在逐步取代X11。很遗憾的是,Wayland的出现非但没有缓解输入法问题,反而将其进一步恶化了。Wayland自己另起炉灶,搞了v1-v4一系列协议6,具体兼容情况各不相同。应用开发者的反应没有协议更新的速度快,通常也不会把IME支持放在比较优先的位置,就导致过渡阶段💩一样的体验。

总之,在2025年的今天,Linux的输入法问题成了最混乱、最糟糕、最劝退的问题之一,上Arch中文论坛搜“Wayland+输入法”,能搜出来一整页的帖子。主要开发者长期忽视IME,造成社区不断分裂、造新的轮子,旧的问题刚刚解决,新的问题又产生了。就结果而言,如今哪怕是处理一个很常见的输入法问题,都需要很多无关的底层知识。Linux的输入法完全不应该这么复杂,本来应该和Windows一样简单才对。


  1. MC-258708 Deleting candidate CJK words in IME also deletes text already entered↩︎

  2. XIM协议↩︎

  3. Tedyin - A Brief Intro to Input Method Framework, Linux IME, and XIM↩︎

  4. csslayer关于XIM的议论↩︎

  5. 早年ubuntu论坛上的讨论↩︎

  6. csslayer - Chrome/Chromium 今日 Wayland 输入法支持现状↩︎