通用输入法

Cim 是 Common Input Method(通用输入法) 的缩写。

在 Linux 和 BSD 环境中,输入法体系目前是碎片化的。 应用程序和 GUI 工具包依赖 XIM、Gtk-IM、Qt-IM、Wayland-IM 等不同标准,因此集成复杂且缺乏一致性。

Cim 是 为统一这些不同输入法接口而设计的软件

Cim 并不将输入法绑定到特定的 GUI 工具包,而是提供 独立于工具包的 C API,使应用程序和框架能够以一致的方式使用输入法。

Cim 的公共接口以 cim.h 中定义的 稳定 C ABI 为核心进行设计。因此,可以在以下不同环境中使用相同的输入法边界。

  • GUI 工具包
  • 终端应用程序
  • 控制台程序
  • 沙盒环境中的应用程序
  • 使用不同编程语言编写的软件

因此,Cim 可以作为 不同环境中文本输入的通用基础设施

架构

Cim 使用 插件架构(plugin architecture)

应用程序可以使用以下任一种形式的公共 Cim API 库:

libcim.a
libcim.so

libcim.a 是位置无关的 static-pic 形式,可以嵌入共享模块中。libcim.so 是可重定位(relocatable)的共享库形式。 不支持非 PIC 静态库。

真正的输入法实现由 插件模块(plugin modules) 提供。

以下路径是插件部署方式的 示例。这并不表示当前公共仓库已经实现或分发下面列出的所有插件。

/usr/lib/input.d/im-sample.so
/usr/lib/input.d/im-nimf.so
/usr/lib/input.d/im-ibus.so
/usr/lib/input.d/im-uim.so
/usr/lib/input.d/im-fcitx.so

当前公共代码树中包含 im-libhangul.so,作为原生示例插件。

每个插件都实现 cim.h 中定义的 Cim 输入上下文 API

插件可以通过多种方式实现:

  • 原生引擎插件 直接实现完整的 IME 引擎。

  • 框架桥接插件 将 Cim 与 ibus、fcitx 等现有输入法框架连接起来。

  • 服务型插件 与守护进程或外部服务通信。

无论采用哪种实现方式,所有插件都导出一个名为 cim_plugin 的小型描述符,其中包含用于描述输入上下文创建与管理方式的 CimIcVTable

当前公共 ABI 版本为 2.1.1。插件会在 cim_plugin 中记录 Cim API 版本;如果 major 版本不兼容,Cim 会拒绝该插件。 CimIcVTablecreatedestroy 是必需的。插件的 initfini 回调是可选的;如果提供,则每次成功的宿主连接(host attachment)初始化都会有一次对应的结束处理。

选择活动插件

活动插件通过以下符号链接选择:

~/.config/cim/plugin

该链接指向要使用的插件模块。

示例:

mkdir -p ~/.config/cim
ln -sf /usr/lib/input.d/im-sample.so ~/.config/cim/plugin

例如,如果 fcitx 桥接插件 已经实现并安装在以下路径,则可以这样进行选择。该命令仅为使用示例,并不表示当前公共仓库提供 im-fcitx.so

ln -sf /usr/lib/input.d/im-fcitx.so ~/.config/cim/plugin

这种方式避免依赖环境变量,因为在某些应用程序启动环境中环境变量可能不存在。 同时也更容易实现图形化配置工具。

在测试或受控部署环境中,可以通过 CIM_PLUGIN 环境变量指定绝对插件路径,临时覆盖该符号链接。

使用 Cim

配置完成后,应用程序或 GUI 工具包只需调用 Cim API。

当创建第一个 CimIcHandle(输入上下文)时,Cim 运行时会加载选定的插件,初始化一个宿主连接(host attachment),并将输入法操作委托给该插件。

一个宿主连接(host attachment)中可以创建多个输入上下文。最后一个上下文销毁后,Cim 会结束该宿主连接并卸载插件。

