7.3 非客戶區滑鼠訊息
摘錄於《Windows程式(第5版,珍藏版).CHarles.Petzold 著》P230
到目前為止,所有討論的 10 種滑鼠訊息都是發生在視窗客戶區內的移動或單擊。如果滑鼠位於視窗內部除客戶區外的其他區域,Windows 就會向視窗過程傳送一個“非客戶區”滑鼠訊息。視窗的非客戶區包括標題欄、選單和視窗滾動條。
系統一般不需要使用者處理非客戶區滑鼠訊息。取而代之的是,使用者只需將這些訊息傳送給 DefWindowProc,從而使 Windows 執行系統函式。從這個角度來看,非客戶區滑鼠訊息與 WM_SYSKEYDOWN、WM_SYSKEYUP 和 WM_SYSCHAR 這樣的系統鍵盤訊息很相似。
非客戶區滑鼠訊息幾乎與客戶區滑鼠訊息完全對應。訊息的識別符號包含了字母“NC”,表示“非客戶”(nonclient)。如果滑鼠在視窗的非客戶區內移動,視窗過程就會接收 WM_NCMOUSEMOVE 訊息。滑鼠按鈕產生的訊息如下表所示。
按 鈕 | 按 下 | 釋 放 | 第二次按下按鈕 |
---|---|---|---|
左鍵 | WM_NCLBUTTONDOWN | WM_NCLBUTTONUP | WM_NCLBUTTONDBLCLK |
中鍵 | WM_NCMBUTTONDOWN | WM_NCMBUTTONUP | WM_NCMBUTTONDBLCLK |
右鍵 | WM_NCRBUTTONDOWN | WM_NCRBUTTONUP | WM_NCRBUTTONDBLCLK |
非客戶區滑鼠訊息的引數 wParam 和 lParam 與客戶區滑鼠訊息的引數有些不同。引數 wParam 表示非客戶區滑鼠移動或單擊的位置。它的值被設定成一個以 HT 為首的識別符號。其中 HT 表示“擊中測試”(hit-test)。這些識別符號都定義在 WINUSER.H 標頭檔案中。
引數 lParam 的低位字包含 x 座標,高位字包含 y 座標。但是,這些座標都是螢幕座標,而不是前面的客戶座標。對螢幕座標來說,顯示區域左上角的 x 和 y 都是 0。向右表示 x 值增加的方向,而沿螢幕向下表示 y 值增加的方向
利用下面兩個 Windows 函式,可以將螢幕座標與客戶區座標相互轉換:
- ScreenToClient (hwnd, &pt);
- ClientToScreen (hwnd, &pt);
注意,如果一個螢幕座標點位於視窗客戶區的上方或者左方,那麼轉換成客戶區座標後,x 值或 y 值會是負數。
7.3.1 擊中測試訊息
數一數,對於所有 21 個滑鼠訊息,到現在我們已經學習了其中 20 個。最後一個訊息是 WM_NCHITTEST,表示“非客戶區擊中測試”(nonclient hit test)。這個訊息的優先順序高於其他所有的客戶區和非客戶區滑鼠訊息。引數 lParam 包含滑鼠位置的螢幕座標 x 和 y。引數 wParam 沒有用到。
Windows 應用程式通常會把這個訊息傳送給 DefWindowProc。然後 Windows 會利用 WM_NCHITTEST 訊息來產生所有其他和滑鼠位置相關的滑鼠訊息。對非客戶區訊息來說,DefWindowProc 處理 WM_NCHITTEST 訊息後返回一個可用於滑鼠訊息引數 wParam 的值。這個返回值可以是任何一個非客戶區滑鼠訊息的 wParam 引數的值,也可以是如下所示的一些值:
- HTCLIENT 客戶區
- HTNOWHERE 不在任何視窗
- HTTRANSPARENT 被另一個視窗覆蓋的視窗
- HTERROR 使函式 DefWindowProc 產生一個警示聲
你可能記得如何捕捉 WM_SYSKEYDOWN 訊息,使所有的系統鍵盤函式失效。也許你會想,可不可以利用滑鼠訊息來實現類似的功能呢?當然可以!如果在視窗過程中包含下面幾行語句:
- case WM_NCHITTEST:
- return (LRESULT) HTNOWHERE;
7.3.2 訊息引發訊息
Windows 利用 WM_NCHITTEST 訊息來產生其他所有的滑鼠訊息。這種訊息引發訊息的思想在 Windows 中很常見。舉一個例子來說,你可能知道,雙擊 Windows 程式的系統選單圖示可以關閉這個這個視窗。雙擊產生了一系列 WM_NCHITTEST 訊息。滑鼠位於系統選單圖示之上,所以 DefWindowProc 返回 HTSYSMENU,這時 Windows 在訊息佇列中添加了一個 WM_NCLBUTTONDBLCLK 訊息,其中引數 wParam 等於 HTSYSMENU。
視窗過程一般將這個訊息傳送給 DefWindowProc。當 DefWindowProc 接收到引數 wParam 為 HTSYSMENU 的 WM_NCLBUTTONDBLCLK 訊息時,系統會在訊息佇列中新增一個 WM_SYSCOMMAND 訊息,其中引數 wParam 等於 SC_CLOSE。(當用戶選擇系統選單中的關閉按鈕時,也產生 WM_SYSCOMMAND 訊息。)然後,通常視窗過程再將這個訊息傳送給 DefWindowProc。DefWindowProc 處理這個訊息,並向視窗傳送 WM_CLOSE 訊息。
如果想在結束程式之前等待使用者的確認,視窗過程可以捕捉 WM_CLOSE 訊息。否則,DefWindowProc 會呼叫 DestroyWindow 函式來處理 WM_CLOSE 訊息。除了其他處理,DestroyWindow 還會向視窗過程傳送一個 WM_DESTROY 訊息。在正常情況下,視窗過程處理 WM_DESTROY 訊息的程式碼如下。
- case WM_DESTROY:
- PostQuitMessage (0);
- reutrn 0;