简体   繁体   English

C ++-使用SendInput方法模拟击键,无法区分rightctrl键

[英]C++ - Simulating keystrokes using SendInput method, failure to distinguish rightctrl key

I have very little experience in C++, and I'm completely unfamiliar with the SendInput method. 我在C ++方面的经验很少,而且我完全不熟悉SendInput方法。 I've setup my laptop (with UK keyboard) via a registry modification, to create a crash dump whenever the right control key is held down and scroll lock is twice pressed. 我已经通过注册表修改设置了我的笔记本电脑(带有UK键盘),以在每次按住right control键并两次按下scroll lock时创建一个故障转储。 I am trying to achieve this programmatically via a c++ executable, compiled in Visual C++ 2010 Express. 我正在尝试通过Visual C ++ 2010 Express中编译的c ++可执行文件以编程方式实现此目标。

Using this post: how to use sendinput function C++ as my inspiration, I have created the code snippet hereunder. 使用本文: 如何使用sendinput函数C ++作为我的灵感,我在下面创建了代码段。 Aside from multiple Cannot find or open the PDB debug outputs, which from reading this post: Error Message : Cannot find or open the PDB file can apparently be ignored, the code compiles and runs. 除了多个Cannot find or open the PDB调试输出外,从阅读这篇文章中可以看到错误消息:显然,可以忽略或找不到PDB文件 ,代码可以编译并运行。 However no BSOD transpires. 但是,没有BSOD发生。 I have manually "forced" the BSOD, so I know it works. 我已经手动“强制”了BSOD,所以我知道它可以工作。

Bearing in mind I'm a novice, please explain what changes must be made for this to work? 请记住,我是新手,请说明必须对此进行哪些更改?

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

int main()
{
INPUT ip;
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0;
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;

ip.ki.wVk = VK_RCONTROL;
ip.ki.dwFlags = 0; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = VK_SCROLL;
ip.ki.dwFlags = 0; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = VK_SCROLL;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = VK_SCROLL;
ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = VK_SCROLL;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = VK_RCONTROL;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));

return 0;
}

Following is the relevant code for a simple application I wrote to display the virtual key, scan code, flags, etc. of keys that are typed into the application. 以下是我编写的一个简单应用程序的相关代码,该应用程序显示了键入到应用程序中的密钥的虚拟密钥,扫描代码,标志等。 (The code demonstrates creating a listbox and handling the WM_KEYDOWN , WM_KEYUP , WM_SYSKEYDOWN , and WM_SYSKEYUP messages, then displaying the parameters: (该代码演示了如何创建列表框并处理WM_KEYDOWNWM_KEYUPWM_SYSKEYDOWNWM_SYSKEYUP消息,然后显示参数:

void CChildView::ReportKey (UINT nChar, UINT nRepCnt, UINT nFlags)
{
    CString str;
    str.Format ( "%s Virtual key=%d; Scan code=%d Extended=%d AltDown=%d",
             (nFlags & 0x8000) ? "Up" : "DOWN",
             nChar, (nFlags & 0xFF), !!(nFlags & 0x0100), !!(nFlags & 0x2000) );
    AddString (str);
}


void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    ReportKey (nChar, nRepCnt, nFlags);
    CListBox::OnKeyDown(nChar, nRepCnt, nFlags);
}

void CChildView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    ReportKey (nChar, nRepCnt, nFlags);
    CListBox::OnKeyUp(nChar, nRepCnt, nFlags);
}

void CChildView::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    ReportKey (nChar, nRepCnt, nFlags);
    CListBox::OnSysKeyDown(nChar, nRepCnt, nFlags);
}

void CChildView::OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    ReportKey (nChar, nRepCnt, nFlags);
    CListBox::OnSysKeyUp(nChar, nRepCnt, nFlags);
}

When the Right Control key is pressed, then released, while this app has the keyboard focus, it displays: 当此应用程序具有键盘焦点时,按下“ Right Control键然后放开,它将显示:

DOWN Virtual key=17; Scan code=29 Extended=1 AltDown=0
Up Virtual key=17; Scan code=29 Extended=1 AltDown=0

Curiously, virtual key "17" is 0x11, which according to this chart is VK_CONTROL , not VK_RCONTROL ! 奇怪的是,虚拟键“ 17”为0x11,根据此图表 ,该键为VK_CONTROL ,而不是VK_RCONTROL And the Extended flag is true. 并且Extended标志为true。

When the Left Control key is pressed and released, the output is: 按下并释放Left Control键时,输出为:

DOWN Virtual key=17; Scan code=29 Extended=0 AltDown=0
Up Virtual key=17; Scan code=29 Extended=0 AltDown=0

So it seems Windows never sees a VK_RCONTROL , instead it sees a VK_CONTROL with Extended = true . 因此,似乎Windows从未看到VK_RCONTROL ,而是看到了Extended = trueVK_CONTROL

So try to call SendInput() with that: 因此,尝试使用以下方法调用SendInput():

