我对C++的经验很少,对SendInput方法也完全不熟悉。我已经通过注册表修改设置了我的笔记本电脑(带有英国键盘),每当按下right control
键并按下scroll lock
两次时,就会创建一个崩溃转储。我正试图通过在Visual c++2010学习版中编译的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
标志为真。
按下并松开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));
EDIT:由于注释而指定ip.ki.wScan
不使用KEYEVENTF_SCACODE并不意味着wScan值将被忽略。它不会,并且如果将wScan设置为0,某些应用程序(例如RDP客户端)的行为可能会不同/错误。
编辑2:我认为这在这里并不重要,但最好只调用SendInput
一次,并将INPUT结构的数组作为事务传递给它执行,这样所有的击键都会作为一个单元进行重放(例如,用户不能将自己的键穿插在击键的中间)。
编辑3:您可以下载显示键入密钥的应用程序。
此代码成功地将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 %dn", numSuccessful, i, GetLastError());
}
return 0;
}
我相信原因是SendInput()将键注入到键盘驱动程序之上的层中,而正是键盘驱动程序监视这些按键来启动BSOD。
@David Ching。。。这让我沮丧不已。。。我已经阅读了所有相关的文档(并试图理解它,记住我是这方面的新手),考虑到你的建议和我所读到的内容,我尝试了无数种代码排列。根据你最后的建议,下面的代码是我最后一次尝试,但没有成功。我正在努力确定还有什么其他因素会对这个问题产生影响-硬件(笔记本电脑是东芝卫星L670D-10N)或操作系统(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;
}
更新-成功发送测试代码
#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((滚动锁)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;
}