前段时间学习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();
}
实际效果: