fcitx架构介绍和模块说明

10 篇文章 11 订阅

fcitx的架构比较简单,输入法的宿主进程称为输入法的客户端,输入法框架从客户端接受按键消息,然后对按键消息进行处理最后向客户端输出一个处理后的字符串。

fcitx处理键盘事件分为四个阶段:PreInput,DoInput,PostInput和处理热键。我们的输入法在DoInput这个阶段被调用。

fcitx的插件被分为四个类别:Frontend,input Method,Module,和User Interface,Frontend负责从客户端程序接收按键消息,然后将消息转发给fcitx框架,Input Method负责将按键消息转换成对应的语言字符串,Modules负责通过注册键盘钩子处理对应的事件,User interface 负责在屏幕上显示对应的元素,也就是对应的皮肤。

Frontend模块

Frontend库负责与客户端程序进行交互,接收客户端发送过来的按键消息,并将处理后的字符串发送给客户端程序。

现在的在Frontend需要实现13个函数分别如下所示:

//创建新的Frontend
void* (*Create)(struct _FcitxInstance*, int frontendindex);

//销毁Frontend
boolean (*Destroy)(void *arg);

//创建新的输入上下文
void (*CreateIC)(void* arg, FcitxInputContext*, void* priv);

//Frontend通过私有值的回调函数检查输入法上下文
boolean (*CheckIC)(void* arg, FcitxInputContext* arg1, void* arg2);

//销毁输入法上下文
void (*DestroyIC) (void* arg, FcitxInputContext *context);

//frontend激活输入法对客户端的回调
void (*EnableIM)(void* arg, FcitxInputContext* arg1);

//frontedn关闭输入法对客户端的回调
void (*CloseIM)(void* arg, FcitxInputContext* arg1);

//frontend 提交字符串的回调
void (*CommitString)(void* arg, FcitxInputContext* arg1, char* arg2);

//frontend 后续的回调函数
void (*ForwardKey)(void* arg, FcitxInputContext* arg1, 
FcitxKeyEventType event, FcitxKeySym sym, unsigned int state);

//设置窗口偏移的回调函数
void (*SetWindowOffset)(void* arg, FcitxInputContext* ic, int x, int y);

//获得窗口的位置
void (*GetWindowPosition)(void* arg, FcitxInputContext* ic, int* x, int* y);

//更新预先屏的字符串的回调
void (*UpdatePreedit)(void* arg, FcitxInputContext* ic);
//更新用户侧边的UI
void (*UpdateClientSideUI)(void* arg, FcitxInputContext* ic);

Frontend需要管理自己的输入上下文,一个客户端至少有一个包含私有数据的输入上下文。我们可以通过CreateIC和DestroyIC来创建和销毁输入上下文的数据。输入上下文通常包含有一个私有的唯一ID,通过这个ID我们可以来查找特定的输入上下文。

一些客户端的输入上下文含有状态值,通过状态值我们可以判断输入上下文是否被激活了。fcitx可以通过EnableIM和CloseIM接口来激活或者关闭某个输入山下文。

当fcitx想向客户端窗口提交字符串或者发送按键消息的时候,可以调用CommitString和

ForwardKey. SetWindowOffset和GetWindowOffset用来设置和获取客户端的光标位置。

当输入上下文支持CAPACITY_PREEDIT 和 CAPACITY_CLIENT_SIDE_UI属性的时候,在选定的输入字符串变化的时候或者UI元素更新的时候我们可以通过UpdatePreedit和UpdateClientSideUI回调函数来更新对应的内容。

InputMethod模块

输入法模块是Fcitx中最重要的模块,它会处理按键消息并更新输入上下文和候选信息。每一个Input Method插件可以注册一个或者多个输入法。

当切换到对应的输入法的时候,初始化函数会被调用,ResetIM用来重置输入法。DoInput函数用来处理按键消息,如果返回值状态是IRV_DISPLAY_CANDWORDS,GetCandidates会被调用。

