按键Hook(Win32, C++)

73 篇文章 0 订阅

前段时间学习windows 的 HOOK 操作, 编写按键信息打印工具, 于是想着写一个工具类拦截按键并相应自定义的操作, 于是编写了下面这个 按键 HOOK 工具类.

实现的思路就是安装一个全局的按键钩子, 当按下组合键后, 先将拦截到的按键进行处理, 检查是不是我们关心的按键组合, 不是的话原路放行, 否则按照我们自定义的操作进行处理, 比方组合键按下时执行操作A, 按住不放3秒后执行操作B, 组合键弹起执行操作C等等操作, 基本上能满足绝大部分按键操作功能了.

 

CKeyboardHookUtils.h

#pragma once
#include <windows.h>
#include <vector>
#include <string>
#include <functional>
#include <mutex>

#define KEYEVENTF_EXTENDEDKEY       0x0001
#define KEYEVENTF_KEYUP             0x0002
#define KEY_HOOK_HANDLED_FLAG       0x0400
#define KEY_HOOK_TIMER_ID           0x0400

class KBDATA;                                                   //按键状态数据
class HkInfo;                                                   //HOOK信息记录
using KdList = std::vector<KBDATA>;                             //按键状态列表
using KdCb = std::function<void(const HkInfo& Hki)>;            //按键触发回调

#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif

// 按键状态记录数据类
class KBDATA
{
public:
    KBDATA();
    KBDATA(DWORD vk, DWORD sc, DWORD f, DWORD t = 0, ULONG_PTR dwInfo = KEY_HOOK_HANDLED_FLAG);
    bool operator == (const KBDATA& r) const;
    bool operator != (const KBDATA& r) const;

    // 清理数据
    void Clean();

    // 获取按键名
    _tstring GetKeyName() const;

public:
    DWORD vkCode;                           // 虚键码
    DWORD scanCode;                         // 扫描码
    DWORD flags;                            // 标志
    DWORD time;                             // 时间
    ULONG_PTR dwExtraInfo;                  // 额外信息
};

// 发送按键助手类
class SendKeysHelper
{
public:
    enum KeyFlag {
        key_down = 0x01,
        key_up = 0x02,
        key_downup = key_down | key_up
    };
public:
    SendKeysHelper() {};
    ~SendKeysHelper() {};

    // 添加按键
    void PushBack(const KBDATA keyState);

    // 添加按键
    void PushBack(WORD vkCode, WORD scanCode, DWORD flags, DWORD time = 0);

    // 清空
    void Clean(void);

    // 发送按键
    static bool SendKeys(const KBDATA& key, KeyFlag flag = key_downup);

    // 发送按键
    bool SendKeys(KeyFlag flag = key_downup);

    // 发送按键列表
    bool SendKeys(const KdList& keys, KeyFlag flag = key_downup);

private:
    KdList m_inputs;                        // 按键列表
};

// 按键 Hook 信息结构类
class HkInfo
{
public:
    HkInfo();
    HkInfo(const KdList& ModifiersKeys, const KBDATA& ActiveKey);
    bool operator == (const HkInfo& info) const;
    bool IsHolding();
public:
    KdList m_ModifiersKeys;                 // 修饰键
    KBDATA m_ActiveKey;                     // 激活键
    ULONGLONG m_ullDownTime;                // 按下时间
    ULONGLONG m_ullDurationTime;            // 持续时间
};

// 按键 HOOK 回调信息类
class HkCbInfo
{
public:
    HkCbInfo() {};
    HkCbInfo(const KdList& info, const KBDATA& ActiveKey, KdCb cbDown = nullptr, KdCb cbHold = nullptr, KdCb cbUp = nullptr);
    bool operator == (const HkCbInfo& obj) const;

public:
    HkInfo KeyInfo;                          // 组合键记录
    KdCb m_cbDown;                           // 激活回调
    KdCb m_cbUp;                             // 激活回调
    KdCb m_cbHold;                           // 按住回调
};

// 按键 HOOK 类
class CKeyboardHookUtils
{
public:

    // 获取唯一实例
    static CKeyboardHookUtils& Instance();

    // 安装键盘钩子
    bool Install(HWND hWnd = NULL);

    // 卸载键盘钩子
    void Uninstall();

