SendInput() 不等于在 C++ 键盘上手动按键?

2021-12-17 00:00:00 keyboard hook winapi c++ sendinput

我想编写一个 C++ 代码来模拟按下键盘键A":

I wanted to write a c++ code to emulate pressing a keyboard key "A":

// Set up a generic keyboard event.
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0; // hardware scan code for key
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;

// Press the "..." key
ip.ki.wVk = code; // virtual-key code for the "a" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));

// Release the "..." key
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));

当我启动其他程序并等待我的程序执行时它工作正常,单击A"并且第一个程序对其做出反应.但是我发现在另一个应用程序中我的操作以某种方式被阻止(我可以在键盘上手动按A",但使用我的程序不会导致任何操作).

It works fine when I launch other program and wait to my program execute, the "A" is clicked and first program react to it. But I found that in the other application my action was somehow prevented (I can manually press "A" on keyboard, but using my program do not cause any action).

那么,我该怎么做才能使从程序中按A"与手动按A"更加相同(这样第二个程序就无法识别它是从程序中调用的)?

So, what I can do to make pressing "A" from program more identical to manually pressed "A" (so the second program won't recognize that it was called from program)?

我没有第二个程序的源代码,不知道它是如何识别A"不是手动按下的.

I do not have source code of second program and do not know how it recognize that "A" wasn't pressed manually.

我确定我想对我的代码做出反应的窗口是前台,接收并阻止我的密钥(因此它可以确定该事件不是来自用户而是来自程序).

I'm sure that the window I want to react to my code is foreground, receive and block my key (so it can decide that event doesn't come from user but from program).

推荐答案

您也可以使用 SendInput() 发送硬件扫描代码(与 DirectInput 可能会忽略的虚拟扫描代码相反).它的文档很差,但 SendInput() 确实可以绕过 DirectInput.Eric 的解决方案不起作用的原因是他设置了硬件扫描码,但最终使用了虚拟扫描码(通过将 dwFlags 设置为 0 并将 wVk 设置为非零).

You can use SendInput() to send hardware scan codes as well (as opposed to virtual scan codes, which DirectInput might ignore). It's poorly documented, but SendInput() can indeed bypass DirectInput. The reason Eric's solution didn't work is he set the hardware scan code, but ended up using a virtual scan code (by setting dwFlags to 0 and wVk to non-zero).

本质上,要做一个你想设置的按键:

Essentially, to do a key press you want to set:

ip.ki.dwFlags = KEYEVENTF_SCANCODE;

要释放密钥,请设置:

ip.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;

下面是一个完整的工作示例,它打印了字母a".您可以在此处找到其他扫描码.

A full working sample is below and it prints the letter 'a'. You can find other scan codes here.

#define WINVER 0x0500
#include <windows.h>

using namespace std;

int main()
{

    //Structure for the keyboard event
    INPUT ip;

    Sleep(5000);

    //Set up the INPUT structure
    ip.type = INPUT_KEYBOARD;
    ip.ki.time = 0;
    ip.ki.wVk = 0; //We're doing scan codes instead
    ip.ki.dwExtraInfo = 0;

    //This let's you do a hardware scan instead of a virtual keypress
    ip.ki.dwFlags = KEYEVENTF_SCANCODE;
    ip.ki.wScan = 0x1E;  //Set a unicode character to use (A)

    //Send the press
    SendInput(1, &ip, sizeof(INPUT));

    //Prepare a keyup event
    ip.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
    SendInput(1, &ip, sizeof(INPUT));



    return 0;
}

注意:您可以通过向 SendInput() 传递一个 INPUT 结构数组来组合按键操作(如 A 的 shift + a).

Note: You can combine keypresses (like, shift + a for A) by passing SendInput() an array of INPUT structures.

相关文章