Priority优先级的值控制着输入法的优先级,每一个输入法自己掌控自己的优先级,如果一个输入法的值小于或者等于0输入法会注册失败。

Fcitx自从4.1.0版本之后,修改了候选词的处理逻辑,每个输入法模块应该提供完整的候选词,而不是单独的一页候选词。翻页函数通过fcitx来实现而不是每个输入法模块。

对于大多数CJK输入法,它们不需要实现单独的标点功能,因为已经有一个共享标点实现。如果输入法需要类似的功能,则不应在输入法中实现,而应在单独的模块中实现。

有些人可能认为将输入法做到一个独立的进程中,比做到共享库中的更好一些,但是目前fcitx只支持共享库的这种模式。所以如果想做成独立的进程,没有简单的方法,不过dbus通信可以用来实现这种方式。

普通模块Module

Event Module

Fcitx中的Event Module通过使用fd来通知消息主循环是否有新的消息。

typedef struct _FcitxModule
{
    //模块的创建主函数
    void* (*Create)(struct _FcitxInstance* instance);
    //设置消息主循环的fd
    void (*SetFD)(void*);
    //处理主循环中的消息
    void (*ProcessEvent)(void*);
    //模块的析构函数
    void (*Destroy)(void*);
    //重新加载配置
    void (*ReloadConfig)(void*);
} FcitxModule;

从多个fd中选择后,将调用ProcessEvent,模块将处理自己的事件。

模块需要在FcitxInstance中更新rfds、wfds、efds,并在FcitxInstance中设置maxfd成员.。模块处理完所有事件后,所有三个fd都会通过SetFD函数设置成FD_ZERO。

除基于事件的模块外,所有其他misc模块都将使用内置钩子来干扰关键事件处理。

目前,有以下可用的钩子来干扰关键事件处理。

//注册重置输入过程中调用的钩子
void FcitxInstanceRegisterResetInputHook(struct _FcitxInstance* instance, FcitxIMEventHook hook);

//注册输入法激活的时候的钩子
void FcitxInstanceRegisterTriggerOnHook(struct _FcitxInstance* instance, FcitxIMEventHook hook);

//注册输入法失效的时候的钩子
void FcitxInstanceRegisterTriggerOffHook(struct _FcitxInstance* instance, FcitxIMEventHook hook);

//注册获得输入焦点的时候的钩子
void FcitxInstanceRegisterInputFocusHook(struct _FcitxInstance* instance, FcitxIMEventHook hook);

//注册失去输入焦点的时候的钩子
void FcitxInstanceRegisterInputUnFocusHook(struct _FcitxInstance* instance, FcitxIMEventHook hook);

//注册输入法切换的时候的钩子
void FcitxInstanceRegisterIMChangedHook(struct _FcitxInstance* instance, FcitxIMEventHook hook);

//注册输入法更新候选词的时候的钩子
void FcitxInstanceRegisterUpdateCandidateWordHook(struct _FcitxInstance* instance, FcitxIMEventHook hook);

//fcitx注册更新输入法列表的时候的钩子
void FcitxInstanceRegisterUpdateIMListHook(struct _FcitxInstance* instance, FcitxIMEventHook hook);

//注册输入状态变化的时候的钩子
void FcitxInstanceRegisterICStateChangedHook(struct _FcitxInstance* instance, FcitxICEventHook hook);

//注册UI状态变化的时候的钩子
void FcitxInstanceRegisterUIStatusChangedHook(struct _FcitxInstance* instance, FcitxUIStatusHook hook);

//注册钩子的调用方法
FcitxIMEventHook imchangehook;  //fcitx输入法事件的钩子
imchangehook.arg = imInstance;  //回调函数的参数一般是指针
imchangehook.func = IMeChangeCallback; //输入法切换的回调函数
//注册输入法切换的回调钩子函数
FcitxInstanceRegisterIMChangedHook(fcitxInstance, imchangehook);

