当前位置:C++技术网 > 资讯 > 在VC编程中怎样识别三个以上的组合功能键?

在VC编程中怎样识别三个以上的组合功能键?

更新时间:2017-06-30 23:34:15浏览次数:1+次

在VC编程中怎样让电脑识别三个以上的组合功能键?

C++技术网会员解答:

    您好,感谢您对C++技术网的支持与信任。

    组合功能键,意思就是同时按下几个按键时触发的按键消息,比如Ctrl+Alt+Shift会启动系统的任务管理器。一般使用很多的组合键还有Ctrl+C、Ctrl+V等等。

    组合键的原理就是,当一个按键按下时,同时知道其他按键的状态,如果其他几个键也同时按下了,就执行一个功能。这个也可以叫做组合快捷功能键。

    按照组合键的原理,我们一般有两种方式来判断。

1.按下一个键时检测之前或者同时是否有按键同时按下

     当我们检测到字母C键被按下时,是WM_KEYDOWN消息或者WM_CHAR产生了。我们此时要判断是否同时按下了CTRL键,我们只需要检测在按下C键之前是否已经按下了CTRL键。一般的逻辑是,如果直接按下C键表示键入字母c,如果先按下CTRL键再按下C键,就表示组合键CTRL+C,表示复制的意思。所以,在检测到C键按下时,我们就需要检测此前CTRL按键的状态。那么是依据什么原理检测的呢?

    实际上,键盘消息都是一系列的消息流,按照先后顺序依次投递到消息队列的。队列中自然知道多个按键消息之前的先后顺序,所以在检测到C键按下时自然就可以判断C键按下消息之前的按键是不是CTRL键了。

    而获取C键之前按下的键的API函数是:GetKeyState。函数的一个参数就是虚拟按键键码,Shift键时VK_SHIFT、CTRL键是VK_CTRL。其他按键,在VS中右击其中一个VK_宏的定义,查看定义,然后会跳转到定义头文件,里面有所有的虚拟键码宏定义,通过名字就可以和按键对上号。其中ALT键叫做菜单键,虚拟键码宏为VK_MENU。如果有左右两个按键,在VK_后面可以通过L或R字母区分,如果不加这两个字母,表示同时检测两边的按键。比如VK_LSHIFT表示左边的SHIFT按键。

int stat = GetKeyState(VK_SHIFT);

    函数的用法示例如上,如果返回值为负数表示SHIFT按键被按下,如果非负表示未按下。

    需要注意的时,GetKeyState只会检测按下当前按键前和此时的消息,所以并不是实时获取指定按键的状态的。所以,你先按下C键再按下前面说的CTRL键,是无效的。因为我们会在C键按下时调用此函数检测CTRL键状态。而CTRL键在C键之后按下,所以不可能检测到,因此无效。你会觉得,那你同时按下CTRL和C键呢?不可能的。因为两个按键在消息队列中总有先后的。而你感觉的同时并且起作用,只不过因为刚好CTRL键是先于C键,只是你感觉是同时而已。

    这个检测原理你需要理解清楚。所以,在一个按键消息里检测另外一个键的状态,不能应用于三个或者三个以上的同时按下的按键组合。因为一个按键按下,只有一个在他前面。假如你通过一系列手段,在多个按键消息中,连续的处理,并得到一个连串的按键序列,并加以判断,也是可以实现的。不过这样就麻烦了。

2.按下一个键时实时检测此时其他按键的状态以确定其他按键是否同时按下了

    第一种方法不仅不方便实现三个和三个以上按键的组合,而且使用的场合还比较有限制。因为需要检测连续的按键状态,一般就是在一个按键按下时进行检测。不过,不一定需要此时调用GetKeyState就是按键消息处理函数,不过一定是根据当前处理的消息来进行消息序列检测的。无论如何,都需要检测消息的序列。

    所以这里我们就有了新的检测函数,即实时检测按键的状态。如果你的按键一直处于按下的时候,调用这个函数检测可以立马得到检测结果就是按下的。同时还可以检测其他的按键,而不依赖与按键的消息顺序。

    这个函数就是GetAsyncKeyState,函数的参数和用法和GetKeyState差不多。如键已被按过,则返回值的位0设为1;否则设为0。如键目前处于按下状态,则位15设为1;我们可以通过位于来判断是按过还是正在处于按下状态。如:


int stat = GetAsyncKeyState(VK_SHIFT);
bool is_pressed = stat & 0x0001;  //如果为真,表示按下过
bool is_pressing = stat & 0x8000;  //如果为真,表示正处于按下状态,展开为二进制来数,最高的一位就是15位


    按下过表示需要每次在检测C键之前,都要重新按一下CTRL键。处于按下状态则只需要一直按着CTRL,可以连续按多次C键就可以实现多次复制。这两者是有区别的,请体会。

    而如果我们想要检测多个组合键,一般就都用处在按下状态来检测。当多个按键同时处于按下状态时,就触发了。

    所以,我们可以这样来检测CTRL+ALT+SHIFT:


bool is_shift = GetAsyncKeyState(VK_SHIFT) & 0x8000; 
bool is_ctrl = GetAsyncKeyState(VK_CTRL) & 0x8000; 
bool is_alt = GetAsyncKeyState(VK_MENU) & 0x8000; 
if(is_shift && is_ctrl && is_alt  ) 
    .....  //此处执行检测成功代码


    基于此,你还可以检测更多的多建组合,原理都是一样的。所以,你可以同时检测A、B和CTRL键的组合:


if((GetAsyncKeyState(''''B'''')&0x8000) &&(GetAsyncKeyState(''''A'''')&0x8000) && (GetAsyncKeyState( VK_CONTROL )&0x8000) )
    .....  //此处执行检测成功代码


    字母直接用字符就行。所以,你可以使用很多个按键组合了哦。

    补充一下,下面一句也是可以检测按下的:

if((GetKeyState(''''B'''')&0x8000) &&(GetKeyState(''''A'''')&0x8000) && (GetKeyState( VK_CONTROL )&0x8000) )
    ...//执行检测成功代码
    不信你可以试试。

    那么在VC即MFC中,我们可以这样来处理:


BOOL CXXXDlg::PreTranslateMessage(MSG* pMsg)
{
    // TODO: 在此添加专用代码和/或调用基类
    char nChar = pMsg->wParam;
    CString str;
    if((GetAsyncKeyState(''''B'''')&0x8000) &&(GetAsyncKeyState(''''A'''')&0x8000) && (GetAsyncKeyState( VK_CONTROL )&0x8000) )
    {
        str.Format(_T("B +A+ + CTRL"),nChar);
        AfxMessageBox(str);
    }
    return CDialogEx::PreTranslateMessage(pMsg);
}

   而在win32中,我们一样可以在TranslateMessage之前来处理。方法是一样的,MFC只是封装了win32。