MTK平台输入法

MTK平台输入法浅析

摘要

输入法作为手机软件中的一个最基本模块,在人机交互界面的中具有举足轻重的位置。为了帮助大家更快更好的理解输入法在MTK平台上的实现,本文结合mtk的代码从框架性的角度对输入法的实现进行概要导读,希望能够对大家有所收益。

一.KeyPad输入

Keypad的输入分为两种:一键候选和多键候选。

a) 一键候选:指每次按键输入的内容都是确定的,一次按键就是一次输入。比如数字输入,智能拼音输入等。

b) 多键候选:指每次按件输入的内容在一定的时间内是不确定的,用户可以通过再次按键来改变当前输入的内容,比如大小写英文,拼音输入法就是这种类型的输入方式。

下面我们将按照上面的划分方式来分别介绍这两种输入方式。

A. 多键候选

为了实现多键候选的功能,MTK提供了一个名为multitap的所谓控件,其对应的数据结构为multitap_input。具体内容可以查看代码。

以下为一段sample code,用来演示如何利用multitap控件来实现某一种multitap类型输入(比如大小写的ABC):

for(i = 0; i < MAX_MULTITAPS; i++)

{

s = (UI_string_type) numberless_lowercase_multitap_strings[i];

pixtel_UI_create_multitap_input(&g_pen_editor_bpmf_pinyin_active_multitap[i],MMI_multitap_x,M MI_multitap_y,width,MMI_multitap_height,s);

}

---为每一个输入键(键0-9)建立一个multitap控件赋一些初值(比如键2的循环数组为“ABC2”);

register_MMI_key_input_handler();

--把所有字符输入(键0-9)的keyhandler都影射到同一个函数MMI_key_input_handler上

此函数的实质就是调用接下来要设置的keyup和key down的handler函数

register_key_up_handler(mmi_pen_editor_bpmf_pinyin_key_up_handler);

--注册所有键的keyup handler,

该handler会调用multitap控件的input_complete_callback函数,来结束一次multitap的输入

register_key_down_handler(mmi_pen_editor_bpmf_pinyin_key_down_handler);

--注册所有键的keydown handler,

该handler会在某个键的候选项里进行循环,同时也会调用multitap控件的input_callback函数

for(i = 0; i < MAX_MULTITAPS; i++)

{

pixtel_UI_set_multitap_input_callbacks(&g_pen_editor_bpmf_pinyin_active_multitap[i],mmi_pen_ editor_bpmf_pinyin_multitap_input,mmi_pen_editor_bpmf_pinyin_multitap_input_complete);

}

--设置multitap的上述两个回调函数

在完成了以上代码以后,一般来说我们就可以进行多键候选的输入了

1) 输入一个键(比如2键),此时Keydown handler会根据键值找到其对应得multitap,此时输入内容为“ABC2”中的第一个字母“A”,并保存当前输入在此数组中的位置,同时更新inputbox的视图,置一个active_multitap为当前按键,并在该键keyuphandler里启动一个定时器

2) 如果用户在定时器超时之前,再次按下一个键,则keydow handler会判断是否跟上一次的active——multitap一样,如果一样则在上次的位置上循环加1,比如上次是A,这次就是B了;如果这次按键和上次不一样,则表示开始一个新的按键了,则首先调用input_complete_callback来处理上一个按键应该完成的事宜(比如更新inputbox的视图)。同时回到状态1进行新的输入处理

3) 如果用户在定时器超时之前,都没有按键,则直接调用input_complete-calllback来处理。完成一次multitap的输入

B. 一键候选

相对多键候选来说,一键候选的实现要简单得多,同样下面我们也使用代码来看看一键候选的实现

clear_multitap_key_handlers();

-----清除以前设置的mutitap keyhandler

register_MMI_key_input_handler();

----把所有字符输入(键0-9)的keyhandler都影射到同一个函数MMI_key_input_handler上

此函数的实质就是调用接下来要设置的key down的handler函数

register_key_down_handler(EMS_inputbox_handle_key_down);

--注册所有键的keydown handler

其实跟上面的多键候选相比,基本上一键候选是非常简单的

每次按键都会调用到keydown handler 在inputbox里面输入唯一的一个输入值。所以keydown handler只需要处理如何更新inputbox的视图即可

二.Touch输入

对于触摸屏来说,通常有两种模式:一种是触摸模式,另一种是手写模式。

由于触摸屏的这个特性,MTK也为我们的输入提供了两种相应的模式:手写输入和虚拟键盘输入。

A. 手写输入

mmi_pen_start_capture_strokes(PEN_EDITOR_STROKE_BUFFER_SIZE, gPenEditorStrokeBuffer, 1, stroke_area, ext_stroke);