按键事件处理分为4个阶段。在输入法的DoInput函数之前调用PreInput。如果按键事件还没有得到处理,PostInput将在输入法的DoInput函数之后调用。热键最后被处理,但即使输入上下文状态为ENG,它也不会被阻止。这是预输入和后输入的主要区别。如果一个插件只有一个需要切换的状态,它应该使用热键而不是输入过滤器。

User Interface

和Frontend、InputMethod、Module类型的模块不一样,User Interface模块只允许有一个运行。如果没有特殊需求,不建议实现一个新的User Interface模块,Fcitx中已经存在了三个用户皮肤插件,分别是fcitx-classic-ui、fcitx-kimpanel-ui(基于dbus)以及fcitx-light-ui。

如果要实现一个自定义的User interface模块的话,最好使用一个和kimpanel兼容的协议,而不是写一个fcitx协议。

Fcitx对用户交互窗口的元素进行了抽象,一般来说,一个输入窗口分为四个部分

User Interface中的一个元素被称为Status,它定义了一个按键,输入法的图标也可以通过User Interface来进行定义。

/**
 * @brief Fcitx Status icon to be displayed on the UI
 **/
typedef struct _FcitxUIStatus {
	/**
	 * @brief status name, will not displayed on the UI.
	 **/
	char name[MAX_STATUS_NAME + 1];
	/**
	 * @brief short desription for this status, can be displayed on the UI
	 **/
	char shortDescription[MAX_STATUS_SDESC + 1];
	/**
	 * @brief long description for this status, can be displayed on the UI
	 **/
	char longDescription[MAX_STATUS_LDESC + 1];
	/**
	 * @brief toogle function
	 **/
	void (*toggleStatus)(void *arg);
	/**
	 * @brief get current value function
	 **/
	boolean (*getCurrentStatus)(void *arg);
	/**
	 * @brief private data for the UI implementation
	 **/
	void *priv;
	/**
	 * @brief extra argument for tooglefunction
	 **/
	void* arg;
} FcitxUIStatus;

还有一个User Interface元素是Menu,Menu元素现在只有fcitx-classic-ui模块和fcitx-light-ui模块支持,由于kimpanel的限制,现在kimpanel不支持fcitx风格的菜单。

如果模块需要注册菜单或者状态图标的话,可以通过RegisterStatus和RegisterMenu来进行注册。如果一个User Interface模块需要支持状态图标和菜单的话,应该实现UpdateStatus,RegisterStatus和RegisterMenu三个回调函数。

Fcitx的文件和目录

Fcitx的文件放在两个目录下,一个是系统目录一个是用户目录

系统目录: /user/share/fcitx

用户目录:~/.config/fcitx

为了能让fcitx的配置工具自动找到fcitx的插件和配置文件,我们需要将对应的文件正确命名并放置在对应的目录下。

每个插件都有一个配置文件,该文件被安装在/usr/share/fcitx/addon目录下,这个文件定义了插件的名称、类别、库名称、类型和优先级。插件的配置文件名称应该为:addon-name.conf。

如果插件需要被各种配置项进行配置,它需要一个配置描述文件,该文件应该被安装在

/usr/share/fcitx/configdesc/目录下,文件名称应该为[addon-name].desc。相应的配置文件应该被防止在/usr/share/fcitx/conf/目录下,文件名称应该为[addon-name].config

如果只有一个数据文件的话可以放置在/usr/share/fcitx/data目录下,如果有多个文件的话最好放置在一个单独的目录下。

配置文件的描述文件的格式如下:

[GroupName/OptionName]
Type=Option Type
Description=Description String
DefaultValue=value

[DescriptionFile]
LocaleDomain=Domain

类型可以是

"File", "Font", "Enum", "String", "I18NString", "Boolean", "Color", "Integer".

DefaultValue是可选的,但是如果配置文件需要自动生成的话,最好添加缺省的值。

所有的类型都会在配置工具中以响应的形式显示,Boolean显示成CheckBox,字符串显示成文本编辑框。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农飞飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值