2013-08-20 32 views
0

我正在編寫一個程序,用於顯示窗口爲8個不同的鍵盤消息發送窗口過程的所有信息。這裏是代碼windows中的鍵盤程序

/*-------------------------------------------------------- 
    KEYVIEW1.C -- Displays Keyboard and Character Messages 
       (c) Charles Petzold, 1998 
    --------------------------------------------------------*/ 

#include <windows.h> 

    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; 

    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 
         PSTR szCmdLine, int iCmdShow) 
    { 
     static TCHAR szAppName[] = TEXT ("KeyView1") ; 
     HWND   hwnd ; 
     MSG   msg ; 
     WNDCLASS  wndclass ; 

     wndclass.style   = CS_HREDRAW | CS_VREDRAW ; 
     wndclass.lpfnWndProc = WndProc ; 
     wndclass.cbClsExtra = 0 ; 
     wndclass.cbWndExtra = 0 ; 
     wndclass.hInstance  = hInstance ; 
     wndclass.hIcon   = LoadIcon (NULL, IDI_APPLICATION) ; 
     wndclass.hCursor  = LoadCursor (NULL, IDC_ARROW) ; 
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; 
     wndclass.lpszMenuName = NULL ; 
     wndclass.lpszClassName = szAppName ; 

     if (!RegisterClass (&wndclass)) 
     { 
       MessageBox (NULL, TEXT ("This program requires Windows NT!"), 
          szAppName, MB_ICONERROR) ; 
       return 0 ; 
     } 

     hwnd = CreateWindow (szAppName, TEXT ("Keyboard Message Viewer #1"), 
           WS_OVERLAPPEDWINDOW, 
           CW_USEDEFAULT, CW_USEDEFAULT, 
           CW_USEDEFAULT, CW_USEDEFAULT, 
           NULL, NULL, hInstance, NULL) ; 

     ShowWindow (hwnd, iCmdShow) ; 
     UpdateWindow (hwnd) ; 

     while (GetMessage (&msg, NULL, 0, 0)) 
     { 
       TranslateMessage (&msg) ; 
       DispatchMessage (&msg) ; 
     } 
     return msg.wParam ; 
    } 

    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 
    { 
     static int cxClientMax, cyClientMax, cxClient, cyClient, cxChar, cyChar ; 
     static int cLinesMax, cLines ; 
     static PMSG pmsg ; 
     static RECT rectScroll ; 
     static TCHAR szTop[] = TEXT ("Message  Key  Char  ") 
           TEXT ("Repeat Scan Ext ALT Prev Tran") ; 
     static TCHAR szUnd[] = TEXT ("_______  ___  ____  ") 
           TEXT ("______ ____ ___ ___ ____ ____") ; 

     static TCHAR * szFormat[2] = { 

        TEXT ("%-13s %3d %-15s%c%6u %4d %3s %3s %4s %4s"), 
        TEXT ("%-13s   0x%04X%1s%c %6u %4d %3s %3s %4s %4s") } ; 

     static TCHAR * szYes = TEXT ("Yes") ; 
     static TCHAR * szNo = TEXT ("No") ; 
     static TCHAR * szDown = TEXT ("Down") ; 
     static TCHAR * szUp = TEXT ("Up") ; 

     static TCHAR * szMessage [] = { 
          TEXT ("WM_KEYDOWN"), TEXT ("WM_KEYUP"), 
          TEXT ("WM_CHAR"),  TEXT ("WM_DEADCHAR"), 
          TEXT ("WM_SYSKEYDOWN"), TEXT ("WM_SYSKEYUP"), 
          TEXT ("WM_SYSCHAR"), TEXT ("WM_SYSDEADCHAR") } ; 
     HDC   hdc ; 
     int   i, iType ; 
     PAINTSTRUCT ps ; 
     TCHAR  szBuffer[128], szKeyName [32] ; 
     TEXTMETRIC tm ; 

     switch (message) 
     { 
     case WM_CREATE: 
     case WM_DISPLAYCHANGE: 

        // Get maximum size of client area 

       cxClientMax = GetSystemMetrics (SM_CXMAXIMIZED) ; 
       cyClientMax = GetSystemMetrics (SM_CYMAXIMIZED) ; 

        // Get character size for fixed-pitch font 

       hdc = GetDC (hwnd) ; 

       SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ; 
       GetTextMetrics (hdc, &tm) ; 
       cxChar = tm.tmAveCharWidth ; 
       cyChar = tm.tmHeight ; 

       ReleaseDC (hwnd, hdc) ; 

        // Allocate memory for display lines 

       if (pmsg) 
        free (pmsg) ; 

       cLinesMax = cyClientMax/cyChar ; 
       pmsg = (PMSG)malloc (cLinesMax * sizeof (MSG)) ; 
       cLines = 0 ; 
             // fall through 
     case WM_SIZE: 
       if (message == WM_SIZE) 
       { 
        cxClient = LOWORD (lParam) ; 
        cyClient = HIWORD (lParam) ; 
       } 
        // Calculate scrolling rectangle 

       rectScroll.left = 0 ; 
       rectScroll.right = cxClient ; 
       rectScroll.top = cyChar ; 
       rectScroll.bottom = cyChar * (cyClient/cyChar) ; 

       InvalidateRect (hwnd, NULL, TRUE) ; 
       return 0 ; 

     case WM_KEYDOWN: 
     case WM_KEYUP: 
     case WM_CHAR: 
     case WM_DEADCHAR: 
     case WM_SYSKEYDOWN: 
     case WM_SYSKEYUP: 
     case WM_SYSCHAR: 
     case WM_SYSDEADCHAR: 

        // Rearrange storage array 

       for (i = cLinesMax - 1 ; i > 0 ; i--) 
       { 
        pmsg[i] = pmsg[i - 1] ; 
       } 
        // Store new message 

       pmsg[0].hwnd = hwnd ; 
       pmsg[0].message = message ; 
       pmsg[0].wParam = wParam ; 
       pmsg[0].lParam = lParam ; 

       cLines = min (cLines + 1, cLinesMax) ; 

        // Scroll up the display 

       ScrollWindow (hwnd, 0, -cyChar, &rectScroll, &rectScroll) ; 

       break ;  // ie, call DefWindowProc so Sys messages work 

     case WM_PAINT: 
       hdc = BeginPaint (hwnd, &ps) ; 

       SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ; 
       SetBkMode (hdc, TRANSPARENT) ; 
       TextOut (hdc, 0, 0, szTop, lstrlen (szTop)) ; 
       TextOut (hdc, 0, 0, szUnd, lstrlen (szUnd)) ; 

       for (i = 1 ; i < max (cLines, cyClient/cyChar - 1) ; i++) 
       { 
        iType = pmsg[i].message == WM_CHAR || 
          pmsg[i].message == WM_SYSCHAR || 
          pmsg[i].message == WM_DEADCHAR || 
          pmsg[i].message == WM_SYSDEADCHAR ; 

        GetKeyNameText (pmsg[i].lParam, szKeyName, 
            sizeof (szKeyName)/sizeof (TCHAR)) ; 

        TextOut (hdc, 0, (cyClient/cyChar - i) * cyChar, szBuffer, 
          wsprintf (szBuffer, szFormat [iType], 
           szMessage [pmsg[i].message - WM_KEYFIRST],     
           pmsg[i].wParam, 
           (PTSTR) (iType!=0 ? TEXT (" ") : szKeyName), 
           (TCHAR) (iType ? pmsg[i].wParam : ' '), 
           LOWORD (pmsg[i].lParam), 
           HIWORD (pmsg[i].lParam) & 0xFF, 
           0x01000000 & pmsg[i].lParam ? szYes : szNo,,// for extended key flag 

           0x20000000 & pmsg[i].lParam ? szYes : szNo, 
           0x40000000 & pmsg[i].lParam ? szDown : szUp,//Previous key state 
           0x80000000 & pmsg[i].lParam ? szUp : szDown)) ;//transition state 
       } 
       EndPaint (hwnd, &ps) ; 
       return 0 ; 

     case WM_DESTROY: 
       PostQuitMessage (0) ; 
       return 0 ; 
     } 
     return DefWindowProc (hwnd, message, wParam, lParam) ; 
    } 

