win32k!xxxSkipSysMsg函数分析之WM_KEYUP消息0Xc0070001的由来和WM_KEYUP消息的31位和30位的含义==非常重要

2小时前发布 清纯小酥
0 0 0

win32k!xxxSkipSysMsg函数分析之WM_KEYUP消息0Xc0070001的由来和WM_KEYUP消息的31位和30位的含义==非常重要

第一部分:

             * 0x80000000 is set if up, clear if down
             * 0x40000000 is previous up/down state of key

第二部分:

win32k!xxxInternalToUnicode函数分析之WM_KEYDOWN和WM_KEYUP的返回值的不同
https://chenghao.blog.csdn.net/article/details/154705786

    case WM_SYSKEYUP:
    case WM_KEYDOWN:
    case WM_KEYUP:
        pti = PtiCurrent();

        if ((pti->pMenuState != NULL) &&
                (HW(pti->pMenuState->pGlobalPopupMenu->spwndPopupMenu) ==
                pmsg->hwnd)) {
            uiTMFlags |= TM_INMENUMODE;
        } else {
            uiTMFlags &= ~TM_INMENUMODE;
        }

        /*
         * Don't change the contents of the passed in structure.
         */
        lParam = pmsg->lParam;

        /*
         * For backward compatibility, mask the virtual key value.
         */
        uVirKey = LOWORD(pmsg->wParam);

        cChar = xxxInternalToUnicode(uVirKey,   // virtual key code
                         HIWORD(lParam),  // scan code, make/break bit
                         pti->pq->afKeyState,
                         awch, sizeof(awch)/sizeof(awch[0]),
                         uiTMFlags, &dwKeyFlags, NULL);
        lParam |= (dwKeyFlags & ALTNUMPAD_BIT);

