簡體   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