1. 鼠标的基础知识:
1) 一般Windows程序会为程序窗口中的每个按钮都分配一个键盘快捷键,但是鼠标的便利还是无法逾越的;
2) 双键鼠标的右键:一般用于打开一些特殊的菜单(即上下文菜单)或执行一些特殊的拖动,而上下文菜单就是指在普通菜单栏之外的窗口中的菜单;
3) 查看鼠标是否接上或者鼠标上一共有几个键:
GetSystemMetrics( SM_MOUSEPRESENT ); // 接上为TRUE否则为FALSE
GetSystemMetrics( SM_CMOUSEBUTTONS ); // 返回鼠标上键的个数,如果鼠标没接上则返回0
4) 鼠标指针及热点:
i) 鼠标指针指图像显示器上显示的一个鼠标的位图小图标;
ii) 热点是指该小图标上的一个但像素精度的点,真正指示了鼠标的位置;
iii) IDI_ARROW的热点是箭头顶点,IDI_CROSS的热点是十字中点;
5) 对鼠标的三种操作:
i) 单击:按下按钮然后松开;
ii) 双击:连续两次快速单击(中间时间间隔要小,该时间可以设定);
iii) 拖动:按下按钮不放,并移动鼠标;
2. 客户区鼠标消息:
1) Windows定义了21种鼠标消息,但是只有10种和客户区有关,其余11种应用程序经常忽略都交由DefWindowProc自动处理;
2) 鼠标消息和键盘消息的一个不同之处在于,键盘消息只有输入焦点才能接受,但是当鼠标经过窗口或者在窗口内击中即使该窗口不是焦点也会收到鼠标消息;
3) 罗列10种客户区鼠标消息,第一种是WM_MOUSEMOVE,当鼠标在窗口中移动时就会受到该消息(不管其是不是焦点窗口):
!!!注意:只有当wndclass.style里加了CS_DBLCLKS选项时才可以接受双键消息!
4) lParam:LOWORD中存放x坐标,HIWORD中存放y坐标;
5) wParam:存放此时鼠标的附加状态,以MK_为前缀的位掩码表示(检测的时候用位与&),表示Mouse Key,即鼠标键,有:
MK_LBUTTON: 按下了左键
MK_RBUTTON:按下了右键
MK_MBUTTON:按下了中键
MK_SHIFT:按下了Shift键
MK_CONTROL:按下了Ctrl键
6) 利用鼠标击键改变当前活动窗口:通过鼠标左击可以将非活动窗口变为活动窗口,即当窗口收到WM_LBUTTONDOWN消息时就可以安全的保证该窗口是活动窗口了;
介绍一种特殊情况,先在一个窗口左击,按下后拖到另一个窗口再释放,则第一个窗口会收到WM_LBUTTONDOWN消息但收不到WM_LBUTTONUP消息,但第二个窗口刚好相反,但是第一个窗口仍然是活动窗口(因为第一个窗口收到了WM_LBUTTONDOWN消息但是第二个没有);
7) 两个特殊的例外:
i) 捕获鼠标:即鼠标位于窗口之外也能捕获其鼠标消息(捕获技术后面会将);
ii) 模态对话框:当一个模块对话框被启动后其它任何程序都不能接受鼠标消息,必须现处理模态对话框并关闭后才能恢复正常;
8) 延时:系统不会为每个鼠标经过的像素都产生WM_MOUSEMOVE消息,具体产生多少个这样的消息取决于过程处理的速度,接下来的程序Connect将展示这一特性,程序为鼠标一次拖动所经过的所有位置两两之间连上线,你会发现如果拖动的慢几乎整个凸包(由鼠标经过的位置形成)多会被填充上黑色,但是如果拖动的快就会看出明显的连线痕迹,因为拖动慢则就能及时处理鼠标消息导致鼠标经过的每个像素都来得及处理,而拖动快则过程来不及处理每个经过的像素;
事实上Windows这样处理WM_MOUSEMOVE消息,消息队列中只能有一个WM_MOUSEMOVE消息,只要该消息没被处理就不会再向队列中假如WM_MOUSEMOVE消息了,所以能处理多少个WM_MOUSEMOVE消息取决于处理速度:
// connect.c
#include <windows.h>
// 追踪轨迹的最大点个数
// 拖动时间太长,轨迹太长的太耗内存
#define CMAXPOINTS 1000
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow )
{
static TCHAR szAppName[] = TEXT("connect");
WNDCLASS wndclass;
HWND hWnd;
MSG msg;
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_A