微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

SendInput() 与 GetAsyncKeyState() (WinAPI) 一起使用时会导致无限循环

如何解决SendInput() 与 GetAsyncKeyState() (WinAPI) 一起使用时会导致无限循环

所以我想让当您按住左键单击时,鼠标开始定期单击。

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

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

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,sizeof(input));
}

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

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

最小可重复示例:

ma​​in.cpp

#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",16,{"SAP (P2000)",150,10,{"Python",6,{"Thompson",130,20,false},{"Custom SMG",100,24,{"AK",133,30,{"MP5",{"LR300",120,{"M92",15,{"M249",{"M39",200,};
#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,(int)weapon_selector->repeatDelay);
                }
                Utilities::SleepThread(200);
            }
        }

        Utilities::SleepThread(1);
    }
}

鼠标::点击()函数

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,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,sizeof(input));

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

Utilities::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. weapon_selector->recoilTable 已初始化,它不是空的!看看populate_recoil_table()函数
  3. 代码使用 C++17(MSVC 编译器/Visual Studio 2019)编译

编辑:我解决了我的问题

我不得不先“松开”我的按钮,然后再次发送 DOWN 消息,我知道为什么我没有早点想到它,唯一的缺点是功能结束前的最后一条消息是 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,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,sizeof(input));
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。