--设置手写区域和手写数据缓冲大小

mmi_pen_register_stroke_down_handler(mmi_pen_editor_stroke_down_handler);

mmi_pen_register_stroke_move_handler(NULL, NULL, mmi_pen_editor_stroke_move_handler);

mmi_pen_register_stroke_up_handler(mmi_pen_editor_stroke_up_handler);

--注册触摸笔手写模式下down,move和up三种状态的回调函数

在进行了以上的操作以后,每次当用户在手写区滑动触笔时,相应的回调会被调用。

1.触笔点下:将开始点的坐标数据放入缓冲区,进入手写状态,更新相关的全局变量,并开始设置新的layer用于绘制当前手写轨迹。

2.触笔移动: 将移动中的每个坐标掉放入设置好的数据缓冲区内,直至缓冲区满。目前MTK提供的代码里,一次手写最大支持500个点的数据。

3.触笔抬起:启动一个定时器。

4.如果直到定时器超时,触笔的状态还是UP状态,则意味着一次手写的完成;

此时reset掉在状态1中设置的新的layer层,并将所有的手写数据传递给手写识别软件来获得此次手写的候选字项。

5.如果定时器超时的时刻,触笔的状态是DOWN的状态,则意味着用户又开始进行新的笔划输入了,本次手写还没有完成。状态继续回到1或者2。

B. 虚拟键盘输入

虚拟键盘的输入较为简单,同所有其他的控件一样,虚拟键盘也是一个的控件。对该控件的触摸输入只需要注册其对应的处理函数即可。

mmi_pen_register_abort_handler(mmi_pen_editor_pen_abort_handler);

mmi_pen_register_down_handler(mmi_pen_editor_pen_down_handler);

mmi_pen_register_long_tap_handler(mmi_pen_editor_pen_long_tap_handler);

mmi_pen_register_move_handler(mmi_pen_editor_pen_move_handler);

mmi_pen_register_up_handler(mmi_pen_editor_pen_up_handler);

mmi_pen_register_repeat_handler(mmi_pen_editor_pen_repeat_handler);

在所有使用到虚拟键盘输入的地方,我们都需要调用以上的一些代码片断来设置我们的触摸控制回调函数。

1) 触笔点下虚拟键盘上的某一个键,会触发mmi_pen_editor_pen_down_handler,这个函数会对触摸的区域进行判断,确定是点在某个有效的按键上还是虚拟键盘以外

2) 如果是合法的按键部分,在mmi_pen_editor_pen_up_handler会对其作相应的处理。比如说,在汉字拼音输入法时输入一个字母h,那么mmi_pen_editor_pen_up_handler里会调用

mmi_ime_get_candidates_by_composition来取得该输入的候选字,并且把该候选字显示在虚拟键盘的候选区域内

三.输入法引擎

在上面两个章节的描述时,我们基本上只关注了如何实现输入,但是没有牵涉到输入法引擎的使用。实际中MTK只提供了英文和数字的输入,对于汉字拼音和笔画之类的输入只能采用第三方的输入法引擎来完成。

对于采用了第三方引擎的输入法实现来说,与上面介绍的不同之处就是:我们必须在key handler里面通过调用引擎的APPI来获取相关的候选字。

下面我们以T9输入引擎为例来看看,如果集成一个输入法引擎来实现输入。

T9ChangeLanguageForEMSInputBox(mode);

---根据mode来初始化引擎

T9ClearKeyStarAndPoundHandler();

T9ClearKeyNavigationHandler();

T9ClearKey0To9Handler();

---清除原有keyhandler

SetKeyHandler(handle_category28_change_input_mode,KEY_POUND,KEY_EVENT_DOWN);

SetKeyHandler(T9KeyStarPressHandlerForEMSInputBox,KEY_STAR,KEY_EVENT_DOWN);

SetKeyHandler(T9KeyArrowUPHandlerForEMSInputBox, KEY_UP_ARROW, KEY_EVENT_ DOWN);

SetKeyHandler(T9KeyArrowRightHandlerForEMSInputBox,KEY_RIGHT_ARROW,KEY_EVENT _DOWN);

SetKeyHandler(T9KeyArrowDownHandlerForEMSInputBox, KEY_DOWN_ARROW,

KEY_EVENT_DOWN);

SetKeyHandler(T9KeyArrowLeftHandlerForEMSInputBox, KEY_LEFT_ARROW,

KEY_EVENT_DOWN);

SetKeyHandler(T9Key0PressHandlerForEMSInputBox,KEY_0,KEY_EVENT_DOWN);

SetKeyHandler(T9Key1PressHandlerForEMSInputBox,KEY_1,KEY_EVENT_DOWN);

