【问题标题】:How can I send mouse clicks and drags to another program that is in the background?如何将鼠标点击和拖动发送到后台的另一个程序?
【发布时间】:2017-10-18 17:00:07
【问题描述】:

我正在尝试编写一个程序,它接收另一个程序(我们将其称为 P2)的视觉输出并将其显示在 3d 世界的屏幕上。

图像采集流程如下:

P2 -> BitBlt -> OpenGL Texture -> 3d World

我希望用户能够使用固定在我的程序视口中间的十字准线环顾四周并单击 P2 中的元素。但是,在我的实现中,我似乎需要 2 个光标——一个用于控制我的 3d 世界中的相机,一个用于控制 P2——我认为这不是微不足道的。

此外,由于窗口仅更新可见部分,并且我希望 P2 以尽可能高分辨率不断更新,因此将 P2 放在第二个虚拟桌面上是有意义的。这使得交互问题变得更加困难。

我能想到的一些缺点的解决方案:

  • 制作合成窗口管理器

    • 听起来工作量很大,我还没有找到任何关于如何完成这项工作的文档。
  • 将实际光标置于 P2 上,但获取光标位置的变化并使用它在 3d 世界中移动相机

    • 这不是从平面坐标到球坐标的线性变换。此外,我不确定光标是否可以位于与当前桌面不同的桌面上。

如果有帮助,我愿意接受有关替代捕获方法的建议。 一个例子是挂钩 P2 的 DirectX 或 OpenGL 输出,并在必要时诱骗它在不处于活动状态时进行渲染。这可能会使 P2 最小化,但不会解决输入问题。

也许可以挂钩P2的输入功能?这甚至会被建议吗?

这里有一些图片来说明我的程序。


更新:

我实现了SendNotifyMessage(),发现当我向应用程序发送WM_LBUTTONDOWN 消息时,它变成了前台窗口。我在 P2 上设置了WS_EX_NOACTIVATE 以阻止这种行为,但是它仍然会窃取焦点。然后我需要 Sleep(),大概直到 P2 处理消息,然后使用SetForegroundWindow()。请注意,SetFocus()SetActiveWindow() 不会导致我的程序重新获得焦点(因此可能焦点是错误的词)。有什么方法可以在保持SendNotifyMessage() 异步的同时消除这种延迟?

另外,在尝试使用PostMessage()时发现坐标变换不正确。但是,它在SendNotifyMessage() 中运行良好。什么可能导致这种行为?

相关代码

获得要捕获的窗口的句柄后,我运行以下命令:

prevWndStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, prevWndStyle | WS_EX_NOACTIVATE);

在我的WndProc 中收到WM_INPUT 消息并处理输入后,我运行以下代码:

if (raw->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) {
    int hitX, hitY;
    if (gls->Click(vec3(0.0f, 0.0f, 1.0f), 0, hitX, hitY)) {
        LPARAM lParam = MAKELPARAM(hitX, hitY);
        SendNotifyMessage(gls->ic.GetHWND(), WM_MOUSEMOVE, 0, lParam);
        SendNotifyMessage(gls->ic.GetHWND(), WM_LBUTTONDOWN, MK_LBUTTON, lParam);
        SendNotifyMessage(gls->ic.GetHWND(), WM_LBUTTONUP, 0, lParam);

        // I want to get rid of these
        Sleep(100);
        SetForegroundWindow(gls->aw.GetHWND());
    }
}

更新 2

我发现WS_EX_NOACTIVATE 会停止切换到第二个桌面,但是当 P2 在同一个桌面上时,P2 会被带到前台。

【问题讨论】:

  • +1,因为总体而言,这似乎是个有趣的问题。但我真的不明白关键问题是什么。您几乎已经清楚地表明,台式机中的内置光标处理不会削减它,那么为什么不根据您的需要“做它”呢?
  • 1) FindWindow() 2) 连续截取窗口截图 3) 将点转换为相对于窗口 4) SendMessage() 鼠标点击窗口。 以后有时间我会给出更详细的答案,如果那时没有其他人做过。
  • @Andreas 我不太清楚你所说的“就这么做”是什么意思。问题是我不知道该怎么做。能详细点吗?
  • @Vallentin 谢谢你的建议。我实现了SendNotifyMessage(),发现当我向应用程序发送 WM_LBUTTONDOWN 消息时,它变成了前台窗口。我在 P2 上设置了WS_EX_NOACTIVATE 以阻止这种行为,但是它仍然会窃取焦点。然后我需要Sleep(),大概直到P2处理完消息,然后使用SetForegroundWindow()。请注意,SetFocusSetActiveWindow() 不会导致我的程序重新获得焦点(因此可能焦点是错误的词)。有什么方法可以在保持SendMessage() 异步的同时消除这种延迟?
  • 我会尝试详细说明。你有 P1 和 P2。两者都有“光标”。当 P1 处于焦点时,P1 光标控制 P1 和 P2,反之亦然。当 PX 失焦时,从 PY 中检索其位置。这是个问题吗?

标签: c++ windows opengl screen-capture


【解决方案1】:

我认为您可以使用 WIN32API 来模拟点击并捕获窗口内容,我以前在不同的 3d“窗口”环境中看到过它,我也看到过它在像 Termina Server 这样的东西中完成。

所以也许当“他们点击你时,你将点击向前传递”(在进行坐标转换时)?

一些链接供您阅读:

https://msdn.microsoft.com/en-us/library/windows/desktop/gg153548%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

http://www.cplusplus.com/forum/windows/24162/

【讨论】:

  • 感谢您的回答。我已经实现了SendNotifyMessage(),但我遇到了窗口焦点的问题。我已经更新了我的问题以反映这一点。
  • 或许可以创建一个虚拟桌面?
  • P2 已经在另一个虚拟桌面上。在我在 P2 上设置 WS_EX_NOACTIVATE 之前,它会切换到该桌面。现在我必须先Sleep(),然后再SetForegroundWindow(),然后我的程序才能获得键盘和鼠标焦点。
猜你喜欢
  • 2012-05-31
  • 1970-01-01
  • 2019-12-10
  • 2011-08-27
  • 1970-01-01
  • 2011-07-19
  • 2019-06-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多