Windows 日记本播放挂钩 (WH_JOURNALPLAYBACK) 忽略 EVENTMSG HWND 参数

Windows Journal playback hook (WH_JOURNALPLAYBACK) ignores EVENTMSG HWND parameter

本文关键字:JOURNALPLAYBACK 忽略 EVENTMSG 参数 HWND WH 播放 日记本 Windows      更新时间:2023-10-16

>我正在开发一个程序来以编程方式模拟键盘和鼠标单击。它需要将单击发送到目标窗口句柄(例如:记事本编辑控件)。我正在获取记事本窗口的句柄并为该窗口生成生成WM_KEYDOWN、WM_SYSKEYDOWN、WM_KEYUP WM_SYSKEYUP消息。事件存储在队列中,稍后使用WH_JOURNALPLAYBACK钩子播放。

对于下面的代码片段,播放过程中的目标 hwnd 虽然设置正确,但消息永远不会到达目标句柄。如果我将记事本放在前台,它确实会收到消息。

我不确定为什么WH_JOURNALPLAYBACK忽略句柄参数。我本来想为各种句柄生成一系列自动化消息并播放它,以便即使没有使窗口成为焦点,我们也可以发送键盘和鼠标事件。

请让我知道

  • 如果可以使用日记将消息发送到各种目标句柄播放挂钩
  • 为什么在下面的代码中忽略 hwnd

..

#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; 
}

日志挂钩将事件注入系统消息队列。 对于键盘和鼠标消息,系统会将它们调度到当前焦点窗口,就像用户手动输入它们一样。 您在事件中指定的 HWND 未使用,它会在调度期间被替换。

而且,如果您考虑到录制的日志可以多次播放,并且其数据可以跨应用程序实例甚至重新启动而持久保存,并且 HWND 可以随着时间的推移重用于不同的事情,那么即使不涉及系统消息队列,日志播放也不能利用事件的 HWND 应该是有意义的。

因此,不能使用 WH_JOURNALPLAYBACK 来定位不在前台的特定窗口。您必须自己发送录制的消息。 但请注意Raymond Chen在博客中提到的一些警告:

您无法使用帖子消息模拟键盘输入

通过WM_CHAR消息模拟输入可能会伪造收件人,但不会伪造输入系统