这种设计既能保持运行时轻量,也允许灵活的插件实现。

与现有工具包的集成

即使显示服务器或 GUI 工具包没有直接采用 Cim,也可以通过桥接模块进行集成。

以下是工具包和输入系统集成中使用的 环境变量示例。当前公共代码树已经实现 GTK 3 和 Qt 6 桥接。XIM 设置用于说明未来或外部集成的可能方式。

QT_IM_MODULE="cim"
GTK_IM_MODULE="cim"
XMODIFIERS="@im=cim"

以下是桥接模块可能使用的 安装路径示例。当前公共代码树中实际实现的桥接是 GTK 3 和 Qt 6。 GTK 2、GTK 4 和 Qt 5 路径用于说明可能的扩展,并不表示当前已经实现。

/usr/local/lib/gtk-4.0/4.0.0/immodules/libim-cim-gtk4.so
/usr/local/lib/gtk-2.0/2.10.0/immodules/im-cim-gtk2.so
/usr/local/lib/gtk-3.0/3.0.0/immodules/im-cim-gtk3.so
/usr/local/lib/qt5/plugins/platforminputcontexts/libqt5im-cim.so
/usr/local/lib/qt6/plugins/platforminputcontexts/libqt6im-cim.so

这些桥接模块使现有应用程序无需修改代码即可使用 Cim。

在默认的 static-pic 配置中,当前的 GTK 3 和 Qt 6 桥接模块会嵌入 libcim.a,同时使嵌入的 Cim 运行时符号对周围进程保持不可见。

基于守护进程的输入系统

某些输入系统,例如 XIMWayland 输入法,需要进程间通信。

对于这类环境,Cim 可以采用如下守护进程式架构。不过,下面的 cimd 二进制文件和守护进程插件路径 只是架构示例,当前公共代码树尚未实现

/usr/local/bin/cimd

守护进程插件示例:

/usr/local/lib/cimd/plugins/cim-xim.so
/usr/local/lib/cimd/plugins/cim-wayland.so

如果实现这些组件,它们可以把 XIM 或 Wayland 输入事件转换为 Cim API 调用。

面向输入法开发者的优势

Cim 可以显著降低输入法开发者的集成负担。

传统上,输入法需要分别为以下环境实现不同模块:

  • Gtk-IM
  • Qt-IM
  • XIM
  • Wayland-IM

Cim 被设计为使用 Cim 输入上下文 API 作为公共边界,使同一个输入法实现能够在不同环境的集成层中复用。 当前公共代码树已经实现 GTK 3 和 Qt 6 桥接;GTK 2、GTK 4、Qt 5、XIM 和 Wayland 集成目前并未全部实现。

另一个重要优势是 低摩擦集成(low-friction integration)

许多现有 IME 库(如 libhangul、librime、libanthy、libpinyin)已经提供核心输入逻辑。 在这种情况下,只需通过 CimIcVTable 暴露现有功能的 小型适配层 即可实现 Cim 插件。

即使 upstream 项目没有直接加入 Cim 支持,也可以用相对较少的代码在外部实现 独立的桥接插件

这种灵活性使 Cim 能够在无需大规模改变现有架构的情况下与输入法生态系统集成。

总结

Cim 提供:

  • 独立于工具包的输入法 API
  • 简单的插件架构
  • 带明确版本的稳定 C ABI
  • 较低的现有 IME 实现集成成本
  • 通过桥接模块与现有输入法框架兼容的架构
    • 当前公共代码树已实现 GTK 3 和 Qt 6 桥接。
    • 其他桥接及基于守护进程的集成目前尚未全部实现。

通过将 输入法 API 与 GUI 工具包和显示服务器分离,Cim 为 Linux 和 BSD 环境提供了更加一致且可移植的文本输入基础。

Cim 技术支持 / 1年

24/7 电子邮件支持 $ 30

下载

Cim 以源代码形式分发。

最新源代码 — GitHub 公共仓库