下面这些操作,一定要看官方文档,这样能少走很多弯路。
虚拟键码
// 获取鼠标位置
POINT p;
GetCursorPos(&p);
qDebug() << "cur mouse:" << p.x << "," << p.y;
// 判断鼠标左键是否被按下
if((GetAsyncKeyState(VK_LBUTTON)& 0x8000)? 1:0){
qDebug()<<"lbutton down";
}
// 判断 K 是否被按下
if((GetAsyncKeyState(0x4B)& 0x8000)? 1:0){
qDebug()<<"k down";
}
GetAsyncKeyState就是检查在调用该函数时,某一key的状态。而GetKeyState是检查window message发生时,某一key的状态。
如果在MSG产生的时候,Ctrl是没有按下的;而在调用GetAsyncKeyState的那一刻,Ctrl是按下的。那么GetAsyncKeyState会通知你Ctrl是按下的。反之通知你Ctrl是没有按下的。
如果在MSG产生的时候,Ctrl是按下的,那么GetKeyState会通知你Ctrl是按下的。反之通知你Ctrl是没有按下的。与调用GetKeyState那一刻Ctrl的状态是没有关系的。
MapVirtualKeyW,该函数可用于虚拟键码和扫描码之间的转换
// 返回结果为翻译结果
UINT WINAPI MapVirtualKeyW(
_In_ UINT uCode, // 扫描码或虚拟键码
// 0: 虚拟键码->扫描码
// 1: 扫描码->虚拟键码
_In_ UINT uMapType
);
扫描码:键盘硬件对应的按键的编码;虚拟键码:操作系统对应的按键的编码;
当用户按下某个按键时:
1)键盘会检测到这个动作,并通过键盘控制器把扫描码(scan code) 传送到计算机; 键盘扫描码跟具体的硬件有关的,不同厂商对同一个键的扫描码有可能不同。
2)计算机接收到 扫描码 后,将其交给键盘驱动程序;
3)键盘驱动程序 把这个 扫描码转换为键盘虚拟码;虚拟码与具体硬件无关,不同厂商的键盘,同一个键的虚拟码总是相同的。
4)然后,键盘驱动程序 把该键盘操作的 扫描码和虚拟码以及其它信息传递给 操作系统;操作系统将获得 的信息封装在一个键盘消息中,并把该键盘消息插入到消息列队。
5)通过Windows的消息系统,该键盘消息被送到某个窗口中;
6)窗口所在的应用程序接收到消息后,可以了解到有关 键盘操作的信息,然后决定作出一定的响应。
我使用SendInput没成功,所以大家如果想用它的话,请参考官方文档。我这里介绍 mouse_event 和 keybd_event 两个函数来实现相应的操作
官方文档
void mouse_event(
[in] DWORD dwFlags, // 操作类型
[in] DWORD dx, // 相对或绝对的移动量
[in] DWORD dy, // 相对或绝对的移动量
[in] DWORD dwData, // 如果有滚轮事件则代表滚轮的变化量,可正负,一圈为120(WHEEL_DELTA),如果没有滚轮事件,该值应当设为0
[in] ULONG_PTR dwExtraInfo // 给0就行
);
可用的操作类型参考官方文档,里面写的很详细,这里提供简单的案例。
// 模拟鼠标左键
mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);
Sleep(50);
mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0);
官方文档
虚拟键码
这里只提供简单的案例,具体的事件课填什么请参考官方文档
void keybd_event(
[in] BYTE bVk, // 虚拟键码
[in] BYTE bScan, // 一般设置为0即可,可以用 MapVirtualKeyW(虚拟键码值,0)得到
[in] DWORD dwFlags, // 具体的事件,0代表按下,KEYEVENTF_KEYUP代表松开
[in] ULONG_PTR dwExtraInfo // 一般设置为0即可
);
// 模拟按键K
keybd_event(0x4B,MapVirtualKeyW(0x4B,0),0,0); // 按下
Sleep(50);
keybd_event(0x4B,MapVirtualKeyW(0x4B,0),KEYEVENTF_KEYUP,0); // 抬起
写这篇文章的时候,我已经走了很多弯路,所以为让大家少走弯路,我把这些经验总结了一下,有许多内容是来自官方文档或者别的博客,由于看的内容比较碎,我也忘了是来源于哪个博客了,感谢各位博主的探索。