1. 简介
玩游戏的时候难免会遇到一些游戏的 "折磨"。例如:我们要使用道具的时候,可这个道具居然没有批量使用!!!
那行吧,我们就来动手做一个按键精灵解放我们的双手。
PS:目前只做了鼠标按键版的,如果有需要键盘的,可以私信或下方留言,后续看需补充吧~
2. 那我们就开始吧~
①. 首先是Win32的框架(这里我就直接套用过来了,不懂可以看下我之前的文章哈~)
//++++++++++++++++++++++++++++++++++ // 宏定义 //---------------------------------- #ifndef UNICODE #define UNICODE // 使用UNICODE编码,如果在编译器设置了使用UNICODE字符集此处可免 #endif #ifndef _UNICODE #define _UNICODE // 使用UNICODE编码,如果在编译器设置了使用UNICODE字符集此处可免 #endif //++++++++++++++++++++++++++++++++++ // 头文件 //---------------------------------- #include <windows.h> // Win32程序最重要的头文件 #include <tchar.h> // 兼容字符集头文件 #include "VibraClick.h" // 鼠标模拟器头文件 //++++++++++++++++++++++++++++++++++ // 全局变量 //---------------------------------- TCHAR g_lpszClassName[] = _T("VibraClick"); // 窗口类的名称 TCHAR g_lpszWindowName[] = _T("VibraClick"); // 窗口的名称,(也就是窗口的标题) VibraClick g_vibraClick; // 鼠标模拟器 //++++++++++++++++++++++++++++++++++ // 函数声明 //---------------------------------- LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // 窗口消息处理过程 VOID VibraClick_Init(HWND); // 初始化软件 //++++++++++++++++++++++++++++++++++ // 游戏主函数 //---------------------------------- INT APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, INT nCmdShow) { /* 1.设计一个窗口类 */ ... /* 2.注册窗口类 */ ... /* 3.创建窗口, 并居中显示 */ ... /* 4.更新显示窗口 */ ... /* 初始化 */ VibraClick_Init(hWnd); /* 5.消息循环 */ ... return msg.wParam; } //++++++++++++++++++++++++++++++++++ // 窗口消息处理过程 //---------------------------------- LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_HOTKEY: g_vibraClick.OnHotKey(wParam); break; case WM_DESTROY: // 窗口销毁,释放资源 ::PostQuitMessage(0); break; default: return ::DefWindowProc(hWnd, message, wParam, lParam); } return ((LRESULT)0); } VOID VibraClick_Init(HWND hWnd) { g_vibraClick.Init(hWnd); }
讯享网
简单讲解上面内容:
1. 定义了一个按键模拟器类(VibraClick) 的变量 g_vibraClick
2. 初始化这个按键模拟器
3. 由于注册了热键 CTRL + S 和 CTRL + R 进行录制和运行,所以消息处理了WM_HOTKEY
②. VibraClick(按键模拟器类)
VibraClick.h
讯享网 #pragma once #ifndef __VIBRA_CLICK_H__ #define __VIBRA_CLICK_H__ #include <Windows.h> #include <vector> // 参照 INPUT 类 struct MouseRecInput { DWORD type; MOUSEINPUT mi; }; // 定时器回调 VOID CALLBACK TimerProc(HWND hwnd, UINT message, UINT nIDEvent, DWORD dwTime); // 鼠标Hook消息处理 LRESULT CALLBACK MouseMessageProc(INT nCode, WPARAM wParam, LPARAM lParam); class VibraClick { using MouseRecInputVector = std::vector<MouseRecInput *>; public: VibraClick(); ~VibraClick(); public: void Init(HWND hWnd); // 初始化 void StartMouseRec(); // 开始录制鼠标操作 void StopMouseRec(); // 停止录制鼠标操作 void StartRunMouseRec(); // 开始运行鼠标录制的内容 void StopRunMouseRec(); // 停止运行鼠标录制的内容 void CleanMouseRecInput(); // 清除鼠标记录内容 void OnHotKey(WPARAM nHotKeyId); // 热键处理 public: static VibraClick *GetInstance() { return _inst; } bool IsStartMouseRec() { return m_IsStartMouseRec; } bool IsStartRunMouseRec() { return m_IsStartRunMouseRec; } HHOOK GetHHMouseHook() { return m_hhMouseHook; } MouseRecInputVector &GetMouseRecInputVector() { return m_vecMouseRecInput; } int GetMouseRecIndex() { return m_MouseRecIndex; } void SetMouseRecIndex(int value) { m_MouseRecIndex = value; } protected: static VibraClick *_inst; // 实例自己 HWND m_hWnd; // 窗口句柄 MouseRecInputVector m_vecMouseRecInput; // 鼠标操作数据 bool m_IsStartMouseRec; // 是否开始记录鼠标操作 bool m_IsStartRunMouseRec; // 是否开始鼠标操作 int m_MouseRecIndex; // 鼠标操作索引 UINT_PTR m_RunTimerId; // 运行的定时器Id ATOM m_VibraClick_StartRec; // 开始记录热键id ATOM m_VibraClick_RunRec; // 开始运行记录热键id // 鼠标的Hook HHOOK m_hhMouseHook; }; #endif // !__VIBRA_CLICK_H__
INPUT 结构体(WinUser.h头文件中)
typedef struct tagINPUT { DWORD type; union { MOUSEINPUT mi; KEYBDINPUT ki; HARDWAREINPUT hi; } DUMMYUNIONNAME; } INPUT, *PINPUT, FAR* LPINPUT;
简单讲解上面的内容:
1. MouseRecInput结构体,具体参照 INPUT 结构体。因为MOUSEINPUT是在共用体内,所以对其进行一个扩展
2. TimerProc是一个定时器的处理,用在运行按键模拟的时候
3. MouseMessageProc这个一个鼠标的录制Hook处理
4. 类的方法和成员变量都有对应的注释就不详细说明了哈~(不懂的话在下方留言吧,到时候再进行补充)
VibraClick.cpp
讯享网 #include "VibraClick.h" #include <tchar.h> VibraClick *VibraClick::_inst = nullptr; VibraClick::VibraClick() { // 初始化一些变量 m_IsStartMouseRec = false; m_IsStartRunMouseRec = false; m_MouseRecIndex = 0; m_RunTimerId = -1; m_hhMouseHook = NULL; m_hWnd = NULL; _inst = this; } VibraClick::~VibraClick() { // 清除鼠标记录内容 CleanMouseRecInput(); StopMouseRec(); StopRunMouseRec(); // 反注册热键 UnregisterHotKey(this->m_hWnd, m_VibraClick_StartRec); // Ctrl + S UnregisterHotKey(this->m_hWnd, m_VibraClick_RunRec); // Ctrl + R } void VibraClick::Init(HWND hWnd) { m_hWnd = hWnd; m_VibraClick_StartRec = GlobalAddAtom(_T("VibraClick_StartRec")) - 0xC000; m_VibraClick_RunRec = GlobalAddAtom(_T("VibraClick_RunRec")) - 0xC000; RegisterHotKey(this->m_hWnd, m_VibraClick_StartRec, MOD_CONTROL, 'S'); // Ctrl + S RegisterHotKey(this->m_hWnd, m_VibraClick_RunRec, MOD_CONTROL, 'R'); // Ctrl + R } void VibraClick::StartMouseRec() { // 清除鼠标记录内容 CleanMouseRecInput(); // 设置当前为录制鼠标操作状态 m_IsStartMouseRec = true; // 开始鼠标Hook(全局鼠标钩子) m_hhMouseHook = SetWindowsHookEx(WH_MOUSE_LL, &MouseMessageProc, GetModuleHandle(NULL), NULL); } void VibraClick::StopMouseRec() { // 取消设置当前为录制鼠标操作状态 m_IsStartMouseRec = false; // 释放鼠标Hook if (m_hhMouseHook != NULL) UnhookWindowsHookEx(m_hhMouseHook); } void VibraClick::StartRunMouseRec() { // 开始模拟鼠标操作 m_IsStartRunMouseRec = true; // 设置运行索引 m_MouseRecIndex = 0; // 开启定时器 m_RunTimerId = SetTimer(m_hWnd, 999, 10, &TimerProc); } void VibraClick::StopRunMouseRec() { // 停止运行鼠标记录的内容 m_IsStartRunMouseRec = false; // 关闭定时器 if (m_RunTimerId != -1) { KillTimer(m_hWnd, m_RunTimerId); m_RunTimerId = -1; } } void VibraClick::CleanMouseRecInput() { // 清除记录的内容 for (auto input : m_vecMouseRecInput) { delete input; input = nullptr; } // 释放vector占用内存 MouseRecInputVector tmp; m_vecMouseRecInput.swap(tmp); // 设置运行索引 m_MouseRecIndex = 0; } void VibraClick::OnHotKey(WPARAM nHotKeyId) { if (nHotKeyId == m_VibraClick_StartRec) { if (m_IsStartMouseRec) StopMouseRec(); else StartMouseRec(); } else if (nHotKeyId == m_VibraClick_RunRec) { if (m_IsStartRunMouseRec) StopRunMouseRec(); else StartRunMouseRec(); } } VOID CALLBACK TimerProc(HWND hwnd, UINT message, UINT nIDEvent, DWORD dwTime) { switch (nIDEvent) { case 999: { // 取余方式进行循环运行 int MouseRecIndex = VibraClick::GetInstance()->GetMouseRecIndex(); MouseRecIndex %= VibraClick::GetInstance()->GetMouseRecInputVector().size(); // 读取当前索引的鼠标模拟消息 auto pMHD = VibraClick::GetInstance()->GetMouseRecInputVector()[MouseRecIndex++]; // 通过INPUT进行模拟操作 INPUT Input; Input.type = pMHD->type; memcpy((void *)&Input.mi, (void *)&pMHD->mi, sizeof(MOUSEINPUT)); // 发送模拟消息 SendInput(1, &Input, sizeof(INPUT)); VibraClick::GetInstance()->SetMouseRecIndex(MouseRecIndex); } break; } } LRESULT CALLBACK MouseMessageProc(INT nCode, WPARAM wParam, LPARAM lParam) { PMSLLHOOKSTRUCT pStruct = (PMSLLHOOKSTRUCT)lParam; // LLMHF_INJECTED标志着: 事件是否被注入,通过SendInput后会触发这个标志,也就是模拟的处理消息则不记录了 // nCode 表示有关Hook的消息 /* * Hook Codes * * #define HC_ACTION 0 * #define HC_GETNEXT 1 * #define HC_SKIP 2 * #define HC_NOREMOVE 3 * #define HC_NOREM HC_NOREMOVE * #define HC_SYSMODALON 4 * #define HC_SYSMODALOFF 5 */ if (nCode < 0 || pStruct->flags & LLMHF_INJECTED) { return CallNextHookEx(VibraClick::GetInstance()->GetHHMouseHook(), nCode, wParam, lParam); } // 是否开启录制鼠标操作 if (!VibraClick::GetInstance()->IsStartMouseRec()) return CallNextHookEx(VibraClick::GetInstance()->GetHHMouseHook(), nCode, wParam, lParam); // 判断是否为鼠标数据, 当前只是列举一部分的鼠标消息,有需要可以自己加哈~ if ( wParam == WM_LBUTTONDOWN || wParam == WM_LBUTTONUP || wParam == WM_RBUTTONDOWN || wParam == WM_RBUTTONUP || wParam == WM_MBUTTONDOWN || wParam == WM_MBUTTONUP || wParam == WM_MOUSEMOVE) { MouseRecInput *Input = new MouseRecInput; // 现在固定为鼠标的模拟输入 Input->type = INPUT_MOUSE; // 设置输入的数据 Input->mi.dx = pStruct->pt.x; Input->mi.dy = pStruct->pt.y; Input->mi.mouseData = pStruct->mouseData; Input->mi.time = pStruct->time; Input->mi.dwExtraInfo = pStruct->dwExtraInfo; switch (wParam) { case WM_LBUTTONDOWN: Input->mi.dwFlags = MOUSEEVENTF_LEFTDOWN; break; case WM_LBUTTONUP: Input->mi.dwFlags = MOUSEEVENTF_LEFTUP; break; case WM_RBUTTONDOWN: Input->mi.dwFlags = MOUSEEVENTF_RIGHTDOWN; break; case WM_RBUTTONUP: Input->mi.dwFlags = MOUSEEVENTF_RIGHTUP; break; case WM_MBUTTONDOWN: Input->mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN; break; case WM_MBUTTONUP: Input->mi.dwFlags = MOUSEEVENTF_MIDDLEUP; break; case WM_MOUSEMOVE: { int cx_screen = ::GetSystemMetrics(SM_CXSCREEN); int cy_screen = ::GetSystemMetrics(SM_CYSCREEN); Input->mi.dx = pStruct->pt.x * 65536 / cx_screen; Input->mi.dy = pStruct->pt.y * 65536 / cy_screen; Input->mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; } break; } VibraClick::GetInstance()->GetMouseRecInputVector().push_back(Input); } return CallNextHookEx(VibraClick::GetInstance()->GetHHMouseHook(), nCode, wParam, lParam); }
简单讲解上面的内容:
1. 对静态的_inst进行一个初始化,做这个主要是在Hook和定时器中进行使用到这个按键模拟器
2. 初始化的时候进行保存窗口的句柄,然后进行注册热键和定时器的使用
3. 讲一下这个HOOK的MOUSEMOVE,鼠标点击的x和y坐标需要转换到绝对位置,屏幕的全屏范围是 0~65535,所以需要用当前的电脑分辨率进行转换到绝对的位置
最后PS:这个按键模拟器没有按钮,所以目前只能靠热键进行模拟
分别是:
CTRL + S 开启和关闭录制
CTRL + R 运行模拟
后续有需求可以下方留言,到时候在补充吧~~~
源码:已上传到Github了哦,有兴趣的读者可以去下载了~

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/54161.html