1

所以我想让当你按住左键时,鼠标开始每隔一段时间点击一次。

从理论上讲,一切都应该正常工作,但在实践中,并不是那么好。

无论如何,这里是我用于检测和点击鼠标的代码:

while (1)
{
    if (GetAsyncKeyState(VK_LBUTTON) && GetAsyncKeyState(VK_RBUTTON))
    {
        if (weapon_selector == nullptr) continue;

        if (weapon_selector->isSemiAutomatic)
        {
            for (Vector2I x : weapon_selector->recoilTable)
            {
                // Detect for hardware click instead
                if (!(GetAsyncKeyState(VK_LBUTTON) & 0x8000) || !GetAsyncKeyState(VK_RBUTTON)) // This right here should detect if you are not holding either of the left or right mouse buttons, and thus abort the movement/clicks of the mouse
                {
                    Utilities::SleepThread(200);
                    break;
                }

                Mouse::Click(); // Look in the code below how this is defined
                Mouse::MoveRelative_Lerp(x.x, x.y, (int)weapon_selector->repeatDelay); // This is essentially doing this_thread::sleep_for() for around 150 ms every time after the click has happened, which would give plenty of time for the GetAsyncKeyState() function to "update" or whatever if it needed it. This function only moves the mouse, it does not click anywhere!
            }
            Utilities::SleepThread(200);
        }
        else
        {
            ...
        }
    }

    Utilities::SleepThread(1);
}

这是我对 Mouse::Click() 函数的实现:

void Mouse::Click()
{
    INPUT input;
    input.type = INPUT_MOUSE;
    input.mi.mouseData = NULL;
    input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
    input.mi.time = 0;
    input.mi.dwExtraInfo = NULL;

    SendInput(1, &input, sizeof(input));

    input.mi.dwFlags = MOUSEEVENTF_LEFTUP;

    SendInput(1, &input, sizeof(input));
}

我尝试了几乎所有我能想到的方法来解决这个问题,但没有成功,比如鼠标低级挂钩,还检查低级鼠标挂钩中的注入标志,使用RegisterRawInputDevices()检测硬件鼠标点击(也没有成功),设置 virtualClick变量和各种不同的检查,没有运气..我厌倦了过去两天尝试这样做

如果有人以前处理过这个问题并且可以帮助我,我将不胜感激。

最小的可重现示例:

主文件

#include <Windows.h>
#include <hidusage.h>

#include <iostream>
#include <cmath>
#include <string>
#include <thread>
#include <atomic>
#include <vector>
#include <fstream>

#include "Mouse.hpp"
#include "Utils.hpp"
#include "Vector2_int.hpp"

struct WeaponData
{
    const char* szName;
    std::vector<Vector2I> recoilTable;
    int repeatDelay;
    int magCapacity;
    bool isSemiAutomatic;
};

#pragma region Recoil Tables
WeaponData RecoilTables[] = {
    {"Revolver", {}, 175, 8, true},
    {"SAR", {}, 175, 16, true},
    {"SAP (P2000)", {}, 150, 10, true},
    {"Python", {}, 150, 6, true},
    {"Thompson", {}, 130, 20, false},
    {"Custom SMG", {}, 100, 24, false},
    {"AK", {}, 133, 30, false},
    {"MP5", {}, 100, 30, false},
    {"LR300", {}, 120, 30, false},
    {"M92", {}, 150, 15, true},
    {"M249", {}, 120, 100, false},
    {"M39", {}, 200, 20, true},
};
#pragma endregion

void populate_recoil_table(WeaponData* data)
{
    if (data->recoilTable.size() > 0) return;

    for (int i = 0; i < data->magCapacity; i++)
    {
        data->recoilTable.push_back({0, 0});
    }
}

int main()
{
    WeaponData* weapon_selector = &RecoilTables[0];

    populate_recoil_table(weapon_selector);

    // just to see the movement of the mouse
    weapon_selector->recoilTable.at(0).x = 20;
    weapon_selector->recoilTable.at(0).y = 20;

    while (1)
    {
        if (GetAsyncKeyState(VK_LBUTTON) && GetAsyncKeyState(VK_RBUTTON))
        {
            if (weapon_selector == nullptr) continue;

            if (weapon_selector->isSemiAutomatic)
            {
                for (Vector2I x : weapon_selector->recoilTable)
                {
                    if (!(GetAsyncKeyState(VK_LBUTTON) & 0x8000) || !(GetAsyncKeyState(VK_RBUTTON) & 0x8000))
                    {
                        puts("stopped bcs no buttons hold");
                        Utilities::SleepThread(200);
                        break;
                    }

                    puts("clicking");
                    Mouse::Click();
                    Utilities::SleepThread(weapon_selector->repeatDelay);
                }
                Utilities::SleepThread(200);
            }
            else
            {
                for (Vector2I x : weapon_selector->recoilTable)
                {
                    if (!GetAsyncKeyState(VK_LBUTTON) || !GetAsyncKeyState(VK_RBUTTON)) { Utilities::SleepThread(200); break; }

                    Mouse::MoveRelative_Lerp(x.x, x.y, (int)weapon_selector->repeatDelay);
                }
                Utilities::SleepThread(200);
            }
        }

        Utilities::SleepThread(1);
    }
}

鼠标::Click() 函数

void Mouse::Click()
{
    INPUT input;
    input.type = INPUT_MOUSE;
    input.mi.mouseData = NULL;
    input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
    input.mi.dx = 0;
    input.mi.dy = 0;
    input.mi.time = 0;
    input.mi.dwExtraInfo = NULL;
    SendInput(1, &input, sizeof(input)); // First send UP event to "unclick" our mouse button

    input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN; // Then send DOWN event to click and hold the button
    SendInput(1, &input, sizeof(input));

    input.mi.dwFlags = MOUSEEVENTF_LEFTUP; // Then send UP again to release it to simulate a click
    SendInput(1, &input, sizeof(input));
}

实用程序::SleepThread() 函数

void SleepThread(uint32_t milliseconds)
    {
        std::chrono::high_resolution_clock::time_point target = std::chrono::high_resolution_clock::now() + std::chrono::milliseconds(milliseconds);

        while (std::chrono::high_resolution_clock::now() < target)
        {
            std::this_thread::yield();
        }
    }

示例需要注意的事项:

  1. Vector2I 本质上是具有 2 个整数的结构:x 和 y,具有一些添加、减去等功能。
  2. 武器选择器->recoilTable 已初始化,它不是空的!查看populate_recoil_table()函数
  3. 代码使用C++17编译(MSVC编译器/Visual Studio 2019)

编辑:我解决了我的问题

我必须先“松开”我的按钮然后再次发送 DOWN 消息,idk 为什么我没有早点想到它,唯一的缺点是函数结束前的最后一条消息是 DOWN,所以鼠标有点“卡住” (无法注意到)但如果您的物理按钮未按下,它会立即更新。

固定点击功能:

void Mouse::Click()
{
    INPUT input;
    input.type = INPUT_MOUSE;
    input.mi.mouseData = NULL;
    input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
    input.mi.dx = 0;
    input.mi.dy = 0;
    input.mi.time = 0;
    input.mi.dwExtraInfo = NULL;
    SendInput(1, &input, sizeof(input));

    Utilities::SleepThread(10); // The application im targeting doesnt get the update if its instant mouse press, thus waiting a little

    input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
    SendInput(1, &input, sizeof(input));
}
4

0 回答 0