确认鼠标是否存在
fMouse = GetSystemMetrics (SM_MOUSEPRESENT); // True(非0)存在
确定按键个数
cButtons = GetSystemMetrics (SM_CMOUSEBUTTONS) ;
双击速度SystemParametersInfo
鼠标按键动作
对三键鼠标来说,三个键分别称为左键、中键、右键。在Windows表头文件中定义的与鼠标有关的标识符使用缩写LBUTTON、MBUTTON和RBUTTON。
只要鼠标跨越窗口或者在某窗口中按下鼠标按键,那么窗口消息处理程序就会收到鼠标消息,而不管该窗口是否活动或者是否拥有输入焦点。Windows为鼠标定义了21种消息,不过,其中有11个消息和显示区域无关(下面称之为「非显示区域」消息),Windows程序经常忽略这些消息。
只要鼠标跨越窗口或者在某窗口中按下鼠标按键,那么窗口消息处理程序就会收到鼠标消息,而不管该窗口是否活动或者是否拥有输入焦点。Windows为鼠标定义了21种消息,不过,其中有11个消息和显示区域无关(下面称之为「非显示区域」消息),Windows程序经常忽略这些消息。
当鼠标移过窗口的显示区域时,窗口消息处理程序收到WM_MOUSEMOVE*消息。当在窗口的显示区域中按下或者释放一个鼠标按键时,窗口消息处理程序会接收到下面这些消息:
键 | 按下 | 释放 | 按下(双键) |
---|---|---|---|
左 | WM_LBUTTONDOWN | WM_LBUTTONUP | WM_LBUTTONDBLCLK |
中 | WM_MBUTTONDOWN | WM_MBUTTONUP | WM_MBUTTONDBLCLK |
右 | WM_RBUTTONDOWN | WM_RBUTTONUP | WM_RBUTTONDBLCLK |
对于所有这些消息来说,其lParam值均含有鼠标的位置:低字组为x坐标,高字组为y坐标,这两个坐标是相对于窗口显示区域左上角的位置。您可以用LOWORD和HIWORD宏来提取这些值:
x = LOWORD (lParam) ;
y = HIWORD (lParam) ;
wParam的值指示鼠标按键以及Shift和Ctrl键的状态。您可以使用表头文件WINUSER.H中定义的位屏蔽来测试wParam。MK前缀代表鼠标按键。
例如,如果收到了WM_LBUTTONDOWN消息,而且值
wparam & MK_SHIFT
是TRUE(非0),您就知道当左键按下时也按下了Shift键。
如果希望您的窗口消息处理程序能够收到双按键的鼠标消息,那么在呼叫RegisterClass初始化窗口类别结构时,必须在窗口风格中包含CS_DBLCLKS标识符:
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ;
如果您的窗口类别风格中包含了CS_DBLCLKS,那么双击时窗口消息处理程序将收到如下消息:
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDBLCLK
WM_LBUTTONUP
WM_LBUTTONDBLCLK消息简单地替换了第二个WM_LBUTTONDOWN消息。
如果鼠标在窗口的显示区域之外但还在窗口内,Windows就给窗口消息处理程序发送一条「非显示区域」鼠标消息。窗口非显示区域包括标题列、菜单和窗口滚动条。
非显示区域鼠标消息几乎完全与显示区域鼠标消息相对应。消息中含有字母「NC」以表示是非显示区域消息。如果鼠标在窗口的非显示区域中移动,那么窗口消息处理程序会接收到WM_NCMOUSEMOVE消息。
键 | 按下 | 释放 | 按下(双击) |
---|---|---|---|
左 | WM_NCLBUTTONDOWN | WM_NCLBUTTONUP | WM_NCLBUTTONDBLCLK |
中 | WM_NCMBUTTONDOWN | WM_NCMBUTTONUP | WM_NCMBUTTONDBLCLK |
右 | WM_NCRBUTTONDOWN | WM_NCRBUTTONUP | WM_NCRBUTTONDBLCLK |
对非显示区域鼠标消息,wParam和lParam参数与显示区域鼠标消息的wParam和lParam参数不同。wParam参数指明移动或者按鼠标按键的非显示区域。它设定为WINUSER.H中定义的以HT开头的标识符之一(HT表示命中测试)。
lParam参数的低位word为x坐标,高位word为y坐标,但是,它们是屏幕坐标,而不是像显示区域鼠标消息那样指的是显示区域坐标。对屏幕坐标,显示器左上角的x和y的值为0。当往右移时x的值增加,往下移时y的值增加。
可以用两个Windows函数将屏幕坐标转换为显示区域坐标或者反之:
POINT pt;
ScreenToClient (hwnd, &pt) ;
ClientToScreen (hwnd, &pt) ;
第21个鼠标消息:命中测试消息WM_NCHITTEST,代表非显示区域命中测试。此消息优先于所有其它的显示区域和非显示区域鼠标消息。lParam参数含有鼠标位置的x和y屏幕坐标,wParam参数没有用。
Windows 应 用 程 序 通 常 把 这 个 消 息 传 送 给 DefWindowProc , 然 后 Windows 用WM_NCHITTEST消息产生与鼠标位置相关的所有其它鼠标消息。对于非显示区域鼠标消息,在处理WM_NCHITTEST时,从DefWindowProc传回的值将成为鼠标消息中的wParam参数,这个值可以是任意非显示区域鼠标消息的wParam值再加上以下内容:
如果DefWindowProc在其处理WM_NCHITTEST消息后传回HTCLIENT,那么Windows将把屏幕坐标转换为显示区域坐标并产生显示区域鼠标消息。
/*-------------------------------------------------------------------------
CHECKER1.C -- Mouse Hit-Test Demo Program No. 1
(c) Charles Petzold,
--------------------------------------------------------------------------*/
#include
#define DIVISIONS 5
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR
szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("Checker1");
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;
}
hwnd = CreateWindow(szAppName, TEXT("Checker1 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 BOOL fState[DIVISIONS][DIVISIONS];
static int cxBlock, cyBlock;
HDC hdc;
int x, y;
PAINTSTRUCT ps;
RECT rect;
switch (message)
{
case WM_SIZE:
cxBlock = LOWORD(lParam) / DIVISIONS;
cyBlock = HIWORD(lParam) / DIVISIONS;
return 0;
case WM_LBUTTONDOWN:
x = LOWORD(lParam) / cxBlock;
y = HIWORD(lParam) / cyBlock;
if (x < DIVISIONS && y < DIVISIONS)
{
fState[x][y] ^= 1;
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])
{
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, message, wParam, lParam);
}
/*----------------------------------------------------------------------------
CHECKER2.C -- Mouse Hit-Test Demo Program No. 2
(c) Charles Petzold, 1998
----------------------------------------------------------------------------*/
#include
#define DIVISIONS 5
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("Checker2");
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;
}
hwnd = CreateWindow(szAppName, TEXT("Checker2 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 BOOL fState[DIVISIONS][DIVISIONS];
static int cxBlock, cyBlock;
HDC hdc;
int x, y;
PAINTSTRUCT ps;
POINT point;
RECT rect;
switch (message)
{
case WM_SIZE:
cxBlock = LOWORD(lParam) / DIVISIONS;
cyBlock = HIWORD(lParam) / DIVISIONS;
return 0;
case WM_SETFOCUS:
ShowCursor(TRUE);
return 0;
case WM_KILLFOCUS:
ShowCursor(FALSE);
return 0;
case WM_KEYDOWN:
GetCursorPos(&point);
ScreenToClient(hwnd, &point);
x = max(0, min(DIVISIONS - 1, point.x / cxBlock));
y = max(0, min(DIVISIONS - 1, point.y / cyBlock));
switch (wParam)
{
case VK_UP:
y--;
break;
case VK_DOWN:
y++;
break;
case VK_LEFT:
x--;
break;
case VK_RIGHT:
x++;
break;
case VK_HOME:
x = y = 0;
break;
case VK_END:
x = y = DIVISIONS - 1;
break;
case VK_RETURN:
case VK_SPACE:
SendMessage(hwnd,
WM_LBUTTONDOWN, MK_LBUTTON,
MAKELONG(x * cxBlock, y * cyBlock));
break;
}
x = (x + DIVISIONS) % DIVISIONS;
y = (y + DIVISIONS) % DIVISIONS;
point.x = x * cxBlock + cxBlock / 2;
point.y = y * cyBlock + cyBlock / 2;
ClientToScreen(hwnd, &point);
SetCursorPos(point.x, point.y);
return 0;
case WM_LBUTTONDOWN:
x = LOWORD(lParam) / cxBlock;
y = HIWORD(lParam) / cyBlock;
if (x < DIVISIONS && y < DIVISIONS)
{
fState[x][y] ^= 1;
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])
{
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, message, wParam, lParam);
}
/*---------------------------------------------------------------------------
CHECKER3.C -- Mouse Hit-Test Demo Program No. 3
(c) Charles Petzold, 1998
----------------------------------------------------------------------------*/
#include
#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);
}
在WinMain中CreateWindow呼叫的参数,与在建立25个子窗口的WndProc中CreateWindow呼叫的参数间的比较:
参数 | 主窗口 | 子窗口 |
---|---|---|
窗口类别 | 「Checker3」 | 「Checker3_Child」 |
窗口标题 | 「Checker3…」 | NULL |
窗口样式 | WS_OVERLAPPEDWINDOW | WS_CHILDWINDOW |WS_VISIBLE |
水平位置 | CW_USEDEFAULT | 0 |
垂直位置 | CW_USEDEFAULT | 0 |
宽度 | CW_USEDEFAULT | 0 |
高度 | CW_USEDEFAULT | 0 |
父窗口句柄 | NULL | hwnd |
菜单句柄/子ID | NULL | (HMENU) (y << 8 | x) |
执行实体句柄 | hInstance | (HINSTANCE)GetWindowLong (hwnd, GWL_HINSTANCE) |
额外参数 | NULL | NULL |
/*---------------------------------------------------------------------------
CHECKER4.C -- Mouse Hit-Test Demo Program No. 4
(c) Charles Petzold, 1998
---------------------------------------------------------------------------*/
#include
#define DIVISIONS 5
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildWndProc(HWND, UINT, WPARAM, LPARAM);
int idFocus = 0;
TCHAR szChildClass[] = TEXT("Checker4_Child");
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int
iCmdShow)
{
static TCHAR szAppName[] = TEXT("Checker4");
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("Checker4 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;
// On set-focus message, set focus to child window
case WM_SETFOCUS:
SetFocus(GetDlgItem(hwnd, idFocus));
return 0;
// On key-down message, possibly change the focus window
case WM_KEYDOWN:
x = idFocus & 0xFF;
y = idFocus >> 8;
switch (wParam)
{
case VK_UP: y--;
break;
case VK_DOWN: y++;
break;
case VK_LEFT: x--;
break;
case VK_RIGHT: x++; break;
case VK_HOME: x = y = 0;
break;
case VK_END: x = y = DIVISIONS - 1;
break;
default: return 0;
}
x = (x + DIVISIONS) % DIVISIONS;
y = (y + DIVISIONS) % DIVISIONS;
idFocus = y << 8 | x;
SetFocus(GetDlgItem(hwnd, idFocus));
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_KEYDOWN:
// Send most key presses to the parent window
if (wParam != VK_RETURN && wParam != VK_SPACE)
{
SendMessage(GetParent(hwnd), message, wParam,
lParam);
return 0;
}
// For Return and Space, fall through to toggle the square
case WM_LBUTTONDOWN:
SetWindowLong(hwnd, 0, 1 ^ GetWindowLong(hwnd, 0));
SetFocus(hwnd);
InvalidateRect(hwnd, NULL, FALSE);
return 0;
// For focus messages, invalidate the window for repaint
case WM_SETFOCUS:
idFocus = GetWindowLong(hwnd, GWL_ID);
// Fall through
case WM_KILLFOCUS:
InvalidateRect(hwnd, NULL, TRUE);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
Rectangle(hdc, 0, 0, rect.right, rect.bottom);
// Draw the "x" mark
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);
}
// Draw the "focus" rectangle
if (hwnd == GetFocus())
{
rect.left += rect.right / 10;
rect.right -= rect.left;
rect.top += rect.bottom / 10;
rect.bottom -= rect.top;
SelectObject(hdc, GetStockObject
(NULL_BRUSH));
SelectObject(hdc, CreatePen(PS_DASH, 0,
0));
Rectangle(hdc, rect.left, rect.top, rect.right,
rect.bottom);
DeleteObject(SelectObject(hdc,
GetStockObject(BLACK_PEN)));
}
EndPaint(hwnd, &ps);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
/*----------------------------------------------------------------------------
BLOKOUT2.C -- Mouse Button & Capture Demo Program
(c) Charles Petzold, 1998
----------------------------------------------------------------------------*/
#include
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("BlokOut2");
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;
}
hwnd = CreateWindow(szAppName, TEXT("Mouse Button & Capture 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;
}
void DrawBoxOutline(HWND hwnd, POINT ptBeg, POINT ptEnd)
{
HDC hdc;
hdc = GetDC(hwnd);
SetROP2(hdc, R2_NOT);
SelectObject(hdc, GetStockObject(NULL_BRUSH));
Rectangle(hdc, ptBeg.x, ptBeg.y, ptEnd.x, ptEnd.y);
ReleaseDC(hwnd, hdc);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM
wParam, LPARAM lParam)
{
static BOOL fBlocking, fValidBox;
static POINT ptBeg, ptEnd, ptBoxBeg, ptBoxEnd;
HDC hdc;
PAINTSTRUCT ps;
switch (message)
{
case WM_LBUTTONDOWN:
ptBeg.x = ptEnd.x = LOWORD(lParam);
ptBeg.y = ptEnd.y = HIWORD(lParam);
DrawBoxOutline(hwnd, ptBeg, ptEnd);
SetCapture(hwnd);
SetCursor(LoadCursor(NULL, IDC_CROSS));
fBlocking = TRUE;
return 0;
case WM_MOUSEMOVE:
if (fBlocking)
{
SetCursor(LoadCursor(NULL, IDC_CROSS));
DrawBoxOutline(hwnd, ptBeg, ptEnd);
ptEnd.x = LOWORD(lParam);
ptEnd.y = HIWORD(lParam);
DrawBoxOutline(hwnd, ptBeg, ptEnd);
}
return 0;
case WM_LBUTTONUP:
if (fBlocking)
{
DrawBoxOutline(hwnd, ptBeg, ptEnd);
ptBoxBeg = ptBeg;
ptBoxEnd.x = LOWORD
(lParam);
ptBoxEnd.y = HIWORD
(lParam);
ReleaseCapture();
SetCursor(LoadCursor(NULL, IDC_ARROW));
fBlocking = FALSE;
fValidBox = TRUE;
InvalidateRect(hwnd, NULL, TRUE);
}
return 0;
case WM_CHAR:
if (fBlocking & wParam == '\x1B') // i.e., Escape
{
DrawBoxOutline(hwnd, ptBeg, ptEnd);
ReleaseCapture();
SetCursor(LoadCursor(NULL, IDC_ARROW));
fBlocking = FALSE;
}
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
if (fValidBox)
{
SelectObject(hdc, GetStockObject
(BLACK_BRUSH));
Rectangle(hdc, ptBoxBeg.x, ptBoxBeg.y,
ptBoxEnd.x, ptBoxEnd.y);
}
if (fBlocking)
{
SetROP2(hdc, R2_NOT);
SelectObject(hdc, GetStockObject
(NULL_BRUSH));
Rectangle(hdc, ptBeg.x, ptBeg.y, ptEnd.x,
ptEnd.y);
}
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
SetCapture (hwnd) ;
在这个函数调用之后,Windows将所有鼠标消息发给窗口句柄为hwnd的窗口消息处理程序。之后收到鼠标消息都是以显示区域消息的型态出现,即使鼠标正在窗口的非显示区域。lParam参数将指示鼠标在显示区域坐标中的位置。不过,当鼠标位于显示区域的左边或者上方时,这些x和y坐标可以是负的。当您想释放鼠标时,调用:
ReleaseCapture () ;
从而使处理恢复正常。
消息:WM_MOUSEWHEEL