INPUT ip[6];
...
ip[0].ki.wVk = VK_CONTROL;
ip[0].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
ip[0].ki.dwFlags = KEYEVENTF_EXTENDEDKEY; 
....
ip[5].ki.wVk = VK_CONTROL;
ip[5].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
ip[5].ki.dwFlags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY; 
SendInput(_countof(ip), &ip[0], sizeof(INPUT));

EDIT: Specify ip.ki.wScan due to the comment 编辑:由于评论指定ip.ki.wScan

not using KEYEVENTF_SCANCODE doesn't mean the wScan value will be ignored. 不使用KEYEVENTF_SCANCODE并不意味着wScan值将被忽略。 It won't and some applications (eg RDP-Client) may behave different/wrong if you set wScan to 0. 不会,如果将wScan设置为0,某些应用程序(例如RDP-Client)的行为可能不同。

EDIT 2: I don't think it matters here, but it is better to call SendInput just once, and pass it an array of INPUT structures to execute as a transaction, so all the keystrokes are replayed as a unit (and user can't intersperse his own keys during the middle of yours, for example). 编辑2:我认为这无关紧要,但是最好只调用一次SendInput ,然后将其传递给INPUT结构数组以作为事务执行,因此所有击键都作为一个单元进行重放(用户可以例如,在您的中间插入他自己的键)。

EDIT 3: You can download the application that shows the keys typed into it. 编辑3:您可以下载显示键入到其中的键的应用程序

@David Ching... this is frustrating me no end... I've read all the relevant documentation (and tried to make sense of it, remember I'm a novice at this), I've tried umpteen permutations of the code taking into account your advice and what I've read. @David Ching ...这令我无休止...我已经阅读了所有相关文档(并试图弄懂它,记住我是新手),我尝试了无数次排列代码,要考虑到您的建议和我阅读的内容。 The code below, according to your last suggestion, is the last I've tried with no success. 根据您的最后建议,下面的代码是我尝试的最后一次,但没有成功。 I'm trying to determine what other factors can have a bearing on the issue - would hardware (Laptop is Toshiba Satellite L670D-10N), or OS (Windows 7 Ultimate - Spanish version with English Language Pack) make a difference? 我试图确定与该问题有关的其他因素-硬件(笔记本电脑是Toshiba Satellite L670D-10N)还是OS(Windows 7 Ultimate-带有英语语言包的西班牙语版本)会有所不同? - I can't imagine so. -我无法想象。 I really, really appreciate your help, please don't give up helping! 我真的非常感谢您的帮助,请不要放弃帮助! - btw, thanks for the app link. -顺便说一句,感谢您的应用程序链接。

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

int main()
{
INPUT ip[6];

ip[0].ki.wVk = VK_CONTROL;
ip[0].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
ip[0].ki.dwFlags = KEYEVENTF_EXTENDEDKEY;

ip[1].ki.wVk = VK_SCROLL;
ip[1].ki.dwFlags = 0;

ip[2].ki.wVk = VK_SCROLL;
ip[2].ki.dwFlags = KEYEVENTF_KEYUP;

ip[3].ki.wVk = VK_SCROLL;
ip[3].ki.dwFlags = 0;

ip[4].ki.wVk = VK_SCROLL;
ip[4].ki.dwFlags = KEYEVENTF_KEYUP;

ip[5].ki.wVk = VK_CONTROL;
ip[5].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
ip[5].ki.dwFlags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY;
SendInput(_countof(ip), &ip[0], sizeof(INPUT));

return 0;
}

UPDATE - THE SUCCESSFUL SENDINPUT TEST CODE 更新-成功的SENDINPUT测试代码

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

int main()
{
INPUT ip;

Sleep(3000);

ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0;
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;

ip.ki.wVk = 0x43;
ip.ki.dwFlags = 0; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x43;
ip.ki.dwFlags = KEYEVENTF_KEYUP; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x48;
ip.ki.dwFlags = 0; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x48;
ip.ki.dwFlags = KEYEVENTF_KEYUP; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x52;
ip.ki.dwFlags = 0; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x52;
ip.ki.dwFlags = KEYEVENTF_KEYUP; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x49;
ip.ki.dwFlags = 0; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x49;
ip.ki.dwFlags = KEYEVENTF_KEYUP; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x53;
ip.ki.dwFlags = 0; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x53;
ip.ki.dwFlags = KEYEVENTF_KEYUP; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x10;
ip.ki.dwFlags = 0; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x43;
ip.ki.dwFlags = 0; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x43;
ip.ki.dwFlags = KEYEVENTF_KEYUP; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x48;
ip.ki.dwFlags = 0; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x48;
ip.ki.dwFlags = KEYEVENTF_KEYUP; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x52;
ip.ki.dwFlags = 0; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x52;
ip.ki.dwFlags = KEYEVENTF_KEYUP; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x49;
ip.ki.dwFlags = 0; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x49;
ip.ki.dwFlags = KEYEVENTF_KEYUP; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x53;
ip.ki.dwFlags = 0; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x53;
ip.ki.dwFlags = KEYEVENTF_KEYUP; 
SendInput(1, &ip, sizeof(INPUT));

ip.ki.wVk = 0x10;
ip.ki.dwFlags = KEYEVENTF_KEYUP; 
SendInput(1, &ip, sizeof(INPUT));

return 0;
}

