热键功能:
1. 按下键盘上的Shift键,Windows 内就要一直按住Shift键。
2. 再次按下键盘上的Shift键,Windows 内就要松开Shift键。
分析:
1. 这是一个热键功能,通常来说,用 RegisterHotKey() 函数这个方法是行不通的,因为一旦使用了,会导致用其他软件时,出现无法打字现象,例如记事本。
2. 这里可能需要一个底层的键盘钩子,所以需要用到 SetWindowsHookEx() 函数。
3. SetWindowsHookEx() 函数有个缺点,就是回调函数中,没有自定义的参数,所以会导致无法用 C++ 的 class 来设计。
4. 按键可以使用 keybd_event() 函数实现。
方案:
1. 在键盘钩子的回调函数中,如果收到Shift键的键代码,就要立即调用 keybd_event() 函数,按住Shift键。
2. 然后用一个全局标志位来屏蔽接收Shift键的键代码,下次收到Shift键的键代码,就立即换回给系统来处理。
3. 那么下次我该如何分辨我是在键盘上按下Shift键。
4. 然后就思想卡壳了。
问题:
1. keybd_event() 函数好像只是按了一次Shift键,我没写弹起按键的代码,它也自动弹起来了。
2. 如方案所述,思想卡壳了。
最后感谢C++技术网的回答。
C++技术网会员解答:
你好,这个问题理解的不到位,才没有很快解答。通过QQ的沟通,清楚了问题。
感谢对C++技术网的信任与支持。
经过QQ沟通后,我对问题比较清楚了,总结一下问题:
使用Windows的热键功能,按下Shift键之后,系统可以保持这个按键按下的状态。而如果你使用软件模拟,结果发现按键按下之后,立马又会弹起,也就起不到保持按下的状态。然后你想使用软件来完全模拟热键的启动和关闭。
模拟按键你选择了keybd_event()。
keybd_event函数功能:该函数合成一次击键事件。系统可使用这种合成的击键事件来产生WM_KEYUP或WM_KEYDOWN消息。
函数原型;
VOID keybd_event(BYTE bVk,BYTE bScan,DWORD dwFlags,DWORD dwExtralnfo);
参数:bVk:定义一个虚拟键码。键码值必须在1~254之间。
bScan:定义该键的硬件扫描码。
dwFlags:定义函数操作的各个方面的一个标志位集。应用程序可使用如下一些预定义常数的组合设置标志位。
KEYEVENTF_EXTENDEDKEY:若指定该值,则扫描码前一个值为OXEO(224)的前缀字节。
KEYEVENTF_KEYUP:若指定该值,该键将被释放;若未指定该值,该键将被按下。
dwExtralnfo:定义与击键相关的附加的32位值。
返回值:该函数无返回值。
你在键盘钩子的回调函数中如果使用keybd_event函数,你可以设置一个全局变量,表示这个按键是你通过模拟按下的还是系统处理后按下的【按键来源】。你还设置了一个全局变量用来切换热键启动和停止【热键状态】。但是这个热键状态切换变量只由你自己的函数控制。
在回调函数中,根据热键状态来执行切换【热键状态】,并且设置【按键来源】是模拟来源。在上层,如果发现按键来源是系统,则屏蔽。如果发现按键来源是模拟,则交给系统来真正切换热键状态。
keybd_event() 是一次按键的模拟组合。你可以通过多次的按键,组合形成一个击键事件。你如果不想要弹起,就不要加入弹起的组合。参考代码:
#include<afx.h>
#include<WinUser.h>
#include<Windows.h>
voidmain()
{
Sleep(3000);
keybd_event(16,0,0,0);//按下Shift键
keybd_event(''''A'''',0,0,0);//按下a键
keybd_event(''''A'''',0,KEYEVENTF_KEYUP,0);//松开a键
keybd_event(16,0,KEYEVENTF_KEYUP,0);//松开Shift键
//构成组合键---->按下Shift的同时按下a,形成A
}
而你这个是模拟出来的按键消息,并不会真的有按键消息,一些函数可能获取不到真正的状态,不过没有太大关系,只要你需要的地方能够得到这个消息就行。
至于你说回调函数中没有自定义参数,所以导致你无法使用C++类设计,你忽略了传参的一种常用做法,那就是全局变量。而且全局变量是非常高效的传参手段,不过一般情况是不建议使用的,特殊情况,像这样没有其他办法的时候,那就可以用。在类中获取全局变量的值得到参数。
这是一个大致的思路,供你参考,具体细节还需要你一步步的实现。