双显示器设置中,将窗口从B显示器移动到A显示器时,A显示器的全屏模式会出现问题。

9
我正在构建一个Win7/8/10 x64 Direct3D11桌面应用程序,允许用户在窗口模式和全屏模式之间切换(正确的专用全屏模式,而不仅仅是最大化的窗口*)。在双显示器设置中,我遇到了一些问题。
切换本身是使用 IDXGISwapChain :: SetFullscreenState 手动执行并按预期工作:包含窗口区域大部分的显示器(称为监视器 A)进入专用全屏模式,同时保持另一个显示器(监视器 B)不变,使用户可以正常与窗口 B 上的窗口以及全屏应用程序 A 进行交互。
然而,如果拖动或调整 B 上的窗口,使其越过到 A 上,应用程序的全屏状态会被破坏:有时它只是恢复回窗口模式(使应用程序内部跟踪变量失步),有时它保持准全屏模式,在这种模式下它似乎拒绝进一步的模式切换等。如果那个应用程序去全屏模式之前重叠了 A 和 B 的窗口获得焦点,同样的事情也会发生。 有没有任何方法可以防止这种情况发生? 我希望操作系统尊重我的应用程序的专用全屏模式,并保持其处于稳定状态,即使其他窗口被拖动到该监视器上。我希望行为类似于在其位置上有一个“始终在顶部,最大化的无边框窗口”,即其他窗口只是“消失在它后面”,并且不会影响我的全屏窗口状态。
我已经尝试了一些解决方法,例如响应 WM_KILLFOCUS 并临时将应用程序切换为“最大化的无边框窗口”,直到它再次接收到 WM_SETFOCUS,但是 WM_KILLFOCUS 消息有一个延迟,在这段时间内,用户有时间将另一个窗口拖动到仍处于全屏模式的区域中,从而使我回到原点。
*我想要这个功能的原因不是简单地使用最大化的无边框窗口(也支持此模式),而是因为它允许更低的鼠标移动到渲染延迟,vsync 控制(开/关)等等...所有这些都是-简而言之-对这个应用程序的性质非常重要(这不是游戏)。
1个回答

2
尽管不是理想的解决方法(理想的解决方法是操作系统本身能够正确处理此类问题),但我已经找到了一个可以接受的变通方法,目前我可以使用它。这是在问题中提到的概念的一种变体(“...比如响应WM_KILLFOCUS并将我的应用程序暂时切换到最大化的无边框窗口...”),但没有延迟问题:
每当应用程序进入专用全屏模式时,它还会通过调用SetCapture来捕获鼠标。这不会影响用户与B显示器上其他窗口交互的能力,但它确保任何这样的激活/取消激活交互 - 比如在另一个应用程序中单击鼠标 - 将在失去焦点之前向我的应用程序发送一个WM_LBUTTONDOWN消息。重要的是,这发生得非常快,不像WM_KILLFOCUS消息那样有明显的延迟。
在全屏状态下收到WM_LBUTTONDOWN消息时,应用程序会检查单击是否发生在其屏幕区域之外。如果是这样,它意味着它即将失去焦点,并因此暴露给原始问题中提出的所有复杂性。因此,它会暂时退出专用全屏模式,并用(在视觉上相同的)无边框最大化窗口“替换”它。当应用程序重新获得焦点时,它会回到专用全屏状态。
这个方法还算可以,因为当你不与应用程序交互时,你并不真正关心应用程序的响应能力。这里最大的不便之处是在这些焦点转移时发生的模式切换闪烁,但考虑到其他选择,我认为这是一个可以接受的代价(但是请务必注意 - 如果有更好的解决方案,我会非常感兴趣)。
编辑1:值得注意的是,由于应用程序失去焦点的方式不仅仅是通过鼠标单击,WM_KILLFOCUS也被处理了。
编辑2:我最近意识到处理WM_BUTTONDOWN消息是多余的。仅使用SetCapture就足以确保快速收到WM_KILLFOCUS消息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接