C++版鼠标连点器(Windows)

caiziling 2026-08-28 21:34:41 2026-10-04 15:23:45

Dev-cpp需要链接

-mwindows -static -lcomctl32 -lwinmm -lshell32 -lgdiplus -luxtheme -ld2d1 -lole32 -luuid -luser32 -lgdi32 -lkernel32 -std=c++14

代码(V2.0)

#define WINVER         0x0600
#define _WIN32_WINNT   0x0600
#include<windows.h>
#include<commctrl.h>
#include<atomic>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<random>
#include<vector>
#include<string>
#include<sstream>
#include<mmsystem.h>
#include<algorithm>
#include<cctype>
#include<mutex>
#include<chrono>
#include<shellapi.h>
#include<gdiplus.h>
#include<uxtheme.h>
#include<d2d1.h>
#include<d2d1helper.h>
#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,"shell32.lib")
#pragma comment(lib,"gdiplus.lib")
#pragma comment(lib,"uxtheme.lib")
#pragma comment(lib,"d2d1.lib")
#ifdef _MSC_VER
#pragma comment(lib,"winmm.lib")
#endif
using namespace std;
void SetDPIAwareness(){
	HMODULE hUser32=GetModuleHandleW(L"user32.dll");
	if(hUser32){
		typedef BOOL(WINAPI*PFN)(PVOID);
		PFN pV2=(PFN)GetProcAddress(hUser32,"SetProcessDPIAwarenessContext");
		if(pV2&&pV2((PVOID)-4))return;
	}
	HMODULE hShcore=LoadLibraryW(L"Shcore.dll");
	if(hShcore){
		typedef HRESULT(WINAPI*PFN2)(int);
		PFN2 p=(PFN2)GetProcAddress(hShcore,"SetProcessDpiAwareness");
		if(p&&SUCCEEDED(p(2))){
			FreeLibrary(hShcore);
			return;
		}
		FreeLibrary(hShcore);
	}
	if(hUser32){
		typedef BOOL(WINAPI*PFN3)();
		PFN3 p=(PFN3)GetProcAddress(hUser32,"SetProcessDPIAware");
		if(p)p();
	}
}
atomic<bool>isClicking(false);
atomic<bool>shouldExit(false);
atomic<int>clickDelay(100);
atomic<int>clickCount(0);
atomic<double>currentCPS(0.0);
atomic<int>clickButton(0);
atomic<bool>isExtremeMode(false);
atomic<bool>jitterEnabled(false);
atomic<int>jitterRange(10);
atomic<bool>sequenceEnabled(false);
vector<pair<int,int>>clickPoints;
atomic<bool>isRecording(false);
atomic<bool>isPlaying(false);
atomic<int>playbackSpeed(50);
struct RecordedEvent{
	int type,x,y,data;
	DWORD time;
	bool isRelative;
};
vector<RecordedEvent>recordedEvents;
HHOOK mouseHook=nullptr;
HANDLE hPlaybackThread=nullptr;
int lastMoveTime=0;
HHOOK keyboardHook=nullptr;
HWND hwndMain=nullptr;
HWND hwndStatusBar=nullptr;
HWND hwndDelayEdit=nullptr;
HWND hwndDelayLabel=nullptr;
HWND hwndButtonCombo=nullptr;
HWND hwndJitterCheck=nullptr;
HWND hwndJitterEdit=nullptr;
HWND hwndSeqCheck=nullptr;
HWND hwndSeqEdit=nullptr;
HWND hwndRecBtn=nullptr;
HWND hwndPlayBtn=nullptr;
HWND hwndSpeedSlider=nullptr;
HWND hwndStartBtn=nullptr;
HWND hwndStopBtn=nullptr;
HWND hwndExitBtn=nullptr;
HWND hwndRelativeCheck=nullptr;
HWND hwndMacroBtn=nullptr;
HWND hwndTitle1=nullptr,hwndTitle2=nullptr,hwndTitle3=nullptr,hwndTitle4=nullptr;
HWND hwndLblDelay=nullptr,hwndLblButton=nullptr,hwndLblJitter=nullptr,hwndLblCoord=nullptr;
HWND hwndLblSpeed=nullptr,hwndLblMacroHint=nullptr,hwndLblHotkey=nullptr;
#define BASE_W 1080
#define BASE_H 700
#define MIN_SCALE 0.75
#define MAX_FONT_SCALE 1.6
#define EDIT_INSET_X 8
#define EDIT_INSET_Y 2
#define WINUI_RADIUS 4   
struct FontSlot{
	int baseSize;
	int weight;
	HFONT hFont;
};
static FontSlot g_fontSlots[7]={
	{28,FW_SEMIBOLD,nullptr},{19,FW_NORMAL,nullptr},
	{22,FW_BOLD,nullptr},     {19,FW_NORMAL,nullptr},
	{21,FW_BOLD,nullptr},     {19,FW_NORMAL,nullptr},
	{16,FW_NORMAL,nullptr}
};
#define F_STATUS      g_fontSlots[0].hFont
#define F_STATUSINFO  g_fontSlots[1].hFont
#define F_DOT         g_fontSlots[2].hFont
#define F_NORMAL      g_fontSlots[3].hFont
#define F_TITLE       g_fontSlots[4].hFont
#define F_BUTTON      g_fontSlots[5].hFont
#define F_INPUT       g_fontSlots[6].hFont
vector<HWND>g_fontGroups[7];
double g_scale=-1.0;
int g_lastMainFontSize  =-1;
int g_lastMacroFontSize=-1;
#define MACRO_BASE_W 900
#define MACRO_BASE_H 500
struct MacroFontSlot{
	int baseSize;
	int weight;
	HFONT hFont;
};
static MacroFontSlot g_macroFontSlots[2]={
	{19,FW_NORMAL,nullptr},{19,FW_NORMAL,nullptr}
};
#define MF_NORMAL  g_macroFontSlots[0].hFont
#define MF_BUTTON  g_macroFontSlots[1].hFont
double g_macroScale=-1.0;
bool g_bRelativeMode=true;
bool g_bRecordingPending=false;
int g_countdownSeconds=3;
UINT g_countdownTimerId=1004;
int g_currentCountdown=0;
HWND hwndMacro=nullptr;
bool g_bMacroRecording=false;
bool g_bMacroPlaying=false;
vector<RecordedEvent>macroEvents;
HHOOK g_macroMouseHook=nullptr;
HHOOK g_macroKeyboardHook=nullptr;
HANDLE hMacroPlayThread=nullptr;
int g_macroPlaySpeed=50;
bool g_bMacroLoop=false;
bool g_bMacroRecordMove=false;
HWND hwndMacroList=nullptr;
HWND hwndMacroPlayBtn=nullptr;
HWND hwndMacroRecBtn=nullptr;
HWND hwndMacroStopRecBtn=nullptr;
HWND hwndMacroStopPlayBtn=nullptr;
HWND hwndMacroLoopCheck=nullptr;
HWND hwndMacroSpeedLabel=nullptr;
HWND hwndMacroSpeedEdit=nullptr;
HWND hwndMacroMoveCheck=nullptr;
atomic<bool>g_bMacroStopPlay(false);
mutex g_macroMutex;
#define TIMER_CPS          1003
#define WM_TRAYICON        (WM_USER+100)
#define WM_ADD_COORD       (WM_USER+2)
#define WM_MACRO_UPDATE    (WM_USER+4)
#define WM_EXECUTE_CMD     (WM_USER+5)
#define WM_MACRO_ADD_EVENT (WM_USER+10)
#define TRAY_SHOW   5001
#define TRAY_HIDE   5002
#define TRAY_TOGGLE 5003
#define TRAY_EXIT   5004
#define ID_STATUS_BAR  9001
#define TOGGLE_ANIM_TIMER_ID  0xA100
HBRUSH hBrushWhite=nullptr;
HBRUSH hBrushBg=nullptr;
bool g_bInitDone=false;
bool g_bTrayCreated=false;
NOTIFYICONDATAA g_nid={};
HICON g_hAppIcon=nullptr;
HICON g_hBlankIcon=nullptr;
ULONG_PTR g_gdiplusToken=0;
ID2D1Factory*g_pD2DFactory=nullptr;
bool g_bD2DReady=false;
thread_local mt19937 rng((unsigned int)time(nullptr)^(unsigned int)GetCurrentThreadId());
namespace WinUI{
	const Gdiplus::Color Accent        (255,   0,103,192);
	const Gdiplus::Color AccentPressed(255,   0,  90,158);
	const Gdiplus::Color ControlBg     (255,253,253,253);
	const Gdiplus::Color ControlPress  (255,249,249,249);
	const Gdiplus::Color ControlHover  (255,246,246,246);
	const Gdiplus::Color Border        (255,229,229,229);
	const Gdiplus::Color BorderStrong  (255,199,199,199);
	const Gdiplus::Color TextPrimary   (255,  26,  26,  26);
	const Gdiplus::Color TextSecondary(255,  92,  92,  92);
	const Gdiplus::Color TextDisabled  (255,158,158,158);
	const Gdiplus::Color DisabledBg    (255,245,245,245);
	const Gdiplus::Color DisabledBorder(255,232,232,232);
	const Gdiplus::Color StatusBg      (255,  32,  60,110);
}
void InitDirect2D(){
	if(g_pD2DFactory)return;
	HRESULT hr=D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,&g_pD2DFactory);
	if(SUCCEEDED(hr)&&g_pD2DFactory){
		g_bD2DReady=true;
	}else{
		g_pD2DFactory=nullptr;
		g_bD2DReady=false;
	}
}
void ShutdownDirect2D(){
	if(g_pD2DFactory){
		g_pD2DFactory->Release();
		g_pD2DFactory=nullptr;
	}
	g_bD2DReady=false;
}
static bool D2DFillRoundRect(HDC hdc,const RECT&rc,float radius,
                             COLORREF fill,bool hasFill,
                             COLORREF border,bool hasBorder,float borderW){
	if(!g_bD2DReady||!g_pD2DFactory)return false;
	int w=rc.right-rc.left;
	int h=rc.bottom-rc.top;
	if(w<=0||h<=0)return false;
	ID2D1DCRenderTarget*pRT=nullptr;
	D2D1_RENDER_TARGET_PROPERTIES props=D2D1::RenderTargetProperties(
	        D2D1_RENDER_TARGET_TYPE_DEFAULT,
	        D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,D2D1_ALPHA_MODE_IGNORE),
	        0,0,
	        D2D1_RENDER_TARGET_USAGE_NONE,
	        D2D1_FEATURE_LEVEL_DEFAULT);
	HRESULT hr=g_pD2DFactory->CreateDCRenderTarget(&props,&pRT);
	if(FAILED(hr)||!pRT)return false;
	RECT bindRect={rc.left,rc.top,rc.right,rc.bottom};
	hr=pRT->BindDC(hdc,&bindRect);
	if(FAILED(hr)){
		pRT->Release();
		return false;
	}
	pRT->BeginDraw();
	pRT->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
	float maxR=((float)w<(float)h?(float)w:(float)h)*0.5f;
	float r=radius;
	if(r>maxR)r=maxR;
	if(r<0.0f)r=0.0f;
	if(hasFill){
		D2D1_ROUNDED_RECT rr=D2D1::RoundedRect(
		                           D2D1::RectF(0.0f,0.0f,(float)w,(float)h),r,r);
		ID2D1SolidColorBrush*pBrush=nullptr;
		D2D1_COLOR_F c=D2D1::ColorF(
		                     GetRValue(fill)/255.0f,GetGValue(fill)/255.0f,
		                     GetBValue(fill)/255.0f,1.0f);
		if(SUCCEEDED(pRT->CreateSolidColorBrush(c,&pBrush))&&pBrush){
			pRT->FillRoundedRectangle(rr,pBrush);
			pBrush->Release();
		}
	}
	if(hasBorder&&borderW>0.0f){
		float halfBw=borderW*0.5f;
		float innerW=(float)w-borderW;
		float innerH=(float)h-borderW;
		float innerR=r-halfBw;
		if(innerW<1.0f)innerW=1.0f;
		if(innerH<1.0f)innerH=1.0f;
		if(innerR<0.5f)innerR=0.5f;
		D2D1_ROUNDED_RECT rr=D2D1::RoundedRect(
		                           D2D1::RectF(halfBw,halfBw,halfBw+innerW,halfBw+innerH),
		                           innerR,innerR);
		ID2D1SolidColorBrush*pBrush=nullptr;
		D2D1_COLOR_F c=D2D1::ColorF(
		                     GetRValue(border)/255.0f,GetGValue(border)/255.0f,
		                     GetBValue(border)/255.0f,1.0f);
		if(SUCCEEDED(pRT->CreateSolidColorBrush(c,&pBrush))&&pBrush){
			pRT->DrawRoundedRectangle(rr,pBrush,borderW);
			pBrush->Release();
		}
	}
	hr=pRT->EndDraw();
	pRT->Release();
	return SUCCEEDED(hr);
}
static Gdiplus::GraphicsPath*MakeRoundRectPath(Gdiplus::REAL x,Gdiplus::REAL y,
        Gdiplus::REAL w,Gdiplus::REAL h,
        Gdiplus::REAL radius){
	Gdiplus::GraphicsPath*p=new Gdiplus::GraphicsPath();
	if(radius<0.5f){
		p->AddRectangle(Gdiplus::RectF(x,y,w,h));
		return p;
	}
	Gdiplus::REAL maxR=(w<h?w:h)*0.5f;
	if(radius>maxR)radius=maxR;
	Gdiplus::REAL d=radius*2.0f;
	p->AddArc(x,y,d,d,180.0f,90.0f);
	p->AddArc(x+w-d,y,d,d,270.0f,90.0f);
	p->AddArc(x+w-d,y+h-d,d,d,0.0f,90.0f);
	p->AddArc(x,y+h-d,d,d,90.0f,90.0f);
	p->CloseFigure();
	return p;
}
static void GdiPlusFillRoundRect(HDC hdc,const RECT&rc,Gdiplus::REAL radius,
                                 Gdiplus::Color fill,Gdiplus::Color border,Gdiplus::REAL borderW){
	bool hasFill   =(fill.GetA()>0);
	bool hasBorder=(border.GetA()>0&&borderW>0);
	if(hasFill||hasBorder){
		COLORREF fillC   =RGB(fill.GetR(),   fill.GetG(),   fill.GetB());
		COLORREF borderC=RGB(border.GetR(),border.GetG(),border.GetB());
		if(D2DFillRoundRect(hdc,rc,(float)radius,
		                     fillC,hasFill,
		                     borderC,hasBorder,(float)borderW)){
			return;
		}
	}
	Gdiplus::Graphics gfx(hdc);
	gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
	gfx.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHalf);
	Gdiplus::REAL px=(Gdiplus::REAL)rc.left;
	Gdiplus::REAL py=(Gdiplus::REAL)rc.top;
	Gdiplus::REAL w  =(Gdiplus::REAL)(rc.right-rc.left);
	Gdiplus::REAL h  =(Gdiplus::REAL)(rc.bottom-rc.top);
	if(w<1.0f||h<1.0f)return;
	if(hasFill){
		Gdiplus::GraphicsPath*pathFill=MakeRoundRectPath(px,py,w,h,radius);
		Gdiplus::SolidBrush br(fill);
		gfx.FillPath(&br,pathFill);
		delete pathFill;
	}
	if(hasBorder){
		Gdiplus::REAL halfBw=borderW*0.5f;
		Gdiplus::REAL innerW=w-borderW;
		Gdiplus::REAL innerH=h-borderW;
		Gdiplus::REAL innerR=radius-halfBw;
		if(innerW<1.0f)innerW=1.0f;
		if(innerH<1.0f)innerH=1.0f;
		if(innerR<0.5f)innerR=0.5f;
		Gdiplus::GraphicsPath*pathBorder=MakeRoundRectPath(
		                                        px+halfBw,py+halfBw,innerW,innerH,innerR);
		Gdiplus::Pen pen(border,borderW);
		pen.SetLineJoin(Gdiplus::LineJoinRound);
		pen.SetStartCap(Gdiplus::LineCapRound);
		pen.SetEndCap(Gdiplus::LineCapRound);
		gfx.DrawPath(&pen,pathBorder);
		delete pathBorder;
	}
}
HICON LoadCustomIcon(){
	HINSTANCE hInst=GetModuleHandleA(nullptr);
	HICON h=(HICON)LoadImageA(nullptr,"clicker.ico",IMAGE_ICON,
	                            0,0,LR_LOADFROMFILE|LR_DEFAULTCOLOR);
	if(h)return h;
	h=LoadIconA(hInst,"CLICKER");
	if(h)return h;
	return LoadIconA(nullptr,IDI_APPLICATION);
}
void RecreateFonts(double s){
	for(int i=0;i<7;i++){
		if(g_fontSlots[i].hFont){
			DeleteObject(g_fontSlots[i].hFont);
			g_fontSlots[i].hFont=nullptr;
		}
		int size=(int)(g_fontSlots[i].baseSize*s+0.5);
		if(size<9)size=9;
		if(size>80)size=80;
		g_fontSlots[i].hFont=CreateFontW(size,0,0,0,g_fontSlots[i].weight,
		                                   FALSE,FALSE,FALSE,DEFAULT_CHARSET,
		                                   OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY,
		                                   DEFAULT_PITCH|FF_DONTCARE,L"Segoe UI");
	}
}
void ApplyFonts(){
	for(int i=0;i<7;i++){
		for(size_t k=0;k<g_fontGroups[i].size();k++){
			HWND h=g_fontGroups[i][k];
			if(h&&IsWindow(h))SendMessage(h,WM_SETFONT,(WPARAM)g_fontSlots[i].hFont,TRUE);
		}
	}
}
void RecreateMacroFonts(double s){
	for(int i=0;i<2;i++){
		if(g_macroFontSlots[i].hFont){
			DeleteObject(g_macroFontSlots[i].hFont);
			g_macroFontSlots[i].hFont=nullptr;
		}
		int size=(int)(g_macroFontSlots[i].baseSize*s+0.5);
		if(size<9)size=9;
		if(size>60)size=60;
		g_macroFontSlots[i].hFont=CreateFontW(size,0,0,0,g_macroFontSlots[i].weight,
		                                        FALSE,FALSE,FALSE,DEFAULT_CHARSET,
		                                        OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY,
		                                        DEFAULT_PITCH|FF_DONTCARE,L"Segoe UI");
	}
}
void ApplyMacroFonts(){
	if(hwndMacroList)        SendMessage(hwndMacroList,        WM_SETFONT,(WPARAM)MF_NORMAL,TRUE);
	if(hwndMacroRecBtn)      SendMessage(hwndMacroRecBtn,      WM_SETFONT,(WPARAM)MF_BUTTON,TRUE);
	if(hwndMacroStopRecBtn)  SendMessage(hwndMacroStopRecBtn,  WM_SETFONT,(WPARAM)MF_BUTTON,TRUE);
	if(hwndMacroPlayBtn)     SendMessage(hwndMacroPlayBtn,     WM_SETFONT,(WPARAM)MF_BUTTON,TRUE);
	if(hwndMacroStopPlayBtn)SendMessage(hwndMacroStopPlayBtn,WM_SETFONT,(WPARAM)MF_BUTTON,TRUE);
	if(hwndMacroLoopCheck)   SendMessage(hwndMacroLoopCheck,   WM_SETFONT,(WPARAM)MF_NORMAL,TRUE);
	if(hwndMacroSpeedLabel)  SendMessage(hwndMacroSpeedLabel,  WM_SETFONT,(WPARAM)MF_NORMAL,TRUE);
	if(hwndMacroSpeedEdit)   SendMessage(hwndMacroSpeedEdit,   WM_SETFONT,(WPARAM)MF_NORMAL,TRUE);
	if(hwndMacroMoveCheck)   SendMessage(hwndMacroMoveCheck,   WM_SETFONT,(WPARAM)MF_NORMAL,TRUE);
}
void ApplyRoundedRegion(HWND h){
	(void)h;
}
LRESULT CALLBACK ModernInputProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam,
                                 UINT_PTR uIdSubclass,DWORD_PTR dwRefData){
	switch(msg){
		case WM_SIZE:
			ApplyRoundedRegion(hwnd);
			break;
		case WM_SETFOCUS:
		case WM_KILLFOCUS:
			InvalidateRect(GetParent(hwnd),nullptr,FALSE);
			break;
		case WM_CHAR:
		case WM_KEYDOWN:
		case WM_PASTE:
		case WM_CUT:
			if(isClicking.load())return 0;
			break;
		case WM_NCDESTROY:
			RemoveWindowSubclass(hwnd,ModernInputProc,uIdSubclass);
			break;
	}
	return DefSubclassProc(hwnd,msg,wParam,lParam);
}
struct ToggleAnimState{
	double pos;
	double target;
	bool   timerRunning;
	DWORD  animStart;
	double animFrom;
	double knobScale;
	double knobScaleTarget;
	bool   pressed;
};
static double EaseOutCubic(double t){
	if(t<0.0)t=0.0;
	if(t>1.0)t=1.0;
	double u=1.0-t;
	return 1.0-u*u*u;
}
static const DWORD TOGGLE_ANIM_DURATION_MS=167;
static const UINT  TOGGLE_ANIM_TIMER_MS   =10;
LRESULT CALLBACK RoundCheckBoxProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam,
                                   UINT_PTR uIdSubclass,DWORD_PTR dwRefData){
	ToggleAnimState*st=(ToggleAnimState*)dwRefData;
	switch(msg){
		case WM_LBUTTONDOWN:{
			if(!IsWindowEnabled(hwnd)||isClicking.load())return 0;
			if(st){
				st->pressed=true;
				st->knobScaleTarget=1.12;
				if(!st->timerRunning){
					st->timerRunning=true;
					SetTimer(hwnd,TOGGLE_ANIM_TIMER_ID,TOGGLE_ANIM_TIMER_MS,nullptr);
				}
			}
			SetCapture(hwnd);
			return 0;
		}
		case WM_LBUTTONUP:{
			if(!IsWindowEnabled(hwnd)||isClicking.load()){
				ReleaseCapture();
				return 0;
			}
			ReleaseCapture();
			if(st){
				st->pressed=false;
				st->knobScaleTarget=1.0;
			}
			POINT pt={LOWORD(lParam),HIWORD(lParam)};
			RECT rc;
			GetClientRect(hwnd,&rc);
			if(PtInRect(&rc,pt)){
				bool checked=(SendMessage(hwnd,BM_GETCHECK,0,0)==BST_CHECKED);
				SendMessage(hwnd,BM_SETCHECK,checked?BST_UNCHECKED:BST_CHECKED,0);
				HWND parent=GetParent(hwnd);
				if(parent)SendMessage(parent,WM_COMMAND,
					                        MAKEWPARAM(GetDlgCtrlID(hwnd),BN_CLICKED),(LPARAM)hwnd);
			}
			return 0;
		}
		case WM_CAPTURECHANGED:{
			if(st&&st->pressed){
				st->pressed=false;
				st->knobScaleTarget=1.0;
				if(!st->timerRunning){
					st->timerRunning=true;
					SetTimer(hwnd,TOGGLE_ANIM_TIMER_ID,TOGGLE_ANIM_TIMER_MS,nullptr);
				}
			}
			break;
		}
		case WM_PAINT:{
			PAINTSTRUCT ps;
			HDC hdc=BeginPaint(hwnd,&ps);
			RECT rc;
			GetClientRect(hwnd,&rc);
			if(rc.right<=0||rc.bottom<=0||!st){
				EndPaint(hwnd,&ps);
				return 0;
			}
			bool disabled=!IsWindowEnabled(hwnd);
			HWND parent=GetParent(hwnd);
			bool isMacro=(hwndMacro&&parent==hwndMacro);
			HBRUSH hBgBr=isMacro?(HBRUSH)GetStockObject(WHITE_BRUSH)
			               :(hBrushBg?hBrushBg:(HBRUSH)GetStockObject(WHITE_BRUSH));
			int h=rc.bottom-rc.top;
			int trackH=h-8;
			if(trackH<14)trackH=14;
			if(trackH>50)trackH=50;
			int trackW=(int)(trackH*1.8);
			if(trackW<26)trackW=26;
			int trackX=rc.left+2;
			int trackY=rc.top+(h-trackH)/2;
			double p=st->pos;
			if(p<0.0)p=0.0;
			if(p>1.0)p=1.0;
			int r,g,b;
			if(disabled){
				r=(int)(224+(196-224)*p);
				g=(int)(224+(196-224)*p);
				b=(int)(224+(196-224)*p);
			}else{
				r=(int)(156+(  0-156)*p);
				g=(int)(160+(103-160)*p);
				b=(int)(164+(192-164)*p);
			}
			HDC memDC=CreateCompatibleDC(hdc);
			HBITMAP memBmp=CreateCompatibleBitmap(hdc,rc.right,rc.bottom);
			HBITMAP oldBmp=(HBITMAP)SelectObject(memDC,memBmp);
			FillRect(memDC,&rc,hBgBr);
			{
				Gdiplus::Graphics gfx(memDC);
				gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
				gfx.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHalf);
				int d=trackH;
				Gdiplus::GraphicsPath path;
				path.AddArc((Gdiplus::REAL)trackX,(Gdiplus::REAL)trackY,
				            (Gdiplus::REAL)d,(Gdiplus::REAL)d,90.0f,180.0f);
				path.AddArc((Gdiplus::REAL)(trackX+trackW-d),(Gdiplus::REAL)trackY,
				            (Gdiplus::REAL)d,(Gdiplus::REAL)d,270.0f,180.0f);
				path.CloseFigure();
				Gdiplus::SolidBrush trackBrush(Gdiplus::Color(255,r,g,b));
				gfx.FillPath(&trackBrush,&path);
				int knobBase=trackH-4;
				double scale=st->knobScale;
				if(scale<1.0)scale=1.0;
				if(scale>1.25)scale=1.25;
				int knobSize=(int)(knobBase*scale+0.5);
				int travel=trackW-knobBase-4;
				int knobCenterBaseX=trackX+2+(int)(travel*p+0.5)+knobBase/2;
				int knobCenterBaseY=trackY+2+knobBase/2;
				int knobX=knobCenterBaseX-knobSize/2;
				int knobY=knobCenterBaseY-knobSize/2;
				if(!disabled&&p>0.001){
					Gdiplus::SolidBrush shadowBrush(Gdiplus::Color(30,0,0,0));
					gfx.FillEllipse(&shadowBrush,
					                (Gdiplus::REAL)knobX,(Gdiplus::REAL)(knobY+1),
					                (Gdiplus::REAL)knobSize,(Gdiplus::REAL)knobSize);
				}
				Gdiplus::Color knobColor=disabled?Gdiplus::Color(255,245,245,245)
				                           :Gdiplus::Color(255,255,255,255);
				Gdiplus::SolidBrush knobBrush(knobColor);
				gfx.FillEllipse(&knobBrush,
				                (Gdiplus::REAL)knobX,(Gdiplus::REAL)knobY,
				                (Gdiplus::REAL)knobSize,(Gdiplus::REAL)knobSize);
			}
			wchar_t text[256];
			GetWindowTextW(hwnd,text,256);
			if(text[0]){
				SetBkMode(memDC,TRANSPARENT);
				SetTextColor(memDC,disabled?RGB(158,158,158):RGB(26,26,26));
				HFONT hF=(HFONT)SendMessage(hwnd,WM_GETFONT,0,0);
				HFONT hOldF=(HFONT)SelectObject(memDC,hF);
				RECT textRc=rc;
				textRc.left=trackX+trackW+8;
				DrawTextW(memDC,text,-1,&textRc,DT_LEFT|DT_VCENTER|DT_SINGLELINE);
				SelectObject(memDC,hOldF);
			}
			BitBlt(hdc,0,0,rc.right,rc.bottom,memDC,0,0,SRCCOPY);
			SelectObject(memDC,oldBmp);
			DeleteObject(memBmp);
			DeleteDC(memDC);
			EndPaint(hwnd,&ps);
			return 0;
		}
		case WM_ERASEBKGND:
			return 1;
		case WM_TIMER:{
			if(wParam==TOGGLE_ANIM_TIMER_ID&&st){
				DWORD now=GetTickCount();
				DWORD elapsed=now-st->animStart;
				double t=(double)elapsed/(double)TOGGLE_ANIM_DURATION_MS;
				bool posDone=false;
				if(t>=1.0){
					st->pos=st->target;
					posDone=true;
				}else{
					st->pos=st->animFrom+(st->target-st->animFrom)*EaseOutCubic(t);
				}
				double ds=st->knobScaleTarget-st->knobScale;
				bool scaleDone;
				if(fabs(ds)<0.005){
					st->knobScale=st->knobScaleTarget;
					scaleDone=true;
				}else{
					st->knobScale+=ds*0.4;
					scaleDone=false;
				}
				InvalidateRect(hwnd,nullptr,FALSE);
				if(posDone&&scaleDone&&!st->pressed){
					KillTimer(hwnd,TOGGLE_ANIM_TIMER_ID);
					st->timerRunning=false;
				}
				return 0;
			}
			break;
		}
		case BM_SETCHECK:{
			LRESULT r=DefSubclassProc(hwnd,msg,wParam,lParam);
			if(st){
				bool checked=(wParam==BST_CHECKED);
				double newTarget=checked?1.0:0.0;
				if(fabs(newTarget-st->target)>0.001){
					st->animFrom=st->pos;
					st->animStart=GetTickCount();
					st->target=newTarget;
					if(!st->timerRunning){
						st->timerRunning=true;
						SetTimer(hwnd,TOGGLE_ANIM_TIMER_ID,TOGGLE_ANIM_TIMER_MS,nullptr);
					}
				}
				InvalidateRect(hwnd,nullptr,FALSE);
			}
			return r;
		}
		case WM_SETFOCUS:
		case WM_KILLFOCUS:
			InvalidateRect(hwnd,nullptr,FALSE);
			break;
		case WM_NCDESTROY:
			if(st){
				if(st->timerRunning)KillTimer(hwnd,TOGGLE_ANIM_TIMER_ID);
				delete st;
			}
			RemoveWindowSubclass(hwnd,RoundCheckBoxProc,uIdSubclass);
			break;
	}
	return DefSubclassProc(hwnd,msg,wParam,lParam);
}
static void AttachToggle(HWND h,bool initialChecked){
	if(initialChecked)SendMessage(h,BM_SETCHECK,BST_CHECKED,0);
	ToggleAnimState*st=new ToggleAnimState;
	st->pos=initialChecked?1.0:0.0;
	st->target=st->pos;
	st->timerRunning=false;
	st->animStart=0;
	st->animFrom=st->pos;
	st->knobScale=1.0;
	st->knobScaleTarget=1.0;
	st->pressed=false;
	SetWindowSubclass(h,RoundCheckBoxProc,0,(DWORD_PTR)st);
}
LRESULT CALLBACK ComboBoxProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam,
                              UINT_PTR uIdSubclass,DWORD_PTR dwRefData){
	switch(msg){
		case WM_NCCALCSIZE:{
			if(wParam==TRUE)return 0;
			break;
		}
		case WM_ERASEBKGND:
			return 1;
		case WM_PAINT:{
			PAINTSTRUCT ps;
			HDC hdc=BeginPaint(hwnd,&ps);
			RECT rc;
			GetClientRect(hwnd,&rc);
			if(rc.right<=0||rc.bottom<=0){
				EndPaint(hwnd,&ps);
				return 0;
			}
			bool disabled=!IsWindowEnabled(hwnd);
			bool focused  =(GetFocus()==hwnd);
			HDC memDC=CreateCompatibleDC(hdc);
			HBITMAP memBmp=CreateCompatibleBitmap(hdc,rc.right,rc.bottom);
			HBITMAP oldBmp=(HBITMAP)SelectObject(memDC,memBmp);
			HBRUSH hBgBr=hBrushBg?hBrushBg:(HBRUSH)GetStockObject(WHITE_BRUSH);
			FillRect(memDC,&rc,hBgBr);
			Gdiplus::Color fill=disabled?WinUI::DisabledBg:WinUI::ControlBg;
			Gdiplus::Color border=disabled?WinUI::DisabledBorder
			                        :(focused?WinUI::Accent:WinUI::BorderStrong);
			Gdiplus::REAL borderW=focused?2.0f:1.0f;
			Gdiplus::REAL radius=WINUI_RADIUS;
			GdiPlusFillRoundRect(memDC,rc,radius,fill,border,borderW);
			if(focused&&!disabled){
				Gdiplus::Graphics gfx(memDC);
				gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
				Gdiplus::Pen underlinePen(WinUI::Accent,2.0f);
				gfx.DrawLine(&underlinePen,
				             (Gdiplus::REAL)(rc.left+(int)radius+2),
				             (Gdiplus::REAL)(rc.bottom-2),
				             (Gdiplus::REAL)(rc.right-(int)radius-2),
				             (Gdiplus::REAL)(rc.bottom-2));
			}
			int sel=(int)SendMessage(hwnd,CB_GETCURSEL,0,0);
			char text[256]={0};
			if(sel!=CB_ERR)SendMessageA(hwnd,CB_GETLBTEXT,sel,(LPARAM)text);
			SetBkMode(memDC,TRANSPARENT);
			SetTextColor(memDC,disabled?RGB(158,158,158):RGB(26,26,26));
			HFONT hF=(HFONT)SendMessage(hwnd,WM_GETFONT,0,0);
			HFONT hOldF=(HFONT)SelectObject(memDC,hF);
			int padLeft=12;
			int padRight=32;
			RECT textRc=rc;
			textRc.left+=padLeft;
			textRc.right-=padRight;
			DrawTextA(memDC,text,-1,&textRc,DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS);
			SelectObject(memDC,hOldF);
			int aw=4,ah=3;
			int arrowCX=rc.right-16;
			int arrowCY=(rc.top+rc.bottom)/2;
			COLORREF arrowColor=disabled?RGB(158,158,158):RGB(90,90,90);
			HPEN hPen=CreatePen(PS_SOLID,2,arrowColor);
			HPEN hOldPen=(HPEN)SelectObject(memDC,hPen);
			MoveToEx(memDC,arrowCX-aw,arrowCY-ah,NULL);
			LineTo(memDC,arrowCX,arrowCY+ah);
			LineTo(memDC,arrowCX+aw,arrowCY-ah);
			SelectObject(memDC,hOldPen);
			DeleteObject(hPen);
			BitBlt(hdc,0,0,rc.right,rc.bottom,memDC,0,0,SRCCOPY);
			SelectObject(memDC,oldBmp);
			DeleteObject(memBmp);
			DeleteDC(memDC);
			EndPaint(hwnd,&ps);
			return 0;
		}
		case WM_SIZE:
			ApplyRoundedRegion(hwnd);
			break;
		case WM_SETFOCUS:
		case WM_KILLFOCUS:
			InvalidateRect(hwnd,nullptr,FALSE);
			InvalidateRect(GetParent(hwnd),nullptr,FALSE);
			break;
		case WM_NCDESTROY:
			RemoveWindowSubclass(hwnd,ComboBoxProc,uIdSubclass);
			break;
	}
	return DefSubclassProc(hwnd,msg,wParam,lParam);
}
void DrawComboListItem(LPDRAWITEMSTRUCT dis){
	HDC hdc=dis->hDC;
	RECT rc=dis->rcItem;
	bool selected=(dis->itemState&ODS_SELECTED)!=0;
	bool comboEdit=(dis->itemState&ODS_COMBOBOXEDIT)!=0;
	int itemID=(int)dis->itemID;
	if(itemID==-1){
		itemID=(int)SendMessage(dis->hwndItem,CB_GETCURSEL,0,0);
		if(itemID==CB_ERR){
			HBRUSH hWhite=(HBRUSH)GetStockObject(WHITE_BRUSH);
			FillRect(hdc,&rc,hWhite);
			return;
		}
	}
	int w=rc.right-rc.left;
	int h=rc.bottom-rc.top;
	if(w<=0||h<=0)return;
	HDC memDC=CreateCompatibleDC(hdc);
	HBITMAP memBmp=CreateCompatibleBitmap(hdc,w,h);
	HBITMAP oldBmp=(HBITMAP)SelectObject(memDC,memBmp);
	RECT local={0,0,w,h};
	{
		Gdiplus::Graphics gfx(memDC);
		gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
		Gdiplus::SolidBrush bg(selected?Gdiplus::Color(255,245,245,245)
		                       :Gdiplus::Color(255,255,255,255));
		gfx.FillRectangle(&bg,0,0,w,h);
		if(selected&&!comboEdit){
			Gdiplus::SolidBrush accent(WinUI::Accent);
			gfx.FillRectangle(&accent,0,6,3,h-12);
		}
	}
	wchar_t text[256]={0};
	SendMessageW(dis->hwndItem,CB_GETLBTEXT,itemID,(LPARAM)text);
	SetBkMode(memDC,TRANSPARENT);
	SetTextColor(memDC,RGB(26,26,26));
	HFONT hF=(HFONT)SendMessage(dis->hwndItem,WM_GETFONT,0,0);
	HFONT hOldF=(HFONT)SelectObject(memDC,hF);
	RECT textRc=local;
	textRc.left+=comboEdit?12:16;
	DrawTextW(memDC,text,-1,&textRc,DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS);
	SelectObject(memDC,hOldF);
	BitBlt(hdc,rc.left,rc.top,w,h,memDC,0,0,SRCCOPY);
	SelectObject(memDC,oldBmp);
	DeleteObject(memBmp);
	DeleteDC(memDC);
}
void DrawStatusBar(LPDRAWITEMSTRUCT dis){
	HDC hdc=dis->hDC;
	RECT rc=dis->rcItem;
	HDC memDC=CreateCompatibleDC(hdc);
	HBITMAP memBmp=CreateCompatibleBitmap(hdc,rc.right-rc.left,rc.bottom-rc.top);
	HBITMAP oldBmp=(HBITMAP)SelectObject(memDC,memBmp);
	RECT local={0,0,rc.right-rc.left,rc.bottom-rc.top};
	{
		Gdiplus::Graphics gfx(memDC);
		gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
		Gdiplus::SolidBrush br(WinUI::StatusBg);
		gfx.FillRectangle(&br,0,0,local.right,local.bottom);
	}
	double s=g_scale>0?g_scale:1.0;
	SetBkMode(memDC,TRANSPARENT);
	HFONT hOld=(HFONT)SelectObject(memDC,F_DOT);
	SetTextColor(memDC,isClicking.load()?RGB(80,220,130):RGB(150,160,180));
	RECT rcDot={(int)(24*s),0,(int)(50*s),local.bottom};
	DrawTextW(memDC,L"●",-1,&rcDot,DT_LEFT|DT_VCENTER|DT_SINGLELINE);
	SelectObject(memDC,F_STATUS);
	SetTextColor(memDC,RGB(255,255,255));
	RECT rcText={(int)(52*s),0,(int)(240*s),local.bottom};
	DrawTextW(memDC,isClicking.load()?L"运行中":L"已停止",-1,&rcText,
	          DT_LEFT|DT_VCENTER|DT_SINGLELINE);
	SelectObject(memDC,F_STATUSINFO);
	SetTextColor(memDC,RGB(190,205,235));
	wchar_t info[128];
	if(isExtremeMode.load())wcscpy(info,L"极速模式   ·   无统计");
	else swprintf(info,128,L"%d 次点击   ·   %.1f CPS",clickCount.load(),currentCPS.load());
	RECT rcInfo={(int)(240*s),0,local.right-(int)(24*s),local.bottom};
	DrawTextW(memDC,info,-1,&rcInfo,DT_RIGHT|DT_VCENTER|DT_SINGLELINE);
	SelectObject(memDC,hOld);
	BitBlt(hdc,0,0,local.right,local.bottom,memDC,0,0,SRCCOPY);
	SelectObject(memDC,oldBmp);
	DeleteObject(memBmp);
	DeleteDC(memDC);
}
void DrawRoundButton(LPDRAWITEMSTRUCT dis){
	HDC hdc=dis->hDC;
	RECT rc=dis->rcItem;
	UINT state=dis->itemState;
	bool pressed  =(state&ODS_SELECTED)!=0;
	bool disabled=(state&ODS_DISABLED)!=0;
	bool focused  =(state&ODS_FOCUS)!=0;
	HWND parent=GetParent(dis->hwndItem);
	bool isMacro=(hwndMacro&&parent==hwndMacro);
	char textBuf[128]={0};
	GetWindowTextA(dis->hwndItem,textBuf,128);
	bool isPrimary=(strstr(textBuf,"开始")!=nullptr)||
	                 (strstr(textBuf,"播放")!=nullptr&&strstr(textBuf,"停止")==nullptr);
	Gdiplus::Color fill,border,txt;
	if(disabled){
		fill=WinUI::DisabledBg;
		border=WinUI::DisabledBorder;
		txt=WinUI::TextDisabled;
	}else if(isPrimary){
		fill=pressed?WinUI::AccentPressed:WinUI::Accent;
		border=Gdiplus::Color(0,0,0,0);
		txt=Gdiplus::Color(255,255,255,255);
	}else{
		fill=pressed?WinUI::ControlPress:WinUI::ControlBg;
		border=WinUI::BorderStrong;
		txt=WinUI::TextPrimary;
	}
	int w=rc.right-rc.left;
	int h=rc.bottom-rc.top;
	RECT local={0,0,w,h};
	HDC memDC=CreateCompatibleDC(hdc);
	HBITMAP memBmp=CreateCompatibleBitmap(hdc,w,h);
	HBITMAP oldBmp=(HBITMAP)SelectObject(memDC,memBmp);
	HBRUSH hBgBr=isMacro?(HBRUSH)GetStockObject(WHITE_BRUSH)
	               :(hBrushBg?hBrushBg:(HBRUSH)GetStockObject(WHITE_BRUSH));
	FillRect(memDC,&local,hBgBr);
	Gdiplus::REAL radius=WINUI_RADIUS;
	GdiPlusFillRoundRect(memDC,local,radius,fill,border,1.0f);
	if(focused&&!disabled){
		Gdiplus::Graphics gfx(memDC);
		gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
		Gdiplus::Pen focusPen(Gdiplus::Color(255,26,26,26),2.0f);
		gfx.DrawRectangle(&focusPen,1.0f,1.0f,(Gdiplus::REAL)(w-2),(Gdiplus::REAL)(h-2));
	}
	wchar_t wtext[256];
	GetWindowTextW(dis->hwndItem,wtext,256);
	SetBkMode(memDC,TRANSPARENT);
	SetTextColor(memDC,RGB(txt.GetR(),txt.GetG(),txt.GetB()));
	HFONT hF=(HFONT)SendMessage(dis->hwndItem,WM_GETFONT,0,0);
	HFONT hOldF=(HFONT)SelectObject(memDC,hF);
	RECT textRc=local;
	DrawTextW(memDC,wtext,-1,&textRc,DT_CENTER|DT_VCENTER|DT_SINGLELINE);
	SelectObject(memDC,hOldF);
	BitBlt(hdc,rc.left,rc.top,w,h,memDC,0,0,SRCCOPY);
	SelectObject(memDC,oldBmp);
	DeleteObject(memBmp);
	DeleteDC(memDC);
}
void PaintInputBorders(HDC hdc){
	HWND inputs[]={hwndDelayEdit,hwndJitterEdit,hwndSpeedSlider,hwndSeqEdit};
	HWND focus=GetFocus();
	RECT clientRc;
	GetClientRect(hwndMain,&clientRc);
	double sx=(double)clientRc.right/BASE_W;
	double sy=(double)clientRc.bottom/BASE_H;
	if(sx<MIN_SCALE)sx=MIN_SCALE;
	if(sx>3.0)sx=3.0;
	if(sy<MIN_SCALE)sy=MIN_SCALE;
	if(sy>3.0)sy=3.0;
	int insetX=(int)(EDIT_INSET_X*sx+0.5);
	int insetY=(int)(EDIT_INSET_Y*sy+0.5);
	if(insetX<3)insetX=3;
	if(insetY<1)insetY=1;
	for(int i=0;i<4;i++){
		HWND h=inputs[i];
		if(!h||!IsWindowVisible(h))continue;
		RECT rc;
		GetWindowRect(h,&rc);
		MapWindowPoints(HWND_DESKTOP,hwndMain,(LPPOINT)&rc,2);
		rc.left   -=insetX;
		rc.right  +=insetX;
		rc.top    -=insetY;
		rc.bottom+=insetY;
		HBRUSH hBgBr=hBrushBg?hBrushBg:(HBRUSH)GetStockObject(WHITE_BRUSH);
		FillRect(hdc,&rc,hBgBr);
		bool hasFocus=(h==focus);
		Gdiplus::Color border=hasFocus?WinUI::Accent:WinUI::BorderStrong;
		Gdiplus::REAL borderW=hasFocus?2.0f:1.0f;
		Gdiplus::REAL radius=WINUI_RADIUS;
		GdiPlusFillRoundRect(hdc,rc,radius,WinUI::ControlBg,border,borderW);
		if(hasFocus){
			Gdiplus::Graphics gfx(hdc);
			gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
			Gdiplus::Pen underlinePen(WinUI::Accent,2.0f);
			gfx.DrawLine(&underlinePen,
			             (Gdiplus::REAL)(rc.left+(int)radius+2),
			             (Gdiplus::REAL)(rc.bottom-2),
			             (Gdiplus::REAL)(rc.right-(int)radius-2),
			             (Gdiplus::REAL)(rc.bottom-2));
		}
	}
}
void ApplyLayout(int clientW,int clientH){
	if(clientW<=0)clientW=BASE_W;
	if(clientH<=0)clientH=BASE_H;
	double sx=(double)clientW/BASE_W;
	double sy=(double)clientH/BASE_H;
	if(sx<MIN_SCALE)sx=MIN_SCALE;
	if(sx>3.0)sx=3.0;
	if(sy<MIN_SCALE)sy=MIN_SCALE;
	if(sy>3.0)sy=3.0;
	double sFont=sqrt(sx*sy);
	if(sFont<MIN_SCALE)      sFont=MIN_SCALE;
	if(sFont>MAX_FONT_SCALE)sFont=MAX_FONT_SCALE;
	int newKey=0;
	for(int i=0;i<7;i++){
		int sz=(int)(g_fontSlots[i].baseSize*sFont+0.5);
		if(sz<9)sz=9;
		if(sz>80)sz=80;
		newKey=newKey*131+sz;
	}
	bool fontChanged=(newKey!=g_lastMainFontSize);
	if(fontChanged)g_lastMainFontSize=newKey;
	g_scale=sFont;
	SendMessage(hwndMain,WM_SETREDRAW,FALSE,0);
	if(fontChanged){
		RecreateFonts(sFont);
		ApplyFonts();
	}
	auto LX=[sx](double v){
		return(int)(v*sx+0.5);
	};
	auto LY=[sy](double v){
		return(int)(v*sy+0.5);
	};
	auto LW=[sx](double v){
		return(int)(v*sx+0.5);
	};
	auto LH=[sy](double v){
		return(int)(v*sy+0.5);
	};
	int baseX=24,baseY=20,statusHBase=52;
	int marginX=LX(baseX);
	int statusW=clientW-marginX*2;
	if(statusW<400)statusW=400;
	int gap=LW(30);
	int colW=(statusW-gap*2)/3;
	if(colW<120)colW=120;
	int x1=marginX;
	int x2=x1+colW+gap;
	int x3=x2+colW+gap;
	int y=baseY+statusHBase+24;
	int insetX=(int)(EDIT_INSET_X*sx+0.5);
	int insetY=(int)(EDIT_INSET_Y*sy+0.5);
	if(insetX<3)insetX=3;
	if(insetY<1)insetY=1;
	HDWP hdwp=BeginDeferWindowPos(40);
#define DEFER(h,xx,yy,ww,hh)do{\
		if((h)&&hdwp)hdwp=DeferWindowPos(hdwp,(h),nullptr,(xx),(yy),(ww),(hh),\
			                                       SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOCOPYBITS);\
	}while(0)
	DEFER(hwndStatusBar,marginX,LY(baseY),statusW,LH(statusHBase));
	DEFER(hwndTitle1,x1,LY(y),colW,LH(26));
	DEFER(hwndTitle2,x2,LY(y),colW,LH(26));
	DEFER(hwndTitle3,x3,LY(y),colW,LH(26));
	DEFER(hwndLblDelay,      x1,             LY(y+42),  LW(80),  LH(24));
	DEFER(hwndDelayEdit,     x1+insetX,LY(y+68)+insetY,
	      LW(80)-insetX*2,LH(28)-insetY*2);
	DEFER(hwndDelayLabel,    x1+LX(95),    LY(y+74),  LW(190),LH(24));
	DEFER(hwndLblButton,     x1,             LY(y+118),LW(80),  LH(24));
	DEFER(hwndButtonCombo,   x1,             LY(y+144),LW(140),LH(300));
	DEFER(hwndJitterCheck,   x1,             LY(y+188),LW(90),  LH(28));
	DEFER(hwndLblJitter,     x1+LX(98),    LY(y+194),LW(36),  LH(18));
	DEFER(hwndJitterEdit,    x1+LX(138)+insetX,LY(y+190)+insetY,
	      LW(50)-insetX*2,LH(24)-insetY*2);
	DEFER(hwndRelativeCheck,x1,             LY(y+224),LW(140),LH(28));
	DEFER(hwndSeqCheck,x2,LY(y+42),  LW(150),LH(28));
	DEFER(hwndLblCoord,x2,LY(y+82),  LW(180),LH(24));
	DEFER(hwndSeqEdit,  x2+insetX,LY(y+108)+insetY,
	      colW-LW(10)-insetX*2,LH(30)-insetY*2);
	DEFER(hwndRecBtn,      x3,           LY(y+42),  LW(140),LH(44));
	DEFER(hwndPlayBtn,     x3+LX(150),LY(y+42),  LW(140),LH(44));
	DEFER(hwndLblSpeed,    x3,           LY(y+100),LW(80),  LH(24));
	DEFER(hwndSpeedSlider,x3+insetX,LY(y+126)+insetY,
	      LW(80)-insetX*2,LH(28)-insetY*2);
	y+=280;
	DEFER(hwndTitle4,       x1,LY(y),     colW,    LH(26));
	DEFER(hwndMacroBtn,     x1,LY(y+42),  LW(180),LH(46));
	DEFER(hwndLblMacroHint,x1,LY(y+98),  colW,    LH(26));
	y+=140;
	DEFER(hwndStartBtn,x1,           LY(y),LW(160),LH(50));
	DEFER(hwndStopBtn,  x1+LX(180),LY(y),LW(160),LH(50));
	DEFER(hwndExitBtn,  x1+LX(360),LY(y),LW(160),LH(50));
	y+=70;
	DEFER(hwndLblHotkey,x1,LY(y),statusW,LH(26));