    // 添加按键序列
    bool AddShortcutKeys(KdList modifiersKeys, KBDATA activeKey, KdCb cbDown = nullptr, KdCb cbHold = nullptr, KdCb cbUp = nullptr);

    // 移除按键序列
    bool RemoveShortcutKeys(KdList modifiersKeys, KBDATA activeKey);

    // 移除按键序列
    bool RemoveShortcutKeys(LPCTSTR keysName);

    // 处理定时器事件
    void ProcessTimerEvent(HWND hWnd, UINT_PTR  nIDEvent);

    // 处理消息循环
    void ProcessMessageLoop();

    // 获取当前时间戳(毫秒)
    ULONGLONG GetCurMilliSecond();

private:
    CKeyboardHookUtils();

    ~CKeyboardHookUtils();

    // 获取组合键名字
    _tstring GetKeyListName(const HkInfo& info);

    // 低级键盘钩子过程
    static LRESULT CALLBACK LowLevelKeybdProc(int nCode, WPARAM wParam, LPARAM lParam);

    // 调式打印信息
    void DebugPrintf(WPARAM wParam, LPARAM lParam);

    // 更新按下的修饰键的状态
    void UpdateModifiersKeys(const KBDATA& key, bool isDown);

    // 按键处理过程
    bool ProcessKeybdHook(WPARAM wParam, LPARAM lParam);
    bool KeybdProc(WPARAM wParam, LPARAM lParam);

    // 自定义拦截按键处理
    bool ProcessShortcutKeys(const KBDATA& key);

    // 重置当前组合键状态
    bool ResetShortcutKeys(void);

private:
    static CKeyboardHookUtils m_Instance;   // 静态实例
    std::vector < HkCbInfo > m_HkCbInfos;   // 按键按下 hook 记录(按键序列 与 触发回调函数)
    KdList m_ModifiersKeysDownRecords;      // 当前按下的按键序列缓存
    HHOOK m_hKeyboard;                      // HOOK 句柄
    bool m_isHolding;                       // 组合键按住不放中
    DWORD m_nHoldTimer;                     // 按住定时器
    std::mutex m_opLock;                    // 操作锁
    HWND m_hWnd;                            // 定时器窗口
};

CKeyboardHookUtils.cpp

#include "CKeyboardHookUtils.h"
#include <sys\timeb.h>
#include <tchar.h>

CKeyboardHookUtils CKeyboardHookUtils::m_Instance;

// 按键状态记录数据类
KBDATA::KBDATA() 
    :vkCode(0), 
    scanCode(0),
    flags(0), 
    time(0), 
    dwExtraInfo(0)
{

};

KBDATA::KBDATA(DWORD vk, DWORD sc, DWORD f, DWORD t, ULONG_PTR dwInfo)
    :
    vkCode(vk), 
    scanCode(sc), 
    flags(f), 
    time(t), 
    dwExtraInfo(dwInfo) 
{

};

bool KBDATA::operator == (const KBDATA& r) const
{
    return (vkCode == r.vkCode && scanCode == r.scanCode && (flags & 0x01) == (r.flags & 0x01));
}

bool KBDATA::operator != (const KBDATA& r) const
{
    return !(*this == r);
}

void KBDATA::Clean()
{
    vkCode = 0;
    scanCode = 0;
    flags = 0;
    time = 0;
    dwExtraInfo = 0;
}

_tstring KBDATA::GetKeyName() const
{
    _tstring strName;
    TCHAR szName[MAX_PATH] = { 0 };

    DWORD lparam = scanCode << 16;

    if (flags & 0x80)
    {
        lparam |= 0x80000000;
    }

    if (flags & 0x20)
    {
        lparam |= 0x20000000;
    }

    //扩展
    if (flags & 0x01 && VK_RSHIFT != vkCode)
    {
        lparam |= 0x01000000;
    }

    //获取按键名称
    GetKeyNameText(lparam, szName, _countof(szName));
    strName = szName;

    return strName;
}

// 发送按键助手类
void SendKeysHelper::PushBack(const KBDATA keyState)
{
    m_inputs.push_back(keyState);
}

void SendKeysHelper::PushBack(WORD vkCode, WORD scanCode, DWORD flags, DWORD time)
{
    m_inputs.push_back(KBDATA(vkCode, scanCode, flags, time));
}

