【问题标题】:How to specify kbd modifiers with SendInput()?如何使用 SendInput() 指定 kbd 修饰符?
【发布时间】:2009-03-19 11:13:33
【问题描述】:

我正在使用 Windows API SendInput() 调用来模拟键盘事件。以下 sn-p(省略了无关细节)非常适合发送字符序列:

wchar_t txt = ...;
INPUT *input = ...;
size_t nInput = 0;

for (unsigned int j = 0; j < length; j++) {
    input[nInput].ki.wVk = 0;
    input[nInput].ki.wScan = txt[j];
    input[nInput].ki.dwFlags = KEYEVENTF_UNICODE;
    nInput++;
    input[nInput].ki.wVk = 0;
    input[nInput].ki.wScan = txt[j];
    input[nInput].ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
    nInput++;
}
SendInput(nInput, input, sizeoF(INPUT));

现在我正在尝试发送带有修饰符的单个按键。我尝试了以下代码:

bool control, alt shift;
wchar_t chr;

if (control) {
    input[nInput].ki.wVk = VK_CONTROL;
    input[nInput].ki.dwFlags = 0;
    nInput++;
}
if (alt) {
    input[nInput].ki.wVk = VK_MENU;
    input[nInput].ki.dwFlags = 0;
    nInput++;
}
if (shift) {
    input[nInput].ki.wVk = VK_SHIFT;
    input[nInput].ki.dwFlags = 0;
    nInput++;
}

input[nInput].ki.wVk = 0;
input[nInput].ki.wScan = chr;
input[nInput].ki.dwFlags = KEYEVENTF_UNICODE;
nInput++;
input[nInput].ki.wVk = 0;
input[nInput].ki.wScan = chr;
input[nInput].ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
nInput++;

if (shift) {
    input[nInput].ki.wVk = VK_SHIFT;
    input[nInput].ki.dwFlags = KEYEVENTF_KEYUP;
    nInput++;
}
if (alt) {
    input[nInput].ki.wVk = VK_MENU;
    input[nInput].ki.dwFlags = KEYEVENTF_KEYUP;
    nInput++;
}
if (control) {
    input[nInput].ki.wVk = VK_CONTROL;
    input[nInput].ki.dwFlags = KEYEVENTF_KEYUP;
    nInput++;
}
SendInput(nInput, input, sizeof(INPUT));

但是,修饰符似乎没有通过,也就是说,即使 control 设置为 true,事件序列也会作为普通按键接收。

【问题讨论】:

    标签: c winapi keyboard-events


    【解决方案1】:

    Pax's answer 没有成功,但它引导我找到了正确的解决方案。简而言之:不要将KEYEVENTF_UNICODE 用于单个按键,而是将字符转换为虚拟键码,然后以这种方式发送。以下是相关代码:

    SHORT virtKey = VkKeyScan((TCHAR) chr);
    input[nInput].ki.wVk = LOBYTE(virtKey);
    input[nInput].ki.dwFlags = 0;
    nInput++;
    input[nInput].ki.wVk = LOBYTE(virtKey);
    input[nInput].ki.dwFlags = KEYEVENTF_KEYUP;
    nInput++;
    

    我还没有测试这对于映射到非英语键盘布局的非 ASCII unicode 字符是如何工作的,以及当我的应用程序的布局集与前面的应用程序的布局集不同时会发生什么。

    【讨论】:

    • @David,你可能应该接受这个答案,否则 SO 会继续用“你有没有想过接受这个问题的答案”来打扰你。
    • @Pax:当然,我会这样做,但首先我想给其他人一个机会来改进我的答案或指出我的错误。
    【解决方案2】:

    我发现的唯一一段可能表明您的问题的代码也在ki 结构中设置了扫描代码。

    尝试将修饰符部分更改为:

    if (control) {
        input[nInput].ki.wVk = VK_CONTROL;
        input[nInput].ki.dwFlags = 0;
        input[nInput].ki.wScan = MapVirtualKey(VK_CONTROL, 0); 
        nInput++;
    }
    if (alt) {
        input[nInput].ki.wVk = VK_MENU;
        input[nInput].ki.dwFlags = 0;
        input[nInput].ki.wScan = MapVirtualKey(VK_MENU, 0); 
        nInput++;
    }
    if (shift) {
        input[nInput].ki.wVk = VK_SHIFT;
        input[nInput].ki.dwFlags = 0;
        input[nInput].ki.wScan = MapVirtualKey(VK_SHIFT, 0); 
        nInput++;
    }
    

    看看有没有帮助。

    如果这仍然不起作用,请尝试将 dwFlags 设置为 KEYEVENTF_SCANCODE 而不是 0(仅适用于修饰键)。

    也为按键事件执行此操作,我假设您将input[nInput].type 设置为INPUT_KEYBOARD,是吗?您的代码没有表明这一点。

    供参考,在this page上找到。

    【讨论】:

    • "你将 input[nInput].type 设置为 INPUT_KEYBOARD" - 是的,当然。
    • 不是“当然”,我从不假设任何没有明确说明的事情(有时我什至怀疑那些:-)。不管怎样,你有没有试过扫码?
    • 很公平 :-) 无论如何,扫描代码没有帮助,但你引用的页面引导我找到解决方案。我会发布它作为答案。 +1,谢谢!
    • 没有问题,很高兴我能帮上忙,哪怕只是一点点。我要睡觉了,奥兹已经很晚了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-16
    • 1970-01-01
    • 2016-04-29
    • 2019-12-18
    • 1970-01-01
    相关资源
    最近更新 更多