#undef DEFER
	if(hdwp)EndDeferWindowPos(hdwp);
	if(hwndButtonCombo){
		int editH=(int)(30*sy+0.5);
		if(editH<22)editH=22;
		if(editH>70)editH=70;
		SendMessage(hwndButtonCombo,CB_SETITEMHEIGHT,(WPARAM)-1,(LPARAM)editH);
		int itemH=(int)(28*sFont+0.5);
		if(itemH<20)itemH=20;
		if(itemH>48)itemH=48;
		SendMessage(hwndButtonCombo,CB_SETITEMHEIGHT,(WPARAM)0,(LPARAM)itemH);
	}
	SendMessage(hwndMain,WM_SETREDRAW,TRUE,0);
	RedrawWindow(hwndMain,nullptr,nullptr,
	             RDW_INVALIDATE|RDW_ALLCHILDREN|RDW_ERASE|RDW_UPDATENOW);
}
void ApplyMacroLayout(int cw,int ch){
	if(!hwndMacro)return;
	if(cw<=0)cw=MACRO_BASE_W;
	if(ch<=0)ch=MACRO_BASE_H;
	double sx=(double)cw/MACRO_BASE_W;
	double sy=(double)ch/MACRO_BASE_H;
	if(sx<0.75)sx=0.75;
	if(sx>2.5)sx=2.5;
	if(sy<0.75)sy=0.75;
	if(sy>2.5)sy=2.5;
	double sFont=sqrt(sx*sy);
	if(sFont<0.75)sFont=0.75;
	if(sFont>2.0)  sFont=2.0;
	int newKey=0;
	for(int i=0;i<2;i++){
		int sz=(int)(g_macroFontSlots[i].baseSize*sFont+0.5);
		if(sz<9)sz=9;
		if(sz>60)sz=60;
		newKey=newKey*131+sz;
	}
	bool macroFontChanged=(newKey!=g_lastMacroFontSize);
	if(macroFontChanged)g_lastMacroFontSize=newKey;
	if(macroFontChanged){
		g_macroScale=sFont;
		RecreateMacroFonts(sFont);
		ApplyMacroFonts();
	}
	const int pad=15,btnH=42,btnW=120,btnGap=8,bottomMargin=15;
	int listY=pad;
	int listH=ch-pad-btnH-bottomMargin*2;
	if(listH<60)listH=60;
	int btnY=ch-btnH-bottomMargin;
	if(btnY<listY+listH+5)btnY=listY+listH+5;
	SetWindowPos(hwndMacroList,nullptr,pad,listY,cw-pad*2,listH,
	             SWP_NOZORDER|SWP_NOACTIVATE);
	int x=pad;
	SetWindowPos(hwndMacroRecBtn,nullptr,x,btnY,btnW,btnH,SWP_NOZORDER|SWP_NOACTIVATE);
	x+=btnW+btnGap;
	SetWindowPos(hwndMacroStopRecBtn,nullptr,x,btnY,btnW,btnH,SWP_NOZORDER|SWP_NOACTIVATE);
	x+=btnW+btnGap;
	SetWindowPos(hwndMacroPlayBtn,nullptr,x,btnY,btnW,btnH,SWP_NOZORDER|SWP_NOACTIVATE);
	x+=btnW+btnGap;
	SetWindowPos(hwndMacroStopPlayBtn,nullptr,x,btnY,btnW,btnH,SWP_NOZORDER|SWP_NOACTIVATE);
	x+=btnW+btnGap+16;
	SetWindowPos(hwndMacroLoopCheck,nullptr,x,btnY+10,90,24,SWP_NOZORDER|SWP_NOACTIVATE);
	x+=90+10;
	SetWindowPos(hwndMacroSpeedLabel,nullptr,x,btnY+12,75,22,SWP_NOZORDER|SWP_NOACTIVATE);
	x+=80;
	SetWindowPos(hwndMacroSpeedEdit,nullptr,x,btnY+8,60,28,SWP_NOZORDER|SWP_NOACTIVATE);
	x+=75;
	SetWindowPos(hwndMacroMoveCheck,nullptr,x,btnY+10,160,24,SWP_NOZORDER|SWP_NOACTIVATE);
	RedrawWindow(hwndMacro,nullptr,nullptr,
	             RDW_INVALIDATE|RDW_ALLCHILDREN|RDW_ERASE|RDW_UPDATENOW);
}
int GetJitterOffset(int range){
	if(range<=0)return 0;
	uniform_int_distribution<int>dist(-range,range);
	return dist(rng);
}
void UpdateDelayDisplay(){
	char buf[32];
	sprintf(buf,"当前: %d ms",clickDelay.load());
	SetWindowTextA(hwndDelayLabel,buf);
}
void UpdateStatusInfo(){
	if(hwndStatusBar)InvalidateRect(hwndStatusBar,nullptr,TRUE);
}
void UpdateCount(){
	UpdateStatusInfo();
}
void UpdateUI(){
	bool running=isClicking.load();
	if(hwndStatusBar)InvalidateRect(hwndStatusBar,nullptr,TRUE);
	EnableWindow(hwndStartBtn,!running);
	EnableWindow(hwndStopBtn,running);
	UpdateDelayDisplay();
	if(hwndSeqEdit)SendMessage(hwndSeqEdit,EM_SETREADONLY,running?TRUE:FALSE,0);
	if(hwndSeqCheck)InvalidateRect(hwndSeqCheck,nullptr,TRUE);
	if(hwndSeqEdit)  InvalidateRect(hwndSeqEdit,nullptr,TRUE);
	if(hwndStartBtn)InvalidateRect(hwndStartBtn,nullptr,TRUE);
	if(hwndStopBtn)  InvalidateRect(hwndStopBtn,nullptr,TRUE);
}
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;
		if(us-elapsed>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){
	clickPoints.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=(int)token.find(',');
		if(comma!=string::npos)
			clickPoints.push_back({atoi(token.substr(0,comma).c_str()),atoi(token.substr(comma+1).c_str())});
	}
	if(!s.empty()){
		int comma=(int)s.find(',');
		if(comma!=string::npos)
			clickPoints.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)return;
	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 / --disable-seq\n"
	    "  --jitter <range>, -j     抖动范围\n"
	    "  --relative / --absolute\n"
	    "  --show / --hide\n"
	    "  --exit, -e               退出\n"
	    "  --help, -h               帮助\n";
	DWORD written;
	WriteConsoleA(hConsole,help,(DWORD)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((unsigned char)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"){
			isClicking=true;
			UpdateUI();
		}else if(arg=="--stop"||arg=="-t"){
			isClicking=false;
			UpdateUI();
			UpdateCount();
		}else if(arg=="--toggle"||arg=="-tg"){
			isClicking=!isClicking.load();
			UpdateUI();
			UpdateCount();
		}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;
			clickDelay=val;
			isExtremeMode=(val==0);
			char tmp[16];
			sprintf(tmp,"%d",val);
			SetWindowTextA(hwndDelayEdit,tmp);
			UpdateDelayDisplay();
			UpdateCount();
		}else if((arg=="--button"||arg=="-b")&&i+1<tokens.size()){
			int val=atoi(tokens[++i].c_str());
			if(val>=0&&val<=2){
				clickButton=val;
				SendMessage(hwndButtonCombo,CB_SETCURSEL,val,0);
				InvalidateRect(hwndButtonCombo,nullptr,TRUE);
			}
		}else if((arg=="--sequence"||arg=="-seq")&&i+1<tokens.size()){
			string seq=tokens[++i];
			SetWindowTextA(hwndSeqEdit,seq.c_str());
			ParseCoordinates(seq);
		}else if(arg=="--enable-seq")  {
			sequenceEnabled=true;
			SendMessage(hwndSeqCheck,BM_SETCHECK,BST_CHECKED,0);
		}else if(arg=="--disable-seq"){
			sequenceEnabled=false;
			SendMessage(hwndSeqCheck,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;
			jitterRange=range;
			jitterEnabled=(range>0);
			SendMessage(hwndJitterCheck,BM_SETCHECK,jitterEnabled.load()?BST_CHECKED:BST_UNCHECKED,0);
			char tmp[16];
			sprintf(tmp,"%d",range);
			SetWindowTextA(hwndJitterEdit,tmp);
		}else if(arg=="--relative"){
			g_bRelativeMode=true;
			SendMessage(hwndRelativeCheck,BM_SETCHECK,BST_CHECKED,0);
		}else if(arg=="--absolute"){
			g_bRelativeMode=false;
			SendMessage(hwndRelativeCheck,BM_SETCHECK,BST_UNCHECKED,0);
		}else if(arg=="--show"){
			ShowWindow(hwndMain,SW_SHOW);
			SetForegroundWindow(hwndMain);
		}else if(arg=="--hide"){
			ShowWindow(hwndMain,SW_HIDE);
		}else if(arg=="--exit"||arg=="-e"){
			PostMessage(hwndMain,WM_DESTROY,0,0);
		}else if(arg=="--help"||arg=="-h"){
			PrintCommandHelp();
		}
	}
}
void PostMacroEventToUI(const char*text){
	if(hwndMacroList)PostMessage(hwndMacroList,WM_MACRO_ADD_EVENT,0,(LPARAM)text);
}
LRESULT CALLBACK MacroMouseHookProc(int nCode,WPARAM wParam,LPARAM lParam){
	if(nCode>=0&&g_bMacroRecording){
		MSLLHOOKSTRUCT*p=(MSLLHOOKSTRUCT*)lParam;
		int type=-1,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&&g_bMacroRecordMove){
			static int lastTick=0;
			int now=GetTickCount();
			if(now-lastTick<10)return CallNextHookEx(g_macroMouseHook,nCode,wParam,lParam);
			lastTick=now;
			type=0;
		}
		if(type!=-1){
			lock_guard<mutex>lock(g_macroMutex);
			macroEvents.push_back({type,p->pt.x,p->pt.y,data,GetTickCount(),false});
			const char*names[]={"移动","左键按下","左键释放","右键按下","右键释放","中键按下","中键释放","","","滚轮"};
			char buf[128];
			sprintf(buf,"%s (%d,%d)",(type>=0&&type<=9)?names[type]:"未知",p->pt.x,p->pt.y);
			PostMacroEventToUI(buf);
		}
	}
	return CallNextHookEx(g_macroMouseHook,nCode,wParam,lParam);
}
LRESULT CALLBACK MacroKeyboardHookProc(int nCode,WPARAM wParam,LPARAM lParam){
	if(nCode>=0&&g_bMacroRecording){
		KBDLLHOOKSTRUCT*p=(KBDLLHOOKSTRUCT*)lParam;
		int type=(wParam==WM_KEYDOWN||wParam==WM_SYSKEYDOWN)?7:8;
		lock_guard<mutex>lock(g_macroMutex);
		macroEvents.push_back({type,0,0,(int)p->vkCode,GetTickCount(),false});
		char buf[64];
		sprintf(buf,"按键 VK=%d",p->vkCode);
		PostMacroEventToUI(buf);
	}
	return CallNextHookEx(g_macroKeyboardHook,nCode,wParam,lParam);
}
DWORD WINAPI MacroPlayThread(LPVOID){
	int speed=g_macroPlaySpeed;
	if(speed<1)speed=1;
	bool loop=g_bMacroLoop;
	g_bMacroStopPlay=false;
	do{
		vector<RecordedEvent>eventsCopy;
		{
			lock_guard<mutex>lock(g_macroMutex);
			eventsCopy=macroEvents;
		}
		for(auto&evt:eventsCopy){
			if(g_bMacroStopPlay.load()||!g_bMacroPlaying)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_bMacroStopPlay.load()||!g_bMacroPlaying)break;
				Sleep(5);
			}
		}
	}while(loop&&g_bMacroPlaying&&!g_bMacroStopPlay.load());
	g_bMacroPlaying=false;
	if(hwndMacroPlayBtn){
		SetWindowTextA(hwndMacroPlayBtn,"播放");
		InvalidateRect(hwndMacroPlayBtn,nullptr,TRUE);
	}
	PostMessageA(hwndMacro,WM_MACRO_UPDATE,0,0);
	return 0;
}
LRESULT CALLBACK MacroWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){
	switch(msg){
		case WM_CREATE:{
			hwndMacro=hwnd;
			HINSTANCE hInst=((LPCREATESTRUCT)lParam)->hInstance;
			hwndMacroList=CreateWindowA("LISTBOX","",
			                              WS_CHILD|WS_VISIBLE|WS_BORDER|WS_VSCROLL|LBS_NOTIFY,
			                              15,15,870,380,hwnd,nullptr,hInst,nullptr);
			int btnY=410,btnH=42,btnW=120,btnGap=8,x=15;
			hwndMacroRecBtn=CreateWindowA("BUTTON","开始录制",WS_CHILD|WS_VISIBLE|BS_OWNERDRAW,
			                                x,btnY,btnW,btnH,hwnd,(HMENU)4001,hInst,nullptr);
			x+=btnW+btnGap;
			hwndMacroStopRecBtn=CreateWindowA("BUTTON","停止录制",WS_CHILD|WS_VISIBLE|BS_OWNERDRAW,
			                                    x,btnY,btnW,btnH,hwnd,(HMENU)4002,hInst,nullptr);
			x+=btnW+btnGap;
			hwndMacroPlayBtn=CreateWindowA("BUTTON","播放",WS_CHILD|WS_VISIBLE|BS_OWNERDRAW,
			                                 x,btnY,btnW,btnH,hwnd,(HMENU)4003,hInst,nullptr);
			x+=btnW+btnGap;
			hwndMacroStopPlayBtn=CreateWindowA("BUTTON","停止播放",WS_CHILD|WS_VISIBLE|BS_OWNERDRAW,
			                                     x,btnY,btnW,btnH,hwnd,(HMENU)4004,hInst,nullptr);
			x+=btnW+btnGap+16;
			hwndMacroLoopCheck=CreateWindowA("BUTTON","循环",WS_CHILD|WS_VISIBLE|BS_CHECKBOX,
			                                   x,btnY+10,90,24,hwnd,(HMENU)4005,hInst,nullptr);
			AttachToggle(hwndMacroLoopCheck,false);
			x+=90+10;
			hwndMacroSpeedLabel=CreateWindowA("STATIC","速度(ms):",WS_CHILD|WS_VISIBLE,
			                                    x,btnY+12,75,22,hwnd,nullptr,hInst,nullptr);
			x+=80;
			hwndMacroSpeedEdit=CreateWindowA("EDIT","50",WS_CHILD|WS_VISIBLE|ES_NUMBER,
			                                   x,btnY+8,60,28,hwnd,(HMENU)4006,hInst,nullptr);
			SendMessage(hwndMacroSpeedEdit,EM_SETMARGINS,EC_LEFTMARGIN|EC_RIGHTMARGIN,MAKELPARAM(6,6));
			SetWindowSubclass(hwndMacroSpeedEdit,ModernInputProc,0,0);
			x+=75;
			hwndMacroMoveCheck=CreateWindowA("BUTTON","记录鼠标移动",WS_CHILD|WS_VISIBLE|BS_CHECKBOX,
			                                   x,btnY+10,160,24,hwnd,(HMENU)4008,hInst,nullptr);
			AttachToggle(hwndMacroMoveCheck,true);
			g_bMacroRecordMove=true;
			RECT rc;
			GetClientRect(hwnd,&rc);
			ApplyMacroLayout(rc.right,rc.bottom);
			break;
		}
		case WM_SIZE:{
			int cw=LOWORD(lParam),ch=HIWORD(lParam);
			if(cw>0&&ch>0&&hwndMacro)ApplyMacroLayout(cw,ch);
			break;
		}
		case WM_GETMINMAXINFO:{
			MINMAXINFO*mmi=(MINMAXINFO*)lParam;
			RECT rc={0,0,MACRO_BASE_W,(int)(MACRO_BASE_H*0.85)};
			AdjustWindowRect(&rc,WS_OVERLAPPEDWINDOW,FALSE);
			mmi->ptMinTrackSize.x=rc.right-rc.left;
			mmi->ptMinTrackSize.y=rc.bottom-rc.top;
			break;
		}
		case WM_ERASEBKGND:{
			HDC hdc=(HDC)wParam;
			RECT rc;
			GetClientRect(hwnd,&rc);
			FillRect(hdc,&rc,(HBRUSH)GetStockObject(WHITE_BRUSH));
			return 1;
		}
		case WM_DRAWITEM:{
			DrawRoundButton((LPDRAWITEMSTRUCT)lParam);
			return TRUE;
		}
		case WM_CTLCOLORSTATIC:{
			HDC hdc=(HDC)wParam;
			SetBkMode(hdc,TRANSPARENT);
			SetTextColor(hdc,RGB(26,26,26));
			return(LRESULT)GetStockObject(WHITE_BRUSH);
		}
		case WM_CTLCOLOREDIT:{
			HDC hdc=(HDC)wParam;
			SetTextColor(hdc,RGB(26,26,26));
			SetBkColor(hdc,RGB(255,255,255));
			return(LRESULT)GetStockObject(WHITE_BRUSH);
		}
		case WM_MACRO_ADD_EVENT:{
			const char*text=(const char*)lParam;
			if(text&&hwndMacroList){
				SendMessageA(hwndMacroList,LB_ADDSTRING,0,(LPARAM)text);
				SendMessageA(hwndMacroList,LB_SETCURSEL,
				             SendMessage(hwndMacroList,LB_GETCOUNT,0,0)-1,0);
				delete[]text;
			}
			break;
		}
		case WM_COMMAND:{
			int id=LOWORD(wParam);
			if(id==4001){
				if(g_bMacroPlaying){
					MessageBoxA(hwnd,"请先停止播放","提示",MB_OK);
					break;
				}
				{
					lock_guard<mutex>lock(g_macroMutex);
					macroEvents.clear();
				}
				if(hwndMacroList)SendMessage(hwndMacroList,LB_RESETCONTENT,0,0);
				g_bMacroRecording=true;
				SetWindowTextA(hwndMacroRecBtn,"录制中...");
				g_macroMouseHook=SetWindowsHookExA(WH_MOUSE_LL,MacroMouseHookProc,GetModuleHandleA(nullptr),0);
				g_macroKeyboardHook=SetWindowsHookExA(WH_KEYBOARD_LL,MacroKeyboardHookProc,GetModuleHandleA(nullptr),0);
				if(!g_macroMouseHook||!g_macroKeyboardHook){
					MessageBoxA(hwnd,"钩子安装失败","错误",MB_OK);
					g_bMacroRecording=false;
					SetWindowTextA(hwndMacroRecBtn,"开始录制");
					if(g_macroMouseHook){
						UnhookWindowsHookEx(g_macroMouseHook);
						g_macroMouseHook=nullptr;
					}
					if(g_macroKeyboardHook){
						UnhookWindowsHookEx(g_macroKeyboardHook);
						g_macroKeyboardHook=nullptr;
					}
				}
				break;
			}
			if(id==4002){
				g_bMacroRecording=false;
				SetWindowTextA(hwndMacroRecBtn,"开始录制");
				if(g_macroMouseHook){
					UnhookWindowsHookEx(g_macroMouseHook);
					g_macroMouseHook=nullptr;
				}
				if(g_macroKeyboardHook){
					UnhookWindowsHookEx(g_macroKeyboardHook);
					g_macroKeyboardHook=nullptr;
				}
				{
					lock_guard<mutex>lock(g_macroMutex);
					MessageBoxA(hwnd,("录制完成,共 "+to_string(macroEvents.size())+" 个事件").c_str(),"提示",MB_OK);
				}
				break;
			}
			if(id==4003){
				{
					lock_guard<mutex>lock(g_macroMutex);
					if(macroEvents.empty()){
						MessageBoxA(hwnd,"宏为空","提示",MB_OK);
						break;
					}
				}
				if(g_bMacroPlaying)break;
				g_bMacroStopPlay=false;
				g_bMacroPlaying=true;
				SetWindowTextA(hwndMacroPlayBtn,"播放中...");
				InvalidateRect(hwndMacroPlayBtn,nullptr,TRUE);
				char buf[16];
				GetWindowTextA(hwndMacroSpeedEdit,buf,sizeof(buf));
				g_macroPlaySpeed=atoi(buf);
				if(g_macroPlaySpeed<1)g_macroPlaySpeed=1;
				g_bMacroLoop=(SendMessage(hwndMacroLoopCheck,BM_GETCHECK,0,0)==BST_CHECKED);
				hMacroPlayThread=CreateThread(nullptr,0,MacroPlayThread,nullptr,0,nullptr);
				if(!hMacroPlayThread){
					g_bMacroPlaying=false;
					SetWindowTextA(hwndMacroPlayBtn,"播放");
					MessageBoxA(hwnd,"线程创建失败","错误",MB_OK);
				}
				break;
			}
			if(id==4004){
				g_bMacroStopPlay=true;
				g_bMacroPlaying=false;
				SetWindowTextA(hwndMacroPlayBtn,"播放");
				InvalidateRect(hwndMacroPlayBtn,nullptr,TRUE);
				if(hMacroPlayThread){
					WaitForSingleObject(hMacroPlayThread,1000);
					CloseHandle(hMacroPlayThread);
					hMacroPlayThread=nullptr;
				}
				break;
			}
			if(id==4008){
				g_bMacroRecordMove=(SendMessage(hwndMacroMoveCheck,BM_GETCHECK,0,0)==BST_CHECKED);
				break;
			}
			break;
		}
		case WM_MACRO_UPDATE:
			SetWindowTextA(hwndMacroPlayBtn,"播放");
			InvalidateRect(hwndMacroPlayBtn,nullptr,TRUE);
			break;
		case WM_CLOSE:{
			g_bMacroRecording=false;
			g_bMacroPlaying=false;
			g_bMacroStopPlay=true;
			if(g_macroMouseHook){
				UnhookWindowsHookEx(g_macroMouseHook);
				g_macroMouseHook=nullptr;
			}
			if(g_macroKeyboardHook){
				UnhookWindowsHookEx(g_macroKeyboardHook);
				g_macroKeyboardHook=nullptr;
			}
			if(hMacroPlayThread){
				WaitForSingleObject(hMacroPlayThread,500);
				CloseHandle(hMacroPlayThread);
				hMacroPlayThread=nullptr;
			}
			DestroyWindow(hwnd);
			break;
		}
		case WM_DESTROY:
			hwndMacro=nullptr;
			hwndMacroList=nullptr;
			hwndMacroRecBtn=nullptr;
			hwndMacroStopRecBtn=nullptr;
			hwndMacroPlayBtn=nullptr;
			hwndMacroStopPlayBtn=nullptr;
			hwndMacroLoopCheck=nullptr;
			hwndMacroSpeedLabel=nullptr;
			hwndMacroSpeedEdit=nullptr;
			hwndMacroMoveCheck=nullptr;
			for(int i=0;i<2;i++)if(g_macroFontSlots[i].hFont){
					DeleteObject(g_macroFontSlots[i].hFont);
					g_macroFontSlots[i].hFont=nullptr;
				}
			g_macroScale=-1.0;
			g_lastMacroFontSize=-1;
			break;
		default:
			return DefWindowProc(hwnd,msg,wParam,lParam);
	}
	return 0;
}
void CreateMacroWindow(){
	if(hwndMacro){
		ShowWindow(hwndMacro,SW_SHOW);
		SetForegroundWindow(hwndMacro);
		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);
	RECT rc={0,0,MACRO_BASE_W,MACRO_BASE_H};
	AdjustWindowRect(&rc,WS_OVERLAPPEDWINDOW,FALSE);
	hwndMacro=CreateWindowA("MacroWindowClass","鼠标宏编辑器",
	                          WS_OVERLAPPEDWINDOW|WS_VISIBLE,CW_USEDEFAULT,CW_USEDEFAULT,
	                          rc.right-rc.left,rc.bottom-rc.top,
	                          hwndMain,nullptr,hInst,nullptr);
	SendMessage(hwndMacro,WM_SETICON,ICON_BIG,(LPARAM)g_hAppIcon);
}
DWORD WINAPI ClickerThread(LPVOID){
	SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_HIGHEST);
	SetThreadAffinityMask(GetCurrentThread(),1);
	int localDelay=clickDelay.load(),localButton=clickButton.load(),localCount=0;
	while(!shouldExit){
		if(isClicking.load()){
			if(sequenceEnabled.load()&&clickDelay.load()>0){
				vector<pair<int,int>>pts=clickPoints;
				if(pts.empty()){
					isClicking=false;
					UpdateUI();
					continue;
				}
				for(auto&p:pts){
					if(!isClicking.load())break;
					SimulateClick(p.first,p.second,clickButton.load());
					clickCount.fetch_add(1);
					PostMessageA(hwndMain,WM_USER+1,0,0);
					int fd=localDelay;
					if(jitterEnabled.load()&&localDelay>0){
						int r=jitterRange.load();
						if(r>0){
							fd+=GetJitterOffset(r);
							if(fd<1)fd=1;
						}
					}
					if(fd==1)usSleep(1000);
					else Sleep(fd);
				}
				continue;
			}
			if(isExtremeMode.load()){
				while(!shouldExit&&isClicking.load()&&isExtremeMode.load()){
					int btn=clickButton.load();
					if(btn!=localButton)localButton=btn;
					INPUT in[2]={};
					in[0].type=INPUT_MOUSE;
					in[1].type=INPUT_MOUSE;
					switch(localButton){
						case 0:
							in[0].mi.dwFlags=MOUSEEVENTF_LEFTDOWN;
							in[1].mi.dwFlags=MOUSEEVENTF_LEFTUP;
							break;
						case 1:
							in[0].mi.dwFlags=MOUSEEVENTF_MIDDLEDOWN;
							in[1].mi.dwFlags=MOUSEEVENTF_MIDDLEUP;
							break;
						case 2:
							in[0].mi.dwFlags=MOUSEEVENTF_RIGHTDOWN;
							in[1].mi.dwFlags=MOUSEEVENTF_RIGHTUP;
							break;
					}
					SendInput(2,in,sizeof(INPUT));
					++localCount;
				}
				if(localCount>0){
					clickCount.fetch_add(localCount);
					localCount=0;
					PostMessageA(hwndMain,WM_USER+1,0,0);
				}
				localDelay=clickDelay.load();
				continue;
			}
			int btn=clickButton.load();
			if(btn!=localButton)localButton=btn;
			INPUT in[2]={};
			in[0].type=INPUT_MOUSE;
			in[1].type=INPUT_MOUSE;
			switch(localButton){
				case 0:
					in[0].mi.dwFlags=MOUSEEVENTF_LEFTDOWN;
					in[1].mi.dwFlags=MOUSEEVENTF_LEFTUP;
					break;
				case 1:
					in[0].mi.dwFlags=MOUSEEVENTF_MIDDLEDOWN;
					in[1].mi.dwFlags=MOUSEEVENTF_MIDDLEUP;
					break;
				case 2:
					in[0].mi.dwFlags=MOUSEEVENTF_RIGHTDOWN;
					in[1].mi.dwFlags=MOUSEEVENTF_RIGHTUP;
					break;
			}
			SendInput(2,in,sizeof(INPUT));
			clickCount.fetch_add(1);
			static int counter=0;
			if(++counter>=10){
				counter=0;
				PostMessageA(hwndMain,WM_USER+1,0,0);
			}
			int fd=localDelay;
			if(jitterEnabled.load()&&localDelay>0){
				int r=jitterRange.load();
				if(r>0){
					fd+=GetJitterOffset(r);
					if(fd<1)fd=1;
				}
			}
			if(fd==1)usSleep(1000);
			else Sleep(fd);
			localDelay=clickDelay.load();
		}else{
			if(localCount>0){
				clickCount.fetch_add(localCount);
				localCount=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(!isClicking.load()){
				POINT pt;
				GetCursorPos(&pt);
				PostMessageA(hwndMain,WM_ADD_COORD,(WPARAM)pt.x,(LPARAM)pt.y);
				MessageBeep(MB_OK);
			}
		}
		if(isRecording.load()){
			if(p->vkCode>=VK_F1&&p->vkCode<=VK_F12)
				return CallNextHookEx(keyboardHook,nCode,wParam,lParam);
			int type=(wParam==WM_KEYDOWN||wParam==WM_SYSKEYDOWN)?7:8;
			recordedEvents.push_back({type,0,0,(int)p->vkCode,GetTickCount(),false});
		}
		static bool f6Down=false,f7Down=false,escDown=false;
		if(wParam==WM_KEYDOWN||wParam==WM_SYSKEYDOWN){
			if(p->vkCode==VK_F6&&!f6Down){
				f6Down=true;
				isClicking=!isClicking.load();
				UpdateUI();
				UpdateCount();
				return 1;
			}
			if(p->vkCode==VK_F7&&!f7Down){
				f7Down=true;
				ToggleRecording();
				return 1;
			}
			if(p->vkCode==VK_ESCAPE&&!escDown){
				escDown=true;
				if(IsWindowVisible(hwndMain))DestroyWindow(hwndMain);
			}
		}else if(wParam==WM_KEYUP||wParam==WM_SYSKEYUP){
			if(p->vkCode==VK_F6)f6Down=false;
			if(p->vkCode==VK_F7)f7Down=false;
			if(p->vkCode==VK_ESCAPE)escDown=false;
		}
	}
	return CallNextHookEx(keyboardHook,nCode,wParam,lParam);
}
LRESULT CALLBACK MouseHookProc(int nCode,WPARAM wParam,LPARAM lParam){
	if(nCode>=0&&isRecording.load()){
		MSLLHOOKSTRUCT*p=(MSLLHOOKSTRUCT*)lParam;
		int cur=GetTickCount(),sx=p->pt.x,sy=p->pt.y,stx,sty;
		bool isRel=g_bRelativeMode;
		if(g_bRelativeMode){
			POINT tl={0,0};
			ClientToScreen(hwndMain,&tl);
			stx=sx-tl.x;
			sty=sy-tl.y;
		}else{
			stx=sx;
			sty=sy;
		}
		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&&cur-lastMoveTime<5)return CallNextHookEx(mouseHook,nCode,wParam,lParam);
			if(type==0)lastMoveTime=cur;
			recordedEvents.push_back({type,stx,sty,data,cur,isRel});
		}
	}
	return CallNextHookEx(mouseHook,nCode,wParam,lParam);
}
DWORD WINAPI PlaybackThread(LPVOID){
	if(recordedEvents.empty()){
		MessageBoxA(hwndMain,"没有录制数据","提示",MB_OK);
		return 0;
	}
	isPlaying=true;
	double speedFactor=50.0/(double)playbackSpeed.load();
	if(speedFactor<0.01)speedFactor=0.01;
	if(speedFactor>100.0)speedFactor=100.0;
	DWORD lastTime=0;
	bool firstEvent=true;
	for(auto&evt:recordedEvents){
		if(!isPlaying)break;
		if(!firstEvent&&lastTime!=0&&evt.time>=lastTime){
			DWORD gap=evt.time-lastTime;
			DWORD delayMs=(DWORD)(gap*speedFactor);
			if(delayMs>0){
				DWORD elapsed=0;
				while(elapsed<delayMs&&isPlaying.load()){
					DWORD chunk=30;
					if(delayMs-elapsed<30)chunk=delayMs-elapsed;
					Sleep(chunk);
					elapsed+=chunk;
				}
			}
		}
		firstEvent=false;
		lastTime=evt.time;
		int sx,sy;
		if(evt.isRelative){
			POINT tl={0,0};
			ClientToScreen(hwndMain,&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;
			}
		}
	}
	isPlaying=false;
	PostMessageA(hwndMain,WM_USER+3,0,0);
	return 0;
}
void CreateTrayIcon(){
	ZeroMemory(&g_nid,sizeof(g_nid));
	g_nid.cbSize=sizeof(g_nid);
	g_nid.hWnd=hwndMain;
	g_nid.uID=1;
	g_nid.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP;
	g_nid.uCallbackMessage=WM_TRAYICON;
	g_nid.hIcon=g_hAppIcon?g_hAppIcon:LoadIconA(nullptr,IDI_APPLICATION);
	strcpy(g_nid.szTip,"自动连点器");
	if(!Shell_NotifyIconA(NIM_ADD,&g_nid)){
		Sleep(100);
		Shell_NotifyIconA(NIM_ADD,&g_nid);
	}
	g_bTrayCreated=true;
}
void DeleteTrayIcon(){
	if(g_bTrayCreated){
		Shell_NotifyIconA(NIM_DELETE,&g_nid);
		g_bTrayCreated=false;
	}
}
void ShowMainWindow(){
	ShowWindow(hwndMain,SW_SHOW);
	SetForegroundWindow(hwndMain);
}
void StartRecordingActual(){
	if(isClicking.load()||sequenceEnabled.load()){
		MessageBoxA(hwndMain,"请先停止连点或关闭序列。","提示",MB_OK);
		return;
	}
	recordedEvents.clear();
	lastMoveTime=0;
	isRecording=true;
	SetWindowTextA(hwndRecBtn,"停止录制");
	InvalidateRect(hwndRecBtn,nullptr,TRUE);
	mouseHook=SetWindowsHookExA(WH_MOUSE_LL,MouseHookProc,GetModuleHandleA(nullptr),0);
	if(!mouseHook){
		MessageBoxA(hwndMain,"设置鼠标钩子失败!","错误",MB_OK);
		isRecording=false;
		SetWindowTextA(hwndRecBtn,"开始录制");
	}
}
void StopRecording(){
	isRecording=false;
	SetWindowTextA(hwndRecBtn,"开始录制");
	InvalidateRect(hwndRecBtn,nullptr,TRUE);
	if(mouseHook){
		UnhookWindowsHookEx(mouseHook);
		mouseHook=nullptr;
	}
	MessageBoxA(hwndMain,("录制完成,共 "+to_string(recordedEvents.size())+" 个事件。").c_str(),"提示",MB_OK);
}
void ToggleRecording(){
	if(isRecording.load()){
		StopRecording();
		return;
	}
	if(g_bRecordingPending){
		KillTimer(hwndMain,g_countdownTimerId);
		g_bRecordingPending=false;
		SetWindowTextA(hwndRecBtn,"开始录制");
		return;
	}
	if(isClicking.load()||sequenceEnabled.load()){
		MessageBoxA(hwndMain,"请先停止连点或关闭序列。","提示",MB_OK);
		return;
	}
	g_bRecordingPending=true;
	g_currentCountdown=g_countdownSeconds;
	char buf[32];
	sprintf(buf,"倒计时 %ds",g_currentCountdown);
	SetWindowTextA(hwndRecBtn,buf);
	InvalidateRect(hwndRecBtn,nullptr,TRUE);
	SetTimer(hwndMain,g_countdownTimerId,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={sizeof(icex),ICC_STANDARD_CLASSES};
			InitCommonControlsEx(&icex);
			hBrushBg=CreateSolidBrush(RGB(243,243,243));
			hBrushWhite=CreateSolidBrush(RGB(255,255,255));
			int baseX=24,baseY=20,colW=320,gap=30;
			int statusW=colW*3+gap*2,statusH=52;
			hwndStatusBar=CreateWindowA("STATIC","",WS_CHILD|WS_VISIBLE|SS_OWNERDRAW,
			                              baseX,baseY,statusW,statusH,hwnd,(HMENU)ID_STATUS_BAR,hInst,nullptr);
			int y=baseY+statusH+24;
			int x1=baseX,x2=baseX+colW+gap,x3=baseX+(colW+gap)*2;
			hwndTitle1=CreateWindowA("STATIC","基础设置",WS_CHILD|WS_VISIBLE,x1,y,colW,26,hwnd,nullptr,hInst,nullptr);
			hwndTitle2=CreateWindowA("STATIC","序列点击",WS_CHILD|WS_VISIBLE,x2,y,colW,26,hwnd,nullptr,hInst,nullptr);
			hwndTitle3=CreateWindowA("STATIC","录制回放",WS_CHILD|WS_VISIBLE,x3,y,colW,26,hwnd,nullptr,hInst,nullptr);
			hwndLblDelay=CreateWindowA("STATIC","间隔(ms)",WS_CHILD|WS_VISIBLE,x1,y+42,80,24,hwnd,nullptr,hInst,nullptr);
			hwndDelayEdit=CreateWindowA("EDIT","100",WS_CHILD|WS_VISIBLE|ES_NUMBER,
			                              x1+8,y+70,64,24,hwnd,(HMENU)1001,hInst,nullptr);
			SendMessage(hwndDelayEdit,EM_SETMARGINS,EC_LEFTMARGIN|EC_RIGHTMARGIN,MAKELPARAM(6,6));
			SetWindowSubclass(hwndDelayEdit,ModernInputProc,0,0);
			hwndDelayLabel=CreateWindowA("STATIC","当前: 100 ms",WS_CHILD|WS_VISIBLE|SS_LEFT,
			                               x1+95,y+74,190,24,hwnd,nullptr,hInst,nullptr);
			hwndLblButton=CreateWindowA("STATIC","按键",WS_CHILD|WS_VISIBLE,x1,y+118,80,24,hwnd,nullptr,hInst,nullptr);
			hwndButtonCombo=CreateWindowA("COMBOBOX","",
			                                WS_CHILD|WS_VISIBLE|CBS_DROPDOWNLIST|CBS_OWNERDRAWFIXED|CBS_HASSTRINGS,
			                                x1,y+144,140,300,hwnd,(HMENU)1002,hInst,nullptr);
			SendMessageA(hwndButtonCombo,CB_ADDSTRING,0,(LPARAM)"左键");
			SendMessageA(hwndButtonCombo,CB_ADDSTRING,0,(LPARAM)"中键");
			SendMessageA(hwndButtonCombo,CB_ADDSTRING,0,(LPARAM)"右键");
			SendMessage(hwndButtonCombo,CB_SETCURSEL,0,0);
			SetWindowTheme(hwndButtonCombo,L"",L"");
			SetWindowSubclass(hwndButtonCombo,ComboBoxProc,0,0);
			hwndJitterCheck=CreateWindowA("BUTTON","抖动",WS_CHILD|WS_VISIBLE|BS_CHECKBOX,
			                                x1,y+188,90,28,hwnd,(HMENU)1003,hInst,nullptr);
			AttachToggle(hwndJitterCheck,false);
			hwndLblJitter=CreateWindowA("STATIC","范围",WS_CHILD|WS_VISIBLE,
			                              x1+98,y+194,36,18,hwnd,nullptr,hInst,nullptr);
			hwndJitterEdit=CreateWindowA("EDIT","10",WS_CHILD|WS_VISIBLE|ES_NUMBER,
			                               x1+146,y+192,34,20,hwnd,(HMENU)1004,hInst,nullptr);
			SendMessage(hwndJitterEdit,EM_SETMARGINS,EC_LEFTMARGIN|EC_RIGHTMARGIN,MAKELPARAM(4,4));
			SetWindowSubclass(hwndJitterEdit,ModernInputProc,0,0);
			hwndRelativeCheck=CreateWindowA("BUTTON","相对窗口",WS_CHILD|WS_VISIBLE|BS_CHECKBOX,
			                                  x1,y+224,140,28,hwnd,(HMENU)1010,hInst,nullptr);
			AttachToggle(hwndRelativeCheck,true);
			hwndSeqCheck=CreateWindowA("BUTTON","启用序列",WS_CHILD|WS_VISIBLE|BS_CHECKBOX,
			                             x2,y+42,150,28,hwnd,(HMENU)1005,hInst,nullptr);
			AttachToggle(hwndSeqCheck,false);
			hwndLblCoord=CreateWindowA("STATIC","坐标 (x,y;x,y)",WS_CHILD|WS_VISIBLE,x2,y+82,180,24,hwnd,nullptr,hInst,nullptr);
			hwndSeqEdit=CreateWindowA("EDIT","100,200;300,400",WS_CHILD|WS_VISIBLE,
			                            x2+8,y+110,colW-26,26,hwnd,(HMENU)1006,hInst,nullptr);
			SendMessage(hwndSeqEdit,EM_SETMARGINS,EC_LEFTMARGIN|EC_RIGHTMARGIN,MAKELPARAM(6,6));
			SetWindowSubclass(hwndSeqEdit,ModernInputProc,0,0);
			char initBuf[512];
			GetWindowTextA(hwndSeqEdit,initBuf,sizeof(initBuf));
			ParseCoordinates(initBuf);
			hwndRecBtn=CreateWindowA("BUTTON","开始录制",WS_CHILD|WS_VISIBLE|BS_OWNERDRAW,
			                           x3,y+42,140,44,hwnd,(HMENU)1007,hInst,nullptr);
			hwndPlayBtn=CreateWindowA("BUTTON","回放",WS_CHILD|WS_VISIBLE|BS_OWNERDRAW,
			                            x3+150,y+42,140,44,hwnd,(HMENU)1008,hInst,nullptr);
			hwndLblSpeed=CreateWindowA("STATIC","速度(ms)",WS_CHILD|WS_VISIBLE,x3,y+100,80,24,hwnd,nullptr,hInst,nullptr);
			hwndSpeedSlider=CreateWindowA("EDIT","50",WS_CHILD|WS_VISIBLE|ES_NUMBER,
			                                x3+8,y+128,64,24,hwnd,(HMENU)1009,hInst,nullptr);
			SendMessage(hwndSpeedSlider,EM_SETMARGINS,EC_LEFTMARGIN|EC_RIGHTMARGIN,MAKELPARAM(6,6));
			SetWindowSubclass(hwndSpeedSlider,ModernInputProc,0,0);
			y+=280;
			hwndTitle4=CreateWindowA("STATIC","鼠标宏",WS_CHILD|WS_VISIBLE,x1,y,colW,26,hwnd,nullptr,hInst,nullptr);
			hwndMacroBtn=CreateWindowA("BUTTON","打开宏编辑器",WS_CHILD|WS_VISIBLE|BS_OWNERDRAW,
			                             x1,y+42,180,46,hwnd,(HMENU)2005,hInst,nullptr);
			hwndLblMacroHint=CreateWindowA("STATIC","录制鼠标/键盘动作,支持循环播放",WS_CHILD|WS_VISIBLE|SS_LEFT,
			                                 x1,y+98,colW,26,hwnd,nullptr,hInst,nullptr);
			y+=140;
			hwndStartBtn=CreateWindowA("BUTTON","开始 (F6)",WS_CHILD|WS_VISIBLE|BS_OWNERDRAW,
			                             baseX,y,160,50,hwnd,(HMENU)1,hInst,nullptr);
			hwndStopBtn=CreateWindowA("BUTTON","停止 (F6)",WS_CHILD|WS_VISIBLE|BS_OWNERDRAW,
			                            baseX+180,y,160,50,hwnd,(HMENU)2,hInst,nullptr);
			hwndExitBtn=CreateWindowA("BUTTON","退出",WS_CHILD|WS_VISIBLE|BS_OWNERDRAW,
			                            baseX+360,y,160,50,hwnd,(HMENU)3,hInst,nullptr);
			y+=70;
			hwndLblHotkey=CreateWindowA("STATIC",
			                              "F6 切换  |  F7 录制  |  ESC 退出  |  CapsLock + [+] 记录坐标",
			                              WS_CHILD|WS_VISIBLE|SS_CENTER,baseX,y,statusW,26,hwnd,nullptr,hInst,nullptr);
			g_fontGroups[3].push_back(hwndDelayLabel);
			g_fontGroups[3].push_back(hwndLblDelay);
			g_fontGroups[3].push_back(hwndLblButton);
			g_fontGroups[3].push_back(hwndLblJitter);
			g_fontGroups[3].push_back(hwndLblCoord);
			g_fontGroups[3].push_back(hwndLblSpeed);
			g_fontGroups[3].push_back(hwndLblMacroHint);
			g_fontGroups[3].push_back(hwndLblHotkey);
			g_fontGroups[4].push_back(hwndTitle1);
			g_fontGroups[4].push_back(hwndTitle2);
			g_fontGroups[4].push_back(hwndTitle3);
			g_fontGroups[4].push_back(hwndTitle4);
			g_fontGroups[5].push_back(hwndRecBtn);
			g_fontGroups[5].push_back(hwndPlayBtn);
			g_fontGroups[5].push_back(hwndStartBtn);
			g_fontGroups[5].push_back(hwndStopBtn);
			g_fontGroups[5].push_back(hwndExitBtn);
			g_fontGroups[5].push_back(hwndMacroBtn);
			g_fontGroups[5].push_back(hwndJitterCheck);
			g_fontGroups[5].push_back(hwndSeqCheck);
			g_fontGroups[5].push_back(hwndRelativeCheck);
			g_fontGroups[6].push_back(hwndDelayEdit);
			g_fontGroups[6].push_back(hwndJitterEdit);
			g_fontGroups[6].push_back(hwndSpeedSlider);
			g_fontGroups[6].push_back(hwndSeqEdit);
			g_fontGroups[6].push_back(hwndButtonCombo);
			keyboardHook=SetWindowsHookExA(WH_KEYBOARD_LL,KeyboardHookProc,GetModuleHandleA(nullptr),0);
			if(!keyboardHook)MessageBoxA(hwnd,"键盘钩子安装失败,热键将不可用!","错误",MB_OK);
			g_bInitDone=true;
			clickDelay=100;
			clickButton=0;
			isExtremeMode=false;
			RECT rc;
			GetClientRect(hwnd,&rc);
			ApplyLayout(rc.right,rc.bottom);
			UpdateUI();
			UpdateCount();
			break;
		}
		case WM_SIZE:{
			int cw=LOWORD(lParam),ch=HIWORD(lParam);
			if(cw>0&&ch>0)ApplyLayout(cw,ch);
			break;
		}
		case WM_GETMINMAXINFO:{
			MINMAXINFO*mmi=(MINMAXINFO*)lParam;
			RECT rc={0,0,(int)(BASE_W*MIN_SCALE),(int)(BASE_H*MIN_SCALE)};
			AdjustWindowRect(&rc,WS_OVERLAPPEDWINDOW,FALSE);
			mmi->ptMinTrackSize.x=rc.right-rc.left;
			mmi->ptMinTrackSize.y=rc.bottom-rc.top;
			break;
		}
		case WM_MEASUREITEM:{
			LPMEASUREITEMSTRUCT mis=(LPMEASUREITEMSTRUCT)lParam;
			if(mis->CtlType==ODT_COMBOBOX){
				double s=g_scale>0?g_scale:1.0;
				int h=(int)(28*s);
				if(h<20)h=20;
				if(h>48)h=48;
				mis->itemHeight=h;
				return TRUE;
			}
			return DefWindowProc(hwnd,msg,wParam,lParam);
		}
		case WM_PAINT:{
			PAINTSTRUCT ps;
			HDC hdc=BeginPaint(hwnd,&ps);
			PaintInputBorders(hdc);
			EndPaint(hwnd,&ps);
			return 0;
		}
		case WM_ERASEBKGND:{
			HDC hdc=(HDC)wParam;
			RECT rc;
			GetClientRect(hwnd,&rc);
			FillRect(hdc,&rc,hBrushBg);
			return 1;
		}
		case WM_DRAWITEM:{
			LPDRAWITEMSTRUCT dis=(LPDRAWITEMSTRUCT)lParam;
			if(dis->hwndItem==hwndStatusBar){
				DrawStatusBar(dis);
			}else if(dis->CtlType==ODT_COMBOBOX){
				DrawComboListItem(dis);
			}else{
				DrawRoundButton(dis);
			}
			return TRUE;
		}
		case WM_CTLCOLORSTATIC:{
			HDC hdc=(HDC)wParam;
			SetBkMode(hdc,TRANSPARENT);
			SetTextColor(hdc,RGB(26,26,26));
			return(LRESULT)hBrushBg;
		}
		case WM_CTLCOLOREDIT:{
			HDC hdc=(HDC)wParam;
			SetTextColor(hdc,RGB(26,26,26));
			SetBkColor(hdc,RGB(255,255,255));
			return(LRESULT)hBrushWhite;
		}
		case WM_CTLCOLORLISTBOX:{
			HDC hdc=(HDC)wParam;
			SetTextColor(hdc,RGB(26,26,26));
			SetBkColor(hdc,RGB(255,255,255));
			return(LRESULT)hBrushWhite;
		}
		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*c=new char[cmd.size()+1];
				strcpy(c,cmd.c_str());
				PostMessage(hwnd,WM_EXECUTE_CMD,(WPARAM)c,0);
				ShowMainWindow();
				return TRUE;
			}
			break;
		}
		case WM_ADD_COORD:{
			if(isClicking.load())break;
			int x=(int)wParam,y=(int)lParam;
			char buf[512]={0};
			GetWindowTextA(hwndSeqEdit,buf,sizeof(buf)-1);
			string str=buf;
			if(!str.empty())str+=";";
			char c[32];
			sprintf(c,"%d,%d",x,y);
			str+=c;
			SetWindowTextA(hwndSeqEdit,str.c_str());
			clickPoints.push_back({x,y});
			break;
		}
		case WM_USER+3:
			SetWindowTextA(hwndPlayBtn,"回放");
			InvalidateRect(hwndPlayBtn,nullptr,TRUE);
			break;
		case WM_SHOWWINDOW:
			if(wParam==TRUE){
				if(!g_bTrayCreated)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);
				AppendMenuA(hMenu,MF_STRING,TRAY_TOGGLE,isClicking.load()?"暂停连点":"继续连点");
				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(!isExtremeMode.load()){
					int total=clickCount.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)
						currentCPS.store((total-last)/(t-lastTime));
					last=total;
					lastTime=t;
				}
				UpdateCount();
			}else if(wParam==g_countdownTimerId){
				if(g_bRecordingPending){
					g_currentCountdown--;
					if(g_currentCountdown<=0){
						KillTimer(hwnd,g_countdownTimerId);
						g_bRecordingPending=false;
						SetWindowTextA(hwndRecBtn,"开始录制");
						StartRecordingActual();
					}else{
						char buf[32];
						sprintf(buf,"倒计时 %ds",g_currentCountdown);
						SetWindowTextA(hwndRecBtn,buf);
					}
				}else KillTimer(hwnd,g_countdownTimerId);
			}
			break;
		}
		case WM_COMMAND:{
			int id=LOWORD(wParam),code=HIWORD(wParam);
			if(id==TRAY_SHOW){
				ShowMainWindow();
				break;
			}
			if(id==TRAY_HIDE){
				ShowWindow(hwndMain,SW_HIDE);
				break;
			}
			if(id==TRAY_TOGGLE){
				isClicking=!isClicking.load();
				UpdateUI();
				UpdateCount();
				break;
			}
			if(id==TRAY_EXIT){
				DestroyWindow(hwndMain);
				break;
			}
			if(id==2005){
				CreateMacroWindow();
				break;
			}
			if(id==1010&&code==BN_CLICKED){
				g_bRelativeMode=(SendMessage(hwndRelativeCheck,BM_GETCHECK,0,0)==BST_CHECKED);
				break;
			}
			if(id==1003&&code==BN_CLICKED){
				jitterEnabled.store(SendMessage(hwndJitterCheck,BM_GETCHECK,0,0)==BST_CHECKED);
				break;
			}
			if(id==1004&&code==EN_CHANGE&&g_bInitDone){
				char buf[16]={0};
				GetWindowTextA(hwndJitterEdit,buf,sizeof(buf));
				if(buf[0]){
					int v=atoi(buf);
					if(v<0)v=0;
					if(v>100)v=100;
					jitterRange.store(v);
				}
				break;
			}
			if(id==1005&&code==BN_CLICKED){
				if(isClicking.load()){
					SendMessage(hwndSeqCheck,BM_SETCHECK,sequenceEnabled.load()?BST_CHECKED:BST_UNCHECKED,0);
					break;
				}
				sequenceEnabled.store(SendMessage(hwndSeqCheck,BM_GETCHECK,0,0)==BST_CHECKED);
				break;
			}
			if(id==1006&&code==EN_KILLFOCUS){
				if(isClicking.load())break;
				char buf[512]={0};
				GetWindowTextA(hwndSeqEdit,buf,sizeof(buf)-1);
				ParseCoordinates(buf);
				break;
			}
			if(id==1007){
				ToggleRecording();
				break;
			}
			if(id==1008){
				if(isPlaying.load()){
					isPlaying=false;
					SetWindowTextA(hwndPlayBtn,"回放");
					InvalidateRect(hwndPlayBtn,nullptr,TRUE);
					break;
				}
				if(isClicking.load()||sequenceEnabled.load()){
					MessageBoxA(hwnd,"请先停止连点或关闭序列。","提示",MB_OK);
					break;
				}
				if(recordedEvents.empty()){
					MessageBoxA(hwnd,"没有录制数据。","提示",MB_OK);
					break;
				}
				SetWindowTextA(hwndPlayBtn,"停止");
				InvalidateRect(hwndPlayBtn,nullptr,TRUE);
				hPlaybackThread=CreateThread(nullptr,0,PlaybackThread,nullptr,0,nullptr);
				if(!hPlaybackThread){
					MessageBoxA(hwnd,"创建回放线程失败。","错误",MB_OK);
					SetWindowTextA(hwndPlayBtn,"回放");
				}
				break;
			}
			if(id==1009&&code==EN_CHANGE){
				char buf[16]={0};
				GetWindowTextA(hwndSpeedSlider,buf,sizeof(buf));
				if(buf[0]){
					int v=atoi(buf);
					if(v<1)v=1;
					if(v>1000)v=1000;
					playbackSpeed.store(v);
				}
				break;
			}
			if(id==1002){
				if(code==CBN_SELCHANGE){
					int sel=(int)SendMessage(hwndButtonCombo,CB_GETCURSEL,0,0);
					if(sel>=0&&sel<=2){
						clickButton.store(sel);
						InvalidateRect(hwndButtonCombo,nullptr,TRUE);
					}
				}
				break;
			}
			if(id==1001&&code==EN_CHANGE&&g_bInitDone){
				char buf[16]={0};
				GetWindowTextA(hwndDelayEdit,buf,sizeof(buf));
				if(buf[0]=='\0')break;
				int v=atoi(buf);
				if(v<0)v=0;
				if(v>10000)v=10000;
				if(v==0){
					int ret=MessageBoxA(hwnd,"进入极速模式(延迟0),CPU占用略高。\n确定继续?","提示",MB_OKCANCEL);
					if(ret==IDCANCEL){
						v=100;
						char tmp[16];
						sprintf(tmp,"%d",v);
						SetWindowTextA(hwndDelayEdit,tmp);
					}
				}
				clickDelay.store(v);
				isExtremeMode.store(v==0);
				UpdateDelayDisplay();
				UpdateCount();
				break;
			}
			switch(id){
				case 1:{
					char buf[512]={0};
					GetWindowTextA(hwndSeqEdit,buf,sizeof(buf)-1);
					ParseCoordinates(buf);
					if(sequenceEnabled.load()&&clickPoints.empty()){
						MessageBoxA(hwnd,"序列已启用但坐标为空,已自动禁用。","提示",MB_OK);
						sequenceEnabled=false;
						SendMessage(hwndSeqCheck,BM_SETCHECK,BST_UNCHECKED,0);
					}
					isClicking=true;
					UpdateUI();
					break;
				}
				case 2:
					isClicking=false;
					UpdateUI();
					UpdateCount();
					break;
				case 3:
					DestroyWindow(hwnd);
					break;
				case 1001:
					ShowMainWindow();
					break;
			}
			break;
		}
		case WM_USER+1:
			UpdateCount();
			break;
		case WM_CLOSE:
			ShowWindow(hwnd,SW_HIDE);
			return 0;
		case WM_DESTROY:{
			KillTimer(hwnd,TIMER_CPS);
			if(g_bRecordingPending){
				KillTimer(hwnd,g_countdownTimerId);
				g_bRecordingPending=false;
			}
			if(hwndMacro)DestroyWindow(hwndMacro);
			DeleteTrayIcon();
			if(mouseHook)UnhookWindowsHookEx(mouseHook);
			if(keyboardHook)UnhookWindowsHookEx(keyboardHook);
			if(hPlaybackThread){
				WaitForSingleObject(hPlaybackThread,500);
				CloseHandle(hPlaybackThread);
				hPlaybackThread=nullptr;
			}
			if(g_hBlankIcon){
				DestroyIcon(g_hBlankIcon);
				g_hBlankIcon=nullptr;
			}
			g_hAppIcon=nullptr;
			for(int i=0;i<7;i++)if(g_fontSlots[i].hFont){
					DeleteObject(g_fontSlots[i].hFont);
					g_fontSlots[i].hFont=nullptr;
				}
			for(int i=0;i<2;i++)if(g_macroFontSlots[i].hFont){
					DeleteObject(g_macroFontSlots[i].hFont);
					g_macroFontSlots[i].hFont=nullptr;
				}
			if(hBrushWhite){
				DeleteObject(hBrushWhite);
				hBrushWhite=nullptr;
			}
			if(hBrushBg)    {
				DeleteObject(hBrushBg);
				hBrushBg    =nullptr;
			}
			g_bInitDone=false;
			shouldExit=true;
			g_lastMainFontSize=-1;
			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();
	Gdiplus::GdiplusStartupInput gpsi;
	Gdiplus::GdiplusStartup(&g_gdiplusToken,&gpsi,nullptr);
	InitDirect2D();
	bool onlyHelp=false;
	if(lpCmd&&*lpCmd){
		string cmd=lpCmd;
		size_t s=cmd.find_first_not_of(" \t");
		if(s!=string::npos){
			cmd=cmd.substr(s);
			size_t e=cmd.find_last_not_of(" \t");
			if(e!=string::npos)cmd=cmd.substr(0,e+1);
			if(cmd=="--help"||cmd=="-h")onlyHelp=true;
		}
	}
	if(onlyHelp){
		PrintCommandHelp();
		ShutdownDirect2D();
		Gdiplus::GdiplusShutdown(g_gdiplusToken);
		return 0;
	}
	HANDLE hMutex=CreateMutexA(NULL,FALSE,"AutoClickerMutex");
	if(GetLastError()==ERROR_ALREADY_EXISTS){
		HWND hExist=FindWindowA("AutoClickerClass",NULL);
		if(hExist){
			if(lpCmd&&*lpCmd){
				COPYDATASTRUCT cds;
				cds.dwData=1;
				cds.cbData=(DWORD)strlen(lpCmd)+1;
				cds.lpData=lpCmd;
				SendMessage(hExist,WM_COPYDATA,0,(LPARAM)&cds);
			}
			ShowWindow(hExist,SW_SHOW);
			SetForegroundWindow(hExist);
		}
		CloseHandle(hMutex);
		ShutdownDirect2D();
		Gdiplus::GdiplusShutdown(g_gdiplusToken);
		return 0;
	}
	timeBeginPeriod(1);
	g_hAppIcon=LoadCustomIcon();
	WNDCLASSA wc={};
	wc.lpfnWndProc=WndProc;
	wc.hInstance=hInst;
	wc.lpszClassName="AutoClickerClass";
	wc.hCursor=LoadCursor(nullptr,IDC_ARROW);
	wc.hbrBackground=NULL;
	wc.hIcon=g_hAppIcon;
	if(!RegisterClassA(&wc)){
		MessageBoxA(nullptr,"注册窗口类失败","错误",MB_OK);
		CloseHandle(hMutex);
		ShutdownDirect2D();
		Gdiplus::GdiplusShutdown(g_gdiplusToken);
		return 1;
	}
	RECT rc={0,0,BASE_W,BASE_H};
	AdjustWindowRect(&rc,WS_OVERLAPPEDWINDOW,FALSE);
	hwndMain=CreateWindowA("AutoClickerClass","自动连点器",
	                         WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,
	                         rc.right-rc.left,rc.bottom-rc.top,
	                         nullptr,nullptr,hInst,nullptr);
	if(!hwndMain){
		MessageBoxA(nullptr,"创建窗口失败","错误",MB_OK);
		CloseHandle(hMutex);
		ShutdownDirect2D();
		Gdiplus::GdiplusShutdown(g_gdiplusToken);
		return 1;
	}
	BYTE andMask[1]={0xFF},xorMask[1]={0x00};
	g_hBlankIcon=CreateIcon(hInst,1,1,1,1,andMask,xorMask);
	SendMessageA(hwndMain,WM_SETICON,ICON_SMALL,(LPARAM)g_hBlankIcon);
	SendMessageA(hwndMain,WM_SETICON,ICON_BIG,   (LPARAM)g_hAppIcon);
	SetWindowPos(hwndMain,nullptr,0,0,0,0,
	             SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
	if(lpCmd&&*lpCmd){
		char*c=new char[strlen(lpCmd)+1];
		strcpy(c,lpCmd);
		PostMessage(hwndMain,WM_EXECUTE_CMD,(WPARAM)c,0);
	}
	ShowWindow(hwndMain,SW_SHOW);
	UpdateWindow(hwndMain);
	HANDLE hClicker=CreateThread(nullptr,0,ClickerThread,nullptr,0,nullptr);
	if(!hClicker){
		MessageBoxA(nullptr,"创建线程失败","错误",MB_OK);
		CloseHandle(hMutex);
		ShutdownDirect2D();
		Gdiplus::GdiplusShutdown(g_gdiplusToken);
		return 1;
	}
	MSG msg;
	while(GetMessageA(&msg,nullptr,0,0)){
		TranslateMessage(&msg);
		DispatchMessageA(&msg);
	}
	shouldExit=true;
	WaitForSingleObject(hClicker,INFINITE);
	CloseHandle(hClicker);
	timeEndPeriod(1);
	CloseHandle(hMutex);
	ShutdownDirect2D();
	Gdiplus::GdiplusShutdown(g_gdiplusToken);
	return 0;
}

代码(V1.0)

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

共 2 条回复

danielhaohuang

当我使用macOS时 : 31 | using namespace Gdiplus; | ^ temp2.cpp:33:5: error: unknown type name 'HMODULE' 33 | HMODULE hUser32 = GetModuleHandleW(L"user32.dll"); | ^ temp2.cpp:33:23: error: use of undeclared identifier 'GetModuleHandleW' 33 | HMODULE hUser32 = GetModuleHandleW(L"user32.dll"); | ^ temp2.cpp:35:23: error: unknown type name 'WINAPI' 35 | typedef BOOL (WINAPI *SetDPIAwarenessContextFunc)(PVOID); | ^ temp2.cpp:35:59: error: unknown type name 'PVOID' 35 | typedef BOOL (WINAPI *SetDPIAwarenessContextFunc)(PVOID); | ^ temp2.cpp:35:17: error: a type specifier is required for all declarations 35 | typedef BOOL (WINAPI *SetDPIAwarenessContextFunc)(PVOID); | ~~~~~~~ ^ temp2.cpp:36:9: error: unknown type name 'SetDPIAwarenessContextFunc' 36 | SetDPIAwarenessContextFunc pV2 = (SetDPIAwarenessContextFunc)GetProcAddress(hUser32, "SetProcessDPIAwarenessContext"); | ^ temp2.cpp:36:43: error: use of undeclared identifier 'SetDPIAwarenessContextFunc' 36 | SetDPIAwarenessContextFunc pV2 = (SetDPIAwarenessContextFunc)GetProcAddress(hUser32, "SetProcessDPIAwarenessContext"); | ^ temp2.cpp:37:29: error: use of undeclared identifier 'PVOID' 37 | if (pV2) { if (pV2((PVOID)-4)) return; } | ^ temp2.cpp:39:5: error: unknown type name 'HMODULE' 39 | HMODULE hShcore = LoadLibraryW(L"Shcore.dll"); | ^ temp2.cpp:39:23: error: use of undeclared identifier 'LoadLibraryW' 39 | HMODULE hShcore = LoadLibraryW(L"Shcore.dll"); | ^ temp2.cpp:41:26: error: unknown type name 'WINAPI' 41 | typedef HRESULT (WINAPI *SetDPIAwarenessFunc)(int); | ^ temp2.cpp:41:17: error: a type specifier is required for all declarations 41 | typedef HRESULT (WINAPI *SetDPIAwarenessFunc)(int); | ~~~~~~~ ^ temp2.cpp:42:9: error: use of undeclared identifier 'SetDPIAwarenessFunc'; did you mean 'SetDPIAwareness'? 42 | SetDPIAwarenessFunc pPerMonitor = (SetDPIAwarenessFunc)GetProcAddress(hShcore, "SetProcessDpiAwareness"); | ^~~~~~~~~~~~~~~~~~~ | SetDPIAwareness temp2.cpp:32:6: note: 'SetDPIAwareness' declared here 32 | void SetDPIAwareness() { | ^ temp2.cpp:42:28: error: expected ';' after expression 42 | SetDPIAwarenessFunc pPerMonitor = (SetDPIAwarenessFunc)GetProcAddress(hShcore, "SetProcessDpiAwareness"); | ^ | ; temp2.cpp:42:29: error: use of undeclared identifier 'pPerMonitor' 42 | SetDPIAwarenessFunc pPerMonitor = (SetDPIAwarenessFunc)GetProcAddress(hShcore, "SetProcessDpiAwareness"); | ^ temp2.cpp:42:44: error: use of undeclared identifier 'SetDPIAwarenessFunc'; did you mean 'SetDPIAwareness'? 42 | SetDPIAwarenessFunc pPerMonitor = (SetDPIAwarenessFunc)GetProcAddress(hShcore, "SetProcessDpiAwareness"); | ^~~~~~~~~~~~~~~~~~~ | SetDPIAwareness temp2.cpp:32:6: note: 'SetDPIAwareness' declared here 32 | void SetDPIAwareness() { | ^ temp2.cpp:43:13: error: use of undeclared identifier 'pPerMonitor' 43 | if (pPerMonitor) { if (SUCCEEDED(pPerMonitor(2))) { FreeLibrary(hShcore); return; } } | ^ temp2.cpp:43:42: error: use of undeclared identifier 'pPerMonitor' 43 | if (pPerMonitor) { if (SUCCEEDED(pPerMonitor(2))) { FreeLibrary(hShcore); return; } } | ^ fatal error: too many errors emitted, stopping now [-ferror-limit=] 20 errors generated.

lct123