函数功能:keybd_event函数模拟一次击键事件。系统可使用这种模拟的击键事件来产生WM_KEYUP或WM_KEYDOWN消息,键盘驱动程序的中断处理程序调用keybd_event函数。在Windows NT中该函数己被使用SendInput来替代它完成操作。
函数原型;VOID keybd_event(BYTE bVk,BYTE bScan,DWORD dwFlags,DWORD dwExtralnfo);
函数参数:
bVk:定义一个虚拟键码,键码值必须在1~254之间。
bScan:定义该键的硬件扫描码。
dwFlags:定义函数操作的各个方面的一个标志位集。应用程序可使用如下一些预定义常数的组合设置标志位:
dwExtralnfo:定义与击键相关的附加的32位值。
返回值:该函数无返回值。
#include<afx.h>
#include<WinUser.h>
#include<Windows.h>
voidmain()
{
keybd_event(16,0,0,0); // 按下Shift键
keybd_event('A',0,0,0); // 按下a键
Sleep(100);
keybd_event('A',0,KEYEVENTF_KEYUP,0);// 松开a键
keybd_event(16,0,KEYEVENTF_KEYUP,0);// 松开Shift键
// 构成组合键---->按下Shift的同时按下a,形成A
}
尽管keybd_event函数传递一个与OEM相关的硬件扫描码给系统,但应用程序不能用此扫描码。系统在内部将扫描码转换成虚拟键码,并且在传送给应用程序前清除键码的UP/DOWN位。应用程序可以摸拟PRINTSCREEN键的按下来获得一个屏幕快照,并把它存放到剪切板中。若要做到这一点,则要将keybd_event的bVk参数置为VK_SNAPSHOT,bScan参数置为0(用以获得全屏快照)或hScan置为1(仅获得活动窗口的快照)。
Windows CE:WindowsCE支持dwFlags参数附加的标志位,即使用KEYEVENTF_SILENT标志模拟击键,而不产生敲击的声音。
Windows CE不支持KEYEVENTF_EXTENDEDKEY标志。
速查:Windows NT:3.1及以上版本;Windows:95及以上版本 ;Windows CE:1.0及以上版本;头文件:winuser.h;库文件:user32.lib。
Windows提供了一个模拟键盘操作的API函数keybd_event(),使用该函数可以模拟相应的键盘动作。keybd_event()函数能触发一个按键事件,也就是说会产生一个WM_KEYDOWN或WM_KEYUP消息。该函数原型如下:
VOID keybd_event(
BYTE bVk, // virtual-key code
BYTE bScan, // hardware scan code
DWORD dwFlags, // flags specifying various function options
DWORD dwExtraInfo // additional data associated with keystroke);
从原型可以看出,keybd_event ()共有四个参数:
bVk:按键虚拟键值,如回车键为vk_return,Tab键为vk_tab;
bScan:为扫描码,一般不用设置,用0代替就行;
dwFlags:为选项标志,如果为keydown则置0即可,如果为keyup则设成"KEYEVENTF_KEYUP";
dwExtraInfo:一般置0即可。
// 例子1:模拟按下'A'键
keybd_event(65,0,0,0);
keybd_event(65,0,KEYEVENTF_KEYUP,0);
// 例子2:模拟按下'ALT+F4'键
keybd_event(18,0,0,0);
keybd_event(115,0,0,0);
keybd_event(115,0,KEYEVENTF_KEYUP,0);
keybd_event(18,0,KEYEVENTF_KEYUP,0);
模拟键盘平时不是很常用,但是当调用某些快捷键执行某项功能时,它真的是那么的方便,看看下面的实现。
1. 显示桌面
很多软件有显示桌面的功能,并且大家的方法都是遍历窗口,然后让它们最小化,其实Windows系统给了一个非常方便的WIN键(就是键盘上在CTRL键和ALT键之间的那个带win标志的按键)。利用它可以轻松的完成显示桌面的功能。
// 显示桌面
keybd_event(VK_LWIN, 0, 0 ,0);
keybd_event('M', 0, 0 ,0);
keybd_event('M', 0, KEYEVENTF_KEYUP ,0);
keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP,0);
其他的操作也类似,比如直接显示“开始”的运行,就把上面的'M'换成'R'即可。
// 显示开始运行
keybd_event(VK_LWIN, 0, 0 ,0);
keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP,0);
直接显示“开始”对话框了。
2. 实现快速全选
很多的时候,比如listctrl实现全选,你可以用listctrl循环设置每一项的状态为选中,多啰嗦的事情。用快捷键试一试CTRL+A,其他的快捷键一样的用法。
keybd_event(VK_CONTROL, (BYTE)0, 0 ,0);
keybd_event('A',(BYTE)0, 0 ,0); //此处可以用 'A', (BYTE)65, 用'a'不起作用.
keybd_event('A', (BYTE)0, KEYEVENTF_KEYUP,0);
keybd_event(VK_CONTROL, (BYTE)0, KEYEVENTF_KEYUP,0);
3. 执行某些特殊键,比如数字键,大小写键
bool bState=true; // true为按下NumLock,false反之
BYTE keyState[256];
GetKeyboardState((LPBYTE)&keyState);
if( (bState && !(keyState[VK_NUMLOCK] & 1)) ||
(!bState && (keyState[VK_NUMLOCK] & 1)) )
{
// Simulate a key press
keybd_event( VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY | 0, 0 );
// Simulate a key release
keybd_event( VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
4. 实现CTRL+ALT+DELETE三键一起按下
keybd_event(VK_CONTROL, 0, 0 ,0);
keybd_event(VK_MENU,0, 0 ,0);
keybd_event(VK_DELETE,0, 0 ,0);
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP ,0);
keybd_event(VK_MENU,0, KEYEVENTF_KEYUP ,0);
keybd_event(VK_DELETE,0, KEYEVENTF_KEYUP ,0);
这样不会成功,因为这几个键是操作系统直接截获执行的,而模拟键盘只能发向应用程序,所以这种方法不行的(想显示锁定对话框,用LockWorkStation();)
5. Window2000/NT/XP已经不提倡用这个函数了,上面的方法只是为了让大家开阔一下思路,怎么替代?
// Window2000/NT/XP下用这个代替,包含"winable.h"
INPUT input[4];
memset(input, 0, sizeof(input));
input[0].type = input[1].type = input[2].type = input[3].type = INPUT_KEYBOARD;
input[0].ki.wVk = input[3].ki.wVk = VK_LWIN;
input[1].ki.wVk = input[2].ki.wVk = 'R';
//接下来释放它,这一点很重要。
input[2].ki.dwFlags = input[3].ki.dwFlags = KEYEVENTF_KEYUP;
input[0].ki.time = input[1].ki.time = input[2].ki.time = input[3].ki.time = GetTickCount();
SendInput(4, input, sizeof(INPUT));
感觉比那个有点啰嗦。
WIN键+D=快速的切到桌面,再次点击返回;
WIN键+E=快速打开资源管理器;
WIN键+R=“运行”;
WIN键+M=全部视窗最小化;
WIN键+Shift+M=取消全部视窗最小化;
WIN键+F1=Help;
WIN键+F=“寻找”;
WIN键+Ctrl+F=显示“查找电脑”;
WIN键+Tab=切换工作列的程式;
WIN键+Break=显示系统内容。
首先你会发现keybd_event函数中是没有窗口句柄作为参数的,那是因为keybd_event是全局模拟按键的,只对前台窗口(即当前的活动窗口)才可以,但是如果模拟的按键正好也是某个窗口的全局热键消息,那该窗口也能接收到的。
而SendMessage、PostMessage是对指定句柄窗口都起作用的,对于做一些外挂是非常有用的。例如可以做成这样的效果:即用SendMessage/PostMessage在某一个窗口模拟动作,而同时自己可以在其他窗口做其他事情,互不影响!
但是有一点要注意,很多人在模拟键盘消息的时候,都会忘记模拟WM_KEYUP的消息。
还有一点就是PostMessage中的窗口句柄参数,可以设置为HWND_BROADCAST,即广播,但不要理所当然地认为是对所有的窗口都起作用。它只对系统的顶层窗口起作用,子窗口是收不到这个消息的!
还要注意的是SendMessage是没有HWND_BROADCAST参数的,那是因为,SendMessage总是等发送的消息在对应的窗口消息队列中处理完毕后才返回的(这是一种负责的行为),细想一下就知道为什么SendMessage没有HWND_BROADCAST参数了!
个人认为:
// 实例
SendMessage(Button.Handle, WM_LBUTTONDOWN, 0, 0); //鼠标左键按下
SendMessage(Button.Handle, WM_LBUTTONUP, 0, 0); //鼠标左键抬起
SendMessage(Edit.Handle, WM_SETTEXT, 255, Integer(PChar('abc'))); //传递文本
SendMessage(Edit.Handle, WM_Char, Wparam('Q'), 2); // 传递字符
SendMessage(Button.Handle, BM_SETSTYLE, BS_RADIOBUTTON, 1); //改变Button风格
SendMessage(ComboBox.Handle, CB_SETDROPPEDWIDTH, 300, 0); //改变CBDownWidth
WM_CUT、WM_COPY和WM_PASTE剪切,复制,粘帖
实现任意组合键:
keybd_event(VK_Control, MapVirtualKey(VK_Control, 0), 0, 0);
keybd_event(ord('V'), MapVirtualKey(ord('V'), 0), 0, 0);
keybd_event(ord('V'), MapVirtualKey(ord('V'), 0), KEYEVENTF_KEYUP, 0);
keybd_event(VK_Control, MapVirtualKey(VK_Control, 0), KEYEVENTF_KEYUP, 0);
模拟鼠标按下事件:
::PostMessage(hwd0,WM_MOUSEMOVE, MK_LBUTTON, MAKELONG(x,y));
::PostMessage(hwd0,WM_LBUTTONDOWN,MK_LBUTTON,MAKELPARAM(x,y));
::PostMessage(hwd0,WM_LBUTTONUP,MK_LBUTTON,MAKELPARAM(x,y));
模拟键盘按下事件
keybd_event(VK_TAB,0,0,0);
keybd_event(VK_TAB,0,KEYEVENTF_KEYUP,0);