输入法
输入法是一种将输入设备输入的数据翻译成字符的方法,这个方法可以表示编码方案和输入平台两种含义,本文将输入法作为输入平台来讲解 LCUI 对它的支持方案。
LCUI 的输入法引擎负责的工作很简单:记录支持的输入法列表,在有按键输入时调用当前激活的输入法驱动进行处理,然后转换成 TEXTINPUT 事件,让 TextEdit 等具有文本输入支持的组件接收输入法输入的文本。
添加输入法
LCUI 将输入法驱动抽象成了 LCUI_IMEHandler
接口,它在 include/LCUI/ime.h 中的定义如下:
typedef struct LCUI_IMEHandlerRec_ { LCUI_BOOL (*prockey)(int, int); void (*totext)(int); LCUI_BOOL (*open)(void); LCUI_BOOL (*close)(void); void (*setcaret)(int, int); } LCUI_IMEHandlerRec, *LCUI_IMEHandler;
添加输入法过程就是补全这些方法供 LCUI 的输入法引擎调用,示例模板代码如下:
static LCUI_BOOL X11IME_ProcessKey(int key, int key_state) { // ... return FALSE; } static void X11IME_ToText(int ch) { wchar_t text[256]; size_t text_len; // ... LCUIIME_Commit(text, text_len); } static LCUI_BOOL X11IME_Open(void) { // ... return TRUE; } static LCUI_BOOL X11IME_Close(void) { // ... return TRUE; } int LCUI_RegisterLinuxIME(void) { LCUI_IMEHandlerRec handler; handler.prockey = X11IME_ProcessKey; handler.totext = X11IME_ToText; handler.close = X11IME_Close; handler.open = X11IME_Open; handler.setcaret = NULL; return LCUIIME_Register("My Input Method", &handler); }
接下来我们将以中文输入法为例,介绍这些方法:
prockey()
方法用于判断输入法是否处理按键,第一个参数是按键码,第二个参数是按键的状态,当返回值为 TRUE 时会调用 totext()
方法。
totext()
用于将按键码转换为文本。当为中文模式时,可以根据输入的按键码组成拼音,并更新候选词列表供用户选择;当为英文模式时,则可以将按键码转换为字符码,然后调用 LCUIIME_Commit()
函数提交它。
open()
方法用于在输入法被激活时调用。你可以在这里做一些与初始化相关的操作。
close()
方法用于在输入法被关闭时调用。你可以在这里终止输入法的工作并清理相关资源。
setcaret()
方法用于设置输入光标的位置,参数是光标的 x、y 坐标。TextEdit 组件中的 TextCaret 组件会在它更新时调用该方法来同步输入法光标的位置,以让输入法的界面定位在 TextEdit 组件附近。
如需了解更多,可参考现有的 Windows 和 Linux 输入法驱动:
待办事项
重构输入法引擎
LCUI 的输入法引擎在设计之初由于可参考的相关资料很少,对输入法的功能需求也不明确,因此只以“能够接收文本输入”为目的做了简单设计,其中一些 API 是参考了 WIndows 输入法相关的文档而设计的。如果你有输入法开发经验,可以帮助我们改进输入法支持模块。
将 proc() 的第二个参数改为布尔类型
按键的状态有按下和释放,将其改为布尔类型的 isPressed
比判断 state == LCUI_KSTATE_PRESSED
更简单。
改进 Linux 输入法引擎
现有的 Linux 输入法引擎过于简单,支持输入英文字母和符号。