bool SendKeysHelper::SendKeys(const KBDATA& key, KeyFlag flag)
{
    static INPUT inputs[0x100] = { 0 };
    UINT nSendCount = 0;

    // 按键按下(序列正向)
    if (KeyFlag::key_down & flag)
    {
        inputs[nSendCount].type = INPUT_KEYBOARD;
        inputs[nSendCount].ki.wVk = key.vkCode;
        inputs[nSendCount].ki.wScan = key.scanCode;
        inputs[nSendCount].ki.dwFlags = key.flags;
        inputs[nSendCount].ki.time = key.time;
        inputs[nSendCount].ki.dwExtraInfo = KEY_HOOK_HANDLED_FLAG;
        nSendCount++;
    }

    if (KeyFlag::key_up & flag)
    {
        inputs[nSendCount].type = INPUT_KEYBOARD;
        inputs[nSendCount].ki.wVk = key.vkCode;
        inputs[nSendCount].ki.wScan = key.scanCode;
        inputs[nSendCount].ki.dwFlags = key.flags | KEYEVENTF_KEYUP;
        inputs[nSendCount].ki.time = key.time;
        inputs[nSendCount].ki.dwExtraInfo = KEY_HOOK_HANDLED_FLAG;
        nSendCount++;
    }

    return nSendCount == SendInput(nSendCount, inputs, sizeof(INPUT));
}

bool SendKeysHelper::SendKeys(KeyFlag flag)
{
    static INPUT inputs[0x100] = { 0 };
    UINT nSendCount = 0;

    if (m_inputs.empty())
    {
        return false;
    }

    // 按键按下(序列正向)
    if (KeyFlag::key_down & flag)
    {
        for (int i = 0; i < m_inputs.size() && i < _countof(inputs); i++)
        {
            inputs[nSendCount].type = INPUT_KEYBOARD;
            inputs[nSendCount].ki.wVk = (WORD)m_inputs[i].vkCode;
            inputs[nSendCount].ki.wScan = (WORD)m_inputs[i].scanCode;
            inputs[nSendCount].ki.dwFlags = m_inputs[i].flags;
            inputs[nSendCount].ki.time = m_inputs[i].time;
            inputs[nSendCount].ki.dwExtraInfo = KEY_HOOK_HANDLED_FLAG;
            nSendCount++;
        }
    }

    if (KeyFlag::key_up & flag)
    {
        for (int i = (int)m_inputs.size() - 1; i >= 0; i--)
        {
            inputs[nSendCount].type = INPUT_KEYBOARD;
            inputs[nSendCount].ki.wVk = (WORD)m_inputs[i].vkCode;
            inputs[nSendCount].ki.wScan = (WORD)m_inputs[i].scanCode;
            inputs[nSendCount].ki.dwFlags = m_inputs[i].flags | KEYEVENTF_KEYUP;
            inputs[nSendCount].ki.time = m_inputs[i].time;
            inputs[nSendCount].ki.dwExtraInfo = KEY_HOOK_HANDLED_FLAG;
            nSendCount++;
        }
    }

    return nSendCount == SendInput(nSendCount, inputs, sizeof(INPUT));
}

bool SendKeysHelper::SendKeys(const KdList& keys, KeyFlag flag)
{
    for (auto& item : keys)
    {
        m_inputs.push_back(item);
    }

    return SendKeys(flag);
}

void SendKeysHelper::Clean(void)
{
    m_inputs.clear();
}

// 按键 Hook 信息结构类
HkInfo::HkInfo()
    : m_ullDownTime(0),
    m_ullDurationTime(0)
{

}

HkInfo::HkInfo(const KdList& ModifiersKeys, const KBDATA& ActiveKey)
    : m_ModifiersKeys(ModifiersKeys),
    m_ActiveKey(ActiveKey),
    m_ullDownTime(0),
    m_ullDurationTime(0)
{

}

bool HkInfo::operator == (const HkInfo& info) const
{
    if (m_ModifiersKeys.size() != info.m_ModifiersKeys.size() || 
        m_ActiveKey != info.m_ActiveKey)
    {
        return false;
    }

    for (int i = 0; i < m_ModifiersKeys.size(); i++)
    {
        if (m_ModifiersKeys[i] != info.m_ModifiersKeys[i])
        {
            return false;
        }
    }

    return true;
}

bool HkInfo::IsHolding()
{
    return 0 != m_ullDownTime;
}

