当前位置:C++技术网 > 精选软件 > 怎么判断按键当前是否处于长按按键状态

怎么判断按键当前是否处于长按按键状态

更新时间:2016-01-06 23:32:02浏览次数:1+次

    我们在实现长按删除全部字符的时候,实现了长按的功能,你可以阅读《win32长按退格键删除全部文字的功能实现》。然而,如果我们要想知道当前得到的WM_KEYDOWN消息是不是还是长按按键产生的,只通过检测重复计数是不准确的。因为当重复计数的消息被处理之后,重复计数就为1了,就无法判断是否是长按的情况。还有一种情况,如果重复速度比较慢,而我们程序处理的很快,即使我们是长按按键的状态,也无法完成长按按键删除的功能。
    以上的情况确实存在的。之前我实现长按删除效果,是使用了延迟。假如你的程序本来就处理的很快,无法累计重复计数,也就无法完成长按删除的效果了。
    所以,我们通过键的先前状态就可以来判定了,不用依赖于重复计数了。

    下面是使用测试代码的运行截图:

长按后通过键的先前状态检测到长按按键了

【长按后通过键的先前状态检测到长按按键了】
    从图中提示的文字已经看到了长按。至于长按删除功能,就不再说了,你可以自己应用上去,替换掉重复计数的判断。
    我们检测键的先前状态,如果之前按键是按下的状态,这个位为1,否则为0。WM_KEYDOWN或者WM_SYSKEYDOWN的lParam参数的最高位的下一个位,即高31位,就是指示这个状态。所以,我们要提取这个位的值,即可判断这个状态了。这个提取方法的分析,在文章《键盘的扩展键有哪些,用程序检测提取扩展键》已经讲述,只是我们提取的位置不一样而已。通过展开一个字节的8各位,最高的下一个位为1,其他位为0,即01000000,换成十六进制位0x40。
    所以提取的代码为:
BYTE btHiByte = HIBYTE(HIWORD(lParam));
bool bIsBeforeDown = btHiByte&0x40;//之前是否为按下状态
    并将提取的结果存入一个布尔变量。如果为true则表示之前的状态是被按下的,否则之前的状态就是弹起的。如果之前的状态是按下的,我们在WM_KEYDOWN或者WM_SYSKEYDOWN消息中处理按键按下的消息,也就意味着这个按键是长按的状态,就可以执行我们的长按删除功能了。
    下面是完整的检测长按状态的代码:
#include "windows.h"
#include <tchar.h>
#define MAX 100
TCHAR tip[MAX]=_T("");

// - 项目是Unicode字符集
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    switch (message)
    {
        case WM_PAINT:
            hdc = BeginPaint(hwnd,&ps);
            TextOut(hdc,0,0,tip,lstrlen(tip));
            EndPaint(hwnd,&ps);
            return 0;
        case WM_KEYDOWN:
            {
                BYTE btHiByte = HIBYTE(HIWORD(lParam));
                bool bIsBeforeDown = btHiByte&0x40;//之前是否为按下状态
                if (bIsBeforeDown)
                {
                    wsprintf(tip,_T("此键先前是按下的,执行全部删除操作"));
                }
                else
                {
                    wsprintf(tip,_T("此键先前是弹起的"));
                }

                InvalidateRect(hwnd,NULL,TRUE);
                return 0;
            }
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        default:
        break;//跳出到默认处理
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrev,LPSTR lpCmd,int iShow)
{
    TCHAR ClassName[] = _T("MyClass");
    TCHAR title1[] = _T("C++技术网http://www.cjjjs.com");
    WNDCLASS wndClass;
    wndClass.cbClsExtra=0;
    wndClass.cbWndExtra=0;
    wndClass.hbrBackground= (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndClass.hCursor=LoadCursor(NULL,IDC_HAND);
    wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
    wndClass.hInstance = hInstance;
    wndClass.lpfnWndProc = WinProc;
    wndClass.lpszClassName = ClassName;
    wndClass.lpszMenuName=NULL;
    wndClass.style=CS_HREDRAW|CS_VREDRAW;

    if(!RegisterClass(&wndClass))return 0;
    HWND hwnd = CreateWindow(ClassName,title1,WS_OVERLAPPEDWINDOW,0,0,650,400,NULL,NULL,hInstance,NULL);
    ShowWindow(hwnd,SW_SHOWNORMAL);

    MSG msg;
    while (GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}