kaixuan1115 / notes

笔记收录
6 stars 0 forks source link

不依赖的 DLL 的全局钩子编写 #11

Closed xiaokaixuan closed 5 years ago

xiaokaixuan commented 5 years ago

在 VC 中捕按键可以在 OnKeyDown 或 OnKeyUp 事件中进行捕获,不过这有很大的局限性,这里只能捕获用户按键。但在一些特殊的工程(项目)中往往需要捕获某些系统按键以完成特殊的功能,我们就不得不选择钩子了,一般情况下 大家都会选择 WH_KEYBOARD 这个钩子类型,但是在编写过程会发现这个钩子类型并不能捕获所有的系统按键,怎么办呢?那就得选择WH_KEYBOARD_LL (低级键盘钩子)了,使用它可以捕获全部的系统按键,一个不漏…… 在使用低级键盘钩子之前,先在 StdAfx.h 的第一行添加一条: #define _WIN32_WINNT 0x400 (这里假定你是用的 MFC 的 DLL),不然在编译的时候会提示说 WH_KEYBOARD_LL 没有定义。

网上还有另一种方法: 首先定义 #define WH_KEYBOARD_LL 13 然后 Winuser.h 中定义的 tagKBDLLHOOKSTRUCT 代码拷贝到工程中。 下面代码用以捕获系统按键:

/*
用户模块
return TRUE; --->丢弃该消息
*/
LRESULT CALLBACK LowLevelKeyboardProc(
    int nCode, // hook code
    WPARAM wParam, // message identifier
    LPARAM lParam // message data
)
{
    PKBDLLHOOKSTRUCT pm = NULL;
    if (nCode == HC_ACTION)
    {
        pm = (PKBDLLHOOKSTRUCT)lParam;
        switch(pm->vkCode)
        {
        //屏蔽 win 键
        case VK_LWIN:
        case VK_RWIN:
            return 1;
            break;
        //屏蔽 alt+tab
        case VK_TAB:
            if(pm->flags & LLKHF_ALTDOWN)
            {
                return 1;
            }
            break;
        //屏蔽 esc alt+esc ctrl+esc
        case VK_ESCAPE:
            return 1;
            break;
        //屏蔽 ALT+F4
        case VK_F4:
            if(pm->flags & LLKHF_ALTDOWN)
            {
                return 1;
            }
            break;
        //屏蔽 F1
        case VK_F1:
            return 1;
            break;
        //屏蔽 CTRL+ALT+DEL
        case VK_DELETE:
            if(pm->flags & LLKHF_ALTDOWN)
            {
                if (GetKeyState(VK_CONTROL) < 0)
                {
                    return 1;
                }
            }
            break;
        default:
            break;
        }
    }
    // if (WM_KEYDOWN == wParam || WM_SYSKEYDOWN)
    // //如果按键为按下状态
    // {
    // if (Key_Info->vkCode == VK_LWIN || Key_Info->vkCode == VK_RWIN)
    // //屏敝 WIN(左右) 键
    // {
    //      return TRUE;
    // }
    // if (Key_Info->vkCode == 0x4D && ((GetKeyState(VK_LWIN) & 0x8000) ||
    // (GetKeyState(VK_RWIN) & 0x8000)))
    // //屏敝 WIN+D 组合键(左右)
    // {
    //      return TRUE;
    // }
    // if (Key_Info->vkCode == 0x44 && ((GetKeyState(VK_LWIN) & 0x8000) ||
    // (GetKeyState(VK_LWIN) & 0x8000)))
    // //屏敝 WIN+M 组合键(左右)
    // {
    //      return TRUE;
    // }
    // if (Key_Info->vkCode == 0x1b && GetKeyState(VK_CONTROL) & 0x8000)
    // //屏敝 CTRL + ESC 组合键
    // {
    //      return TRUE;
    // }
    // if  (Key_Info->vkCode  ==  VK_TAB  &&  Key_Info->flags  & LLKHF_ALTDOWN)
    // //屏敝 ATL + TAB 组合键
    // {
    //      return TRUE;
    // }
    // if  (Key_Info->vkCode  ==  VK_ESCAPE  &&  Key_Info->flags  & LLKHF_ALTDOWN)
    // //屏敝 ATL + ESC 组合键
    // {
    //      return TRUE;
    // }
    // if (Key_Info->flags & LLKHF_ALTDOWN)
    // //屏敝 CTRL 键
    // {
    //      return TRUE;
    // }
    return CallNextHookEx(g_hhk, nCode, wParam, lParam);
}
BOOL CTestHookDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    // Set the icon for this dialog. The framework does this automatically
    // when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE); // Set big icon
    SetIcon(m_hIcon, FALSE); // Set small icon
    // TODO: Add extra initialization here
    g_hhk = SetWindowsHookEx(13, LowLevelKeyboardProc, GetModuleHandle(NULL), 0);
    return TRUE; // return TRUE unless you set the focus to a control
}

注意 此钩子必须是系统级的钩子,也就是说在安装钩子的时候,ThreadID 的值必须为 0。 在这儿需要特别说明的是:if (WM_KEYDOWN == wParam || WM_SYSKEYDOWN) ,如果不加这句,按键信息会被响应两次(KeyUP & KeyDown),开始我只写了 if (WM_KEYDOWN == wParam) ,在捕获 ALT+TAB 时就一直出错,找不到方向,后来才想到 ALT 键盘是系统键,所以必须得加上WM_SYSKEYDOWN,这样才能捕获 ALT+TAB !if (WM_KEYDOWN == wParam || WM_SYSKEYDOWN)也可以写成if (WM_KEYDOWN == wParam || WM_SYSKEYDOWN == wParam)如果要想屏敝 CTRL+ALT+DEL 键的话,也可能用相当的方法!不过可以用一种更简单的方法来屏敝 CTRL+ALT+DEL :屏敝这个组合键的其中任意一个按键便可达到相同的效果。