UPDATE - THE UNSUCCESSFUL REVISED CTRL((SCROLL LOCK)X2) CODE 更新-未成功修订的CTRL((SCROLL LOCK)X2)代码

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

int main()
{
INPUT ip[6] = {0};

Sleep(3000);

ip[0].ki.wVk = VK_CONTROL;
ip[0].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
ip[0].ki.dwFlags = KEYEVENTF_EXTENDEDKEY;

ip[1].ki.wVk = VK_SCROLL;
ip[1].ki.wScan = MapVirtualKey(VK_SCROLL, 0);
ip[1].ki.dwFlags = 0;

ip[2].ki.wVk = VK_SCROLL;
ip[2].ki.wScan = MapVirtualKey(VK_SCROLL, 0);
ip[2].ki.dwFlags = KEYEVENTF_KEYUP;

ip[3].ki.wVk = VK_SCROLL;
ip[3].ki.wScan = MapVirtualKey(VK_SCROLL, 0);
ip[3].ki.dwFlags = 0;

ip[4].ki.wVk = VK_SCROLL;
ip[4].ki.wScan = MapVirtualKey(VK_SCROLL, 0);
ip[4].ki.dwFlags = KEYEVENTF_KEYUP;

ip[5].ki.wVk = VK_CONTROL;
ip[5].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
ip[5].ki.dwFlags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY;
SendInput(_countof(ip), &ip[0], sizeof(INPUT));

return 0;
}

This Code successfully stuffs RControl+ScrollLock+ScrollLock into the ScanCode app, however, sorry, the computer does not reboot like when it does when these keys are manually typed. 该代码成功将RControl + ScrollLock + ScrollLock填充到ScanCode应用程序中,但是,很抱歉,计算机不会像手动键入这些键时那样重新启动。

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

int main()
{
    // Must specify INPUT_KEYBOARD for all INPUT structs
    INPUT ip[6] = { 
            { INPUT_KEYBOARD },
            { INPUT_KEYBOARD },
            { INPUT_KEYBOARD },
            { INPUT_KEYBOARD },
            { INPUT_KEYBOARD },
            { INPUT_KEYBOARD },
    };

    Sleep(3000);


    // Specify keys by scancode.  For the VK_SCROLL, it was necessary
    // to instead specify the wVK, otherwise VK==3 was received by ScanCode, instead
    // of VK_SCROLL == 145!
    //ip[0].ki.wVk = VK_CONTROL;
    ip[0].ki.wScan = MapVirtualKey(VK_RCONTROL, MAPVK_VK_TO_VSC);
    ip[0].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_EXTENDEDKEY;

    ip[1].ki.wVk = VK_SCROLL;
    ip[1].ki.wScan = MapVirtualKey(VK_SCROLL, MAPVK_VK_TO_VSC);
    ip[1].ki.dwFlags = /*KEYEVENTF_SCANCODE*/ 0;

    ip[2].ki.wVk = VK_SCROLL;
    ip[2].ki.wScan = MapVirtualKey(VK_SCROLL, MAPVK_VK_TO_VSC);
    ip[2].ki.dwFlags = /*KEYEVENTF_SCANCODE |*/ KEYEVENTF_KEYUP;

    ip[3].ki.wVk = VK_SCROLL;
    ip[3].ki.wScan = MapVirtualKey(VK_SCROLL, MAPVK_VK_TO_VSC);
    ip[3].ki.dwFlags = /*KEYEVENTF_SCANCODE*/ 0;

    ip[4].ki.wVk = VK_SCROLL;
    ip[4].ki.wScan = MapVirtualKey(VK_SCROLL, MAPVK_VK_TO_VSC);
    ip[4].ki.dwFlags = /*KEYEVENTF_SCANCODE |*/ KEYEVENTF_KEYUP;

    //ip[5].ki.wVk = VK_CONTROL;
    ip[5].ki.wScan = MapVirtualKey(VK_RCONTROL, MAPVK_VK_TO_VSC);
    ip[5].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY;

    int i = _countof(ip);
    int numSuccessful = SendInput(i, ip, sizeof(INPUT));
    if (numSuccessful == i)
        printf("Stuffed successful.\n");
    else
    {
        printf("Succeeded with %d of %d; error %d\n", numSuccessful, i, GetLastError());
    }

    return 0;
}

I believe the reason is that SendInput() injects the keys into the layer above the keyboard driver, and it is the keyboard driver that is monitored for these keystrokes to initiate the BSOD. 我相信原因是SendInput()将按键注入到键盘驱动程序上方的层中,并且监视这些按键启动BSOD的是键盘驱动程序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM