在 MTK MMI event 小结 5 中,提到了event 处理函数 mmi_frm_key_handle,这个函数主要作用是判断是否需要处理按键,从按键缓存里面持续的读取按键信息,然后调用 mmi_frm_convert_process_key_event 进行处理。这个函数没有什么可说的,最多是在屏幕旋转的情况下,把 导航键 转换一下,接着它调用了 ProcessKeyEvent, 这个函数主要是对于一些状态的处理,防止key down 和up 不成对,出现混乱。
void ProcessKeyEvent(U32 MsgType, U16 DeviceKeyCode) { MMI_BOOL isKeyPaired; U16 KeyMapIndex; /*----------------------------------------------------------------*/ /* Code Body */ /*----------------------------------------------------------------*/ // 按键影射,把驱动的按键码,转换成MMI 的 按键消息 KeyMapIndex = mmi_frm_get_idx_from_device_key_code(DeviceKeyCode); if (KeyMapIndex >= MAX_KEYS) { return; } // 处理各种按键事件,没有什么可以多说的, // 主体结构都一样, // 1 判断状态是否正常 // 2 正常 则调用 KeyEventHandler 处理, 否则忽略该事件 if (MsgType == WM_KEYPRESS) { // 这里处理 多案件同时按下的情况。这里需要硬件支持 if ((KeyMapIndex != prevKeyMapIndex) && (g_kbd_concurrent_key_mode == CONCURRENT_KEY_MODE_1_KEY)) { isKeyPaired = (nKeyPadStatus[prevKeyMapIndex] == KEY_EVENT_UP); prevKeyMapIndex = KeyMapIndex; } //判断案件状态是否正常,防止不匹配 if (nKeyPadStatus[KeyMapIndex] == KEY_EVENT_UP) { KEYBRD_MESSAGE KeyBrdMsg; KeyBrdMsg.nKeyCode = nKeyPadMap[KeyMapIndex].nMMIKeyCode; if (mmi_frm_is_2step_keyCode(KeyBrdMsg.nKeyCode)) { nKeyPadStatus[KeyMapIndex] = KEY_HALF_PRESS_DOWN; key_is_pressing_count++; KeyBrdMsg.nMsgType = KEY_HALF_PRESS_DOWN; } else { nKeyPadStatus[KeyMapIndex] = KEY_EVENT_DOWN; /* same with KEY_FULL_PRESS_DOWN */ key_is_pressing_count++; KeyBrdMsg.nMsgType = KEY_EVENT_DOWN; } // 处理按键事件 KeyEventHandler((KEYBRD_MESSAGE*) & KeyBrdMsg); } else { /* Ignore the event */ } } else if (MsgType == WM_KEYRELEASE) { if ((nKeyPadStatus[KeyMapIndex] == KEY_EVENT_DOWN) || (nKeyPadStatus[KeyMapIndex] == KEY_LONG_PRESS) || (nKeyPadStatus[KeyMapIndex] == KEY_REPEAT) || (nKeyPadStatus[KeyMapIndex] == KEY_HALF_PRESS_DOWN)) { KEYBRD_MESSAGE KeyBrdMsg; nKeyPadStatus[KeyMapIndex] = KEY_EVENT_UP; key_is_pressing_count--; KeyBrdMsg.nMsgType = KEY_EVENT_UP; KeyBrdMsg.nKeyCode = nKeyPadMap[KeyMapIndex].nMMIKeyCode; KeyEventHandler((KEYBRD_MESSAGE*) & KeyBrdMsg); } else { /* Ignore the event */ } } /* ++Robin, modified by Max Chen */ else if (MsgType == DRV_WM_KEYLONGPRESS) { if (nKeyPadStatus[KeyMapIndex] == KEY_EVENT_DOWN) { KEYBRD_MESSAGE KeyBrdMsg; nKeyPadStatus[KeyMapIndex] = KEY_LONG_PRESS; KeyBrdMsg.nMsgType = KEY_LONG_PRESS; KeyBrdMsg.nKeyCode = nKeyPadMap[KeyMapIndex].nMMIKeyCode; KeyEventHandler((KEYBRD_MESSAGE*) & KeyBrdMsg); } else { /* Ignore the event */ } } else if (MsgType == DRV_WM_KEYREPEATED) { if ((nKeyPadStatus[KeyMapIndex] == KEY_LONG_PRESS) || (nKeyPadStatus[KeyMapIndex] == KEY_REPEAT)) { KEYBRD_MESSAGE KeyBrdMsg; nKeyPadStatus[KeyMapIndex] = KEY_REPEAT; KeyBrdMsg.nMsgType = KEY_REPEAT; KeyBrdMsg.nKeyCode = nKeyPadMap[KeyMapIndex].nMMIKeyCode; KeyEventHandler((KEYBRD_MESSAGE*) & KeyBrdMsg); } else { /* Ignore the event */ } } else if (MsgType == DRV_WM_KEYFULLPRESS) { /* * Only in two-stage key will have KEY_FULL_PRESS_DOWN, and it followed after KEY_HALF_PRESS_DOWN */ if (nKeyPadStatus[KeyMapIndex] == KEY_HALF_PRESS_DOWN) { KEYBRD_MESSAGE KeyBrdMsg; nKeyPadStatus[KeyMapIndex] = KEY_EVENT_DOWN; KeyBrdMsg.nMsgType = KEY_EVENT_DOWN; KeyBrdMsg.nKeyCode = nKeyPadMap[KeyMapIndex].nMMIKeyCode; KeyEventHandler((struct KEYBRD_MESSAGE*)&KeyBrdMsg); } else { /* Ignore the event */ } } else if ((MsgType == DRV_WM_ENABLE_TWOKEY_DETECTION) || (MsgType == DRV_WM_ENABLE_THREEKEY_DETECTION) || (MsgType == DRV_WM_DISABLE_MULTIKEY_DETECTION)) { /* Ignore the event */ } else { MMI_TRACE(MMI_FW_TRC_G6_FRM_DETAIL, MMI_FRM_ERROR_PROC_KEYEVENT_HDLR); MMI_ASSERT(0); } }
KeyEventHandler 函数主要判断是否要真的处理该事件,可以看成是一个按键事件的拦截,比如应用切换过程中,需要一个切换动画,而这个动画工程中,需要处理忽略这些按键。就需要特殊的处理。
static void KeyEventHandler(KEYBRD_MESSAGE *eventKey) { MMI_BOOL is_hdlr_enabled = MMI_TRUE; // 主要处理一些特殊相应:屏幕背光,屏幕锁定,按键声音 mmi_kbd_app_key_hdlr(eventKey); // 判断是否有前置处理函数 if (g_mmi_frm_cntx.kbd_pre_func) { is_hdlr_enabled = g_mmi_frm_cntx.kbd_pre_func(eventKey); } // 根据前置处理函数结果,判断是否要处理该 key event if (is_hdlr_enabled) { //处理 案件事件 ExecuteCurrKeyHandler((S16) eventKey->nKeyCode, (S16) eventKey->nMsgType); } // 是否有后置处理函数,可以进行一些监视 if (g_mmi_frm_cntx.kbd_post_func) { g_mmi_frm_cntx.kbd_post_func(eventKey); } }
接下来是 ExecuteCurrKeyHandler 这个函数就是根据 按键事件,获得处理函数,进行处理。
void ExecuteCurrKeyHandler(S16 keyCode, S16 keyType) { FuncPtr currFuncPtr = NULL; // 重新设定 键盘锁和屏保timer mmi_idle_restart_keypad_lock_timer(); mmi_idle_restart_screensaver_timer(); frm_p->currKeyCode = keyCode; frm_p->currKeyType = keyType; // 对电话状态下,挂电话键的特殊处理. if (frm_p->currKeyType == KEY_EVENT_DOWN && isInCall() && !GetWapCallPresent() && IsBitReset(g_mmi_frm_cntx.end_key_flag, frm_p->currKeyType) ) { RegisterEndKeyHandlerInCall(); } // 获得按键处理函数 currFuncPtr = currKeyFuncPtrs[keyCode][keyType]; // 导航的选择键,默认和左功能键的效果一样。 if (keyCode == KEY_ENTER && currFuncPtr == NULL) { if (currKeyFuncPtrs[KEY_ENTER][KEY_EVENT_UP] == NULL && currKeyFuncPtrs[KEY_ENTER][KEY_EVENT_DOWN] == NULL && currKeyFuncPtrs[KEY_ENTER][KEY_HALF_PRESS_DOWN] == NULL && currKeyFuncPtrs[KEY_ENTER][KEY_REPEAT] == NULL && currKeyFuncPtrs[KEY_ENTER][KEY_LONG_PRESS] == NULL) { currFuncPtr = currKeyFuncPtrs[KEY_LSK][keyType]; } } // 处理按键 消息 if (currFuncPtr) { (*currFuncPtr)(); } } // 重置状态 if (keyType == KEY_EVENT_UP) { frm_p->currKeyCode = KEY_INVALID; frm_p->currKeyType = MAX_KEY_TYPE; } }
从整个按键事件的处理流程来看,也没有什么特殊的地方,就是收到消息后,从按键buffer里取出按键事件,然后处理。如果有有别的事件要处理,那么就break出来,等到处理完这个消息后,在 MMI task 调用 mmi_frm_key_handle 继续处理剩下的按键事件。这里无非多了很多的判断,是否要进行按键处理,MTK的代码函数名字上虽然看不出什么东西,但是一层一层函数,每一层函数的功能还是比较独立的,所以也不是很难看懂。
待续