无论用户安装或使用什么布局,如何使 SendInput 使用固定(en-US)布局?

How to make SendInput use fixed (en-US) layout regardless of what layouts the user have installed or uses?

我发现我可以使用 SendInput 将文本和控件混合成单个字符串并将其发送到任何应用程序,例如 "\nHello\nWorld" 将以

的序列结束
hit {Enter}
type "Hello"
hit {enter}
type "World"

在任何聊天应用程序中(例如)。

我有以下代码

void GenerateKey(WORD vk)
{

    INPUT Input;
    ZeroMemory(&Input, sizeof(Input));
    Input.type = INPUT_KEYBOARD;
    Input.ki.time = 0;
    Input.ki.dwFlags = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_UNICODE;
    Input.ki.wVk = vk;
    SendInput(1, &Input, sizeof(INPUT));
    return;
}

void SendKeys(const LPCWSTR format, ...)
{
    va_list args;
    va_start(args, format);
    WCHAR buffer[256];
    vswprintf_s(buffer, format, args);
    va_end(args);

    BlockInput(true);
    for (unsigned int i = 0; i<wcslen(buffer); ++i)
        GenerateKey((WORD)VkKeyScan(buffer[i]));
    BlockInput(false);
}

它工作得很好。但问题是,这取决于当前使用的键盘布局。

我也试过用LoadKeyboardLayout,但是下面的完全没有效果

    BlockInput(true);
    HKL keyboard_layout = LoadKeyboardLayout("00000409", KLF_ACTIVATE);
    for (unsigned int i = 0; i<wcslen(buffer); ++i)
        GenerateKey((WORD)VkKeyScanExW(buffer[i], keyboard_layout));
    BlockInput(false);

我也欢迎任何实现目标的想法。

SendMessage 不是一个选项,因为它需要我获得 window 和文本框的句柄。

cInputs==1 调用 SendInput() 是(几乎)总是用户代码中的错误。不要这样做!使用 SendInput() 而不是 keybd_event() 的主要好处之一是能够 原子地 一次提交一组输入(因此不需要使用 BlockInput()

在这种情况下,为击键创建一个 INPUT 数组,然后仅调用 SendInput() 1 次。而且,根据 KEYBDINPUT documentationKEYEVENTF_UNICODE 不采用虚拟键码作为输入,而是采用实际的 Unicode 文本字符(这意味着您不必手动处理键盘布局)。

您也根本没有发送 KEYEVENTF_KEYUP 事件。你需要那些,即使在使用 KEYEVENTF_UNICODE.

时也是如此

有关详细信息,请参阅 to

话虽如此,请尝试更类似的方法:

#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));
}

void SendKeys(LPCWSTR format, ...)
{
    std::wstring buffer;

    va_list args;
    va_start(args, format);

    buffer.resize(_vscwprintf(format, args) + 1);
    buffer.resize(vswprintf_s(&buffer[0], buffer.size(), format, args));

    va_end(args);

    SendInputString(buffer);
}