惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
人人都是产品经理
人人都是产品经理
IT之家
IT之家
T
The Blog of Author Tim Ferriss
V
V2EX
博客园 - 聂微东
The Cloudflare Blog
Blog — PlanetScale
Blog — PlanetScale
A
About on SuperTechFans
U
Unit 42
Vercel News
Vercel News
L
LangChain Blog
博客园 - 司徒正美
H
Help Net Security
Recent Announcements
Recent Announcements
Recorded Future
Recorded Future
V
Visual Studio Blog
Jina AI
Jina AI
Microsoft Azure Blog
Microsoft Azure Blog
GbyAI
GbyAI
Y
Y Combinator Blog
C
Check Point Blog
博客园 - 三生石上(FineUI控件)
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
J
Java Code Geeks
The Register - Security
The Register - Security
The GitHub Blog
The GitHub Blog
B
Blog RSS Feed
F
Fortinet All Blogs
B
Blog
G
Google Developers Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
云风的 BLOG
云风的 BLOG
爱范儿
爱范儿
MongoDB | Blog
MongoDB | Blog
F
Full Disclosure
有赞技术团队
有赞技术团队
罗磊的独立博客
博客园_首页
MyScale Blog
MyScale Blog
aimingoo的专栏
aimingoo的专栏
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence
N
Netflix TechBlog - Medium
Engineering at Meta
Engineering at Meta
量子位
I
InfoQ
小众软件
小众软件
P
Proofpoint News Feed

暗无天日

