海盗小K 发表于 2016-9-19 21:59

【C++】【超级模块】之【监视热键】

本帖最后由 wushaominkk 于 2018-5-7 16:51 编辑

最近真的没啥时间了,无聊折腾了些小玩意儿,预计年后才能回归。

前段时间搞DNF辅助,必须要用到热键,C++的那个API RigisterHotkey各种不好使,然后自己对着超级模块封装了一个C++版本的,用着还不错,但是有些小bug。今晚没事回头调了几遍代码,把小bug修复了。现在分享出来,以后大家用C++监视热键的时候也能图个方便。

这个用法也非常简单,你会用超级模块,肯定会用这个,没什么差别。源码中附赠了一个超级模块中的【超级延时】功能函数,还有两个简单的弹窗测试函数。

先贴一下源码吧。

HotKey.h

#ifndef _HOTKEY_H_
#define _HOTKEY_H_

#include<iostream>
#include<cstdlib>
#include<vector>
#include<Windows.h>


#define MOD_NONE 0x0000

typedef unsigned int HOTKEY_ID;
typedef DWORD PFUNC;


typedef struct tagHOTKEY_INFO
{
      HOTKEY_ID HotkeyID;
      PFUNC pfnCallbackFunc;
      BYTE KeyCode;
      BYTE FuncKey;
      BYTE AnotherKeyCode;
      BYTE byKeyStatus;
      BOOL bStatus;
      BOOL bDirectTrigger;
}HOTKEY_INFO, *PHOTKEY_INFO;

void HandleTheEvents();
void SuperDelay(int nElapse, int nUnit = 0);
VOID HotKeyTest();
VOID HotKeyTest2();

