让微信在 Wayland 下原生跑起来
微信打不出中文,问题不在输入法。把 Qt 应用推回原生 Wayland 的 text-input 协议,一行 Exec 就够。
同一个桌面、同一个 fcitx5、同一个用户。终端能使用中文输入法,微信不能。
这真的是一个很恼火的问题,而且对于小白来说也确实是使用 Linux 的第一关(Maybe?)。所以我准备了如下教程。
注意,如果你是一个 Hyprland / niri 用户,以下教程可能不适合你。 笔者曾经使用 Hyprland 时找遍了网络的教程也没法调教好微信
先决条件
| 需要 | 说明 |
|---|---|
| 微信 Linux 版 4.x | 3.x 及 Wine 版是另一回事,见附录 |
| Fcitx5 | 输入法本体。`fcitx5-diagnose` 跟着它一起装 |
| Wayland 会话 | `echo $XDG_SESSION_TYPE` 要输出 `wayland` |
| KDE / GNOME 等 | 靠 `.desktop` 文件启动应用的环境都适用 |
这套做法在什么环境上验证过
```plaintextCachyOS (Arch) | KDE Plasma 6 | Wayland wechat-bin 4.1.13.23 | fcitx5 5.1.22
```
只在上面这一个组合上实测过。 下面这张表说明哪些地方会因环境而异:
| 项 | 是否通用 | 说明 |
|---|---|---|
用户级 `.desktop` 覆盖系统级 |
✅ 通用 | XDG 规范,各桌面环境一致 |
`env VAR=值 命令` 的写法 |
✅ 通用 | `env` 是 coreutils,一定有 |
`text-input-unstable-v3` 这个模块名 |
⚠️ 需要 Qt 自带 | 见「这两个参数各干什么」 |
`--ozone-platform=wayland` |
⚠️ 只对有内嵌 Chromium 的应用有意义 | 同上 |
| 微信的具体版本 | ❌ 会变 | 写这篇时是 4.1.13.23 |
三个自查命令:
```bashecho "$XDG_SESSION_TYPE" # 要输出 wayland which fcitx5-diagnose # 诊断工具,随 fcitx5 一起装 ls ~/.local/share/applications/ # 用户级 launcher 放这
```
第一步:先搞清楚微信到底是什么
网上流传一个说法:「Linux 微信是 Wine / 兼容层跑的」。实际上,微信的官网上或者 AUR 上均可以下载到原生的 Linux版本
```bash# ① 它链接了 Qt 吗? ldd /opt/wechat/wechat | grep -c Qt # → 0 # ② 那 Qt 在哪? grep -a -o -m1 'Qt 6\.[0-9.]*' /opt/wechat/wechat # → Qt 6.6. # ③ 是 Chromium 套壳吗? grep -a -c 'Electron/' /opt/wechat/wechat # → 0
```
三条读下来:
| 结论 | 依据 |
|---|---|
| 它是 Qt 6.6 应用 | 主程序里能搜到 `Qt 6.6.` |
| Qt 是静态链接进去的 | `ldd` 看不到任何 Qt 库,`/opt/wechat/` 下也没有 `libQt*.so` —— 整个 Qt 被编进了那个 181 MB 的主程序 |
| 不是 Electron / Chromium 套壳 | `Electron/`、`Chrome/` 各 0 处 |
| 不是 Wine | 同上。这是腾讯官方的 Linux 原生客户端 |
虽然现在的微信已经是原生的 Linux 程序了,但是我们还是会按照古法教程提供可能已经没有作用的环境变量设置
原理:Qt 应用在 Wayland 下有两条路
同一个 Qt 应用,在一个同时有 `DISPLAY` 和 `WAYLAND_DISPLAY` 的会话里,
可能落在两个完全不同的地方:
```plaintext① 兼容路径(XWayland) Qt → xcb 插件 → XWayland → X 服务器 输入走 XIM:按【字符串】名字查服务 ② 原生路径(Wayland) Qt → wayland 插件 → 合成器 输入走 text-input:协议握手,不查名字
```
XIM 是按名字查的:应用拿着 `XMODIFIERS` 里那个字符串去找服务,
差一个字符就连不上,而且失败时它不吭声(附录里有完整案例)。
原生 Wayland 没有这一层 —— 输入法由合成器统一调度, 应用和输入法之间是协议握手,不存在「名字对不上」这种失败模式。
所以正解不是「把 XIM 修好」,是「别走 XIM」。
第二步:修改应用程序快捷方式
⚠️ 不要改 `/usr/share/applications/wechat.desktop`。,下次升级就会被覆盖回去了。
拷一份到用户级目录,改那份:
```bashmkdir -p ~/.local/share/applications cp /usr/share/applications/wechat.desktop ~/.local/share/applications/
```
然后把里面的 `Exec` 改成这一行:
```plaintextExec=env QT_IM_MODULE=text-input-unstable-v3 /opt/wechat/wechat %U --ozone-platform=wayland
```
用户级目录里的同名文件会覆盖系统级那个,不用删系统文件,也不用 root。
嫌手改麻烦就在桌面的菜单编辑器里改(KDE 是右键 → 编辑应用程序)。 它会把改完的整份文件写到用户级目录 —— 效果一样,而且是同一个机制。
改完重新从菜单启动微信。已经在跑的进程不会变,得退干净再开。
这两个参数各干什么
分开说,因为它们的作用域完全不同。
`QT_IM_MODULE=text-input-unstable-v3`
让 Qt 用 Wayland 原生的 text-input 协议找输入法,而不是回退到 X11 那套。
这个值是谁认的?实测可以查:
```bashgrep -rl 'text-input-unstable-v3' /usr/lib/qt6/sbom/
```
输出里有 `qtbase-WaylandClient_Attribution_wayland-text-input-unstable-v3` ——
它是 QtBase 自带的 Wayland 客户端实现,编译在 Qt 里,不是外挂插件。
顺带排掉一个误解:它不是 fcitx5 提供的。系统里的 `
/usr/lib/qt6/plugins/platforminputcontexts/` 只有 `compose`、`fcitx5`、`ibus` 三个插件,没有这个名字 —— 它走的是 Qt 自己那条路。
`--ozone-platform=wayland`
把应用里内嵌的 Chromium 组件推上原生 Wayland。
这里要诚实说一句实测结果:
```bashgrep -a -c ozone /opt/wechat/wechat # → 0 grep -a -l ozone /opt/wechat/*.so # → libmmcronet.so、libmmmojo.so
```
`ozone` 这个字符串在主程序里一个都没有,它只出现在 `libmmcronet.so`
(Chromium 的网络栈)和 `libmmmojo.so`(Chromium 的 IPC)里。
也就是说:这个开关管的是微信内嵌网页渲染那一半,不是 Qt 主界面。 打包者把它和上面那条一起给,两条配着用 —— 别只加一条。
⚠️ 为什么写成 `env` 前缀,而不是塞进 `/etc/environment`
把 `QT_IM_MODULE=text-input-unstable-v3` 全局设上,会连 X11 应用一起改 ——
而那些应用恰恰相反,需要的是 `QT_IM_MODULE=fcitx`(Qt 的 X11 输入法模块)。
一个变量,两种应用,需求是相反的。 所以正确的粒度是按应用:
| 作用范围 | 怎么设 | 给谁 |
|---|---|---|
| 全局 | `/etc/environment` 或 `~/.config/environment.d/` |
走 XWayland 的 Qt 应用 → `QT_IM_MODULE=fcitx` |
| 单个应用 | `.desktop` 的 `Exec` 里用 `env` 前缀 |
走原生 Wayland 的 Qt 应用 → `text-input-unstable-v3` |
实测这台机器上就是这么配的,同一个手法用在两个应用上:
```plaintextwechat.desktop Exec=env QT_IM_MODULE=text-input-unstable-v3 /opt/wechat/wechat %U --ozone-platform=wayland chatgpt.desktop Exec=env QT_IM_MODULE=text-input-unstable-v3 chatgpt %U
```
这个模式可以推广:任何「Qt + 跑在 Wayland + 打不出中文」的应用, 先别动全局变量,先给它单独加一个 `
env QT_IM_MODULE=text-input-unstable-v3`。 改错了只影响这一个应用。
怎么验证
① 能打字(这似乎是废话)
打开微信,`Ctrl`(实际切换键盘的按键因人而异),输入法面板弹出来、能输入中文。
② 想确认它真落在 Wayland 而不是 XWayland
```bash# 看这个进程实际拿到的环境变量 pid=$(pgrep -f '/opt/wechat/wechat' | head -1) tr '\0' '\n' < /proc/$pid/environ | grep -E 'QT_IM_MODULE|QT_QPA_PLATFORM'
```
期望看到 `QT_IM_MODULE=text-input-unstable-v3`。看不到就说明 launcher 没生效 ——
多半是还在用旧的桌面缓存,注销重登一次。
更彻底的办法是看它有没有出现在 X11 的客户端列表里 (`
xlsclients`,Arch 上是 `xorg-xlsclients` 包)。 出现在那里 = 还在走 XWayland。这个工具本文没有实测,只作为线索。
附录:如果应用还在走 XWayland
老版本微信、不支持 Wayland 的 Qt 应用、纯 X11 程序 —— 它们还是得走 XIM。 这时才轮到下面这套。
先跑 `fcitx5-diagnose`
它是 fcitx5 自带的体检表,会逐环检查环境变量、X 服务器上的注册名、 Qt / GTK 的 IM module。报错会指名道姓地说哪个变量不对。
| 小节 | 管谁 |
|---|---|
`## Xim:` |
X11 应用 |
`## Qt:` / `## Gtk:` |
对应框架的程序 |
⚠️ 它会打印发行版、内核版本、进程名。脚本自己在结尾也提醒了 —— 贴到论坛之前先自己扫一遍。
⚠️ 莫大的陷阱:尾随空格
`/etc/environment` 里那一行长这样:
```plaintextXMODIFIERS=@im=fcitx
```
看着完全正常。但那最后一个空格会被原样当成服务名的一部分,
而 X 服务器上注册的名字是 `fcitx`(不带空格)。名字对不上就查不到,
查不到它也不报错 —— 表现就是「按了没反应」。
让它现形:用 `cat -A`,它把行尾这类不可见字符显示出来。
```bashcat -A /etc/environment | grep XMODIFIERS
```
```plaintextXMODIFIERS=@im=fcitx $ ← 出错:$ 前面多一个空格 XMODIFIERS=@im=fcitx$ ← 正确:$ 紧贴着 x
```
末尾那个 `$` 是 `cat -A` 给行尾打的标记。它前面挨着的是不是空格,就是全部区别。
怎么修:环境变量有两个独立注入点,别只改一处。
| 机制 | 文件 | 谁读它 | 要 root 吗 |
|---|---|---|---|
| PAM | `/etc/environment` |
`pam_env`,登录时 |
要 |
| systemd –user | `~/.config/environment.d/*.conf` |
systemd 用户管理器 | 不要 |
```bashmkdir -p ~/.config/environment.d cat > ~/.config/environment.d/fcitx5.conf <<'EOF' XMODIFIERS=@im=fcitx GTK_IM_MODULE=fcitx QT_IM_MODULE=fcitx SDL_IM_MODULE=fcitx EOF
```
注意,如果你选择直接复制我的代码,那么建议自行输入最后的 EOF 并回车
改完必须重新登录 —— 环境变量只在会话建立时读一次,新开终端不算。
排错
| 现象 | 可能原因 | 下一步 |
|---|---|---|
| 改完没变化 | 应用还在跑旧进程 | 退干净再启动 |
| 还是没有 | 桌面缓存没刷新 | 注销重登,或 `update-desktop-database ~/.local/share/applications` |
| Wayland 应用也打不出中文 | 输入法没起来 | `pgrep -a fcitx5`;没进程就 `fcitx5 -d` |
| 只有 X11 应用不行 | 走的是 XIM | 看上面的附录 |
`xprop` 说没有 XIM_SERVERS |
不在 X 会话里 | `echo "$DISPLAY"` 要有值 |
参考
- `
fcitx5-diagnose` —— fcitx5 自带的诊断工具,附录部分的第一手来源 - AUR: wechat-bin —— 上面那行 `
Exec` 的建议出处 - Fcitx5 Wiki — 输入法相关环境变量