读:AI Agent 安全日志——从可见性与隐私的两难说起 - 暗无天日 读:AI Agent 生产化——一份从原型到上线的速查清单 - 暗无天日 AI写作的语言指纹——如何让文字不那么像机器 - 暗无天日 读:50 条 Claude Code 技巧——一个工程经理的六个月使用心得 读:AI 辅助开发为什么让 E2E 测试更有价值 - 暗无天日 读:在Emacs中使用Claude Code(Spacemacs适配版) - 暗无天日 Claude Code 背后的工程哲学——读 Agent Harness Engineering 读:Agent Harness Engineering——AI 智能体不只是模型,还有套件 - 暗无天日 browser-harness:让 AI 直接接管你的浏览器 - 暗无天日 读:Security-First CI/CD —— DevSecOps 自动化实践指南 TIL: 数字小键盘的小数点陷阱与行内算术求值 - 暗无天日 读:Immutability 不是万能药,它是一种权衡 - 暗无天日 Conducty:给 Claude Code 加上项目记忆和并行执行能力 - 暗无天日 读 — GitHub Trending 里的 Claude Code 技能包 读 — Prompt Caching 省钱指南 TIL: Emacs 中那些跟鼠标配合的冷门快捷键 - 暗无天日 读:Anvil——把 Emacs 变成 AI 的工具服务器 读:Emacs 代码折叠终极指南 - 暗无天日 读:Clojure 搭车客指南 - 暗无天日 git推送失败后恢复仓库损坏的完整记录 - 暗无天日 多智能体系统的两个有效模式——以及对 Claude Code 用户的启示 - 暗无天日 用 Org Babel 写 Literate 博文:扩展执行 + 定制导出 proced:Emacs 内置的进程查看器 - 暗无天日 从 proced 定制中学到的 Elisp 模式 读:让 Emacs proced 在 macOS 上显示 CPU 和内存 异步编程的函数着色税 - 暗无天日 链式调用的代价:JavaScript 和 Clojure 的共同教训 - 暗无天日 hyperfine:命令行基准测试工具 - 暗无天日 管道中的变量去哪了?——子 shell 作用域陷阱 - 暗无天日 开源包装器的信任陷阱:四个危险信号 - 暗无天日 程序员愿意为 AI 写文档,却不愿为同事写 - 暗无天日 mktemp: Shell 脚本中临时文件的安全陷阱与最佳实践 - 暗无天日 WSL9x —— 在 Windows 9x 里跑 Linux 内核 6.19 用 ox.el 做你想做的事 —— org-export 高级编程指南 读:Hot-wiring the Lisp Machine —— 用纯 Elisp 构建零依赖的 Org 静态站点生成器 Elisp 性能优化的六个实战教训 - 暗无天日 ERT 测试交互命令的三种方式 - 暗无天日 SEM Assistant: 当 Elisp 守护进程遇上 LLM 用 dmsg 给 Elisp 加上结构化调试日志 用 org-habit 追踪非每日习惯 - 暗无天日 Clojure X-Men:当编程语言特性变成超能力 - 暗无天日 TIL: 用 diff-hl 在 fringe 中显示 git 变更 读:llm-test —— 用 LLM agent 驱动 Emacs 测试 TIL: AI 时代的橡皮鸭调试 - 暗无天日 fcitx 启动后键盘输入卡顿的排查 - 暗无天日 TIL: 早期网页的图片热区导航 - 暗无天日 读 Seeing the Whole System 用 Emacs 自动生成每周链接推荐 - 暗无天日 读:ASCII control characters in my terminal 读 What to learn - 暗无天日 Lisp 的括号之痛——一个愚人节玩笑揭开的老伤疤 - 暗无天日 一本书该"线性读"还是"并行读" - 暗无天日 读 How to Monetize a Blog:一篇伪装成变现指南的讽刺文 Python Mock 第三方依赖的四种策略 - 暗无天日 Emacs Lisp 热重载实用指南 - 暗无天日 Prot 的 Emacs 配置哲学 - 暗无天日 TIL: 从直播对谈中学到的三个 Emacs 技巧 - 暗无天日 TIL: 自动使用项目虚拟环境的 Python - 暗无天日 TIL: 让 Help buffer 自动获得焦点 一条命令让本地开发用上 HTTPS —— slim 工具介绍 用 fsck 检查和修复 Linux 文件系统 排查Linux进程"卡死"实战:从strace到gdb全流程 - 暗无天日 PostgreSQL 索引:从基础到你可能不知道的高级用法 - 暗无天日 用 .pdbrc 自定义 Python 调试器 ANSI 转义码的标准化现状 - 暗无天日 终端程序的潜规则 - 暗无天日 PARA Org-mode 测试配置 - 暗无天日 AI越强越辣鸡?控制论说这是必然的 - 暗无天日 AI 越强越需要你盯着——反馈循环实操指南 - 暗无天日 你的AI代理正在偷你的密钥——四种你没想到的泄露通道 - 暗无天日 LLM 在 DevOps 中的三种角色 - 暗无天日 写作风格的反建议 - 暗无天日 反驳本质复杂性——Dan Luu 论为什么《没有银弹》错了 - 暗无天日 文件充满了危险——Dan Luu 谈文件系统的可靠性陷阱 - 暗无天日 AI 时代的 PARA 方法:用 Org-mode 和 AI 打造个人知识管理系统 Linux 数据去重学习笔记 - 暗无天日 创建跨平台 ZIP 文件的隐藏陷阱:Extra Field - 暗无天日 X11 Forwarding 排障指南 - 暗无天日 IP欺骗端口扫描:当别人冒充你去扫描别人 - 暗无天日 Linux 输入栈全景解析:从硬件按键到屏幕响应 - 暗无天日 Unix 系统中那些被埋没的配置开关——以 FontConfig 为例 - 暗无天日 在Linux上限制儿童使用电脑 - 暗无天日 GIF不仅仅是一种图片格式——用GIF流做些奇怪的事 - 暗无天日 Leiningen 学习笔记:Clojure 项目构建与管理从入门到实战配置 - 暗无天日 Google SRE Book 读书笔记 - 暗无天日 yes 管道 head 发生了什么 - 暗无天日 为什么 nohup 在 crontab 中不起作用 Bash中的Indirection与Nameref - 暗无天日 Linux PAM 简介 - 暗无天日 从Linux ISO文件启动计算机 - 暗无天日 用 Bash 打造一个Screen Locker 用GitHub Actions自动构建EGO博客 - 暗无天日 blocking I/O 的作用 - 暗无天日 mobileog 手机端同步提示Error:2 No such file 的解决方法 回收 WSL2 VHDX 文件占用空间 使用 org-mode columnview 生成任务列表 - 暗无天日 Emacs 作为 MPD 客户端 - 暗无天日 移动文件路径却不破坏org file link的方法 - 暗无天日 如何合理的导出help link 成HTML - 暗无天日 笑话理解之Biology - 暗无天日
fcitx5 下 Emacs 无法切换输入法的排查 - 暗无天日
2026-04-23 · via 暗无天日

背景

我之前从 fcitx4 升级到了 fcitx5,解决了键盘输入卡顿的问题(详见fcitx 启动后键盘输入卡顿的排查)。升级后,普通应用(浏览器、终端等)都能正常切换输入法,唯独 Emacs 不行——按切换快捷键毫无反应,只能输入英文。

故障现象

  • fcitx5 在其他应用(Firefox、终端等)中正常工作
  • 在 Emacs 中无法切换到中文输入法
  • Emacs 是通过 systemd user service 以 daemon 模式启动的
  • 系统为 Arch Linux,Emacs 版本 31.0.50,使用 Lucid(Xaw)工具包

