久久精品精选,精品九九视频,www久久只有这里有精品,亚洲熟女乱色综合一区
    分享

    ucgui_向按鈕發(fā)送一個(gè)按鍵消息的程序追蹤

     guitarhua 2012-09-22

    ucgui_向按鈕發(fā)送一個(gè)按鍵消息的程序追蹤

    分類: 驅(qū)動(dòng)程序 246人閱讀 評(píng)論(0) 收藏 舉報(bào)

    原發(fā)于www. @2007-7-4

    轉(zhuǎn)帖請(qǐng)注明出處【獻(xiàn)給初學(xué)者,若您是高手請(qǐng)不吝賜教,甚為感激!】


    把Msg的結(jié)構(gòu)體寫在最前面:

    typedef struct {
       int MsgId;             /* type of message */
       WM_HWIN hWin;         /* Destination window */
       WM_HWIN hWinSrc;       /* Source window   */
       union {
         const void* p;             /* Some messages need more info ... Pointer is declared "const" because some systems (M16C) have 4 byte const, byte 2 byte default ptrs */
         int v;
         GUI_COLOR Color;
       } Data;
    } WM_MESSAGE;


    首先跟蹤一個(gè)按鍵發(fā)送函數(shù)

    void GUI_SendKeyMsg(int Key, int PressedCnt);
    --》
    WM_OnKey(Key, PressedCnt)
    int WM_OnKey(int Key, int Pressed) {
       int r = 0;
       WM_MESSAGE Msg;
       WM_LOCK();
       if (WM__hWinFocus != 0) {
         WM_KEY_INFO Info;
         Info.Key = Key;
         Info.PressedCnt = Pressed;
         Msg.MsgId = WM_KEY;
         Msg.Data.p = &Info;
        WM__SendMessage(WM__hWinFocus, &Msg);
         r = 1;
       }
       WM_UNLOCK();
       return r;
    }

    注意,消息發(fā)送到了WM__hWinFocus

    --》WM__SendMessage(WM__hWinFocus, &Msg);
    void WM__SendMessage(WM_HWIN hWin, WM_MESSAGE* pMsg) {
       WM_Obj* pWin = WM_HANDLE2PTR(hWin);
       pMsg->hWin = hWin;
       if (pWin->cb != NULL) {
         (*pWin->cb)(pMsg);
       } else {
         WM_DefaultProc(pMsg);
       }
    }


    消息發(fā)到了哪兒?yeah,就是我們直觀看到的當(dāng)前焦點(diǎn)--button

    調(diào)用其回調(diào)函數(shù),一個(gè)KEY類型的消息,如下

    void BUTTON_Callback(WM_MESSAGE *pMsg)
    void BUTTON_Callback(WM_MESSAGE *pMsg) {
       BUTTON_Handle hObj = pMsg->hWin;
       BUTTON_Obj* pObj = BUTTON_H2P(hObj);           (1)
       /* Let widget handle the standard messages */
       if (WIDGET_HandleActive(hObj, pMsg) == 0) {
         return;
       }
       switch (pMsg->MsgId) {                                            (2)
    #if BUTTON_REACT_ON_LEVEL
       case WM_PID_STATE_CHANGED:
         _OnPidStateChange(hObj, pObj, pMsg);
         return;       /* Message handled. Do not call WM_DefaultProc, because the window may have been destroyed */
    #endif
       case WM_TOUCH:
         _OnTouch(hObj, pObj, pMsg);
         return;       /* Message handled. Do not call WM_DefaultProc, because the window may have been destroyed */
       case WM_PAINT:
         GUI_DEBUG_LOG("BUTTON: _BUTTON_Callback(WM_PAINT)\n");
         _Paint(pObj, hObj);
         return;
       case WM_DELETE:
         GUI_DEBUG_LOG("BUTTON: _BUTTON_Callback(WM_DELETE)\n");
         _Delete(pObj);
         break;       /* No return here ... WM_DefaultProc needs to be called */
       #if 0     /* TBD: Button should react to space & Enter */
       case WM_KEY:
         {
           int PressedCnt = ((WM_KEY_INFO*)(pMsg->Data.p))->PressedCnt;
           int Key = ((WM_KEY_INFO*)(pMsg->Data.p))->Key;
           if (PressedCnt > 0) {   /* Key pressed? */
             switch (Key) {
             case ' ':
               _ButtonPressed(hObj, pObj);
               return;
             }
           } else {
             switch (Key) {
             case ' ':
               _ButtonReleased(hObj, pObj, WM_NOTIFICATION_RELEASED);
               return;
             }
           }
         }
         break;
       #endif
       }
       WM_DefaultProc(pMsg);
    }

    (1)由句柄獲得對(duì)象

    (2)判斷消息類型,本次發(fā)送消息為一個(gè)按鍵類型


    直接忽略其他的消息,看case WM_KEY標(biāo)簽

       case WM_KEY:
         {
           int PressedCnt = ((WM_KEY_INFO*)(pMsg->Data.p))->PressedCnt; (1)
           int Key = ((WM_KEY_INFO*)(pMsg->Data.p))->Key;         (2)
           if (PressedCnt > 0) {   /* Key pressed? */           (3)
             switch (Key) {
             case ' ':
               _ButtonPressed(hObj, pObj);
               return;
             }
           } else {
             switch (Key) {
             case ' ':
               _ButtonReleased(hObj, pObj, WM_NOTIFICATION_RELEASED);
               return;
             }
           }
         }
         break;


        
    (1-2)局部變量,獲得按下的key和狀態(tài)
    這個(gè)函數(shù)有點(diǎn)兒令人匪夷所思,如果按下空格,則執(zhí)行_ButtonPressed(hObj, pObj);
    如果是釋放空格,則執(zhí)行_ButtonReleased(hObj, pObj, WM_NOTIFICATION_RELEASED);
    這兩個(gè)函數(shù)是做什么的?
    這些都是private函數(shù),對(duì)外不提供接口

    ucgui利用c的特性,很好的模擬了封裝、繼承等等面向?qū)ο筇匦?br>這里的private實(shí)現(xiàn)很好理解
    類實(shí)現(xiàn)代碼中實(shí)現(xiàn)的行為不在其頭(.h)文件中提供聲明
    其它通過包含頭文件使用這個(gè)類的函數(shù)由于沒有某些函數(shù)的聲明故不能調(diào)用
    就完成了private特性


    首先是_ButtonPressed(BUTTON_Handle hObj, BUTTON_Obj* pObj)
    這個(gè)函數(shù)比較容易理解,更改外觀的同時(shí)將消息上泵,通知自己的父窗體,自己的模樣被更新了


    static void _ButtonPressed(BUTTON_Handle hObj, BUTTON_Obj* pObj) {
       WIDGET_OrState(hObj, BUTTON_STATE_PRESSED);                   (1)
       if (pObj->Widget.Win.Status & WM_SF_ISVIS) {                   (2)
         WM_NotifyParent(hObj, WM_NOTIFICATION_CLICKED);    (3)
       }
    }


    (1)首先將這個(gè)Button對(duì)象的狀態(tài)設(shè)置成按下的
    (2)看看這個(gè)Button對(duì)象的狀態(tài)是不是可見的(若在C++中,可以實(shí)現(xiàn)pObj->Status,不需要利用Widget.Win標(biāo)簽但這里我們可以清楚地看出類中組合關(guān)系)
    (3)如果是可見的,就通知父窗體,觸發(fā)一個(gè)單擊事件。

    void WM_NotifyParent(WM_HWIN hWin, int Notification) {
       WM_MESSAGE Msg;
       Msg.MsgId   = WM_NOTIFY_PARENT;
       Msg.Data.v   = Notification;
       WM_SendToParent(hWin, &Msg);
    }

    我們知道,Button的父窗體是Framewin中的Client。(注意,F(xiàn)ramewin和Client對(duì)象都有回調(diào)函數(shù),但Button的父窗體是Client,所以執(zhí)行的不是Framewin而是Client的回調(diào)函數(shù).)如此,一個(gè)按下消息發(fā)給了Client,如果Client中不進(jìn)行攔截,則將傳給用戶定義的
    接口回調(diào)函數(shù)。
    再讓我們看看釋放函數(shù):

    static void _ButtonReleased(BUTTON_Handle hObj, BUTTON_Obj* pObj, int Notification) {
       WIDGET_AndState(hObj, BUTTON_STATE_PRESSED);
       if (pObj->Widget.Win.Status & WM_SF_ISVIS) {
         WM_NotifyParent(hObj, Notification);
       }
       if (Notification == WM_NOTIFICATION_RELEASED) {
         GUI_DEBUG_LOG("BUTTON: Hit\n");
         GUI_StoreKey(pObj->Widget.Id);
       }
    }

    后面一個(gè)if是陌生的

       if (Notification == WM_NOTIFICATION_RELEASED) {
         GUI_DEBUG_LOG("BUTTON: Hit\n");
         GUI_StoreKey(pObj->Widget.Id);
       }

       此處我不是很理解,當(dāng)按下-釋放過程結(jié)束時(shí),就證明一個(gè)按鍵工作結(jié)束,將這個(gè)按鍵的接受者的Id放到系統(tǒng)的Key隊(duì)列中去?(后經(jīng)試驗(yàn)發(fā)現(xiàn),目的大概為了保護(hù)按鍵信息,以便后期處理。)
    綜上我們已經(jīng)可以分析一個(gè)按鍵消息通過系統(tǒng)的路徑(以Button為例)
    按鍵--》找到focus窗體,將消息發(fā)送給它--》在這個(gè)窗體的回調(diào)函數(shù)中,如果定義了這個(gè)按鍵值,則將其攔截并工作
    (以按鍵的回調(diào)函數(shù)為例,如果按鍵了,則將這個(gè)消息以NOTIFYPARENT的形式向上泵,知道用戶定義的接口回調(diào)函數(shù))
    如果button回調(diào)函數(shù)沒有攔截這個(gè)按鍵值呢?

       WM_DefaultProc(pMsg);
      
       void WM_DefaultProc(WM_MESSAGE* pMsg) {
       WM_HWIN hWin = pMsg->hWin;
       const void *p = pMsg->Data.p;
       WM_Obj* pWin = WM_H2P(hWin);
       /* Exec message */
       switch (pMsg->MsgId) {
       case WM_GET_INSIDE_RECT:       /* return client window in absolute (screen) coordinates */
         WM__GetClientRectWin(pWin, (GUI_RECT*)p);
         break;
       case WM_GET_CLIENT_WINDOW:       /* return handle to client window. For most windows, there is no seperate client window, so it is the same handle */
         pMsg->Data.v = (int)hWin;
         return;                       /* Message handled */
       case WM_KEY:
         WM_SendToParent(hWin, pMsg);
         return;                       /* Message handled */

       case WM_GET_BKCOLOR:
         pMsg->Data.Color = GUI_INVALID_COLOR;
         return;                       /* Message handled */
       case WM_NOTIFY_ENABLE:
         WM_InvalidateWindow(hWin);    
         return;                       /* Message handled */
       }
       /* Message not handled. If it queries something, we return 0 to be on the safe side. */
       pMsg->Data.v = 0;
       pMsg->Data.p = 0;
    }

    注意,這里對(duì)于按鍵,直接向上泵(parent)

       case WM_KEY:
         WM_SendToParent(hWin, pMsg);
         return;                       /* Message handled */

    這兒的句柄hWin還是Button,向上泵給Client,再泵給用戶定義回調(diào)函數(shù),最終在那里結(jié)束。
    此處有一點(diǎn)提示,因?yàn)橛脩艋卣{(diào)函數(shù)中通常也會(huì)用到WM_DefaultProc這個(gè)過程處理不攔截的鍵,那么會(huì)不會(huì)產(chǎn)生死循環(huán)呢?
    當(dāng)然不會(huì),因?yàn)樵谖覀冏鯳M_SendToParent函數(shù)的時(shí)候,MSG的目標(biāo)句柄已經(jīng)變成了Client窗體,而在Client中直接泵給用戶定義接口時(shí),
    而在Client的回調(diào)函數(shù)中,又巧妙地將MSG的目標(biāo)句柄編程了FRAMEWIN,這樣在我們定義的接口回調(diào)函數(shù)中,我們收到的是一個(gè)發(fā)送到FRAMEWIN的消息。這里聰明地使Client
    窗體這一層對(duì)用戶透明了。


    看到這里,再回頭看一個(gè)預(yù)編譯標(biāo)志#if 0
    我們可以確定的是,在Button控件中壓根不攔截WM_KEY消息,而是直接提供給DefaultProc中,通過DefaultProc泵給Client,隨后再直接提供給
    用戶定義的接口回調(diào)函數(shù)。
    知道了這樣的一個(gè)消息傳遞過程,我們就可以放心大膽的在自己定義的接口回調(diào)函數(shù)中定義對(duì)各種各樣的鍵進(jìn)行處理的過程了
    case WM_KEY就可以攔截到傳遞給Button的所有按鍵,但怎么判斷傳來的值是來自Button呢?我們回過頭去看那個(gè)被傳遞的MSG的起源:


       WM_MESSAGE Msg;
       WM_LOCK();
       if (WM__hWinFocus != 0) {
         WM_KEY_INFO Info;
         Info.Key = Key;
         Info.PressedCnt = Pressed;
         Msg.MsgId = WM_KEY;
         Msg.Data.p = &Info;


    糟糕,沒有定義hWinSrc,我們無法從消息中判斷信息來源了!?當(dāng)然可以,消息是發(fā)送到WM__hWinFocus的,而在消息傳遞的過程中沒有改變這個(gè)
    全局的指針,我們可以大膽的把WM__hWinFocus的句柄拿來操作。但得到的只是一個(gè)句柄,如何知道它是Button?還是EditBox還是(*&……&?
    uCGUI提供了一個(gè)由句柄得到Id的函數(shù)
    int WM_GetId (WM_HWIN hWin);
    反過來,從Id也可以得到控件的句柄,用的是函數(shù)
    其中第一個(gè)參數(shù)是控件屬于的窗體句柄,
    WM_HWIN WM_GetDialogItem (WM_HWIN hWin, int Id);

    是在內(nèi)存管理上做的文章

    我認(rèn)為,這里應(yīng)該是模仿windows編程中的句柄-id-對(duì)象互相調(diào)用的幾個(gè)函數(shù)

    這個(gè)函數(shù)中使用了遞歸,去查詢所有hWin的子窗體
    言歸正傳,還是看WM_GetId:


    int WM_GetId(WM_HWIN hObj) {
       WM_MESSAGE Msg;
       Msg.MsgId   = WM_GET_ID;
       WM_SendMessage(hObj, &Msg);
       return Msg.Data.v;
    }


    發(fā)送一個(gè)消息,像句柄索要它的Id
    在觀察Button的callback時(shí),發(fā)現(xiàn)沒有現(xiàn)式地?cái)r截WM_GET_ID這一消息,但根據(jù)常識(shí),這樣一個(gè)標(biāo)準(zhǔn)接口不應(yīng)該在最終的實(shí)體化的類中實(shí)現(xiàn),
    應(yīng)該由它的父類或祖父類實(shí)現(xiàn),仔細(xì)觀察,注意到這一句:

       if (WIDGET_HandleActive(hObj, pMsg) == 0) {
         return;
       }


    以下是定義:

    int WIDGET_HandleActive(WM_HWIN hObj, WM_MESSAGE* pMsg) {
       int Diff, Notification;
       WIDGET* pWidget = WIDGET_H2P(hObj);
       switch (pMsg->MsgId) {
       case WM_WIDGET_SET_EFFECT:
         Diff = pWidget->pEffect->EffectSize;
         pWidget->pEffect = (const WIDGET_EFFECT*)pMsg->Data.p;
         Diff -= pWidget->pEffect->EffectSize;
         _UpdateChildPostions(hObj, Diff);
         WM_InvalidateWindow(hObj);
         return 0;                         /* Message handled -> Return */
       case WM_GET_ID:
         pMsg->Data.v = pWidget->Id;
         return 0;                         /* Message handled -> Return */
       case WM_PID_STATE_CHANGED:
         if (pWidget->State & WIDGET_STATE_FOCUSSABLE) {
           const WM_PID_STATE_CHANGED_INFO * pInfo = (const WM_PID_STATE_CHANGED_INFO*)pMsg->Data.p;
           if (pInfo->State) {
             WM_SetFocus(hObj);
           }
         }
         break;
       case WM_TOUCH_CHILD:
         /* A descendent (child) has been touched or released.
           If it has been touched, we need to get to top.
         */
         {
           const WM_MESSAGE * pMsgOrg;
           const GUI_PID_STATE * pState;
           pMsgOrg = (const WM_MESSAGE*)pMsg->Data.p;       /* The original touch message */
           pState = (const GUI_PID_STATE*)pMsgOrg->Data.p;
           if (pState) {           /* Message may not have a valid pointer (moved out) ! */
             if (pState->Pressed) {
               WM_BringToTop(hObj);
               return 0;                     /* Message handled -> Return */
             }
           }
         }
         break;
       case WM_SET_ID:
         pWidget->Id = pMsg->Data.v;
         return 0;                         /* Message handled -> Return */
       case WM_SET_FOCUS:
         if (pMsg->Data.v == 1) {
           WIDGET_SetState(hObj, pWidget->State |   WIDGET_STATE_FOCUS);
           Notification = WM_NOTIFICATION_GOT_FOCUS;
         } else {
           WIDGET_SetState(hObj, pWidget->State & ~WIDGET_STATE_FOCUS);
           Notification = WM_NOTIFICATION_LOST_FOCUS;
         }
         WM_NotifyParent(hObj, Notification);
         pMsg->Data.v = 0;   /* Focus change accepted */
         return 0;
       case WM_GET_ACCEPT_FOCUS:
         pMsg->Data.v = (pWidget->State & WIDGET_STATE_FOCUSSABLE) ? 1 : 0;               /* Can handle focus */
         return 0;                         /* Message handled */
       case WM_GET_INSIDE_RECT:
         WIDGET__GetInsideRect(pWidget, (GUI_RECT*)pMsg->Data.p);
         return 0;                         /* Message handled */
       }
       return 1;                           /* Message NOT handled */
    }

    證實(shí)了我的猜測,按鍵的父類Widget實(shí)現(xiàn)了對(duì)這樣的消息的攔截
    注意這一句:
       WIDGET* pWidget = WIDGET_H2P(hObj);
    其實(shí)等于做了兩件事,首先獲得指針,然后類型轉(zhuǎn)換
    記得C++中的 static_castpWidget;么?uCGUI中利用結(jié)構(gòu)體的巧妙安排使得類型轉(zhuǎn)換不需要指針偏移。
    對(duì)于GET_ID的要求:

       case WM_SET_ID:
         pWidget->Id = pMsg->Data.v;
         return 0;                         /* Message handled -> Return */

    完成了取得Id的工作。
    好了,我們獲得了消息來源的Id,是用WM__hWinFocus句柄取得的,別忘了:P

    case WM_KEY:
    switch(((WM_KEY_INFO*)pMsg->Data.p)->Key),還記得WM_KEY_INFO和WM_MESSAGE么?
    {
    case GUI_KEY_ENTER:
       switch(WM_GetId(WM__hWinFocus))
       {
       case GUI_ID_BUTTON0:
       //這里就是在BUTTON0上按回車應(yīng)該做的事情(按下或釋放)
         break;
       case GUI_ID_BUTTON1:
         break;
       }
    }

    現(xiàn)在我們已經(jīng)知道了怎么在自己定義的回調(diào)函數(shù)中接受對(duì)話框中某個(gè)按鍵按下的消息了,但屏幕上應(yīng)該怎么反應(yīng)呢?

    應(yīng)該有個(gè)動(dòng)態(tài)的按下、釋放過程,然后再工作吧!
    Button控件提供了一個(gè)函數(shù):
    void BUTTON_SetPressed(BUTTON_Handle hObj, int State);
    State參數(shù),0表示沒有被按下,1表示被按下
    這個(gè)函數(shù)只是簡單地改變Button的狀態(tài)標(biāo)志(其中的Pressed位)么?當(dāng)然不是,它還將整個(gè)按鈕標(biāo)記為需要更新的Invalid,在下次GUI_EXEC()
    中,將會(huì)重畫這個(gè)按鈕。
    最終的代碼像這個(gè)樣子:


    static void DialogCallBack(WM_MESSAGE* pMsg)
    {
    switch(pMsg->MsgId)
    {
    case WM_KEY:
       switch(((WM_KEY_INFO*)pMsg->Data.p)->Key)
       {
       case GUI_KEY_ENTER:
       switch(WM_GetId(WM__hWinFocus))
       {
       case GUI_ID_BUTTON0:
         BUTTON_SetPressed(WM__hWinFocus, ((WM_KEY_INFO*)pMsg->Data.p)->PressedCnt);
         break;
       case GUI_ID_BUTTON1:
         BUTTON_SetPressed(WM__hWinFocus, ((WM_KEY_INFO*)pMsg->Data.p)->PressedCnt);
         break;
       }
       break;
       }
       break;
    default:
       WM_DefaultProc(pMsg);
    }
    }

      本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
      轉(zhuǎn)藏 分享 獻(xiàn)花(0

      0條評(píng)論

      發(fā)表

      請(qǐng)遵守用戶 評(píng)論公約

      類似文章 更多

      主站蜘蛛池模板: 国产午夜影视大全免费观看| 国内综合精品午夜久久资源| 精品熟女少妇AV免费观看| 女上男下激烈啪啪无遮挡| 日本一区不卡高清更新二区 | 国产午夜精品一区理论片| 一本色道久久综合亚洲精品| 精品中文人妻中文字幕| 国产日产欧产精品精乱了派| 国产欧美日韩精品丝袜高跟鞋 | 国产情侣激情在线对白| 国产精品 视频一区 二区三区| 四虎库影成人在线播放| 久久五十路丰满熟女中出| 一本一道av中文字幕无码| 秋霞A级毛片在线看| 国产成人不卡一区二区| 看全色黄大色大片免费久久| 成人亚欧欧美激情在线观看 | 三上悠亚久久精品| 日夜啪啪一区二区三区| 精品国精品无码自拍自在线| 亚洲国产精品久久久天堂麻豆宅男 | 又粗又硬又黄a级毛片| 精品一卡2卡三卡4卡乱码精品视频| 野花社区视频在线观看| 成人三级视频在线观看不卡| a级黑人大硬长爽猛出猛进| 九九电影网午夜理论片| 国产免费一区二区不卡| 婷婷综合久久中文字幕蜜桃三电影 | 中文字幕国产精品综合| 国产精品国产三级国AV| 色欲国产精品一区成人精品| 亚洲精品成人片在线观看精品字幕| 国产精品久久福利新婚之夜| 91福利视频一区二区| 午夜天堂精品久久久久| 久久亚洲AV成人网站玖玖| 一区二区三区鲁丝不卡| 97人人添人人澡人人澡人人澡|