Этот фрагмент кода всегда делает что-то неожиданное

Я хотел использовать снайперскую винтовку в качестве винтовки, когда играл в PUBG, поэтому я написал кликер мыши, который в большинстве случаев работает очень хорошо, но в некоторых случаях, когда я отпускаю мышь, он все еще продолжает непрерывно стрелять. Я подозреваю, что это происходит потому, что я отпускаю левую кнопку мыши после того, как код определяет, что мышь нажата, но код еще не выполнил смоделированный щелчок, что приведет к тому, что операционная система получит аппаратное сообщение об освобождении мыши, но программное обеспечение отправляет еще одну левую кнопку мыши. Сообщение о том, что кнопка нажата, заставляет левую кнопку мыши оставаться нажатой.

Я пытался использовать потоки или мьютексы, чтобы убедиться, что следующее событие будет выполнено после завершения выполнения, но это не имеет никакого эффекта. Поэтому я подозреваю, что это вызвано задержкой выполнения процессора. Как решить эту проблему.

Ниже приведена часть оценки цикла таймера в коде.

static void click() {

        if (KEY_DOWN(VK_LBUTTON)) {
            POINT point;
            GetCursorPos(&point);
            if (KEY_DOWN(VK_LBUTTON)) {
                mouse_event(MOUSEEVENTF_LEFTDOWN, point.x, point.y, 0, 0);
            }
        };
    }

Все коды ниже.


#include <windows.h>
#include<vector>
#include<string>
#include<uxtheme.h>
#pragma comment(lib,"UxTheme.lib")
using namespace std;
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
#pragma region Help
#define WM_MONITOR 0x8075u
#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0) 
INT toint(std::wstring  str) {
    INT nRet = 0;
    if (!str.empty())
    {
        nRet = _wtoi(str.c_str());
    }
    else
        nRet = 0;
    return nRet;
}
std::wstring GetText(HWND m_hWnd)
{
    if (!m_hWnd)
    {
        return std::wstring();
    }
    int length = GetWindowTextLengthW(m_hWnd);
    std::vector<wchar_t> buffer(length + 1);
    GetWindowTextW(m_hWnd, buffer.data(), buffer.size());
    return std::wstring(buffer.data());
}

#pragma endregion

#pragma region Helpclass
class Clock
{
public:
    //-回调函数 返回值:无 (整数型 hWnd,整数型 msg,整数型 时钟ID,整数型 系统启动时间)
    //-void (HWND hWnd,UINT msg,UINT_PTR 时钟ID,UINT_PTR 系统启动时间)
    bool Create(HWND hWnd, UINT time, void* callback)
    {
        m_hWnd = hWnd;
        m_hClock = (UINT_PTR)this;
        m_Callback = callback;
        m_Time = time;
        if (time == 0)
        {
            return true;
        }
        m_hClock = SetTimer(hWnd, m_hClock, time, (TIMERPROC)m_Callback);;

        return m_hClock == 0;
    };
    bool Time(UINT time) {

        if (time != m_Time)
        {
            if (m_Time == 0) {
                m_hClock = SetTimer(m_hWnd, m_hClock, time, (TIMERPROC)m_Callback);
                if (m_hClock) {

                    m_Time = time;
                    return true;
                };
            }
            if (time == 0)
            {
                m_Time = time;
                return KillTimer(m_hWnd, m_hClock);
            }
            if (KillTimer(m_hWnd, m_hClock)) {
                m_hClock = SetTimer(m_hWnd, m_hClock, time, (TIMERPROC)m_Callback);
                if (m_hClock) {

                    m_Time = time;
                    return true;
                };
            };
        }
        return false;
    };
    UINT Time() {
        return m_Time;
    };
    bool Destory() {
        return KillTimer(m_hWnd, m_hClock);
    };
    Clock() {
        m_hWnd = 0;
        m_hClock = (UINT_PTR)this;
        m_Callback = 0;
        m_Time = 0;
    };
    ~Clock() {
        if (m_hClock)
        {
            KillTimer(m_hWnd, m_hClock);
            m_Callback = nullptr;
            m_hClock = 0;
            m_hWnd = 0;
            m_Time = 0;
        }

    };
private:
    UINT_PTR m_hClock;
    HWND m_hWnd;
    void* m_Callback;
    UINT m_Time;
};

