- UID
- 1029342
- 性别
- 男
|
这段时间因为需要移植一个输入法程序,所以学习研究了GTK下输入法实现的相关程序,这才发现输入法所涉及到的内容不光是输入法应用程序本身,GTK和XWindow系统中,还必须要有相应的模块支持,这篇文档是我对于GTK的输入法支持模块GtkIMContext的一点粗浅的理解。
1 相关参考资料
http://library.gnome.org/devel/gtk/stable/GtkIMContext.html GtkIMContext的API文档
http://www.ibm.com/developerworks/cn/linux/i18n/xim/xim-2/index.html XIM协议的原理及其实现,这篇文章和本文没有太大的关系,但是可以了解一下XWindow系统的输入法协议作为辅助的背景知识。
2 IM-Context模块框架
2.1 类层次结构
Ø GtkIMContext:虚基类,定义了IMContext类支持的信号和接口函数。其主要用途是作为GtkIMMultiContext及其它子类的基类,并提供了一组的函数封装用于调用这些类函数。
Ø GtkIMMultiContext:GtkIMContext的子类,实现了一个可以动态加载不同的Slave IMContext模块的框架,自己并不真正处理输入法相关的任务,而是作为一个类似二传手的角色,在GTK Widget和具体的Slave IMContext之间传递数据,转发信号。
Ø GtkIMContextSimple:GtkIMContext的子类,实现了一个基于查表实现文字检索的IMContext,主要用途:一是作为其它具体的基于查表实现文字检索的IMContext的父类(具体子类只需要添加自己的索引表格即可),二是作为GtkIMMultiContext的一个默认的Slave Context,当特定的Slave由于某些原因无法被创建时,SimpleContext将被创建并返回。
Ø Build-in IMContext:除了上述IMContext相关类实现,GTK还自带了GtkIMContextTai,GtkIMContextXIM等基于GtkIMContext实现的具体的全功能IMContext,以及Am_et等基于GtkIMContextSimple的查表类的IMContext的具体实现。
Ø Other IMContext:此外,不同的输入法可以根据自己的需要,实现自己的子类。如SCIM基于GtkIMContext实现的GTKIMContextSCIM和Matchbox-keyboard基于GtkIMContextSimple实现的MbIMContext。
3 工作机制
3.1 GTK Widget和IMContext的关系
在GTK的Widget中,涉及到IMContext的主要是和文字编辑相关的GTK Entry 和GTK TextView这两个Widget。这两个widget的类成员中都包含了一个指向GtkIMContext对象的指针,并在类实例的初始化函数中分配并将指针指向了一个GtkIMMultiContext的实例对象。
GtkIMMultiContext对象在初始化过程中,首先设置其Slave成员指针为空,而后在IMContext相关的后续操作中,再通过gtk_im_multicontext_set_slave、gtk_im_multicontext_get_slave函数设置其具体的slave IMContext对象。
3.2 GtkIMContext成员函数和信号
GtkIMContext的类成员函数中:
Ø set_client_window
Ø focus_in
Ø focus_out
这几个函数主要是由相关的GTK Widget在初始化,以及焦点,可视等状态变化的时候调用,用来通知IMContext相关信息的。具体的IMContext通常用这些函数来初始化事件通讯机制,显示消隐UI界面等。
Ø reset
Ø set_cursor_location
Ø filter_keypress
这几个函数主要是在用户在执行输入等操作时,由相关的GTK Widget根据当前文本的状态进行调用,通知IMContext模块状态重置,光标位置变动(可以用来实现光标跟随)和键值输入的情况。
Ø get_surrounding
Ø delete_surrounding
Ø get_preedit_string
Ø set_use_preedit
Ø set_surrounding
这几个函数的主要目的是用来实现Preedit和auto correct或者其它前后文相关操作功能,前三个函数是由IM端发起调用,用于从相关GTK Widget读写数据。后两个函数则是由Widget端发起调用,用于通知IM是否使用preedit模式,和反馈surrounding数据。
GtkIMContext的信号包括:
Ø "commit"
Ø "delete-surrounding"
Ø "preedit-changed"
Ø "preedit-end"
Ø "preedit-start"
Ø "retrieve-surrounding"
这些信号用于IM模块通知相关的GTK Widget对应事件的发生,是IM模块向Widget发送信息的主要途径。
3.3 Widget和IMContext的交互
以GtkEntry为例,GtkWidget和IMContext交互的流程大致如下:
Ø GtkEntry对象初始化:创建GtkIMMultiContext成员对象,设置GtkIMMultiContext的commit和preedit等信号的处理函数。GtkIMMultiContext的初始化函数设置IM模块默认工作模式等。
Ø GtkEntry对象实例化(realize):调用set_client_window设置IMContext对应的GDKWindow。通常这是GtkIMMultiContext第一次获取并创建它具体的slave IMContext对象的时刻,GtkIMMultiContext将自己实现的callback函数链接到slave IMContext的上述信号上,这些Callback函数通常再将这些信号通过自身的对象emit出去,从而让GtkEntry所注册的callback函数得到调用。
Ø GtkEntry窗口获得、失去焦点:调用focus_in, focus_out函数通知IM模块焦点的变化情况
Ø GtkEntry窗口获得按键事件:调用filter_keypress函数通知IM模块键值的输入,IM模块通常会根据当前的输入法状态,通过preedit-start,preedit-changed信号通知GtkEntry处于预编辑状态的文字内容发生变化,GtkEntry通过get_preedit_string函数获得实际的预编辑状态的文字内容并更新显示。用户选取文字完成输入后,IM模块通过preedit-end信号通知GtkEntry预编辑状态结束,并通过commit信号通知GtkEntry用户选择的文字内容。如果Preedit模式不适用,如英文输入状态等,则输入法模块可能直接通过commit信号通知GtkEntry文字内容。
3.4 IMContext与IM的交互
需要注意的是GtkIMContext是作为相关GTK Widget的成员对象运行在用户程序的进程内,而不是输入法程序的进程内。所以IMContext和IM之间还存在着通讯问题。
因为通过使用GtkIMMultiContext实现了IMContext模块的动态加载机制,所以具体的IMContext和对应的IM的通讯机制根据各自的实现而不同。从而实现了对各种不同通讯协议的兼容支持。
GtkIMContextXIM支持XWindow标准所定义的XIM协议,通过XIM协议规定的xevent在XIM APP和XIM Server之间发送相关信息。
由SCIM所支持的GtkIMContextSCIM则通过socket通讯机制与SCIM进行通讯。
3.5 其它输入方式
对于字母或其它可由X11逻辑键值所对应的各种符号,除了通过GtkIMContext输入以外,有些程序如虚拟键盘(xvkbd, matchbox-keyboard)等,还可能通过发送fake key_event来模拟物理键盘的输入,通过X11的事件分发机制将键值传送到当前on focus的GTK Widget上实现字母和符号的输入,此外即使在非字母符号的输入状态下,某些特殊的键值如回车,删除等,在一些输入法实现中,也可能通过这个途径来发送。 |
|