关于输入法的工作原理及编程 - 奔跑吧人生

时间:2024-03-10 18:01:39

关于输入法的工作原理及编程

缘起

在windows下使用的sougou输入法,除了经常弹出广告,没有什么异常行为,Linux下的中文输入法似乎没那么强大好用了。起初用的是Ibus中的pinyin,后来因为机缘巧合装了yong输入法,发现挺好用的,就一直用着。渐渐的发现yong输入法在一些*软件中不起作用,有时还行为诡异,虽然大多数的时候,工作的很正常。本着程序员好奇的心态,我想打开输入法这个黑匣子,看看里面有些什么。

正文

1. 简介

输入法的工作原理是击键消息(window中消息)首先送给输入法管理器(前端),输入法管理器调用输入法的转换函数(输入法引擎),输入法的转换函数得到击键消息并保存在自己的数组中,当符合规定条件时(如五笔输入法输入:四键、两键+空格等),输入法把适当的字、词返回给输入法管理器,输入法管理器再把结果字、词传给关联的应用窗口。

简单的来说,输入法就是一个查表操作,输入的信息是键盘信息,根据击键消息到表中查找对应的汉字。举个例子:将码表导入到Excel。假设码表是基于拼音的,码表分两列,一列是拼音,一列是汉字串,那么用鼠标点击编辑->查找,在查找内容框中敲入shishi,点击查找下一个按钮,黑色矩形框立即就跳到A列的shishi的行上面,对应的B列就是“试试、事事、实施、时世、史实……”等等这些汉字串,输入法的原理就是这样[2]。PS:计算机程序中都可以简化为查表程序,这个表可能是数组,字符串或者数据库。表驱动编程本质上就是从数据的角度出发,根据数据来编程(参考《代码大全 第二版》)。

由于输入法编程中涉及消息处理机制,而消息处理机制是操作系统的核心机制,理解起来比较麻烦。但是,“学习输入法编程,要带着问题学,活学活用,学用结合,急用先学,立杆见影,在“用”字上狠下功夫。为了把输入法编程的精髓真正学到手,要反复学习输入法编程的结构和算法,有些概念、算法最好要背熟,反复学习,反复运用。”[2] PS:这段话可以简化为:世上无难事,只要肯攀登。

关于在windows下学习输入法编程的资料搜集如下:

1.输入法工作原理:http://blog.csdn.net/shuilan0066/article/details/6883629

2.输入法漫谈:http://wenku.baidu.com/view/3d179422bcd126fff7050b9d.html(备注:原文发布在某论坛上,地址为:)

Linux下的输入法框架无非Scim/Ibus/Fcitx这三类。在网上搜了一通,仅发现一篇关于Scim工作原理的论文,ibus和fcitx都是相应的google代码库,估计源码和文档都应该很全。个人感觉,用scim的人不如ibus和fcitx多了,开发也不及后两者了。但是scim有这么一篇2页的论文,省去看ibus之类的文档和源码,而且既然同样都是输入法框架,总会存在一些共性的特征,相差不到那里去。

2. SCIM

基于XIM结构的输入法与X Windows系统结合过于紧密,无法支持国际化语言环境,SCIM就是针对这些问题的。Smart Common Input Method(SCIM),SCIM输入法架构的优越性: 1.支持语言多 2.面向对象设计 3.高度模块化,功能模块,插件形式 4 编程接口简单 5. 独立于图形界面,便于开发和移植

2.1. SCIM的结构设计

