1按鍵處理流程
主要简单分析一下左右软件的事件,以左软键事件为例
牵涉到的常用函数:
1.
2.
2高亮處理機制
MTK高亮机制
1介绍:...3
2相关函数和变量列表:...3
3高亮机制说明:...5
4相关知识点说明:...7
1介绍:
本文旨在介绍MTK平台高亮机制的处理逻辑,相信能对刚入手MTK平台的同学有一定帮助,也能给平时为了项目进度和其他原因,对MTK的这些基本常识不求甚解,只能依葫芦画瓢的添加菜单和处理函数的同学一个警醒和帮助,能主动去深入了解问题和提高自己。
本人从事MTK的时间也不长,上面的话有些托大,对新手还是说得过去的。文档中有些地方不正确和清楚的,欢迎评论和讨论。
2相关函数和变量列表:
voidRegisterHighlightHan
注册窗口的通用高亮处理函数。
MMI_list_highlight_handler
通用高亮处理函数的全局变量指针。
voidExecuteCurrHiliteHan
当前高亮菜单项的通用处理函数,它会找到菜单项对应的处理函数。一般在窗口创建过程中被创建RegisterHighlightHandler
FuncPtrmmi_frm_get_hilite_hdlr(U16menu_id)
获取menu_id对应的菜单高亮函数,从两个函数指针数组里获取。先查找动态菜单的高亮函数指针数组,这个是在程序中动态添加的数组;如果找不到,再到静态数组里查找,这个数组是在编译过程中生成的,通常我们在res_mainmenu.c等函数里增加的菜单会被资源生成工具编译成一个静态数组。
mmi_frm_int_hilite_hdlr_table[]动态数组。
mmi_frm_const_hilite_hdlr_table[]静态数组。
currParentID
当前父窗口全局变量
voidSetHiliteHandler(U16itemid,FuncPtrhiliteFuncPtr)
设置动态高亮数组的MENUID及它相对应的处理函数,一般用在自定义的菜单项。比如在图片浏览、JAVA应用、WAP记录等不可预期菜单项数目的环境,我们不可能做静态的MENUID和处理函数,就需要用到动态的实现方式。
hintData[][]
[待确认]:这是一个动态菜单的数据缓冲,和MENUID一一对应。通俗一点说,就是菜单的显示字符串。网上有文章对此以及ConstructHintsList()理解应该有误,主要是因为代码里该函数注释说是处理静态的,应该是注释错了。引用一段描述:
3、ConstructHintsList()
ConstructsHintListforast
voidConstructHintsList(U16parentID,U8**hintArray)
{。。。。。。
(*maxHiliteInfo[hiliteItemID[i]].hintFuncPtr)(idx);//SetHintHandler注册的函数的函数在此被执行
hintArray[idx]=hintData[idx];//该语句是该函数的核心,就是将全局变量hintData[idx]数组地址
//赋给用户传过来的指针数组;至于hintData[idx]中是否有数据不
//管;hintData[idx]的数据会在调用SetHintHandler注册的函数时对其
//进行初始化;要记住SetHintHandler注册的函数在SetHiliteHandler注册的
//函数之前执行。
我认为ConstructHintsList()是创建动态菜单的,时间关系,待分析。
3高亮机制说明:
3.1使用流程
每个窗口进入后基本都有类似下面的一段程序:
。。。。。。
EntryNewScreen(EM_DEBUG_INFO_SCR,NULL,EntryEMDebugInfo,NULL);
guiBuffer=GetCurrGuiBuffer(EM_DEBUG_INFO_SCR);
nItems=GetNumOfChild(EM_DEBUG_INFO_MENUID);
GetSequenceStringIds(EM_DEBUG_INFO_MENUID,ItemList);
SetParentHandler(EM_DEBUG_INFO_MENUID);
RegisterHighlightHandler
ShowCategory52Screen(。。。)
SetRightSoftkeyFunction(GoBackHistory,KEY_EVENT_UP);
。。。。。。
3.2分析
这是窗口建立过程的一个通用处理结构,这里简单说明一下,每个函数的具体实现和功能请阅读代码。
EntryNewScreen初始化建立一个窗口需要的变量和过程,并退出上一个窗口,清除按键处理函数等;
SetParentHandler很重要,设置当前父窗口全局变量的MENUID,用来定位到当前是在哪一个窗口,后面依据他来在菜单树中查找到高亮的菜单项的MENUID,找到菜单项的MENUID后,通过mmi_frm_get_hilite_hdlr(U16menu_id)可以找到菜单项对应的高亮函数;RegisterHighlightHandler
ShowCategory52Screen()只是一个窗口界面绘制函数,和事件处理逻辑没有关系。
SetRightSoftkeyFunction(GoBackHistory,KEY_EVENT_UP)等函数设置这个窗口要响应哪些按键事件,并设置好相应的处理函数。
3.3高亮函数触发过程
RegisterHighlightHandler
由于MTK平台支持各种菜单形式,比如纯文本的菜单、带CHECKBOX的、带RADIO的、带一个图片的、带两个图片的、两行的。我们现在只对一种标准菜单进行分析,其他形式的分析方法相同。
standard_list_highlight_handler(S32item_index)里会执行注册的高亮处理函数MMI_list_highlight_handler,而standard_list_highlight_handler本身又是一个注册函数,在wgui_fixed_list_create_text_menu()里会被注册到MMI_fixed_list_menu.item_highlighted,MMI_fixed_list_menu是菜单组件的数据结构,包含有菜单组件从显示到功能处理函数的所有数据,具体每个组件怎么被显示,怎么响应功能按键就不在这里讨论了,后续我可能会写出文档,有兴趣的同学自己看代码,效果会更好。
这里简单说一下,MMI_fixed_list_menu.item_highlighted在这个组件里,会被gui_fixed_list_menu_switch_highlighted_item()函数来执行,而gui_fixed_list_menu_switch_highlighted_item()则在上下按键执行的时候被执行,比响应上按键的函数是voidfixed_list_goto_previous_item(void),它调用voidgui_fixed_list_menu_goto_previous_item(fixed_list_menu*m),而voidgui_fixed_list_menu_goto_previous_item(fixed_list_menu*m)则调用gui_fixed_list_menu_switch_highlighted_item(),整个触发过程就完成了。
关于上下按键的注册,则在wgui_fixed_list_create_text_menu()里有:
if(flag&WGUI_LIST_MENU_DISABLE_VOL_KEY)
register_fixed_list_keys_ex();
else
register_fixed_list_keys();
来注册按键事件处理函数,其实现过程很简单:
voidregister_fixed_list_keys(void)
{
SetKeyHandler(fixed_list_goto_previous_item,KEY_UP_ARROW,KEY_EVENT_DOWN);
SetKeyHandler(fixed_list_goto_next_item,KEY_DOWN_ARROW,KEY_EVENT_DOWN);
SetKeyHandler(fixed_list_goto_previous_item,KEY_VOL_UP,KEY_EVENT_DOWN);
SetKeyHandler(fixed_list_goto_next_item,KEY_VOL_DOWN,KEY_EVENT_DOWN);
}
关于如何实现按键事件的响应、按键的处理逻辑,又是一个专题了。大致包括键盘中断、去抖、键盘映射、检测、进程通信、应用部分按键处理机制等,有机会再写出文档。
4相关知识点说明:
4.1初始化相关
高亮的一些全局变量会在InitEvents()里进行初始化,在event.c文件里。这个函数在开机过程中的一个调用栈关系如下:
InitEvents();
InitEventHandlersBeforeP
voidMMI_task(oslEntryType*entry_param)
InitEvents();还会在InitFramework()中被调用,而InitFramework()会由于开机的状态不同,如USB开机、闹钟开机等,调用流程也不尽相同。具体的可参见我的另一篇应用开机流程的文档。
4.2菜单结构及查找
4.2.1菜单数数组示意
constCUSTOM_MENUmtk_nCustMenus[]={
{1,0,18,0,16,2,10933,11062,(U16*)nOrderMenuItem_0},
{2,0,3,1,0,1,26218,26085,(U16*)nOrderMenuItem_1},
{3,2,0,1,0,1,555,0,(U16*)0},
{4,2,0,1,0,1,552,0,(U16*)0},
{5,2,0,1,0,1,26173,0,(U16*)0},
{0,0,0,0,0,0,0,0,(U16*)0},
{0,0,0,0,0,0,0,0,(U16*)0},
{0,0,0,0,0,0,0,0,(U16*)0},
{0,0,0,0,0,0,0,0,(U16*)0},
{0,0,0,0,0,0,0,0,(U16*)0},
{0,0,0,0,0,0,0,0,(U16*)0},
。。。。。。。。
}
CUSTOM_MENUnCustMenus[MAX_MENU_ITEMS];
4.2.2通过父窗口MENUID及高亮INDEX找到高亮窗口MENUID
U16GetSeqItemId_Ext(U16parent_item_id,U16index)
{
U8i=0,idx=0;
U16item_id=0;
U8child_count=(U8)nCustMenus[parent_item_id-1].nNumofMenuItem;
#ifdefDEVAPP_RESOURCE
if(parent_item_id>=MENU_ID_DEVAPP_START)
{
returnDevAppGetSeqItemId
}
#endif
for(i=0;i<child_count;i++)
{
item_id=nCustMenus[parent_item_id-1].nOrderMenuItemId[i];
if(!mmi_frm_test_menu_item_hide(item_id))
{
if(idx==index)
{
break;
}
else
{
idx++;
}
}
}
MMI_TRACE(MMI_FW_TRC_G2_GUI,MMI_RESGEN_ALL_MENU_HIDE,parent_item_id);
returnitem_id;
}
4.2.3通过高亮窗口MENUID找到对应的高亮函数
FuncPtrmmi_frm_get_hilite_hdlr(U16menu_id)
{
U32index;
if(mmi_frm_binary_search((U32)menu_id,(mmi_frm_pair_da
(U32)mmi_frm_int_hilite_hdlr_count,&index))
{
returnmmi_frm_int_hilite_hdlr_table[index].hilite_hdlr;
}
elseif(mmi_frm_binary_search((U32)menu_id,
(mmi_frm_pair_da
(U32)ARRAY_COUNT(mmi_frm_const_hilite_hdlr_table),&index))
{
returnmmi_frm_const_hilite_hdlr_table[index].hilite_hdlr;
}
else
{
returnNULL;
}
}
3 MTK 內存管理
1
内存管理。平台不提供动态分配内存的方式;应用程序需要使用动态分配内存时,可以采用以下几种方式:
与系统其他模块共享内存,典型的是使用MED模块的内存;
定义一个静态数组,交给系统adm托管,然后调用kal_adm_alloc、kal_adm_free等内存操作函数实现动态内存分配;
定义一个静态数组,应用自己实现基于此数组的分配和管理,也就是实现自己的内存管理模块。
2
内存分配机制
ADM就完全没有使用操作系统提供的内存管理算法,是平台自创了一套。开发者,可以自己开辟一个POOL,自己在这个池用ADM提供的内存管理API完成内存的动态管理。具体的分配算法,就没有再细看,跟一些通用的内存分配算法应该一致。但是在以前调试一个问题的时候,应该是可以断定,ADM在每一个alloc node前后都加了GAP调试区,来判断是否被overwrite。
3
少于2K 使用get_ctrl_buffer。
大于2K 使用adm
get_ctrl_buffer是在系统定义的一块区域申请空间。 这段空间被分为好多块均等大小。好像有以下几种方式:
2个 1K*2
4个 0.5K*4
6个 0.25K*8
....
申请的话,按首适应算法。这就是你所说的小块内存管理。
adm主要是你自己定义的一块全局数组比如400K.
你可以使用它的adm相关函数去动态申请释放这400K大小的区域,维护也靠你自己。
4 任務管理
任务管理。系统任务采用静态创建方式,静态配置任务优先级、栈大小、任务全局唯一ID等;不提供动态创建Task的方式;任务内部以及任务之间的通信通过内部事件队列和外部事件队列完成
Application_Initialize中的mainp函数,负责任务的创建。我们在代码中见不到任务创建的函数,只需要维护任务初始化参数数据结构。对于系统的那些task信息,都保存在sys_comp_config_tbl变量中,我们看不到。但是MTK提供给客户的custom_comp_config_tbl,客户是可以修改的,在这里用户可以定义自己的task。
关于任务,需要关心数据结构comptask_handler_struct。关于comptask_handler_struct成员的执行顺序,应该是:comp_init_func 在系统还未 schedule 即在Application_Initialize中完成,然后task schedule后执行comp_entry_func。comp_cfg_func、comp_reset_func、comp_end_func我认为无太多意义。
5 事件機制
事件机制。平台事件机制采用“注册一回调”机制,把需要处理的各个按键、触摸屏等通过系统函数注册,当有事件发生时系统调用所注册的监听者。
6 定時器消息機制
MTK定时器消息机制分析
1.
2.
3.
4.
5.