// 按键 HOOK 回调信息类
HkCbInfo::HkCbInfo(const KdList& info, const KBDATA& ActiveKey, KdCb cbDown, KdCb cbHold, KdCb cbUp) :
    KeyInfo(info, ActiveKey), m_cbDown(cbDown), m_cbHold(cbHold), m_cbUp(cbUp)
{

};

bool HkCbInfo::operator == (const HkCbInfo& obj) const
{
    return this->KeyInfo == obj.KeyInfo;
}

CKeyboardHookUtils& CKeyboardHookUtils::Instance()
{
    return m_Instance;
}

CKeyboardHookUtils::CKeyboardHookUtils()
{
    m_hKeyboard = NULL;
    m_isHolding = false;
    m_hWnd = NULL;
    m_nHoldTimer = KEY_HOOK_TIMER_ID;
}

CKeyboardHookUtils::~CKeyboardHookUtils()
{
    Uninstall();
}

void CKeyboardHookUtils::DebugPrintf(WPARAM wParam, LPARAM lParam)
{
    static long count = 0;
    static KBDLLHOOKSTRUCT lastKey = { 0 };
    static long repeatCount = 0;
    ++count;
    KBDLLHOOKSTRUCT& event = *(PKBDLLHOOKSTRUCT)lParam;
    bool keyDown = (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN);
    bool bShitf = GetAsyncKeyState(VK_SHIFT) & 0x8000;
    bool bCtrl = GetAsyncKeyState(VK_CONTROL) & 0x8000;
    bool bAlt = GetAsyncKeyState(VK_MENU) & 0x8000;
    bool bWin = GetAsyncKeyState(VK_LWIN) & 0x8000 || GetAsyncKeyState(VK_RWIN) & 0x8000;
    DWORD dwTime = event.time;

    DWORD lparam = event.scanCode << 16;

    if (event.flags & 0x80)
    {
        lparam |= 0x80000000;
    }

    if (event.flags & 0x20)
    {
        lparam |= 0x20000000;
    }

    //扩展
    if (event.flags & 0x01 && VK_RSHIFT != event.vkCode)
    {
        lparam |= 0x01000000;
    }

    //获取按键名称
    TCHAR szName[MAX_PATH] = { 0 };
    GetKeyNameText(lparam, szName, _countof(szName));

    if (keyDown)
    {
        if (lastKey.vkCode == event.vkCode &&
            lastKey.scanCode == event.scanCode &&
            lastKey.flags == event.flags
            )
        {
            repeatCount++;
        }
        else
        {
            repeatCount = 0;
            lastKey = event;
        }

        wprintf(_T("%04u Data:%02u repeat:%03u vk:%02X(%03u) %-12s down Shift:%u Ctrl:%u Alt:%d Win:%u flags:%04X sc:%02X tm:%04X Ex:%04X\n"),
            count, (int)m_ModifiersKeysDownRecords.size(), repeatCount,
            event.vkCode, event.vkCode, szName, bShitf, bCtrl, bAlt, bWin, event.flags, event.scanCode, dwTime, (int)event.dwExtraInfo);
    }
    else
    {
        lastKey.vkCode = 0;
        lastKey.scanCode = 0;
        lastKey.flags = 0;
        repeatCount = 0;

        wprintf(_T("%04u Data:%02u repeat:%03u vk:%02X(%03u) %-12s   up Shift:%u Ctrl:%u Alt:%d Win:%u flags:%04X sc:%02X tm:%04X Ex:%04X\n"),
            count, (int)m_ModifiersKeysDownRecords.size(), repeatCount,
            event.vkCode, event.vkCode, szName, bShitf, bCtrl, bAlt, bWin, event.flags, event.scanCode, dwTime, (int)event.dwExtraInfo);
    }
}

bool CKeyboardHookUtils::Install(HWND hWnd)
{
    if (NULL == m_hKeyboard)
    {
        m_hKeyboard = ::SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeybdProc, NULL, 0);
    }

    m_hWnd = hWnd;

    return NULL != m_hKeyboard;
}

void CKeyboardHookUtils::Uninstall()
{
    if (m_hKeyboard)
    {
        ::UnhookWindowsHookEx(m_hKeyboard);
        m_hKeyboard = NULL;
    }
}

