特殊说明:版权归个人所有,请勿转载,谢谢合作。
鼠标及键盘作为Windows系统最重要的输入设置,要深入理解消息的类型以及消息的捕获方法。本章节重点介绍鼠标及键盘消息的基本概念与应用。
4.1 鼠标消息的应用
根据MSDN的描述,Windows系统有24种不同的消息,用来报告与鼠标有关的事件。这些消息分为两大类:客户区域鼠标消息与非客户区域鼠标消息。客户区域鼠标消息,用来报告当前窗口客户区域里发生的事件。非客户区域鼠标消息,则用来报告除当前窗口以外的窗口区域发生的事件。
在鼠标消息处理过程中,非客户区域并不常用,在过程处理函数中不去捕获这部分消息即可,系统会通过DefWindowProc函数交给系统处理。表4.1列出了鼠标的消息,并对响应区域进行了区分。
- 表4.1 鼠标消息事件
| 区域 | 消息 | 事件描述 |
| 客户区域 | WM_LBUTTONDOWN | 客户区左键按下事件 |
| WM_LBUTTONUP | 客户区左键抬起事件 | |
| WM_LBUTTONDBLCLK | 客户区左键双击事件 | |
| WM_MBUTTONDOWN | 客户区中键按下事件 | |
| WM_MBUTTONUP | 客户区中键抬起事件 | |
| WM_MBUTTONDBLCLK | 客户区中键双击事件 | |
| WM_RBUTTONDOWN | 客户区右键按下事件 | |
| WM_RBUTTONUP | 客户区右键抬起事件 | |
| WM_RBUTTONDBLCLK | 客户区右键双击事件 | |
| WM_MOUSEMOVE | 客户区鼠标移动事件 | |
| WM_MOUSEWHEEL | 客户区滚轮滚动事件 | |
| WM_MOUSEACTIVATE | 非活动窗口,鼠标操作事件 | |
| WM_CAPTURECHANGED | 失去鼠标捕获窗口的事件 | |
| 非客户区域 | WM_NCHITTEST | 移动窗口标题栏发生的事件 |
| WM_NCLBUTTONDBLCLK | 非客户区左键双击事件 | |
| WM_NCLBUTTONDOWN | 非客户区左键按下事件 | |
| WM_NCLBUTTONUP | 非客户区左键抬起事件 | |
| WM_NCMBUTTONDBLCLK | 非客户区中键双击事件 | |
| WM_NCMBUTTONDOWN | 非客户区中键按下事件 | |
| WM_NCMBUTTONUP | 非客户区中键抬起事件 | |
| WM_NCMOUSEMOVE | 非客户区鼠标移动事件 | |
| WM_NCRBUTTONDBLCLK | 非客户区右键双击事件 | |
| WM_NCRBUTTONDOWN | 非客户区右键按下事件 | |
| WM_NCRBUTTONUP | 非客户区右键抬起事件 |
鼠标消息的记忆,有一定的规则,“WM_”为消息的标识,“L”为left,代表左键,“M”为middle,代表中键, “R”为right,代表右键,NC表示为非客户区域。例如,鼠标右键抬起事件,可以写为:“WM_ R BUTTON UP”,当然正确的写法是“WM_RBUTTONUP”,只是用空格将规则进行区分。部分鼠标消息是有连贯性的,其中包括左键、中键与右键。如果做了一次鼠标左键的点击事件,系统则先触发左键接下(WM_LBUTTONDOWN)事件,再触发左键抬起(WM_LBUTTONUP)事件。
接下来以鼠标左键按下事件为例,讲解鼠标消息在过程处理函数中的处理方法以及各参数的含义。下例是鼠标左键按下时,弹出一个提示框:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
// 鼠标左键按下实例
case WM_LBUTTONDOWN:
MessageBox(hWnd, "鼠标左键被接下。", "提示", MB_OK);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
// 调用系统默认消息处理,即交给系统处理。
return DefWindowProc(hWnd, message, wParam, lParam);
}//end switch
return 0;
}
从事例中不难看出,捕获鼠标消息非常简单。对于此时的过程处理函数,其参数是有一定含义的:
参数hWnd,当前窗口的句柄;
参数message,消息的类型,此处值为WM_LBUTTONDOWN;
参数wParam,存放一个标志,该标志注明了当鼠标左键按下的时,还有什么键同时被按下。如果判断鼠标左键按下的同时按了什么键,可以通过如下方法来验证:
// 鼠标左键按下实例
case WM_LBUTTONDOWN:
if(wParam & MK_CONTROL)
{
MessageBox(hWnd, "Ctrl键同时被按下。", "提示", MB_OK);
}
break;
其中MK_CONTROL为虚拟键值,系统还提供如表4.2所示的虚拟键值。
- 表4.2 鼠标消息中wParam的值
| 值 | 含义 |
| MK_CONTROL | 按下了Ctrl键 |
| MK_LBUTTON | 按下了鼠标左键 |
| MK_MBUTTON | 按下了鼠标中键 |
| MK_RBUTTON | 按下了鼠标右键 |
| MK_SHIFT | 按下了Shift键 |
参数lParam,存放当前光标在窗口中的位置。在获得光标位置时,需要将lParam进行拆分,lParam为四个字节的数值,高位两位代表着鼠标的Y坐标,低两位代表着鼠标的X坐标,如图所示。

