#ifndef UNICODE #define UNICODE #endif #ifndef _UN...

Criado em: 13 de maio de 2026

Respondido usando GPT-5.5 Thinking por Chat01

Pergunta

#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif

#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <shellapi.h>
#include <mmsystem.h>
#include <thread>
#include <atomic>
#include <vector>
#include <string>
#include <sstream>
#include <mutex>
#include <algorithm>
#include <cwchar>
#include <cstdint>

#pragma comment(lib, "Comctl32.lib")
#pragma comment(lib, "Shell32.lib")
#pragma comment(lib, "Winmm.lib")

// =====================================================
// Settings
// =====================================================
static constexpr int APP_W = 1020;
static constexpr int APP_H = 760;

static constexpr COLORREF CLR_BG = RGB(8, 8, 10);
static constexpr COLORREF CLR_PANEL = RGB(14, 14, 17);
static constexpr COLORREF CLR_PANEL_2 = RGB(21, 21, 25);
static constexpr COLORREF CLR_BORDER = RGB(120, 0, 15);
static constexpr COLORREF CLR_ACCENT = RGB(235, 25, 40);
static constexpr COLORREF CLR_ACCENT_2 = RGB(165, 15, 25);
static constexpr COLORREF CLR_TEXT = RGB(235, 235, 235);
static constexpr COLORREF CLR_MUTED = RGB(165, 165, 165);

static constexpr unsigned long long MAX_CPS = 10000042ULL;

// Layout
static constexpr int CPS_Y_WINDOWS = 616;
static constexpr int CPS_Y_SCREEN = 196;
static constexpr int VIRTUAL_Y_WINDOWS = 694;
static constexpr int VIRTUAL_Y_SCREEN = 274;

// =====================================================
// Globals
// =====================================================
struct WindowItem {
HWND hwnd;
std::wstring title;
HICON icon;
};

enum class ClickMode {
Windows,
Screen
};

std::vector<WindowItem> g_windowList;
std::vector<HWND> g_selectedWindows;
std::mutex g_windowsMutex;

std::atomic<bool> g_clicking(false);
std::atomic<unsigned long long> g_cps(42);
std::atomic<bool> g_useVirtualMouse(false);
std::atomic<long> g_virtualX(0);
std::atomic<long> g_virtualY(0);
std::atomic<int> g_mode((int)ClickMode::Windows);

HWND g_mainHwnd = nullptr;

HFONT g_font = nullptr;
HFONT g_fontBold = nullptr;
HFONT g_fontTitle = nullptr;
HFONT g_fontMenu = nullptr;
HFONT g_fontEdit = nullptr;

HBRUSH g_brBg = nullptr;
HBRUSH g_brPanel = nullptr;
HBRUSH g_brEdit = nullptr;

HIMAGELIST g_imgList = nullptr;

// =====================================================
// UI
// =====================================================
HWND hBtnRefresh = nullptr;
HWND hBtnApplyWindows = nullptr;
HWND hStaticApplied = nullptr;
HWND hListView = nullptr;
HWND hEditCPS = nullptr;
HWND hBtnApplyCPS = nullptr;
HWND hStaticCPS = nullptr;
HWND hChkVirtual = nullptr;
HWND hLblVirtual = nullptr;
HWND hStaticHint = nullptr;

HWND hTabWindows = nullptr;
HWND hTabScreen = nullptr;

HWND hBtnMin = nullptr;
HWND hBtnMax = nullptr;
HWND hBtnClose = nullptr;

// =====================================================
// IDs
// =====================================================
enum {
ID_BTN_REFRESH = 101,
ID_LISTVIEW = 102,
ID_EDIT_CPS = 103,
ID_BTN_APPLY_CPS = 104,
ID_STATIC_CPS = 105,
ID_CHK_VIRTUAL = 106,
ID_BTN_APPLY_WINDOWS = 107,
ID_HOTKEY_F6 = 108,
ID_STATIC_APPLIED = 109,

text
ID_TAB_WINDOWS = 120, ID_TAB_SCREEN = 121, ID_BTN_MIN = 201, ID_BTN_MAX = 202, ID_BTN_CLOSE = 203

};

// =====================================================
// Prototypes
// =====================================================
void RefreshWindowList();
void UpdateSelectedWindows();
void ClickLoop();
void SetVirtualMouseFromCursor();
void UpdateCpsText();
void UpdateAppliedText();
void UpdateModeUi();

static inline POINT GetVirtualPoint()
{
return POINT{ g_virtualX.load(), g_virtualY.load() };
}

static inline unsigned long long ClampUll(unsigned long long v, unsigned long long lo, unsigned long long hi)
{
return std::min(std::max(v, lo), hi);
}

// =====================================================
// GDI helpers
// =====================================================
void FillRound(HDC hdc, RECT rc, COLORREF fill, COLORREF border, int radius)
{
HBRUSH br = CreateSolidBrush(fill);
HPEN pen = CreatePen(PS_SOLID, 1, border);

text
HGDIOBJ oldBr = SelectObject(hdc, br); HGDIOBJ oldPen = SelectObject(hdc, pen); RoundRect(hdc, rc.left, rc.top, rc.right, rc.bottom, radius, radius); SelectObject(hdc, oldBr); SelectObject(hdc, oldPen); DeleteObject(br); DeleteObject(pen);

}

void DrawTitleLogo(HDC hdc)
{
HPEN redPen = CreatePen(PS_SOLID, 3, CLR_ACCENT);
HGDIOBJ oldPen = SelectObject(hdc, redPen);
HGDIOBJ oldBr = SelectObject(hdc, GetStockObject(NULL_BRUSH));

text
Ellipse(hdc, 28, 24, 64, 60); Ellipse(hdc, 38, 34, 54, 50); MoveToEx(hdc, 46, 42, nullptr); LineTo(hdc, 70, 66); SelectObject(hdc, oldBr); SelectObject(hdc, oldPen); DeleteObject(redPen); SetBkMode(hdc, TRANSPARENT); HFONT oldFont = (HFONT)SelectObject(hdc, g_fontTitle); SetTextColor(hdc, CLR_ACCENT); TextOutW(hdc, 84, 27, L"Red", 3); SetTextColor(hdc, CLR_TEXT); TextOutW(hdc, 130, 27, L"Clicer", 6); SelectObject(hdc, oldFont);

}

void DrawWindowChrome(HDC hdc)
{
RECT full{ 0, 0, APP_W, APP_H };
HBRUSH bg = CreateSolidBrush(CLR_BG);
FillRect(hdc, &full, bg);
DeleteObject(bg);

text
RECT outer{ 0, 0, APP_W, APP_H }; FillRound(hdc, outer, CLR_BG, CLR_BORDER, 18); RECT topLine{ 0, 74, APP_W, 75 }; HBRUSH brLine = CreateSolidBrush(RGB(40, 20, 23)); FillRect(hdc, &topLine, brLine); DeleteObject(brLine); DrawTitleLogo(hdc); RECT modePanel{ 28, 90, 988, 164 }; FillRound(hdc, modePanel, CLR_PANEL, RGB(45, 45, 50), 8); ClickMode mode = (ClickMode)g_mode.load(); bool windowsMode = mode == ClickMode::Windows; SetBkMode(hdc, TRANSPARENT); HFONT oldFont = (HFONT)SelectObject(hdc, g_fontBold); if (windowsMode) { RECT appliedPanel{ 28, 180, 988, 230 }; FillRound(hdc, appliedPanel, CLR_PANEL, RGB(45, 45, 50), 8); RECT listPanel{ 28, 244, 988, 588 }; FillRound(hdc, listPanel, CLR_BG, CLR_BORDER, 8); SetTextColor(hdc, CLR_ACCENT); TextOutW(hdc, 50, 260, L"Список окон", 11); RECT cpsPanel{ 28, 604, 988, 734 }; FillRound(hdc, cpsPanel, CLR_PANEL, RGB(45, 45, 50), 8); } else { RECT cpsPanel{ 28, 180, 988, 330 }; FillRound(hdc, cpsPanel, CLR_PANEL, RGB(45, 45, 50), 8); SetTextColor(hdc, CLR_ACCENT); TextOutW(hdc, 50, 182, L"Настройки кликов", 16); } SelectObject(hdc, oldFont);

}