void CKeyboardHookUtils::UpdateModifiersKeys(const KBDATA& key, bool isDown)
{
    if (isDown)
    {
        // 查找已经存放的按键
        bool isFind = false;
        for (int i = 0; i < m_ModifiersKeysDownRecords.size(); i++)
        {
            if (m_ModifiersKeysDownRecords[i] == key)
            {
                isFind = true;
                break;
            }
        }

        // 未找到则添加
        if (!isFind)
        {
            m_ModifiersKeysDownRecords.push_back(key);
        }
    }
    else
    {
        // 查找已经存放的按键
        for (auto it = m_ModifiersKeysDownRecords.begin(); m_ModifiersKeysDownRecords.end() != it;)
        {
            if (*it == key)
            {
                // 找到则移除掉
                it = m_ModifiersKeysDownRecords.erase(it);
                break;
            }
            it++;
        }
    }
}

void CKeyboardHookUtils::ProcessTimerEvent(HWND hWnd, UINT_PTR  nIDEvent)
{
    if (hWnd != m_hWnd || nIDEvent != m_nHoldTimer)
    {
        return;
    }

    for (auto& item : m_HkCbInfos)
    {
        if (item.KeyInfo.IsHolding())
        {
            if (item.m_cbHold)
            {
                item.KeyInfo.m_ullDurationTime = GetCurMilliSecond() - item.KeyInfo.m_ullDownTime;
                item.m_cbHold(item.KeyInfo);
                return;
            }
        }
    }
}

ULONGLONG CKeyboardHookUtils::GetCurMilliSecond()
{
    struct timeb rawtime;
    ftime(&rawtime);
    return (ULONGLONG)rawtime.time * 1000 + (ULONGLONG)rawtime.millitm;
}

void CKeyboardHookUtils::ProcessMessageLoop()
{
    MSG msg = { 0 };

    // 使用消息环处理消息
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);

        if (WM_TIMER == msg.message)
        {
            ProcessTimerEvent(msg.hwnd, msg.wParam);
        }
    }
}

bool CKeyboardHookUtils::AddShortcutKeys(KdList modifiersKeys, KBDATA activeKey, KdCb cbDown, KdCb cbHold, KdCb cbUp)
{
    HkCbInfo info(modifiersKeys, activeKey, cbDown, cbHold, cbUp);
    std::lock_guard<std::mutex> lock(m_opLock);

    // 已存在则不会添加
    for (const auto item : m_HkCbInfos)
    {
        if (item.KeyInfo == info.KeyInfo)
        {
            return false;
        }
    }

    m_HkCbInfos.push_back(info);
    return true;
}

bool CKeyboardHookUtils::RemoveShortcutKeys(KdList modifiersKeys, KBDATA activeKey)
{
    HkCbInfo info(modifiersKeys, activeKey);
    std::lock_guard<std::mutex> lock(m_opLock);

    // 不存在则不会移除
    for (auto item = m_HkCbInfos.begin(); item != m_HkCbInfos.end(); item++)
    {
        if (item->KeyInfo == info.KeyInfo)
        {
            if (item->KeyInfo.IsHolding())
            {
                KillTimer(m_hWnd, m_nHoldTimer);
            }
            item = m_HkCbInfos.erase(item);
            return true;
        }
    }

    return false;
}

bool CKeyboardHookUtils::RemoveShortcutKeys(LPCTSTR keysName)
{
    std::lock_guard<std::mutex> lock(m_opLock);

    // 不存在则不会移除
    for (auto item = m_HkCbInfos.begin(); item != m_HkCbInfos.end(); item++)
    {
        if (GetKeyListName(item->KeyInfo) == keysName)
        {
            if (item->KeyInfo.IsHolding())
            {
                KillTimer(m_hWnd, m_nHoldTimer);
            }
            m_HkCbInfos.erase(item);
            return true;
        }
    }

    return false;
}

_tstring CKeyboardHookUtils::GetKeyListName(const HkInfo& info)
{
    _tstring sreKeyList;
    for (auto& key : info.m_ModifiersKeys)
    {
        sreKeyList += key.GetKeyName();
        sreKeyList += _T(" + ");
    }

    sreKeyList += info.m_ActiveKey.GetKeyName();

    return sreKeyList;
}