HOTKEY_ID HotkeyMonitor(PFUNC pfnCallbackFunc, BYTE KeyCode, BYTE FuncKeyStatus = MOD_NONE, BYTE AnotherKeyCode = 0, UINT uElapse = USER_TIMER_MINIMUM, BOOL bDirectTrigger = FALSE);
VOID CALLBACK HotKeyMonThread(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
BOOL HotKeyUnMonitor(HOTKEY_ID HotkeyID = 0);


#endif

HotKey.cpp

#include"stdafx.h"
#include"HotKey.h"


std::vector<HOTKEY_INFO> HotKeyList;

void HandleTheEvents()
{
      MSG msg;
      while (PeekMessage(&msg, 0, 0, 0, 1))
      {
                DispatchMessage(&msg);
                TranslateMessage(&msg);
      }
}

void SuperDelay(int nElapse, int nUnit)
{
      LARGE_INTEGER int64;
      HANDLE hTimer;

      if (1 == nUnit)
      {
                int64.QuadPart = -10 * nElapse;
                hTimer = CreateWaitableTimer(NULL, FALSE, NULL);
                SetWaitableTimer(hTimer, &int64, 0, NULL, NULL, FALSE);
                while (WAIT_OBJECT_0 != MsgWaitForMultipleObjects(1, &hTimer, FALSE, INFINITE, QS_ALLINPUT))
                {
                        HandleTheEvents();
                }
                CloseHandle(hTimer);
                return;
      }
      switch (nUnit)
      {
      case 0:
                nUnit = 1;
                break;
      case 2:
                nUnit = 1000;
                break;
      case 3:
                nUnit = 1000 * 60;
                break;
      case 4:
                nUnit = 1000 * 60 * 60;
                break;
      case 5:
                nUnit = 1000 * 60 * 60 * 24;
                break;
      default:
                break;
      }

      for (int i = 0; i < nUnit; i++)
      {
                int64.QuadPart = -10 * nElapse * 1000;
                hTimer = CreateWaitableTimer(NULL, FALSE, NULL);
                SetWaitableTimer(hTimer, &int64, 0, NULL, NULL, FALSE);
                while (WAIT_OBJECT_0 != MsgWaitForMultipleObjects(1, &hTimer, FALSE, INFINITE, QS_ALLINPUT))
                {
                        HandleTheEvents();
                }
                CloseHandle(hTimer);
                return;
      }

}


VOID HotKeyTest()
{
      MessageBox(NULL, _T("Test"), _T("Test"), MB_OK);
}

VOID HotKeyTest2()
{
      MessageBox(NULL, _T("Test2"), _T("Test2"), MB_OK);
}

/*

.Function Name: HotkeyMonitor,监视一个热键, 当热键被触发时激活响应事件.(成功返回热键标识, 失败返回0).注:必须真实的按键才会触发热键
.Parameter pfnCallbackFunc, 子程序指针, , 响应事件(热键标识, 其它...), 事件参数数目不限!如果再次监视热键将响应事件!
.Parameter KeyCode, 字节型, , 触发事件的基本键
.Parameter FuncKeyStatus, 字节型, 可空, 1 Alt2 Ctrl4 Shift8 Win 若要两个或以上的状态键, 则把它们的值相加,可以使用相应的宏MOD_ALT,MOD_CONTROL,MOD_SHIFT,MOD_WIN来位或运算
.Parameter AnotherKeyCode, 字节型, 可空, 如果你需要注册由两个普通键组合的热键, 可设置一个其它键代码.
.Parameter uElapse, 无符号整数型, 可空, 默认为10, 监视热键的周期时间(建议5 - 200之间)
.Parameter bDirectTrigger, 逻辑型, 可空, 默认为假:创建新的线程事件 真 : 直接调用事件等待返回

*/
HOTKEY_ID HotkeyMonitor(PFUNC pfnCallbackFunc, BYTE KeyCode, BYTE FuncKeyStatus, BYTE AnotherKeyCode, UINT uElapse, BOOL bDirectTrigger)
{
      HOTKEY_INFO TempHotkeyInfo;

      if (KeyCode <= 0)
                return 0;

      for (std::vector<HOTKEY_INFO>::iterator it = HotKeyList.begin(); it != HotKeyList.end(); it++)
      {
                if (it->KeyCode == KeyCode && it->FuncKey == FuncKeyStatus && it->AnotherKeyCode == AnotherKeyCode)
                {
                        it->pfnCallbackFunc = pfnCallbackFunc;
                        it->bDirectTrigger = bDirectTrigger;
                        if (it->HotkeyID)
                              return it->HotkeyID;
                        it->HotkeyID = 1000001 + (it - HotKeyList.begin());
                        return it->HotkeyID;
                }
      }

      TempHotkeyInfo.pfnCallbackFunc = pfnCallbackFunc;
      TempHotkeyInfo.KeyCode = KeyCode;
      TempHotkeyInfo.FuncKey = FuncKeyStatus;
      TempHotkeyInfo.AnotherKeyCode = AnotherKeyCode;
      TempHotkeyInfo.bDirectTrigger = bDirectTrigger;
      TempHotkeyInfo.HotkeyID = 1000001 + HotKeyList.size();

      HotKeyList.push_back(TempHotkeyInfo);

      if (1000001 == TempHotkeyInfo.HotkeyID)
                SetTimer(NULL, 666, uElapse, (TIMERPROC)&HotKeyMonThread);

      return TempHotkeyInfo.HotkeyID;
}


//监视热键线程
VOID CALLBACK HotKeyMonThread(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
      PFUNC pfnTempEvent;
      UINT uTempID;
      SHORT KeyStatusCache;
      INT byTemp = 0;

      for (int i = 1; i <= 255; i++)
      {
                KeyStatusCache = 251;
                KeyStatusCache = GetAsyncKeyState(i);
      }
      for (std::vector<HOTKEY_INFO>::iterator it = HotKeyList.begin(); it != HotKeyList.end(); it++)
      {
                if (it->HotkeyID)
                {
                        byTemp = (BYTE)(it->KeyCode);
                        byTemp = KeyStatusCache;

                        if (0 == byTemp || 1 == byTemp)
                        {
                              if (1 == it->byKeyStatus)
                                        it->byKeyStatus = 2;
                              else
                              {
                                        it->byKeyStatus = 0;
                                        continue;
                              }
                        }
                        else if (byTemp < 0)
                        {
                              if (0 == it->byKeyStatus)
                                        it->byKeyStatus = 1;
                              else if (it->byKeyStatus < 0)
                                        continue;
                        }

                        if (it->byKeyStatus > 0 && it->byKeyStatus != 88)
                        {
                              it->byKeyStatus = 88;
                              if (it->FuncKey == ((KeyStatusCache < 0 ? MOD_ALT : 0)
                                        | (KeyStatusCache < 0 ? MOD_CONTROL : 0)
                                        | (KeyStatusCache < 0 ? MOD_SHIFT : 0)
                                        | (KeyStatusCache < 0 ? MOD_WIN : 0)))
                              {
                                        if (it->AnotherKeyCode)
                                        {
                                                byTemp = it->AnotherKeyCode;
                                                if (KeyStatusCache >= 0)
                                                      continue;
                                        }
                                        pfnTempEvent = it->pfnCallbackFunc;
                                        uTempID = it->HotkeyID;
                                        if (it->bDirectTrigger)
                                                CallWindowProcA((WNDPROC)pfnTempEvent, (HWND)uTempID, 0, 0, 0);
                                        else
                                                CloseHandle(CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pfnTempEvent, (LPVOID)uTempID, 0, NULL));
                              }
                        }
                }
      }

}