// =====================================================
// Owner-draw buttons
// =====================================================
void DrawOwnerButton(const DRAWITEMSTRUCT* dis)
{
HDC hdc = dis->hDC;
RECT rc = dis->rcItem;
UINT id = dis->CtlID;

text
bool pressed = (dis->itemState & ODS_SELECTED) != 0; bool hot = (dis->itemState & ODS_HOTLIGHT) != 0; COLORREF fill = CLR_PANEL_2; COLORREF border = RGB(55, 55, 60); COLORREF text = CLR_TEXT; HFONT font = g_fontBold; if (id == ID_TAB_WINDOWS || id == ID_TAB_SCREEN) { ClickMode mode = (ClickMode)g_mode.load(); bool active = (id == ID_TAB_WINDOWS && mode == ClickMode::Windows) || (id == ID_TAB_SCREEN && mode == ClickMode::Screen); fill = active ? CLR_ACCENT : (hot ? RGB(30, 30, 36) : CLR_PANEL_2); border = active ? RGB(255, 65, 78) : RGB(60, 60, 66); text = active ? RGB(255, 255, 255) : CLR_MUTED; font = g_fontMenu; } if (id == ID_BTN_APPLY_WINDOWS || id == ID_BTN_APPLY_CPS) { fill = pressed ? CLR_ACCENT_2 : CLR_ACCENT; border = RGB(255, 60, 75); text = RGB(255, 255, 255); } if (id == ID_BTN_CLOSE) { fill = pressed ? RGB(130, 15, 25) : CLR_BG; border = CLR_BG; text = CLR_TEXT; } if (id == ID_BTN_MIN || id == ID_BTN_MAX) { fill = CLR_BG; border = CLR_BG; text = CLR_TEXT; } if (hot && id != ID_BTN_APPLY_WINDOWS && id != ID_BTN_APPLY_CPS && id != ID_BTN_CLOSE && id != ID_BTN_MIN && id != ID_BTN_MAX && id != ID_TAB_WINDOWS && id != ID_TAB_SCREEN) { fill = RGB(26, 26, 31); } FillRound(hdc, rc, fill, border, 10); wchar_t textBuf[128]{}; GetWindowTextW(dis->hwndItem, textBuf, 128); SetBkMode(hdc, TRANSPARENT); SetTextColor(hdc, text); HFONT oldFont = (HFONT)SelectObject(hdc, font); DrawTextW(hdc, textBuf, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE); SelectObject(hdc, oldFont);

}

// =====================================================
// Window icons
// =====================================================
HICON GetWindowSmallIcon(HWND hwnd)
{
HICON icon = (HICON)SendMessageW(hwnd, WM_GETICON, ICON_SMALL2, 0);
if (!icon)
icon = (HICON)SendMessageW(hwnd, WM_GETICON, ICON_SMALL, 0);
if (!icon)
icon = (HICON)SendMessageW(hwnd, WM_GETICON, ICON_BIG, 0);

text
if (!icon) { LONG_PTR clsIcon = GetClassLongPtrW(hwnd, GCLP_HICONSM); if (clsIcon) icon = (HICON)clsIcon; } if (!icon) { LONG_PTR clsIcon = GetClassLongPtrW(hwnd, GCLP_HICON); if (clsIcon) icon = (HICON)clsIcon; } if (!icon) icon = LoadIconW(nullptr, IDI_APPLICATION); return icon;

}

// =====================================================
// Window enum
// =====================================================
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM)
{
if (!IsWindowVisible(hwnd))
return TRUE;

text
if (hwnd == g_mainHwnd) return TRUE; wchar_t title[512]{}; GetWindowTextW(hwnd, title, 512); if (wcslen(title) == 0) return TRUE; LONG_PTR exStyle = GetWindowLongPtrW(hwnd, GWL_EXSTYLE); if (exStyle & WS_EX_TOOLWINDOW) return TRUE; g_windowList.push_back(WindowItem{ hwnd, title, GetWindowSmallIcon(hwnd) }); return TRUE;

}

void RefreshWindowList()
{
g_windowList.clear();
EnumWindows(EnumWindowsProc, 0);

text
std::sort(g_windowList.begin(), g_windowList.end(), [](const WindowItem& a, const WindowItem& b) { return a.title < b.title; }); ListView_DeleteAllItems(hListView); if (g_imgList) { ImageList_Destroy(g_imgList); g_imgList = nullptr; } g_imgList = ImageList_Create(24, 24, ILC_COLOR32 | ILC_MASK, 16, 16); ListView_SetImageList(hListView, g_imgList, LVSIL_SMALL); LVCOLUMNW col{}; col.mask = LVCF_TEXT | LVCF_WIDTH; col.pszText = const_cast<LPWSTR>(L"Окна"); col.cx = 850; if (Header_GetItemCount(ListView_GetHeader(hListView)) == 0) ListView_InsertColumn(hListView, 0, &col); else ListView_SetColumn(hListView, 0, &col); for (int i = 0; i < (int)g_windowList.size(); ++i) { int img = ImageList_AddIcon(g_imgList, g_windowList[i].icon); LVITEMW item{}; item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; item.iItem = i; item.iSubItem = 0; item.pszText = const_cast<LPWSTR>(g_windowList[i].title.c_str()); item.lParam = reinterpret_cast<LPARAM>(g_windowList[i].hwnd); item.iImage = img; ListView_InsertItem(hListView, &item); } { std::lock_guard<std::mutex> lock(g_windowsMutex); g_selectedWindows.clear(); } UpdateAppliedText();

}

void UpdateAppliedText()
{
size_t count = 0;

text
{ std::lock_guard<std::mutex> lock(g_windowsMutex); count = g_selectedWindows.size(); } std::wstringstream ss; ss << L"Выбрано окон: " << count; SetWindowTextW(hStaticApplied, ss.str().c_str());

}

void UpdateSelectedWindows()
{
std::vector<HWND> picked;

text
int count = ListView_GetItemCount(hListView); for (int i = 0; i < count; ++i) { UINT state = ListView_GetItemState(hListView, i, LVIS_STATEIMAGEMASK); if (state == INDEXTOSTATEIMAGEMASK(2)) { LVITEMW item{}; item.mask = LVIF_PARAM; item.iItem = i; if (ListView_GetItem(hListView, &item)) { HWND hwnd = reinterpret_cast<HWND>(item.lParam); if (IsWindow(hwnd)) picked.push_back(hwnd); } } } { std::lock_guard<std::mutex> lock(g_windowsMutex); g_selectedWindows = picked; } UpdateAppliedText();

}

// =====================================================
// CPS
// =====================================================
void UpdateCpsText()
{
std::wstringstream ss;
ss << L"КПС: " << g_cps.load();
SetWindowTextW(hStaticCPS, ss.str().c_str());
}

void ApplyCpsFromEdit()
{
wchar_t buf[64]{};
GetWindowTextW(hEditCPS, buf, 64);

text
unsigned long long value = _wcstoui64(buf, nullptr, 10); if (value < 1) value = 1; if (value > MAX_CPS) value = MAX_CPS; g_cps.store(value); std::wstringstream ss; ss << value; SetWindowTextW(hEditCPS, ss.str().c_str()); UpdateCpsText();

}

// =====================================================
// Clicks
// =====================================================
void SendGlobalClickBatch(unsigned long long clicks)
{
const unsigned long long MAX_BATCH = 4096;

text
while (clicks > 0) { unsigned long long batch64 = std::min(clicks, MAX_BATCH); int batch = (int)batch64; std::vector<INPUT> inputs(batch * 2); for (int i = 0; i < batch; ++i) { inputs[i * 2].type = INPUT_MOUSE; inputs[i * 2].mi.dwFlags = MOUSEEVENTF_LEFTDOWN; inputs[i * 2 + 1].type = INPUT_MOUSE; inputs[i * 2 + 1].mi.dwFlags = MOUSEEVENTF_LEFTUP; } SendInput((UINT)inputs.size(), inputs.data(), sizeof(INPUT)); clicks -= batch64; }

}

void SendVirtualClickBatch(POINT p, unsigned long long clicks)
{
const unsigned long long MAX_BATCH = 4096;

text
int screenW = GetSystemMetrics(SM_CXSCREEN); int screenH = GetSystemMetrics(SM_CYSCREEN); if (screenW <= 1 || screenH <= 1) return; LONG xAbs = (LONG)((double)p.x * 65535.0 / (screenW - 1)); LONG yAbs = (LONG)((double)p.y * 65535.0 / (screenH - 1)); while (clicks > 0) { unsigned long long batch64 = std::min(clicks, MAX_BATCH); int batch = (int)batch64; std::vector<INPUT> inputs(1 + batch * 2); inputs[0].type = INPUT_MOUSE; inputs[0].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; inputs[0].mi.dx = xAbs; inputs[0].mi.dy = yAbs; for (int i = 0; i < batch; ++i) { inputs[1 + i * 2].type = INPUT_MOUSE; inputs[1 + i * 2].mi.dwFlags = MOUSEEVENTF_LEFTDOWN; inputs[1 + i * 2 + 1].type = INPUT_MOUSE; inputs[1 + i * 2 + 1].mi.dwFlags = MOUSEEVENTF_LEFTUP; } SendInput((UINT)inputs.size(), inputs.data(), sizeof(INPUT)); clicks -= batch64; }

}

LPARAM MakeMouseLParam(POINT clientPoint)
{
return MAKELPARAM((SHORT)clientPoint.x, (SHORT)clientPoint.y);
}

void PostWindowClick(HWND hwnd, POINT screenPoint)
{
if (!IsWindow(hwnd))
return;

text
POINT clientPoint = screenPoint; ScreenToClient(hwnd, &clientPoint); LPARAM lp = MakeMouseLParam(clientPoint); PostMessageW(hwnd, WM_MOUSEMOVE, 0, lp); PostMessageW(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, lp); PostMessageW(hwnd, WM_LBUTTONUP, 0, lp);

}

void DoClickBurst(unsigned long long amount)
{
if (amount == 0)
return;

text
ClickMode mode = (ClickMode)g_mode.load(); bool virtualMode = g_useVirtualMouse.load(); POINT realPos{}; GetCursorPos(&realPos); POINT virtualPos = GetVirtualPoint(); POINT effectivePos = virtualMode ? virtualPos : realPos; if (mode == ClickMode::Screen) { if (virtualMode) SendVirtualClickBatch(effectivePos, amount); else SendGlobalClickBatch(amount); return; } std::vector<HWND> targets; { std::lock_guard<std::mutex> lock(g_windowsMutex); targets = g_selectedWindows; } if (targets.empty()) return; for (unsigned long long i = 0; i < amount; ++i) { for (HWND hwnd : targets) { PostWindowClick(hwnd, effectivePos); } }

}