bool CKeyboardHookUtils::ProcessShortcutKeys(const KBDATA& key)
{
    HkCbInfo info(m_ModifiersKeysDownRecords, key);

    bool isFind = false;

    for (auto &item : m_HkCbInfos)
    {
        isFind = false;

        if (item == info)
        {
            // 按住中则返回
            if (item.KeyInfo.IsHolding())
            {
                return true;
            }

            isFind = true;

            //按下时记录时间
            item.KeyInfo.m_ullDownTime = GetCurMilliSecond();
            item.KeyInfo.m_ullDurationTime = 0;
            m_isHolding = true;

            // 释放掉组合键防止干扰
            {
                // 释放掉组合键防止干扰
                SendKeysHelper keys;
                keys.SendKeys(info.KeyInfo.m_ActiveKey, SendKeysHelper::key_up);
                keys.SendKeys(info.KeyInfo.m_ModifiersKeys, SendKeysHelper::key_up);
                keys.SendKeys(SendKeysHelper::key_up);
            }
            // 设置一个定时器处理按住不放的情况
            m_nHoldTimer = SetTimer(m_hWnd, KEY_HOOK_TIMER_ID, 50, NULL);
            if (item.m_cbDown)
            {
                item.m_cbDown(item.KeyInfo);
            }
            break;
        }
    }

    return isFind;
}

bool CKeyboardHookUtils::ResetShortcutKeys(void)
{
    // 没有组合键按下直接返回
    if (!m_isHolding)
    {
        return false;
    }

    // 查找激活的组合键
    for (auto& item : m_HkCbInfos)
    {
        // 存在计时器
        if (item.KeyInfo.IsHolding())
        {
            //按键弹起时记录时间
            item.KeyInfo.m_ullDurationTime = GetCurMilliSecond() - item.KeyInfo.m_ullDownTime;

            if (item.m_cbUp)
            {
                item.m_cbUp(item.KeyInfo);
            }

            //清除定时器
            KillTimer(m_hWnd, KEY_HOOK_TIMER_ID);

            item.KeyInfo.m_ullDownTime = 0;
            item.KeyInfo.m_ullDurationTime = 0;
            m_isHolding = false;

            return true;
        }
    }

    return false;
}

LRESULT CALLBACK CKeyboardHookUtils::LowLevelKeybdProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode >= 0)
    {
        // HOOK 处理
        if (Instance().KeybdProc(wParam, lParam))
        {
            return 1;
        }
    }

    return ::CallNextHookEx(Instance().m_hKeyboard, nCode, wParam, lParam);
}

bool CKeyboardHookUtils::ProcessKeybdHook(WPARAM wParam, LPARAM lParam)
{
    LPKBDLLHOOKSTRUCT pEvent = (LPKBDLLHOOKSTRUCT)lParam;
    DWORD vkCode = pEvent->vkCode;
    DWORD scanCode = pEvent->scanCode;
    DWORD flags = pEvent->flags;
    DWORD time = pEvent->time;
    ULONG_PTR dwExtraInfo = pEvent->dwExtraInfo;

    static KBDATA lastKey;
    static long keyRepeat = 0;

    bool bKeyDown = (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN);
    bool isModifiersKey = false;
    bool isHookHandled = false;

    // 修饰键检查
    if (VK_LWIN == vkCode || VK_RWIN == vkCode ||
        VK_LCONTROL == vkCode || VK_RCONTROL == vkCode ||
        VK_LMENU == vkCode || VK_RMENU == vkCode ||
        VK_LSHIFT == vkCode || VK_RSHIFT == vkCode
        )
    {
        isModifiersKey = true;
    }

    KBDATA curKey(pEvent->vkCode, pEvent->scanCode, pEvent->flags, pEvent->time);

    // 重复按住检查
    if (curKey == lastKey)
    {
        keyRepeat++;
    }
    else
    {
        lastKey = curKey;
        keyRepeat = 0;
    }

    // 清理重复键记录
    if (!bKeyDown)
    {
        lastKey.Clean();
        keyRepeat = 0;
    }

    // 组合键按住时触发键有重复不传递按键
    if (keyRepeat > 0 && m_isHolding)
    {
        return true;
    }

    // 如果按键是修饰键则更新缓存的状态
    if (isModifiersKey)
    {
        UpdateModifiersKeys(curKey, bKeyDown);
    }

    // 如果已经激活组合键, 则其中任意按键弹起都需要释放掉
    if (!bKeyDown && ResetShortcutKeys())
    {
        return false;
    }

    // 非修饰键按下时记录下来
    if (!isModifiersKey && bKeyDown)
    {
        isHookHandled = ProcessShortcutKeys(curKey);
    }

    if (isHookHandled)
    {
        return true;
    }

    return false;
}

