当前位置:C++技术网 > 资讯 > [Win32] 如何实现热键控制按键功能

[Win32] 如何实现热键控制按键功能

更新时间:2017-03-11 13:21:21浏览次数:1+次

    热键功能:

    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++类设计,你忽略了传参的一种常用做法,那就是全局变量。而且全局变量是非常高效的传参手段,不过一般情况是不建议使用的,特殊情况,像这样没有其他办法的时候,那就可以用。在类中获取全局变量的值得到参数。

    这是一个大致的思路,供你参考,具体细节还需要你一步步的实现。