注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

gmd20的个人空间

// 编程和生活

 
 
 

日志

 
 

linux输入法ibus架构简析  

2010-12-29 20:38:19|  分类: linux相关 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

项目主页 是  http://code.google.com/p/ibus/wiki/Sources
好像没什么详细的开发文档,不过代码很简单的,因为想改改pinyin输入法来玩玩,就简单看了一下代码。
IBus Reference Manual http://ibus.googlecode.com/svn/docs/ibus/index.html 这个可以看一下,了解一下ibus的各个组件的功能什么的。


在线的代码可以在这里浏览,
https://github.com/phuang/ibus
http://code.google.com/p/ibus/wiki/Develop


不过要看的话还是用git下载下来看的方便一些:
git clone git://github.com/ibus/ibus.git ibus
git clone git://github.com/ibus/ibus-pinyin.git ibus-pinyin
写一个新的引擎,这里有两个简单的例子,一个c的一饿python的
git clone git://github.com/phuang/ibus-tmpl.git ibus-tmpl




一开始看直接看pinyin引擎,感觉有点复杂阿,所以先看一下ibus-tmpl这个简单的输入引擎的例子,看看是怎么工作的:

ibus应该是自持python和c两种语言写的引擎的,这里以c为例子。每个输入法其实作为一个独立的模块,在需要的时候的动态加载的。整个可以说是一种“插件“的架构,利用GType 和Dbus的功能实现。 每个输入法模块通过GType导出IBUS_TYPE_ENGINE 接口类, 核心部分就可以根据导出类加载某个输入法了。 ibus和核心部分和各个输入法的模块直接可以通过dbus通讯。


下马简单的看看,核心部分是怎么和输入法模块连接到一起的。




首先,每个模块都是一个xml配置文件,指定了这个输入法对应的模块是,一个模块他ibus术语叫做一个component,已经安装的输入法的配置文件应该都是可以在这个目录下找到的吧。/usr/share/ibus/component/

比如   /usr/share/ibus/component/pinyin.xml  

------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<!-- filename: pinyin.xml -->
<component>
    <name>org.freedesktop.IBus.Pinyin</name>
    <description>Pinyin Component</description>
    <exec>/usr/lib/ibus-pinyin/ibus-engine-pinyin --ibus</exec>    ///这个指定输入法对应的应用程序模块
    <version>1.3.10</version>
    <author>Peng Huang &lt;shawn.p.huang@gmail.com&gt;</author>
    <license>GPL</license>
    <homepage>http://code.google.com/p/ibus</homepage>
    <textdomain>ibus-pinyin</textdomain>

    <engines>
        <engine>
            <name>pinyin</name>
            <language>zh</language>
            <license>GPL</license>
            <author>Peng Huang &lt;shawn.p.huang@gmail.com&gt;
BYVoid &lt;byvoid1@gmail.com&gt;</author>
            <icon>/usr/share/ibus-pinyin/icons/ibus-pinyin.svg</icon>
            <layout>us</layout>
            <longname>Pinyin</longname>
            <description>Pinyin input method</description>
            <rank>99</rank>
        </engine>
        <engine>
            <name>bopomofo</name>
            <language>zh</language>
            <license>GPL</license>
            <author>BYVoid &lt;byvoid1@gmail.com&gt;
Peng Huang &lt;shawn.p.huang@gmail.com&gt;</author>
            <icon>/usr/share/ibus-pinyin/icons/ibus-bopomofo.svg</icon>
            <layout>us</layout>
            <longname>Bopomofo</longname>
            <description>Bopomofo input method</description>
            <rank>98</rank>
        </engine>
    </engines>

</component>
-------------------------------------------------






应用程序main函数,完成了对应的输入法模块的注册加载:

static void
init (void)
{
    IBusComponent *component;

    ibus_init ();

    bus = ibus_bus_new ();
    g_object_ref_sink (bus);
    g_signal_connect (bus, "disconnected", G_CALLBACK (ibus_disconnected_cb), NULL);
    
    factory = ibus_factory_new (ibus_bus_get_connection (bus));
    g_object_ref_sink (factory);
    ibus_factory_add_engine (factory, "enchant", IBUS_TYPE_ENCHANT_ENGINE);

    ibus_bus_request_name (bus, "org.freedesktop.IBus.Enchant", 0);

    component = ibus_component_new ("org.freedesktop.IBus.Enchant",
                                    "English Writer",
                                    "0.1.0",
                                    "GPL",
                                    "Peng Huang <shawn.p.huang@gmail.com>",
                                    "http://code.google.com/p/ibus/",
                                    "",
                                    "ibus-tmpl");
    ibus_component_add_engine (component,
                               ibus_engine_desc_new ("enchant",
                                                     "English Writer",
                                                     "English Writer",
                                                     "en",
                                                     "GPL",
                                                     "Peng Huang <shawn.p.huang@gmail.com>",
                                                     PKGDATADIR"/icon/ibus-enchant.svg",
                                                     "en"));
    ibus_bus_register_component (bus, component);
}

int main()
{

    init ();
    ibus_main ();
}






========另外一个文件里面的输入法类====================
typedef struct _IBusEnchantEngine IBusEnchantEngine;
typedef struct _IBusEnchantEngineClass IBusEnchantEngineClass;

struct _IBusEnchantEngine {
    IBusEngine parent;

    /* members */
    GString *preedit;
    gint cursor_pos;

    IBusLookupTable *table;
};

struct _IBusEnchantEngineClass {
    IBusEngineClass parent;
};


G_DEFINE_TYPE (IBusEnchantEngine, ibus_enchant_engine, IBUS_TYPE_ENGINE)  

static void
ibus_enchant_engine_class_init (IBusEnchantEngineClass *klass)
{
    IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
    IBusEngineClass *engine_class = IBUS_ENGINE_CLASS (klass);
    
    ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_enchant_engine_destroy;

    engine_class->process_key_event = ibus_enchant_engine_process_key_event;   ///键盘按键的处理事件的注册
}

static void
ibus_enchant_engine_init (IBusEnchantEngine *enchant)
{
    if (broker == NULL) {
        broker = enchant_broker_init ();
        dict = enchant_broker_request_dict (broker, "en");
    }

    enchant->preedit = g_string_new ("");
    enchant->cursor_pos = 0;

    enchant->table = ibus_lookup_table_new (9, 0, TRUE, TRUE);
    g_object_ref_sink (enchant->table);
}




==================================
其中关键是G_DEFINE_TYPE宏的用法,这个注册了IBUS_TYPE_ENGINE 的类型,并把ibus_enchant_engine_class_init等函数设置为这个类型的初始化函数。这样ibus核心就可以找到相应模块中的自定义输入法类,并且调用相应的初始化函数了。详细的文档参考
http://library.gnome.org/devel/gobject/unstable/gobject-Type-Information.html
我自己之前也大理解gobject-Type 这个东西,所以看起来不是明白。

简单的说这个宏会展开成这样:

---------------------------------------------------------------

The most general convenience macro for type implementations, on which G_DEFINE_TYPE(), etc are based.

1
2
3
4
5
6
G_DEFINE_TYPE_EXTENDED (GtkGadget,
gtk_gadget,
GTK_TYPE_WIDGET,
0,
G_IMPLEMENT_INTERFACE (TYPE_GIZMO,
gtk_gadget_gizmo_init));

expands to

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
static void     gtk_gadget_init       (GtkGadget      *self);
static void gtk_gadget_class_init (GtkGadgetClass *klass);
static gpointer gtk_gadget_parent_class = NULL;
static void gtk_gadget_class_intern_init (gpointer klass)
{
gtk_gadget_parent_class = g_type_class_peek_parent (klass);
gtk_gadget_class_init ((GtkGadgetClass*) klass);
}

GType
gtk_gadget_get_type (void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile))
{
GType g_define_type_id =
g_type_register_static_simple (GTK_TYPE_WIDGET,
g_intern_static_string ("GtkGadget"),
sizeof (GtkGadgetClass),
(GClassInitFunc) gtk_gadget_class_intern_init,
sizeof (GtkGadget),
(GInstanceInitFunc) gtk_gadget_init,
(GTypeFlags) flags);
{
static const GInterfaceInfo g_implement_interface_info = {
(GInterfaceInitFunc) gtk_gadget_gizmo_init
};
g_type_add_interface_static (g_define_type_id, TYPE_GIZMO, &g_implement_interface_info);
}
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}

The only pieces which have to be manually provided are the definitions of the instance and class structure and the definitions of the instance and class init functions.

------------------------------------------------------------------------------

 

理解了加载与关联办法,其他代码看起来就简单了。关于dbus的进程间通讯的,也可以去dbus官网看一下

http://www.freedesktop.org/wiki/Software/dbus

  评论这张
 
阅读(971)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017