class MyRegisterHotKey
{
public:
    int  Register(HWND hWnd, HWND labelhwnd, UINT fsModifiers, UINT vk)
    {
        // 将 fsModifiers 转换为 RegisterHotKey 函数所需的值
        label_hwnd = labelhwnd;
        switch (fsModifiers)
        {
        case 1: // Alt
            fsModifiers = MOD_ALT;
            break;
        case 2: // Ctrl
            fsModifiers = MOD_CONTROL;
            break;
        case 4: // Shift
            fsModifiers = MOD_SHIFT;
            break;
        case 3: // Alt + Ctrl
            fsModifiers = MOD_ALT | MOD_CONTROL;
            break;
        case 5: // Alt + Shift
            fsModifiers = MOD_ALT | MOD_SHIFT;
            break;
        case 6: // Ctrl + Shift
            fsModifiers = MOD_CONTROL | MOD_SHIFT;
            break;
        }

        // 如果窗口还没有设置窗口过程,就将窗口过程设置为 shellEx__RegWindowProc
        if (!old_proc)
            old_proc = (WNDPROC)SetWindowLongPtrA(hWnd, GWLP_WNDPROC, (LONG_PTR)RegWindowProc);//获取缺省回调,不太安全是否有方法修改

        SetWindowLongPtrA(hWnd, GWLP_USERDATA, (LONG_PTR)this);
        IDarry = ++regcount + 33000;//本次标识
        if (RegisterHotKey(hWnd, regcount + 33000, fsModifiers, vk))
            return IDarry;
        else
            return 0;
    }

private:
    static LRESULT WINAPI RegWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        MyRegisterHotKey* r = (MyRegisterHotKey*)GetWindowLongPtrA(hWnd, GWLP_USERDATA);
        // 当接收到消息类型为 WM_HOTKEY 时,执行循环遍历
        if (uMsg == WM_HOTKEY)
        {

            for (int i = 33000; i <= r->IDarry; i++)//易里标识里从33000开始,不知道为什么怕冲突??
            {
                // 检查 传入参数 是否与 值 相等
                if (i == wParam)//ID值
                {
                    // 如果相等,则发送消息类型为 WM_COMMAND 的消息给 label_hwnd
                    SendMessageA(r->label_hwnd, WM_MONITOR, wParam, 0);
                }
            }
        }
        // 调用原来的窗口过程函数
        return CallWindowProcA(r->old_proc, hWnd, uMsg, wParam, lParam);
    }
    int regcount = 0;
    int IDarry = 0;
    HWND label_hwnd = 0;
    WNDPROC old_proc = 0;

};


#pragma endregion

static int F11 = 0;
static int F10 = 0;
static bool IsF10 = false;
static Clock Click;
static HWND hStatic;
static HWND hEditBox;
static WNDPROC StaticOldProc = NULL;












class ClickWindow
{
    static void StarContinuousClick() {
        if (!IsF10)
        {
            IsF10 = true;
            ::MessageBeep(MB_OK);
            int t = 0;
            if (!GetText(hEditBox).empty())
            {
                t = toint(GetText(hEditBox));
            }
            //开始连点就不允许编辑
            EnableWindow(hEditBox, FALSE);
            Click.Time(t);
        }
    };
    static void EndContinuousClick() {

        if (IsF10)
        {
            IsF10 = false;
            ::MessageBeep(0xFFFFFFFF);
            EnableWindow(hEditBox, TRUE);
            Click.Time(0);
        }

    };