排查过程

第一步:检查环境变量

输入法框架依赖三个关键环境变量来告诉应用程序"该用哪个输入法"。我先检查了当前 shell 中的值:

echo "GTK_IM_MODULE=$GTK_IM_MODULE"
echo "QT_IM_MODULE=$QT_IM_MODULE"
echo "XMODIFIERS=$XMODIFIERS"
GTK_IM_MODULE=fcitx5
QT_IM_MODULE=fcitx5
XMODIFIERS=@im=fcitx5

三个变量都有值,看起来没问题。

小知识:这三个环境变量是干什么的?

Linux 下的应用程序通过三种不同的协议连接输入法:

  1. XMODIFIERS=@im=xxx :告诉 所有 X11 应用 ,通过 XIM 协议连接名为 xxx 的输入法服务器。这是最古老的方案,几乎所有 X 应用都支持,但功能最基础。
  2. GTK_IM_MODULE=xxx :让 GTK 应用 加载专门的输入法模块,比 XIM 体验更好(支持光标跟随、预编辑文字等)。
  3. QT_IM_MODULE=xxx :同理,让 Qt 应用 加载专门的输入法模块。

简单来说:=XMODIFIERS= 是万能兜底方案,=GTK_IM_MODULE= 和 QT_IM_MODULE 是各自框架的增强方案。

第二步:运行 fcitx5-diagnose

fcitx5 自带了一个诊断工具,可以自动检查各种常见配置问题:

fcitx5-diagnose

诊断结果里出现了多处警告:

环境变量 XMODIFIERS 的值被设为了"@im=fcitx5"而不是"@im=fcitx"。
请检查您是否在某个初始化文件中错误的设置了它的值。

环境变量 GTK_IM_MODULE 的值被设为了"fcitx5"而不是"fcitx"。
环境变量 QT_IM_MODULE 的值被设为了"fcitx5"而不是"fcitx"。

诊断工具建议把所有值从 fcitx5 改成 fcitx 。看起来很合理——虽然软件叫 fcitx5 ,但输入法模块注册的名字可能不带版本号。

于是我按建议修改了 ~/.xinitrc

export GTK_IM_MODULE=fcitx5
export QT_IM_MODULE=fcitx5
export XMODIFIERS="@im=fcitx5"

export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=fcitx
export XMODIFIERS="@im=fcitx"

但问题没有解决——Emacs 还是无法切换输入法。

小知识:=.xinitrc= 是什么?

当你用 startx 命令启动图形界面时,=X 服务器= 会读取 ~/.xinitrc 这个文件,执行里面的命令来初始化桌面环境。通常在里面设置环境变量、启动输入法、启动窗口管理器等。

第三步:发现 Emacs 是 systemd 服务启动的

我意识到一个关键问题:我的 Emacs 不是从 .xinitrc 启动的,而是通过 systemd user service 以 daemon 模式在后台运行的。

小知识:Emacs daemon 模式

Emacs 可以以"守护进程"方式运行(=emacs --fg-daemon= 或 emacs --daemon=),在后台常驻。之后用 =emacsclient 连接到这个后台进程来打开窗口。好处是:

  • 启动速度极快(不用每次都重新加载配置)
  • 多个客户端共享同一个 Emacs 进程(状态、缓冲区等)

这意味着 Emacs 的环境变量 不来自 .xinitrc ,而是来自 systemd service 文件中的 Environment 配置。查看服务文件:

cat ~/.config/systemd/user/emacs.service
[Service]
Type=simple
ExecStart=/usr/bin/emacs --fg-daemon
Environment=... GTK_IM_MODULE=fcitx QT_IM_MODULE=fcitx XMODIFIERS="@im=fcitx" ...

果然!Emacs 的环境变量是独立的:

  • GTK_IM_MODULE=fcitx
  • QT_IM_MODULE=fcitx
  • XMODIFIERS"@im=fcitx"

看起来都是正确的

第四步:发现根因——XIM 服务器名称不匹配

既然 .xinitrcemacs.service 都设了 XMODIFIERS ,那问题出在哪里?我检查了 fcitx5 实际注册到 X 服务器的 XIM 服务名称:

xprop -root XIM_SERVERS
XIM_SERVERS(ATOM) = @server=fcitx5

然后检查 Emacs 进程实际的 XMODIFIERS 值:

cat /proc/$(pgrep -x emacs)/environ | tr '\0' '\n' | grep XMODIFIERS
XMODIFIERS=@im=fcitx

找到根因了!

  • fcitx5 注册的 XIM 服务器名: @server=fcitx5
  • Emacs 的 XMODIFIERS 值: @im=fcitx

