Winapi - 扩展键盘扫描码

Winapi - Extended Keyboard Scan Codes

如果我想使用像 0xE0 0x1D(右 CTRL)这样的扩展扫描码来模拟按键,我将如何在 C 中模拟这样的按键?我试过用两个 INPUT 结构调用 SendInput,但只有左 CTRL 键是 "pressed"。对于具有 "twin"(Shift 和 Alt)的其他键,也会发生同样的事情。

其次,如何为 "extended" 键引发 keyup 事件?

您没有指定是将密钥发送到同一个应用程序还是另一个应用程序。使用 SendInput,我们无法指定键的位置。我们必须以某种方式确保 window 处于活动状态并且焦点设置正确。 请注意,SendInput 将发送 WM_KEYDOWN 或 WM_KEYUP 消息。 如果您直接使用 SendMessage 发送 WM_KEYDOWN 和 WM_KEYUP 消息,您将拥有更大的灵活性。您指定要发送到的 window 的 window 句柄。 window 句柄用于文本框或接受文本的控件,而不是文本框或其他控件所在的 window。

这是确定要在 SendMessage 中使用的确切参数的方法。请注意,SendInput 将生成 SendMessage。

在 Visual Studio 中单击“工具”菜单。您将看到 "Spy++" 和 "Spy++ x64"。我不确定我们什么时候需要一个或另一个,但如果一个不起作用,那就试试另一个。在 Spy++ 中,单击消息菜单,然后单击 "Logging Options..."。在右上角区域单击 Findor Tool 并拖动到 window。释放鼠标后,单击“消息”选项卡。然后单击 "Clear All",然后选中 "Keyboard" 的复选框。请注意,消息菜单也有用于启动和停止日志记录的命令,但我认为它是默认打开的。转到选定的 window 并键入您要尝试的键。然后查看 Spy++ 中记录的消息。您将看到 to/from window 发送的所有消息。我通常会在拥有所需的一切后立即停止记录,因为根据为记录选择的消息,记录的消息可能太多而无用。如果您只记录键盘消息,那么您不会记录太多消息。

对我来说,扩展字段是右 Ctrl 为 1,左 Ctrl 为 0。

KEYBDINPUT结构有一个KEYEVENTF_EXTENDEDKEY标志来为你处理0xE0字节:

If specified, the scan code was preceded by a prefix byte that has the value 0xE0 (224).

尝试这样的事情:

INPUT inputs[2];
ZeroMemory(inputs, sizeof(inputs));

inputs[0].type = INPUT_KEYBOARD;
inputs[0].ki.wScan = 0x1D;
inputs[0].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_EXTENDEDKEY;

CopyMemory(&inputs[1], &inputs[0], sizeof(INPUT));
inputs[1].ki.dwFlags |= KEYEVENTF_KEYUP;

SendInput(2, inputs, sizeof(INPUT));

不过,我建议使用虚拟钥匙代替扫描码:

INPUT inputs[2];
ZeroMemory(inputs, sizeof(inputs));

inputs[0].type = INPUT_KEYBOARD;
inputs[0].ki.wVk = VK_CONTROL;
inputs[0].ki.dwFlags = KEYEVENTF_EXTENDEDKEY;

CopyMemory(&inputs[1], &inputs[0], sizeof(INPUT));
inputs[1].ki.dwFlags |= KEYEVENTF_KEYUP;

SendInput(2, inputs, sizeof(INPUT));

但是,如果您确实需要扫描码,至少可以看看 MapVirtualKey() 将虚拟键转换为扫描码:

inputs[0].type = INPUT_KEYBOARD;
inputs[0].ki.wScan = MapVirtualKey(VK_RCONTROL, MAPVK_VK_TO_VSC);
inputs[0].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_EXTENDEDKEY;