void WaitBeforeNextClick(unsigned long long cps, long double accumulator, unsigned long long preferredBatch, int& idleSpins)
{
if (cps < 1)
cps = 1;

text
long double need = (long double)preferredBatch - accumulator; if (need < 1.0L) need = 1.0L; long double secondsToBatch = need / (long double)cps; if (secondsToBatch > 0.0025L) { Sleep(1); idleSpins = 0; } else { if (++idleSpins < 300) { YieldProcessor(); } else { Sleep(0); idleSpins = 0; } }

}

void ClickLoop()
{
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
timeBeginPeriod(1);

text
LARGE_INTEGER freq{}; LARGE_INTEGER last{}; LARGE_INTEGER now{}; QueryPerformanceFrequency(&freq); QueryPerformanceCounter(&last); long double accumulator = 0.0L; int idleSpins = 0; unsigned long long lastCps = g_cps.load(std::memory_order_relaxed); while (g_clicking.load(std::memory_order_relaxed)) { QueryPerformanceCounter(&now); long double elapsed = (long double)(now.QuadPart - last.QuadPart) / (long double)freq.QuadPart; last = now; // Не даём старому лагу копиться и потом выдавать лишний большой залп. if (elapsed > 0.10L) elapsed = 0.10L; unsigned long long localCps = g_cps.load(std::memory_order_relaxed); if (localCps < 1) localCps = 1; // При смене КПС сбрасываем остаток, чтобы старый темп не давал скачок. if (localCps != lastCps) { accumulator = 0.0L; lastCps = localCps; } accumulator += elapsed * (long double)localCps; // До 30к КПС делаем маленькие ровные пачки примерно на 1 мс. // Так меньше разброс: 3000 не должен превращаться в 8000 на тестерах CPS. unsigned long long preferredBatch = ClampUll(localCps / 1000ULL, 1ULL, 30ULL); if (accumulator < (long double)preferredBatch) { WaitBeforeNextClick(localCps, accumulator, preferredBatch, idleSpins); continue; } unsigned long long due = (unsigned long long)accumulator; ClickMode mode = (ClickMode)g_mode.load(std::memory_order_relaxed); unsigned long long maxBurst = 0; if (localCps <= 30000ULL) { maxBurst = ClampUll(preferredBatch * 2ULL, 1ULL, 64ULL); } else { maxBurst = (mode == ClickMode::Screen) ? 2048ULL : 512ULL; } if (due > maxBurst) due = maxBurst; accumulator -= (long double)due; // Ограничиваем догоняющий хвост, чтобы после зависания не было резкого перелёта КПС. long double maxBacklog = (long double)maxBurst * 2.0L; if (accumulator > maxBacklog) accumulator = maxBacklog; DoClickBurst(due); idleSpins = 0; } timeEndPeriod(1);

}

void ToggleClicking()
{
bool now = !g_clicking.load();

text
g_clicking.store(now); if (now) { std::thread(ClickLoop).detach(); SetWindowTextW(hStaticHint, L"F6: стоп"); } else { SetWindowTextW(hStaticHint, L"F6: старт / стоп"); }

}

// =====================================================
// Virtual mouse
// =====================================================
void SetVirtualMouseFromCursor()
{
POINT p{};
GetCursorPos(&p);

text
g_virtualX.store(p.x); g_virtualY.store(p.y);

}

// =====================================================
// Mode
// =====================================================
void UpdateModeUi()
{
ClickMode mode = (ClickMode)g_mode.load();
bool windowsMode = mode == ClickMode::Windows;

text
ShowWindow(hBtnRefresh, windowsMode ? SW_SHOW : SW_HIDE); ShowWindow(hBtnApplyWindows, windowsMode ? SW_SHOW : SW_HIDE); ShowWindow(hStaticApplied, windowsMode ? SW_SHOW : SW_HIDE); ShowWindow(hListView, windowsMode ? SW_SHOW : SW_HIDE); int cpsY = windowsMode ? CPS_Y_WINDOWS : CPS_Y_SCREEN; int virtualY = windowsMode ? VIRTUAL_Y_WINDOWS : VIRTUAL_Y_SCREEN; MoveWindow(hEditCPS, 50, cpsY, 180, 54, TRUE); MoveWindow(hBtnApplyCPS, 252, cpsY, 255, 54, TRUE); MoveWindow(hStaticCPS, 532, cpsY + 14, 280, 32, TRUE); MoveWindow(hChkVirtual, 50, virtualY, 22, 22, TRUE); MoveWindow(hLblVirtual, 80, virtualY, 260, 30, TRUE); MoveWindow(hStaticHint, 360, virtualY + 2, 500, 28, TRUE); InvalidateRect(hTabWindows, nullptr, TRUE); InvalidateRect(hTabScreen, nullptr, TRUE); InvalidateRect(g_mainHwnd, nullptr, TRUE);

}

// =====================================================
// Main window
// =====================================================
LRESULT CALLBACK MainProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_CREATE:
{
g_brBg = CreateSolidBrush(CLR_BG);
g_brPanel = CreateSolidBrush(CLR_PANEL);
g_brEdit = CreateSolidBrush(CLR_PANEL_2);

text
g_font = CreateFontW( 21, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH, L"Segoe UI Variable Display" ); g_fontBold = CreateFontW( 21, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH, L"Segoe UI Variable Display" ); g_fontTitle = CreateFontW( 30, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH, L"Segoe UI Variable Display" ); g_fontMenu = CreateFontW( 27, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH, L"Segoe UI Variable Display" ); g_fontEdit = CreateFontW( 26, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH, L"Segoe UI Variable Display" ); hBtnMin = CreateWindowW( L"BUTTON", L"—", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, APP_W - 198, 22, 54, 38, hwnd, (HMENU)ID_BTN_MIN, GetModuleHandleW(nullptr), nullptr ); hBtnMax = CreateWindowW( L"BUTTON", L"□", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, APP_W - 134, 22, 54, 38, hwnd, (HMENU)ID_BTN_MAX, GetModuleHandleW(nullptr), nullptr ); hBtnClose = CreateWindowW( L"BUTTON", L"×", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, APP_W - 70, 22, 54, 38, hwnd, (HMENU)ID_BTN_CLOSE, GetModuleHandleW(nullptr), nullptr ); hTabWindows = CreateWindowW( L"BUTTON", L"1 Окна", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 50, 100, 280, 54, hwnd, (HMENU)ID_TAB_WINDOWS, GetModuleHandleW(nullptr), nullptr ); hTabScreen = CreateWindowW( L"BUTTON", L"2 Экран", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 350, 100, 280, 54, hwnd, (HMENU)ID_TAB_SCREEN, GetModuleHandleW(nullptr), nullptr ); hBtnRefresh = CreateWindowW( L"BUTTON", L"Обновить список", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 650, 100, 150, 54, hwnd, (HMENU)ID_BTN_REFRESH, GetModuleHandleW(nullptr), nullptr ); hBtnApplyWindows = CreateWindowW( L"BUTTON", L"Применить", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 818, 100, 142, 54, hwnd, (HMENU)ID_BTN_APPLY_WINDOWS, GetModuleHandleW(nullptr), nullptr ); hStaticApplied = CreateWindowW( L"STATIC", L"Выбрано окон: 0", WS_CHILD | WS_VISIBLE, 50, 194, 420, 28, hwnd, (HMENU)ID_STATIC_APPLIED, GetModuleHandleW(nullptr), nullptr ); hListView = CreateWindowW( WC_LISTVIEWW, nullptr, WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOCOLUMNHEADER, 52, 292, 910, 276, hwnd, (HMENU)ID_LISTVIEW, GetModuleHandleW(nullptr), nullptr ); ListView_SetExtendedListViewStyle( hListView, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES | LVS_EX_DOUBLEBUFFER ); ListView_SetBkColor(hListView, CLR_PANEL); ListView_SetTextBkColor(hListView, CLR_PANEL); ListView_SetTextColor(hListView, CLR_TEXT); hEditCPS = CreateWindowW( L"EDIT", L"42", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NUMBER, 50, CPS_Y_WINDOWS, 180, 54, hwnd, (HMENU)ID_EDIT_CPS, GetModuleHandleW(nullptr), nullptr ); hBtnApplyCPS = CreateWindowW( L"BUTTON", L"Применить КПС", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 252, CPS_Y_WINDOWS, 255, 54, hwnd, (HMENU)ID_BTN_APPLY_CPS, GetModuleHandleW(nullptr), nullptr ); hStaticCPS = CreateWindowW( L"STATIC", L"КПС: 42", WS_CHILD | WS_VISIBLE, 532, CPS_Y_WINDOWS + 14, 280, 32, hwnd, (HMENU)ID_STATIC_CPS, GetModuleHandleW(nullptr), nullptr ); hChkVirtual = CreateWindowW( L"BUTTON", L"", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 50, VIRTUAL_Y_WINDOWS, 22, 22, hwnd, (HMENU)ID_CHK_VIRTUAL, GetModuleHandleW(nullptr), nullptr ); hLblVirtual = CreateWindowW( L"STATIC", L"Виртуальная мышь", WS_CHILD | WS_VISIBLE, 80, VIRTUAL_Y_WINDOWS, 260, 30, hwnd, nullptr, GetModuleHandleW(nullptr), nullptr ); hStaticHint = CreateWindowW( L"STATIC", L"F6: старт / стоп", WS_CHILD | WS_VISIBLE, 360, VIRTUAL_Y_WINDOWS + 2, 500, 28, hwnd, nullptr, GetModuleHandleW(nullptr), nullptr ); HWND controls[] = { hBtnMin, hBtnMax, hBtnClose, hTabWindows, hTabScreen, hBtnRefresh, hBtnApplyWindows, hStaticApplied, hListView, hEditCPS, hBtnApplyCPS, hStaticCPS, hChkVirtual, hLblVirtual, hStaticHint }; for (HWND c : controls) SendMessageW(c, WM_SETFONT, (WPARAM)g_font, TRUE); SendMessageW(hTabWindows, WM_SETFONT, (WPARAM)g_fontMenu, TRUE); SendMessageW(hTabScreen, WM_SETFONT, (WPARAM)g_fontMenu, TRUE); SendMessageW(hEditCPS, WM_SETFONT, (WPARAM)g_fontEdit, TRUE); SendMessageW(hStaticApplied, WM_SETFONT, (WPARAM)g_fontBold, TRUE); SendMessageW(hStaticCPS, WM_SETFONT, (WPARAM)g_fontBold, TRUE); RefreshWindowList(); RegisterHotKey(hwnd, ID_HOTKEY_F6, 0, VK_F6); POINT center{ GetSystemMetrics(SM_CXSCREEN) / 2, GetSystemMetrics(SM_CYSCREEN) / 2 }; g_virtualX.store(center.x); g_virtualY.store(center.y); UpdateModeUi(); return 0; } case WM_ERASEBKGND: return 1; case WM_PAINT: { PAINTSTRUCT ps{}; HDC hdc = BeginPaint(hwnd, &ps); DrawWindowChrome(hdc); EndPaint(hwnd, &ps); return 0; } case WM_NCHITTEST: { POINT p{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; ScreenToClient(hwnd, &p); if (p.y >= 0 && p.y <= 75) { if (p.x >= APP_W - 220) return HTCLIENT; return HTCAPTION; } return HTCLIENT; } case WM_CTLCOLORSTATIC: { HDC hdc = (HDC)wParam; SetBkMode(hdc, TRANSPARENT); HWND ctl = (HWND)lParam; if (ctl == hStaticApplied || ctl == hStaticCPS) SetTextColor(hdc, CLR_TEXT); else SetTextColor(hdc, CLR_MUTED); return (LRESULT)g_brPanel; } case WM_CTLCOLORBTN: { HDC hdc = (HDC)wParam; SetBkMode(hdc, TRANSPARENT); SetTextColor(hdc, CLR_TEXT); return (LRESULT)g_brPanel; } case WM_CTLCOLOREDIT: { HDC hdc = (HDC)wParam; SetBkColor(hdc, CLR_PANEL_2); SetTextColor(hdc, CLR_TEXT); return (LRESULT)g_brEdit; } case WM_DRAWITEM: { DrawOwnerButton((DRAWITEMSTRUCT*)lParam); return TRUE; } case WM_NOTIFY: { LPNMHDR hdr = (LPNMHDR)lParam; if (hdr->idFrom == ID_LISTVIEW && hdr->code == NM_CUSTOMDRAW) { LPNMLVCUSTOMDRAW cd = (LPNMLVCUSTOMDRAW)lParam; if (cd->nmcd.dwDrawStage == CDDS_PREPAINT) { SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, CDRF_NOTIFYITEMDRAW); return TRUE; } if (cd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) { cd->clrText = CLR_TEXT; cd->clrTextBk = CLR_PANEL; SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, CDRF_DODEFAULT); return TRUE; } } return 0; } case WM_HOTKEY: { if (wParam == ID_HOTKEY_F6) ToggleClicking(); return 0; } case WM_COMMAND: { switch (LOWORD(wParam)) { case ID_BTN_REFRESH: RefreshWindowList(); break; case ID_BTN_APPLY_WINDOWS: UpdateSelectedWindows(); break; case ID_BTN_APPLY_CPS: ApplyCpsFromEdit(); break; case ID_TAB_WINDOWS: g_mode.store((int)ClickMode::Windows); UpdateModeUi(); break; case ID_TAB_SCREEN: g_mode.store((int)ClickMode::Screen); UpdateModeUi(); break; case ID_CHK_VIRTUAL: { LRESULT state = SendMessageW(hChkVirtual, BM_GETCHECK, 0, 0); bool enabled = state == BST_CHECKED; g_useVirtualMouse.store(enabled); if (enabled) SetVirtualMouseFromCursor(); break; } case ID_BTN_MIN: ShowWindow(hwnd, SW_MINIMIZE); break; case ID_BTN_MAX: if (IsZoomed(hwnd)) ShowWindow(hwnd, SW_RESTORE); else ShowWindow(hwnd, SW_MAXIMIZE); break; case ID_BTN_CLOSE: DestroyWindow(hwnd); break; } return 0; } case WM_DESTROY: { g_clicking.store(false); UnregisterHotKey(hwnd, ID_HOTKEY_F6); if (g_imgList) ImageList_Destroy(g_imgList); if (g_font) DeleteObject(g_font); if (g_fontBold) DeleteObject(g_fontBold); if (g_fontTitle) DeleteObject(g_fontTitle); if (g_fontMenu) DeleteObject(g_fontMenu); if (g_fontEdit) DeleteObject(g_fontEdit); if (g_brBg) DeleteObject(g_brBg); if (g_brPanel) DeleteObject(g_brPanel); if (g_brEdit) DeleteObject(g_brEdit); PostQuitMessage(0); return 0; } } return DefWindowProcW(hwnd, msg, wParam, lParam);

}