SCIM包含的模块:

  • l 配置模块(Config):配置模块最主要的功能就是为应用程序配置共享信息,以防冲突。所有的配置信息都由Config统一进行管理,其他模块存取配置信息都需要通过向它发送请求。SCIM的配置文件由Config文件和Global文件组成,前者保存的是与输入法相关的配置信息,如输入法引擎、快捷键等参数,后者保存的是与输入法无关的配置信息,如socket超时、socket地址等信息。SCIM中的配置模块有不同的实现,但这些实现都必须遵循ConfigBase接口规范。
  • l 前端模块(FrontEnd):前端模块的主要功能是接受输入法服务进程中来自客户端应用程序的的请求,然后把请求转发给具体的输入法引擎或者配置模块,最后把处理的结果返回给刚才请求的客户端应用程序(在这里,输入法是作为一个服务进程来实现的)。SCIM输入法前端也有不同的实现,这些实现都遵循FrontEndBase接口规范。
  • l 引擎模块(IMEngine):输入法引擎的功能是实现具体的输入法。比如要实现全拼输入法,五笔输入法,首先需要实现一个输入法引擎,然后将其编译成一个动态库,放在指定的目录之中。所以其它输入法都是以单独的软件包发行的,不属于SCIM的核心。SCIM中的输入法引擎也有多种实现,这些实现都遵循IMEngineInstanceBase接口。
  • l 进程间通信模块(IPC):SCIM采用的本地socket(参考*uix中BSD Socket API,是一种进程间通信的方式)方式。应用层协议封装在Transaction中,它主要负责把特定的请求或事件等打包成数据包和从数据包中取出请求或事件。Socket实现数据的实际传输。服务器端使用SocketServer,客户端使用SocketClient。无论是服务器端还是客户端,Transaction并不关心,因为它使用的是Socket的抽象接口。
  • l 输入法Panel:对于输入法来说,Panel是不可缺少的一部分。Panel的主要功能是提供给用户比较直观的感受,如候选字,联想词组等,也提供了一些辅助功能,如全角半角切换,中英文切换、标点切换、查看帮助信息等。Panel是有图形用户界面的,且必须要与特定的GUI绑定起来,SCIM虽然实现了一个基于GTK的Panel,但它是一个完全独立的工具,不管用哪一个GUI实现Panel,大部分代码都是相同或者相似的,只要稍做修改即可。SCIM把Panel模块的代码封装在PanelAgent和PanelClient这两个类中。前者实现所有和面板相关的socket协议,后者处理所有面板和前端的socket通信,前端用PanelClient来Panel后台进程进行交互。
  • l Helper模块:SCIM把一些新的输入法方式,如手写输入法等进行特殊处理,通过Helper集成进来。SCIM提供了一个HelperAgent类,这个类的功能是把手写输入法的结果提交给应用程序。

2.2. 工作原理

在SCIM中,输入法有三大功能模块:前端(FrontEnd),引擎(IMEngine)和后端(BackEnd)。这三大模块分别实现的功能是:

FrontEnd:主要负责用户界面的显示,以及与客户程序进行交互,将客户程序的按键请求转发给IMEngine,执行IMEngine发出的各种命令,如绘制预编辑字符串等等。FrontEndBase基类负责管理所有IMEngineInstance实例。

IMEngine:接收FrontEnd发送的按键事件,然后向FrontEnd发送相应的命令,如显示预编辑字符串、向客户程序提交字符串等等。

BackEnd:管理所有的IMEngine。如全拼、双拼、五笔、手写等。

在SCIM中最关键的部分是FrontEnd和IMEngine。这两部分的实现及其之间的通讯方式(本地socket)是SCIM较其它输入法平台最不同的地方。

FrontEnd主要完成用户界面的绘制、与客户应用程序交互,FrontEndBase基类负责管理所有IMEngineInstance实例这三方面工作。每个IMEngineInstance 实例用唯一的id进行标识,FrontEndBase类提供的函数和IMEngineInstance的id完成对IMEngineInstance的所有操作。FrontEnd派生类不需直接处理IMEngineInstance实例或者其指针。

IMEngine分为IMEngineFactory和IMengineInstance两个接口类。要实现具体的输入法,比如纵横汉字输入法,就必须提供这两个类的具体实现。IMengineFactory除了负责管理如词库等的输入法涉及的公共数据,还负责创建IMEngineInstance实例。IMEngineInstance类则负责把实际的按键转换为字符串。

FrontEnd和IMEngine之间的数据通信采用了一种松散的接口形式,即signal-slot技术,这样的方式可以简化编程接口。输入法引擎所需的所有动作都经由signal-slot发送给FrontEnd,而输入法引擎需要处理的事件则直接由FrontEnd调用IMEngineInstance类的相应函数来传递。

2.3. 吐槽

参考[4]的论文中存在一些文字错误,重复以及术语的前后不一致,明显有整合和拼凑的感觉,看了一下其参考文献,百度文库和一篇csdn的博客赫然在列,让我对该中文期刊的质量表示怀疑,去看了一下引用的源后,果然是整合的,前半截+图来自文库,后半截来自博客,对于这种拼接法搞学术,表示强烈的鄙视,虽然我也经常干这种事情,但是我copy & paste的技术绝对比他们好,感觉有点五十步笑百步。

强烈建立参考原出处,原出处的文章具有一致性和连贯性,不是拼接的,而且更加图文并茂:

1.SCIM输入法架构分析(上)http://blog.csdn.net/absurd/article/details/1151404

2.SCIM输入法架构分析(下)http://blog.csdn.net/absurd/article/details/1151524

3. IBUS

Intelligent Input BUS(iBus)是一个输入法平台,可以理解为是一个已经写好的与系统交互的库,各种输入法运行在iBus上。iBus曾经是Python写的,现在已经用C++重写,效率得到很大的提高,兼容性要远远强于Scim。iBus可以让程序员专心地编写输入法功能的代码,而不是把过多的精力浪费在与系统交互上,从而增强输入法的可移植性。

Ibus的wiki上的介绍:http://en.wikipedia.org/wiki/Intelligent_Input_Bus (百度百科上的介绍过时太久了)

