Reputation: 529
I have very little experience in C++, and I'm completely unfamiliar with the SendInput method. 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. I am trying to achieve this programmatically via a c++ executable, compiled in Visual C++ 2010 Express.
Using this post: how to use sendinput function C++ as my inspiration, I have created the code snippet hereunder. 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. However no BSOD transpires. I have manually "forced" the BSOD, so I know it works.
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;
}
Upvotes: 0
Views: 3085
Reputation: 1963
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.
#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.
Upvotes: 0
Reputation: 529
@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. 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? - 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
#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
#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;
}
Upvotes: 0
Reputation: 1963
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:
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:
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
! And the Extended
flag is true.
When the Left Control
key is pressed and released, the output is:
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
.
So try to call SendInput() with that:
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
not using KEYEVENTF_SCANCODE doesn't mean the wScan value will be ignored. It won't and some applications (e.g. RDP-Client) may behave different/wrong if you set wScan to 0.
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).
EDIT 3: You can download the application that shows the keys typed into it.
Upvotes: 1