    static LRESULT CALLBACK StaticWNDPROC(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
    {
        if (StaticOldProc == NULL)
        {
            StaticOldProc = DefWindowProc;
        }
        PAINTSTRUCT ps;
        HDC hdcWnd;
        HDC hdcStatic;
        static HBRUSH hBrush; //画刷
        hBrush = CreateSolidBrush(RGB(0x41, 0x96, 0x4F));
        switch (Message) {
        case  WM_MONITOR:
            if (wParam == F10)
            {
                StarContinuousClick();
            }
            else if (wParam == F11)
            {
                EndContinuousClick();
            }
            break;
        default:
            break;
        }

        return StaticOldProc(hwnd, Message, wParam, lParam);
    }

    static void click() {

        if (KEY_DOWN(VK_LBUTTON)) {
            POINT point;
            GetCursorPos(&point);
            if (KEY_DOWN(VK_LBUTTON)) {
                mouse_event(MOUSEEVENTF_LEFTDOWN, point.x, point.y, 0, 0);
            }
        };
    }
    static LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
    {
        static HBRUSH hBrush; //画刷

        switch (Message)
        {
        case WM_CREATE: {

            //创建画刷
            hBrush = CreateSolidBrush(RGB(255, 255, 255)); //白色
            //创建控件
            hEditBox = CreateWindow(L"Edit",
                L"80",
                WS_CHILD | WS_VISIBLE | ES_LEFT | WS_BORDER | ES_LEFT | ES_MULTILINE | ES_AUTOHSCROLL,
                125,
                11,
                96,
                24,
                hwnd,
                0,
                GetModuleHandleW(0),
                NULL);
            LONG_PTR exStyle = GetWindowLongPtr(hEditBox, GWL_EXSTYLE);
            HWND temp = CreateWindow(L"Static",
                L"请输入频率",
                WS_CHILD | WS_VISIBLE | ES_LEFT | BS_MULTILINE,
                40,
                13,
                72,
                24,
                hwnd,
                0,
                GetModuleHandleW(0),
                NULL);
            hStatic = CreateWindow(L"Static",
                L"F10:开启   F11:关闭",
                WS_CHILD | WS_VISIBLE | ES_LEFT | BS_MULTILINE,
                60,
                52,
                136,
                24,
                hwnd,
                0,
                GetModuleHandleW(0),
                NULL);
            SetBkMode(GetDC(hStatic), TRANSPARENT);
            LOGFONTW m_Font = { 0 };
            wchar_t FontName[LF_FACESIZE] = L"Times New Roman";
            wcscpy_s(m_Font.lfFaceName, FontName);
            m_Font.lfHeight = 16;
            SendMessageW(hStatic, WM_SETFONT, (WPARAM)CreateFontIndirectW(&m_Font), 1);
            SendMessageW(hEditBox, WM_SETFONT, (WPARAM)CreateFontIndirectW(&m_Font), 1);
            SendMessageW(temp, WM_SETFONT, (WPARAM)CreateFontIndirectW(&m_Font), 1);
            StaticOldProc = (WNDPROC)SetWindowLongPtrW(hStatic, GWLP_WNDPROC, (LONG_PTR)StaticWNDPROC);
            Click.Create(hwnd, 0, click);
            //win98风格
            SetWindowTheme(hwnd, L"", L"");
            break;
        }
        case WM_CTLCOLORSTATIC:
        {
            //可以通过子类化窗口回调加上获取HDC需要绘制的rect,来改变指定控件
            HDC hdc = (HDC)wParam;
            SetTextColor(hdc, 255);
            SetBkColor(hdc, RGB(255, 255, 255));
            return (LRESULT)hBrush;
        }
        case WM_DESTROY:
        {
            PostQuitMessage(0);
            break;
        }
        default:
            return DefWindowProc(hwnd, Message, wParam, lParam);
        }
        return 0;
    }
public:
    ClickWindow(HMODULE hInstance) :hwnd(NULL), msg{ 0 }{

        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(WNDCLASSEX);
        wc.lpfnWndProc = WndProc;
        wc.hInstance = hInstance;
        wc.lpszClassName = L"ALWindowClass";
        if (!RegisterClassEx(&wc)) {
            exit(0);
            return;
        }
        hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,
            L"ALWindowClass",
            L"阿龙吃鸡连点器:",
            WS_VISIBLE | WS_CAPTION | WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT,
            280,
            119,
            NULL,
            NULL,
            hInstance,
            NULL);
        //置WIN98风格


        F11 = r.Register(hwnd, hStatic, 0, 122);
        F10 = r.Register(hwnd, hStatic, 0, 121);

    };
    WPARAM ShowAndLoop() {
        while (GetMessage(&msg, NULL, 0, 0) > 0) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return msg.wParam;

    }
    ~ClickWindow() {
        DestroyWindow(hwnd);
        exit(0);
    };

private:
    HWND hwnd;
    MSG msg;
    MyRegisterHotKey r;
};

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR    lpCmdLine,
    _In_ int       nCmdShow)

{
    ClickWindow MainWindow(hInstance);

    MainWindow.ShowAndLoop();
}

Никогда не давайте весь код. Укажите абсолютный минимум, необходимый для воспроизведения ошибки. Это код события win32, так что будет много шаблонов, но 400 строк — это немного круто. Мало кто захочет пройти через это бесплатно.

user4581301 05.01.2023 02:00

Я предполагаю, что программа стреляет себе в лицо с приведением m_hClock = SetTimer(hWnd, m_hClock, time, (TIMERPROC)m_Callback);; Многолетний опыт научил меня, что если вам нужно привести указатель на функцию, вы уже проиграли. Более глубокое чтение доказывает, что я ошибаюсь, но вы должны поддерживать правильный тип на протяжении всей системы. Приведение к void*, а затем обратно лишает компилятор способности предотвращать МНОЖЕСТВО ошибок.

user4581301 05.01.2023 02:03

Неа. Я был прав в первый раз. void click() не совпадает void (*)(HWND__*, unsigned int, long long unsigned int, long unsigned int) Взял компилятор, чтобы увидеть.

user4581301 05.01.2023 02:12

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

Community 05.01.2023 02:18

@user4581301 user4581301 Это правильно только для 64-битной версии, я поставил правильную подпись в своем ответе ...

Anders 05.01.2023 02:18

@Андерс меня не удивляет. Хуже того, я возился с gcc, когда я должен был просто сделать это в начале и избавил себя от второго предположения

user4581301 05.01.2023 02:20
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
68
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Установите крючок WH_MOUSE_LL. Когда кнопка мыши будет отпущена, отправьте сообщение окну, чтобы остановить его или установить глобальную переменную.

Как отмечено в комментариях, сигнатура функции click неверна для обратного вызова таймера. Снимите гипс и исправьте click() и свой класс.

void CALLBACK click(HWND, UINT, UINT_PTR, DWORD) { ... }

Другие вопросы по теме