【问题标题】:simulating "!" with keybd_event (or anything) in c ++ (windows.h)模拟“!”在 c ++ (windows.h) 中使用 keybd_event (或任何东西)
【发布时间】:2022-01-19 00:21:33
【问题描述】:

!在Win32的虚拟键码中不存在。有没有办法可以使用keybd_event() 或其他任何东西来模拟导致! 的键盘输入?

这是我第一次在 Discord 赌场(私人)制作垃圾邮件机器人。

【问题讨论】:

  • 好吧,qwerty 键盘上没有! 键。要输入!,您需要两个键,shift + 1
  • 查看我的previous answer 以使用 C++ 发送带有SendInput()keybd_event() 的继任者)的 Unicode 字符串。
  • @RemyLebeau 直到现在我才注意到你也有一个C++ answer :-) Light Blur:介意我们将其作为副本关闭吗?

标签: c++ winapi visual-c++ bots


【解决方案1】:

由于keybd_event() 已被SendInput() 取代,我建议您改用它。

使用SendInput(),您可以发送多个INPUT 结构。您可以发送鼠标输入、键盘输入和硬件输入。我将展示如何发送键盘输入。

可以使用扫描码或 Unicode 字符发送键盘输入。我将使用 Unicode。为你不知道的东西找到 Unicode 字符通常很简单:https://www.google.com/search?q=unicode+exclamation+mark,你会得到答案,比如 U+0021 代表 !,它可以在 C++ 的 Unicode 字符串中编码为 \u0021 .

我将从继承INPUT 结构开始,以使其更易于实例化:

#include <Windows.h>

#include <iostream>
#include <stdexcept>
#include <vector>

struct mINPUT : INPUT {
    mINPUT() : INPUT{} {}    // make sure it's clean if default constructed.

    // this constructor prepares the structure for different kinds of input:
    mINPUT(DWORD type) : INPUT{type} {
        switch (type) {
        case INPUT_MOUSE:
            // use mi.
            break;
        case INPUT_KEYBOARD:
            // use ki.
            ki.dwFlags = KEYEVENTF_UNICODE;  // we'll use unicode
            break;
        case INPUT_HARDWARE:
            // use hi.
            break;
        }
    }
};
// helper functions to create `mINPUT` structures from Unicode values:
mINPUT key_down(char16_t unicode_char) {
    mINPUT rv{INPUT_KEYBOARD};
    rv.ki.wScan = unicode_char;
    return rv;
}

mINPUT key_up(char16_t unicode_char) {
    mINPUT rv{INPUT_KEYBOARD};
    rv.ki.dwFlags |= KEYEVENTF_KEYUP;
    rv.ki.wScan = unicode_char;
    return rv;
}
// Helper functions to check UTF16 surrogate ranges
bool is_surrogate(char16_t code_unit) {
    return code_unit >= 0xD800 && code_unit <= 0xDFFF;
}

bool is_high_surrogate(char16_t code_unit) {
    return code_unit >= 0xD800 && code_unit <= 0xDBFF;
}

bool is_low_surrogate(char16_t code_unit) {
    return code_unit >= 0xDC00 && code_unit <= 0xDFFF;
}
// A helper structure to prepare a sequence of events
struct Inputs {
    UINT cInputs() const { return static_cast<UINT>(inputs.size()); }
    LPINPUT pInputs() { return inputs.data(); }
    int cbSize() const { return static_cast<int>(sizeof(INPUT)); }

    // A helper function to add down+up events for a string:
    void add_string(const char16_t* str) {
        while (*str) {
            char16_t ch = *str++;

            if (is_surrogate(ch)) {
                char16_t first = ch;
                char16_t second = *str++;
                if (!is_high_surrogate(first) || !is_low_surrogate(second))
                    throw std::runtime_error("Broken UTF16 surrogate pair");
                inputs.push_back(key_down(first));
                inputs.push_back(key_down(second));
                inputs.push_back(key_up(first));
                inputs.push_back(key_up(second));
            } else {
                inputs.push_back(key_down(ch));
                inputs.push_back(key_up(ch));
            }
        }
    }
 
    UINT Send() {            // Send the stored events
        return SendInput(cInputs(), pInputs(), cbSize());
    }

    std::vector<mINPUT> inputs;
};
int main() {
    std::cout << "Switch to Notepad or some other app taking input" << std::endl;
    Sleep(5000);  // in 5 seconds, you should see the input

    Inputs x; // Create an event container

    // Add events for a full string including exclamation marks in two
    // different formats:
    x.add_string(u"Hello world!!! or \u0021\u0021\u0021 ");
    x.add_string(u"This is something with surrogate pairs: ? ?");

    // Send the events:
    UINT rv = x.Send();
    
    std::cout << "Sent " << rv << " events\n";
}

如果一切按计划进行,它将发送134 事件,并且您应该会看到感叹号和其他字符出现在您激活的任何应用程序中,如果它能够接收键盘输入并显示结果,例如记事本或可视化Studio - 所以要小心放置光标的位置。

【讨论】:

  • 请注意,您的代码未正确处理 UTF-16 代理项。有关该问题,请参阅我的 previous answer
  • @RemyLebeau 谢谢,看起来不错!奇怪的是 MS 没有记录这一点。下班后我会更仔细地阅读你的答案。 :)
  • @RemyLebeau 再次感谢您引起我的注意。我也更新了它以照顾代理人。
  • 检测到第一个代理后,if (*str == u'\0') 没有正确检测到无效的第二个代理。我会建议更像这样的东西:if (first &gt;= 0xDC00 || *str &lt; 0xDC00 || *str &gt; 0xDFFF) throw ...;
  • @RemyLebeau 啊,是的,谢谢。我添加了适当的代理检查。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-01
  • 2012-06-14
  • 1970-01-01
  • 2013-02-14
  • 1970-01-01
  • 2011-11-05
  • 2012-11-29
相关资源
最近更新 更多