emacs-在windows上使用emacs内的rimel进行中文输入

为避免频繁编辑主帖导致此贴一直被顶到论坛首页的情况,后续内容可能有更新,请参见我的博客: emacs-在windows上使用emacs内的rimel进行中文输入

[2026-05-14 周四 23:02]

本文全程使用emacs内置的rimel输入法+rime-frost方案写作

Emacs的中文输入一直以来都是一个问题。虽然我们已经有了珠玉在前的sis,可以在Emacs内流畅切换外部输入法,但是在Windows和MacOS上,外部输入法的表现总有一些美中不足:

在Windows上,获取输入法状态的API好像有点问题。根据我个人使用小狼毫的经验来看,当小狼毫在其他程序中切换中英文输入状态时,又或者当你的rime重载后,Emacs往往记住的是先前的状态,导致不得不手动切换一次小狼毫的中英文状态以匹配Emacs内的sis状态。

在MacOS上,问题更加麻烦,广泛使用的Emacs-plus并没有内置的切换输入法API,相反的是GUI Emacs Mac Port有,导致我一直用坛友Lucius的编译脚本为Emacs-plus 打上输入法切换功能的补丁,以适配sis。

而 sis 本身也有一些美中不足。因为它无法判断用户的按键输入是为了在可输入区域内输入文本,还是为了触发一个按键功能,所以在一些时候比较麻烦。比如在 org-agenda 的界面,就可能会出现按下 =t= 键弹出拼音输入框的问题。但内置的输入法就没有这个困扰,只会在可输入文本的场景出现。

幸好,Emacs内部也能调用动态模组,因此涌现了pyimliberimeemacs-rimerimel等充分利用Emacs内置输入功能以及librime的中文输入模组。其中liberime仅用于提供一个动态模组,将Emacs和外部的librime.dll结合起来,因此暂且不将其列入对比。至于剩下的三者,可以在这里查看比较。

我选用 rimel 的原因其实也很简单,单纯是它比较轻量,安装理论上来说相对更容易。我曾经尝试过在Windows 的 Emacs 上安装 emacs-rime ,最终还是被编译动态模块所劝退了。

安装配置 liberime 和 rimel

因为这两者都上了 melpa 且 rimel 依赖着 liberime ,因此我们在写 use-package 的时候仅需要指明 rimel 即可:

(use-package rimel :ensure t

然后我们参考 rimel 和 liberime 给出的说明,进行一番配置。

首先配置 liberime 的 dll 位置以及相关文件夹。
我把 liberime-core.dll 放在了 ~/.emacs.d/bin/ 路径下,以便在多设备下同步。相关的依赖 DLL ,也在同一个位置,我们后面详解有哪些需要复制过来。

  :custom
  (liberime-module-file "~/.emacs.d/bin/liberime-core.dll")

然后我们设置两个关键的文件夹路径: shared-data-dir 决定了共享的基础 rime 配置文件,每次我们启动 rimel 的时候,都会从这个文件夹和 user-data-dir 读取配置文件,并在 user-data-dir 生成一个直接使用的最终build文件夹。两者最好都不放在跨设备同步的文件夹内,还是另外找个地方放起来。我这里是把它们放到了 ~/emacs-local/ 文件夹中。

前者可以先从 liberime 的 release 路径里 /share/rime-data 中复制来。

  (liberime-shared-data-dir "~/emacs-local/rime-data")
  (liberime-user-data-dir "~/emacs-local/rimel")

这里记得配置一下默认输入法为 rimel

  (default-input-method "rimel")

下面这个变量决定了在什么区域自动关闭输入法进入英文模式。

  ;; 推荐配置:代码区 + 字母后 + 大写字母
  (rimel-disable-predicates
      '(rimel-predicate-prog-in-code-p
        rimel-predicate-after-alphabet-char-p
        rimel-predicate-current-uppercase-letter-p)

这里其实也可以再添加一个 rimel-predicate-org-in-src-block-p ,以便在代码块内自动切换成英文。但是需要注意,它用到的函数 org-in-src-block-p 文档中明确指出:所有在 end 之后的空行都会被计算进 src-block 之内。

Note that affiliated keywords and blank lines after are considered a part of a source block.

所以根据实际情况考虑使用吧。

在 GUI 下使用悬浮框展示候选词

;; 可选:使用 posframe 展示候选(如果安装了 posframe,默认会使用 posframe)
  (rimel-show-candidate 'posframe))

安装配置 DLL

注意,由于我用的 UCRT 版本的 Windows Emacs ,因此后续均以次为参考,请读者自行根据 Emacs 版本选择对应 DLL 。

书接上文,如果我们从 liberime 的 release 中直接下载预编译打包好的 DLL 文件,放到前面指明的 liberime-module-file 路径中,会发现根本没办法启动。

根据尝试,这是因为预编译好的文件中仅在 /bin 里有 liberime.dlllibrime-1.dll ,还缺少这两个 DLL 的依赖文件。

具体依赖文件如下:

libgflags.dll
libglog-2.dll
libleveldb.dll
libmarisa-0.dll
libopencc-1.2.dll
libunwind.dll
libyaml-cpp.dll

最简单的方式就是下载一个msys2,然后安装-配置镜像源-更新,安装一个librime,最后在对应的 版本/bin (比如我是 /ucrt/bin )中找到DLL并拷贝即可。

第二简单的获取方式就是找到 msys2 的 package 界面,搜索需要的文件名,然后点击 「File:」 后面跟随的链接,下载解压,并在 /bin 下找到对应 DLL ,复制出来放到前面指明的 liberime-module-file 路径中即可。

调整 rime 配置方案

假如你以上两步均胜利完成,那么重启 Emacs 之后,轻按 C-\ ,随便按几下键盘,应该就能看见候选词出现在 minibuffer 或者 posframe 中了。但细心的你同样发现,怎么打出来的是繁体字啊?这是因为前面复制的默认使用明月拼音,初始输出就是繁体。幸好,我们可以充分利用 rime 的自定义功能,换成我们想用的方案。

但是在你兴高采烈准备使用各种花里胡哨的方案前,不得不提醒一句:由于我们的 liberime 仅使用了 librime ,因此在许多方案中被广泛使用的 LUA 脚本插件、语言模型插件(octagram)均无法在 liberime 中生效使用,因此需要我们手动调整方案。

至于使用什么方案,可以参考 rime-frost 的作者搞的 rime-schema 评测,并着重查看其中没有「_with_gram」的结果。根据 2026 年 5 月 12 日的评测结果,rime_frost 句子正确率: 46.88% 、文字正确率: 86.25% 、文字正确率(逐句平均): 84.87% ,排名前列。所以我后续以 rime-frost 方案为例讲解。

我们从 rime-frost 的 release 下载最新方案压缩包,解压之后将里面内容全部复制替换 user-data-dir 内文件,并直接修改 user-data-dir 内对应文件。

修改默认输入方案

虽然 rimel 提示我们可以通过修改 rimel-schema 变量来修改输入方案,但实践证明没有这个必要,直接修改 default.yaml 就好了。由于我只用小鹤双拼,因此我改为了:

# 方案列表
schema_list:
  # 可以直接删除或注释不需要的方案,对应的 *.schema.yaml 方案文件也可以直接删除
  - schema: rime_frost_double_pinyin_flypy    # 小鹤双拼

然后,进入你选择的方案配置文件中,我这里是 rime_frost_double_pinyin_flypy.schema.yaml ,删除掉其中涉及到 lua 的部分,比如 engine 下,所有以 lua_ 开头的行,都必须删掉。我删除后的结果如下:

# 输入引擎
engine:
  processors:
    - ascii_composer
    - recognizer
    - key_binder
    - speller
    - punctuator
    - selector
    - navigator
    - express_editor
  segmentors:
    - ascii_segmentor
    - matcher
    - abc_segmentor
    - affix_segmentor@radical_lookup  # 部件拆字自定义 tag
    - punct_segmentor
    - fallback_segmentor
  translators:
    - punct_translator
    - table_translator@frost_aux       # ` single-char aux lookup
    - script_translator
    - table_translator@custom_phrase    # 自定义短语 custom_phrase.txt
    - table_translator@melt_eng         # 英文输入
    - table_translator@cn_en            # 中英混合词汇
    - table_translator@radical_lookup   # 部件拆字反查
  filters:
    - reverse_lookup_filter@radical_reverse_lookup  # 部件拆字滤镜
    - simplifier@emoji                              # Emoji
    - simplifier@chaifen
    - simplifier@chaifen_all
    - simplifier@chinese_english
    - simplifier@traditionalize                     # 简繁切换
    - simplifier@mars                               #火星文
    - uniquifier                                    # 去重

一些个人偏好的优化

由于 Emacs 的内部界面寸土寸金,我关闭了候选词备注拼音功能,仅需将 translator:comment_format: 设置为 - xform/.*// 即可。

rimel在启动的时候似乎会错误将 rimel-schema(liberime-current-schema) 进行字符串比较,但后者根本不是一个可行的函数。我们需要手动修改 rimel-active 函数,将

(defun rimel-activate (_name)
  "Activate rimel input method.
Called by Emacs when user selects the \"rimel\" input method.
_NAME is the input method name (unused)."
  (unless (liberime-workable-p)
    (liberime-load))
  (when (and rimel-schema
             (liberime-workable-p)
             (not (string= rimel-schema (liberime-current-schema))))
    (liberime-try-select-schema rimel-schema))
  (setq-local input-method-function #'rimel-input-method)
  (setq-local deactivate-current-input-method-function #'rimel-deactivate))

替换为

(defun rimel-activate (_name)
  "Activate rimel input method.
Called by Emacs when user selects the \"rimel\" input method.
_NAME is the input method name (unused)."
  (unless (liberime-workable-p)
    (liberime-load))
  (when (and rimel-schema
             (liberime-workable-p)
             (not (string= rimel-schema liberime-current-schema)))
    (liberime-try-select-schema rimel-schema))
  (setq-local input-method-function #'rimel-input-method)
  (setq-local deactivate-current-input-method-function #'rimel-deactivate))

内置的 rimel-predicate-org-in-src-block-p 因为直接调用 org-in-src-block-p ,导致代码块换行后难以输入中文。我们直接修改一个自己的判断函数,删去跳过换行、空格功能:

(defun my/rimel-predicate-org-in-src-block-p ()
  "Return non-nil when point is inside an Org source block."
  (and (derived-mode-p 'org-mode)
       (fboundp 'org-in-src-block-p)
       (save-match-data (setq element (org-element-at-point)))
       (when (org-element-type-p element 'src-block)
         (not (or (<= (line-beginning-position)
                      (org-element-post-affiliated element))
                  (>= (line-end-position)
                      (org-with-point-at (org-element-end element)
                        (point))))))))
;; 添加进去
(add-to-list 'rimel-disable-predicates 'my/rimel-predicate-org-in-src-block-p)

补充说明

如果你一切都配置就绪了,但是发现执行 liberime-load 的时候报错,可能是加载路径的问题,可以考虑将 liberime-module-file 所在路径添加到 Windows 的用户环境变量里,然后重启电脑以重新读取用户环境变量,再启动 Emacs 试试。

3 个赞

说到windows上的输入法,可能有人会对这东西感兴趣,供参考:0、我为什么要做柚子输入法 - 简书

注意,由于我用的 UCRT 版本的 Windows Emacs ,因此后续均以次为参考,请读者自行根据 Emacs 版本选择对应 DLL 。

请问UCRT你是怎么安装或者在哪下载的?

不过我是通过scoop添加了它的bucket安装emacs-k,这样可以避免dll文件名损坏。

我使用的也是 scoop install emacs-k 来安装的,但是会出现下面这个错误:

apply: Module could not be opened: "d:/home/.emacs.d/modules/liberime-v0.0.9-windows-ucrt-x86_64-with-deps/bin/liberime-core.dll", "                  "

librime 放在如下的文件夹中 D:\home.emacs.d\modules\liberime-v0.0.9-windows-ucrt-x86_64-with-deps\bin

我安装了 MSYS2,其中的动态库我是从 D:\Scoop\apps\msys2\2026-03-22\ucrt64\bin 目录中复制来的。

这个文件夹我也放到了 PATH 的第一个了

我的配置如下:

(use-package rimel
	:custom
  	(liberime-module-file (expand-file-name "modules/liberime-v0.0.9-windows-ucrt-x86_64-with-deps/bin/liberime-core.dll" user-emacs-directory))
  	(liberime-shared-data-dir "C:/Program Files/Rime/weasel-0.17.4/data")
  	(liberime-user-data-dir "~/rime")
  	(default-input-method "rimel")
  	;; 推荐配置:代码区 + 字母后 + 大写字母
    (rimel-disable-predicates
     '(rimel-predicate-prog-in-code-p
       rimel-predicate-after-alphabet-char-p
       rimel-predicate-current-uppercase-letter-p)
     ;; 可选:使用 posframe 展示候选(如果安装了 posframe,默认会使用 posframe)
     (rimel-show-candidate 'posframe))
    :config
    (defun rimel-activate (_name)
        "Activate rimel input method.
Called by Emacs when user selects the \"rimel\" input method.
_NAME is the input method name (unused)."
        (unless (liberime-workable-p)
            (liberime-load))
        (when (and rimel-schema
                   (liberime-workable-p)
                   (not (string= rimel-schema liberime-current-schema)))
            (liberime-try-select-schema rimel-schema))
        (setq-local input-method-function #'rimel-input-method)
        (setq-local deactivate-current-input-method-function #'rimel-deactivate))
    (defun my/rimel-predicate-org-in-src-block-p ()
        "Return non-nil when point is inside an Org source block."
        (and (derived-mode-p 'org-mode)
             (fboundp 'org-in-src-block-p)
             (save-match-data (setq element (org-element-at-point)))
             (when (org-element-type-p element 'src-block)
                 (not (or (<= (line-beginning-position)
                              (org-element-post-affiliated element))
                          (>= (line-end-position)
                              (org-with-point-at (org-element-end element)
                                                 (point)))))))))

编辑:我猜测是用户环境变量的问题,这里要注意,如果你新修改了用户/系统环境变量,需要重启Windows,否则Emacs不会继承新修改的变量。


这个就是路径问题了,确实很神秘。我今天在另一台电脑上测试了下,相同的DLL,放在之前一直使用的 ~/.emacs.d/bin/ 下就没问题,如果我拿出去放到 ~/emacs-local/bin/ 里,就会报错无法打开。

建议排查一下路径,感觉是环境变量之类的问题,因为我检查了下用户环境变量,里面有 ~/.emacs.d/bin/ ,没有 ~/emacs-local/bin/ 。可以试试把这些依赖dll放到之前可以正常工作的DLL同路径,并指明 liberime-module-file

改了环境变量和动态库的路径还是报错

apply: Module could not be opened: "d:/home/.emacs.d/bin/liberime-core.dll", "                  "

用这个检查liberime librime 两个dll的依赖试试呢

谢谢先,不过看不懂啊,看着都是绿色的也没啥问题啊

1 个赞

那就不清楚了

我今天也试图用自己编译的librime-1.dll,失败了。

可能最简单的方式还是通过msys2安装emacs吧,这样编译也方便一点。

多谢,搞定了。

是怎么解决的呢?

scoop install emacs-k

download https://github.com/emacs-rime/liberime/releases/download/v0.0.9/liberime-v0.0.9-windows-ucrt-x86_64-with-deps.zip

解压缩后,从其中的 bin 目录中复制以下两个 动态库到 ~/.emacs.d/bin

MSYS2 安装 mingw-w64-ucrt-x86_64-liberime

从MSYS2 对应的目录中复制动态库到 ~/.emacs.d/bin目录中

PS D:\home\.emacs.d\bin> dir *.dll

    Directory: D:\home\.emacs.d\bin

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---           2026/4/27    11:07         165741 liberime-core.dll
-a---            2026/3/2    15:14         151364 libgcc_s_seh-1.dll
-a---            2025/9/1    17:09         222908 libgflags.dll
-a---           2025/9/13    15:45         311768 libglog-2.dll
-a---           2025/2/25     0:18         378861 libleveldb.dll
-a---          2025/11/16     2:23         145102 libmarisa-0.dll
-a---           2026/3/20    23:25         656852 libopencc-1.2.dll
-a---           2026/4/27    11:07        2754575 librime-1.dll
-a---            2026/3/2    15:14        2463202 libstdc++-6.dll
-a---          2025/12/24    18:00         224768 libunwind.dll
-a---            2026/3/5    16:44          63678 libwinpthread-1.dll
-a---           2025/11/6    13:33         340684 libyaml-cpp.dll
1 个赞

根据我的排查,应该是更新 GCC 16.1导致的ABI变化引发的问题。msys2于5月2日重新编译了许多package,而liberime的0.09发布时间为4月27日,kiennq的emacs-k发布时间为5月1日。

liberime 利用 github action 调用这个脚本打包

所有依赖安装好以后 有一个copy的过程 目前WITH_DEPS=true只复制了librime 及liberime 其依赖没有做 我没有windows 环境 大家有兴趣的 可以fork 后改下脚本 把需要的依赖梳理验证下 都copy一下 fork后 自己先打个tag 就会自动触发打包

有兴趣的 我可以邀请加入共同维护这个项目

我fork了kiennq的repo,用内置的action编译了最新的windows emacs,然后编译安装了最新的librime包(带4个插件)以及liberime,再将所有缺少的dll移动到emacs便携版的bin路径下后能正常使用liberime和rimel了。

下面是lua的时间脚本效果

所以基本可以确定,之前的无法加载错误,是因为5月2日msys2更新gcc之后引入ABI变动导致的。目前来说等到6月1日kiennq自动更新新版的emacs,再等我提交的msys2的librime更新PR被合并后,就可以通过liberime的action自动构建所需内容了。

不过确实有必要手动指明一下没有随emacs打包来的依赖,我有空提一个PR。

现在使用还是太麻烦了,影响推广呀

这个挺厉害的,我就是看了这个,才想着用emacs hydra也弄一个出来,都是改键工具,hydra可解决我emacs上所有快捷键相关的问题,在把输入法解决好像也不是不行,然而知易行难,现在都还没搞定

使用并不麻烦吧。

rimel是一个基于liberime的emacs中rime前端,同样生态位的还有emacs-rime和pyim。

liberime是在emacs中操作librime的动态模组,需要获取相应的库。

  • 对于macos/linux/msys2这种环境内自带依赖路径的emacs安装,则仅需安装librime,然后获取release中的liberime-core即可,如果没有放在已知路径中则需指明liberime-module-file具体路径;
  • 对于普通的Windows,则需将librime的依赖一并放在liberime-module-file目录内。