Poky环境的中文输入法实验

2019-07-13 07:28发布

1 概述

Poky是一个简洁的嵌入式Linux图形环境。在poky中实现中文显示比较容易,主要是设置区域和增加中文字体。实现中文输入就要复杂一些。我尝试过移植scim或fcitx,但都碰到同样的问题:poky环境的xim用不起来。我写了一个IMdkit的测试程序,在调用IMOpenIM后,我登记的回调函数收不到任何XIM呼叫。我想这个问题可能是poky对xlib的简化引起的。 为了回避xim问题,我改用Gtk的IMContext接口。输入法引擎基本上照搬fcitx,重写了接口和显示部分。另外还写了一个GTK的IM模块。

2 工作原理

2.1 程序框架

程序构架如下图所示。 GTK的IM模块派生自GtkIMContext接口。它负责把编辑窗口的输入法事件传递给输入法程序,并将输入法程序返回的文本用"commit"信号提交给编辑框。输入法程序接收IM模块传来的输入法事件,显示预编辑信息,并将用户选择的文本发送给IM模块。

2.2 输入法程序

输入法程序可以分成三块:
  1. 接口部分。这部分负责与客户程序通信。目前它是和GTK的IM模块通信。如果要改成基于XIM的输入法,主要是重写这块。
  2. 输入法引擎。这部分基本照搬fcitx。不过我去掉了fcitx的大部分全局变量,只保留了几个简单的接口。只要能实现几个接口函数,就可以把引擎替换掉。
  3. 用户界面。这部分负责状态窗口、候选窗口的绘制。
三个部分用一些简单的接口代码连接起来,基本上可以独立测试。例如我先在windows的VC环境调好输入法引擎。然后调好IM模块和输入法程序接口部分的通信。最后才是绘制界面。

2.3 IM模块和输入法程序的通信

IM模块和输入法程序用socket通信。IM模块通过GTK的io channel接收socket数据。输入法程序用select同时接收X事件和通过socket传来的输入法事件。

2.4 IM模块的实现

中文输入需要显示预编辑输入和候选字词。根据这些输入信息的显示位置,XIM总结了4种输入法风格:
  1. root-window就是在输入法窗口显示所有输入信息。
  2. over-the-spot就是输入法程序将输入信息显示在一个小窗口里面,小窗口随光标移动,例如:
  3. on-the-spot就是由客户程序直接在光标位置显示预编辑输入,例如:
  4. off-the-spot是由客户程序提供一个显示窗口,由输入法程序负责绘制。
在Windows中,通常只有输入法感知的程序才能实现on-the-spot,即客户程序要处理输入法信号。在GTK中,GtkIMContext提供了预编辑接口,所以由IM模块和输入法程序配合就可以实现on-the-spot,不需要客户程序直接参与。 不过,为了简单起见,我还是使用了over-the-spot的风格。这样只需要重载5个接口: static void mb_im_context_class_init (MbIMContextClass *klass) { GtkIMContextClass *context_class = GTK_IM_CONTEXT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); context_class->set_client_window = mb_im_context_set_client_window; context_class->focus_in = mb_im_context_focus_in; context_class->focus_out = mb_im_context_focus_out; context_class->filter_keypress = mb_im_context_filter_keypress; context_class->set_cursor_location = mb_im_context_set_cursor_location; } 在focus_in和focus_out显示或隐藏输入法窗口。set_client_window和set_cursor_location收集光标位置,传给输入法程序。 filter_keypress将按键信息传给输入法程序。 字母和数字按键都可以异步处理,即这些按键都交给输入法程序,不需要编辑窗口处理。有的按键需要同步处理。例如退格键,首先交给输入法程序,如果输入法程序认为这个键未处理,就要再返还给编辑窗口处理。因此对于此类按键,im模块要同步等待输入法程序的响应。

3 结束语

scim的框架有78597行代码,拼音输入模块有13917行代码。 fcitx有28542行代码,其中IMdkit库有10000行代码,调用IMdkit库的xim.c有800行代码。我写的IM模块有842行代码,输入法程序有7230行代码,其中服务器接口部分只有291行代码。虽然我的程序是实验性的,但这也说明使用GtkIMContext接口比使用XIM接口要简单一点。 但基于GtkIMContext的输入法只能用于GTK程序,在兼容性上要弱于基于XIM的输入法。所以以后还是可以尝试一下重新构建poky,去掉影响xim功能的简化。