SetKeyHandler(T9Key2PressHandlerForEMSInputBox,KEY_2,KEY_EVENT_DOWN);

SetKeyHandler(T9Key3PressHandlerForEMSInputBox,KEY_3,KEY_EVENT_DOWN);

SetKeyHandler(T9Key4PressHandlerForEMSInputBox,KEY_4,KEY_EVENT_DOWN);

SetKeyHandler(T9Key5PressHandlerForEMSInputBox,KEY_5,KEY_EVENT_DOWN);

SetKeyHandler(T9Key6PressHandlerForEMSInputBox,KEY_6,KEY_EVENT_DOWN);

SetKeyHandler(T9Key7PressHandlerForEMSInputBox,KEY_7,KEY_EVENT_DOWN);

SetKeyHandler(T9Key8PressHandlerForEMSInputBox,KEY_8,KEY_EVENT_DOWN);

SetKeyHandler(T9Key9PressHandlerForEMSInputBox,KEY_9,KEY_EVENT_DOWN);

---------设置在T9输入时的keyhandler

T9SynT9WithInputBoxForEMSInputBox();

T9ScreenStateChnageForEMSInputBox();

--------改变T9引擎的内部状态

T9InputBoxDisplayForEMSInputBox();

----- 显示T9输入时的输入候选部分界面

以上的代码片断,为进入T9引擎输入法时必须要调用的一段代码。从代码中我们可以看到以下的操作:

1) 初始化引擎

2) 设置key handler;在t9输入法时,几乎所有的有效输入键都被注册到了

T9KeyXPressHandlerForEMSInputBox(其中X代表0-9).而察看相关代码,我们不能发现所有的

T9KeyXPressHandlerForEMSInputBox最后都调用了同一个函数T9Key0To9HandlerForEMSInputBox

3) 维护引擎内部状态

4) 更新界面

在实际的输入中,

1.按键产生,调用T9Key0To9HandlerForEMSInputBox。这个函数根据输入的键值获得候选字数组

2.调用T9ScreenStateChnageForEMSInputBox();改变内部状态机的状态

3.根据内部状态机的状态,更新候选部分和inputbox部分

四.键盘与TOUCH输入结合方式

在实际的情况中,有时候我们往往想鱼与熊掌兼得。那么如果既有键盘又有触摸屏,输入法如何实现呢。

A. 键盘输入和touch输入分别互斥

这种方式相对比较简单,其实只是上面两种方式的简单结合。

实现方法,基本上就是用一个全局变量来区分当前是手写模式还是键盘模式。

如果是键盘模式,我们只能使用假你判输入,控制使其流程走无touchpanel时的路径;

如果是手写模式,我们只能使用touch模式输入,使其走touchpanel输入的路径

在实现结构上无需作大的调整,但是这种方式的一个很大问题就是两种模式对于一些公共的全局变量的维护是一个重点。在实际中,往往会因为在键盘状态时,我们修改了一些全局的变量,可是到了手写模式时,这些变量由于没有很好的同步会引起很多的问题。

目前我们D308就是采用这样的模式的,问题基本上都集中出现在这一块。

B. 键盘输入和touch输入的融合

此种输入方式相对上面的互斥结合来说,在用户友好性方面具有更大的优势。用户的每个按键输入都在虚拟键盘上有所体现。比如用户在拼音输入法下按下2键,虚拟键盘就会显示A,并出现相应的候选字。同时也支持用户使用触摸选取的方式来进行选择。

由于是跟键盘输入的结合,自然也有一键候选和多键候选两种模式。考虑到前者比较简单。这里只对后者做相关的描述。

基本步骤同不使用第三方输入法引擎时的KeyPad多键候选输入一样

1) 为每个输入键建立multitap控件,并初始化

2) 注册key_input_handler,key_down_handler,key_up_handler

3) 为每个输入键注册input_callback和input_complete_callback

它们之间有点不同的在于:input_callback的实现上

在keypad是,inputcallback直接把key_down对应的输入候选显示在inputbox中

而在结合方式时,inputcallback是把key_down对应的输入及通过类似

mmi_ime_get_candidates_by_composition接口获得的候选显示在虚拟键盘上

五.结束语

通过上面四个章节的介绍,我希望能够对输入法部分的大概设计和实现作出一个框架性的介绍。由于时间和篇幅的关系,实际上输入法很多相关的细节并没有在这里一一详述。(比如,所有输入法的实现与inputbox控件的结合是很紧密的。在mtk的系统里,光inputbox的类型就多达10种。而在输入法更新界面时很大一部分工作就是根据各种类型进行界面的resize或者其他调整,否则界面就会发现混乱。)。如果大家对文章里的内容有疑问的话,欢迎大家就这部分内容跟我进行交流。

相关主题
相关文档
最新文档