emWin(ucgui) 在PC端的模拟器,默认的按键机制是"按抬都发送Msg",当在按下键盘时,会收到一个key值-1,在按键没有离开时一直维持,当按键松开时还发送一个key值-0的标记。所以在你手速多快的情况下都会有一个 key,1和key,0两个操作。程序中没有对按键的状态做判定,所以在PC上不管是按下,还是按下后离开都会进行响应(两次响应)。

假设有以下的应用场景,一级菜单->(ENTER键)->二级菜单>(ENTER键)->三级菜单,即,在一级菜单是可以用ENTER键进入二级菜单,同样在二级菜单可以用ENTER键进入三级菜单,实现的方式是:响应ENTER键的消息,然后切换菜单。

/*******************************************************************************

* Function Name :WIN_Enter

* Description :进入下一级窗口

* Input :int id:把进入的ID号

* Output :void

* Other :

* Date :2013/06/02

*******************************************************************************/

int WIN_Enter(int id)

{

ELEM_BLOCK_TYPE *pElem;

MENU_INFO_ITEM *pInfo;

MENU_INFO_ITEM *pCur; //当前的窗口

WIN_ContextLock();

if (m_WinList.index < 1) //窗口调度没有初始化

goto ext;

if (m_WinList.index >= WIN_LEVEL_LAYER_COUNT - 1)//窗口深度超出最大范围

goto ext;

pElem = &m_WinList.elem[m_WinList.index - 1]; //获得当前窗口

pCur = pInfo = pElem->menu;

pInfo = BT_GetRightChild(pInfo); //获取下级窗口

pInfo = BT_GetLChildElem(pInfo, *(int *)id);

if (pInfo == NULL) //无下级窗口

goto ext;

if (pInfo->data == NULL) //下级窗口元素为空

goto ext;

pElem->ret.id = *(int *)id; //保存所进入的ID

if (pInfo->data->win == NULL) //下级窗口无窗口数据

goto end;

if (pCur->data->win->destroy) //销毁当前窗口

(*pCur->data->win->destroy)(NULL);

if (pInfo->data->win->create) //新窗口建立

(*pInfo->data->win->create)(pInfo);

m_WinList.elem[m_WinList.index++].menu = pInfo; //保存新窗口到窗口列表中

end:

WIN_ContextUnlock();

if (pInfo->data->enter) {

(*pInfo->data->enter)(&id);

}

return OK;

ext:

WIN_ContextUnlock();

return FALSE;

}

以上代码是通过提前构造少的菜单树结构,然后在菜单节点响应ENTER键和ESC键完成进入和退出,从代码上看不出有什么问题了,但是在PC实际仿真的过程成发现,在一级菜单按下ENTER键时进入二级菜单,紧接着进入三级菜单。


所有需要对ENTER键进行判断响应,每次按下ENTER键就响应一次:

case WM_KEY:

        switch (((WM_KEY_INFO *)(pMsg->Data.p))->Key){

            case GUI_KEY_ENTER:

             if(((WM_KEY_INFO *)(pMsg->Data.p))->PressedCnt == 0)

                 WIN_Enter(0);

             break;

        }

     break;