bool CKeyboardHookUtils::KeybdProc(WPARAM wParam, LPARAM lParam)
{
    LPKBDLLHOOKSTRUCT pEvent = (LPKBDLLHOOKSTRUCT)lParam;
    DWORD vkCode = pEvent->vkCode;
    DWORD scanCode = pEvent->scanCode;
    DWORD flags = pEvent->flags;
    DWORD time = pEvent->time;
    ULONG_PTR dwExtraInfo = pEvent->dwExtraInfo;

    bool bKeyDown = (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN);
    bool bCtrl = GetAsyncKeyState(VK_CONTROL) & 0x8000;
    bool bAlt = GetAsyncKeyState(VK_MENU) & 0x8000;

    // 调试信息打印
    DebugPrintf(wParam, lParam);

    // SAS(安全注意序列)发生时清空存储的记录
    if (bCtrl && bAlt && VK_DELETE == vkCode)
    {
        ResetShortcutKeys();
        m_ModifiersKeysDownRecords.clear();
        return false;
    }

    // 如果是 HOOK 处理后发送过来的按键不进行任何处理
    if (dwExtraInfo == KEY_HOOK_HANDLED_FLAG)
    {
        return false;
    }

    bool isHandled = ProcessKeybdHook(wParam, lParam);

    return isHandled;
}

main.cpp

// CKeyboardHookUtils.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <tchar.h>
#include "CKeyboardHookUtils.h"

void SendKeys_ESC();
void SendKeys_Ctrl_Win_O();
void SendKeys_Win_G();
void SendKeys_Win_D();
void SendKeys_Shift_Ctrl_Esc();

void Test_LWin_D();
void Test_LWin_ESC();

int main()
{
    auto hStdin = ::GetStdHandle(STD_INPUT_HANDLE);
    DWORD mode;
    ::GetConsoleMode(hStdin, &mode);
    mode &= ~ENABLE_QUICK_EDIT_MODE;
    ::SetConsoleMode(hStdin, mode);

    CKeyboardHookUtils::Instance().Install(NULL);

    // 测试Win + D
    Test_LWin_D();

    // 测试 Win + ESC
    Test_LWin_ESC();

    // 需要一个消息环, 否则键盘 HOOK 不会生效
    CKeyboardHookUtils::Instance().ProcessMessageLoop();

    CKeyboardHookUtils::Instance().Uninstall();

    return 0;
}

void Test_LWin_D()
{
    std::vector<KBDATA> keysWinD;
    static bool ShortcutKeysHold = false;

    auto cbDown = [](const HkInfo& KeyInfo) {
        ShortcutKeysHold = false;
        printf("按下: LWin_D Up 持续: %lu 毫秒\n", KeyInfo.m_ullDurationTime);
    };

    auto cbHold = [](const HkInfo& KeyInfo) {
        if (KeyInfo.m_ullDurationTime >= 1000)
        {
            if (!ShortcutKeysHold)
            {
                printf("长按: LWin_D Up 持续: %lu 毫秒\n", KeyInfo.m_ullDurationTime);
                SendKeys_Ctrl_Win_O();
                ShortcutKeysHold = true;
            }
            printf("按住: LWin_D Up 持续: %lu 毫秒\n", KeyInfo.m_ullDurationTime);
        }
        else
        {
            printf("按住: LWin_D Up 持续: %lu 毫秒\n", KeyInfo.m_ullDurationTime);
        }

    };

    auto cbUp = [](const HkInfo& KeyInfo) {
        ShortcutKeysHold = false;
        // 按住短按
        if (KeyInfo.m_ullDurationTime < 1000)
        {
            printf("弹起: LWin_D Up 持续: %lu 毫秒\n", KeyInfo.m_ullDurationTime);
            SendKeys_Shift_Ctrl_Esc();
            ShortcutKeysHold = true;
        }
        else
        {
            printf("弹起: LWin_D Up 持续: %lu 毫秒\n", KeyInfo.m_ullDurationTime);
        }
    };

    keysWinD.push_back(KBDATA(VK_LWIN, 0x5B, KEYEVENTF_EXTENDEDKEY));
    CKeyboardHookUtils::Instance().AddShortcutKeys(keysWinD, KBDATA('D', 0x20, 0), cbDown, cbHold, cbUp);

    keysWinD.clear();
    keysWinD.push_back(KBDATA(VK_RWIN, 0x5C, KEYEVENTF_EXTENDEDKEY));
    CKeyboardHookUtils::Instance().AddShortcutKeys(keysWinD, KBDATA('D', 0x20, 0), cbDown, cbHold, cbUp);
}

