Chinaunix首页 | 论坛 | 博客
  • 博客访问: 786485
  • 博文数量: 129
  • 博客积分: 3477
  • 博客等级: 中校
  • 技术积分: 1329
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-30 21:53
文章分类

全部博文(129)

文章存档

2023年(10)

2022年(4)

2021年(10)

2020年(9)

2018年(1)

2017年(1)

2014年(4)

2013年(3)

2012年(12)

2011年(24)

2010年(2)

2009年(8)

2008年(6)

2007年(34)

2006年(1)

分类: C/C++

2022-11-08 15:20:24

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是一个{BANNED}{BANNED}最佳佳简单的协议流的例子: 

当 应用程序发生按键事件时,它调用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协议模型中,所有的事件结构有如下的通用成员:

点击(此处)折叠或打开

  1. typedef    struct{
  2.     int    major_code;
  3.     int    minor_code;
  4.     CARD16    connect_id;
  5.     }


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

2)协议处理

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


XIM的实现

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

1.初始化输入法服务

点击(此处)折叠或打开

  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.协议处理函数

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

点击(此处)折叠或打开

  1. MyProtoHandler(XIMS ims,IMProtocol *call_data)
  2. {
  3.     switch(call_data->major_code){
  4.     case XIM_OPEN:
  5.     case XIM_CLOSE:
  6.     case XIM_CREATE_IC:
  7.     case XIM_DESTROY_IC:
  8.     case XIM_SET_IC_VALUES:
  9.     case XIM_GET_IC_VALUES:
  10.     case XIM_FORWARD_EVENT:
  11.     case XIM_SET_IC_FOCUS:
  12.     case XIM_UNSET_IC_FOCUS:
  13.     case XIM_RESET_IC:
  14.     case XIM_TRIGGER_NOTIFY:
  15.      }
  16. }

函数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事件,


点击(此处)折叠或打开

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

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

点击(此处)折叠或打开

  1. for(::){
  2.     XNext event;
  3.     XNextEvent(display,&event);
  4.     if (XFilterEvent(&event,NULL)= =True)
  5.              continue;
  6.     MyXEventHandler(&event);
  7. }

函数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
原文地址:https://blog.csdn.net/shenbin1430/article/details/5737403
阅读(1749) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~