您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 企业财务 > 基于XIM协议的输入法原理与实现
基于XIM协议的输入法原理与实现1关于本文的由来这段时间,项目上需要在XWindow中实现一个自动输入的功能。具体说来就是对于任意的控件,只要焦点落在该控件上,并且该控件为可输入的控件,就在光标位置处自动输入一串特定的字符。我是通过实现一个特殊的输入法完成了这个功能的。或者,还有更好的办法?若有请读者告知。不胜感激!参考了几位前辈的文章,查阅了相关的文档,使我对输入法的原理有了一定的了解。所以写下本文,当作一个小结。2XIM输入法原理输入法的作用,主要是为了解决键盘的按键数不足的问题,其原理简单说起来就是把一串由按键所产生的字符串转变成我们所要输入的字符串,然后通过某种方式通知等待输入的应用程序可以输出字符串了。在这个过程中,等待输入的应用程序与输入法之间必然要有一个沟通的规则,XIMProtocol就是这种规则之中的一个。当XIMClient(可以理解成应用程序的窗口)打开输入法时,通常情况下,会导致XLibrary和XServer之间建立一条连接。基于XIMProtocol的中文输入流程如图1:图1首先要注意,(1)按键是由XServer接收的,这一点只要明白了XWindow的工作机制就不难理解了。(2)XServer在接收到按键后,会转发到相应程序的窗口中。在窗口的处理函数中,可以选择是否响应按键等,这里假定窗口是可输入的,(3)这时窗口将收到的按键回传给XServer,询问XServer关于XIMServer的相关信息。倘若输入法是打开的,(4)XServer会将事件发送给XIMServer(也就是输入法)去处理。XIMServer通过某种方式(例如,查码表)将按键转换成特定的字符串,(5)之后返回给XServer。(6)XServer得到字符串后,再通知窗口输出字符串。事实上,图1是输入法两种体系结构中的一种,叫做Client/Server模型,还有一种叫Library模型的,它主要是用于处理欧洲语言的输入,这里也作介绍。在windows系统中,输入法的工作过程也是比较类似的,这里就不再做说明了,请看如图2:图2在XWindow中,有一个叫做Xi18n的概念,也就是XWindow的国际化。用Xlib来设计支持国际化的widget是很麻烦的,在Xwindow中如果你想支持中文的输入输出,除了有输入法的存在外,还必需自己在程序中编程设置Locale和XMODIFIERS环境,产生FontSet,打开输入法,对输入法进行操作等等。具体可以参考《XlibProgrammingManual》第一卷和参考3。但是现在有很多界面库如gtk、qt,都对国际化有了很好的支持,这些库说到底是使用Xi18n的相关库帮我们做了一些烦琐的事情。设置XWindow的国际化软件虽然与输入法的实现并无太大的关系,但是作为初学者,有时却会把它与实现输入法混为一谈。3基于XIM输入法的实现首先可以阅读一下《TheInputMethodProtocol》(forX11R6),但是这个协议对于我们来说都太难实现,事实上也没有必要自己去实现。我们可以用现成的IMdkit来实现基于XIM的输入法。IMdkit(IMServerDevelopsKit)是X11R6的Xi18n执行工作组发布的XIM服务器开发工具,它提供了一个低级的C语言接口,把每个IM协议操作都绑定到了简单的C语言接口,这样用户就可以很容易的使你的IM服务器与XIM客户程序通讯,而不用直接处理复杂的IM协议。(参考2)3.1IMdkit中重要的API函数介绍IMdkit的API文档中详细介绍了各个API函数(参考7)。现就其中的一些函数作一个简单的说明。XIMSIMOpenIM(Displaydisplay,...):为IMServer初始化连接,并设置一个或者多个IMValues。若成功,返回XIMS一个结构,失败返回NULL。char*IMSetIMValues(XIMSims,...):注册IM的值。比如IMSetIMValues(ims,IMProtocolHandler,MyProtoHandler,NULL)的意思是将回调函数设置成MyProtoHandler这个函数。这里顺便说一下IMProtocolHandler,它标识当IMServer接收到XIMClients的输入时所调用的回调函数。voidIMCloseIM(XIMSims):关闭IMServer的连接,并清理相关的资源。3.2在XIMServer中主要处理的IM消息我们在由IMProtocolHandler标识的回调函数中,要处理的消息主要有:XIM_OPEN:XIM客户程序(也就是我们的应用程序窗口)打开输入法时,要在IMLIBRARY和IMSERVER之间建立逻辑连接。XIM_CLOSE:关闭在IMLIBRARY和IMSERVER之间建立的逻辑连接。XIM_CREATE_IC:当客户程序创建了一个输入法上下文(InputContext,IC)时,发送这个消息协议到IMSERVER,这时在IMSERVER中为此IC申请了一个相应的结构,用于记录一些必要的信息,包括字体、位置、前背景色等等。XIM_DESTROY_IC:当客户程序退出时,删除相应的IC,释放一些与IC相关的存储空间。XIM_SET_IC_VALUES:设置当前连接IMSERVER的IC的属性。这个消息会定期产生。XIM_GET_IC_VALUES:取得当前连接IMSERVER的IC属性。XIM_FORWARD_EVENT:当有按键发生时,客户程序发送这个消息到IMSERVER。在相应的处理函数中,读出相应的键值,如果是一些控制键,就作相应的操作,如输入法的开启,不同输入法之间的切换等;如果是输入法不需要处理的键,就直接送回客户程序,如一些功能键,组合键等;否则调用输入法的处理程序,输入法处理程序对这个字符进行处理,此时在预编辑区和选择区会有相应的变化,如果有结果字符串生成,输入法服务器会按照开始时确定的编码方式把这个字符串发送到客户程序,这样就完成了一次输入过程。这也就是整个输入法的核心部分的。XIM_SET_IC_FOCUS:当在不同的应用程序间进行切换时,当前的IC会发生变化,此时新的应用程序会发送这个消息到IMSERVER,输入法服务器会改变当前的焦点,当前的一些与IC有关的属性和全局变量也要有相应的变化。XIM_UNSET_IC_FOCUS:当前IC失去焦点。在此处可以释放一些与当前IC相关的资源。XIM_RESET_IC:重置在IMSERVER中的IC的状态。XIM_TRIGGER_NOTIFY:IMLIBRARY通知IMSERVER匹配启动(on-keys)和关闭(off-keys)的事件发生了。下面是一段fcitx运行时记录下来的日志,可以看出在打开输入法的过程中消息的顺序:XIM_OPEN:icid=0connect_id=1XIM_CLOSE:icid=0connect_id=1XIM_OPEN:icid=0connect_id=1XIM_CREATE_IC:icid=0connect_id=1XIM_GET_IC_VALUES:icid=1connect_id=1XIM_SET_IC_FOCUS:icid=1connect_id=1XIM_SET_IC_VALUES:icid=1connect_id=13.3一个简单输入法的代码结构1.初始化X环境,创建窗口:if((dpy=XOpenDisplay((char*)NULL))==NULL){……returnFalse;}iScreen=DefaultScreen(dpy);mainWin=XCreateSimpleWindow(dpy,DefaultRootWindow(dpy),0,0,50,50,0,0,0);XMapRaised(dpy,mainWin);……上面代码段的mainWin就是输入法的状态栏了。当然了,如果要实现一个真正的XIM输入法,还要有候选词窗口,输入窗口等等。2.初始化输入法:ims=IMOpenIM(dpy,IMModifiers,Xi18n,IMServerWindow,mainWin,IMServerName,youIMName,IMLocale,strLocale,IMServerTransport,X/,NULL);if(ims==(XIMS)NULL){……returnFalse;}IMSetIMValues(ims,IMProtocolHandler,MyProtoHandler,NULL);IMSetIMValues(ims,IMFilterEventMask,KeyPressMask|KeyReleaseMask,NULL);在IMOpenIM函数的参数设置可以参考IMdkitAPI文档,这里不再多讲了。IMProtocolHandler的值就是主要的IM消息处理函数了。下面还会讲到。3.在主函数的结尾处放置X消息循环:for(;;){XNextEvent(dpy,&event);if(XFilterEvent(&event,None)==True)continue;}4.编写IM消息处理函数:这个函数的格式为:BoolMyProtoHandler(XIMS_ims,IMProtocol*call_data){switch(call_data-major_code){caseXIM_OPEN:caseXIM_CLOSE:caseXIM_CREATE_IC:caseXIM_DESTROY_IC:caseXIM_SET_IC_VALUES:caseXIM_GET_IC_VALUES:caseXIM_FORWARD_EVENT:caseXIM_SET_IC_FOCUS:caseXIM_UNSET_IC_FOCUS:caseXIM_RESET_IC:caseXIM_TRIGGER_NOTIFY:}}要对每个major_code的值进行不同的处理。特别要指出的是XIM_FORWARD_EVENT,这个消息的处理过程实现上就是判断按键、查码表、返回字符,这也是整个输入法的核心部分了。3.4关于XIM输入法的实现建议上面所讲的一切,是不足以让一个初学者完全实现一个基于XIMprotocol的输入法的。所以建议从阅读开源代码(如fcitx)开始,先了解XIM的工作原理和IMdkitAPI,然后尝试修改开源代码。我想这样比从第一行代码开始编起容易得多。最后,如果你想实现自己的输入法,你不妨考虑一下采用更先的输入法技术如ibus。
本文标题:基于XIM协议的输入法原理与实现
链接地址:https://www.777doc.com/doc-2572972 .html