void Test_LWin_ESC()
{
    std::vector<KBDATA> keysWinEsc;
    static bool ShortcutKeysHold = false;

    auto cbDown = [](const HkInfo& KeyInfo) {
        ShortcutKeysHold = false;
        printf("按下: LWin_D Up 持续: %lu 毫秒\n", KeyInfo.m_ullDurationTime);
    };

    auto cbHold = [](const HkInfo& KeyInfo) {
        if (KeyInfo.m_ullDurationTime >= 1000)
        {
            if (!ShortcutKeysHold)
            {
                printf("长按: LWin_D Up 持续: %lu 毫秒\n", KeyInfo.m_ullDurationTime);
                PostMessage(NULL, WM_QUIT, 0, 0);
                ShortcutKeysHold = true;
            }
            printf("按住: LWin_D Up 持续: %lu 毫秒\n", KeyInfo.m_ullDurationTime);
        }
        else
        {
            printf("按住: LWin_D Up 持续: %lu 毫秒\n", KeyInfo.m_ullDurationTime);
        }

    };

    auto cbUp = [](const HkInfo& KeyInfo) {
        ShortcutKeysHold = false;
        // 按住短按
        if (KeyInfo.m_ullDurationTime < 1000)
        {
            printf("弹起: LWin_D Up 持续: %lu 毫秒\n", KeyInfo.m_ullDurationTime);
            SendKeys_Win_G();
            ShortcutKeysHold = true;
        }
        else
        {
            printf("弹起: LWin_D Up 持续: %lu 毫秒\n", KeyInfo.m_ullDurationTime);
        }
    };

    keysWinEsc.push_back(KBDATA(VK_LWIN, 0x5B, KEYEVENTF_EXTENDEDKEY));
    CKeyboardHookUtils::Instance().AddShortcutKeys(keysWinEsc, KBDATA(VK_ESCAPE, 0x01, 0), cbDown, cbHold, cbUp);

    keysWinEsc.clear();
    keysWinEsc.push_back(KBDATA(VK_RWIN, 0x5C, KEYEVENTF_EXTENDEDKEY));
    CKeyboardHookUtils::Instance().AddShortcutKeys(keysWinEsc, KBDATA(VK_ESCAPE, 0x01, 0), cbDown, cbHold, cbUp);
}

void SendKeys_ESC()
{
    SendKeysHelper keys;
    keys.PushBack(VK_ESCAPE, 0x01, 0);
    keys.SendKeys();
}

void SendKeys_Ctrl_Win_O()
{
    SendKeysHelper keys;
    keys.PushBack(VK_LCONTROL, 0x1D, KEYEVENTF_EXTENDEDKEY);
    keys.PushBack(VK_LWIN, 0x5B, 1);
    keys.PushBack('O', 0x18, 0);
    keys.SendKeys();
}

void SendKeys_Win_G()
{
    SendKeysHelper keys;
    keys.PushBack(VK_LWIN, 0x5B, KEYEVENTF_EXTENDEDKEY);
    keys.PushBack('G', 0x18, 0);
    keys.SendKeys();
}

void SendKeys_Win_D()
{
    SendKeysHelper keys;
    keys.PushBack(VK_LWIN, 0x5B, KEYEVENTF_EXTENDEDKEY);
    keys.PushBack('D', 0x20, 0);
    keys.SendKeys();
}

void SendKeys_Shift_Ctrl_Esc()
{
    SendKeysHelper keys;
    keys.PushBack(VK_LSHIFT, 0x2A, KEYEVENTF_EXTENDEDKEY);
    keys.PushBack(VK_LCONTROL, 0x1D, KEYEVENTF_EXTENDEDKEY);
    keys.PushBack(VK_ESCAPE, 0x01, 0);
    keys.SendKeys();
}

 

 

实际效果:35a8893b6ef443f88e63ae2a92f4c6a7.png

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值