MTK调试阅读
2012-10-19 10:36
134 查看
VS2008代码中设个断点,然后按F5调试,然后菜单栏->调试->窗口, 里面有反汇编,内存等。
VC6.0调试过程中经常使用的快捷键如下:
F5调试,F10单步调试,shift+F5退出调试;
F10单语句执行,F11单指令执行,Ctrl+F10执行至光标处;
F9按行设置/取消断点, Alt+F9可按行,按数据或按消息设置断点;
调试时,按Alt+3打开跟踪窗口,
Alt+4打开变量窗口,
Alt+5打开寄存器窗口,
Alt+6打开内存窗口,
Alt+7打开堆栈窗口,
Alt+8打开汇编指令窗口;
VC++断点的使用:
a.如何使用断点快速定位到问题点呢?如果我们发现,拨号窗口显示出了问题,但我们对代码不熟,不知道拨号窗口的代码在哪个文件,哪一行,我们就可以在EntryNewScreen函数上打断点,当进入拨号时他就会停下来,这时我们能过堆栈窗口信息就可以很轻松的找到这个窗口的实现函数。详细研究代码,就可以找到解决方法.
b.断点可以用于快速解决窗口显示问题,比如我们的拨号窗口,有一个图片显示不正常,这时我们可以在绘图函数gdi_image_codec_draw上打上断点,进入拨号窗口中,每一次显示图片,都会在该函数上停下来,结合堆栈,我们可以很容易找到是哪个地方代码出来问题,从而找到解决方法.有关此类的函数太多,不一一举例.
c.断点可以用来研究全局变量被意外修改问题,我们打开断点对话框,选第二个选项卡,把需要跟踪的变量打进去,当每次变量变化时,VC都会停下来等我们调试.也可以设置条件,假设某全局变量U8 g_XXX, 其值等于5时会出错,但你不知道这个全局变量在什么地方被什么代码赋值为5,这时就可以设置数据断点,在第二选项卡上面的对话框里输入g_XXX,靠下的对话框里输入5,当其值为5时就会停下来.
d.研究代码也可以使用断点,比如MTK代码里使用有很多函数指针封装,例如gui_print_text指针,你想研究他的实现过程,但由于是指针,你找不到他的函数体,这时你就可以在数据断点中,把指针gui_print_text输入进去,重启模拟器时,他就会定位到ui_print_text函数处.
断点可以使用于你需要调试的任何场合,但过多的断点会影响你查找问题的速度,等熟练使用时,就可以有针对性的对某些变量和函数打断点以解决问题.这是一个积累的过程。
堆栈调试,Alt+7打开堆栈窗口.该窗口中我们可以看到函数之间的调用关系,这是十分有用的,一般都是结合断点使用,定位BUG和研究代码十分有用。
变量窗口,Alt+4打开变量窗口,该窗口会自动显示断点代码处使用的变量及其值,阅读代码解决BUG时使用,单步执行时经常参考该窗口数据。
WATCH窗口,按Alt+3打开,由于变量窗口自动显示的变量有时不是我们需要的,这时就可以把我们需要查看的变量拖放到该窗口研究,结合断点使用,并且这里也支持表达式取值,真是太棒了。
内存窗口,Alt+6打开内存窗口,内存窗口可以显示一块内存的内容,这是很有用的,比如我们要跟踪短信内容,有一个短信内容的指针,把该指针输入WATCH窗口,只能看到该指针指向的第一个值,要看其他的,会很麻烦,你只能输入表达式,但你把该指针输入内存窗口,就不必这样费事了。
汇编指令窗口,Alt+8打开汇编指令窗口,这个窗口用处不是很大,学习汇编的话,还是有用处的.一般情况下,如果第三方的库文件出了问题,也就只能使用这个窗口调试了.普通情况下,如果错误定位在C标准库文件的汇编代码上,只有一种可能,就是你的调用出错了。
调试占了研发的很大一部分时间,调试的基本技术就这样,一般情况下是综合运用,灵活掌握,以期快速解决问题,稳定代码.剩下就是经验积累的问题了.
按键处理断点调试法:
主要简单分析一下左右软键的事件,以左软键事件为例:
牵涉到的常用函数:
void SetKeyHandler( FuncPtr funcPtr, U16 keyCode, U16 keyType );
void SetLeftSoftkeyFunction( void (*f)(void), MMI_key_event_type k );
void ChangeLeftSoftkey( U16 s, U16 i );
①SetKeyHandler
函数SetKeyHandler的大概实现如下(精简版):
其实就是把函数指针传递到currKeyFuncPtrs[][]这个二维数组里。
即把需要起作用的函数指针传递到全局矩阵数组currKeyFuncPtrs[keyCode][keyType]的指定位置,然后exec_key_handler()这个函数就从这个数组里面取出对应的函数指针执行。
static void exec_key_handler(mmi_key_evt_struct *evt_p)//(精简了)
{
U16 ucs2_value = 0;
U32 special_key_flag = 0;
FuncPtr curr_func_ptr;
SetkeyInfo(evt_p->cvt_code, evt_p->mmi_key_type);
if (mmi_frm_dispatch_key_event(evt_p->cvt_code, evt_p->mmi_key_type, ucs2_value, special_key_flag) == MMI_FALSE)
{
/* get the key handler */
curr_func_ptr = get_key_handler(evt_p->cvt_code, evt_p->mmi_key_type);
/* invoke the key handler */
if (curr_func_ptr)
{
(*curr_func_ptr)();
}
}
/* If finish the key up handler, we reset the current key info. */
if (evt_p->mmi_key_type == KEY_EVENT_UP)
{
SetkeyInfo(evt_p->cvt_code, MAX_KEY_TYPE);
}
}
static FuncPtr get_key_handler(S16 mmi_key_code, S16 mmi_key_type)
{
FuncPtr currFuncPtr = NULL;
S32 i;
for (i = 0; i < SPE_KEY_HDL_TBL_NUM; i++)
{
if ((currFuncPtr = (* g_key_handler[i])(mmi_key_code, mmi_key_type)) != NULL)
{
break;
}
}
return currFuncPtr;
}
//静态常数组
const static get_func_ptr g_key_handler[] =
{
#if defined(__MMI_QWERTY_KEYPAD_SUPPORT__)
get_any_key_handler,
#endif
get_repeat_key_handler,
#ifdef __MMI_WGUI_MINI_TAB_BAR__
get_mini_tab_bar_key_handler,
#endif
#ifdef __MMI_SCREEN_SNAPSHOT__
get_screen_snapshot_key_handler,
#endif
#ifdef __LSK_KEYSEND2_IN_ONE__
/* under construction !*/
#endif
get_default_key_handler
};
get_default_key_handler 这里面就调用了currKeyFuncPtrs这个数组。流程就是这样的。
static FuncPtr get_default_key_handler(S16 mmi_key_code, S16 mmi_key_type)
{
if (mmi_key_code < MAX_KEYS)
{
return currKeyFuncPtrs[mmi_key_code][mmi_key_type];
}
else
{
return NULL;
}
}
②SetLeftSoftkeyFunction
void SetLeftSoftkeyFunction(void (*f) (void), MMI_key_event_type k)
{
register_left_softkey_handler();
set_left_softkey_function(f, k);
mmi_imc_key_setup_rsk_function(f);
}
如:SetLeftSoftkeyFunction(EntryMainMenuFromIdleScreen, KEY_EVENT_UP);
该函数内部主要流程:
Step1. call register_left_softkey_handler( )
这个函数会调用 SetKeyHandler以存储需要起作用的函数(left_softkey_down/left_softkey_up) 。
以left_softkey_down为例, 该函数首先首先刷新按键区域图像(redraw_softkey), 然后执行关联函数(softkey_functions[key][k]).
宏定义:
#define register_left_softkey_handler() register_softkey_handler(MMI_LEFT_SOFTKEY)
void register_softkey_handler(WGUI_SOFTKEY_ENUM key)
{
switch (key)
{
case MMI_LEFT_SOFTKEY:
SetKeyHandler(left_softkey_down, KEY_LSK, KEY_EVENT_DOWN);
SetKeyHandler(left_softkey_up, KEY_LSK, KEY_EVENT_UP);
left_softkey_keyboard_handler_active = 1;
break;
case MMI_RIGHT_SOFTKEY:
SetKeyHandler(right_softkey_down, KEY_RSK, KEY_EVENT_DOWN);
SetKeyHandler(right_softkey_up, KEY_RSK, KEY_EVENT_UP);
right_softkey_keyboard_handler_active = 1;
break;
case MMI_CENTER_SOFTKEY:
SetKeyHandler(center_softkey_down, KEY_CSK, KEY_EVENT_DOWN);
SetKeyHandler(center_softkey_up, KEY_CSK, KEY_EVENT_UP);
center_softkey_keyboard_handler_active = 1;
break;
}
}
void left_softkey_down(void)
{
if (!(MMI_softkeys[MMI_LEFT_SOFTKEY].flags & UI_BUTTON_STATE_CLICKED))
{
/* change the state of LSK button */
MMI_softkeys[MMI_LEFT_SOFTKEY].flags |= UI_BUTTON_STATE_CLICKED;
MMI_softkeys[MMI_LEFT_SOFTKEY].flags |= UI_BUTTON_STATE_DOWN;
redraw_softkey(MMI_LEFT_SOFTKEY); /* redraw LSK */
/* call function handlers of LSK down */
execute_softkey_function(KEY_EVENT_DOWN, MMI_LEFT_SOFTKEY);
}
}
void redraw_softkey(WGUI_SOFTKEY_ENUM key)
{
gdi_layer_lock_frame_buffer();
#if defined(__PWV_UI_BLACKBERRY_STYLE__)
{
extern MMI_BOOL g_bMainmenu;
extern MMI_BOOL g_bCalculator;
extern MMI_BOOL g_bSmartDial;
if((g_bMainmenu == MMI_FALSE)&&(g_bCalculator==MMI_FALSE)&&(g_bSmartDial))
{
hide_softkey[key] ();
show_softkey(key);
}
}
#else
hide_softkey[key] ();
show_softkey(key);
#endif
gdi_layer_unlock_frame_buffer();
}
void execute_softkey_function(MMI_key_event_type k, WGUI_SOFTKEY_ENUM key)
{
if ((MMI_softkeys[key].text == NULL) && (MMI_softkeys[key].normal_up_icon == NULL))
{
if (k == KEY_EVENT_UP)
{
clear_softkey_handler(key);
}
return;
}
if (softkey_functions[key][k] != NULL)
{
if (GetActiveScreenId() == MAIN_MENU_SCREENID)
{
gui_screen_switch_effect_setup_MM();
}
softkey_functions[key][k] ();
}
}
Step2.
在上一步里我们会发现,softkey_functions[key][k]里的函数指针没有初始化
通过调用函数 set_left_softkey_function(f, k);
完成赋值softkey_functions[key][k] = f; 这样,就成功的把按键按下/放开的作用函数与具体的动作关联起来了。
#define set_left_softkey_function(FUNC, KEY_TYPE) set_softkey_function(FUNC, KEY_TYPE, MMI_LEFT_SOFTKEY)
如:set_left_softkey_function(EntryMainMenuFromIdleScreen, KEY_EVENT_UP);
set_softkey_function(EntryMainMenuFromIdleScreen, KEY_EVENT_UP,MMI_LEFT_SOFTKEY);
void set_softkey_function(void (*f) (void), MMI_key_event_type k, WGUI_SOFTKEY_ENUM key)
{
switch (key)
{
case MMI_LEFT_SOFTKEY:
if (k == KEY_LONG_PRESS)
{
SetKeyHandler(f, KEY_LSK, KEY_LONG_PRESS);
}
softkey_functions[key][k] = f;
break;
case MMI_RIGHT_SOFTKEY:
if (k == KEY_LONG_PRESS)
{
SetKeyHandler(f, KEY_RSK, KEY_LONG_PRESS);
}
softkey_functions[key][k] = f;
break;
case MMI_CENTER_SOFTKEY:
if (k == KEY_LONG_PRESS)
{
SetKeyHandler(f, KEY_CSK, KEY_LONG_PRESS);
}
softkey_functions[key][k] = f;
if (MMI_TRUE == mmi_frm_kbd_is_key_supported(KEY_ENTER))
{
register_center_softkey_to_enter_key();
}
break;
}
}
Step3. 最后调用mmi_imc_key_setup_lsk_function(f) ,处理输入法imc(input method controller),将上述函数与特定的输入(如触摸笔)关联起来。
void mmi_imc_key_setup_lsk_function(FuncPtr f)
{
g_imc_key_inputbox_LSK_function = f;
}
SetLeftSoftkeyFunction还可以识别长按状态并且可以关联触摸笔操作等。
③ChangeLeftSoftkey
主要执行流程:
Step1. call change_left_softkey: 设置左软键图表,文字
Step2. redraw_softkey: 刷新左软键显示区域
打断点:Alt+F9输入left_softkey_down
开始代码阅读(待续):
①T9main.c
This file is to implement Man Machine Interface between UI layer and T9 core engine.该文件致于实现图形界面层与T9输入法核心引擎之间人机界面。
所谓T9,即为输入法,T9输入法全名为智能输入法,字库容量九千多字,支持十多种语言,包括欧洲及中文繁体、简体、香港常用字等。该输入法是由美国特捷通讯(Tegic Communications)软件公司研制的。
VC6.0调试过程中经常使用的快捷键如下:
F5调试,F10单步调试,shift+F5退出调试;
F10单语句执行,F11单指令执行,Ctrl+F10执行至光标处;
F9按行设置/取消断点, Alt+F9可按行,按数据或按消息设置断点;
调试时,按Alt+3打开跟踪窗口,
Alt+4打开变量窗口,
Alt+5打开寄存器窗口,
Alt+6打开内存窗口,
Alt+7打开堆栈窗口,
Alt+8打开汇编指令窗口;
VC++断点的使用:
a.如何使用断点快速定位到问题点呢?如果我们发现,拨号窗口显示出了问题,但我们对代码不熟,不知道拨号窗口的代码在哪个文件,哪一行,我们就可以在EntryNewScreen函数上打断点,当进入拨号时他就会停下来,这时我们能过堆栈窗口信息就可以很轻松的找到这个窗口的实现函数。详细研究代码,就可以找到解决方法.
b.断点可以用于快速解决窗口显示问题,比如我们的拨号窗口,有一个图片显示不正常,这时我们可以在绘图函数gdi_image_codec_draw上打上断点,进入拨号窗口中,每一次显示图片,都会在该函数上停下来,结合堆栈,我们可以很容易找到是哪个地方代码出来问题,从而找到解决方法.有关此类的函数太多,不一一举例.
c.断点可以用来研究全局变量被意外修改问题,我们打开断点对话框,选第二个选项卡,把需要跟踪的变量打进去,当每次变量变化时,VC都会停下来等我们调试.也可以设置条件,假设某全局变量U8 g_XXX, 其值等于5时会出错,但你不知道这个全局变量在什么地方被什么代码赋值为5,这时就可以设置数据断点,在第二选项卡上面的对话框里输入g_XXX,靠下的对话框里输入5,当其值为5时就会停下来.
d.研究代码也可以使用断点,比如MTK代码里使用有很多函数指针封装,例如gui_print_text指针,你想研究他的实现过程,但由于是指针,你找不到他的函数体,这时你就可以在数据断点中,把指针gui_print_text输入进去,重启模拟器时,他就会定位到ui_print_text函数处.
断点可以使用于你需要调试的任何场合,但过多的断点会影响你查找问题的速度,等熟练使用时,就可以有针对性的对某些变量和函数打断点以解决问题.这是一个积累的过程。
堆栈调试,Alt+7打开堆栈窗口.该窗口中我们可以看到函数之间的调用关系,这是十分有用的,一般都是结合断点使用,定位BUG和研究代码十分有用。
变量窗口,Alt+4打开变量窗口,该窗口会自动显示断点代码处使用的变量及其值,阅读代码解决BUG时使用,单步执行时经常参考该窗口数据。
WATCH窗口,按Alt+3打开,由于变量窗口自动显示的变量有时不是我们需要的,这时就可以把我们需要查看的变量拖放到该窗口研究,结合断点使用,并且这里也支持表达式取值,真是太棒了。
内存窗口,Alt+6打开内存窗口,内存窗口可以显示一块内存的内容,这是很有用的,比如我们要跟踪短信内容,有一个短信内容的指针,把该指针输入WATCH窗口,只能看到该指针指向的第一个值,要看其他的,会很麻烦,你只能输入表达式,但你把该指针输入内存窗口,就不必这样费事了。
汇编指令窗口,Alt+8打开汇编指令窗口,这个窗口用处不是很大,学习汇编的话,还是有用处的.一般情况下,如果第三方的库文件出了问题,也就只能使用这个窗口调试了.普通情况下,如果错误定位在C标准库文件的汇编代码上,只有一种可能,就是你的调用出错了。
调试占了研发的很大一部分时间,调试的基本技术就这样,一般情况下是综合运用,灵活掌握,以期快速解决问题,稳定代码.剩下就是经验积累的问题了.
按键处理断点调试法:
主要简单分析一下左右软键的事件,以左软键事件为例:
牵涉到的常用函数:
void SetKeyHandler( FuncPtr funcPtr, U16 keyCode, U16 keyType );
void SetLeftSoftkeyFunction( void (*f)(void), MMI_key_event_type k );
void ChangeLeftSoftkey( U16 s, U16 i );
①SetKeyHandler
函数SetKeyHandler的大概实现如下(精简版):
void SetKeyHandler(FuncPtr funcPtr,U16 keyCode,U16 keyType) { currKeyFuncPtrs[keyCode][keyType] = funcPtr; }
其实就是把函数指针传递到currKeyFuncPtrs[][]这个二维数组里。
即把需要起作用的函数指针传递到全局矩阵数组currKeyFuncPtrs[keyCode][keyType]的指定位置,然后exec_key_handler()这个函数就从这个数组里面取出对应的函数指针执行。
static void exec_key_handler(mmi_key_evt_struct *evt_p)//(精简了)
{
U16 ucs2_value = 0;
U32 special_key_flag = 0;
FuncPtr curr_func_ptr;
SetkeyInfo(evt_p->cvt_code, evt_p->mmi_key_type);
if (mmi_frm_dispatch_key_event(evt_p->cvt_code, evt_p->mmi_key_type, ucs2_value, special_key_flag) == MMI_FALSE)
{
/* get the key handler */
curr_func_ptr = get_key_handler(evt_p->cvt_code, evt_p->mmi_key_type);
/* invoke the key handler */
if (curr_func_ptr)
{
(*curr_func_ptr)();
}
}
/* If finish the key up handler, we reset the current key info. */
if (evt_p->mmi_key_type == KEY_EVENT_UP)
{
SetkeyInfo(evt_p->cvt_code, MAX_KEY_TYPE);
}
}
static FuncPtr get_key_handler(S16 mmi_key_code, S16 mmi_key_type)
{
FuncPtr currFuncPtr = NULL;
S32 i;
for (i = 0; i < SPE_KEY_HDL_TBL_NUM; i++)
{
if ((currFuncPtr = (* g_key_handler[i])(mmi_key_code, mmi_key_type)) != NULL)
{
break;
}
}
return currFuncPtr;
}
//静态常数组
const static get_func_ptr g_key_handler[] =
{
#if defined(__MMI_QWERTY_KEYPAD_SUPPORT__)
get_any_key_handler,
#endif
get_repeat_key_handler,
#ifdef __MMI_WGUI_MINI_TAB_BAR__
get_mini_tab_bar_key_handler,
#endif
#ifdef __MMI_SCREEN_SNAPSHOT__
get_screen_snapshot_key_handler,
#endif
#ifdef __LSK_KEYSEND2_IN_ONE__
/* under construction !*/
#endif
get_default_key_handler
};
get_default_key_handler 这里面就调用了currKeyFuncPtrs这个数组。流程就是这样的。
static FuncPtr get_default_key_handler(S16 mmi_key_code, S16 mmi_key_type)
{
if (mmi_key_code < MAX_KEYS)
{
return currKeyFuncPtrs[mmi_key_code][mmi_key_type];
}
else
{
return NULL;
}
}
②SetLeftSoftkeyFunction
void SetLeftSoftkeyFunction(void (*f) (void), MMI_key_event_type k)
{
register_left_softkey_handler();
set_left_softkey_function(f, k);
mmi_imc_key_setup_rsk_function(f);
}
如:SetLeftSoftkeyFunction(EntryMainMenuFromIdleScreen, KEY_EVENT_UP);
该函数内部主要流程:
Step1. call register_left_softkey_handler( )
这个函数会调用 SetKeyHandler以存储需要起作用的函数(left_softkey_down/left_softkey_up) 。
以left_softkey_down为例, 该函数首先首先刷新按键区域图像(redraw_softkey), 然后执行关联函数(softkey_functions[key][k]).
宏定义:
#define register_left_softkey_handler() register_softkey_handler(MMI_LEFT_SOFTKEY)
void register_softkey_handler(WGUI_SOFTKEY_ENUM key)
{
switch (key)
{
case MMI_LEFT_SOFTKEY:
SetKeyHandler(left_softkey_down, KEY_LSK, KEY_EVENT_DOWN);
SetKeyHandler(left_softkey_up, KEY_LSK, KEY_EVENT_UP);
left_softkey_keyboard_handler_active = 1;
break;
case MMI_RIGHT_SOFTKEY:
SetKeyHandler(right_softkey_down, KEY_RSK, KEY_EVENT_DOWN);
SetKeyHandler(right_softkey_up, KEY_RSK, KEY_EVENT_UP);
right_softkey_keyboard_handler_active = 1;
break;
case MMI_CENTER_SOFTKEY:
SetKeyHandler(center_softkey_down, KEY_CSK, KEY_EVENT_DOWN);
SetKeyHandler(center_softkey_up, KEY_CSK, KEY_EVENT_UP);
center_softkey_keyboard_handler_active = 1;
break;
}
}
void left_softkey_down(void)
{
if (!(MMI_softkeys[MMI_LEFT_SOFTKEY].flags & UI_BUTTON_STATE_CLICKED))
{
/* change the state of LSK button */
MMI_softkeys[MMI_LEFT_SOFTKEY].flags |= UI_BUTTON_STATE_CLICKED;
MMI_softkeys[MMI_LEFT_SOFTKEY].flags |= UI_BUTTON_STATE_DOWN;
redraw_softkey(MMI_LEFT_SOFTKEY); /* redraw LSK */
/* call function handlers of LSK down */
execute_softkey_function(KEY_EVENT_DOWN, MMI_LEFT_SOFTKEY);
}
}
void redraw_softkey(WGUI_SOFTKEY_ENUM key)
{
gdi_layer_lock_frame_buffer();
#if defined(__PWV_UI_BLACKBERRY_STYLE__)
{
extern MMI_BOOL g_bMainmenu;
extern MMI_BOOL g_bCalculator;
extern MMI_BOOL g_bSmartDial;
if((g_bMainmenu == MMI_FALSE)&&(g_bCalculator==MMI_FALSE)&&(g_bSmartDial))
{
hide_softkey[key] ();
show_softkey(key);
}
}
#else
hide_softkey[key] ();
show_softkey(key);
#endif
gdi_layer_unlock_frame_buffer();
}
void execute_softkey_function(MMI_key_event_type k, WGUI_SOFTKEY_ENUM key)
{
if ((MMI_softkeys[key].text == NULL) && (MMI_softkeys[key].normal_up_icon == NULL))
{
if (k == KEY_EVENT_UP)
{
clear_softkey_handler(key);
}
return;
}
if (softkey_functions[key][k] != NULL)
{
if (GetActiveScreenId() == MAIN_MENU_SCREENID)
{
gui_screen_switch_effect_setup_MM();
}
softkey_functions[key][k] ();
}
}
Step2.
在上一步里我们会发现,softkey_functions[key][k]里的函数指针没有初始化
通过调用函数 set_left_softkey_function(f, k);
完成赋值softkey_functions[key][k] = f; 这样,就成功的把按键按下/放开的作用函数与具体的动作关联起来了。
#define set_left_softkey_function(FUNC, KEY_TYPE) set_softkey_function(FUNC, KEY_TYPE, MMI_LEFT_SOFTKEY)
如:set_left_softkey_function(EntryMainMenuFromIdleScreen, KEY_EVENT_UP);
set_softkey_function(EntryMainMenuFromIdleScreen, KEY_EVENT_UP,MMI_LEFT_SOFTKEY);
void set_softkey_function(void (*f) (void), MMI_key_event_type k, WGUI_SOFTKEY_ENUM key)
{
switch (key)
{
case MMI_LEFT_SOFTKEY:
if (k == KEY_LONG_PRESS)
{
SetKeyHandler(f, KEY_LSK, KEY_LONG_PRESS);
}
softkey_functions[key][k] = f;
break;
case MMI_RIGHT_SOFTKEY:
if (k == KEY_LONG_PRESS)
{
SetKeyHandler(f, KEY_RSK, KEY_LONG_PRESS);
}
softkey_functions[key][k] = f;
break;
case MMI_CENTER_SOFTKEY:
if (k == KEY_LONG_PRESS)
{
SetKeyHandler(f, KEY_CSK, KEY_LONG_PRESS);
}
softkey_functions[key][k] = f;
if (MMI_TRUE == mmi_frm_kbd_is_key_supported(KEY_ENTER))
{
register_center_softkey_to_enter_key();
}
break;
}
}
Step3. 最后调用mmi_imc_key_setup_lsk_function(f) ,处理输入法imc(input method controller),将上述函数与特定的输入(如触摸笔)关联起来。
void mmi_imc_key_setup_lsk_function(FuncPtr f)
{
g_imc_key_inputbox_LSK_function = f;
}
SetLeftSoftkeyFunction还可以识别长按状态并且可以关联触摸笔操作等。
③ChangeLeftSoftkey
主要执行流程:
Step1. call change_left_softkey: 设置左软键图表,文字
Step2. redraw_softkey: 刷新左软键显示区域
打断点:Alt+F9输入left_softkey_down
开始代码阅读(待续):
①T9main.c
This file is to implement Man Machine Interface between UI layer and T9 core engine.该文件致于实现图形界面层与T9输入法核心引擎之间人机界面。
所谓T9,即为输入法,T9输入法全名为智能输入法,字库容量九千多字,支持十多种语言,包括欧洲及中文繁体、简体、香港常用字等。该输入法是由美国特捷通讯(Tegic Communications)软件公司研制的。
相关文章推荐
- Eclipse断点调试 分类: Java 2015-07-28 14:38 12人阅读 评论(0) 收藏
- VC下ffmpeg例程调试报错处理 分类: ffmpeg-SDL-VLC-Live555 2013-08-23 09:24 2466人阅读 评论(1) 收藏
- DDMS调试方法介绍 分类: Android开发 2014-05-30 10:54 51人阅读 评论(0) 收藏
- MTK CCT之CAMERA TUNNING调试学习总结
- linux 下c 编译和调试 分类: 嵌入式开发学习 2011-03-10 20:33 2433人阅读 评论(0) 收藏
- 调试MVC源代码时"[A]System.Web.WebPages.Razor.Configuration.HostSection 无法强制转换为 ..."解决办法 分类: ASP.NET MVC 2012-12-09 10:49 6506人阅读 评论(3) 收藏
- eclipse 远程调试hadoop代码 分类: Linux hadoop 2015-05-27 22:14 148人阅读 评论(0) 收藏
- MTK camera 闪光灯Flashlight驱动调试流程
- [Chrome源码阅读] Chrome的多进程调试方法
- MTK_显示屏调试
- MTK camera 闪光灯Flashlight驱动调试流程
- MTK模拟器调试指南
- Mtk WIFI常用调试命令
- MTK调试入门之一 --- TRACE使用的技巧
- MTK调试的奇淫技巧
- MTK CCT之CAMERA TUNNING调试学习总结
- DDMS调试方法 分类: Android开发 2014-05-30 10:54 72人阅读 评论(0) 收藏
- mtk android sd卡调试
- 调试MVC源代码时"[A]System.Web.WebPages.Razor.Configuration.HostSection 无法强制转换为 ..."解决办法 分类: ASP.NET MVC 2012-12-09 10:49 6506人阅读 评论(3) 收藏
- eclipse 远程调试hadoop代码 分类: Linux hadoop 2015-05-27 22:14 149人阅读 评论(0) 收藏