聲明:以上資料來自網上
1.按鍵處理流程
主要簡單分析一下左右軟件的事件,以左軟鍵事件爲例
牽涉到的常用函數:
void SetKeyHandler( FuncPtr funcPtr, U16 keyCode, U16 keyType );
void SetLeftSoftkeyFunction( void (*f)(void), MMI_key_event_type k );
void ChangeLeftSoftkey( U16 s, U16 i );
1. SetKeyHandler與SetLeftSoftkeyFunction
(1). SetKeyHandler
主要作用就是將需要起作用的函數的指針(funcPtr)
-->全局矩陣數組currKeyFuncPtrs[keyCode][keyType]的指定位置 ;
(2). SetLeftSoftkeyFunction
該函數內部主要流程:
Step1. call register_left_softkey_handler( )
這個函數call SetKeyHandler: 存儲需要起作用的函數(left_softkey_down/left_softkey_up)
以left_softkey爲例, 該函數首先首先刷新按鍵區域圖像(redraw_softkey),
然後執行關聯函數(softkey_functions[key][k]).
Step2. 在上一步裏我們會發現,softkey_functions[key][k]裏的函數指針沒有初始化
通過 call set_left_softkey_function(f, k);
--->softkey_functions[key][k] = f;
這樣,就成功的把按鍵按下/放開的作用函數與具體的動作關聯起來了。
Step3. 最後call SetInputboxLSKFunction(f)
--->將上述函數與特定的輸入(如觸摸筆)關聯起來。
(3). 以上兩個函數的主要區別:
SetLeftSoftkeyFunction可以識別長按狀態並且可以關聯觸摸筆操作等。
2. ChangeLeftSoftkey
主要執行流程:
Step1. call change_left_softkey: 設置左軟鍵圖表,文字
Step2. redraw_softkey: 刷新左軟鍵顯示區域
2.高亮處理機制
1 相關函數和變量列表:
voidRegisterHighlightHandler(void(*f)(S32item_index))
註冊窗口的通用高亮處理函數。
MMI_list_highlight_handler
通用高亮處理函數的全局變量指針。
voidExecuteCurrHiliteHandler(S32hiliteid)
當前高亮菜單項的通用處理函數,它會找到菜單項對應的處理函數。一般在窗口創建過程中被創建RegisterHighlightHandler(ExecuteCurrHiliteHandler)。
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()理解應該有誤,主要是因爲代碼裏該函數註釋說是處理靜態的,應該是註釋錯了。引用一段描述:
2、ConstructHintsList()
ConstructsHintListforastaticmenuscreen
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(ExecuteCurrHiliteHandler);
ShowCategory52Screen(。。。)
SetRightSoftkeyFunction(GoBackHistory,KEY_EVENT_UP);
。。。。。。
3.2分析
這是窗口建立過程的一個通用處理結構,這裏簡單說明一下,每個函數的具體實現和功能請閱讀代碼。
EntryNewScreen初始化建立一個窗口需要的變量和過程,並退出上一個窗口,清除按鍵處理函數等;
SetParentHandler很重要,設置當前父窗口全局變量的MENUID,用來定位到當前是在哪一個窗口,後面依據他來在菜單樹中查找到高亮的菜單項的MENUID,找到菜單項的MENUID後,通過mmi_frm_get_hilite_hdlr(U16menu_id)可以找到菜單項對應的高亮函數;RegisterHighlightHandler把ExecuteCurrHiliteHandler註冊成一個通用的高亮處理函數,我們只要告訴ExecuteCurrHiliteHandler當前高亮的菜單項的MENUID,它就能找到執行函數並開始執行了。到這裏就應該已經基本明白了高亮機制了,弄明白了其實也很簡單的^_^;
ShowCategory52Screen()只是一個窗口界面繪製函數,和事件處理邏輯沒有關係。
SetRightSoftkeyFunction(GoBackHistory,KEY_EVENT_UP)等函數設置這個窗口要響應哪些按鍵事件,並設置好相應的處理函數。
3.3高亮函數觸發過程
RegisterHighlightHandler把ExecuteCurrHiliteHandler註冊成一個通用的高亮處理函數,實際上是給MMI_list_highlight_handler函數指針賦值。觸發則需要調用MMI_list_highlight_handler。
由於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)
{
/*----------------------------------------------------------------*/
/*LocalVariables*/
/*----------------------------------------------------------------*/
/*----------------------------------------------------------------*/
/*CodeBody*/
/*----------------------------------------------------------------*/
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();
InitEventHandlersBeforePowerOn();
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)
{
/*----------------------------------------------------------------*/
/*LocalVariables*/
/*----------------------------------------------------------------*/
U8i=0,idx=0;
U16item_id=0;
U8child_count=(U8)nCustMenus[parent_item_id-1].nNumofMenuItem;
/*----------------------------------------------------------------*/
/*CodeBody*/
/*----------------------------------------------------------------*/
#ifdefDEVAPP_RESOURCE
if(parent_item_id>=MENU_ID_DEVAPP_START)
{
returnDevAppGetSeqItemId_Ext(parent_item_id,index);
}
#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))/*theitemisnothidden*/
{
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)
{
/*----------------------------------------------------------------*/
/*LocalVariables*/
/*----------------------------------------------------------------*/
U32index;
/*----------------------------------------------------------------*/
/*CodeBody*/
/*----------------------------------------------------------------*/
/*Firstlysearchthedynamictable*/
if(mmi_frm_binary_search((U32)menu_id,(mmi_frm_pair_data_struct*)mmi_frm_int_hilite_hdlr_table,
(U32)mmi_frm_int_hilite_hdlr_count,&index))
{
returnmmi_frm_int_hilite_hdlr_table[index].hilite_hdlr;
}
/*Andthensearchtheconstanttable.Theconstanttableisgenerantedbyresgen.*/
elseif(mmi_frm_binary_search((U32)menu_id,
(mmi_frm_pair_data_struct*)mmi_frm_const_hilite_hdlr_table,
(U32)ARRAY_COUNT(mmi_frm_const_hilite_hdlr_table),&index))
{
returnmmi_frm_const_hilite_hdlr_table[index].hilite_hdlr;
}
else
{
returnNULL;
}
}