内容


XIM协议的原理及其实现

引言

1.输入法

世界上大多数语言是基于字母表的,一些字母的集合组成了单词,当在计算机中输入这些语言时,用户通常是在键盘上键入相应的字符或一些组合键来实现。但表意文字(如中,日,韩等)却不能在键盘上找到相应的键,如果想在计算机中输入这些文字,就需要相应的输入法。输入法有很多种,如拼音,五笔等,但这些输入法的一个共同的特征是用户敲多个键来组成一个文字(或一组文字),统称为编码输入。

2.XIM协议

XIM(X Input Method)是X-Window系统下的符合国际化标准的输入法协议,只要应用程序和系统都支持这种输入协议,应用程序就不必具体考虑在不同语言环境下的输入问题,系统可以根据相应的locale去寻找相应的输入法,从而达到国际化的要求。

XIM的原理

1.体系结构

  • 1.1 实现模型 在X-Window 系统环境下,XIM的实现有以下两种典型的体系结构:

    1)Client/Server模型:

    IM服务器是一个独立的进程,由它来处理输入、预编辑、转换和确认。IM库存在于应用程序中,就象IM服务器的一个客户,它只是简单的从IM服务器接收确认字符串。

    2)Library模型:

    所有的输入都由应用程序中的IM库来处理。事件处理在IM库中就被关闭了,所以就不再需要一个独立的IM服务器。

    大多数语言,如亚洲语言一般都有复杂的预编辑,所以都采用Client/Server模型来实现,其他的只有一些死键或组合键的语言,如欧洲语言一般都采用Library模型来实现。

    下面主要都讨论Client/Server模型,如图1所示:

    客户程序通过连接IM服务器来实现XIM输入,它们之间的通讯是利用XIM的协议来实现的。IM子系统完成文字查找和文本的组合。

  • 1.2 IM结构 当客户程序向服务器发出连接或断开请求时,在客户和服务器之间会产生打开和关闭操作。

    函数XopenIM()设置或修改客户的locale,IM是根据相应的locale来指定的。另外,客户支持的IM类型可以通过函数XGetIMValues()来获得。

    一个客户程序通常有多个输入域,Xlib提供了一个结构“Input Context”(IC)来管理每个输入域。函数XCreateIC()可以指定XIM并创建一个相应的IC,函数XDestroyIC()用来删除此IC。许多重要的信息,比如确认字符串都通过IC来从IM服务器送到客户程序。每一个IC与一个输入域相关,函数XSetICFocus()用来通知IM服务器当前IC获得了焦点(XUnSetICFocus()表示失去焦点)。

  • 1.3 事件处理模型 现存的输入法都支持前端输入法和后端输入法或其中的一种。XIM把后端输入法作为一种默认的输入法,但也支持前端输入法。

    1)后端输入法:

    在后端输入法中,客户窗口的输入事件总是送到IM库中,然后IM库把此事件送到IM服务器中。事件以传送的顺序来处理,因此在IM库和IM服务器中没有需要同步的问题。

    2)前端输入法:

    在前端输入法中,客户窗口的输入事件由XServer直接传送到IM库和IM服务器中。因此这种方法提供了更好的接口性能(尤其在IM服务器运行在一台工作站而客户程序运行在另一台工作站上,且网络又相对较慢时)。而,前端模型在处理键的时候有同步问题,时会引起事件丢失或时间重复。因此后端输入法是由核心输入法支持的,前端输入法是从扩展性能的目的出发的。

  • 1.4 事件流控制

    XIM协议在IM库和IM服务器之间的通讯支持两种事件流:静态和动态。

    1)静态事件流是客户程序的输入事件总是发送到IM服务器。

    2)动态事件流是输入事件中需要处理的事件发送到IM服务器。例如,在即输入ASCII字符又输入中文字符的时候,ASCII字符就不必送到IM服务器了。因此,采用动态事件流后,在XServer、客户和IM服务器之间的需求事件大大减少了,从而性能有所提高。IM服务器发送XIM_REGISTER_TRIGGERKEYS事件来切换动态事件流。

2.简单协议处理模型

下图2是一个最简单的协议流的例子:

当应用程序发生按键事件时,它调用Xlib API的XNextEvent函数,对于后端输入法模型,事件都由IM库来处理,IM库先发出XIM_FORWARD_EVENT作为同步请求,IM服务器接收到此协议后发出XIM_FORWARD_EVENT或XIM_COMMIT作为同步应答,双方完成同步。然后,IM服务器阻塞从IM库接收到的XIM_FORWARD_EVENT消息,进行处理,结束后把结果返回到应用程序。