// =====================================================
// Entry point
// =====================================================
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR, int nCmdShow)
{
SetProcessDPIAware();

text
INITCOMMONCONTROLSEX icex{}; icex.dwSize = sizeof(icex); icex.dwICC = ICC_LISTVIEW_CLASSES | ICC_STANDARD_CLASSES; InitCommonControlsEx(&icex); WNDCLASSW wc{}; wc.lpfnWndProc = MainProc; wc.hInstance = hInstance; wc.lpszClassName = L"RedClicerMainWindow"; wc.hCursor = LoadCursorW(nullptr, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); if (!RegisterClassW(&wc)) { MessageBoxW(nullptr, L"Не удалось зарегистрировать класс окна.", L"Ошибка", MB_OK | MB_ICONERROR); return 0; } int x = (GetSystemMetrics(SM_CXSCREEN) - APP_W) / 2; int y = (GetSystemMetrics(SM_CYSCREEN) - APP_H) / 2; g_mainHwnd = CreateWindowExW( WS_EX_APPWINDOW, L"RedClicerMainWindow", L"RedClicer", WS_POPUP | WS_MINIMIZEBOX, x, y, APP_W, APP_H, nullptr, nullptr, hInstance, nullptr ); if (!g_mainHwnd) { MessageBoxW(nullptr, L"Не удалось создать окно.", L"Ошибка", MB_OK | MB_ICONERROR); return 0; } HRGN rgn = CreateRoundRectRgn(0, 0, APP_W + 1, APP_H + 1, 18, 18); SetWindowRgn(g_mainHwnd, rgn, TRUE); ShowWindow(g_mainHwnd, nCmdShow); UpdateWindow(g_mainHwnd); MSG msg{}; while (GetMessageW(&msg, nullptr, 0, 0)) { TranslateMessage(&msg); DispatchMessageW(&msg); } return 0;

}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
return wWinMain(hInstance, hPrevInstance, GetCommandLineW(), nCmdShow);
}
компилил - g++ -std=c++17 12.cpp -O2 -municode -mwindows -lcomctl32 -lgdi32 -luser32 -lshell32 -lwinmm -o RedClicker.exe

надо исправит

  1. когда выбераешь экран чучуть криво и пол текст настойка кликов убрать и сделать более ровно
  2. виртуальная мышь должна созронять последнию позицию где была мышь и кликать туда уже виртуал мышь даж когда окно свёрнуто но оно кликает ток в точку всегда

итог скинь готовый код в виде файла сюда и как компилить

Pensamento

Handling virtual mouse point capture and updates

I need to find the right moment to capture the virtual mouse position when switching between modes. It's essential to avoid locking issues, so I'll capture the point safely when toggling to screen mode or when F6 is pressed. The user may want to adjust the saved position, but "last position" should be preserved, and I might add a hint for clarity.

Thought for 54s

Python

