IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> fcitx架构介绍和模块说明 -> 正文阅读

[C++知识库]fcitx架构介绍和模块说明

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,字符串显示成文本编辑框。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-28 15:10:05  更:2022-02-28 15:11:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:15:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码