无论用户安装或使用什么布局,如何使 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
documentation,KEYEVENTF_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);
}
我发现我可以使用 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
documentation,KEYEVENTF_UNICODE
不采用虚拟键码作为输入,而是采用实际的 Unicode 文本字符(这意味着您不必手动处理键盘布局)。
您也根本没有发送 KEYEVENTF_KEYUP
事件。你需要那些,即使在使用 KEYEVENTF_UNICODE
.
有关详细信息,请参阅
话虽如此,请尝试更类似的方法:
#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);
}