【问题标题】:Using SendInput or mouse_event doesn't work with clock()?使用 SendInput 或 mouse_event 不适用于 clock()?
【发布时间】:2020-10-27 23:10:45
【问题描述】:
void leftClick(){
    INPUT input[2];

    input[0].type = INPUT_MOUSE;
    input[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
    input[1].type = INPUT_MOUSE;
    input[1].mi.dwFlags = MOUSEEVENTF_LEFTUP;

    SendInput(2, input, sizeof(INPUT));
    cout<<"click down\n";
    cout<<"click up\n\n";

/*
    mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);
    mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0);
*/
}

ReadProcessMemory(process, (void*)address, &value, sizeof(value), 0);
if (value == 1){
    if (clock() - click_time >= 500){
        cout<<"click time = "<< click_time <<endl;
        cout<<clock() - click_time <<endl;

        leftClick();

        click_time = clock();
    }
}

这给出了一个输出

click time = 0
57209
click down
click up

click time = 57222
501
click down
click up

click time = 57738
500
click down
click up

如您所见,点击应该会发生,但这不会发送任何点击。只有当我拿出所有时钟的东西时,它才会真正发出咔嗒声。如果我使用 mouse_event 而不是 SendInput,也会发生同样的事情。

编辑:我在那里更改了 SendInput,没有改变任何行为。注释的 mouse_events 也给出了相同的行为

编辑:似乎我无法制作一个最小的可重现示例。如果没有 ReadProcessMemory,它会延迟正常工作,它只是在读取进程时不会延迟发送点击。研究将 ReadProcessMemory 与任何类型的延迟输入相结合的问题。

【问题讨论】:

  • cInputs=1 调用SendInput() (几乎)总是一个错误。使用INPUT[] 数组在一次调用中发送多个输入。另外,it takes time for simulated input to be processed。你怎么知道这没有发送任何点击?当点击发生时,您期望什么结果?看起来您希望另一个流程中的变量发生变化,您怎么知道您正在观察正确的变量,或者另一个流程并非旨在忽略模拟输入?你为什么首先使用模拟点击?
  • 是的,它正在读取一个布尔值,并且只有在该值为 1 时才会点击。我知道它有效,因为没有时钟的东西,它点击得太快了。我正在尝试使用时钟()每 500 毫秒仅发送 1 次点击
  • 你没有回答我所有的问题。你说代码没有发送任何点击。你怎么知道?根据您的控制台输出,它实际上是在发送点击。那么你怎么知道目标进程不是简单地忽略你的点击呢?或者您实际上是在单击正确的屏幕坐标(因为您没有移动鼠标)?你在这里的实际目标是什么?还有其他触发 UI 点击的方法(UI 自动化。窗口消息),您尝试过吗?
  • 什么会让它忽略点击?如果值为 1,则它位于正确的坐标处。目标是当值为 1 时左键单击,这有效;每 500 毫秒,这是行不通的。如果您取出时钟的东西并且只在 if(value==1) 中单击 leftClick,它会使用 SendInput 或 mouse_events 进行单击。如果它点击,那是很明显的。在您看来,读取进程内存以获取值并在两次单击之间延迟 500 毫秒发送左键单击的最佳方法是什么?就像我说的,没有时钟也能正常工作。
  • "什么会让它忽略点击?" - 如果它专门设计来忽略虚假用户输入,这可以通过以下方式轻松完成WH_MOUSE_LL 钩子在输入事件上寻找 LLMHF_INJECTED/LLMHF_LOWER_IL_INJECTED 标志。 “就像我说的,没有时钟也可以正常工作” - 那么问题必须出在您自己的代码中,而不是点击本身,除非目标应用程序是专门设计的 i> 忽略延迟后收到的点击。

标签: c++ mouseevent clock sendinput


【解决方案1】:

目标进程/窗口可以检测到 SendInput 并使用 LLMHF_INJECTED 标志阻止它。

如果它没有阻塞输入,你应该用 MOUSEEVENTF_LEFTDOWN 一次 SendInput(),然后在延迟之后,你应该用 MOUSEEVENTF_LEFTUP 再次调用它。您不知道目标进程如何处理输入,添加延迟在几种情况下对我很有帮助。

这是一个使用 std::chrono 的示例,用于 1 个延迟计时器,我在 DOWN 和 UP 之间使用了睡眠,以努力避免使解决方案过于复杂,而不是简单的示例。

#include <chrono>
#include <thread>

int main()
{
    INPUT input{ 0 };
    input.type = INPUT_MOUSE;

    bool bClick = false;

    using Clock = std::chrono::steady_clock;
    std::chrono::time_point<std::chrono::steady_clock> start, now;
    std::chrono::milliseconds duration;

    start = Clock::now();

    while (true)
    {
        //toggles it on and off with one key
        if (GetAsyncKeyState('U') & 1)
            bClick = !bClick;

        if (bClick)
        {
            now = Clock::now();
            duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - start);

            if (duration.count() >= 100)
            {
                input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
                SendInput(1, &input, sizeof(INPUT));

                std::this_thread::sleep_for(std::chrono::milliseconds(30));

                input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
                SendInput(1, &input, sizeof(INPUT));
                start = std::chrono::steady_clock::now();
            }
        }
    }
    return 0;
}

您可以使用 U 键打开和关闭它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-15
    • 1970-01-01
    • 2018-08-17
    • 1970-01-01
    • 2018-01-29
    相关资源
    最近更新 更多