Linux下面的输入法,似乎都不太好用,总觉得与搜狗,紫光拼音有点差距,做完第一个开源辞典软件:AlphaDict后,决定自己做一个试试看, 没想到一下子掉入了好大的一个”坑“里,足足花了近一年的时间,不过,好歹总算是做出了一个1.0版本,一个基本可用的输入法。做完以后,很累也很失落,坑太多,没有那么多得精力去填满它,所以,感觉这个输入法用得人估计不会太多。写这篇文章来同大家聊一下,如何开发一个输入法。
一:输入法协议
首先肯定是要研究,了解系统支持的输入法协议,它是整个输入法,最基础的部分。
在X11环境下,这确是一个大坑,它不像windows那样有一个强制的,统一的标准。x11的输入法扩展协议是xim,但不是所有的程序都会支持,有的程序只是支持部份feature,导致拿不到准确的输入位置等。无论如何,我觉得xim,还是值得去支持的。AllphaIM目前也只对xim提供了支持。
xim协议
推荐文档是《XlibProgramming Manual》(xlib.pdf)里面的第11章”InternationalizedText Input” 和 《TheInput Method Protocol》(xim.pdf)这两篇文档看完后,会大概了解xim的协议框架,具体到编程, 还需要去找xim的一个实现IMdkit,可惜这个库估计早就不被支持了,ubuntu发行版的仓库里面没有,最终,我在http://xorg.freedesktop.org/archive/unsupported/lib/IMdkit/找到了,可以通过ftpxorg.freedesktop.org来下栽,由于该库好久不更新,有一些明显的bug,需要修正后,才能跑起来。一边学习该库自带的sample,一边进行调试,不明白的地方,还要查看xlib的源码(libx11),逐步地从理论到实践来掌握xim编程的技术,它的基本原理大概是:
imserver启动后,会使用_XRegisterFilterByType来注册过滤器Xserver,client则需要callXFilterEvent来callback到imserver的过滤器。_XRegisterFilterByType XFilterEvent 这一对函数用来在client端,过滤imserver的event,代码片断如下:
IMdkit: xi18n_openIM
_XRegisterFilterByType(dpy, i18n_core->address.im_window,
SelectionRequest, SelectionRequest,
WaitXSelectionRequest, ims);
client:
XNextEvent(dpy,&event);
if(XFilterEvent(&event, None))
continue;
switch(event.type) ....
感觉是X11通过selection机制来实现两个窗口之间的通讯,它们通讯的规范就是XIM协议。
client把按键事件转发给imserver,server翻译后,再把最终文本回传给client。
x11应用程序如何找到imserver呢? 就是通过XMODIFIERS环境参数。
当x11应用程序启动后,它会读取分析XMODIFIERS环境参数,来得到imserver window id, 通过XSendEvent来把消息发给imserver。
libx11大概流程的源码片断是:
fun:XOpenIM --> _XDefaultOpenIM -->_XimPreConnect
这一路主要是分析环境参数@im=xx,检查支持的local等,得到imserver的windowid,im_name等等(im->core.im_name = @im=xx)
imserver= XInternAtom(display, XIM_SERVERS, True)
im_window= XGetSelectionOwner(display, atoms[i]))
-->(str = XGetAtomName( display, atoms[i] ))
-->check str == im->core.im_name
getthe selectionowner's window id
XSendEventto im_window.
所以,一个完整的xim输入法流程,是这样的:
1:配置输入法的环境参数: XMODIFIERS="@im=xxx"
2:运行imserver.
3:运行客户端软件。激活输入法,输入拼音,得到汉字
一定要先运行imserver , 再打开客户端软件,否则输入法不起作用,如果,imserver(输入法进
程)意外crash,再重启的话,所有的客户端软件,都需要重新打开一下,不然,输入法不起作用。
二:输入法的核心功能
xim方面的工作完成后,是典型的万里长征的的第一步,接下来是输入法功能的开发,作为一个智能拼音输入法,最基本的功能无非是:汉字/词组查找,优先级排序, 用户词组记录。
首先,汉字和词组的搜索匹配:关键点是数据结构的创建, 是使用sqlite类的文件型数据库,还是自己创建呢?我仍然使用的是同AlphaDict一样的树来做为基本存储结构,只不过,AlphaDict里面的树是只读的,而AlphaIM需要读写功能,需要添加用户词组,修改优先级。
其次,用户词组记录:这里面有两个问题,一是敏感数据处理,二是如何认定用户输入的是词组。
相关数据处理,可以加密,然后就是当用户切换到非中文的时候,就不要记录。基本上,只要不记录数字和字母等非中文,就不会记录用户的敏感数据。
如何认定用户的输入为词组呢?
我使用的是笨方法,一:用户如果是整句输入的,我就认为是词组而添加到用户词典。同时,把用户输入的汉字记录下来,当达到比如说3000个的时候,分析一下这些汉字,两个以上汉子有重复的就人为是词组。然后,添加到用户词组。
这样一来,随着用户使用的时间越来越长,它的词库会越来越多,达到一定数量后,需要根据优先级清理一下,把一些不常用,或误判断为词组的清理掉。
做到这里,一个基本可用的输入法就完成了。
可是Linux/X11还有一个大坑,就是输入法的配置,各个发行版本的配制文件,都有一些小的差异,而且,各发行版都会自带一套输入法,需得先卸载掉系统自带的输入法,取消先前的配制,对系统不太熟悉的人,估计又是一个不小的挑战。
sf: https://sourceforge.net/projects/aphaim/
github: https://github.com/kartorz/AlphaIM