c++版鼠标连点器(windows)

caiziling 2026-08-28 21:34:41

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;
}