在双显示器设置中,监视器A的全屏模式在将窗口从监视器B移动到监视器B时中断

Fullscreen mode on monitor A in dual-monitor setup breaks when moving windows from monitor B onto it

本文关键字:监视器 窗口 中断 移动 模式 设置 显示器 双显示      更新时间:2023-10-16

我正在构建一个Win7/8/10 x64 Direct3D11桌面应用程序,允许用户在窗口和全屏模式之间切换(适当的专用全屏模式,而不仅仅是最大化窗口*)。在双显示器设置下,我遇到了一些问题。

切换本身是使用IDXGISwapChain::SetFullscreenState手动执行的,并按预期工作:容纳最大份额窗口区域的监视器(我们称之为监视器A)进入专用全屏模式,而另一个监视器(监视器B)保持原样,允许用户与B上的窗口以及A上的全屏应用程序进行正常交互。

然而,如果B上的窗口被拖拽或调整大小,使其跨越到a上,则应用程序的全屏状态受到干扰:有时它只是恢复到窗口模式(使应用程序的内部跟踪变量不同步),有时它停留在准全屏模式,似乎拒绝进一步的模式切换,等等。如果在应用程序进入全屏模式之前,一个与a和B重叠的窗口获得焦点,也会发生同样的事情。

有什么方法可以防止这种情况吗?

我希望操作系统能尊重我的应用程序专用的全屏模式,并保持它在一个健壮的状态,即使其他窗口被拖到显示器上。我想要的行为类似于有一个"总是在顶部,最大化的无边框窗口"在它的代替,即有其他窗口只是"消失在它后面",不影响我的全屏窗口的状态。

我尝试了一些变通方法,如响应WM_KILLFOCUS,并暂时将我的应用程序切换为"最大化无边界窗口",直到它再次接收WM_SETFOCUS,但WM_KILLFOCUS消息有一个延迟,在此期间,用户有时间将另一个窗口拖到然后仍处于全屏模式的区域,从而使我回到第一。


*我想要这个功能,而不是简单地使用一个最大化的无边界窗口(这也是一个支持的模式,顺便说一句)的原因是它允许更低的鼠标移动到渲染延迟,垂直同步控制(ON/OFF)等。简而言之,所有这些对这个应用程序的性质都很重要(它不是一个游戏)。

虽然不理想(理想的是有一种方法让操作系统本身正确处理这个问题),但我已经找到了一个合理的解决方案,我想我现在可以接受。它是问题("……")中提到的概念的一种变体。比如响应WM_KILLFOCUS并暂时将我的应用程序切换到最大化无边界窗口…"),但没有严重的延迟问题:

当应用程序进入专用全屏模式时,它也通过调用SetCapture来捕获鼠标。这不会影响用户与监视器B上的其他窗口交互的能力,但是它确保任何这样的取消/激活交互-例如在另一个应用程序中单击鼠标-将在失去焦点之前向我的应用程序发送WM_LBUTTONDOWN。重要的是,这是立即发生的,不像WM_KILLFOCUS消息具有明显的延迟。

当收到这样的WM_LBUTTONDOWN消息时(在全屏时),应用程序检查点击是否发生在其屏幕区域之外。如果是这样,这意味着它即将失去焦点,从而使自己暴露于最初问题中提出的所有复杂情况。因此,它暂时退出专用的全屏模式,并以(视觉上相同的)无边界最大化窗口"取代"它。当应用程序恢复焦点时,它将返回专用全屏。

这工作得很好,因为当你不与应用程序交互时,你并不真正关心它的响应性。这里最大的不便是在这些焦点转移时发生的模式切换闪烁,但考虑到替代方案,我发现为我想要完成的任务付出的代价是可以接受的(但无论如何-我会非常对更好的解决方案感兴趣)。


编辑1:值得注意的是,由于除了通过鼠标点击之外,还有其他方法可以使应用程序失去焦点,因此WM_KILLFOCUS也被处理。


编辑2:我最近意识到处理WM_BUTTONDOWN消息是多余的。SetCapture单独将确保WM_KILLFOCUS消息被足够快地接收。