繁体   English   中英

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

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

我在C ++方面的经验很少,而且我完全不熟悉SendInput方法。 我已经通过注册表修改设置了我的笔记本电脑(带有UK键盘),以在每次按住right control键并两次按下scroll lock时创建一个故障转储。 我正在尝试通过Visual C ++ 2010 Express中编译的c ++可执行文件以编程方式实现此目标。

使用本文: 如何使用sendinput函数C ++作为我的灵感,我在下面创建了代码段。 除了多个Cannot find or open the PDB调试输出外,从阅读这篇文章中可以看到错误消息:显然,可以忽略或找不到PDB文件 ,代码可以编译并运行。 但是,没有BSOD发生。 我已经手动“强制”了BSOD,所以我知道它可以工作。

请记住,我是新手,请说明必须对此进行哪些更改?

#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;
}

以下是我编写的一个简单应用程序的相关代码,该应用程序显示了键入到应用程序中的密钥的虚拟密钥,扫描代码,标志等。 (该代码演示了如何创建列表框并处理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);
}

当此应用程序具有键盘焦点时,按下“ Right Control键然后放开,它将显示:

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

奇怪的是,虚拟键“ 17”为0x11,根据此图表 ,该键为VK_CONTROL ,而不是VK_RCONTROL 并且Extended标志为true。

按下并释放Left Control键时,输出为:

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

因此,似乎Windows从未看到VK_RCONTROL ,而是看到了Extended = trueVK_CONTROL

因此,尝试使用以下方法调用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));

编辑:由于评论指定ip.ki.wScan

不使用KEYEVENTF_SCANCODE并不意味着wScan值将被忽略。 不会,如果将wScan设置为0,某些应用程序(例如RDP-Client)的行为可能不同。

编辑2:我认为这无关紧要,但是最好只调用一次SendInput ,然后将其传递给INPUT结构数组以作为事务执行,因此所有击键都作为一个单元进行重放(用户可以例如,在您的中间插入他自己的键)。

编辑3:您可以下载显示键入到其中的键的应用程序

@David Ching ...这令我无休止...我已经阅读了所有相关文档(并试图弄懂它,记住我是新手),我尝试了无数次排列代码,要考虑到您的建议和我阅读的内容。 根据您的最后建议,下面的代码是我尝试的最后一次,但没有成功。 我试图确定与该问题有关的其他因素-硬件(笔记本电脑是Toshiba Satellite L670D-10N)还是OS(Windows 7 Ultimate-带有英语语言包的西班牙语版本)会有所不同? -我无法想象。 我真的非常感谢您的帮助,请不要放弃帮助! -顺便说一句,感谢您的应用程序链接。

#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;
}

更新-成功的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;
}

更新-未成功修订的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;
}

该代码成功将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;
}

我相信原因是SendInput()将按键注入到键盘驱动程序上方的层中,并且监视这些按键启动BSOD的是键盘驱动程序。

暂无
暂无

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

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