fcitx输入法代码分析总结

fcitx处理输入的方式

首先,作为一个输入法,fcitx在linux下的工作方式是这样的:
键盘输入处理流程

fcitx的组织结构

Fcitx小企鹅输入法通过将各个模块抽象成不同的addon插件,来管理诸多功能。像frontend、im(输入法)、ui, 属于必备的特殊的addon,fcitx有专门的对应的代码来处理加载,其他像简繁体、dbus、标点等作为普通的modules,都使用通用的module模块对之加载。
在fcitx下,不管是一个ime、ui,或是其他普通module,都要首先在fcitx下进行addon注册,方法就是在 /usr/share/fcitx/addon目录下放入自己的 .config(作为插件的普通配置)文件,然后根据自己功能的不同在文件夹下放入对应功能的 .config(具体功能的配置) 文件,并编译自己的模块生成动态库 .so文件供fcitx动态使用。
代码结构

fcitx的启动流程

Fcitx经过历次修改后,目前的架构视所有功能都为插件,这样可以很容易的扩充其功能,能够很容易的面对将来的变化。在启动一个instance时,fcitx框架下可能会有很多插件,instance启动的第一步,便是为各种类型的插件们先提供一个容器。C语言实现的fcitx使用utarray(ut列表类似于C++的array)和uthash作为容器。

    FcitxInstance* instance = (FcitxInstance*) arg;
    FcitxAddonsInit(&instance->addons);
    FcitxInstanceInitIM(instance);
    FcitxInstanceInitNoPreeditApps(instance);
    FcitxFrontendsInit(&instance->frontends);
    InitFcitxModules(&instance->modules);
    InitFcitxModules(&instance->eventmodules);

为插件申请完成空间之后,便是加载所有的插件。这里的“加载”,只是将所有的插件配置信息pushback到addons列表里,与其说是加载,不如说是在fcitx里先注册,fcitx的加载采用的是lazy-load懒惰式加载,使用某个插件再加载之。
Fcitx的注册插件方式:通过遍历所有在 /usr/share/fcitx/addon 下的 .config 文件,完成所有addon的加载。这里的加载加载只是通用性的加载,不针对特殊功能的addon做特殊加载,下面还会根据不同的插件类型做进一步加载。

im加载

输入法addon的注册流程
输入法注册流程
输入法addon的加载流程:
目前的addon都是动态库文件方式dlopen()加载,lazyload方式,以输入法插件为例:当切换至某个输入法时才会加载该输入法的动态库,通过dlsym()函数导入动态库中接口变量,该变量都是通过宏定义FCITX_DEFINE_PLUGIN()定义的变量。
具体加载方式可参加下图。

输入法动态加载流程

用代码生成代码

用宏定义生成指定的函数、变量。
函数结构相同,需要的参数类型有一点差异的情况
看函数FcitxIMEntryConfigBind(),查看该函数的定义将跳转到带参宏CONFIG_BINDING_BEGIN(FcitxIMEntry),查看该宏定义才发现它定义了一个通用的配置绑定函数,只要指定参数类型,就会生成对应类型的函数配置绑定函数。
为什么要这样做——避免代码的重复一处改变多处修改。
fcitx有多种插件(addon),都会用到配置绑定函数,做相同的操作,但是他们传入的参数类型会有不同,所以不能使用同一个函数,所以使用这种方法。
在这里插入图片描述

继承

前面说fcitx的各类功能(输入法、前端、模块)都是作为插件addon加载的,所有功能都有作为addon的共同部分,(就可以理解为都继承自addon),用FcitxGenericConfig作为不同模块结构体的共用部分,放在模块结构体的最前面(这很重要,在强转类型的时候,会舍弃掉结构体后面的部分,而保留前面部分),当只要使用共同部分时,就可以使用类型强转,(将派生类转换为基类)就可以使用公共的基类函数了。唯一麻烦一点的是不同的结构体在函数参数上是不会进行尝试转换的,对于每一个结构体,需要自己定义这种类型的“向基类转换”函数,然后在使用公共的基类操作函数。here is an instance:

在这里插入图片描述

FcitxInstanceLoadAllIM()函数的作用,就是遍历所有输入法配置文件,将他们对应的输入法加入到instance->availimes 这个容器里面。(这只相当于注册到instance,并未真正的加载其二进制文件,.so 库文件要等使用时再加载)
过程:先遍历addon插件,在所有插件中寻找属于输入法的插件:
在这里插入图片描述

之后对每个输入法addon按其.config文件创建并写入FcitxIM结构体,(其中FcitxGenericConfig公共部分已在之前就配置好了)

真正的加载使用输入法是从FcitxInstanceSwitchIMByIndex()函数入口的:
在这里插入图片描述

从函数字面上看是切换输入法,无论是初始化加载默认输入法还是切换时转换输入法,实际上都是给该函数一个Index去调用的。
一步步往后,在函数FcitxInstanceLoadIM中,使用了linux库函数dlopen()去动态调用对应的动态库文件,一旦加载完成动态库,动态库里的全局变量在fcitx进程空间中就可见了,使用dlsym()函数,传入打开的动态库文件句柄和要搜索的全局变量名,返回的就是该变量。
在这里插入图片描述

每一个动态库的代码中,都有一个形如这样的变量定义宏定义语句:
FCITX_DEFINE_PLUGIN():
在这里插入图片描述

这样就形成了统一的命名风格,fcitx框架代码即使在不知道对应库的情况下,也能根据外界的.config文件调用到该变量
而dlsym()函数搜寻的正是这个变量,他就是整个.so文件的接口,所有的功能函数都是通过它调用的。

输入法开发接口

区位输入法详细分析

区位输入法流程分析

附注

Fcitx wiki:https://fcitx-im.org/wiki/Fcitx/zh-hans
Fcitx github:https://github.com/fcitx
Fcitx 开发者讨论社区(google):https://groups.google.com/group/fcitx-dev
Fcitx 作者博客:https://www.csslayer.info/wordpress/author/csslayer/

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值