Ibus在Ubuntu系统上安装:http://wiki.ubuntu.org.cn/IBus

Ibus项目地址:http://code.google.com/p/ibus/

4. Fcitx

Fcitx的wiki介绍:http://en.wikipedia.org/wiki/Fcitx

Fcitx还和搜狗合作开发Linux上的搜狗输入法,其在Ubuntu(Linux Mint)的安装参考http://1.techblog.sinaapp.com/?p=283#more-283

Fcitx的google项目地址:http://code.google.com/p/fcitx/

Fcitx的GitHub地址:https://github.com/fcitx/fcitx

Fcitx的安装:http://wiki.ubuntu.org.cn/Fcitx

5. Yong输入法

Yong输入法基于ibus的,但是又和Ibus上的输入法ibus-pinyin之类的不太一样。

输入法论坛及下载:http://yong.dgod.net/

安装可参考:http://blog.csdn.net/xiajian2010/article/details/9625131 

具体的,我也不是特明白其实现机制,先留给伏笔,等以后我明白了再加。

 

仔细查看了yong提供的帮助和相关的文档,发现在当前Home目录下的.yong中存在这样的一个文件pinyin.usr,打开后可以看到如下模式的文本:

{0}aihe 爱喝

{-}anquanjiang 安全将

{0}anshenye 安神液

{0}ansong 暗送

{0}aojiao 傲骄

{0}badi 拔地

{0}baiban 白板

{0}bailv 百虑

{0}baishikuai 百十块

{0}baiyou 柏油

{1}baiyou 柏由

{0}baiyulan 白玉兰

在看到有一些自己常用的输入后,想到yong的帮助提到的造词和删词的功能(快捷键操作太难用),估计就是通过在文件中设置{}中的数字实现,{-}表示删除,{0}或{1}行为不太明白,在文件中添加新词表示造词。修改该文件后,发现并没有能禁止,将yong进程杀死,再重启就起效了,看来yong默认会将该文件加载到内存中去,回想上面介绍的输入法就是查表操作,这个pinyin.usr就是这样的表,除了这个表以外,还有个pinyin的主表是安装目录yong/mb/下的pinyin.txt和pypre.bin,打开pinyin.txt后,其文件内容是:

name=ƴ??

key=abcdefghijklmnopqrstuvwxyz

len=63

wildcard=?

pinyin=1

split=\'

hint=0

user=pinyin.usr

assist=mb/yong.txt 2

code_a1=p..

[DATA]

a ?? ?? ?? ?? ?? ?? ߹

aba ????

adou ????

aduwu ??????

在[DATA]目录下的字母对应的字符为不可识别,估计是对怕pypre.bin中的二进制的数据的索引,但又觉得不太像。

根据帮助文档的,将一些不需要的文件删除了,只剩下3M了,同样也能工作,感觉非常好。安装目录yong保留的文件如下:

yong目录下的:libl.so(基础库),libmb.so(码表库),yong(主程序),yong.conf(配置文件),yong.ini,yong-tool.sh(安装卸载脚本),yong.chm(帮助文档),keyboard.ini(软件盘配置文件),normal.txt

skin目录全部保留

mb目录只保留我需要的拼音输入法(pinyin.ini,pinyin.txt,pypre.bin)和english.txt

gtk-im目录下的动态连接库也需要保留,不然连输入框都不显示。

yong-config二进制程序也要保留,这个图形配置界面的程序。

备注:看到yong官方将输入法更新到了2.1,不清楚作者怎么设置版本号的,试用了一段时间,发现很不稳定,常常打字不上屏,害我要将进程杀死再重启,相当麻烦,我又退回1.7,用了很久,非常稳定。

后记

本来想好好的了解一下输入法,以及我使用的Yong输入法的,结果只是在搜集资料,了解一些很宽范的东西。在搜集资料的时候,看到一个关于学习方法的观点:重基础胜于技巧,看书胜于看杂志,看代码胜于看文章,和朋友讨论胜于上论坛,写BLOG胜于看BLOG,以及学习方法无好坏之分,只有合适不合适之分,所谓天下殊途同归,一致百虑。

二手文献和原始文献之间,存在一条加工的沟,而且并不是所有的二手文献都比原始文献好。

Linux Mint的界面蛮好看的,有机会尝试一下。

参考文献

[1]SCIM输入法架构分析:http://wenku.baidu.com/view/a33b1484bceb19e8b8f6baea.html

[2]输入法漫谈:http://wenku.baidu.com/view/3d179422bcd126fff7050b9d.html

[3]关于Ibus拼音的开发:https://www.byvoid.com/blog/join-develop-ibus-pinyin/

[4]SCIM输入法架构及其工作原理,王丽君,李培峰,China Academic Journal Electronic Publishing House 

[5] 我的学习方法:http://blog.csdn.net/absurd/article/details/6475353