当监视器B将窗口移动到监视器上时,双监视器设置中的监视器A上的全屏模式会中断

d7s*_*rai 9 c++ winapi multiple-monitors fullscreen direct3d11

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

交换机本身是手动执行的IDXGISwapChain::SetFullscreenState,并按预期工作:占据窗口区域狮子的显示器(让我们称之为监视器A)进入专用全屏模式,而另一个(监视器B)保持原样,允许用户与B上的窗口以及A上的全屏应用程序正常交互.

但是,如果拖动或调整B上的窗口使其跨越到A,则应用程序的全屏状态会受到干扰:有时它只会恢复到窗口模式(使应用程序的内部跟踪变量不同步),有时会保持不变准全屏模式,它似乎拒绝进一步的模式切换,等等.如果在应用程序进入全屏模式之前与A和B重叠的窗口获得焦点,则会发生同样的情况.

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

我希望操作系统能够尊重我的应用程序的专用全屏模式,并将其保持在稳健状态,即使其他窗口被拖动到该监视器上也是如此.我希望这种行为类似于拥有一个"永远在顶部,最大化的无边界窗口",即让其他窗口"消失在它后面"并且根本不影响我的全屏窗口的状态.

我已经尝试了一些解决方法,比如响应WM_KILLFOCUS并暂时将我的应用程序切换到"最大化无边界窗口",直到它WM_SETFOCUS再次收到,但是WM_KILLFOCUS消息有一个滞后期间,用户有时间将另一个窗口拖到当时的区域仍处于全屏模式,从而让我回到原点.


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

d7s*_*rai 2

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

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

当收到此类WM_LBUTTONDOWN消息时(在全屏模式下),应用程序会检查单击是否发生在其屏幕区域之外。如果是这样,则意味着它将失去焦点,从而使自己面临最初问题中提出的所有复杂情况。因此,它暂时退出专用全屏模式,并用(视觉上相同的)无边框最大化窗口“替换”它。当应用程序重新获得焦点时,它会返回专用全屏。

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


编辑 1:值得注意的是,由于应用程序还有其他方式失去焦点,而不是通过鼠标单击,因此WM_KILLFOCUS进行了处理。


编辑2:我最近意识到处理WM_BUTTONDOWN消息是多余的。SetCapture仅此一项就可以确保WM_KILLFOCUS足够快地接收消息。