XIM开发工具IMdkit简介

IMdkit(IMServer Develops Kit)是X11R6的Xi18n执行工作组发布的XIM服务器开发工具,它提供了一个低级的C语言接口,把每个IM协议操作都绑定到了简单的C语言接口,这样用户就可以很容易的使你的IM服务器与XIM客户程序很容易的通讯,而不用直接处理复杂的IM协议。XIM客户程序是指利用在X11R6中定义的XIM API国际化过的应用程序。IMdkit封装了实际的IM协议操作,这样用户自己就不必处理实际包,可以利用它提供的数据结构,简化了许多细节麻烦;封装了不同的传输机制(包括X协议,TCP/IP,DECNET),这些协议用来在IM库和IM服务器之间传输数据包;封装了多种IM协议模型,包括Ximp和Xi18n。

IMdkit定义了一个不透明的数据结构XIMS,用来抽象输入法服务器的结构。它由函数IMOpenIM返回,函数IMOpenIM如果成功的话,返回一个XIMS结构,否则返回NULL。

对于每一个XIM协议输入,在IMdkit的头文件中都定义了一些相应的结构,对于R6标准的IM协议模型,中定义了所有的IM协议结构。

1)IM协议的通用数据结构

在R6的标准IM协议模型中,所有的事件结构有如下的通用成员:

	typedef	struct{
	int	major_code;
	int	minor_code;
	CARD16	connect_id;
	}

major_code和minor_code指定了唯一鉴别这个IM协议类型本身的常量名。connect_id指定了连接的客户ID。

2)协议处理

一些由IM库发送的IM协议请求由IMdkit内部处理了,不需要发送到IM服务器。因为IMdkit会根据你在XIMS结构中设置的值来决定对这个IM协议请求的应答。需要处理的一些IM协议请求参看下面介绍的XIM的实现。

XIM的实现

以下讨论的具体实现是利用IMdkit开发的XIM服务器。

1.初始化输入法服务

	ims = IMOpenIM(display,IMModifiers,”Xi18n”,IMServerWindow,window,
		IMServerName,imname,IMLocale,DEFAULT_LOCALE,
		IMServerTransport,transport,IMInputStyles,input_styles,
		IMProtocolHandler,MyProtoHandler,IMEncodingList,encodings,NULL);

函数IMOpenIM初始化输入法服务的连接,并设置一个或多个由变长的参数列表指定的IM的属性。

下面简介上面函数中的参数:

Display是当前的屏幕显示。

IMModifiers定义XIM的协议模型,有两种:

“Xi18n”指定R6标准的IM协议模型。
“XIMP”指定R5标准的Ximp模型。

IMServerWindow指定IM服务器的窗口以便于与XIM客户程序进行通讯。

IMServerName指定IM服务器的名字。

IMLocale指定IM服务器支持的locale列表。

IMServerTransport指定IM服务器用来与客户程序间的通讯技术。

IMIputStyles指定IM服务器支持的输入风格列表。如:XIMPeeditPosition|XIMStatusNothing为光标跟随,不需要状态显示风格。下面的具体协议处理就是根据这种风格来介绍的。

IMProtocolHandler指定当IM主循环接收到客户程序的协议时的时间处理函数。

IMEncodingList指定IM服务器支持的传输编码列表。

2.协议处理函数

下面函数用于处理整个客户协议,由于篇幅原因,本文只列出了相应的协议,而没有具体的处理函数,实际应用中,每一个分支都由一个相应的函数来处理。

MyProtoHandler(XIMS ims,IMProtocol *call_data)
{
	switch(call_data->major_code){
	case XIM_OPEN:
	case XIM_CLOSE:
	case XIM_CREATE_IC:
	case XIM_DESTROY_IC:
	case XIM_SET_IC_VALUES:
	case XIM_GET_IC_VALUES:
	case XIM_FORWARD_EVENT:
	case XIM_SET_IC_FOCUS:
	case XIM_UNSET_IC_FOCUS:
	case XIM_RESET_IC:
	case XIM_TRIGGER_NOTIFY:
}
}

函数MyProtoHandler是由IMOpenIM登记的处理客户程序发送到IM服务器的协议的函数,在参数call_data中有相应的协议。上面列出了一些主要的协议,对于不同的情况(主要是根据不同的输入法风格),有一些协议不必处理,或根本不会发生。下面简介一些主要的协议处理过程。

