Emacs for Windows的TUI IME支持

目录

本文介绍我给 GNU Emacs for Windows 上对于 TUI 的IME输入法支持.
相关的 bug报告.

1. 问题描述

在终端里面启动 emacs (emacs -nw), 输入中文字符串完成按下回车或者候选数字
emacs接收不到结果.

2. 前置知识

首先要了解Windows上的控制台方面api, 且了解Emacs相关代码

GNU Emacs政策禁止AI编写代码, 要遵循相关政策知道贡献指南.
开发流程通过邮件列表和linux一模一样.

参考链接

3. 修复过程

commit的链接

原先代码有一个分支会忽略emacs自己的状态键

if (faked_key == event->wVirtualKeyCode)
  {
    faked_key = 0;
    return 0
  }

问题出现在这个分支上, IME消息发送时, event->wVirtualKeyCode的值为0,
同时faked_key未赋值也是0, 就把IME消息给忽略了.

修复的地方同时还有处理读取字符版本的分支, emacs需要兼容Windows 9x版本,
也就是是上世纪的Windows 95等, 所用到的api会有大量ascii版本带A后缀的.

所以emacs会有多个flag变量来判断支不支持Unicode, 当前代码需要用到的变量是
w32_console_unicode_input.

原先代码的判断逻辑

if (event->uChar.AsciiChar == 0)
  {
    // ...
  }
else if (event->uChar.AsciiChar > 0)
  {
  // ...
  }

这个分支的判断可能在几十年前是对的, 但是现在是错误的. 根据微软文档 KEY_EVENT_RECORD
结构体的uChar类型是一个 AsciiChar 低8位, UnicodeChar 高16位的联合体

union {
  WCHAR UnicodeChar;
  CHAR  AsciiChar;
} uChar;

所以得先判断高位的UnicodeChar, 不然会混进AsciiChar的数据导致乱码.

if ((w32_console_unicode_input && event->uChar.UnicodeChar < 128)
    || (!w32_console_unicode_input && event->uChar.AsciiChar > 0))

这样判断就能有效判断是ascii支持还是unicode, 同时还兼容了上世纪的代码.

相关技术细节bug报告会更详细.

4. 后日谈

这是我第二次给GNU项目贡献代码, 非常有趣的一次贡献, 改动的代码虽然小, 但花费了我大量的
时间和精力, 隐约有掉头发的感觉, 最后代码成功合并到emacs的master主线了.

日期: 2026-09-03

作者: 赵大牛