特殊说明:版权归个人所有,请勿转载,谢谢合作。
鼠标及键盘作为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 鼠标移动实例