使用 SendInput 发送两个或更多字符

2021-12-17 00:00:00 winapi c++

要发送字符,我们可以使用 SendInput.如何使用它发送多个字符?

To send a char, we can use SendInput. How can I use it to send more than one char?

我试过这个代码,但它没有发送任何东西:

I tried this code but it does not send anything:

INPUT in;
in.type=INPUT_KEYBOARD;
in.ki.wScan=0;
in.ki.time=0;
in.ki.dwExtraInfo=0;
in.ki.wVk=0x53+0x54;

SendInput(2,&in,sizeof(INPUT));

那么,正确的方法是什么?

So, what is the right way?

推荐答案

SendInput() 的第一个参数指定你传入的 INPUT 结构的数量.你是仅传入 1,但您告诉 SendInput() 您正在传入 2.

The first parameter of SendInput() specifies how many INPUT structures you are passing in. You are only passing in 1, but you are telling SendInput() that you are passing in 2.

您不能在单个 INPUT 中指定两个单独的虚拟键.您需要声明一个由多个 INPUT 组成的数组,每个虚拟键有 2 个 INPUT - 一个用于 keydown 事件,一个用于 keyup 事件.因此,在您的示例中,您实际上需要 4 个 INPUT 来发送 2 个虚拟键,如@user4581301 的回答所示.

You cannot specify two separate virtual keys in a single INPUT. You need to declare an array of multiple INPUTs, 2 INPUTs for each virtual key - one for the keydown event, and one for the keyup event. So, in your example, you actually need 4 INPUTs to send 2 virtual keys, as shown in @user4581301's answer.

现在,关于 KEYEVENTF_UNICODE,你不使用虚拟键,而是使用实际的 Unicode 代码点,它们使用 UTF-16 代码单元指定,每个 INPUT.所以这意味着如果你想发送一个需要 UTF-16 代理对的 Unicode 代码点,你需要 2 组向下/向上 INPUT,一组用于高代理,一组用于低代理.该警告在 SendInput() 文档中未提及,但实际上 vScan 字段是 16 位 WORD,并且 KEYEVENTF_UNICODE 事件生成 WM_CHAR 消息,该消息将 UTF-16 代理代码单元作为单独的消息传递.

Now, regarding KEYEVENTF_UNICODE, you don't use virtual keys with it, you use actual Unicode codepoints instead, where they are specified using UTF-16 codeunits, one per INPUT. So that means if you want to send a Unicode codepoint that requires a UTF-16 surrogate pair, you need 2 sets of down/up INPUTs, one set for the high surrogate, and one set for the low surrogate. That caveat is NOT mentioned in the SendInput() documentation, but it is implied by the fact that the vScan field is a 16bit WORD, and that KEYEVENTF_UNICODE events generate WM_CHAR messages, which passes UTF-16 surrogate codeunits as separate messages.

因此,要使用 KEYEVENTF_UNICODE 发送一串 Unicode 字符,您可以执行以下操作:

So, to send a string of Unicode characters using KEYEVENTF_UNICODE, you can do something like this:

#include <vector>
#include <string>

void SendInputString(const std::wstring &str)
{
    int len = str.length();
    if (len == 0) return;

    std::vector<INPUT> in(len*2);
    ZeroMemory(&in[0], in.size()*sizeof(INPUT));

    int i = 0, idx = 0;
    while (i < len)
    {
        WORD ch = (WORD) str[i++];

        if ((ch < 0xD800) || (ch > 0xDFFF))
        {
            in[idx].type = INPUT_KEYBOARD;
            in[idx].ki.wScan = ch;
            in[idx].ki.dwFlags = KEYEVENTF_UNICODE;
            ++idx;

            in[idx] = in[idx-1];
            in[idx].ki.dwFlags |= KEYEVENTF_KEYUP;
            ++idx;
        }
        else
        {
            in[idx].type = INPUT_KEYBOARD;
            in[idx].ki.wScan = ch;
            in[idx].ki.dwFlags = KEYEVENTF_UNICODE;
            ++idx;

            in[idx].type = INPUT_KEYBOARD;
            in[idx].ki.wScan = (WORD) str[i++];
            in[idx].ki.dwFlags = KEYEVENTF_UNICODE;
            ++idx;

            in[idx] = in[idx-2];
            in[idx].ki.dwFlags |= KEYEVENTF_KEYUP;
            ++idx;

            in[idx] = in[idx-2];
            in[idx].ki.dwFlags |= KEYEVENTF_KEYUP;
            ++idx;
        }
    }

    SendInput(in.size(), &in[0], sizeof(INPUT));
}

相关文章