int xxxInternalToUnicode(
    IN  UINT   uVirtKey,
    IN  UINT   uScanCode,
    CONST IN PBYTE pfvk,
    OUT PWCHAR awchChars,
    IN  INT    cChar,
    IN  UINT   uiTMFlags,
    OUT PDWORD pdwKeyFlags,
    IN  HKL    hkl)
{
    WORD wModBits;
    WORD nShift;
    WCHAR *pUniChar;
    PVK_TO_WCHARS1 pVK;
    PVK_TO_WCHAR_TABLE pVKT;
    static WORD NumpadChar;
    static WORD VKLastDown;
    static BYTE ConvMode;   // 0 == NUMPADCONV_OEMCP
    PTHREADINFO ptiCurrent = PtiCurrentShared();
    PKL pkl;
    PKBDTABLES pKbdTbl;
    PLIGATURE1 pLigature;

    *pdwKeyFlags = (uScanCode & KBDBREAK);

    if (*pdwKeyFlags & KBDBREAK) {        // break code processing,表示是WM_KEYUP

第三部分:

1: kd> kc
 #
00 win32k!xxxSkipSysMsg
01 win32k!xxxScanSysQueue
02 win32k!xxxRealInternalGetMessage
03 win32k!NtUserPeekMessage
04 nt!_KiSystemService
05 SharedUserData!SystemCallStub
06 USER32!NtUserPeekMessage
07 USER32!PeekMessageW
08 USER32!DialogBox2
09 USER32!InternalDialogBox
0a USER32!DialogBoxIndirectParamAorW
0b USER32!DialogBoxParamW
0c USER32!DialogBoxParamW_wrapper
0d winlogon!Fusion_DialogBoxParam
0e winlogon!TimeoutDialogBoxParam
0f winlogon!WlxDialogBoxParam
10 MSGINA!WlxWkstaLockedSAS
11 winlogon!DoLockWksta
12 winlogon!DoScreenSaver
13 winlogon!LoggedonDlgProc
14 winlogon!RootDlgProc
15 USER32!InternalCallWinProc
16 USER32!UserCallDlgProcCheckWow
17 USER32!DefDlgProcWorker
18 USER32!DefDlgProcW
19 USER32!InternalCallWinProc
1a USER32!UserCallWinProcCheckWow
1b USER32!DispatchMessageWorker
1c USER32!DispatchMessageW
1d USER32!IsDialogMessageW
1e USER32!DialogBox2
1f USER32!InternalDialogBox
20 USER32!DialogBoxIndirectParamAorW
21 USER32!DialogBoxParamW
22 USER32!DialogBoxParamW_wrapper
23 winlogon!Fusion_DialogBoxParam
24 winlogon!TimeoutDialogBoxParam
25 winlogon!WlxDialogBoxParam
26 winlogon!BlockWaitForUserAction
27 winlogon!MainLoop
28 winlogon!WinMain
29 winlogon!WinMainCRTStartup
1: kd> dv
            pti = 0xe1404c50
          pqmsg = 0xf75c6bc4
          fDown = 0n-1082094230
         pqmsgT = 0xbf808d6a
             vk = 0x00 ''
1: kd> dx -id 0,0,89413020 -r1 ((win32k!tagQMSG *)0xf75c6bc4)
((win32k!tagQMSG *)0xf75c6bc4)                 : 0xf75c6bc4 [Type: tagQMSG *]
    [+0x000] pqmsgNext        : 0x0 [Type: tagQMSG *]
    [+0x004] pqmsgPrev        : 0x0 [Type: tagQMSG *]
    [+0x008] msg              : {msg=0x101 wp=0x36 lp=0x70001} [Type: tagMSG]
    [+0x024] ExtraInfo        : 0 [Type: long]
    [+0x028] dwQEvent         : 0x0 [Type: unsigned long]
    [+0x02c] pti              : 0xe1404c50 [Type: tagTHREADINFO *]

1: kd> !thread
THREAD 897f2020  Cid 01c8.01cc  Teb: 7ffde000 Win32Thread: e1404c50 RUNNING on processor 1
IRP List:
    89590158: (0006,0094) Flags: 00000800  Mdl: 00000000
Not impersonating
DeviceMap                 e10003d8
Owning Process            89413020       Image:         winlogon.exe
Attached Process          N/A            Image:         N/A
Wait Start TickCount      274798196      Ticks: 3 (0:00:00:00.046)
Context Switch Count      3506           IdealProcessor: 1                 LargeStack
UserTime                  00:00:15.687
KernelTime                00:00:32.078
Stack Init f75c7000 Current f75c6bdc Base f75c7000 Limit f75c2000 Call 00000000
Priority 15 BasePriority 15 PriorityDecrement 0 IoPriority 0 PagePriority 0
ChildEBP RetAddr  Args to Child              
f75c6a9c bf80af08 e1404c50 f75c6bc4 bf9ea2a4 win32k!xxxSkipSysMsg (FPO: [Non-Fpo]) (CONV: stdcall) [d:srv03rtmwindowscore
tuserkernelinput.c @ 3352]
f75c6c40 bf8ad571 e1404c50 f75c6d04 00000000 win32k!xxxScanSysQueue+0x18a0 (FPO: [Non-Fpo]) (CONV: stdcall) [d:srv03rtmwindowscore
tuserkernelinput.c @ 5153]
f75c6cd8 bf89b537 f75c6d04 00000000 00000000 win32k!xxxRealInternalGetMessage+0x3c3 (FPO: [Non-Fpo]) (CONV: stdcall) [d:srv03rtmwindowscore
tuserkernelinput.c @ 636]
f75c6d3c 80afbcb2 0006f8f8 00000000 00000000 win32k!NtUserPeekMessage+0x7d (FPO: [Non-Fpo]) (CONV: stdcall) [d:srv03rtmwindowscore
tuserkernel
tstubs.c @ 5734]
f75c6d3c 7ffe0304 0006f8f8 00000000 00000000 nt!_KiSystemService+0x13f (FPO: [0,3] TrapFrame @ f75c6d64) (CONV: cdecl) [d:srv03rtmase
toskei386 rap.asm @ 1328]

       /*
         * Delete this message from the input queue. Make sure pqmsgT isn't
         * 1: this could happen if an app unhooked a journal record hook
         * during a callback from xxxScanSysQueue.
         */
        if (pqmsgT != PQMSG_PLAYBACK) {
            /*
             * There are cases when idSysPeek points to a different message
             * than the one we are trying to remove. This can happen if
             * two threads enters in xxxScanSysQueue, sets the idSysPeek and
             * after this their queues got redistributed. The first thread
             * will have the idSysPeek preserved but the second one has to
             * search the queue for its message. – ask CLupu
             */
            if (!EqualMsg(pqmsgT, pqmsg)) {

                PQMSG pqmsgS;

#if DBG
                if (IsDbgTagEnabled(DBGTAG_SysPeek)) {
                    gnSysPeekSearch++;
                }
#endif

                TAGMSG0(DBGTAG_SysPeek | RIP_THERESMORE,              “Different message than idSysPeek
“);
                TAGMSG2(DBGTAG_SysPeek | RIP_NONAME | RIP_THERESMORE, “pqmsg   = %#p  idSysPeek = %#p”,  pqmsg,              pqmsgT);
                TAGMSG2(DBGTAG_SysPeek | RIP_NONAME | RIP_THERESMORE, “pti     = %#p  pti       = %#p”,  pqmsg->pti,         pqmsgT->pti);
                TAGMSG2(DBGTAG_SysPeek | RIP_NONAME | RIP_THERESMORE, “msg     = %08lx  msg       = %08lx”,  pqmsg->msg.message, pqmsgT->msg.message);
                TAGMSG2(DBGTAG_SysPeek | RIP_NONAME | RIP_THERESMORE, “hwnd    = %#p  hwnd      = %#p”,  pqmsg->msg.hwnd,    pqmsgT->msg.hwnd);
                TAGMSG2(DBGTAG_SysPeek | RIP_NONAME | RIP_THERESMORE, “wParam  = %#p  wParam    = %#p”,  pqmsg->msg.wParam,  pqmsgT->msg.wParam);
                TAGMSG2(DBGTAG_SysPeek | RIP_NONAME | RIP_THERESMORE, “lParam  = %#p  lParam    = %#p”,  pqmsg->msg.lParam,  pqmsgT->msg.lParam);
                TAGMSG2(DBGTAG_SysPeek | RIP_NONAME | RIP_THERESMORE, “time    = %08lx  time      = %08lx”,  pqmsg->msg.time,    pqmsgT->msg.time);
                TAGMSG2(DBGTAG_SysPeek | RIP_NONAME | RIP_THERESMORE, “Extra   = %08lx  Extra     = %08lx”,  pqmsg->ExtraInfo,   pqmsgT->ExtraInfo);
                TAGMSG1(DBGTAG_SysPeek | RIP_NONAME,                  ”
pqmsgT  = %#p”, pqmsgT);

                /*
                 * Begin to search for this message
                 */
                pqmsgS = pti->pq->mlInput.pqmsgRead;

                while (pqmsgS != NULL) {
                    if (EqualMsg(pqmsgS, pqmsg)) {
                        TAGMSG2(DBGTAG_SysPeek | RIP_THERESMORE,
                                “Deleting pqmsg %#p, pti %#p”,
                                pqmsgS, pqmsgS->pti);

                        TAGMSG4(DBGTAG_SysPeek | RIP_NONAME,
                                “m %04lx, w %#p, l %#p, t %lx”,
                                pqmsgS->msg.message, pqmsgS->msg.hwnd,
                                pqmsgS->msg.lParam, pqmsgS->msg.time);

                        pqmsgT = pqmsgS;
                        break;
                    }
                    pqmsgS = pqmsgS->pqmsgNext;
                }
                if (pqmsgS == NULL) {
                    TAGMSG0(DBGTAG_SysPeek, “Didn't find a matching message. No message removed.”);
                    return;
                }
            }

BOOL EqualMsg(PQMSG pqmsg1, PQMSG pqmsg2)
{
    if (pqmsg1->msg.hwnd    != pqmsg2->msg.hwnd ||
        pqmsg1->msg.message != pqmsg2->msg.message)
        return FALSE;

    /*
     * This might be a coalesced WM_MOUSEMOVE
     */
    if (pqmsg1->msg.message == WM_MOUSEMOVE)
        return TRUE;

    if (pqmsg1->pti      != pqmsg2->pti ||
        pqmsg1->msg.time != pqmsg2->msg.time)
        return FALSE;

    return TRUE;
}

1: kd> dv
            pti = 0xe1404c50
          pqmsg = 0xf75c6bc4
          fDown = 0n-512778072
         pqmsgT = 0xe16fa0a8
             vk = 0xe1 ''
1: kd> dx -id 0,0,89413020 -r1 ((win32k!tagQMSG *)0xf75c6bc4)
((win32k!tagQMSG *)0xf75c6bc4)                 : 0xf75c6bc4 [Type: tagQMSG *]
    [+0x000] pqmsgNext        : 0x0 [Type: tagQMSG *]
    [+0x004] pqmsgPrev        : 0x0 [Type: tagQMSG *]
    [+0x008] msg              : {msg=0x101 wp=0x36 lp=0x70001} [Type: tagMSG]
    [+0x024] ExtraInfo        : 0 [Type: long]
    [+0x028] dwQEvent         : 0x0 [Type: unsigned long]
    [+0x02c] pti              : 0xe1404c50 [Type: tagTHREADINFO *]
1: kd> dx -id 0,0,89413020 -r1 ((win32k!tagQMSG *)0xe16fa0a8)
((win32k!tagQMSG *)0xe16fa0a8)                 : 0xe16fa0a8 [Type: tagQMSG *]
    [+0x000] pqmsgNext        : 0x0 [Type: tagQMSG *]
    [+0x004] pqmsgPrev        : 0x0 [Type: tagQMSG *]
    [+0x008] msg              : {msg=0x101 wp=0x36 lp=0x70001} [Type: tagMSG]
    [+0x024] ExtraInfo        : 0 [Type: long]
    [+0x028] dwQEvent         : 0x0 [Type: unsigned long]
    [+0x02c] pti              : 0xe1404c50 [Type: tagTHREADINFO *]

            DelQEntry(&pti->pq->mlInput, pqmsgT);

1: kd> dx -id 0,0,89413020 -r1 (*((win32k!tagMLIST *)0xe1630530))
(*((win32k!tagMLIST *)0xe1630530))                 [Type: tagMLIST]
    [+0x000] pqmsgRead        : 0xe16fa0a8 [Type: tagQMSG *]
    [+0x004] pqmsgWriteLast   : 0xe16fa0a8 [Type: tagQMSG *]
    [+0x008] cMsgs            : 0x1 [Type: unsigned long]
1: kd> dv
            pti = 0xe1404c50
          pqmsg = 0xf75c6bc4
          fDown = 0n-512778072
         pqmsgT = 0xe16fa0a8
             vk = 0xe1 ''

1: kd> dx -id 0,0,89413020 -r1 ((win32k!tagQ *)0xe1630530)
((win32k!tagQ *)0xe1630530)                 : 0xe1630530 [Type: tagQ *]
    [+0x000] mlInput          [Type: tagMLIST]

1: kd> dx -id 0,0,89413020 -r1 (*((win32k!tagMLIST *)0xe1630530))
(*((win32k!tagMLIST *)0xe1630530))                 [Type: tagMLIST]
    [+0x000] pqmsgRead        : 0xe16fa0a8 [Type: tagQMSG *]
    [+0x004] pqmsgWriteLast   : 0xe16fa0a8 [Type: tagQMSG *]
    [+0x008] cMsgs            : 0x1 [Type: unsigned long]

1: kd> dx -id 0,0,89413020 -r1 ((win32k!tagQMSG *)0xe16fa0a8)
((win32k!tagQMSG *)0xe16fa0a8)                 : 0xe16fa0a8 [Type: tagQMSG *]
    [+0x000] pqmsgNext        : 0x0 [Type: tagQMSG *]
    [+0x004] pqmsgPrev        : 0x0 [Type: tagQMSG *]
    [+0x008] msg              : {msg=0x101 wp=0x36 lp=0x70001} [Type: tagMSG]
    [+0x024] ExtraInfo        : 0 [Type: long]
    [+0x028] dwQEvent         : 0x0 [Type: unsigned long]
    [+0x02c] pti              : 0xe1404c50 [Type: tagTHREADINFO *]

VOID DelQEntry(
    PMLIST pml,
    PQMSG pqmsg)
{
    DebugValidateMLISTandQMSG(pml, pqmsg);
    UserAssert((int)pml->cMsgs > 0);
    UserAssert(pml->pqmsgRead);
    UserAssert(pml->pqmsgWriteLast);

    /*
     * Unlink this pqmsg from the message list.
     */
    if (pqmsg->pqmsgPrev != NULL)
        pqmsg->pqmsgPrev->pqmsgNext = pqmsg->pqmsgNext;

    if (pqmsg->pqmsgNext != NULL)
        pqmsg->pqmsgNext->pqmsgPrev = pqmsg->pqmsgPrev;

    /*
     * Update the read/write pointers if necessary.
     */
    if (pml->pqmsgRead == pqmsg)
        pml->pqmsgRead = pqmsg->pqmsgNext;

    if (pml->pqmsgWriteLast == pqmsg)
        pml->pqmsgWriteLast = pqmsg->pqmsgPrev;

    /*
     * Adjust the message count and free the message structure.
     */
    pml->cMsgs–;

    ExFreeToPagedLookasideList(QEntryLookaside, pqmsg);

    DebugValidateMLIST(pml);
}

1: kd> dx -id 0,0,89413020 -r1 (*((win32k!tagMLIST *)0xe1630530))
(*((win32k!tagMLIST *)0xe1630530))                 [Type: tagMLIST]
    [+0x000] pqmsgRead        : 0x0 [Type: tagQMSG *]
    [+0x004] pqmsgWriteLast   : 0x0 [Type: tagQMSG *]
    [+0x008] cMsgs            : 0x0 [Type: unsigned long]

    switch (pqmsg->msg.message) {

    case WM_KEYUP:
    case WM_SYSKEYUP:
        fDown = FALSE;

        /*
         * Fall through.
         */
    case WM_KEYDOWN:
    case WM_SYSKEYDOWN:
        vk = LOBYTE(LOWORD(pqmsg->msg.wParam));
        break;

             vk = 0x36 '6'

    } else {
        UpdateKeyState(pti->pq, vk, fDown);
    }
}

1: kd> t
eax=e1404c50 ebx=00000000 ecx=00000000 edx=f75c6bc4 esi=bf9ea2a4 edi=bf9eb174
eip=bf80921a esp=f75c6a7c ebp=f75c6a9c iopl=0         nv up ei pl nz na po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000202
win32k!xxxSkipSysMsg+0x4b0:
bf80921a e811010000      call    win32k!UpdateKeyState (bf809330)
1: kd> t
eax=e1404c50 ebx=00000000 ecx=00000000 edx=f75c6bc4 esi=bf9ea2a4 edi=bf9eb174
eip=bf809330 esp=f75c6a78 ebp=f75c6a9c iopl=0         nv up ei pl nz na po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000202
win32k!UpdateKeyState:
bf809330 55              push    ebp
1: kd> dv
             pq = 0xe1630530
             vk = 0x36
          fDown = 0n0
1: kd> dx -id 0,0,89413020 -r1 ((win32k!tagQ *)0xe1630530)
((win32k!tagQ *)0xe1630530)                 : 0xe1630530 [Type: tagQ *]
    [+0x000] mlInput          [Type: tagMLIST]
    [+0x00c] ptiSysLock       : 0xe1404c50 [Type: tagTHREADINFO *]
    [+0x010] idSysLock        : 0xe16fa0a8 [Type: unsigned long]
    [+0x014] idSysPeek        : 0x0 [Type: unsigned long]
    [+0x018] ptiMouse         : 0xe1404c50 [Type: tagTHREADINFO *]
    [+0x01c] ptiKeyboard      : 0xe1404c50 [Type: tagTHREADINFO *]
    [+0x020] spwndCapture     : 0x0 [Type: tagWND *]
    [+0x024] spwndFocus       : 0xbc6449ac [Type: tagWND *]
    [+0x028] spwndActive      : 0xbc644124 [Type: tagWND *]
    [+0x02c] spwndActivePrev  : 0x0 [Type: tagWND *]
    [+0x030] codeCapture      : 0x1 [Type: unsigned int]
    [+0x034] msgDblClk        : 0x201 [Type: unsigned int]
    [+0x038] xbtnDblClk       : 0x0 [Type: unsigned short]
    [+0x03c] timeDblClk       : 0xffe598d9 [Type: unsigned long]
    [+0x040] hwndDblClk       : 0xc00d6 [Type: HWND__ *]
    [+0x044] ptDblClk         : {x=464 y=375} [Type: tagPOINT]
    [+0x04c] afKeyRecentDown  [Type: unsigned char [32]]
    [+0x06c] afKeyState       [Type: unsigned char [64]]
    [+0x0ac] caret            [Type: tagCARET]
    [+0x0e4] spcurCurrent     : 0x0 [Type: tagCURSOR *]
    [+0x0e8] iCursorLevel     : 0 [Type: int]
    [+0x0ec] QF_flags         : 0x140 [Type: unsigned long]
    [+0x0f0] cThreads         : 0x1 [Type: unsigned short]
    [+0x0f2] cLockCount       : 0x0 [Type: unsigned short]
    [+0x0f4] msgJournal       : 0x0 [Type: unsigned int]
    [+0x0f8] ExtraInfo        : 0 [Type: long]
1: kd> dx -id 0,0,89413020 -r1 (*((win32k!unsigned char (*)[64])0xe163059c))
(*((win32k!unsigned char (*)[64])0xe163059c))                 [Type: unsigned char [64]]
    [0]              : 0x8 [Type: unsigned char]
    [1]              : 0x0 [Type: unsigned char]
    [2]              : 0x8 [Type: unsigned char]
    [3]              : 0x0 [Type: unsigned char]
    [4]              : 0x8 [Type: unsigned char]
    [5]              : 0x0 [Type: unsigned char]
    [6]              : 0x0 [Type: unsigned char]
    [7]              : 0x0 [Type: unsigned char]
    [8]              : 0x0 [Type: unsigned char]
    [9]              : 0x0 [Type: unsigned char]
    [10]             : 0x0 [Type: unsigned char]
    [11]             : 0x20 [Type: unsigned char]
    [12]             : 0x0 [Type: unsigned char]
    [13]             : 0x3a [Type: unsigned char]

0011  0110
0011  01
0n13
0011 1010
0010 1010
0x2a

1: kd> dx -id 0,0,89413020 -r1 (*((win32k!unsigned char (*)[64])0xe163059c))
(*((win32k!unsigned char (*)[64])0xe163059c))                 [Type: unsigned char [64]]
    [0]              : 0x8 [Type: unsigned char]
    [1]              : 0x0 [Type: unsigned char]
    [2]              : 0x8 [Type: unsigned char]
    [3]              : 0x0 [Type: unsigned char]
    [4]              : 0x8 [Type: unsigned char]
    [5]              : 0x0 [Type: unsigned char]
    [6]              : 0x0 [Type: unsigned char]
    [7]              : 0x0 [Type: unsigned char]
    [8]              : 0x0 [Type: unsigned char]
    [9]              : 0x0 [Type: unsigned char]
    [10]             : 0x0 [Type: unsigned char]
    [11]             : 0x20 [Type: unsigned char]
    [12]             : 0x0 [Type: unsigned char]
    [13]             : 0x2a [Type: unsigned char]

           /*
             * Get the previous up/down state of the key here since
             * SkipSysMsg() sets the key state table and destroys
             * the previous state info.
             */由于SkipSysMsg()函数会设置按键状态表并销毁之前的状态信息,因此需要在此处获取按键的上一次按下/释放状态

            fPrevDown = FALSE;
            if (TestKeyStateDown(ptiCurrent->pq, wParam))
                fPrevDown = TRUE;        //fPrevDown=true这里被赋值为TRUE

            /*
             * Eat the message from the input queue and set the keystate
             * table.
             */
            PATHTAKEN3(0x20);
            if (fRemove) {
                xxxSkipSysMsg(ptiCurrent, &qmsg);
            }

            /*
             * This gets us the LOWORD of lParam, the repeat count,
             * the bit in the hi byte indicating whether this is an extended
             * key, and the scan code.  We also need to re-get the wParam in
             * case xxxSkipSysMsg called a hook which modified the message.
             * AfterDark's password protection does this.
             */
            lParam = qmsg.msg.lParam;
            wParam = qmsg.msg.wParam;

            /*
             * Indicate if it was previously down.
             */
            if (fPrevDown)
                lParam |= 0x40000000;           // KF_REPEAT        //关键代码

1: kd> dv lParam
         lParam = 0n1074200577
1: kd> ?0n1074200577
Evaluate expression: 1074200577 = 40070001

            /*
             * Set the transition bit.
             */
            switch (message) {
            case WM_KEYUP:
            case WM_SYSKEYUP:
                lParam |= 0x80000000;           // KF_UP
                break;
            }

1: kd> dv lParam
         lParam = 0n-1073283071
1: kd> ?0n-1073283071
Evaluate expression: -1073283071 = c0070001

            /*
             * Set the alt key down bit.
             */
            if (TestKeyStateDown(ptiCurrent->pq, VK_MENU)) {
                lParam |= 0x20000000;           // KF_ALTDOWN
            }

            /*
             * Set the menu state flag.
             */
            if (IsMenuStarted(ptiCurrent)) {
                lParam |= 0x10000000;           // KF_MENUMODE
            }

            /*
             * Set the dialog state flag.
             */
            if (ptiCurrent->pq->QF_flags & QF_DIALOGACTIVE) {
                lParam |= 0x08000000;           // KF_DLGMODE
            }

            /*
             * 0x80000000 is set if up, clear if down
             * 0x40000000 is previous up/down state of key
             * 0x20000000 is whether the alt key is down
             * 0x10000000 is whether currently in menumode.
             * 0x08000000 is whether in dialog mode
             * 0x04000000 is not used
             * 0x02000000 is not used
             * 0x01000000 is whether this is an extended keyboard key
             *
             * Low word is repeat count, low byte hiword is scan code,
             * hi byte hiword is all these bits.
             */

© 版权声明

相关文章

没有相关内容!

暂无评论

none
暂无评论...