在window上使用c++控制鼠标点击,实现的exe
上代码编译方式在代码中已经提示。/** * 后台自动点击工具 v3 - 增加坐标拾取功能 * 基于 Win32 API Interception 驱动 * * 编译MSVC * cl autoclicker_v3.cpp interception.lib user32.lib gdi32.lib comctl32.lib /subsystem:windows * * 编译MinGW * g autoclicker_v3.cpp -L. -linterception -luser32 -lgdi32 -lcomctl32 -mwindows -o AutoClicker.exe */ #define UNICODE #define _UNICODE #define WIN32_LEAN_AND_MEAN #include windows.h #include commctrl.h #include string #include atomic #include vector #include fstream #include sstream #include algorithm #include interception.h #pragma comment(lib, comctl32.lib) #pragma comment(lib, user32.lib) #pragma comment(lib, gdi32.lib) // ─── 控件 ID ────────────────────────────────────────────────────────────────── #define ID_BTN_START 101 #define ID_BTN_STOP 102 #define ID_BTN_ADD 103 #define ID_BTN_CLEAR 104 #define ID_BTN_SAVE 105 #define ID_BTN_PICK 106 // 坐标拾取按钮 #define ID_EDIT_X 201 #define ID_EDIT_Y 202 #define ID_EDIT_INTERVAL 203 #define ID_EDIT_REPEAT 204 #define ID_COMBO_BUTTON 205 #define ID_EDIT_SCHED_H 206 #define ID_EDIT_SCHED_M 207 #define ID_EDIT_SCHED_S 208 #define ID_CHECK_SCHED 209 #define ID_LIST_TASKS 301 #define ID_STATUS 401 #define ID_TIMER_COUNTDOWN 1001 #define ID_TIMER_PICK 1002 // 拾取时的轮询定时器 #define WM_UPDATE_STATUS (WM_USER 100) // 自定义消息更新状态栏 #define WM_TASK_COMPLETED (WM_USER 101) // 自定义消息任务完成 // ─── 颜色 ──────────────────────────────────────────────────────────────────── #define CLR_BG RGB(18, 18, 24) #define CLR_PANEL RGB(28, 28, 38) #define CLR_ACCENT RGB(99, 179, 237) #define CLR_TEXT RGB(220, 220, 235) #define CLR_SUBTEXT RGB(120, 120, 145) #define CLR_BORDER RGB(50, 50, 68) #define CLR_YELLOW RGB(255, 214, 90) #define CLR_GREEN RGB(72, 199, 142) #define CONFIG_FILE Lautoclicker.cfg // ─── 任务结构 ───────────────────────────────────────────────────────────────── struct ClickTask { int x, y; int interval_ms; int repeat; bool right_btn; }; // ─── 全局状态 ───────────────────────────────────────────────────────────────── HWND g_hwnd; HWND g_hList, g_hStatus; HWND g_hEditX, g_hEditY, g_hEditInterval, g_hEditRepeat, g_hComboBtn; HWND g_hBtnStart, g_hBtnStop, g_hBtnSave, g_hBtnPick; HWND g_hSchedH, g_hSchedM, g_hSchedS, g_hCheckSched; std::vectorClickTask g_tasks; std::atomicbool g_running(false); std::atomicbool g_picking(false); // 是否处于坐标拾取模式 HANDLE g_worker nullptr; InterceptionContext g_ctx NULL; InterceptionDevice g_device INTERCEPTION_MOUSE(0); HFONT g_fontMain, g_fontMono, g_fontTitle, g_fontSmall; HBRUSH g_brBg, g_brPanel; // ─── Interception ───────────────────────────────────────────────────────────── void ic_click(bool right_btn) { if (!g_ctx) return; InterceptionMouseStroke s {}; s.state right_btn ? INTERCEPTION_MOUSE_RIGHT_BUTTON_DOWN : INTERCEPTION_MOUSE_LEFT_BUTTON_DOWN; interception_send(g_ctx, g_device, (InterceptionStroke*)s, 1); Sleep(8); s.state right_btn ? INTERCEPTION_MOUSE_RIGHT_BUTTON_UP : INTERCEPTION_MOUSE_LEFT_BUTTON_UP; interception_send(g_ctx, g_device, (InterceptionStroke*)s, 1); } void ic_move(int x, int y) { if (!g_ctx) return; int sw GetSystemMetrics(SM_CXSCREEN); int sh GetSystemMetrics(SM_CYSCREEN); InterceptionMouseStroke s {}; s.state INTERCEPTION_MOUSE_MOVE_ABSOLUTE; s.x (x * 65535) / sw; s.y (y * 65535) / sh; interception_send(g_ctx, g_device, (InterceptionStroke*)s, 1); } // ─── 工具函数 ───────────────────────────────────────────────────────────────── int GetEditInt(HWND h, int def 0) { wchar_t buf[32]; GetWindowTextW(h, buf, 32); try { return std::stoi(buf); } catch (...) { return def; } } void SetEditInt(HWND h, int val) { SetWindowTextW(h, std::to_wstring(val).c_str()); } // ─── 保存 / 加载配置 ────────────────────────────────────────────────────────── static std::string wstring_to_string(const std::wstring wstr) { int size_needed WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.size(), NULL, 0, NULL, NULL); std::string str(size_needed, 0); WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.size(), str[0], size_needed, NULL, NULL); return str; } void SaveConfig() { std::string filename wstring_to_string(CONFIG_FILE); std::wofstream f(filename.c_str()); if (!f) return; f Lsched_enabled (IsDlgButtonChecked(g_hwnd, ID_CHECK_SCHED) ? 1 : 0) L\n; f Lsched_h GetEditInt(g_hSchedH) L\n; f Lsched_m GetEditInt(g_hSchedM) L\n; f Lsched_s GetEditInt(g_hSchedS) L\n; f Ltask_count g_tasks.size() L\n; for (int i 0; i (int)g_tasks.size(); i) { auto t g_tasks[i]; f Ltask_ i L t.x L, t.y L, t.interval_ms L, t.repeat L, (t.right_btn ? 1 : 0) L\n; } SetWindowTextW(g_hStatus, L✓ 配置已保存); } void LoadConfig() { std::string filename wstring_to_string(CONFIG_FILE); std::wifstream f(filename.c_str()); if (!f) return; std::wstring line; g_tasks.clear(); while (std::getline(f, line)) { auto sep line.find(L); if (sep std::wstring::npos) continue; std::wstring key line.substr(0, sep); std::wstring val line.substr(sep 1); auto wi [](const std::wstring v, int d 0) - int { try { return std::stoi(v); } catch (...) { return d; } }; if (key Lsched_enabled) CheckDlgButton(g_hwnd, ID_CHECK_SCHED, wi(val) ? BST_CHECKED : BST_UNCHECKED); else if (key Lsched_h) SetWindowTextW(g_hSchedH, val.c_str()); else if (key Lsched_m) SetWindowTextW(g_hSchedM, val.c_str()); else if (key Lsched_s) SetWindowTextW(g_hSchedS, val.c_str()); else if (key.substr(0, 5) Ltask_) { std::wistringstream ss(val); std::wstring tok; std::vectorint nums; while (std::getline(ss, tok, L,)) nums.push_back(wi(tok)); if (nums.size() 5) { ClickTask t; t.x nums[0]; t.y nums[1]; t.interval_ms nums[2]; t.repeat nums[3]; t.right_btn nums[4] ! 0; g_tasks.push_back(t); } } } } // ─── 刷新任务列表 ───────────────────────────────────────────────────────────── void RefreshList() { SendMessageW(g_hList, LB_RESETCONTENT, 0, 0); for (int i 0; i (int)g_tasks.size(); i) { auto t g_tasks[i]; std::wstring line L# std::to_wstring(i 1) L ( std::to_wstring(t.x) L, std::to_wstring(t.y) L) L std::to_wstring(t.interval_ms) Lms L × (t.repeat -1 ? L∞ : std::to_wstring(t.repeat)) L (t.right_btn ? L右键 : L左键); SendMessageW(g_hList, LB_ADDSTRING, 0, (LPARAM)line.c_str()); } } // ─── 坐标拾取开始 ─────────────────────────────────────────────────────────── void StartPicking() { g_picking true; SetWindowTextW(g_hBtnPick, L 拾取中...); SetWindowTextW(g_hStatus, L▶ 请点击目标位置左键或右键均可 ESC 取消); // 每 50ms 轮询一次鼠标按键状态 SetTimer(g_hwnd, ID_TIMER_PICK, 50, NULL); } // ─── 坐标拾取结束 ─────────────────────────────────────────────────────────── void StopPicking(bool cancelled false) { g_picking false; KillTimer(g_hwnd, ID_TIMER_PICK); SetWindowTextW(g_hBtnPick, L 拾取坐标); if (cancelled) SetWindowTextW(g_hStatus, L拾取已取消); } // ─── 倒计时显示 ─────────────────────────────────────────────────────────────── void UpdateCountdown() { if (g_running || g_picking) return; if (!IsDlgButtonChecked(g_hwnd, ID_CHECK_SCHED)) return; SYSTEMTIME now; GetLocalTime(now); int target GetEditInt(g_hSchedH) * 3600 GetEditInt(g_hSchedM) * 60 GetEditInt(g_hSchedS); int cur now.wHour * 3600 now.wMinute * 60 now.wSecond; int diff target - cur; if (diff 0) diff 86400; wchar_t buf[64]; swprintf_s(buf, L等待定时启动 还剩 %02d:%02d:%02d, diff/3600, (diff%3600)/60, diff%60); SetWindowTextW(g_hStatus, buf); } // ─── 工作线程 ───────────────────────────────────────────────────────────────── DWORD WINAPI worker_thread(LPVOID) { if (IsDlgButtonChecked(g_hwnd, ID_CHECK_SCHED)) { while (g_running) { SYSTEMTIME now; GetLocalTime(now); if (now.wHour GetEditInt(g_hSchedH) now.wMinute GetEditInt(g_hSchedM) now.wSecond GetEditInt(g_hSchedS)) break; Sleep(500); } } if (!g_running) return 0; int total 0; for (auto task : g_tasks) { if (!g_running) break; int count 0; while (g_running (task.repeat -1 || count task.repeat)) { ic_move(task.x, task.y); Sleep(15); ic_click(task.right_btn); count; total; // 减少状态栏更新频率通过消息队列更新 static int last_update 0; if (total - last_update 10) { PostMessageW(g_hwnd, WM_UPDATE_STATUS, total, 0); last_update total; } for (int i 0; i task.interval_ms g_running; i 50) Sleep(std::min(50, task.interval_ms - i)); } } g_running false; PostMessageW(g_hwnd, WM_TASK_COMPLETED, 0, 0); return 0; } // ─── 窗口过程 ───────────────────────────────────────────────────────────────── LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { switch (msg) { case WM_CREATE: { g_fontTitle CreateFontW(20, 0, 0, 0, FW_BOLD, 0,0,0, DEFAULT_CHARSET,0,0, CLEARTYPE_QUALITY,0, LSegoe UI); g_fontMain CreateFontW(15, 0, 0, 0, FW_NORMAL, 0,0,0, DEFAULT_CHARSET,0,0, CLEARTYPE_QUALITY,0, LSegoe UI); g_fontSmall CreateFontW(13, 0, 0, 0, FW_NORMAL, 0,0,0, DEFAULT_CHARSET,0,0, CLEARTYPE_QUALITY,0, LSegoe UI); g_fontMono CreateFontW(14, 0, 0, 0, FW_NORMAL, 0,0,0, DEFAULT_CHARSET,0,0, CLEARTYPE_QUALITY,0, LConsolas); g_brBg CreateSolidBrush(CLR_BG); g_brPanel CreateSolidBrush(CLR_PANEL); auto MkLabel [](const wchar_t* t, int x, int y, int w, HFONT f NULL) { HWND h CreateWindowW(LSTATIC, t, WS_CHILD|WS_VISIBLE, x, y, w, 18, hwnd, NULL, NULL, NULL); SendMessageW(h, WM_SETFONT, (WPARAM)(f?f:g_fontSmall), TRUE); return h; }; auto MkEdit [](int id, int x, int y, int w, const wchar_t* def, DWORD extra ES_NUMBER) { HWND h CreateWindowW(LEDIT, def, WS_CHILD|WS_VISIBLE|WS_BORDER|extra, x, y, w, 24, hwnd, (HMENU)(INT_PTR)id, NULL, NULL); SendMessageW(h, WM_SETFONT, (WPARAM)g_fontMain, TRUE); return h; }; auto MkBtn [](const wchar_t* t, int id, int x, int y, int w, int h_28) { HWND h CreateWindowW(LBUTTON, t, WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, x, y, w, h_, hwnd, (HMENU)(INT_PTR)id, NULL, NULL); SendMessageW(h, WM_SETFONT, (WPARAM)g_fontMain, TRUE); return h; }; // ── 定时区 ────────────────────────────────────────────────────── MkLabel(L定时启动, 20, 52, 70, g_fontMain); g_hCheckSched CreateWindowW(LBUTTON, L启用定时, WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, 100, 51, 80, 18, hwnd, (HMENU)ID_CHECK_SCHED, NULL, NULL); SendMessageW(g_hCheckSched, WM_SETFONT, (WPARAM)g_fontSmall, TRUE); g_hSchedH MkEdit(ID_EDIT_SCHED_H, 185, 52, 38, L12); MkLabel(L时, 185385, 52, 14); g_hSchedM MkEdit(ID_EDIT_SCHED_M, 18538514, 52, 38, L00); MkLabel(L分, 18538514385, 52, 14); g_hSchedS MkEdit(ID_EDIT_SCHED_S, 18538514385145, 52, 38, L00); MkLabel(L秒, 18538514385145385, 52, 14); MkLabel(L( 24小时制 ), 18538514385145385145, 52, 100, g_fontSmall); // ── 坐标拾取区 ────────────────────────────────────────────────── MkLabel(LX 坐标, 20, 108, 55); MkLabel(LY 坐标, 95, 108, 55); g_hEditX MkEdit(ID_EDIT_X, 20, 126, 65, L500); g_hEditY MkEdit(ID_EDIT_Y, 95, 126, 65, L400); // 拾取按钮放在 XY 旁边 g_hBtnPick MkBtn(L 拾取坐标, ID_BTN_PICK, 172, 124, 110, 28); MkLabel(L间隔ms, 295, 108, 65); MkLabel(L次数(0∞), 370, 108, 80); MkLabel(L按键, 458, 108, 45); g_hEditInterval MkEdit(ID_EDIT_INTERVAL, 295, 126, 65, L1000); g_hEditRepeat MkEdit(ID_EDIT_REPEAT, 370, 126, 75, L10); g_hComboBtn CreateWindowW(LCOMBOBOX, NULL, WS_CHILD|WS_VISIBLE|CBS_DROPDOWNLIST, 458, 124, 60, 80, hwnd, (HMENU)ID_COMBO_BUTTON, NULL, NULL); SendMessageW(g_hComboBtn, WM_SETFONT, (WPARAM)g_fontMain, TRUE); SendMessageW(g_hComboBtn, CB_ADDSTRING, 0, (LPARAM)L左键); SendMessageW(g_hComboBtn, CB_ADDSTRING, 0, (LPARAM)L右键); SendMessageW(g_hComboBtn, CB_SETCURSEL, 0, 0); // ── 按钮行 ────────────────────────────────────────────────────── MkBtn(L➕ 添加, ID_BTN_ADD, 20, 166, 85); MkBtn(L 清空, ID_BTN_CLEAR, 115, 166, 85); g_hBtnSave MkBtn(L 保存, ID_BTN_SAVE, 210, 166, 85); g_hBtnStart MkBtn(L▶ 开始, ID_BTN_START, 320, 166, 80); g_hBtnStop MkBtn(L■ 停止, ID_BTN_STOP, 410, 166, 80); EnableWindow(g_hBtnStop, FALSE); // ── 任务列表 ──────────────────────────────────────────────────── g_hList CreateWindowW(LLISTBOX, NULL, WS_CHILD|WS_VISIBLE|WS_BORDER|WS_VSCROLL|LBS_NOSEL, 20, 206, 500, 130, hwnd, (HMENU)ID_LIST_TASKS, NULL, NULL); SendMessageW(g_hList, WM_SETFONT, (WPARAM)g_fontMono, TRUE); // ── 状态栏 ────────────────────────────────────────────────────── g_hStatus CreateWindowW(LSTATIC, L初始化中..., WS_CHILD|WS_VISIBLE|SS_LEFT, 20, 350, 500, 18, hwnd, (HMENU)ID_STATUS, NULL, NULL); SendMessageW(g_hStatus, WM_SETFONT, (WPARAM)g_fontSmall, TRUE); // ── 初始化驱动 ────────────────────────────────────────────────── g_ctx interception_create_context(); SetWindowTextW(g_hStatus, g_ctx ? L✓ Interception 驱动已连接 | F8 紧急停止 : L⚠ 驱动未找到请安装 Interception 后重启); LoadConfig(); RefreshList(); SetTimer(hwnd, ID_TIMER_COUNTDOWN, 1000, NULL); RegisterHotKey(hwnd, 1, 0, VK_F8); break; } case WM_TIMER: { if (wp ID_TIMER_COUNTDOWN) { UpdateCountdown(); } else if (wp ID_TIMER_PICK g_picking) { // 实时显示当前鼠标坐标 POINT pt; GetCursorPos(pt); wchar_t buf[80]; swprintf_s(buf, L 拾取中 当前坐标: (%d, %d) — 点击任意键确认 ESC取消, pt.x, pt.y); SetWindowTextW(g_hStatus, buf); // 检测左键或右键按下 bool left_down (GetAsyncKeyState(VK_LBUTTON) 0x8000) ! 0; bool right_down (GetAsyncKeyState(VK_RBUTTON) 0x8000) ! 0; bool esc (GetAsyncKeyState(VK_ESCAPE) 0x8000) ! 0; if (esc) { StopPicking(true); } else if (left_down || right_down) { // 捕获坐标写入输入框 SetEditInt(g_hEditX, pt.x); SetEditInt(g_hEditY, pt.y); // 同步设置按键下拉 SendMessageW(g_hComboBtn, CB_SETCURSEL, right_down ? 1 : 0, 0); StopPicking(false); wchar_t done[64]; swprintf_s(done, L✓ 已拾取坐标 (%d, %d) %s, pt.x, pt.y, right_down ? L右键 : L左键); SetWindowTextW(g_hStatus, done); // 短暂等待避免立刻再次触发 Sleep(300); } } break; } case WM_UPDATE_STATUS: { wchar_t buf[64]; swprintf_s(buf, L运行中 已点击: %d 次, (int)wp); SetWindowTextW(g_hStatus, buf); break; } case WM_TASK_COMPLETED: { SetWindowTextW(g_hStatus, L✓ 已完成); EnableWindow(g_hBtnStart, TRUE); EnableWindow(g_hBtnStop, FALSE); break; } case WM_COMMAND: { int id LOWORD(wp); if (id ID_BTN_PICK) { if (!g_picking) StartPicking(); else StopPicking(true); } if (id ID_BTN_ADD) { int rep GetEditInt(g_hEditRepeat, 10); if (rep 0) rep 0; if (rep 100) rep 100; ClickTask t; t.x GetEditInt(g_hEditX, 500); t.y GetEditInt(g_hEditY, 400); t.interval_ms GetEditInt(g_hEditInterval, 1000); t.repeat (rep 0) ? -1 : rep; t.right_btn SendMessageW(g_hComboBtn, CB_GETCURSEL, 0, 0) 1; g_tasks.push_back(t); RefreshList(); } if (id ID_BTN_CLEAR) { g_tasks.clear(); RefreshList(); } if (id ID_BTN_SAVE) { SaveConfig(); } if (id ID_BTN_START !g_running !g_tasks.empty()) { g_running true; EnableWindow(g_hBtnStart, FALSE); EnableWindow(g_hBtnStop, TRUE); if (!IsDlgButtonChecked(g_hwnd, ID_CHECK_SCHED)) SetWindowTextW(g_hStatus, L运行中...); if (g_worker) { WaitForSingleObject(g_worker, INFINITE); CloseHandle(g_worker); g_worker nullptr; } g_worker CreateThread(NULL, 0, worker_thread, NULL, 0, NULL); } if (id ID_BTN_STOP) { g_running false; EnableWindow(g_hBtnStart, TRUE); EnableWindow(g_hBtnStop, FALSE); SetWindowTextW(g_hStatus, L已停止); } break; } case WM_HOTKEY: if (wp 1) { if (g_picking) { StopPicking(true); } else if (g_running) { g_running false; EnableWindow(g_hBtnStart, TRUE); EnableWindow(g_hBtnStop, FALSE); SetWindowTextW(g_hStatus, L已停止F8); } } break; case WM_CTLCOLORSTATIC: case WM_CTLCOLOREDIT: case WM_CTLCOLORLISTBOX: { HDC hdc (HDC)wp; SetTextColor(hdc, CLR_TEXT); SetBkColor(hdc, CLR_PANEL); return (LRESULT)g_brPanel; } case WM_CTLCOLORBTN: { HDC hdc (HDC)wp; SetTextColor(hdc, CLR_TEXT); SetBkColor(hdc, CLR_PANEL); return (LRESULT)g_brPanel; } case WM_PAINT: { PAINTSTRUCT ps; HDC hdc BeginPaint(hwnd, ps); RECT rc; GetClientRect(hwnd, rc); FillRect(hdc, rc, g_brBg); RECT title {0, 0, rc.right, 40}; FillRect(hdc, title, g_brPanel); SetBkMode(hdc, TRANSPARENT); SelectObject(hdc, g_fontTitle); SetTextColor(hdc, CLR_ACCENT); TextOutW(hdc, 16, 10, L⚡ AutoClicker v3, 17); SelectObject(hdc, g_fontSmall); SetTextColor(hdc, CLR_SUBTEXT); TextOutW(hdc, 210, 14, L坐标拾取 · 定时启动 · 配置保存, 17); HPEN pen CreatePen(PS_SOLID, 1, CLR_BORDER); HPEN old (HPEN)SelectObject(hdc, pen); auto Line [](int y){ MoveToEx(hdc,0,y,NULL); LineTo(hdc,rc.right,y); }; Line(40); Line(96); Line(160); Line(200); Line(340); SelectObject(hdc, old); DeleteObject(pen); SetTextColor(hdc, CLR_SUBTEXT); SelectObject(hdc, g_fontSmall); TextOutW(hdc, 20, 344, LF8 紧急停止 / 取消拾取 | 配置保存至 autoclicker.cfg, 28); EndPaint(hwnd, ps); break; } case WM_ERASEBKGND: return 1; case WM_DESTROY: g_running false; g_picking false; KillTimer(hwnd, ID_TIMER_COUNTDOWN); KillTimer(hwnd, ID_TIMER_PICK); if (g_worker) { WaitForSingleObject(g_worker, INFINITE); CloseHandle(g_worker); g_worker nullptr; } if (g_ctx) interception_destroy_context(g_ctx); UnregisterHotKey(hwnd, 1); DeleteObject(g_fontMain); DeleteObject(g_fontMono); DeleteObject(g_fontTitle); DeleteObject(g_fontSmall); DeleteObject(g_brBg); DeleteObject(g_brPanel); PostQuitMessage(0); break; } return DefWindowProcW(hwnd, msg, wp, lp); } // ─── 入口 ───────────────────────────────────────────────────────────────────── int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int) { INITCOMMONCONTROLSEX icex; icex.dwSize sizeof(icex); icex.dwICC ICC_WIN95_CLASSES; InitCommonControlsEx(icex); WNDCLASSW wc {}; wc.lpfnWndProc WndProc; wc.hInstance hInst; wc.lpszClassName LAutoClickerV3; wc.hCursor LoadCursor(NULL, IDC_ARROW); wc.hbrBackground CreateSolidBrush(CLR_BG); RegisterClassW(wc); g_hwnd CreateWindowExW(WS_EX_APPWINDOW, LAutoClickerV3, LAutoClicker v3, WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, 545, 390, NULL, NULL, hInst, NULL); ShowWindow(g_hwnd, SW_SHOW); UpdateWindow(g_hwnd); MSG msg; while (GetMessageW(msg, NULL, 0, 0)) { TranslateMessage(msg); DispatchMessageW(msg); } return 0; }