我的問題是,我無法理解的代碼。我盡我所能。

在線路

靜態TCHAR * szFormat [2] = {

   TEXT ("%-13s %3d %-15s%c%6u %4d %3s %3s %4s %4s"), 
       TEXT ("%-13s   0x%04X%1s%c %6u %4d %3s %3s %4s %4s") } ; 

正在發生什麼?我理解的第一行而不是第二個。

在TextOut函數

什麼呢​​ 意味着
什麼代碼使用 0x01000000
,爲什麼我們與HIWORD (pmsg[i].lParam) & 0xFF,

我知道這些都是很多的問題,但沒有具體&使用0XFF他們在書中解釋。請任何人回答至少一個問題。 任何幫助,將不勝感激

+1

只是一個評論,我並不真正瞭解Windows編程,但它肯定自1998年以來肯定發生了很大的變化。我的意思是當時甚至沒有NT內核。也許你應該考慮投資這個時代的教科書。 –

+2

@Jean它真的沒有,至少不是基礎知識。 Petzold的[Programming Windows,5th Edition](http://www.amazon.com/Programming-Windows%C2%AE-Edition-Microsoft-Series/dp/157231995X)仍然是標準教科書。版權日期1998. –

回答

5

在行

static TCHAR * szFormat[2] = {     
      TEXT ("%-13s %3d %-15s%c%6u %4d %3s %3s %4s %4s"), 
      TEXT ("%-13s   0x%04X%1s%c %6u %4d %3s %3s %4s %4s") } ; 

發生了什麼?我理解了第一行,而不是第二行。

這不是Windows特有的。它只是一個C風格的字符串數組,它們本身是指向一個以nul結尾的字符數組的指針。

  • 它宣佈static使得它僅初始化一次當函數首先調用,並保持其在後續調用值。

  • TCHAR是一個Windows typedef,用於charwchar_t,具體取決於您是否構建Unicode應用程序。所以TCHAR *相當於char *wchar_t *

  • 名稱szFormatsystems hungarian notation,在Win32編程中很常見,並且由Petzold廣泛使用。 sz表示它是nul(z ero) - 終止s tring。

  • [2]部分只是使其包含兩個元素的數組。一個本身包含數組的數組。

  • TEXT是一個函數式宏,用於根據構建配置適當地聲明字符串文字。在Unicode版本中,L被附加到字符串文字的開頭,以使其成爲一個寬字符串。在非Unicode版本中,沒有附加任何內容。

  • 字符串本身只是格式字符串,就像你可能在標準C.與printf function使用除Petzold的代碼使用它與wsprintf,這個C函數的Windows版本。基本上,所有%零件都是佔位符,它們填充了您指定的變量的值。它們有特殊的裝飾以提供對輸出字符串格式化的更廣泛的控制。

case WM_SIZE: 

     if (message == WM_SIZE) 
     { 
      cxClient = LOWORD (lParam) ; 
      cyClient = HIWORD (lParam) ; 
     } 

是什麼message == WM_SIZE意思?

我不知道。實際上,這看起來像是一個錯誤。在WM_SIZE的情況下,您已經知道messageWM_SIZE。因此再次檢查它是沒有意義的。只是假裝它不在那裏。

​​是什麼意思?

從名稱,並在頂部的變量聲明,你知道szMessage是C風格的字符串數組,就像我們看到了szFormat。它包含他感興趣的窗口消息的名稱,如WM_KEYDOWNWM_KEYUP

括號內的東西是數組中的索引器。就好像他編寫了szMessage[1]來訪問數組中的第二個元素,除非他正在使用表達式計算要動態訪問的項的索引。

構建該表達式,以便它將數組中的消息名稱與運行時已知的消息ID相匹配。您從pmsg[i].message獲得消息ID,然後從WM_KEYFIRST中減去它,因爲這是第一個鍵盤消息的ID。這使得消息ID與字符串數組中消息名稱的順序同步。

,哪些代碼使用0x01000000
,爲什麼我們與HIWORD (pmsg[i].lParam) & 0xFF,

專門用於& 0XFF那些只是位掩碼。使用&運算符(按位AND)將指定位隱藏起來,將它們與一個位值組合。

至於它們的含義,這些都在特定窗口消息的文檔中涵蓋。例如,在WM_KEYDOWN docs中,它會告訴您lParam值中特定位的含義。通過掩蓋這些位,您可以將它們隔離以獲取單個數據片段。

Petzold利用了他監控的所有鍵盤相關消息(列在我們剛纔談到的szMessage陣列中)都使用相同格式的lParam值。這可以通過查看每條消息的相應文檔來驗證。例如,WM_CHAR與我們剛剛看到的WM_KEYDOWN相同。這使得代碼大大簡化。

這樣做的目的當然是每次窗口被繪製時向用戶顯示有關鍵盤事件的信息。

+1

「它被聲明爲靜態的,因爲它只能在定義它的代碼文件中使用 - 即它沒有外部鏈接。」鏈接與局部變量(名稱..)AFAIK無關。 – dyp

+0

@DyP Err,oops。我認爲這是一個全球變量。錯過了它是本地的事實。正在修復... –

+2

「一個本身包含數組的數組。」它是一個指針數組,它可以包含*數組。 – dyp

相關問題