两者不匹配!XIM 协议要求 XMODIFIERS 的值必须和 XIM 服务器的注册名一致。Emacs 拿着 @im=fcitx 去找名为 fcitx 的 XIM 服务器,但实际注册的名字是 fcitx5 ,当然找不到。

小知识:XIM 协议的连接机制

XIM(X Input Method)是 X11 的输入法协议,工作流程是:

  1. 输入法框架(如 fcitx5)启动后,在 X 服务器上注册一个 XIM 服务器,名字形如 @server=fcitx5
  2. 应用程序读取 XMODIFIERS 环境变量(如 =@im=fcitx5=)
  3. 应用程序拿着这个名字去 X 服务器上查找对应的 XIM 服务器
  4. 找到后建立连接,输入法就可以工作了

如果 XMODIFIERS 的名字和 XIM 服务器注册的名字对不上,应用程序就找不到输入法服务器,输入法自然无法使用。

这也说明 fcitx5-diagnose 的建议是 误导 的:它建议把 XMODIFIERS 改成 @im=fcitx ,但 fcitx5 的 XIM 服务器偏偏注册为 fcitx5 。对于通过 XIM 协议连接输入法的应用(比如使用 Lucid 工具包的 Emacs),这个建议反而是错的。

第五步:确认 Emacs 走的是 XIM 而非 GTK 模块

为了确认我的 Emacs 确实走 XIM 协议,我检查了 Emacs 的构建特性:

emacs --batch --eval '(princ (format "%s\n" system-configuration-features))'
... X11 XDBE XIM XINPUT2 ... LUCID ...

关键信息:

  • XIM ——Emacs 支持 XIM 协议
  • LUCID ——Emacs 使用 Lucid(Xaw)工具包,不是 GTK

Lucid 工具包不使用 GTK_IM_MODULE ,只走 XIM 协议。所以对 Emacs 来说,唯一重要的环境变量就是 XMODIFIERS ,而且它的值必须和 XIM 服务器注册名一致。

解决方案

明确了根因后,修复很简单:

修改 emacs.service 中的 XMODIFIERS

XMODIFIERS"@im=fcitx"= 改为 XMODIFIERS"@im=fcitx5"= :

# 修改前
Environment=... XMODIFIERS="@im=fcitx" ...

# 修改后
Environment=... XMODIFIERS="@im=fcitx5" ...

重启 Emacs 服务

systemctl --user daemon-reload
systemctl --user restart emacs

修改后确认 Emacs 进程的环境变量已更新:

cat /proc/$(pgrep -x emacs)/environ | tr '\0' '\n' | grep XMODIFIERS

重启后 Emacs 中顺利切换到中文输入法,问题解决。

恢复 .xinitrc

由于我的桌面环境也使用 fcitx5 ,且 fcitx5 的 XIM 服务器注册名为 fcitx5 ,所以 ~/.xinitrc 中的值保持为 fcitx5 是正确的:

export GTK_IM_MODULE=fcitx5
export QT_IM_MODULE=fcitx5
export XMODIFIERS="@im=fcitx5"

复盘

根因链条

fcitx5 注册 XIM 服务器名为 "@server=fcitx5"
  → emacs.service 中 XMODIFIERS="@im=fcitx"
    → 名称不匹配
      → Emacs 通过 XIM 找不到输入法服务器
        → 无法切换输入法

走过的弯路

这次排查最大的弯路是 轻信了 fcitx5-diagnose 的建议 。它建议把所有环境变量从 fcitx5 改成 fcitx ,我照做了,但这反而让 XMODIFIERS 和 XIM 服务器名不匹配的问题更加恶化了。

关键经验

  1. xprop -root XIM_SERVERS 可以查看 XIM 服务器注册名 :排查 XIM 问题时,先确认服务器叫什么名字,再和 XMODIFIERS 对比
  2. systemd 服务的环境变量是独立的 :不继承 .xinitrc 或 shell 的环境,需要在 service 文件中单独设置。遇到服务启动的程序出问题时,用 cat /proc/$PID/environ | tr '\0' '\n' | grep XXX 检查实际的环境变量
  3. 诊断工具的建议不一定全对 :=fcitx5-diagnose= 的建议在大部分场景下是对的,但对于 XIM 这种特殊场景会给出错误建议。理解原理比盲目执行建议更重要
  4. Emacs 的工具包决定了它用什么输入法协议 :Lucid 走 XIM(看 XMODIFIERS ),GTK 走 GTK IM Module(看 GTK_IM_MODULE )。排查前先搞清楚 Emacs 用的什么工具包