Skip to content

使用 Rust 实现 Windows 输入法

kingzcheung
Published date:
Edit this post

这是一个实验,如何使用 Rust 在 Windows 上实现一个输入法?

重复靠轮子毫无意义,除非,你要学习。

TSF

Text Services Framework (文本服务框架)是一种系统服务,主要用于 Windows 平台的键盘处理器、手写识别和语音识别,当然,也包括输入法的实现。

理论上,最小实现只需要一个实现了 TSF 接口的 DLL 就可以了。使用下面的命令注册到系统中,输入法就可以出现在输入法列表中:

regsvr32 "C:\Program Files\SampleIME\SampleIME.dll"

它的大致原理是,在输入的过程中,各个应用会自动调用这个 DLL 来处理按键输入。

但是一个功能完备的输入法肯定不可能只有一个DLL。下面是微信输入法的组件:

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----         2026/5/10     11:33                BuildIn
d-----         2026/5/10     11:33                flutter_datas
...
-a----          2026/5/8     19:27        5816936 wetype_installer.exe
-a----          2026/5/8     19:48        6912048 wetype_renderer.exe
-a----          2026/5/8     19:48        8137776 wetype_server.exe
-a----          2026/5/8     19:48        1201704 wetype_service.exe
-a----          2026/5/8     19:48       18203184 wetype_update.exe
-a----          2026/5/8     19:48         166952 WeUIResource.dll
-a----          2026/5/8     19:48         588336 window_manager_plugin.dll
-a----          2026/5/8     19:48        1430056 WXP2PTransfer.dll
-a----          2026/5/8     19:48       17777712 XNet.dll

可以看到,光exe就有5个模块。因为我们需要处理复杂的输入逻辑、候选栏、系统托盘菜单、设置面板等。

IPC 通信

自然地,这需要一个IPC通信机制,来满足多个输入法模块之间的通信。Windows 上的 IPC 常用的应该是 Windows Named Pipe(命名管道)。

同样地,我们使用 Rime 引擎来处理输入逻辑。

所以处理流程如下:

按键 → TSF DLL → IPC → Server → Rime引擎 → 返回结果 → 显示/上屏

系统托盘菜单(Server)的一些状态变更,也是通过 IPC(WNPipe)来通知的。

能使用 Rust 实现吗?

因为 Rime 引擎是 C++ 实现的,而 Windows 接口也是C/C++ 实现的,所以,理论上,最佳的实现输入法语言应该是C++。

那么,Rust 呢? 当然可以。

首先,微软官方有 Rust 的绑定库:https://github.com/microsoft/windows-rs。 其次,Rime 引擎有 C 接口输出。我们只要对 librime 进行 FFI 封装就可以了。

至此,没有什么障碍了。

架构如下:

graph TB
    subgraph "RIME 模块组"
        LIBRIME_SYS[librime-sys<br/>原生 FFI]
        LIBRIME[librime<br/>高层封装]
        RIME[winxime-rime<br/>引擎封装]
        LIBRIME_C[librime/ 子模块<br/>C++ 库]
    end
    
    subgraph "核心模块"
        IPC[winxime-ipc<br/>IPC 协议]
        CONFIG[winxime-config<br/>配置 + 日志]
    end
    
    subgraph "应用层"
        TSF[winxime-tsf<br/>TSF DLL]
        SERVER[winxime-server<br/>主服务器]
        SETUP[winxime-setup<br/>设置界面]
        REGISTER[winxime-tsf-register<br/>注册工具]
    end
    
    subgraph "Windows 系统"
        WIN_TSF[Windows TSF API]
        WIN_PIPE[Named Pipe]
    end
    
    LIBRIME_SYS --> LIBRIME
    LIBRIME --> RIME
    RIME --> LIBRIME_C
    
    IPC --> TSF
    IPC --> SERVER
    IPC --> SETUP
    
    CONFIG --> TSF
    CONFIG --> SERVER
    CONFIG --> SETUP
    
    RIME --> SERVER
    
    WIN_TSF --> TSF
    TSF --> WIN_PIPE
    WIN_PIPE --> SERVER

实现

由于输入我们交给了 Rime 引擎 ,所以我们需要做的是大概有以下工作:

  1. TSF DLL 通过 IPC 与 server 通信。
  2. 实现候选栏
  3. 实现系统托盘菜单
  4. 实现设置面板

TSF <=> IPC <=> Server <=> Rime 引擎

TSF 接收到应用程序的键盘事件,通过发送 JSON 到管道(管道路径为 \\.\pipe\WinximeNamedPipe),Server 接收请求后,转交给 Rime 引擎处理。

在这个过程中, Server 只是一个中转站,它并不处理输入逻辑,有点类似于 web 开发中的 Controller。

通过 regsvr32 注册 TSF DLL,就可以在 Windows 系统中看到输入法。

设置列表 输入法实现

实现候选栏

候选栏采用 Direct2D + DirectComposition + DXGI SwapChain 的组合方案,而非传统的 GDI 或 WPF。

采用这个方案主要有2点原因:

  1. 高性能,无外部依赖,候选栏并不会有太多的交互和复杂的元素,额外引用 GUI 库没有太大的必要。
  2. 候选栏实现在 server 模块,而整个server 模块也只有候选栏需要实现UI。

输入法实现

系统托盘菜单与设置菜单

事实上,实现候选栏已经完成了输入法的MVP功能。如果还需要输入法像商业输入法一样的话,就那实现系统托盘菜单了。比如,中/英 切换,输入法配置入口等。

问题

事实上,这个项目最大的难度不在于开发,而在于调试。

相对于一般的应用开发,输入法开发要难调试一些。由于它并不是一个单体应用,而是由一个 DLL 和一堆 exe 组成。

因为 windows 自带的卸载根本无法干净地卸载,它只能卸载其中一个,而dll和安装目前还存在于电脑中。所以,一个友好的独立卸载工具是必须的。

Previous
使用 Rust 实现 Linux 输入法
Next
Xime 输入法的2.0