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_LBUTTON
VK_RBUTTON
VK_MBUTTON
VK_SHIFT
VK_CONTROL
VK_LMENU
VK_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 5
LRESULT 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显示,则点击会显示X
rect.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 5
LRESULT 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) ;
}