Windows的GetKeyState函數能夠返回滑鼠按鍵或Shift等鍵的狀態,當GetKeyState函數返回一個負值時,表示已經按下了滑鼠按鍵或相應的Shift或Ctrl鍵。
在沒有按下滑鼠時,不能使用GetKeyState函數。
在滑鼠事件的時候,有時候,需要對參數wParam和MK_XX進行位與運算
if(wParam & MK_SHIFT){ if(wParam & MK_CONTROL) { 按下Shift+Ctrl } else{ 按下Shift鍵 }}else{ if(wParam & MK_CONTROL) { 按下Ctrl鍵 } else { Shift和Ctrl鍵都沒有按下 }}
又如:
case WM_LBUTTONDOWN: if(!(wParam & MK_SHIFT)) { 這裡處理左鍵; } return 0;
下面常用的虛擬按鍵碼:
VK_LBUTTONVK_RBUTTONVK_MBUTTONVK_SHIFTVK_CONTROLVK_LMENUVK_RMENU
看看非客戶區滑鼠訊息
視窗的非客戶區包括標題列,菜單和視窗捲軸。
滑鼠按鍵產生的訊息如下所示:
| 按鈕 |
按下 |
釋放 |
第二次按下按鈕 |
| 左鍵 |
WM_NCLBUTTONDOWN |
WM_NCLBUTTONUP |
WM_NCLBUTTONDBLCLK |
| 中鍵 |
WM_NCMBUTTONDOWN |
WM_NCMBUTTONUP |
WM_NCMBUTTONDBLCLK |
| 右鍵 |
WN_NCRBUTTONDOWN |
WM_NCRBUTTONUP |
WM_NCRBUTTONDBLCLK |
利用下面兩個函數,可以將螢幕座標和客戶區座標進行互換
ScreenToClient(hwnd,&pt);ClientToScreen(hwnd,&pt);
擊中測試訊息:
| HTCLIENT |
客戶區 |
| HTNOWHERE |
不在任何視窗 |
| HTTRANSPARENT |
被另一個視窗覆蓋的視窗 |
| HTERROR |
使函數DefWindowProc產生一個警示聲 |
下面這個代碼,可以讓你的視窗叫天天不應,叫地地不靈
case WM_NCHITTEST: return (LRESULT)HTNOWHERE;
此時,無論滑鼠位於視窗任何位置,包括系統功能表表徵圖,調整大小和關閉按鈕,滑鼠按鍵操作都將失效。
一個簡單的程式,該程式將客戶區劃分成25個矩形,構成5X5的數組,如果在其中一個矩形內單擊滑鼠,就用X形填充該矩形,再次單擊,則X形消失;
#include<windows.h>#include<windowsx.h>#define DIVISIONS 5LRESULT CALLBACK WindowProc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter);int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // command line int nCmdShow // show state){static TCHAR szAppName[]=TEXT("leidemingzi");HWND hwnd;MSG msg;WNDCLASS wndclass;wndclass.cbClsExtra=0;wndclass.cbWndExtra=0;wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);wndclass.hIcon=LoadIcon(NULL,IDI_ERROR);wndclass.hInstance=hInstance;wndclass.lpfnWndProc=WindowProc;wndclass.lpszClassName=szAppName;wndclass.lpszMenuName=NULL;wndclass.style=CS_HREDRAW|CS_VREDRAW;if(!RegisterClass(&wndclass)){MessageBox(NULL,TEXT("the program require window NT"),szAppName,MB_ICONERROR);return 0;}hwnd=CreateWindow( szAppName, // registered class name TEXT("this is title"), // window name WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // horizontal position of window CW_USEDEFAULT, // vertical position of window CW_USEDEFAULT, // window width CW_USEDEFAULT, // window height NULL, // handle to parent or owner window NULL, // menu handle or child identifier hInstance, // handle to application instance NULL // window-creation data);ShowWindow(hwnd,nCmdShow);UpdateWindow(hwnd);while(GetMessage(&msg,NULL,0,0)){TranslateMessage(&msg);DispatchMessage(&msg);}return msg.wParam;}LRESULT CALLBACK WindowProc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter){HDC hdc;PAINTSTRUCT ps;static BOOL fState[DIVISIONS][DIVISIONS];static int cxBlock,cyBlock;int x,y;RECT rect;switch(uMsg){case WM_SIZE:cxBlock=LOWORD(lParam)/DIVISIONS;//橫豎都分成五份cyBlock=HIWORD(lParam)/DIVISIONS;return 0;case WM_LBUTTONDOWN:x=GET_X_LPARAM(lParam)/cxBlock;y=GET_Y_LPARAM(lParam)/cyBlock;if(x<DIVISIONS && y<DIVISIONS){fState[x][y]^=1;//異或,如果已經顯示了X,再點擊,則X消失,如果沒有X顯示,則點擊會顯示Xrect.left=x*cxBlock; //標記該被點擊的矩形地區,為後面“顯示”和“消失”固定一個範圍rect.top=y*cyBlock;rect.right=(x+1)*cxBlock;rect.bottom=(y+1)*cyBlock;InvalidateRect(hwnd,&rect,FALSE);}else{MessageBeep(0);}return 0;case WM_PAINT:hdc=BeginPaint(hwnd,&ps);for(x=0;x<DIVISIONS;++x){for(y=0;y<DIVISIONS;++y){Rectangle(hdc,x*cxBlock,y*cyBlock,(x+1)*cxBlock,(y+1)*cyBlock);if(fState[x][y])//畫“X”{MoveToEx(hdc,x*cxBlock,y*cyBlock,NULL);LineTo(hdc,(x+1)*cxBlock,(y+1)*cyBlock);MoveToEx(hdc,x*cxBlock,(y+1)*cyBlock,NULL);LineTo(hdc,(x+1)*cxBlock,y*cyBlock);}}}EndPaint(hwnd,&ps);return 0;case WM_DESTROY:PostQuitMessage(0);return 0;}return DefWindowProc(hwnd,uMsg,wParam,lParam);}
運行結果如下:
可以用子視窗完成相同的功能:
#include <windows.h>#define DIVISIONS 5LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;LRESULT CALLBACK ChildWndProc (HWND, UINT, WPARAM, LPARAM) ;TCHAR szChildClass[] = TEXT ("Checker3_Child") ;int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){ static TCHAR szAppName[] = TEXT ("Checker3") ; 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 ("Program requires Windows NT!"), szAppName, MB_ICONERROR) ; return 0 ; } wndclass.lpfnWndProc = ChildWndProc ; wndclass.cbWndExtra = sizeof (long) ; wndclass.hIcon = NULL ; wndclass.lpszClassName = szChildClass ; RegisterClass (&wndclass) ; hwnd = CreateWindow (szAppName, TEXT ("Checker3 Mouse Hit-Test Demo"), 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 HWND hwndChild[DIVISIONS][DIVISIONS] ; int cxBlock, cyBlock, x, y ; switch (message) { case WM_CREATE : for (x = 0 ; x < DIVISIONS ; x++) for (y = 0 ; y < DIVISIONS ; y++) hwndChild[x][y] = CreateWindow (szChildClass, NULL, WS_CHILDWINDOW | WS_VISIBLE, 0, 0, 0, 0, hwnd, (HMENU) (y << 8 | x), (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE), NULL) ; return 0 ; case WM_SIZE : cxBlock = LOWORD (lParam) / DIVISIONS ; cyBlock = HIWORD (lParam) / DIVISIONS ; for (x = 0 ; x < DIVISIONS ; x++) for (y = 0 ; y < DIVISIONS ; y++) MoveWindow (hwndChild[x][y], x * cxBlock, y * cyBlock, cxBlock, cyBlock, TRUE) ; return 0 ; case WM_LBUTTONDOWN : MessageBeep (0) ; return 0 ; case WM_DESTROY : PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ;}LRESULT CALLBACK ChildWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ HDC hdc ; PAINTSTRUCT ps ; RECT rect ; switch (message) { case WM_CREATE : SetWindowLong (hwnd, 0, 0) ; // on/off flag return 0 ; case WM_LBUTTONDOWN : SetWindowLong (hwnd, 0, 1 ^ GetWindowLong (hwnd, 0)) ; InvalidateRect (hwnd, NULL, FALSE) ; return 0 ; case WM_PAINT : hdc = BeginPaint (hwnd, &ps) ; GetClientRect (hwnd, &rect) ; Rectangle (hdc, 0, 0, rect.right, rect.bottom) ; if (GetWindowLong (hwnd, 0)) { MoveToEx (hdc, 0, 0, NULL) ; LineTo (hdc, rect.right, rect.bottom) ; MoveToEx (hdc, 0, rect.bottom, NULL) ; LineTo (hdc, rect.right, 0) ; } EndPaint (hwnd, &ps) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ;}