dev-c++需要链接
-std=c++14 -lcomctl32 -lgdiplus -lwinmm -mwindows
代码
#define WINVER 0x0600
#define _WIN32_WINNT 0x0600
#include <windows.h>
#include <commctrl.h>
#include <atomic>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <random>
#include <vector>
#include <string>
#include <sstream>
#include <tuple>
#include <mmsystem.h>
#include <algorithm>
#include <cctype>
#include <mutex>
#include <chrono>
#include <gdiplus.h>
#include <shellapi.h>
#include <iostream>
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#pragma comment(lib, "comctl32.lib")
#pragma comment(lib, "gdiplus.lib")
#ifdef _MSC_VER
#pragma comment(lib, "winmm.lib")
#endif
using namespace std;
using namespace Gdiplus;
void SetDPIAwareness() {
HMODULE hUser32 = GetModuleHandleW(L"user32.dll");
if (hUser32) {
typedef BOOL (WINAPI *SetDPIAwarenessContextFunc)(PVOID);
SetDPIAwarenessContextFunc pV2 = (SetDPIAwarenessContextFunc)GetProcAddress(hUser32, "SetProcessDPIAwarenessContext");
if (pV2) { if (pV2((PVOID)-4)) return; }
}
HMODULE hShcore = LoadLibraryW(L"Shcore.dll");
if (hShcore) {
typedef HRESULT (WINAPI *SetDPIAwarenessFunc)(int);
SetDPIAwarenessFunc pPerMonitor = (SetDPIAwarenessFunc)GetProcAddress(hShcore, "SetProcessDpiAwareness");
if (pPerMonitor) { if (SUCCEEDED(pPerMonitor(2))) { FreeLibrary(hShcore); return; } }
FreeLibrary(hShcore);
}
if (hUser32) {
typedef BOOL (WINAPI *SetDPIAwareFunc)();
SetDPIAwareFunc pOld = (SetDPIAwareFunc)GetProcAddress(hUser32, "SetProcessDPIAware");
if (pOld) pOld();
}
}
atomic<bool> g_ic(false);
atomic<bool> g_se(false);
atomic<int> g_cd(100);
atomic<int> g_cc(0);
atomic<double> g_cps(0.0);
atomic<int> g_cb(0);
atomic<bool> g_em(false);
atomic<bool> g_je(false);
atomic<int> g_jr(10);
atomic<bool> g_seq(false);
vector<pair<int,int>> g_pts;
atomic<bool> g_rec(false);
atomic<bool> g_ply(false);
atomic<int> g_ps(50);
struct RecordedEvent {
int type, x, y, data, time;
bool isRelative;
};
vector<RecordedEvent> g_evt;
HHOOK g_mh = nullptr;
HANDLE g_hPlay = nullptr;
int g_lmt = 0;
HHOOK g_kh = nullptr;
HWND g_hM = nullptr;
HWND g_hS = nullptr;
HWND g_hC = nullptr;
HWND g_hP = nullptr;
HWND g_hDE = nullptr;
HWND g_hDL = nullptr;
HWND g_hBC = nullptr;
HWND g_hJC = nullptr;
HWND g_hJE = nullptr;
HWND g_hSC = nullptr;
HWND g_hSE = nullptr;
HWND g_hRB = nullptr;
HWND g_hPB = nullptr;
HWND g_hSS = nullptr;
HWND g_hSB = nullptr;
HWND g_hTB = nullptr;
HWND g_hEB = nullptr;
HWND g_hRC = nullptr;
HWND g_hME = nullptr;
HWND g_hMC = nullptr;
HWND g_hMI = nullptr;
HWND g_hMB = nullptr;
HWND g_hMS = nullptr;
HWND g_hMac = nullptr;
HFONT g_fS = nullptr;
HFONT g_fN = nullptr;
HBRUSH g_bW = nullptr;
HBRUSH g_bS = nullptr;
bool g_rel = true;
bool g_recPend = false;
int g_cdSec = 3;
UINT g_cdTimer = 1004;
int g_curCd = 0;
bool g_mpAct = false;
int g_mpCnt = 5;
int g_mpInt = 100;
int g_mpBtn = 0;
HHOOK g_mpHook = nullptr;
HWND g_hOv = nullptr;
atomic<bool> g_mpStop(false);
mutex g_mpMtx;
bool g_mpBusy = false;
HWND g_hMacW = nullptr;
bool g_macRec = false;
bool g_macPlay = false;
vector<RecordedEvent> g_macEvt;
HHOOK g_macMH = nullptr;
HHOOK g_macKH = nullptr;
HANDLE g_macThr = nullptr;
int g_macSpeed = 50;
bool g_macLoop = false;
bool g_macMove = false;
HWND g_hMacL = nullptr;
HWND g_hMacPB = nullptr;
atomic<bool> g_macStop(false);
mutex g_macMtx;
#define HOTKEY_F6 1
#define HOTKEY_ESC 2
#define HOTKEY_F7 3
#define WM_TRAYICON (WM_USER + 100)
#define TIMER_CPS 1003
#define WM_ADD_COORD (WM_USER + 2)
#define WM_MACRO_UPDATE (WM_USER + 4)
#define WM_EXECUTE_CMD (WM_USER + 5)
#define TRAY_SHOW 5001
#define TRAY_HIDE 5002
#define TRAY_TOGGLE 5003
#define TRAY_EXIT 5004
bool g_init = false;
bool g_tray = false;
NOTIFYICONDATAA g_nid = {};
HICON g_icon = nullptr;
bool g_hookHot = false;
thread_local mt19937 rng((unsigned int)time(nullptr) ^ (unsigned int)GetCurrentThreadId());
int GetJitterOffset(int range) {
if (range <= 0) return 0;
uniform_int_distribution<int> dist(-range, range);
return dist(rng);
}
HICON LoadCustomIcon() {
HICON hIcon = (HICON)LoadImageA(GetModuleHandleA(nullptr), "clicker.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
if (hIcon) return hIcon;
hIcon = (HICON)LoadImageA(GetModuleHandleA(nullptr), MAKEINTRESOURCEA(101), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
if (hIcon) return hIcon;
return LoadIconA(nullptr, IDI_APPLICATION);
}
void UpdateDelayDisplay() {
char buf[32]; sprintf(buf, "当前: %d ms", g_cd.load());
SetWindowTextA(g_hDL, buf);
}
void UpdateUI() {
bool running = g_ic.load();
SetWindowTextA(g_hS, running ? "● 运行中" : "● 已停止");
InvalidateRect(g_hS, nullptr, TRUE);
EnableWindow(g_hSB, !running);
EnableWindow(g_hTB, running);
UpdateDelayDisplay();
EnableWindow(g_hSC, !running);
EnableWindow(g_hSE, !running);
}
void UpdateCount() {
if (g_em.load()) {
SetWindowTextA(g_hC, "极速模式");
SetWindowTextA(g_hP, "无统计");
return;
}
char buf[64]; sprintf(buf, "已点击: %d 次", g_cc.load());
SetWindowTextA(g_hC, buf);
}
void UpdateCPSDisplay() {
if (g_em.load()) {
SetWindowTextA(g_hP, "无统计");
return;
}
char buf[32]; sprintf(buf, "CPS: %.1f", g_cps.load());
SetWindowTextA(g_hP, buf);
}
void usSleep(long long us) {
if (us <= 0) return;
if (us > 2000) { Sleep((DWORD)(us / 1000)); return; }
LARGE_INTEGER freq, start, now;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&start);
long long elapsed = 0;
while (elapsed < us) {
QueryPerformanceCounter(&now);
elapsed = (now.QuadPart - start.QuadPart) * 1000000 / freq.QuadPart;
if (elapsed >= us) break;
long long remaining = us - elapsed;
if (remaining > 500) SwitchToThread();
}
}
void SimulateClick(int x, int y, int button) {
SetCursorPos(x, y);
INPUT input[2] = {};
input[0].type = INPUT_MOUSE;
input[1].type = INPUT_MOUSE;
switch (button) {
case 0: input[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN; input[1].mi.dwFlags = MOUSEEVENTF_LEFTUP; break;
case 1: input[0].mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN; input[1].mi.dwFlags = MOUSEEVENTF_MIDDLEUP; break;
case 2: input[0].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN; input[1].mi.dwFlags = MOUSEEVENTF_RIGHTUP; break;
}
SendInput(2, input, sizeof(INPUT));
}
void ParseCoordinates(const string& str) {
g_pts.clear();
string s = str;
s.erase(remove_if(s.begin(), s.end(), ::isspace), s.end());
size_t pos = 0;
while ((pos = s.find(';')) != string::npos) {
string token = s.substr(0, pos);
s.erase(0, pos + 1);
int comma = token.find(',');
if (comma != string::npos) {
g_pts.push_back({atoi(token.substr(0, comma).c_str()), atoi(token.substr(comma+1).c_str())});
}
}
if (!s.empty()) {
int comma = s.find(',');
if (comma != string::npos) {
g_pts.push_back({atoi(s.substr(0, comma).c_str()), atoi(s.substr(comma+1).c_str())});
}
}
}
void ToggleRecording();
void StartRecordingActual();
void StopRecording();
void PrintCommandHelp() {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if (hConsole == INVALID_HANDLE_VALUE) {
AllocConsole();
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
}
if (hConsole != INVALID_HANDLE_VALUE) {
const char* help =
"自动连点器命令行选项:\n"
" --start, -s 启动连点\n"
" --stop, -t 停止连点\n"
" --toggle, -tg 切换连点状态\n"
" --delay <ms>, -d <ms> 设置点击间隔(毫秒)\n"
" --button <0|1|2>, -b 设置按键(0左,1中,2右)\n"
" --sequence <x,y;x,y> 设置序列坐标(分号分隔)\n"
" --enable-seq 启用序列模式\n"
" --disable-seq 禁用序列模式\n"
" --jitter <range>, -j 启用抖动并设置范围(像素)\n"
" --relative 使用相对窗口坐标\n"
" --absolute 使用绝对屏幕坐标\n"
" --show 显示主窗口\n"
" --hide 隐藏主窗口到托盘\n"
" --exit, -e 退出程序\n"
" --help, -h 显示此帮助(并退出)\n"
"\n示例:\n"
" clicker.exe --start --delay 50 --button 1\n"
" clicker.exe --sequence \"100,200;300,400\" --enable-seq\n"
" clicker.exe --exit\n";
DWORD written;
WriteConsoleA(hConsole, help, strlen(help), &written, NULL);
}
}
void ExecuteCommand(const string& cmd) {
vector<string> tokens;
string token;
bool inQuotes = false;
for (char c : cmd) {
if (c == '"') { inQuotes = !inQuotes; continue; }
if (isspace(c) && !inQuotes) {
if (!token.empty()) { tokens.push_back(token); token.clear(); }
} else {
token += c;
}
}
if (!token.empty()) tokens.push_back(token);
for (size_t i = 0; i < tokens.size(); ++i) {
string arg = tokens[i];
transform(arg.begin(), arg.end(), arg.begin(), ::tolower);
if (arg == "--start" || arg == "-s") {
g_ic = true;
UpdateUI();
strcpy(g_nid.szTip, "自动连点器 (运行中)");
Shell_NotifyIconA(NIM_MODIFY, &g_nid);
}
else if (arg == "--stop" || arg == "-t") {
g_ic = false;
UpdateUI();
UpdateCount();
strcpy(g_nid.szTip, "自动连点器 (已停止)");
Shell_NotifyIconA(NIM_MODIFY, &g_nid);
}
else if (arg == "--toggle" || arg == "-tg") {
bool running = g_ic.load();
g_ic = !running;
UpdateUI();
if (!running) UpdateCount();
strcpy(g_nid.szTip, g_ic.load() ? "自动连点器 (运行中)" : "自动连点器 (已停止)");
Shell_NotifyIconA(NIM_MODIFY, &g_nid);
}
else if ((arg == "--delay" || arg == "-d") && i+1 < tokens.size()) {
int val = atoi(tokens[++i].c_str());
if (val < 0) val = 0;
if (val > 10000) val = 10000;
g_cd = val;
g_em = (val == 0);
char tmp[16]; sprintf(tmp, "%d", val);
SetWindowTextA(g_hDE, tmp);
UpdateDelayDisplay();
if (!g_ic.load()) UpdateCount();
}
else if ((arg == "--button" || arg == "-b") && i+1 < tokens.size()) {
int val = atoi(tokens[++i].c_str());
if (val >= 0 && val <= 2) {
g_cb = val;
SendMessage(g_hBC, CB_SETCURSEL, val, 0);
}
}
else if ((arg == "--sequence" || arg == "-seq") && i+1 < tokens.size()) {
string seq = tokens[++i];
SetWindowTextA(g_hSE, seq.c_str());
ParseCoordinates(seq);
}
else if (arg == "--enable-seq") {
g_seq = true;
SendMessage(g_hSC, BM_SETCHECK, BST_CHECKED, 0);
}
else if (arg == "--disable-seq") {
g_seq = false;
SendMessage(g_hSC, BM_SETCHECK, BST_UNCHECKED, 0);
}
else if ((arg == "--jitter" || arg == "-j") && i+1 < tokens.size()) {
int range = atoi(tokens[++i].c_str());
if (range < 0) range = 0;
if (range > 100) range = 100;
g_jr = range;
g_je = (range > 0);
SendMessage(g_hJC, BM_SETCHECK, g_je.load() ? BST_CHECKED : BST_UNCHECKED, 0);
char tmp[16]; sprintf(tmp, "%d", range);
SetWindowTextA(g_hJE, tmp);
}
else if (arg == "--relative") {
g_rel = true;
SendMessage(g_hRC, BM_SETCHECK, BST_CHECKED, 0);
}
else if (arg == "--absolute") {
g_rel = false;
SendMessage(g_hRC, BM_SETCHECK, BST_UNCHECKED, 0);
}
else if (arg == "--show") {
ShowWindow(g_hM, SW_SHOW);
SetForegroundWindow(g_hM);
}
else if (arg == "--hide") {
ShowWindow(g_hM, SW_HIDE);
}
else if (arg == "--exit" || arg == "-e") {
PostMessage(g_hM, WM_DESTROY, 0, 0);
}
else if (arg == "--help" || arg == "-h") {
PrintCommandHelp();
}
}
}
void DoMultiPointClick(int x, int y, int button, int count, int interval) {
for (int i = 0; i < count; ++i) {
if (g_mpStop.load() || !g_mpAct) break;
SetCursorPos(x, y);
INPUT input[2] = {};
input[0].type = INPUT_MOUSE;
input[1].type = INPUT_MOUSE;
switch (button) {
case 0: input[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN; input[1].mi.dwFlags = MOUSEEVENTF_LEFTUP; break;
case 1: input[0].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN; input[1].mi.dwFlags = MOUSEEVENTF_RIGHTUP; break;
case 2: input[0].mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN; input[1].mi.dwFlags = MOUSEEVENTF_MIDDLEUP; break;
}
SendInput(2, input, sizeof(INPUT));
if (i < count - 1 && interval > 0) Sleep(interval);
}
}
DWORD WINAPI MultiPointClickThread(LPVOID lp) {
int* p = (int*)lp;
DoMultiPointClick(p[0], p[1], p[2], p[3], p[4]);
delete[] p;
return 0;
}
LRESULT CALLBACK MultiPointMouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= 0 && g_mpAct && !g_mpStop.load()) {
MSLLHOOKSTRUCT* p = (MSLLHOOKSTRUCT*)lParam;
bool match = false;
if (g_mpBtn == 0 && wParam == WM_LBUTTONDOWN) match = true;
else if (g_mpBtn == 1 && wParam == WM_RBUTTONDOWN) match = true;
else if (g_mpBtn == 2 && wParam == WM_MBUTTONDOWN) match = true;
if (match) {
lock_guard<mutex> lock(g_mpMtx);
if (g_mpBusy) return CallNextHookEx(g_mpHook, nCode, wParam, lParam);
g_mpBusy = true;
int* param = new int[5]{ p->pt.x, p->pt.y, g_mpBtn, g_mpCnt, g_mpInt };
HANDLE h = CreateThread(nullptr, 0, MultiPointClickThread, param, 0, nullptr);
if (h) CloseHandle(h);
Sleep(20);
g_mpBusy = false;
}
}
return CallNextHookEx(g_mpHook, nCode, wParam, lParam);
}
ULONG_PTR g_gdiTok;
LRESULT CALLBACK OverlayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE: {
HINSTANCE hInst = ((LPCREATESTRUCT)lParam)->hInstance;
CreateWindowA("BUTTON", "停止多点", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
10, 10, 80, 30, hwnd, (HMENU)3001, hInst, nullptr);
CreateWindowA("STATIC", "多点工作中...", WS_CHILD | WS_VISIBLE | SS_CENTER,
110, 10, 150, 30, hwnd, nullptr, hInst, nullptr);
SendMessage(GetDlgItem(hwnd, 3001), WM_SETFONT, (WPARAM)g_fN, TRUE);
SendMessage(GetDlgItem(hwnd, 3002), WM_SETFONT, (WPARAM)g_fN, TRUE);
break;
}
case WM_COMMAND:
if (LOWORD(wParam) == 3001) {
g_mpStop.store(true);
g_mpAct = false;
if (g_mpHook) { UnhookWindowsHookEx(g_mpHook); g_mpHook = nullptr; }
if (g_hOv) { DestroyWindow(g_hOv); g_hOv = nullptr; }
ShowWindow(g_hM, SW_SHOW);
if (g_hMacW) ShowWindow(g_hMacW, SW_SHOW);
SetWindowTextA(g_hME, "启用多点");
SetWindowTextA(g_hMS, "已停止");
EnableWindow(g_hMC, TRUE);
EnableWindow(g_hMI, TRUE);
EnableWindow(g_hMB, TRUE);
g_mpStop.store(false);
}
break;
case WM_ERASEBKGND: {
HDC hdc = (HDC)wParam;
RECT rc; GetClientRect(hwnd, &rc);
Graphics graphics(hdc);
GraphicsPath path;
int radius = 15;
path.AddArc(rc.left, rc.top, radius*2, radius*2, 180, 90);
path.AddArc(rc.right - radius*2, rc.top, radius*2, radius*2, 270, 90);
path.AddArc(rc.right - radius*2, rc.bottom - radius*2, radius*2, radius*2, 0, 90);
path.AddArc(rc.left, rc.bottom - radius*2, radius*2, radius*2, 90, 90);
path.CloseFigure();
Color color(180, 40, 40, 40);
SolidBrush brush(color);
graphics.FillPath(&brush, &path);
return 1;
}
case WM_NCHITTEST: {
POINT pt = { LOWORD(lParam), HIWORD(lParam) };
ScreenToClient(hwnd, &pt);
HWND hBtn = GetDlgItem(hwnd, 3001);
if (hBtn) {
RECT rcBtn; GetWindowRect(hBtn, &rcBtn);
MapWindowPoints(HWND_DESKTOP, hwnd, (LPPOINT)&rcBtn, 2);
if (PtInRect(&rcBtn, pt)) return HTCLIENT;
}
return HTTRANSPARENT;
}
case WM_DESTROY: PostQuitMessage(0); break;
default: return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
void ShowOverlayWindow() {
HINSTANCE hInst = GetModuleHandle(nullptr);
static bool gdiplusStarted = false;
if (!gdiplusStarted) {
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&g_gdiTok, &gdiplusStartupInput, NULL);
gdiplusStarted = true;
}
WNDCLASSA wc = {};
wc.lpfnWndProc = OverlayWndProc;
wc.hInstance = hInst;
wc.lpszClassName = "OverlayWindowClass";
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
RegisterClassA(&wc);
int screenW = GetSystemMetrics(SM_CXSCREEN);
int x = (screenW - 300) / 2;
int y = 10;
g_hOv = CreateWindowA("OverlayWindowClass", "Overlay",
WS_POPUP | WS_VISIBLE,
x, y, 300, 60,
nullptr, nullptr, hInst, nullptr);
SetLayeredWindowAttributes(g_hOv, RGB(0,0,0), 0, LWA_ALPHA);
SetWindowPos(g_hOv, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);
ShowWindow(g_hOv, SW_SHOW);
UpdateWindow(g_hOv);
}
LRESULT CALLBACK MacroMouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= 0 && g_macRec) {
MSLLHOOKSTRUCT* p = (MSLLHOOKSTRUCT*)lParam;
int type = -1;
int data = 0;
if (wParam == WM_LBUTTONDOWN) type = 1;
else if (wParam == WM_LBUTTONUP) type = 2;
else if (wParam == WM_RBUTTONDOWN) type = 3;
else if (wParam == WM_RBUTTONUP) type = 4;
else if (wParam == WM_MBUTTONDOWN) type = 5;
else if (wParam == WM_MBUTTONUP) type = 6;
else if (wParam == WM_MOUSEWHEEL) { type = 9; data = (short)HIWORD(p->mouseData); }
else if (wParam == WM_MOUSEMOVE) {
if (g_macMove) {
static int lmtk = 0;
int now = GetTickCount();
if (now - lmtk < 10) return CallNextHookEx(g_macMH, nCode, wParam, lParam);
lmtk = now;
type = 0;
} else {
return CallNextHookEx(g_macMH, nCode, wParam, lParam);
}
}
if (type != -1) {
lock_guard<mutex> lock(g_macMtx);
g_macEvt.push_back({type, p->pt.x, p->pt.y, data, GetTickCount(), false});
if (g_hMacL) {
char buf[128];
const char* names[] = {"移动","左键按下","左键释放","右键按下","右键释放","中键按下","中键释放","","","滚轮"};
const char* name = (type>=0 && type<=9) ? names[type] : "未知";
sprintf(buf, "%s (%d,%d)", name, p->pt.x, p->pt.y);
SendMessageA(g_hMacL, LB_ADDSTRING, 0, (LPARAM)buf);
SendMessageA(g_hMacL, LB_SETCURSEL, g_macEvt.size()-1, 0);
}
}
}
return CallNextHookEx(g_macMH, nCode, wParam, lParam);
}
LRESULT CALLBACK MacroKeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= 0 && g_macRec) {
KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam;
int type = (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) ? 7 : 8;
lock_guard<mutex> lock(g_macMtx);
g_macEvt.push_back({type, 0, 0, (int)p->vkCode, GetTickCount(), false});
if (g_hMacL) {
char buf[64]; sprintf(buf, "按键 VK=%d", p->vkCode);
SendMessageA(g_hMacL, LB_ADDSTRING, 0, (LPARAM)buf);
SendMessageA(g_hMacL, LB_SETCURSEL, g_macEvt.size()-1, 0);
}
}
return CallNextHookEx(g_macKH, nCode, wParam, lParam);
}
DWORD WINAPI MacroPlayThread(LPVOID) {
int speed = g_macSpeed; if (speed < 1) speed = 1;
bool loop = g_macLoop;
g_macStop = false;
do {
vector<RecordedEvent> eventsCopy;
{
lock_guard<mutex> lock(g_macMtx);
eventsCopy = g_macEvt;
}
for (auto& evt : eventsCopy) {
if (g_macStop.load() || !g_macPlay) break;
int x = evt.x, y = evt.y;
switch (evt.type) {
case 0: SetCursorPos(x, y); break;
case 1: case 2: case 3: case 4: case 5: case 6: {
SetCursorPos(x, y);
INPUT inp = {}; inp.type = INPUT_MOUSE;
switch (evt.type) {
case 1: inp.mi.dwFlags = MOUSEEVENTF_LEFTDOWN; break;
case 2: inp.mi.dwFlags = MOUSEEVENTF_LEFTUP; break;
case 3: inp.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN; break;
case 4: inp.mi.dwFlags = MOUSEEVENTF_RIGHTUP; break;
case 5: inp.mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN; break;
case 6: inp.mi.dwFlags = MOUSEEVENTF_MIDDLEUP; break;
}
SendInput(1, &inp, sizeof(INPUT));
break;
}
case 7: case 8: {
INPUT inp = {}; inp.type = INPUT_KEYBOARD;
inp.ki.wVk = (WORD)evt.data;
if (evt.type == 8) inp.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &inp, sizeof(INPUT));
break;
}
case 9: {
SetCursorPos(x, y);
INPUT inp = {}; inp.type = INPUT_MOUSE;
inp.mi.dwFlags = MOUSEEVENTF_WHEEL;
inp.mi.mouseData = evt.data;
SendInput(1, &inp, sizeof(INPUT));
break;
}
}
auto start = chrono::steady_clock::now();
while (chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - start).count() < speed) {
if (g_macStop.load() || !g_macPlay) break;
Sleep(1);
}
}
} while (loop && g_macPlay && !g_macStop.load());
g_macPlay = false;
if (g_hMacPB) SetWindowTextA(g_hMacPB, "播放");
PostMessageA(g_hMacW, WM_MACRO_UPDATE, 0, 0);
return 0;
}
LRESULT CALLBACK MacroWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE: {
HINSTANCE hInst = ((LPCREATESTRUCT)lParam)->hInstance;
g_hMacL = CreateWindowA("LISTBOX", "",
WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | LBS_NOTIFY,
10, 10, 820, 260, hwnd, nullptr, hInst, nullptr);
SendMessage(g_hMacL, WM_SETFONT, (WPARAM)g_fN, TRUE);
CreateWindowA("BUTTON", "录制", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
10, 280, 80, 30, hwnd, (HMENU)4001, hInst, nullptr);
CreateWindowA("BUTTON", "停止录制", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
100, 280, 80, 30, hwnd, (HMENU)4002, hInst, nullptr);
g_hMacPB = CreateWindowA("BUTTON", "播放", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
190, 280, 80, 30, hwnd, (HMENU)4003, hInst, nullptr);
CreateWindowA("BUTTON", "停止", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
280, 280, 80, 30, hwnd, (HMENU)4004, hInst, nullptr);
HWND hLoop = CreateWindowA("BUTTON", "循环", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
370, 280, 60, 30, hwnd, (HMENU)4005, hInst, nullptr);
CreateWindowA("STATIC", "速度(ms):", WS_CHILD | WS_VISIBLE,
440, 285, 60, 20, hwnd, nullptr, hInst, nullptr);
HWND hSpeed = CreateWindowA("EDIT", "50", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NUMBER,
510, 280, 60, 30, hwnd, (HMENU)4006, hInst, nullptr);
SendMessage(hSpeed, WM_SETFONT, (WPARAM)g_fN, TRUE);
HWND hMove = CreateWindowA("BUTTON", "记录鼠标移动", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
590, 280, 130, 30, hwnd, (HMENU)4008, hInst, nullptr);
SendMessage(hMove, WM_SETFONT, (WPARAM)g_fN, TRUE);
SendMessage(hMove, BM_SETCHECK, BST_CHECKED, 0);
g_macMove = true;
CreateWindowA("BUTTON", "清空", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
740, 280, 80, 30, hwnd, (HMENU)4007, hInst, nullptr);
break;
}
case WM_COMMAND: {
int id = LOWORD(wParam);
if (id == 4001) {
if (g_macPlay) { MessageBoxA(hwnd, "请先停止播放", "提示", MB_OK); break; }
{
lock_guard<mutex> lock(g_macMtx);
g_macEvt.clear();
}
if (g_hMacL) SendMessage(g_hMacL, LB_RESETCONTENT, 0, 0);
g_macRec = true;
SetWindowTextA(GetDlgItem(hwnd, 4001), "录制中...");
g_macMH = SetWindowsHookExA(WH_MOUSE_LL, MacroMouseHookProc, GetModuleHandleA(nullptr), 0);
g_macKH = SetWindowsHookExA(WH_KEYBOARD_LL, MacroKeyboardHookProc, GetModuleHandleA(nullptr), 0);
if (!g_macMH || !g_macKH) {
MessageBoxA(hwnd, "钩子安装失败", "错误", MB_OK);
g_macRec = false;
SetWindowTextA(GetDlgItem(hwnd, 4001), "录制");
if (g_macMH) { UnhookWindowsHookEx(g_macMH); g_macMH = nullptr; }
if (g_macKH) { UnhookWindowsHookEx(g_macKH); g_macKH = nullptr; }
}
break;
}
if (id == 4002) {
g_macRec = false;
SetWindowTextA(GetDlgItem(hwnd, 4001), "录制");
if (g_macMH) { UnhookWindowsHookEx(g_macMH); g_macMH = nullptr; }
if (g_macKH) { UnhookWindowsHookEx(g_macKH); g_macKH = nullptr; }
{
lock_guard<mutex> lock(g_macMtx);
MessageBoxA(hwnd, ("录制完成,共 " + to_string(g_macEvt.size()) + " 个事件").c_str(), "提示", MB_OK);
}
break;
}
if (id == 4003) {
{
lock_guard<mutex> lock(g_macMtx);
if (g_macEvt.empty()) { MessageBoxA(hwnd, "宏为空", "提示", MB_OK); break; }
}
if (g_macPlay) break;
g_macStop = false;
g_macPlay = true;
SetWindowTextA(g_hMacPB, "播放中...");
char buf[16]; GetWindowTextA(GetDlgItem(hwnd, 4006), buf, sizeof(buf));
g_macSpeed = atoi(buf); if (g_macSpeed < 1) g_macSpeed = 1;
g_macLoop = (SendMessage(GetDlgItem(hwnd, 4005), BM_GETCHECK, 0, 0) == BST_CHECKED);
g_macThr = CreateThread(nullptr, 0, MacroPlayThread, nullptr, 0, nullptr);
if (!g_macThr) {
g_macPlay = false;
SetWindowTextA(g_hMacPB, "播放");
MessageBoxA(hwnd, "线程创建失败", "错误", MB_OK);
}
break;
}
if (id == 4004) {
g_macStop = true;
g_macPlay = false;
SetWindowTextA(g_hMacPB, "播放");
if (g_macThr) {
WaitForSingleObject(g_macThr, 1000);
CloseHandle(g_macThr);
g_macThr = nullptr;
}
break;
}
if (id == 4007) {
lock_guard<mutex> lock(g_macMtx);
g_macEvt.clear();
if (g_hMacL) SendMessage(g_hMacL, LB_RESETCONTENT, 0, 0);
break;
}
if (id == 4008) {
g_macMove = (SendMessage(GetDlgItem(hwnd, 4008), BM_GETCHECK, 0, 0) == BST_CHECKED);
break;
}
break;
}
case WM_MACRO_UPDATE:
SetWindowTextA(g_hMacPB, "播放");
break;
case WM_CLOSE: {
g_macRec = false;
g_macPlay = false;
g_macStop = true;
if (g_macMH) { UnhookWindowsHookEx(g_macMH); g_macMH = nullptr; }
if (g_macKH) { UnhookWindowsHookEx(g_macKH); g_macKH = nullptr; }
if (g_macThr) { WaitForSingleObject(g_macThr, 500); CloseHandle(g_macThr); g_macThr = nullptr; }
DestroyWindow(hwnd);
break;
}
case WM_DESTROY:
g_hMacW = nullptr;
g_hMacL = nullptr;
g_hMacPB = nullptr;
break;
default: return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
void CreateMacroWindow() {
if (g_hMacW) { ShowWindow(g_hMacW, SW_SHOW); SetForegroundWindow(g_hMacW); return; }
HINSTANCE hInst = GetModuleHandle(nullptr);
WNDCLASSA wc = {};
wc.lpfnWndProc = MacroWndProc;
wc.hInstance = hInst;
wc.lpszClassName = "MacroWindowClass";
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
RegisterClassA(&wc);
g_hMacW = CreateWindowA("MacroWindowClass", "鼠标宏编辑器",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, 860, 360,
g_hM, nullptr, hInst, nullptr);
SendMessage(g_hMacW, WM_SETICON, ICON_SMALL, (LPARAM)g_icon);
}
DWORD WINAPI ClickerThread(LPVOID) {
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
SetThreadAffinityMask(GetCurrentThread(), 1);
int localDelay = g_cd.load();
int localBtn = g_cb.load();
int localCnt = 0;
while (!g_se) {
if (g_ic.load()) {
if (g_seq.load() && g_cd.load() > 0) {
vector<pair<int,int>> ptsCopy = g_pts;
if (ptsCopy.empty()) {
MessageBoxA(g_hM, "序列点位为空,请先设置点位。", "提示", MB_OK);
g_ic = false;
UpdateUI();
continue;
}
for (auto& pt : ptsCopy) {
if (!g_ic.load()) break;
SimulateClick(pt.first, pt.second, g_cb.load());
g_cc.fetch_add(1);
PostMessageA(g_hM, WM_USER + 1, 0, 0);
int finalDelay = localDelay;
if (g_je.load() && localDelay > 0) {
int range = g_jr.load();
if (range > 0) {
int offset = GetJitterOffset(range);
finalDelay += offset;
if (finalDelay < 1) finalDelay = 1;
}
}
if (finalDelay == 1) usSleep(1000);
else Sleep(finalDelay);
}
continue;
}
if (g_em.load()) {
while (!g_se && g_ic.load() && g_em.load()) {
int btnCur = g_cb.load();
if (btnCur != localBtn) localBtn = btnCur;
INPUT input[2] = {};
input[0].type = INPUT_MOUSE;
input[1].type = INPUT_MOUSE;
switch (localBtn) {
case 0: input[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN; input[1].mi.dwFlags = MOUSEEVENTF_LEFTUP; break;
case 1: input[0].mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN; input[1].mi.dwFlags = MOUSEEVENTF_MIDDLEUP; break;
case 2: input[0].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN; input[1].mi.dwFlags = MOUSEEVENTF_RIGHTUP; break;
}
SendInput(2, input, sizeof(INPUT));
++localCnt;
}
if (localCnt > 0) { g_cc.fetch_add(localCnt); localCnt = 0; PostMessageA(g_hM, WM_USER + 1, 0, 0); }
localDelay = g_cd.load();
continue;
}
int btnCur = g_cb.load();
if (btnCur != localBtn) localBtn = btnCur;
INPUT input[2] = {};
input[0].type = INPUT_MOUSE;
input[1].type = INPUT_MOUSE;
switch (localBtn) {
case 0: input[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN; input[1].mi.dwFlags = MOUSEEVENTF_LEFTUP; break;
case 1: input[0].mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN; input[1].mi.dwFlags = MOUSEEVENTF_MIDDLEUP; break;
case 2: input[0].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN; input[1].mi.dwFlags = MOUSEEVENTF_RIGHTUP; break;
}
SendInput(2, input, sizeof(INPUT));
static int clickCounter = 0;
if (++clickCounter >= 10) { clickCounter = 0; PostMessageA(g_hM, WM_USER + 1, 0, 0); }
int finalDelay = localDelay;
if (g_je.load() && localDelay > 0) {
int range = g_jr.load();
if (range > 0) {
int offset = GetJitterOffset(range);
finalDelay += offset;
if (finalDelay < 1) finalDelay = 1;
}
}
if (finalDelay == 1) usSleep(1000);
else Sleep(finalDelay);
localDelay = g_cd.load();
} else {
if (localCnt > 0) { g_cc.fetch_add(localCnt); localCnt = 0; UpdateCount(); }
Sleep(10);
}
}
return 0;
}
LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= 0) {
KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam;
if ((p->vkCode == VK_OEM_PLUS || p->vkCode == VK_ADD) && (GetKeyState(VK_CAPITAL) & 1)) {
if (!g_ic.load()) {
POINT pt; GetCursorPos(&pt);
PostMessageA(g_hM, WM_ADD_COORD, (WPARAM)pt.x, (LPARAM)pt.y);
MessageBeep(MB_OK);
}
}
if (g_rec.load()) {
if (p->vkCode >= VK_F1 && p->vkCode <= VK_F12)
return CallNextHookEx(g_kh, nCode, wParam, lParam);
int type = (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) ? 7 : 8;
g_evt.push_back({type, 0, 0, (int)p->vkCode, GetTickCount(), false});
}
if (g_hookHot && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)) {
static bool fd6 = false, fd7 = false, fdE = false;
if (p->vkCode == VK_F6 && !fd6) {
fd6 = true;
bool running = g_ic.load();
g_ic = !running;
UpdateUI();
if (!running) UpdateCount();
strcpy(g_nid.szTip, g_ic.load() ? "自动连点器 (运行中)" : "自动连点器 (已停止)");
Shell_NotifyIconA(NIM_MODIFY, &g_nid);
return 1;
} else if (p->vkCode == VK_F6 && wParam == WM_KEYUP) {
fd6 = false;
}
if (p->vkCode == VK_F7 && !fd7) {
fd7 = true;
ToggleRecording();
return 1;
} else if (p->vkCode == VK_F7 && wParam == WM_KEYUP) {
fd7 = false;
}
if (p->vkCode == VK_ESCAPE && !fdE) {
fdE = true;
if (IsWindowVisible(g_hM)) {
DestroyWindow(g_hM);
}
} else if (p->vkCode == VK_ESCAPE && wParam == WM_KEYUP) {
fdE = false;
}
}
}
return CallNextHookEx(g_kh, nCode, wParam, lParam);
}
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= 0 && g_rec.load()) {
MSLLHOOKSTRUCT* p = (MSLLHOOKSTRUCT*)lParam;
int currentTime = GetTickCount();
int screenX = p->pt.x, screenY = p->pt.y;
int storeX, storeY;
bool isRel = g_rel;
if (g_rel) {
POINT clientTL = {0,0}; ClientToScreen(g_hM, &clientTL);
storeX = screenX - clientTL.x; storeY = screenY - clientTL.y;
} else { storeX = screenX; storeY = screenY; }
int type = -1, data = 0;
if (wParam == WM_MOUSEMOVE) { type = 0; }
else if (wParam == WM_LBUTTONDOWN) type = 1;
else if (wParam == WM_LBUTTONUP) type = 2;
else if (wParam == WM_RBUTTONDOWN) type = 3;
else if (wParam == WM_RBUTTONUP) type = 4;
else if (wParam == WM_MBUTTONDOWN) type = 5;
else if (wParam == WM_MBUTTONUP) type = 6;
else if (wParam == WM_MOUSEWHEEL) { type = 9; data = (short)HIWORD(p->mouseData); }
else if (wParam == WM_MOUSEHWHEEL) { type = 10; data = (short)HIWORD(p->mouseData); }
if (type != -1) {
if (type == 0 && currentTime - g_lmt < 5) return CallNextHookEx(g_mh, nCode, wParam, lParam);
if (type == 0) g_lmt = currentTime;
g_evt.push_back({type, storeX, storeY, data, currentTime, isRel});
}
}
return CallNextHookEx(g_mh, nCode, wParam, lParam);
}
DWORD WINAPI PlaybackThread(LPVOID) {
if (g_evt.empty()) { MessageBoxA(g_hM, "没有录制数据", "提示", MB_OK); return 0; }
g_ply = true;
for (auto& evt : g_evt) {
if (!g_ply) break;
int sx, sy;
if (evt.isRelative) {
POINT tl = {0,0}; ClientToScreen(g_hM, &tl);
sx = tl.x + evt.x; sy = tl.y + evt.y;
} else { sx = evt.x; sy = evt.y; }
switch (evt.type) {
case 0: SetCursorPos(sx, sy); break;
case 1: case 2: case 3: case 4: case 5: case 6: {
SetCursorPos(sx, sy);
INPUT inp = {}; inp.type = INPUT_MOUSE;
switch (evt.type) {
case 1: inp.mi.dwFlags = MOUSEEVENTF_LEFTDOWN; break;
case 2: inp.mi.dwFlags = MOUSEEVENTF_LEFTUP; break;
case 3: inp.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN; break;
case 4: inp.mi.dwFlags = MOUSEEVENTF_RIGHTUP; break;
case 5: inp.mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN; break;
case 6: inp.mi.dwFlags = MOUSEEVENTF_MIDDLEUP; break;
}
SendInput(1, &inp, sizeof(INPUT));
break;
}
case 7: case 8: {
INPUT inp = {}; inp.type = INPUT_KEYBOARD;
inp.ki.wVk = (WORD)evt.data;
if (evt.type == 8) inp.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &inp, sizeof(INPUT));
break;
}
case 9: case 10: {
SetCursorPos(sx, sy);
INPUT inp = {}; inp.type = INPUT_MOUSE;
inp.mi.dwFlags = (evt.type == 9) ? MOUSEEVENTF_WHEEL : MOUSEEVENTF_HWHEEL;
inp.mi.mouseData = evt.data;
SendInput(1, &inp, sizeof(INPUT));
break;
}
}
Sleep(g_ps.load());
}
g_ply = false;
PostMessageA(g_hM, WM_USER + 3, 0, 0);
return 0;
}
void CreateTrayIcon() {
ZeroMemory(&g_nid, sizeof(NOTIFYICONDATAA));
g_nid.cbSize = sizeof(NOTIFYICONDATAA);
g_nid.hWnd = g_hM;
g_nid.uID = 1;
g_nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
g_nid.uCallbackMessage = WM_TRAYICON;
g_nid.hIcon = g_icon ? g_icon : LoadIconA(nullptr, IDI_APPLICATION);
strcpy(g_nid.szTip, "自动连点器");
if (!Shell_NotifyIconA(NIM_ADD, &g_nid)) {
Sleep(100);
if (!Shell_NotifyIconA(NIM_ADD, &g_nid)) {
MessageBoxA(g_hM, "托盘图标创建失败!", "提示", MB_OK);
return;
}
}
g_tray = true;
}
void DeleteTrayIcon() { if (g_tray) { Shell_NotifyIconA(NIM_DELETE, &g_nid); g_tray = false; } }
void ShowMainWindow() { ShowWindow(g_hM, SW_SHOW); SetForegroundWindow(g_hM); }
HBRUSH CreateGradientBrush(int width, int height, COLORREF top, COLORREF bottom) {
if (width <= 0 || height <= 0) return nullptr;
HDC hdc = GetDC(nullptr);
HDC mem = CreateCompatibleDC(hdc);
HBITMAP bmp = CreateCompatibleBitmap(hdc, width, height);
HBITMAP old = (HBITMAP)SelectObject(mem, bmp);
for (int y = 0; y < height; ++y) {
double r = (double)y / (height - 1);
BYTE R = (BYTE)(GetRValue(top) + r * (GetRValue(bottom) - GetRValue(top)));
BYTE G = (BYTE)(GetGValue(top) + r * (GetGValue(bottom) - GetGValue(top)));
BYTE B = (BYTE)(GetBValue(top) + r * (GetBValue(bottom) - GetBValue(top)));
HBRUSH line = CreateSolidBrush(RGB(R,G,B));
RECT rc = {0, y, width, y+1};
FillRect(mem, &rc, line);
DeleteObject(line);
}
SelectObject(mem, old);
HBRUSH brush = CreatePatternBrush(bmp);
DeleteObject(bmp);
DeleteDC(mem);
ReleaseDC(nullptr, hdc);
return brush;
}
void StartRecordingActual() {
if (g_ic.load() || g_seq.load()) {
MessageBoxA(g_hM, "请先停止连点或关闭序列。", "提示", MB_OK);
return;
}
g_evt.clear();
g_lmt = 0;
g_rec = true;
SetWindowTextA(g_hRB, "停止录制");
g_mh = SetWindowsHookExA(WH_MOUSE_LL, MouseHookProc, GetModuleHandleA(nullptr), 0);
if (!g_mh) {
MessageBoxA(g_hM, "设置鼠标钩子失败!", "错误", MB_OK);
g_rec = false;
SetWindowTextA(g_hRB, "开始录制");
}
}
void StopRecording() {
g_rec = false;
SetWindowTextA(g_hRB, "开始录制");
if (g_mh) { UnhookWindowsHookEx(g_mh); g_mh = nullptr; }
MessageBoxA(g_hM, ("录制完成,共 " + to_string(g_evt.size()) + " 个事件。").c_str(), "提示", MB_OK);
}
void ToggleRecording() {
if (g_rec.load()) { StopRecording(); return; }
if (g_recPend) {
KillTimer(g_hM, g_cdTimer);
g_recPend = false;
SetWindowTextA(g_hRB, "开始录制");
return;
}
if (g_ic.load() || g_seq.load()) {
MessageBoxA(g_hM, "请先停止连点或关闭序列。", "提示", MB_OK);
return;
}
g_recPend = true;
g_curCd = g_cdSec;
char buf[32]; sprintf(buf, "倒计时 %ds", g_curCd);
SetWindowTextA(g_hRB, buf);
SetTimer(g_hM, g_cdTimer, 1000, nullptr);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE: {
HINSTANCE hInst = ((LPCREATESTRUCT)lParam)->hInstance;
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_STANDARD_CLASSES;
InitCommonControlsEx(&icex);
int baseX = 20, baseY = 20;
int colW = 340, gap = 25, statusW = colW*3 + gap*2;
int rowH = 34;
g_fS = CreateFont(44, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
DEFAULT_CHARSET, OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS,
ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_SWISS, "Segoe UI");
g_fN = CreateFont(22, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
DEFAULT_CHARSET, OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS,
ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_SWISS, "Segoe UI");
g_bW = CreateSolidBrush(RGB(255,255,255));
g_hS = CreateWindowA("STATIC", "● 已停止", WS_CHILD|WS_VISIBLE|SS_CENTER,
baseX, baseY, statusW, 56, hwnd, nullptr, hInst, nullptr);
SendMessage(g_hS, WM_SETFONT, (WPARAM)g_fS, TRUE);
baseY += 68;
int x1 = baseX, x2 = baseX + colW + gap, x3 = baseX + (colW+gap)*2;
int y = baseY;
CreateWindowA("BUTTON", "基础设置", WS_CHILD|WS_VISIBLE|BS_GROUPBOX,
x1, y, colW, 190, hwnd, nullptr, hInst, nullptr);
CreateWindowA("STATIC", "间隔(ms):", WS_CHILD|WS_VISIBLE, x1+15, y+32, 85, rowH, hwnd, nullptr, hInst, nullptr);
g_hDE = CreateWindowA("EDIT", "100", WS_CHILD|WS_VISIBLE|WS_BORDER|ES_NUMBER,
x1+105, y+28, 95, 34, hwnd, (HMENU)1001, hInst, nullptr);
SendMessage(g_hDE, WM_SETFONT, (WPARAM)g_fN, TRUE);
g_hDL = CreateWindowA("STATIC", "当前:100ms", WS_CHILD|WS_VISIBLE|SS_LEFT,
x1+210, y+32, 120, rowH, hwnd, nullptr, hInst, nullptr);
SendMessage(g_hDL, WM_SETFONT, (WPARAM)g_fN, TRUE);
CreateWindowA("STATIC", "按键:", WS_CHILD|WS_VISIBLE, x1+15, y+80, 65, rowH, hwnd, nullptr, hInst, nullptr);
g_hBC = CreateWindowA("COMBOBOX", "", WS_CHILD|WS_VISIBLE|WS_BORDER|CBS_DROPDOWNLIST|CBS_HASSTRINGS,
x1+85, y+76, 120, 120, hwnd, (HMENU)1002, hInst, nullptr);
SendMessage(g_hBC, WM_SETFONT, (WPARAM)g_fN, TRUE);
SendMessageA(g_hBC, CB_ADDSTRING, 0, (LPARAM)"左键");
SendMessageA(g_hBC, CB_ADDSTRING, 0, (LPARAM)"中键");
SendMessageA(g_hBC, CB_ADDSTRING, 0, (LPARAM)"右键");
SendMessage(g_hBC, CB_SETCURSEL, 0, 0);
g_hJC = CreateWindowA("BUTTON", "抖动", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX,
x1+15, y+124, 85, 30, hwnd, (HMENU)1003, hInst, nullptr);
SendMessage(g_hJC, WM_SETFONT, (WPARAM)g_fN, TRUE);
CreateWindowA("STATIC", "范围:", WS_CHILD|WS_VISIBLE, x1+115, y+124, 55, 30, hwnd, nullptr, hInst, nullptr);
g_hJE = CreateWindowA("EDIT", "10", WS_CHILD|WS_VISIBLE|WS_BORDER|ES_NUMBER,
x1+170, y+120, 75, 34, hwnd, (HMENU)1004, hInst, nullptr);
SendMessage(g_hJE, WM_SETFONT, (WPARAM)g_fN, TRUE);
g_hRC = CreateWindowA("BUTTON", "相对窗口", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX,
x1+15, y+160, 130, 28, hwnd, (HMENU)1010, hInst, nullptr);
SendMessage(g_hRC, WM_SETFONT, (WPARAM)g_fN, TRUE);
SendMessage(g_hRC, BM_SETCHECK, BST_CHECKED, 0);
g_rel = true;
CreateWindowA("BUTTON", "序列点击", WS_CHILD|WS_VISIBLE|BS_GROUPBOX,
x2, y, colW, 190, hwnd, nullptr, hInst, nullptr);
g_hSC = CreateWindowA("BUTTON", "启用序列", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX,
x2+15, y+32, 130, 30, hwnd, (HMENU)1005, hInst, nullptr);
SendMessage(g_hSC, WM_SETFONT, (WPARAM)g_fN, TRUE);
CreateWindowA("STATIC", "坐标 (x,y;x,y):", WS_CHILD|WS_VISIBLE, x2+15, y+74, 190, 30, hwnd, nullptr, hInst, nullptr);
g_hSE = CreateWindowA("EDIT", "100,200;300,400", WS_CHILD|WS_VISIBLE|WS_BORDER,
x2+15, y+104, colW-30, 44, hwnd, (HMENU)1006, hInst, nullptr);
SendMessage(g_hSE, WM_SETFONT, (WPARAM)g_fN, TRUE);
char initBuf[512]; GetWindowTextA(g_hSE, initBuf, sizeof(initBuf));
ParseCoordinates(initBuf);
CreateWindowA("BUTTON", "录制回放", WS_CHILD|WS_VISIBLE|BS_GROUPBOX,
x3, y, colW, 190, hwnd, nullptr, hInst, nullptr);
g_hRB = CreateWindowA("BUTTON", "开始录制", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
x3+15, y+32, 140, 42, hwnd, (HMENU)1007, hInst, nullptr);
SendMessage(g_hRB, WM_SETFONT, (WPARAM)g_fN, TRUE);
g_hPB = CreateWindowA("BUTTON", "回放", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
x3+170, y+32, 140, 42, hwnd, (HMENU)1008, hInst, nullptr);
SendMessage(g_hPB, WM_SETFONT, (WPARAM)g_fN, TRUE);
CreateWindowA("STATIC", "速度(ms):", WS_CHILD|WS_VISIBLE, x3+15, y+92, 85, 30, hwnd, nullptr, hInst, nullptr);
g_hSS = CreateWindowA("EDIT", "50", WS_CHILD|WS_VISIBLE|WS_BORDER|ES_NUMBER,
x3+105, y+88, 95, 34, hwnd, (HMENU)1009, hInst, nullptr);
SendMessage(g_hSS, WM_SETFONT, (WPARAM)g_fN, TRUE);
y += 210;
int row2H = 160;
CreateWindowA("BUTTON", "鼠标多点", WS_CHILD|WS_VISIBLE|BS_GROUPBOX,
x1, y, colW, row2H, hwnd, nullptr, hInst, nullptr);
CreateWindowA("STATIC", "次数:", WS_CHILD|WS_VISIBLE, x1+15, y+32, 55, 30, hwnd, nullptr, hInst, nullptr);
g_hMC = CreateWindowA("EDIT", "5", WS_CHILD|WS_VISIBLE|WS_BORDER|ES_NUMBER,
x1+75, y+28, 75, 34, hwnd, (HMENU)2001, hInst, nullptr);
SendMessage(g_hMC, WM_SETFONT, (WPARAM)g_fN, TRUE);
CreateWindowA("STATIC", "间隔(ms):", WS_CHILD|WS_VISIBLE, x1+165, y+32, 80, 30, hwnd, nullptr, hInst, nullptr);
g_hMI = CreateWindowA("EDIT", "100", WS_CHILD|WS_VISIBLE|WS_BORDER|ES_NUMBER,
x1+250, y+28, 75, 34, hwnd, (HMENU)2002, hInst, nullptr);
SendMessage(g_hMI, WM_SETFONT, (WPARAM)g_fN, TRUE);
CreateWindowA("STATIC", "按键:", WS_CHILD|WS_VISIBLE, x1+15, y+78, 55, 30, hwnd, nullptr, hInst, nullptr);
g_hMB = CreateWindowA("COMBOBOX", "", WS_CHILD|WS_VISIBLE|WS_BORDER|CBS_DROPDOWNLIST|CBS_HASSTRINGS,
x1+75, y+74, 110, 120, hwnd, (HMENU)2003, hInst, nullptr);
SendMessage(g_hMB, WM_SETFONT, (WPARAM)g_fN, TRUE);
SendMessageA(g_hMB, CB_ADDSTRING, 0, (LPARAM)"左键");
SendMessageA(g_hMB, CB_ADDSTRING, 0, (LPARAM)"右键");
SendMessageA(g_hMB, CB_ADDSTRING, 0, (LPARAM)"中键");
SendMessage(g_hMB, CB_SETCURSEL, 0, 0);
g_hME = CreateWindowA("BUTTON", "启用多点", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
x1+200, y+72, 125, 42, hwnd, (HMENU)2004, hInst, nullptr);
SendMessage(g_hME, WM_SETFONT, (WPARAM)g_fN, TRUE);
g_hMS = CreateWindowA("STATIC", "未启动", WS_CHILD|WS_VISIBLE|SS_CENTER,
x1+15, y+126, colW-30, 26, hwnd, nullptr, hInst, nullptr);
SendMessage(g_hMS, WM_SETFONT, (WPARAM)g_fN, TRUE);
CreateWindowA("BUTTON", "鼠标宏", WS_CHILD|WS_VISIBLE|BS_GROUPBOX,
x2, y, colW, row2H, hwnd, nullptr, hInst, nullptr);
g_hMac = CreateWindowA("BUTTON", "打开宏编辑器", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
x2+65, y+50, 200, 50, hwnd, (HMENU)2005, hInst, nullptr);
SendMessage(g_hMac, WM_SETFONT, (WPARAM)g_fN, TRUE);
CreateWindowA("STATIC", "录制鼠标/键盘动作,支持循环播放", WS_CHILD|WS_VISIBLE|SS_CENTER,
x2+15, y+118, colW-30, 28, hwnd, nullptr, hInst, nullptr);
CreateWindowA("BUTTON", "统计", WS_CHILD|WS_VISIBLE|BS_GROUPBOX,
x3, y, colW, row2H, hwnd, nullptr, hInst, nullptr);
g_hC = CreateWindowA("STATIC", "已点击: 0 次", WS_CHILD|WS_VISIBLE,
x3+25, y+40, 200, 34, hwnd, nullptr, hInst, nullptr);
SendMessage(g_hC, WM_SETFONT, (WPARAM)g_fN, TRUE);
g_hP = CreateWindowA("STATIC", "CPS: 0.0", WS_CHILD|WS_VISIBLE|SS_LEFT,
x3+25, y+90, 200, 34, hwnd, nullptr, hInst, nullptr);
SendMessage(g_hP, WM_SETFONT, (WPARAM)g_fN, TRUE);
y += row2H + 20;
CreateWindowA("BUTTON", "控制", WS_CHILD|WS_VISIBLE|BS_GROUPBOX,
baseX, y, statusW, 96, hwnd, nullptr, hInst, nullptr);
g_hSB = CreateWindowA("BUTTON", "开始 (F6)", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
baseX+25, y+22, 170, 52, hwnd, (HMENU)1, hInst, nullptr);
SendMessage(g_hSB, WM_SETFONT, (WPARAM)g_fN, TRUE);
g_hTB = CreateWindowA("BUTTON", "停止 (F6)", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
baseX+210, y+22, 170, 52, hwnd, (HMENU)2, hInst, nullptr);
SendMessage(g_hTB, WM_SETFONT, (WPARAM)g_fN, TRUE);
g_hEB = CreateWindowA("BUTTON", "退出", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
baseX+395, y+22, 170, 52, hwnd, (HMENU)3, hInst, nullptr);
SendMessage(g_hEB, WM_SETFONT, (WPARAM)g_fN, TRUE);
y += 110;
CreateWindowA("STATIC", "F6 切换 | F7 录制 | ESC 退出 | CapsLock + [+] 记录坐标",
WS_CHILD|WS_VISIBLE|SS_CENTER, baseX, y, statusW, 32, hwnd, nullptr, hInst, nullptr);
bool f6ok = RegisterHotKey(hwnd, HOTKEY_F6, 0, VK_F6);
bool escok = RegisterHotKey(hwnd, HOTKEY_ESC, 0, VK_ESCAPE);
bool f7ok = RegisterHotKey(hwnd, HOTKEY_F7, 0, VK_F7);
if (!f6ok || !f7ok || !escok) {
g_hookHot = true;
char msg[256];
sprintf(msg, "部分热键注册失败(F6:%s, F7:%s, ESC:%s),\n程序已自动启用键盘钩子作为替代方案。\nF6/F7 将独占(其他程序无法收到),ESC 不拦截。",
f6ok ? "成功" : "失败",
f7ok ? "成功" : "失败",
escok ? "成功" : "失败");
MessageBoxA(hwnd, msg, "热键冲突提示", MB_OK | MB_ICONWARNING);
} else {
g_hookHot = false;
}
g_kh = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleA(nullptr), 0);
if (!g_kh) MessageBoxA(hwnd, "键盘钩子安装失败", "警告", MB_OK);
HRGN hRgn = CreateRoundRectRgn(0, 0, 1100, 820, 30, 30);
SetWindowRgn(hwnd, hRgn, TRUE);
g_init = true;
g_cd = 100; g_cb = 0; g_em = false;
UpdateUI(); UpdateCount(); UpdateCPSDisplay();
break;
}
case WM_EXECUTE_CMD: {
char* cmd = (char*)wParam;
if (cmd) {
ExecuteCommand(string(cmd));
delete[] cmd;
}
break;
}
case WM_COPYDATA: {
COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)lParam;
if (pcds->dwData == 1) {
string cmd = (char*)pcds->lpData;
char* cmdCopy = new char[cmd.size() + 1];
strcpy(cmdCopy, cmd.c_str());
PostMessage(hwnd, WM_EXECUTE_CMD, (WPARAM)cmdCopy, 0);
ShowMainWindow();
return TRUE;
}
break;
}
case WM_ADD_COORD: {
if (g_ic.load()) break;
int x = (int)wParam, y = (int)lParam;
char buf[512] = {0}; GetWindowTextA(g_hSE, buf, sizeof(buf)-1);
string str = buf;
if (!str.empty()) str += ";";
char coord[32]; sprintf(coord, "%d,%d", x, y);
str += coord;
SetWindowTextA(g_hSE, str.c_str());
g_pts.push_back({x,y});
break;
}
case WM_USER + 3: SetWindowTextA(g_hPB, "回放"); break;
case WM_SHOWWINDOW:
if (wParam == TRUE) { if (!g_tray) CreateTrayIcon(); SetTimer(hwnd, TIMER_CPS, 500, nullptr); }
break;
case WM_TRAYICON: {
if (lParam == WM_LBUTTONDBLCLK) {
ShowMainWindow();
} else if (lParam == WM_RBUTTONUP) {
POINT pt; GetCursorPos(&pt);
HMENU hMenu = CreatePopupMenu();
AppendMenuA(hMenu, MF_STRING, TRAY_SHOW, "显示窗口");
AppendMenuA(hMenu, MF_STRING, TRAY_HIDE, "隐藏窗口");
AppendMenuA(hMenu, MF_SEPARATOR, 0, NULL);
const char* toggleText = g_ic.load() ? "暂停连点" : "继续连点";
AppendMenuA(hMenu, MF_STRING, TRAY_TOGGLE, toggleText);
AppendMenuA(hMenu, MF_SEPARATOR, 0, NULL);
AppendMenuA(hMenu, MF_STRING, TRAY_EXIT, "退出程序");
SetForegroundWindow(hwnd);
TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
PostMessageA(hwnd, WM_NULL, 0, 0);
DestroyMenu(hMenu);
}
break;
}
case WM_TIMER: {
if (wParam == TIMER_CPS) {
if (!g_em.load()) {
int total = g_cc.load();
static int last = 0;
static double lastTime = 0.0;
LARGE_INTEGER freq, now;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&now);
double t = (double)now.QuadPart / freq.QuadPart;
if (lastTime != 0.0 && (t - lastTime) > 0.01) {
double cps = (total - last) / (t - lastTime);
g_cps.store(cps);
UpdateCPSDisplay();
}
last = total; lastTime = t;
}
UpdateCount();
} else if (wParam == g_cdTimer) {
if (g_recPend) {
g_curCd--;
if (g_curCd <= 0) {
KillTimer(hwnd, g_cdTimer);
g_recPend = false;
SetWindowTextA(g_hRB, "开始录制");
StartRecordingActual();
} else {
char buf[32]; sprintf(buf, "倒计时 %ds", g_curCd);
SetWindowTextA(g_hRB, buf);
}
} else KillTimer(hwnd, g_cdTimer);
}
break;
}
case WM_COMMAND: {
int id = LOWORD(wParam);
int code = HIWORD(wParam);
if (id == TRAY_SHOW) { ShowMainWindow(); break; }
if (id == TRAY_HIDE) { ShowWindow(g_hM, SW_HIDE); break; }
if (id == TRAY_TOGGLE) {
bool running = g_ic.load();
g_ic = !running;
UpdateUI();
if (!running) UpdateCount();
strcpy(g_nid.szTip, g_ic.load() ? "自动连点器 (运行中)" : "自动连点器 (已停止)");
Shell_NotifyIconA(NIM_MODIFY, &g_nid);
break;
}
if (id == TRAY_EXIT) { DestroyWindow(g_hM); break; }
if (id == 2004) {
if (!g_mpAct) {
char buf[16];
GetWindowTextA(g_hMC, buf, sizeof(buf));
int cnt = max(1, atoi(buf));
GetWindowTextA(g_hMI, buf, sizeof(buf));
int inter = max(0, atoi(buf));
int sel = (int)SendMessage(g_hMB, CB_GETCURSEL, 0, 0);
if (sel < 0) sel = 0;
g_mpCnt = cnt;
g_mpInt = inter;
g_mpBtn = sel;
g_mpStop.store(false);
g_mpBusy = false;
ShowWindow(g_hM, SW_HIDE);
if (g_hMacW) ShowWindow(g_hMacW, SW_HIDE);
ShowOverlayWindow();
g_mpHook = SetWindowsHookExA(WH_MOUSE_LL, MultiPointMouseHookProc, GetModuleHandleA(nullptr), 0);
if (!g_mpHook) {
MessageBoxA(hwnd, "钩子安装失败", "错误", MB_OK);
ShowWindow(g_hM, SW_SHOW);
if (g_hMacW) ShowWindow(g_hMacW, SW_SHOW);
if (g_hOv) { DestroyWindow(g_hOv); g_hOv = nullptr; }
break;
}
g_mpAct = true;
SetWindowTextA(g_hME, "停止多点");
SetWindowTextA(g_hMS, "工作中...");
EnableWindow(g_hMC, FALSE);
EnableWindow(g_hMI, FALSE);
EnableWindow(g_hMB, FALSE);
} else {
g_mpStop.store(true);
g_mpAct = false;
if (g_mpHook) { UnhookWindowsHookEx(g_mpHook); g_mpHook = nullptr; }
if (g_hOv) { DestroyWindow(g_hOv); g_hOv = nullptr; }
ShowWindow(g_hM, SW_SHOW);
if (g_hMacW) ShowWindow(g_hMacW, SW_SHOW);
SetWindowTextA(g_hME, "启用多点");
SetWindowTextA(g_hMS, "已停止");
EnableWindow(g_hMC, TRUE);
EnableWindow(g_hMI, TRUE);
EnableWindow(g_hMB, TRUE);
g_mpStop.store(false);
}
break;
}
if (id == 2005) { CreateMacroWindow(); break; }
if (id == 1010 && code == BN_CLICKED) {
g_rel = (SendMessage(g_hRC, BM_GETCHECK, 0, 0) == BST_CHECKED);
break;
}
if (id == 1003 && code == BN_CLICKED) {
g_je.store(SendMessage(g_hJC, BM_GETCHECK, 0, 0) == BST_CHECKED);
break;
}
if (id == 1004 && code == EN_CHANGE && g_init) {
char buf[16] = {0}; GetWindowTextA(g_hJE, buf, sizeof(buf));
if (buf[0]) { int val = atoi(buf); if (val < 0) val = 0; if (val > 100) val = 100; g_jr.store(val); }
break;
}
if (id == 1005 && code == BN_CLICKED) {
if (g_ic.load()) {
SendMessage(g_hSC, BM_SETCHECK, g_seq.load() ? BST_CHECKED : BST_UNCHECKED, 0);
break;
}
g_seq.store(SendMessage(g_hSC, BM_GETCHECK, 0, 0) == BST_CHECKED);
break;
}
if (id == 1006 && code == EN_KILLFOCUS) {
if (g_ic.load()) break;
char buf[512] = {0}; GetWindowTextA(g_hSE, buf, sizeof(buf)-1);
ParseCoordinates(buf);
break;
}
if (id == 1007) { ToggleRecording(); break; }
if (id == 1008) {
if (g_ply.load()) { g_ply = false; SetWindowTextA(g_hPB, "回放"); break; }
if (g_ic.load() || g_seq.load()) {
MessageBoxA(hwnd, "请先停止连点或关闭序列。", "提示", MB_OK);
break;
}
if (g_evt.empty()) { MessageBoxA(hwnd, "没有录制数据。", "提示", MB_OK); break; }
SetWindowTextA(g_hPB, "停止");
g_hPlay = CreateThread(nullptr, 0, PlaybackThread, nullptr, 0, nullptr);
if (!g_hPlay) { MessageBoxA(hwnd, "创建回放线程失败。", "错误", MB_OK); SetWindowTextA(g_hPB, "回放"); }
break;
}
if (id == 1009 && code == EN_CHANGE) {
char buf[16] = {0}; GetWindowTextA(g_hSS, buf, sizeof(buf));
if (buf[0]) { int val = max(1, min(1000, atoi(buf))); g_ps.store(val); }
break;
}
if (id == 1002) {
if (code == CBN_SELCHANGE) {
int sel = (int)SendMessage(g_hBC, CB_GETCURSEL, 0, 0);
if (sel >= 0 && sel <= 2) g_cb.store(sel);
} else if (code == 0) { DestroyWindow(g_hM); }
break;
}
if (id == 1001 && code == EN_CHANGE && g_init) {
char buf[16] = {0}; GetWindowTextA(g_hDE, buf, sizeof(buf));
if (buf[0] == '\0') break;
int val = atoi(buf);
if (val < 0) val = 0; if (val > 10000) val = 10000;
if (val == 0) {
int ret = MessageBoxA(hwnd, "进入极速模式(延迟0),CPU占用略高。\n确定继续?", "提示", MB_OKCANCEL);
if (ret == IDCANCEL) { val = 100; char tmp[16]; sprintf(tmp, "%d", val); SetWindowTextA(g_hDE, tmp); }
}
g_cd.store(val);
g_em.store(val == 0);
UpdateDelayDisplay();
if (!g_ic.load()) UpdateCount();
break;
}
switch (id) {
case 1: {
char buf[512] = {0}; GetWindowTextA(g_hSE, buf, sizeof(buf)-1);
ParseCoordinates(buf);
if (g_seq.load() && g_pts.empty()) {
MessageBoxA(hwnd, "序列已启用但坐标为空,已自动禁用。", "提示", MB_OK);
g_seq = false;
SendMessage(g_hSC, BM_SETCHECK, BST_UNCHECKED, 0);
}
g_ic = true;
UpdateUI();
strcpy(g_nid.szTip, "自动连点器 (运行中)");
Shell_NotifyIconA(NIM_MODIFY, &g_nid);
break;
}
case 2: {
g_ic = false;
UpdateUI();
UpdateCount();
strcpy(g_nid.szTip, "自动连点器 (已停止)");
Shell_NotifyIconA(NIM_MODIFY, &g_nid);
break;
}
case 3: DestroyWindow(g_hM); break;
case 1001: ShowMainWindow(); break;
}
break;
}
case WM_HOTKEY: {
if (wParam == HOTKEY_F6) {
bool running = g_ic.load();
g_ic = !running;
UpdateUI();
if (!running) UpdateCount();
strcpy(g_nid.szTip, g_ic.load() ? "自动连点器 (运行中)" : "自动连点器 (已停止)");
Shell_NotifyIconA(NIM_MODIFY, &g_nid);
} else if (wParam == HOTKEY_ESC) {
DestroyWindow(g_hM);
} else if (wParam == HOTKEY_F7) {
ToggleRecording();
}
break;
}
case WM_USER + 1: UpdateCount(); break;
case WM_CTLCOLORSTATIC: {
HDC hdc = (HDC)wParam;
HWND hCtrl = (HWND)lParam;
if (hCtrl == g_hS) {
if (!g_bS) {
RECT rc; GetClientRect(g_hS, &rc);
g_bS = CreateGradientBrush(rc.right-rc.left, rc.bottom-rc.top, RGB(30,60,120), RGB(60,90,138));
}
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, RGB(255,255,255));
return (LRESULT)g_bS;
}
SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
SetTextColor(hdc, RGB(0,0,0));
return (LRESULT)GetSysColorBrush(COLOR_WINDOW);
}
case WM_CTLCOLOREDIT: {
HDC hdc = (HDC)wParam;
SetTextColor(hdc, RGB(0,0,0));
SetBkColor(hdc, RGB(255,255,255));
return (LRESULT)g_bW;
}
case WM_CLOSE:
ShowWindow(hwnd, SW_HIDE);
return 0;
case WM_DESTROY: {
KillTimer(hwnd, TIMER_CPS);
if (g_recPend) { KillTimer(hwnd, g_cdTimer); g_recPend = false; }
if (g_mpAct) {
g_mpStop.store(true);
if (g_mpHook) UnhookWindowsHookEx(g_mpHook);
if (g_hOv) DestroyWindow(g_hOv);
g_mpAct = false;
}
if (g_hMacW) DestroyWindow(g_hMacW);
UnregisterHotKey(hwnd, HOTKEY_F6);
UnregisterHotKey(hwnd, HOTKEY_ESC);
UnregisterHotKey(hwnd, HOTKEY_F7);
DeleteTrayIcon();
if (g_mh) UnhookWindowsHookEx(g_mh);
if (g_kh) UnhookWindowsHookEx(g_kh);
if (g_hPlay) { WaitForSingleObject(g_hPlay, 500); CloseHandle(g_hPlay); g_hPlay = nullptr; }
if (g_icon) DestroyIcon(g_icon);
if (g_fS) DeleteObject(g_fS);
if (g_fN) DeleteObject(g_fN);
if (g_bW) DeleteObject(g_bW);
if (g_bS) DeleteObject(g_bS);
g_init = false;
g_se = true;
PostQuitMessage(0);
break;
}
default: return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow) {
(void)hPrev; (void)nShow;
SetDPIAwareness();
bool onlyHelp = false;
if (lpCmd && strlen(lpCmd) > 0) {
string cmd = lpCmd;
size_t start = cmd.find_first_not_of(" \t");
if (start != string::npos) {
cmd = cmd.substr(start);
size_t end = cmd.find_last_not_of(" \t");
if (end != string::npos) cmd = cmd.substr(0, end+1);
if (cmd == "--help" || cmd == "-h") onlyHelp = true;
}
}
if (onlyHelp) {
PrintCommandHelp();
return 0;
}
HANDLE hMutex = CreateMutexA(NULL, FALSE, "AutoClickerMutex");
if (GetLastError() == ERROR_ALREADY_EXISTS) {
HWND hExisting = FindWindowA("AutoClickerClass", NULL);
if (hExisting) {
if (lpCmd && strlen(lpCmd) > 0) {
COPYDATASTRUCT cds;
cds.dwData = 1;
cds.cbData = strlen(lpCmd) + 1;
cds.lpData = lpCmd;
SendMessage(hExisting, WM_COPYDATA, 0, (LPARAM)&cds);
ShowWindow(hExisting, SW_SHOW);
SetForegroundWindow(hExisting);
} else {
ShowWindow(hExisting, SW_SHOW);
SetForegroundWindow(hExisting);
}
}
CloseHandle(hMutex);
return 0;
}
timeBeginPeriod(1);
g_icon = LoadCustomIcon();
WNDCLASSA wc = {};
wc.lpfnWndProc = WndProc;
wc.hInstance = hInst;
wc.lpszClassName = "AutoClickerClass";
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hIcon = g_icon;
if (!RegisterClassA(&wc)) {
MessageBoxA(nullptr, "注册窗口类失败", "错误", MB_OK);
timeEndPeriod(1); CloseHandle(hMutex); return 1;
}
g_hM = CreateWindowA("AutoClickerClass", "自动连点器",
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, 1100, 820,
nullptr, nullptr, hInst, nullptr);
if (!g_hM) {
MessageBoxA(nullptr, "创建窗口失败", "错误", MB_OK);
timeEndPeriod(1); CloseHandle(hMutex); return 1;
}
SendMessageA(g_hM, WM_SETICON, ICON_SMALL, (LPARAM)g_icon);
SendMessageA(g_hM, WM_SETICON, ICON_BIG, (LPARAM)g_icon);
if (lpCmd && strlen(lpCmd) > 0) {
char* cmdCopy = new char[strlen(lpCmd) + 1];
strcpy(cmdCopy, lpCmd);
PostMessage(g_hM, WM_EXECUTE_CMD, (WPARAM)cmdCopy, 0);
}
ShowWindow(g_hM, SW_SHOW);
UpdateWindow(g_hM);
HANDLE hClicker = CreateThread(nullptr, 0, ClickerThread, nullptr, 0, nullptr);
if (!hClicker) {
MessageBoxA(nullptr, "创建线程失败", "错误", MB_OK);
timeEndPeriod(1); CloseHandle(hMutex); return 1;
}
MSG msg;
while (GetMessageA(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
g_se = true;
WaitForSingleObject(hClicker, INFINITE);
CloseHandle(hClicker);
timeEndPeriod(1);
CloseHandle(hMutex);
return 0;
}

粤公网安备44010602015266号