[英]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_KEYDOWN
, WM_KEYUP
, WM_SYSKEYDOWN
和WM_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 = true
的VK_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結構數組以作為事務執行,因此所有擊鍵都作為一個單元進行重放(用戶可以例如,在您的中間插入他自己的鍵)。
@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.