我正在编写一个以编程方式模拟键盘和鼠标点击的程序。它需要将点击发送到目标窗口句柄(例如:记事本编辑控件)。我得到了记事本窗口的句柄,并为该窗口生成WM_KEYDOWN,WM_SYSKEYDOWN,WM_KEYUP,WM_SYSKEYUP消息。事件存储在队列中,稍后使用WH_JOURNALPLAYBACK挂钩进行播放。
对于下面的代码段,虽然设置正确,但播放过程中的目标hwnd仍然无法到达目标句柄。如果我将记事本带到前台,它会收到消息。
我不确定为什么WH_JOURNALPLAYBACK会忽略handle参数。我本来希望为各种句柄生成一系列自动化消息并播放它,这样即使不将窗口置于焦点,我们也可以发送键盘和鼠标事件。
请告诉我
...
#include <queue>
#include <iostream>
#include <windows.h>
using std::cout;
using std::endl;
using std::error;
struct Event
{
UINT msg;
UINT wparam;
UINT lparam;
HWND hwnd;
Event(UINT m, UINT wp, UINT lp, HWND h)
:msg(m),
wparam(wp),
lparam(lp),
hwnd(h)
{}
};
HHOOK jhook= NULL;
std::queue<Event> events;
bool gotoNextMsg = false;
LRESULT CALLBACK JournalPlaybackProc(int code, WPARAM wParam, LPARAM lParam)
{
switch( code )
{
case HC_SKIP:
cout<<"skip: "<<endl;
if(!events.empty())
{
events.pop();
}
break;
case HC_GETNEXT:
{
cout<<"next: "<<events.size()<<endl;
gotoNextMsg = true;
EVENTMSG * evm = (EVENTMSG*) lParam;
Event e = events.front();
switch(e.msg)
{
case WM_KEYDOWN:
cout<<"WM_KEYDOWN"<<endl;
break;
case WM_KEYUP:
cout<<"WM_KEYUP"<<endl;
break;
case WM_SYSKEYDOWN:
cout<<"WM_SYSKEYDOWN"<<endl;
break;
case WM_SYSKEYUP:
cout<<"WM_SYSKEYUP"<<endl;
break;
}
cout<<"handle: "<<e.hwnd<<endl;
cout<<"handle1:"<<evm->hwnd<<endl;
evm->message = e.msg;
evm->paramL = e.wparam;
evm->paramH = e.lparam;
evm->hwnd = e.hwnd;
evm->time = ::GetTickCount();
}
break;
default:
if( code < 0 )
::CallNextHookEx(jhook, code, wParam, lParam);
break;
}
if(events.empty())
{
cout<<"uinstalled"<<endl;
::UnhookWindowsHookEx(jhook);
::PostMessage(NULL, WM_USER+100, 0, 0);
}
return 0;
}
答案 0 :(得分:1)
日记挂钩将事件注入系统消息队列。对于键盘和鼠标消息,系统会将它们分派到当前聚焦窗口,就像用户手动输入它们一样。您未在事件中指定的HWND在调度期间被替换。
如果您认为录制的日志可以多次播放,并且其数据可以在应用程序实例中持续存在甚至重新启动,并且HWND可以随着时间的推移重复用于不同的事情,那么为什么期刊播放不能即使没有涉及系统消息队列,也要使用事件的HWND。
因此,您无法使用WH_JOURNALPLAYBACK
来定位不在前台的特定窗口。您必须自己发送录制的消息。但请注意Raymond Chen撰写的一些警告: