c++ 使用PostMessage模拟/合成不在焦点上的应用程序窗口中的简单按键

kuhbmx9i  于 2023-02-26  发布在  其他
关注(0)|答案(2)|浏览(253)

尝试编写一个简单的演示程序,其中键盘输入到控制台将被转换为在属于其他应用程序进程的目标窗口上的按键。因此,如果我在键盘上键入字符"w"到控制台,它将被转换为发送到目标线程的消息队列的适当消息,该消息使应用程序相信在其窗口处于焦点时按下了"w"键。
这是我尝试过的方法:

int main()
{
    // setting up window handle etc...

    println("Enter W, A, S, D or SPACE:");
    while (true)
    {
        int posted_key = NULL;
        int key_char = _getch();
        
        if (key_char==27) break;

        switch(key_char)
        {
            case 119: posted_key = 0x57; break;
            case 97: posted_key = 0x41; break;
            case 115: posted_key = 0x53; break;
            case 100: posted_key = 0x44; break;
            case 32: posted_key = VK_SPACE; break;
        }

        if (posted_key == NULL) continue; // Key isn't W, A, S, D or SPACE

        if (!PostMessage(hndl, WM_KEYDOWN, posted_key, MapVirtualKey(posted_key, MAPVK_VK_TO_VSC))) print("Error while posting WM_KEYDOWN"); break;
        if (!PostMessage(hndl, WM_CHAR, posted_key, MapVirtualKey(posted_key, MAPVK_VK_TO_VSC))) print("Error while posting WM_CHAR"); break;
        Sleep(100);
        if (!PostMessage(hndl, WM_KEYUP, posted_key, MapVirtualKey(posted_key, MAPVK_VK_TO_VSC))) print("Error while posting WM_KEYUP"); break;
    }

    return 0;
}

但是,只有WM_KEYDOWNWM_CHAR消息(每个消息1个)最终实际发布到队列中,而没有WM_KEYUP消息,导致应用程序的行为就像键被无限期地按下一样。在各种应用程序上使用Spy ++后,似乎快速按键通常在3秒内完成:WM_KEYDOWNWM_CHAR,然后几分之一秒后的WM_KEYUP。这就是我试图在代码中模拟的,但显然没有起作用。
更重要的是,当我按W、A、S、D或空格键时,我的程序立即退出,返回代码为0,并且错误消息没有打印出来,所以要么是我的程序崩溃了,要么是我对PostMessage的调用返回了一个非零值,后者可能不太可能,因为我的错误消息没有打印出来。
我做错了什么?我不能使用SendInputSendKeys来完成我正在尝试做的事情,因为我需要它工作,即使应用程序窗口不在焦点上。

  • --编辑--*

我在原始文件中错误地格式化了if条件。

int main()
{
    // setting up window handle etc...

    println("Enter W, A, S, D or SPACE:");
    while (true)
    {
        int posted_key = NULL;
        int key_char = _getch();

        if (key_char==27) break;

        switch(key_char)
        {
            case 119: posted_key = 0x57; break;
            case 97: posted_key = 0x41; break;
            case 115: posted_key = 0x53; break;
            case 100: posted_key = 0x44; break;
            case 32: posted_key = VK_SPACE; break;
        }

        if (posted_key == NULL) continue; // Key isn't W, A, S, D or SPACE

        if (!PostMessage(hndl, WM_KEYDOWN, posted_key, MapVirtualKey(posted_key, MAPVK_VK_TO_VSC)))
        { 
            print("Error while posting WM_KEYDOWN"); 
            break; 
        }

        if (!PostMessage(hndl, WM_CHAR, posted_key, MapVirtualKey(posted_key, MAPVK_VK_TO_VSC))) 
        { 
            print("Error while posting WM_CHAR"); 
            break; 
        }

        Sleep(100);
        if (!PostMessage(hndl, WM_KEYUP, posted_key, MapVirtualKey(posted_key, MAPVK_VK_TO_VSC))) 
        { 
            print("Error while posting WM_KEYUP"); 
            break; 
        }
    }

    return 0;
}

现在发布的消息具有不同的模式as you can see here。在字符代码为"119"的3条预期消息之间似乎发布了字符代码为"83"的WM_CHAR消息。然后在WM_KEYUP消息之后又发布了一条字符代码为"119"的消息。
至于我的程序行为,它不再突然退出,表明PostMessage返回一个非零值。
然而,目标应用程序仍然表现得好像该键被无限期地按下。

p8h8hvxi

p8h8hvxi1#

我认为如果您正确地格式化代码,这个问题就会变得很明显。
比较:

if (!PostMessage(hndl, WM_KEYDOWN, posted_key, MapVirtualKey(posted_key, MAPVK_VK_TO_VSC))) print("Error while posting WM_KEYDOWN"); break;

if (!PostMessage(hndl, WM_KEYDOWN, posted_key, MapVirtualKey(posted_key, MAPVK_VK_TO_VSC))) 
    print("Error while posting WM_KEYDOWN"); 
break;

提示:你可能需要一些花括号。

idfiyjo8

idfiyjo82#

好像是四号PostMessage函数的(lParam)参数需要不同类型的数据,而我并不知道。感谢@KungPhoo让我注意到这个参数。这篇MSDN文章解释了需要在那里输入什么。我在目标窗口上按“w”后从Spy++复制了lParam值,并将它们硬编码到我的程序中,然后按“w”在控制台中。这导致了所需的行为和没有“无限键下”的行为。只需要知道如何制作我自己的lParam

相关问题