【问题标题】:c++ - SendInput() doesn't manage Alt codes properlyc++ - SendInput() 不能正确管理 Alt 代码
【发布时间】:2018-03-11 19:51:10
【问题描述】:

在我正在开发的程序中,我必须模拟击键,为此我使用SendInput() 方法,将包含作为击键一部分的输入的向量作为参数传递。我当前的代码似乎适用于我正在测试的所有组合,除了 Alt 代码。

这是我目前所做的:

// Press ALT
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_LMENU;
input.ki.wScan = 0;
input.ki.dwFlags = 0;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;    
keystroke.push_back(input);

// Press NumPad2
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_NUMPAD2;
input.ki.wScan = 0;
input.ki.dwFlags = 0;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;    
keystroke.push_back(input);

// Release NumPad2
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_NUMPAD2;
input.ki.wScan = 0;
input.ki.dwFlags = KEYEVENTF_KEYUP;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;    
keystroke.push_back(input);

// Press NumPad1
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_NUMPAD1;
input.ki.wScan = 0;
input.ki.dwFlags = 0;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;    
keystroke.push_back(input);

// Release NumPad1
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_NUMPAD1;
input.ki.wScan = 0;
input.ki.dwFlags = KEYEVENTF_KEYUP;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;    
keystroke.push_back(input);

// Press NumPad2
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_NUMPAD2;
input.ki.wScan = 0;
input.ki.dwFlags = 0;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;    
keystroke.push_back(input);

// Release NumPad2
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_NUMPAD2;
input.ki.wScan = 0;
input.ki.dwFlags = KEYEVENTF_KEYUP;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;    
keystroke.push_back(input);

// Release ALT
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_LMENU;
input.ki.wScan = 0;
input.ki.dwFlags = KEYEVENTF_KEYUP;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;    
keystroke.push_back(input);

SendInput(keystroke.size(), &keystroke[0], sizeof(keystroke[0]));

push_backs 是在 for 循环中完成的,这就是我每次都完全重新定义 input 变量的原因。

这种方法似乎适用于除 Alt 代码之外的所有组合。我怎样才能让它们也工作?谢谢。

PS:如您所见,dwFlags 从未将ALT (VK_LMENU) 声明为扩展密钥,因为据我了解,只有VK_RMENU(而不是VK_LMENU)是这样的。 This MSDN page 似乎证实了这一点。

【问题讨论】:

  • 对按钮和标志使用幻数无助于代码的可读性。
  • 我已将虚拟键代码和 dwFlags 的原始值替换为它们对应的#define 关键字。

标签: c++ keystroke sendinput modifier-key


【解决方案1】:

使用扫描码代替虚拟键。这将键注入系统的级别要低得多,并且比虚拟键更可靠地模拟真实用户的键入。

由于存在一些差异,我花了一段时间才找到最终的扫描码列表。但是从this page 中间的大表中引用“set 1”列似乎有效。

INPUT createScanCodeEvent(WORD scancode, bool isDown)
{
    INPUT input = {};
    input.type = INPUT_KEYBOARD;
    input.ki.wVk = 0;
    input.ki.wScan = scancode;
    input.ki.dwFlags = (isDown ? 0 : KEYEVENTF_KEYUP) | KEYEVENTF_SCANCODE;
    input.ki.time = 0;
    input.ki.dwExtraInfo = 0;
    return input;
}

int inject()
{
    std::vector<INPUT> keystroke;
    const WORD SCANCODE_ALT = 0x38;
    const WORD SCANCODE_NUMPAD_1 = 0x4f;
    const WORD SCANCODE_NUMPAD_2 = 0x50;

    keystroke.push_back(createScanCodeEvent(SCANCODE_ALT, true) );

    keystroke.push_back(createScanCodeEvent(SCANCODE_NUMPAD_2, true));
    keystroke.push_back(createScanCodeEvent(SCANCODE_NUMPAD_2, false));

    keystroke.push_back(createScanCodeEvent(SCANCODE_NUMPAD_1, true));
    keystroke.push_back(createScanCodeEvent(SCANCODE_NUMPAD_1, false));

    keystroke.push_back(createScanCodeEvent(SCANCODE_NUMPAD_2, true));
    keystroke.push_back(createScanCodeEvent(SCANCODE_NUMPAD_2, false));

    keystroke.push_back(createScanCodeEvent(SCANCODE_ALT, false));

    SendInput(keystroke.size(), keystroke.data(), sizeof(keystroke[0]));

    return 0;
}

【讨论】:

  • 成功了,非常感谢!!!您知道为什么虚拟键不足以完成任务吗?据我了解,虚拟键和扫描码共享相同的目标——识别一个键——但是虽然虚拟键是独立于机器的,但扫描码不是,所以虚拟键对我来说听起来是一个更好的选择。顺便说一句,由于我输入的是虚拟键,所以我现在使用MapVirtualKey(vKey, MAPVK_VK_TO_VSC) 从虚拟键中获取扫描码。
  • 已经有一段时间了,但我记得,扫描码会在输入堆栈中的较低级别注入。而 VK 在堆栈中的位置非常高。某些应用程序(例如游戏)专门侦听较低级别的键盘输入,并且会错过任何注入的 VK。如果您尝试模拟 被 ALT+221 按下,我怀疑 Windows 正在中间某处进行翻译。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-18
  • 2018-03-03
  • 2018-06-22
  • 1970-01-01
  • 2014-10-11
相关资源
最近更新 更多