/*

.Function Name: HotKeyUnMonitor, 逻辑型撤消由监视热键注册的一个或全部热键(成功返回真,失败返回假)
.Parameter HotkeyID, HOTKEY_ID型, 可空, 欲撤消的热键标识,如果留空则撤消全部热键

*/

BOOL HotKeyUnMonitor(HOTKEY_ID HotkeyID)
{
      for (std::vector<HOTKEY_INFO>::iterator it = HotKeyList.begin(); it != HotKeyList.end(); it++)
      {
                if (0 == HotkeyID)
                        it->HotkeyID = 0;
                else if (HotkeyID == it->HotkeyID)
                {
                        it->HotkeyID = 0;
                        return TRUE;
                }
      }
      return (0 == HotkeyID);
}

用法:先将这两个文件添加到你的VS工程,要用到监视热键的文件中头部加入#include "HotKey.h"然后调用即可。

例子:


HOTKEY_ID vkid_F2 = 0, vkid_F3 = 0;


//HotKeyTest可以换成你的函数名
vkid_F2 = HotkeyMonitor((PFUNC)&HotKeyTest, VK_F2);
vkid_F3 = HotkeyMonitor((PFUNC)&HotKeyTest2, VK_LEFT, MOD_ALT);

HotKeyUnMonitor(vkid_F3);



文件简单,也懒得搞什么排版了。。。
注意:这是我从MFC工程中扒下来的,所以有#include "stdafx.h",如果你要用于非MFC工程的话,去掉该行,并添加#include <tchat.h>

感谢1257210463童鞋的指正。

再会。以上。


1257210463 发表于 2016-12-11 18:28

请问楼主数组赋值能这样写吗,你这是什么语言或者是什么编译器
SHORT KeyStatusCache;
      INT byTemp = 0;

      for (int i = 1; i <= 255; i++)
      {
                KeyStatusCache = 251;
                KeyStatusCache = GetAsyncKeyState(i);
      }

海盗小K 发表于 2016-9-19 22:53

wxj364094000 发表于 2016-9-19 22:51
楼主是用c++& MFC写DNF辅助吗

最开始玩CE,CT。后来转易语言。之前又搞过一段时间MFC EXE,没图标的问题很烦,现在准备用Win32 DLL或者MFC DLL玩劫持。

绘梨衣 发表于 2016-9-19 22:28

漂亮啊啊

xouou 发表于 2016-9-19 22:29

沙发 出租,2CB/天

wxj364094000 发表于 2016-9-19 22:51

楼主是用c++& MFC写DNF辅助吗

熊猫京京 发表于 2016-9-19 23:39

海盗小K 发表于 2016-9-19 22:53
最开始玩CE,CT。后来转易语言。之前又搞过一段时间MFC EXE,没图标的问题很烦,现在准备用Win32 DLL或者 ...

如今会MFC的大神真是凤毛麟角

夜羽天隐 发表于 2016-9-20 07:21

先学的c然后看不懂转的易语言然后又去学的java现在为了考级又学回来了

wxj364094000 发表于 2016-9-20 17:21

夜羽天隐 发表于 2016-9-20 07:21
先学的c然后看不懂转的易语言然后又去学的java现在为了考级又学回来了

c你看不懂?你去看谭浩强写的那本大学教材,就算你是个小学生都能看懂

YY妖爱YY妖 发表于 2016-9-21 09:12

wxj364094000 发表于 2016-9-21 15:46

YY妖爱YY妖 发表于 2016-9-21 09:12
是吗 我不觉得哦

请问你大学学的什么专业?
页: [1] 2
查看完整版本: 【C++】【超级模块】之【监视热键】