XIM_OPEN:XIM客户程序启动时,要在IM库和IM服务器之间建立逻辑连接。

XIM_CLOSE:关闭在IM库和IM服务器之间建立 的逻辑连接。

XIM_CREATE_IC:当客户程序创建了一个输入法上下文(IC)时,发送此协议到IM服务器,这时在IM服务器中为此IC申请了一个相应的结构,用于记录一些必要的信息,包括字体、位置、前背景色等等。

XIM_DESTROY_IC:当客户程序退出时,删除相应的IC,释放一些与IC相关的存储空间。

XIM_SET_IC_VALUES:设置当前连接IM服务器的IC的属性。实际XIM服务器定期发送此协议来修改IC的属性值。

XIM_GET_IC_VALUES:取得当前连接IM服务器的IC的属性。

XIM_FORWARD_EVENT:当有按键发生时,客户程序发送此协议到IM服务器,此按键事件放在call_data的event结构中。在相应的处理函数中,读出相应的键值,如果是一些控制键,就作相应的操作,如输入法的开启,不同输入法之间的切换等;如果是输入法不需要处理的键,就直接送回客户程序,如一些功能键,组合键等;否则调用输入法的处理程序,输入法处理程序对这个字符进行处理,此时在预编辑区和选择区会有相应的变化,如果有结果字符串生成,输入法服务器会按照开始时确定的编码方式把这个字符串发送到客户程序,这样就完成了一次输入过程。

XIM_SET_IC_FOCUS:当在不同的应用程序间进行切换时,当前的IC会发生变化,此时新的应用程序会发送此协议到IM服务器,输入法服务器会改变当前的焦点,当前的一些与IC有关的属性和全局变量也要有相应的变化。

XIM_UNSET_IC_FOCUS:当前IC失去焦点。在此处可以释放一些与当前IC相关的资源。

XIM_RESET_IC:重置在IM服务器中的IC的状态。

XIM_TRIGGER_NOTIFY:IM库通知IM服务器匹配启动(on-keys)和关闭(off-keys)的事件发生了。

3.主事件循环

在主程序中要用XselectInput选择输入法窗口要处理的所有X事件,

	XSelectInput(display,window,ExposureMask|ButtonPressMask|ButtonReleaseMask|
				ButtonMotionMask|VisibilityChangeMask);

然后在主循环中要处理所有这些事件,如下由函数MyXEventHandler完成。

	for(::){
	XNext event;
	XNextEvent(display,&event);
	if (XFilterEvent(&event,NULL)= =True) continue;
	MyXEventHandler(&event);
	}

函数MyEventHandler要处理输入法窗口的事件。包括在屏幕上的显示,窗口的改变,拖动窗口,及与其他窗口进行通讯等消息。通过此函数,可以使程序达到对用户友好的目的。

以上三点是一个XIM服务器的必须要处理的,我们还需要包含以下头文件:X11/Xlib.h、IMdkit.h和Xi18n.h,后面两个头文件是IMdkit提供的面向R6标准的一些结构定义。另外连接的时候要连接IMdkit的libXimd.so。

五、小结

以前的X Window下的输入法的实现大都是通过截取X的通讯函数的方法来实现在X下的应用程序中进行文本输入。具体方法是修改libX11.so.6里面的XNextEvent函数,当时按键事件时,如果此是在中文状态,就把按键消息发送到输入法去处理,并等待输入法的回应。相应的要修改XlookupString函数,和一些显示函数。这种方法属于非标准的方法,在实际应用中如果有一些应用程序通过其它方法接收输入时,输入法就会起不到作用,为了达到目的需要修改很多应用程序,另外对于其他语言不兼容,每一种语言都要有不同的输入法,给程序的开发者和应用者带来了很多困难。采用了XIM协议后,完全符合国际化标准,这样X下的应用程序根本不必过多的考虑输入问题,就可以达到国际化的要求,在不同的语言环境下可以自由的应用,减少了应用程序开发者的麻烦。


相关主题

  • 参考文献
    • [1] Open Software Foundation:X Window System Version 11 Input Method Secifications,November 1990
    • [2] X11R6 Xi18n Implementation Group:IM Server Developers Kit-C Language Interface,May 15 1994
static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Linux
ArticleID=21079
ArticleTitle=XIM协议的原理及其实现
publish-date=11012000