前言
在尝试开发一款可以远程控制电脑进行文字输入软件时候,需要找到合适方法在Windows端注入键盘事件。查询微软的相关文档之后,发现通过两个简单的函数就能实现基本的键盘事件注入功能。
事件注入
使用SendInput
方法即可。参照官方给出的实例:
cpp
//**********************************************************************
//
// Sends Win + D to toggle to the desktop
//
//**********************************************************************
void ShowDesktop()
{
OutputString(L"Sending 'Win-D'\r\n");
INPUT inputs[4] = {};
ZeroMemory(inputs, sizeof(inputs));
inputs[0].type = INPUT_KEYBOARD;
inputs[0].ki.wVk = VK_LWIN;
inputs[1].type = INPUT_KEYBOARD;
inputs[1].ki.wVk = 'D';
inputs[2].type = INPUT_KEYBOARD;
inputs[2].ki.wVk = 'D';
inputs[2].ki.dwFlags = KEYEVENTF_KEYUP;
inputs[3].type = INPUT_KEYBOARD;
inputs[3].ki.wVk = VK_LWIN;
inputs[3].ki.dwFlags = KEYEVENTF_KEYUP;
UINT uSent = SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
if (uSent != ARRAYSIZE(inputs))
{
OutputString(L"SendInput failed: 0x%x\n", HRESULT_FROM_WIN32(GetLastError()));
}
}
写成如下函数进行测试:
cpp
UINT sendInput(WORD virtualKeyCode) {
cout<<"sendInput"<<virtualKeyCode<<endl;
INPUT inputs[2] = {};
ZeroMemory(inputs, sizeof(inputs));
inputs[0].type = INPUT_KEYBOARD;
inputs[0].ki.wVk = virtualKeyCode;
inputs[1].type = INPUT_KEYBOARD;
inputs[1].ki.wVk = virtualKeyCode;
inputs[1].ki.dwFlags = KEYEVENTF_KEYUP;
UINT uSent = SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
if (uSent != ARRAYSIZE(inputs))
{
printf("SendInput failed: 0x%x\n", HRESULT_FROM_WIN32(GetLastError()));
}
return uSent;
}
int main()
{
sendInput('W');
sendInput('E');
sendInput('B');
}
根据函数返回值,事件在这个时候已经注入成功了。
使用SetForegroundWindow 聚焦窗口
然而,事件被成功注入不代表被注入到我们想要的地方。sendInput方法只会将事件注入到已经聚焦的窗口,如果窗口没有聚焦的话是收不到注入的消息的。通过SetForegroundWindow
方法,可以将特定的窗口聚焦。为了找到我们想聚焦的窗口,可以使用FindWindow
方法。FindWindow
需要两个参数,依次是类名、窗口名。 用法如下:
cpp
HWND targetWindow = FindWindow("YodaoMainWndClass",NULL);
if (targetWindow != NULL)
{
std::cout << "Window found!" << std::endl;
SetForegroundWindow(targetWindow);
}
如何获取窗口的类名与方法名?
一般的窗口使用Visual Studio的工具Spy++即可。以网易有道词典为例:
如图可以看到,类名为YodaoMainWindClass,窗口名为网易有道词典。