python
from pathlib import Path code = r'''#ifndef UNICODE #define UNICODE #endif #ifndef _UNICODE #define _UNICODE #endif #include <windows.h> #include <windowsx.h> #include <commctrl.h> #include <shellapi.h> #include <mmsystem.h> #include <thread> #include <atomic> #include <vector> #include <string> #include <sstream> #include <mutex> #include <algorithm> #include <cwchar> #include <cstdint> #pragma comment(lib, "Comctl32.lib") #pragma comment(lib, "Shell32.lib") #pragma comment(lib, "Winmm.lib") // ===================================================== // Settings // ===================================================== static constexpr int APP_W = 1020; static constexpr int APP_H = 760; static constexpr COLORREF CLR_BG = RGB(8, 8, 10); static constexpr COLORREF CLR_PANEL = RGB(14, 14, 17); static constexpr COLORREF CLR_PANEL_2 = RGB(21, 21, 25); static constexpr COLORREF CLR_BORDER = RGB(120, 0, 15); static constexpr COLORREF CLR_ACCENT = RGB(235, 25, 40); static constexpr COLORREF CLR_ACCENT_2 = RGB(165, 15, 25); static constexpr COLORREF CLR_TEXT = RGB(235, 235, 235); static constexpr COLORREF CLR_MUTED = RGB(165, 165, 165); static constexpr unsigned long long MAX_CPS = 10000042ULL; // Layout static constexpr int CPS_Y_WINDOWS = 616; static constexpr int CPS_Y_SCREEN = 210; static constexpr int VIRTUAL_Y_WINDOWS = 694; static constexpr int VIRTUAL_Y_SCREEN = 286; // ===================================================== // Globals // ===================================================== struct WindowItem { HWND hwnd; std::wstring title; HICON icon; }; struct SavedVirtualPoint { HWND hwnd; POINT clientPoint; }; enum class ClickMode { Windows, Screen }; std::vector<WindowItem> g_windowList; std::vector<HWND> g_selectedWindows; std::vector<SavedVirtualPoint> g_virtualClientPoints; std::mutex g_windowsMutex; std::atomic<bool> g_clicking(false); std::atomic<unsigned long long> g_cps(42); std::atomic<bool> g_useVirtualMouse(false); std::atomic<long> g_virtualX(0); std::atomic<long> g_virtualY(0); std::atomic<int> g_mode((int)ClickMode::Windows); HWND g_mainHwnd = nullptr; HFONT g_font = nullptr; HFONT g_fontBold = nullptr; HFONT g_fontTitle = nullptr; HFONT g_fontMenu = nullptr; HFONT g_fontEdit = nullptr; HBRUSH g_brBg = nullptr; HBRUSH g_brPanel = nullptr; HBRUSH g_brEdit = nullptr; HIMAGELIST g_imgList = nullptr; // ===================================================== // UI // ===================================================== HWND hBtnRefresh = nullptr; HWND hBtnApplyWindows = nullptr; HWND hStaticApplied = nullptr; HWND hListView = nullptr; HWND hEditCPS = nullptr; HWND hBtnApplyCPS = nullptr; HWND hStaticCPS = nullptr; HWND hChkVirtual = nullptr; HWND hLblVirtual = nullptr; HWND hStaticHint = nullptr; HWND hTabWindows = nullptr; HWND hTabScreen = nullptr; HWND hBtnMin = nullptr; HWND hBtnMax = nullptr; HWND hBtnClose = nullptr; // ===================================================== // IDs // ===================================================== enum { ID_BTN_REFRESH = 101, ID_LISTVIEW = 102, ID_EDIT_CPS = 103, ID_BTN_APPLY_CPS = 104, ID_STATIC_CPS = 105, ID_CHK_VIRTUAL = 106, ID_BTN_APPLY_WINDOWS = 107, ID_HOTKEY_F6 = 108, ID_STATIC_APPLIED = 109, ID_TAB_WINDOWS = 120, ID_TAB_SCREEN = 121, ID_BTN_MIN = 201, ID_BTN_MAX = 202, ID_BTN_CLOSE = 203 }; // ===================================================== // Prototypes // ===================================================== void RefreshWindowList(); void UpdateSelectedWindows(); void ClickLoop(); void SetVirtualMouseFromCursor(); void UpdateCpsText(); void UpdateAppliedText(); void UpdateModeUi(); static inline POINT GetVirtualPoint() { return POINT{ g_virtualX.load(), g_virtualY.load() }; } static inline unsigned long long ClampUll(unsigned long long v, unsigned long long lo, unsigned long long hi) { return std::min(std::max(v, lo), hi); } static inline LONG ClampLong(LONG v, LONG lo, LONG hi) { return std::min(std::max(v, lo), hi); } // ===================================================== // GDI helpers // ===================================================== void FillRound(HDC hdc, RECT rc, COLORREF fill, COLORREF border, int radius) { HBRUSH br = CreateSolidBrush(fill); HPEN pen = CreatePen(PS_SOLID, 1, border); HGDIOBJ oldBr = SelectObject(hdc, br); HGDIOBJ oldPen = SelectObject(hdc, pen); RoundRect(hdc, rc.left, rc.top, rc.right, rc.bottom, radius, radius); SelectObject(hdc, oldBr); SelectObject(hdc, oldPen); DeleteObject(br); DeleteObject(pen); } void DrawTitleLogo(HDC hdc) { HPEN redPen = CreatePen(PS_SOLID, 3, CLR_ACCENT); HGDIOBJ oldPen = SelectObject(hdc, redPen); HGDIOBJ oldBr = SelectObject(hdc, GetStockObject(NULL_BRUSH)); Ellipse(hdc, 28, 24, 64, 60); Ellipse(hdc, 38, 34, 54, 50); MoveToEx(hdc, 46, 42, nullptr); LineTo(hdc, 70, 66); SelectObject(hdc, oldBr); SelectObject(hdc, oldPen); DeleteObject(redPen); SetBkMode(hdc, TRANSPARENT); HFONT oldFont = (HFONT)SelectObject(hdc, g_fontTitle); SetTextColor(hdc, CLR_ACCENT); TextOutW(hdc, 84, 27, L"Red", 3); SetTextColor(hdc, CLR_TEXT); TextOutW(hdc, 130, 27, L"Clicer", 6); SelectObject(hdc, oldFont); } void DrawWindowChrome(HDC hdc) { RECT full{ 0, 0, APP_W, APP_H }; HBRUSH bg = CreateSolidBrush(CLR_BG); FillRect(hdc, &full, bg); DeleteObject(bg); RECT outer{ 0, 0, APP_W, APP_H }; FillRound(hdc, outer, CLR_BG, CLR_BORDER, 18); RECT topLine{ 0, 74, APP_W, 75 }; HBRUSH brLine = CreateSolidBrush(RGB(40, 20, 23)); FillRect(hdc, &topLine, brLine); DeleteObject(brLine); DrawTitleLogo(hdc); RECT modePanel{ 28, 90, 988, 164 }; FillRound(hdc, modePanel, CLR_PANEL, RGB(45, 45, 50), 8); ClickMode mode = (ClickMode)g_mode.load(); bool windowsMode = mode == ClickMode::Windows; SetBkMode(hdc, TRANSPARENT); HFONT oldFont = (HFONT)SelectObject(hdc, g_fontBold); if (windowsMode) { RECT appliedPanel{ 28, 180, 988, 230 }; FillRound(hdc, appliedPanel, CLR_PANEL, RGB(45, 45, 50), 8); RECT listPanel{ 28, 244, 988, 588 }; FillRound(hdc, listPanel, CLR_BG, CLR_BORDER, 8); SetTextColor(hdc, CLR_ACCENT); TextOutW(hdc, 50, 260, L"Список окон", 11); RECT cpsPanel{ 28, 604, 988, 734 }; FillRound(hdc, cpsPanel, CLR_PANEL, RGB(45, 45, 50), 8); } else { // В режиме "Экран" убран обрезанный заголовок и выровнены элементы. RECT cpsPanel{ 28, 180, 988, 348 }; FillRound(hdc, cpsPanel, CLR_PANEL, RGB(45, 45, 50), 8); } SelectObject(hdc, oldFont); } // ===================================================== // Owner-draw buttons // ===================================================== void DrawOwnerButton(const DRAWITEMSTRUCT* dis) { HDC hdc = dis->hDC; RECT rc = dis->rcItem; UINT id = dis->CtlID; bool pressed = (dis->itemState & ODS_SELECTED) != 0; bool hot = (dis->itemState & ODS_HOTLIGHT) != 0; COLORREF fill = CLR_PANEL_2; COLORREF border = RGB(55, 55, 60); COLORREF text = CLR_TEXT; HFONT font = g_fontBold; if (id == ID_TAB_WINDOWS || id == ID_TAB_SCREEN) { ClickMode mode = (ClickMode)g_mode.load(); bool active = (id == ID_TAB_WINDOWS && mode == ClickMode::Windows) || (id == ID_TAB_SCREEN && mode == ClickMode::Screen); fill = active ? CLR_ACCENT : (hot ? RGB(30, 30, 36) : CLR_PANEL_2); border = active ? RGB(255, 65, 78) : RGB(60, 60, 66); text = active ? RGB(255, 255, 255) : CLR_MUTED; font = g_fontMenu; } if (id == ID_BTN_APPLY_WINDOWS || id == ID_BTN_APPLY_CPS) { fill = pressed ? CLR_ACCENT_2 : CLR_ACCENT; border = RGB(255, 60, 75); text = RGB(255, 255, 255); } if (id == ID_BTN_CLOSE) { fill = pressed ? RGB(130, 15, 25) : CLR_BG; border = CLR_BG; text = CLR_TEXT; } if (id == ID_BTN_MIN || id == ID_BTN_MAX) { fill = CLR_BG; border = CLR_BG; text = CLR_TEXT; } if (hot && id != ID_BTN_APPLY_WINDOWS && id != ID_BTN_APPLY_CPS && id != ID_BTN_CLOSE && id != ID_BTN_MIN && id != ID_BTN_MAX && id != ID_TAB_WINDOWS && id != ID_TAB_SCREEN) { fill = RGB(26, 26, 31); } FillRound(hdc, rc, fill, border, 10); wchar_t textBuf[128]{}; GetWindowTextW(dis->hwndItem, textBuf, 128); SetBkMode(hdc, TRANSPARENT); SetTextColor(hdc, text); HFONT oldFont = (HFONT)SelectObject(hdc, font); DrawTextW(hdc, textBuf, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE); SelectObject(hdc, oldFont); } // ===================================================== // Window icons // ===================================================== HICON GetWindowSmallIcon(HWND hwnd) { HICON icon = (HICON)SendMessageW(hwnd, WM_GETICON, ICON_SMALL2, 0); if (!icon) icon = (HICON)SendMessageW(hwnd, WM_GETICON, ICON_SMALL, 0); if (!icon) icon = (HICON)SendMessageW(hwnd, WM_GETICON, ICON_BIG, 0); if (!icon) { LONG_PTR clsIcon = GetClassLongPtrW(hwnd, GCLP_HICONSM); if (clsIcon) icon = (HICON)clsIcon; } if (!icon) { LONG_PTR clsIcon = GetClassLongPtrW(hwnd, GCLP_HICON); if (clsIcon) icon = (HICON)clsIcon; } if (!icon) icon = LoadIconW(nullptr, IDI_APPLICATION); return icon; } // ===================================================== // Window enum // ===================================================== BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM) { if (!IsWindowVisible(hwnd)) return TRUE; if (hwnd == g_mainHwnd) return TRUE; wchar_t title[512]{}; GetWindowTextW(hwnd, title, 512); if (wcslen(title) == 0) return TRUE; LONG_PTR exStyle = GetWindowLongPtrW(hwnd, GWL_EXSTYLE); if (exStyle & WS_EX_TOOLWINDOW) return TRUE; g_windowList.push_back(WindowItem{ hwnd, title, GetWindowSmallIcon(hwnd) }); return TRUE; } void RefreshWindowList() { g_windowList.clear(); EnumWindows(EnumWindowsProc, 0); std::sort(g_windowList.begin(), g_windowList.end(), [](const WindowItem& a, const WindowItem& b) { return a.title < b.title; }); ListView_DeleteAllItems(hListView); if (g_imgList) { ImageList_Destroy(g_imgList); g_imgList = nullptr; } g_imgList = ImageList_Create(24, 24, ILC_COLOR32 | ILC_MASK, 16, 16); ListView_SetImageList(hListView, g_imgList, LVSIL_SMALL); LVCOLUMNW col{}; col.mask = LVCF_TEXT | LVCF_WIDTH; col.pszText = const_cast<LPWSTR>(L"Окна"); col.cx = 850; if (Header_GetItemCount(ListView_GetHeader(hListView)) == 0) ListView_InsertColumn(hListView, 0, &col); else ListView_SetColumn(hListView, 0, &col); for (int i = 0; i < (int)g_windowList.size(); ++i) { int img = ImageList_AddIcon(g_imgList, g_windowList[i].icon); LVITEMW item{}; item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; item.iItem = i; item.iSubItem = 0; item.pszText = const_cast<LPWSTR>(g_windowList[i].title.c_str()); item.lParam = reinterpret_cast<LPARAM>(g_windowList[i].hwnd); item.iImage = img; ListView_InsertItem(hListView, &item); } { std::lock_guard<std::mutex> lock(g_windowsMutex); g_selectedWindows.clear(); g_virtualClientPoints.clear(); } UpdateAppliedText(); } void UpdateAppliedText() { size_t count = 0; { std::lock_guard<std::mutex> lock(g_windowsMutex); count = g_selectedWindows.size(); } std::wstringstream ss; ss << L"Выбрано окон: " << count; SetWindowTextW(hStaticApplied, ss.str().c_str()); } void UpdateSelectedWindows() { std::vector<HWND> picked; int count = ListView_GetItemCount(hListView); for (int i = 0; i < count; ++i) { UINT state = ListView_GetItemState(hListView, i, LVIS_STATEIMAGEMASK); if (state == INDEXTOSTATEIMAGEMASK(2)) { LVITEMW item{}; item.mask = LVIF_PARAM; item.iItem = i; if (ListView_GetItem(hListView, &item)) { HWND hwnd = reinterpret_cast<HWND>(item.lParam); if (IsWindow(hwnd)) picked.push_back(hwnd); } } } { std::lock_guard<std::mutex> lock(g_windowsMutex); g_selectedWindows = picked; g_virtualClientPoints.clear(); } // Если виртуальная мышь уже включена, сразу пересохраняем точку // относительно выбранных окон. if (g_useVirtualMouse.load()) SetVirtualMouseFromCursor(); UpdateAppliedText(); } // ===================================================== // CPS // ===================================================== void UpdateCpsText() { std::wstringstream ss; ss << L"КПС: " << g_cps.load(); SetWindowTextW(hStaticCPS, ss.str().c_str()); } void ApplyCpsFromEdit() { wchar_t buf[64]{}; GetWindowTextW(hEditCPS, buf, 64); unsigned long long value = _wcstoui64(buf, nullptr, 10); if (value < 1) value = 1; if (value > MAX_CPS) value = MAX_CPS; g_cps.store(value); std::wstringstream ss; ss << value; SetWindowTextW(hEditCPS, ss.str().c_str()); UpdateCpsText(); } // ===================================================== // Clicks // ===================================================== void SendGlobalClickBatch(unsigned long long clicks) { const unsigned long long MAX_BATCH = 4096; while (clicks > 0) { unsigned long long batch64 = std::min(clicks, MAX_BATCH); int batch = (int)batch64; std::vector<INPUT> inputs(batch * 2); for (int i = 0; i < batch; ++i) { inputs[i * 2].type = INPUT_MOUSE; inputs[i * 2].mi.dwFlags = MOUSEEVENTF_LEFTDOWN; inputs[i * 2 + 1].type = INPUT_MOUSE; inputs[i * 2 + 1].mi.dwFlags = MOUSEEVENTF_LEFTUP; } SendInput((UINT)inputs.size(), inputs.data(), sizeof(INPUT)); clicks -= batch64; } } void SendVirtualClickBatch(POINT p, unsigned long long clicks) { const unsigned long long MAX_BATCH = 4096; int virtualLeft = GetSystemMetrics(SM_XVIRTUALSCREEN); int virtualTop = GetSystemMetrics(SM_YVIRTUALSCREEN); int virtualW = GetSystemMetrics(SM_CXVIRTUALSCREEN); int virtualH = GetSystemMetrics(SM_CYVIRTUALSCREEN); if (virtualW <= 1 || virtualH <= 1) return; LONG xAbs = (LONG)(((long double)(p.x - virtualLeft) * 65535.0L) / (long double)(virtualW - 1)); LONG yAbs = (LONG)(((long double)(p.y - virtualTop) * 65535.0L) / (long double)(virtualH - 1)); xAbs = ClampLong(xAbs, 0, 65535); yAbs = ClampLong(yAbs, 0, 65535); while (clicks > 0) { unsigned long long batch64 = std::min(clicks, MAX_BATCH); int batch = (int)batch64; std::vector<INPUT> inputs(1 + batch * 2); inputs[0].type = INPUT_MOUSE; inputs[0].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK; inputs[0].mi.dx = xAbs; inputs[0].mi.dy = yAbs; for (int i = 0; i < batch; ++i) { inputs[1 + i * 2].type = INPUT_MOUSE; inputs[1 + i * 2].mi.dwFlags = MOUSEEVENTF_LEFTDOWN; inputs[1 + i * 2 + 1].type = INPUT_MOUSE; inputs[1 + i * 2 + 1].mi.dwFlags = MOUSEEVENTF_LEFTUP; } SendInput((UINT)inputs.size(), inputs.data(), sizeof(INPUT)); clicks -= batch64; } } LPARAM MakeMouseLParam(POINT clientPoint) { return MAKELPARAM((SHORT)clientPoint.x, (SHORT)clientPoint.y); } void PostWindowClickClient(HWND hwnd, POINT clientPoint) { if (!IsWindow(hwnd)) return; LPARAM lp = MakeMouseLParam(clientPoint); PostMessageW(hwnd, WM_MOUSEMOVE, 0, lp); PostMessageW(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, lp); PostMessageW(hwnd, WM_LBUTTONUP, 0, lp); } void PostWindowClick(HWND hwnd, POINT screenPoint) { if (!IsWindow(hwnd)) return; POINT clientPoint = screenPoint; ScreenToClient(hwnd, &clientPoint); PostWindowClickClient(hwnd, clientPoint); } bool GetSavedClientPointFor(HWND hwnd, const std::vector<SavedVirtualPoint>& savedPoints, POINT& outPoint) { for (const SavedVirtualPoint& item : savedPoints) { if (item.hwnd == hwnd && IsWindow(item.hwnd)) { outPoint = item.clientPoint; return true; } } return false; } void DoClickBurst(unsigned long long amount) { if (amount == 0) return; ClickMode mode = (ClickMode)g_mode.load(); bool virtualMode = g_useVirtualMouse.load(); POINT realPos{}; GetCursorPos(&realPos); POINT virtualPos = GetVirtualPoint(); POINT effectivePos = virtualMode ? virtualPos : realPos; if (mode == ClickMode::Screen) { if (virtualMode) SendVirtualClickBatch(effectivePos, amount); else SendGlobalClickBatch(amount); return; } std::vector<HWND> targets; std::vector<SavedVirtualPoint> savedPoints; { std::lock_guard<std::mutex> lock(g_windowsMutex); targets = g_selectedWindows; if (virtualMode) savedPoints = g_virtualClientPoints; } if (targets.empty()) return; for (unsigned long long i = 0; i < amount; ++i) { for (HWND hwnd : targets) { if (virtualMode) { POINT clientPoint{}; if (GetSavedClientPointFor(hwnd, savedPoints, clientPoint)) PostWindowClickClient(hwnd, clientPoint); else PostWindowClick(hwnd, effectivePos); } else { PostWindowClick(hwnd, realPos); } } } } void WaitBeforeNextClick(unsigned long long cps, long double accumulator, unsigned long long preferredBatch, int& idleSpins) { if (cps < 1) cps = 1; long double need = (long double)preferredBatch - accumulator; if (need < 1.0L) need = 1.0L; long double secondsToBatch = need / (long double)cps; if (secondsToBatch > 0.0025L) { Sleep(1); idleSpins = 0; } else { if (++idleSpins < 300) { YieldProcessor(); } else { Sleep(0); idleSpins = 0; } } } void ClickLoop() { SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); timeBeginPeriod(1); LARGE_INTEGER freq{}; LARGE_INTEGER last{}; LARGE_INTEGER now{}; QueryPerformanceFrequency(&freq); QueryPerformanceCounter(&last); long double accumulator = 0.0L; int idleSpins = 0; unsigned long long lastCps = g_cps.load(std::memory_order_relaxed); while (g_clicking.load(std::memory_order_relaxed)) { QueryPerformanceCounter(&now); long double elapsed = (long double)(now.QuadPart - last.QuadPart) / (long double)freq.QuadPart; last = now; // Не даём старому лагу копиться и потом выдавать лишний большой залп. if (elapsed > 0.10L) elapsed = 0.10L; unsigned long long localCps = g_cps.load(std::memory_order_relaxed); if (localCps < 1) localCps = 1; // При смене КПС сбрасываем остаток, чтобы старый темп не давал скачок. if (localCps != lastCps) { accumulator = 0.0L; lastCps = localCps; } accumulator += elapsed * (long double)localCps; // До 30к КПС делаем маленькие ровные пачки примерно на 1 мс. // Так меньше разброс: 3000 не должен превращаться в 8000 на тестерах CPS. unsigned long long preferredBatch = ClampUll(localCps / 1000ULL, 1ULL, 30ULL); if (accumulator < (long double)preferredBatch) { WaitBeforeNextClick(localCps, accumulator, preferredBatch, idleSpins); continue; } unsigned long long due = (unsigned long long)accumulator; ClickMode mode = (ClickMode)g_mode.load(std::memory_order_relaxed); unsigned long long maxBurst = 0; if (localCps <= 30000ULL) { maxBurst = ClampUll(preferredBatch * 2ULL, 1ULL, 64ULL); } else { maxBurst = (mode == ClickMode::Screen) ? 2048ULL : 512ULL; } if (due > maxBurst) due = maxBurst; accumulator -= (long double)due; // Ограничиваем догоняющий хвост, чтобы после зависания не было резкого перелёта КПС. long double maxBacklog = (long double)maxBurst * 2.0L; if (accumulator > maxBacklog) accumulator = maxBacklog; DoClickBurst(due); idleSpins = 0; } timeEndPeriod(1); } void ToggleClicking() { bool now = !g_clicking.load(); g_clicking.store(now); if (now) { if (g_useVirtualMouse.load()) SetVirtualMouseFromCursor(); std::thread(ClickLoop).detach(); SetWindowTextW(hStaticHint, L"F6: стоп"); } else { SetWindowTextW(hStaticHint, L"F6: старт / стоп"); } } // ===================================================== // Virtual mouse // ===================================================== void SetVirtualMouseFromCursor() { POINT p{}; GetCursorPos(&p); g_virtualX.store(p.x); g_virtualY.store(p.y); std::lock_guard<std::mutex> lock(g_windowsMutex); g_virtualClientPoints.clear(); for (HWND hwnd : g_selectedWindows) { if (!IsWindow(hwnd)) continue; POINT clientPoint = p; ScreenToClient(hwnd, &clientPoint); g_virtualClientPoints.push_back(SavedVirtualPoint{ hwnd, clientPoint }); } } // ===================================================== // Mode // ===================================================== void UpdateModeUi() { ClickMode mode = (ClickMode)g_mode.load(); bool windowsMode = mode == ClickMode::Windows; ShowWindow(hBtnRefresh, windowsMode ? SW_SHOW : SW_HIDE); ShowWindow(hBtnApplyWindows, windowsMode ? SW_SHOW : SW_HIDE); ShowWindow(hStaticApplied, windowsMode ? SW_SHOW : SW_HIDE); ShowWindow(hListView, windowsMode ? SW_SHOW : SW_HIDE); int cpsY = windowsMode ? CPS_Y_WINDOWS : CPS_Y_SCREEN; int virtualY = windowsMode ? VIRTUAL_Y_WINDOWS : VIRTUAL_Y_SCREEN; MoveWindow(hEditCPS, 50, cpsY, 180, 54, TRUE); MoveWindow(hBtnApplyCPS, 252, cpsY, 255, 54, TRUE); MoveWindow(hStaticCPS, 532, cpsY + 14, 280, 32, TRUE); MoveWindow(hChkVirtual, 50, virtualY, 22, 22, TRUE); MoveWindow(hLblVirtual, 80, virtualY, 260, 30, TRUE); MoveWindow(hStaticHint, 360, virtualY + 2, 500, 28, TRUE); InvalidateRect(hTabWindows, nullptr, TRUE); InvalidateRect(hTabScreen, nullptr, TRUE); InvalidateRect(g_mainHwnd, nullptr, TRUE); } // ===================================================== // Main window // ===================================================== LRESULT CALLBACK MainProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CREATE: { g_brBg = CreateSolidBrush(CLR_BG); g_brPanel = CreateSolidBrush(CLR_PANEL); g_brEdit = CreateSolidBrush(CLR_PANEL_2); g_font = CreateFontW( 21, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH, L"Segoe UI Variable Display" ); g_fontBold = CreateFontW( 21, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH, L"Segoe UI Variable Display" ); g_fontTitle = CreateFontW( 30, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH, L"Segoe UI Variable Display" ); g_fontMenu = CreateFontW( 27, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH, L"Segoe UI Variable Display" ); g_fontEdit = CreateFontW( 26, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH, L"Segoe UI Variable Display" ); hBtnMin = CreateWindowW( L"BUTTON", L"—", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, APP_W - 198, 22, 54, 38, hwnd, (HMENU)ID_BTN_MIN, GetModuleHandleW(nullptr), nullptr ); hBtnMax = CreateWindowW( L"BUTTON", L"□", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, APP_W - 134, 22, 54, 38, hwnd, (HMENU)ID_BTN_MAX, GetModuleHandleW(nullptr), nullptr ); hBtnClose = CreateWindowW( L"BUTTON", L"×", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, APP_W - 70, 22, 54, 38, hwnd, (HMENU)ID_BTN_CLOSE, GetModuleHandleW(nullptr), nullptr ); hTabWindows = CreateWindowW( L"BUTTON", L"1 Окна", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 50, 100, 280, 54, hwnd, (HMENU)ID_TAB_WINDOWS, GetModuleHandleW(nullptr), nullptr ); hTabScreen = CreateWindowW( L"BUTTON", L"2 Экран", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 350, 100, 280, 54, hwnd, (HMENU)ID_TAB_SCREEN, GetModuleHandleW(nullptr), nullptr ); hBtnRefresh = CreateWindowW( L"BUTTON", L"Обновить список", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 650, 100, 150, 54, hwnd, (HMENU)ID_BTN_REFRESH, GetModuleHandleW(nullptr), nullptr ); hBtnApplyWindows = CreateWindowW( L"BUTTON", L"Применить", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 818, 100, 142, 54, hwnd, (HMENU)ID_BTN_APPLY_WINDOWS, GetModuleHandleW(nullptr), nullptr ); hStaticApplied = CreateWindowW( L"STATIC", L"Выбрано окон: 0", WS_CHILD | WS_VISIBLE, 50, 194, 420, 28, hwnd, (HMENU)ID_STATIC_APPLIED, GetModuleHandleW(nullptr), nullptr ); hListView = CreateWindowW( WC_LISTVIEWW, nullptr, WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOCOLUMNHEADER, 52, 292, 910, 276, hwnd, (HMENU)ID_LISTVIEW, GetModuleHandleW(nullptr), nullptr ); ListView_SetExtendedListViewStyle( hListView, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES | LVS_EX_DOUBLEBUFFER ); ListView_SetBkColor(hListView, CLR_PANEL); ListView_SetTextBkColor(hListView, CLR_PANEL); ListView_SetTextColor(hListView, CLR_TEXT); hEditCPS = CreateWindowW( L"EDIT", L"42", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NUMBER, 50, CPS_Y_WINDOWS, 180, 54, hwnd, (HMENU)ID_EDIT_CPS, GetModuleHandleW(nullptr), nullptr ); hBtnApplyCPS = CreateWindowW( L"BUTTON", L"Применить КПС", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 252, CPS_Y_WINDOWS, 255, 54, hwnd, (HMENU)ID_BTN_APPLY_CPS, GetModuleHandleW(nullptr), nullptr ); hStaticCPS = CreateWindowW( L"STATIC", L"КПС: 42", WS_CHILD | WS_VISIBLE, 532, CPS_Y_WINDOWS + 14, 280, 32, hwnd, (HMENU)ID_STATIC_CPS, GetModuleHandleW(nullptr), nullptr ); hChkVirtual = CreateWindowW( L"BUTTON", L"", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 50, VIRTUAL_Y_WINDOWS, 22, 22, hwnd, (HMENU)ID_CHK_VIRTUAL, GetModuleHandleW(nullptr), nullptr ); hLblVirtual = CreateWindowW( L"STATIC", L"Виртуальная мышь", WS_CHILD | WS_VISIBLE, 80, VIRTUAL_Y_WINDOWS, 260, 30, hwnd, nullptr, GetModuleHandleW(nullptr), nullptr ); hStaticHint = CreateWindowW( L"STATIC", L"F6: старт / стоп", WS_CHILD | WS_VISIBLE, 360, VIRTUAL_Y_WINDOWS + 2, 500, 28, hwnd, nullptr, GetModuleHandleW(nullptr), nullptr ); HWND controls[] = { hBtnMin, hBtnMax, hBtnClose, hTabWindows, hTabScreen, hBtnRefresh, hBtnApplyWindows, hStaticApplied, hListView, hEditCPS, hBtnApplyCPS, hStaticCPS, hChkVirtual, hLblVirtual, hStaticHint }; for (HWND c : controls) SendMessageW(c, WM_SETFONT, (WPARAM)g_font, TRUE); SendMessageW(hTabWindows, WM_SETFONT, (WPARAM)g_fontMenu, TRUE); SendMessageW(hTabScreen, WM_SETFONT, (WPARAM)g_fontMenu, TRUE); SendMessageW(hEditCPS, WM_SETFONT, (WPARAM)g_fontEdit, TRUE); SendMessageW(hStaticApplied, WM_SETFONT, (WPARAM)g_fontBold, TRUE); SendMessageW(hStaticCPS, WM_SETFONT, (WPARAM)g_fontBold, TRUE); RefreshWindowList(); RegisterHotKey(hwnd, ID_HOTKEY_F6, 0, VK_F6); POINT center{ GetSystemMetrics(SM_XVIRTUALSCREEN) + GetSystemMetrics(SM_CXVIRTUALSCREEN) / 2, GetSystemMetrics(SM_YVIRTUALSCREEN) + GetSystemMetrics(SM_CYVIRTUALSCREEN) / 2 }; g_virtualX.store(center.x); g_virtualY.store(center.y); UpdateModeUi(); return 0; } case WM_ERASEBKGND: return 1; case WM_PAINT: { PAINTSTRUCT ps{}; HDC hdc = BeginPaint(hwnd, &ps); DrawWindowChrome(hdc); EndPaint(hwnd, &ps); return 0; } case WM_NCHITTEST: { POINT p{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; ScreenToClient(hwnd, &p); if (p.y >= 0 && p.y <= 75) { if (p.x >= APP_W - 220) return HTCLIENT; return HTCAPTION; } return HTCLIENT; } case WM_CTLCOLORSTATIC: { HDC hdc = (HDC)wParam; SetBkMode(hdc, TRANSPARENT); HWND ctl = (HWND)lParam; if (ctl == hStaticApplied || ctl == hStaticCPS) SetTextColor(hdc, CLR_TEXT); else SetTextColor(hdc, CLR_MUTED); return (LRESULT)g_brPanel; } case WM_CTLCOLORBTN: { HDC hdc = (HDC)wParam; SetBkMode(hdc, TRANSPARENT); SetTextColor(hdc, CLR_TEXT); return (LRESULT)g_brPanel; } case WM_CTLCOLOREDIT: { HDC hdc = (HDC)wParam; SetBkColor(hdc, CLR_PANEL_2); SetTextColor(hdc, CLR_TEXT); return (LRESULT)g_brEdit; } case WM_DRAWITEM: { DrawOwnerButton((DRAWITEMSTRUCT*)lParam); return TRUE; } case WM_NOTIFY: { LPNMHDR hdr = (LPNMHDR)lParam; if (hdr->idFrom == ID_LISTVIEW && hdr->code == NM_CUSTOMDRAW) { LPNMLVCUSTOMDRAW cd = (LPNMLVCUSTOMDRAW)lParam; if (cd->nmcd.dwDrawStage == CDDS_PREPAINT) { SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, CDRF_NOTIFYITEMDRAW); return TRUE; } if (cd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) { cd->clrText = CLR_TEXT; cd->clrTextBk = CLR_PANEL; SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, CDRF_DODEFAULT); return TRUE; } } return 0; } case WM_HOTKEY: { if (wParam == ID_HOTKEY_F6) ToggleClicking(); return 0; } case WM_COMMAND: { switch (LOWORD(wParam)) { case ID_BTN_REFRESH: RefreshWindowList(); break; case ID_BTN_APPLY_WINDOWS: UpdateSelectedWindows(); break; case ID_BTN_APPLY_CPS: ApplyCpsFromEdit(); break; case ID_TAB_WINDOWS: g_mode.store((int)ClickMode::Windows); UpdateModeUi(); break; case ID_TAB_SCREEN: g_mode.store((int)ClickMode::Screen); UpdateModeUi(); break; case ID_CHK_VIRTUAL: { LRESULT state = SendMessageW(hChkVirtual, BM_GETCHECK, 0, 0); bool enabled = state == BST_CHECKED; g_useVirtualMouse.store(enabled); if (enabled) SetVirtualMouseFromCursor(); break; } case ID_BTN_MIN: ShowWindow(hwnd, SW_MINIMIZE); break; case ID_BTN_MAX: if (IsZoomed(hwnd)) ShowWindow(hwnd, SW_RESTORE); else ShowWindow(hwnd, SW_MAXIMIZE); break; case ID_BTN_CLOSE: DestroyWindow(hwnd); break; } return 0; } case WM_DESTROY: { g_clicking.store(false); UnregisterHotKey(hwnd, ID_HOTKEY_F6); if (g_imgList) ImageList_Destroy(g_imgList); if (g_font) DeleteObject(g_font); if (g_fontBold) DeleteObject(g_fontBold); if (g_fontTitle) DeleteObject(g_fontTitle); if (g_fontMenu) DeleteObject(g_fontMenu); if (g_fontEdit) DeleteObject(g_fontEdit); if (g_brBg) DeleteObject(g_brBg); if (g_brPanel) DeleteObject(g_brPanel); if (g_brEdit) DeleteObject(g_brEdit); PostQuitMessage(0); return 0; } } return DefWindowProcW(hwnd, msg, wParam, lParam); } // ===================================================== // Entry point // ===================================================== int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR, int nCmdShow) { SetProcessDPIAware(); INITCOMMONCONTROLSEX icex{}; icex.dwSize = sizeof(icex); icex.dwICC = ICC_LISTVIEW_CLASSES | ICC_STANDARD_CLASSES; InitCommonControlsEx(&icex); WNDCLASSW wc{}; wc.lpfnWndProc = MainProc; wc.hInstance = hInstance; wc.lpszClassName = L"RedClicerMainWindow"; wc.hCursor = LoadCursorW(nullptr, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); if (!RegisterClassW(&wc)) { MessageBoxW(nullptr, L"Не удалось зарегистрировать класс окна.", L"Ошибка", MB_OK | MB_ICONERROR); return 0; } int x = (GetSystemMetrics(SM_CXSCREEN) - APP_W) / 2; int y = (GetSystemMetrics(SM_CYSCREEN) - APP_H) / 2; g_mainHwnd = CreateWindowExW( WS_EX_APPWINDOW, L"RedClicerMainWindow", L"RedClicer", WS_POPUP | WS_MINIMIZEBOX, x, y, APP_W, APP_H, nullptr, nullptr, hInstance, nullptr ); if (!g_mainHwnd) { MessageBoxW(nullptr, L"Не удалось создать окно.", L"Ошибка", MB_OK | MB_ICONERROR); return 0; } HRGN rgn = CreateRoundRectRgn(0, 0, APP_W + 1, APP_H + 1, 18, 18); SetWindowRgn(g_mainHwnd, rgn, TRUE); ShowWindow(g_mainHwnd, nCmdShow); UpdateWindow(g_mainHwnd); MSG msg{}; while (GetMessageW(&msg, nullptr, 0, 0)) { TranslateMessage(&msg); DispatchMessageW(&msg); } return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { return wWinMain(hInstance, hPrevInstance, GetCommandLineW(), nCmdShow); } ''' path = Path("/mnt/data/RedClicker_fixed.cpp") path.write_text(code, encoding="utf-8") print(f"Готово: {path}")

Resposta

Готовый файл: RedClicker_fixed.cpp

Что исправил:

  • В режиме “Экран” убрал обрезанный текст “Настройки кликов”.
  • Выровнял блок КПС и виртуальной мыши.
  • Виртуальная мышь теперь сохраняет последнюю позицию курсора при включении или при старте через F6.
  • Для режима “Окна” сохраняется позиция внутри выбранного окна, поэтому клик идёт в ту же точку даже если выбранное окно свернули или сдвинули.
  • Добавил нормальную поддержку координат для нескольких мониторов через SM_XVIRTUALSCREEN.

Компиляция:

bash
g++ -std=c++17 RedClicker_fixed.cpp -O2 -municode -mwindows -finput-charset=UTF-8 -fexec-charset=UTF-8 -lcomctl32 -lgdi32 -luser32 -lshell32 -lwinmm -o RedClicker.exe

Если целевое окно запущено от администратора, то и кликер лучше запускать от администратора, иначе Windows может блокировать отправку кликов.

Compartilhar esta Q&A