- 图4.1 lParam中的坐标
可以通过LOWORD函数与HIWORD函数,分别获得鼠标的X坐标值与Y坐标值,具体写法如下:
xPos = LOWORD(lParam); yPos = HIWORD(lParam);
已经学会了鼠标左键按下消息的捕获与处理,针对于鼠标的其他事件,处理方法相同,所以,这里不过多介绍。接下来,做一个关于鼠标的示例。【例4-1】介绍了如何响应鼠标消息。鼠标移动时,窗口标题显示当前光标在客户区的位置。
//-----------------------------------------------------------------------------
// FUNC : 回调函数
//-----------------------------------------------------------------------------
// IN : hWnd,窗口句柄;
// message,要处理的消息ID,以此来区分消息;
// wParam,消息参数,根据消息的不同内容也有所不同;
// lParam,消息参数,根据消息的不同内容也有所不同。
// OUT : void
// RETURN : void
// AUTHOR : 2012-2-6 11:36 Create by lixinghua for functions.
// NOTE : 此函数用于系统消息的处理。
//-----------------------------------------------------------------------------
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
char szBuffer[64] = { 0 }; // 用于存放鼠标位置的缓冲区
int nX, nY; // 存放鼠标的X,Y值
// 消息处理
//
switch (message)
{
// 鼠标移动事件
case WM_MOUSEMOVE:
// 获取X,Y值
nX = LOWORD(lParam);
nY = HIWORD(lParam);
// 格式化到缓冲区
sprintf(szBuffer, "X:%d, Y:%d", nX, nY);
// 设置窗口标题
SetWindowText(hWnd, szBuffer);
break;
// 窗口销毁消息,关闭窗口时响应。
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
// 调用系统默认消息处理,即交给系统处理。
return DefWindowProc(hWnd, message, wParam, lParam);
}//end switch
return 0;
}
首先,需要捕获鼠标的移动事件(捕获WM_MOUSEMOVE消息);其次,得到鼠标的坐标位置。可以使用LOWORD、HIWORD函数,分别获得X、Y坐标。坐标已经有了,但需要将X、Y的值格式化到字符串中,可以使用sprintf函数。sprintf函数的用法与printf函数的用法相似,printf函数是打印相关的内容到屏幕上,而sprintf函数是结果格式化到它的第一个参数中。sprintf函数的第一个参数是字符串,它要有足够大的空间来存放X、Y坐标值;最后,将存放坐标位置的字符串显示在窗口的标题栏中。SetWindowText函数的功能是设置窗口标题的内容,它的第一个参数是窗口的句柄(将设置窗口的句柄),第二个参数是设置的内容。最终实现结果如图4.2所示。

- 图4.2 鼠标移动实例