无论用户已安装或使用哪种布局,如何使SendInput使用固定的(en-US)布局?

时间:2019-04-17 13:20:45

标签: c++ winapi sendinput

我觉得很方便,可以使用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不能选择,因为它需要我获得窗口以及文本框的句柄。

1 个答案:

答案 0 :(得分:2)

SendInput()调用cInputs==1(几乎)始终是用户代码中的错误。不要做!与SendInput()相比,使用keybd_event()的主要好处之一是能够一次 atomical 原子提交一系列输入(因此,无需在以下情况下使用BlockInput()全部)。

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

您也根本不会发送KEYEVENTF_KEYUP事件。即使使用KEYEVENTF_UNICODE,您也需要这些。

有关更多详细信息,请参见my previous answerSending Two or more chars using SendInput

话虽如此,请尝试以下类似操作:

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