将窗口从监视器B移动到监视器上时,双监视器设置中监视器A的全屏模式会中断 [英] Fullscreen mode on monitor A in dual-monitor setup breaks when moving windows from monitor B onto it

查看:170
本文介绍了将窗口从监视器B移动到监视器上时,双监视器设置中监视器A的全屏模式会中断的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

该开关本身是使用IDXGISwapChain::SetFullscreenState手动执行的,并且可以按预期工作:容纳大部分窗口区域的监视器(称为监视器A)进入专用的全屏模式,而另一监视器(监视器B)则保持为全屏模式.是的,它允许用户与B上的窗口以及A上的全屏应用程序正常交互.

但是,如果拖动或调整B上的窗口大小以使其越过A,则应用程序的全屏状态会受到干扰:有时它会返回到窗口模式(使应用程序的内部跟踪变量不同步),有时它保持在准全屏模式,在该模式下它似乎拒绝进一步的模式切换,依此类推.如果在应用程序进入全屏模式之前重叠了A和B的窗口获得焦点,就会发生同样的事情.

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

我希望操作系统会尊重我的应用程序专用的全屏模式,即使将其他窗口拖到该显示器上也能使其保持稳定状态.我希望它的行为类似于具有始终位于顶部的,最大化的无边界窗口",即让其他窗口仅在其后消失"而根本不影响全屏窗口的状态./p>

我尝试了一些解决方法,例如响应WM_KILLFOCUS并将我的应用程序临时切换到最大无边界窗口",直到它再次接收到WM_SETFOCUS,但是WM_KILLFOCUS消息有一个滞后,在这段时间内会有时间用户将另一个窗口拖动到仍处于全屏模式的区域,从而将我设置回方形.


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

解决方案

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

只要应用程序进入专用的全屏模式,它就会通过调用SetCapture捕获鼠标.这不会影响用户与监视器B上其他窗口进行交互的能力,但是 将确保任何此类取消激活的交互(例如在其他应用程序中单击鼠标)将向计算机发送WM_LBUTTONDOWN我的应用程序之前失去了焦点.重要的是,这种情况立即发生,与WM_KILLFOCUS消息具有明显的延迟不同.

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

这行得通,因为当您不与之交互时,您实际上并不关心应用程序的响应能力.这里最大的不便是在这些焦点转移上发生的模式切换闪烁,但是考虑到其他选择,我发现为完成我想完成的工作付出了合理的代价(但无论如何,我会非常对更好的解决方案感兴趣).


值得注意的是,由于除了通过鼠标单击之外,应用程序还有其他失去焦点的方法,因此也可以 处理.


我最近意识到处理WM_BUTTONDOWN消息是多余的.仅SetCapture可以确保WM_KILLFOCUS消息被足够快地接收.

I am building a Win7/8/10 x64 Direct3D11 desktop application that allows the user to switch between windowed and fullscreen mode (proper dedicated fullscreen mode, not just a maximized window*). On a dual-monitor setup I am encountering some issues.

The switch itself is performed manually using IDXGISwapChain::SetFullscreenState and works as intended: The monitor that houses the lion's share of the window area (let's call it monitor A) goes into dedicated fullscreen mode while leaving the other (monitor B) as it was, allowing the user to interact normally with windows on B as well as the fullscreen application on A.

However, if a window on B is dragged or resized so that it crosses over to A, the application's fullscreen state gets disturbed: Sometimes it just reverts back to windowed mode (leaving the application's internal tracking variable out of sync), sometimes it stays in a quasi fullscreen mode where it seemingly refuses further mode switches, and so on. The same thing happens if a window that overlapped both A and B before the application went into fullscreen mode gets focus.

Is there any way to prevent this?

I wish the OS would honor my application's dedicated fullscreen mode and keep it in a robust state even if other windows are dragged onto that monitor. I'd want the behavior to be similar to having an "always-on-top, maximized borderless window" in its stead, i.e. have other windows just "disappear behind it" and not affect the state of my fullscreen window at all.

I have tried some workarounds, like responding to WM_KILLFOCUS and temporarily switching my application into a "maximixed borderless window" until it receives WM_SETFOCUS again, but the WM_KILLFOCUS message has a lag during which there is time for a user to drag another window into the area that is then still in fullscreen mode, thereby setting me back to square one.


*The reason I want this feature rather than simply using a maximized borderless window (which is also a supported mode, btw) has to do with it allowing for much lower mouse-movement-to-rendering latency, vsync control (ON/OFF) etc.. all of which are - in short - important to the nature of this application (which is not a game).

解决方案

Although not ideal (ideal would be that there was a way to have the OS itself handle this properly), I have found a reasonable workaround that I suppose I can live with for now. It is a variation of the concept mentioned in the question ("..like responding to WM_KILLFOCUS and temporarily switching my application into a maximixed borderless window.."), but without the crippling delay problem:

Whenever the application enters dedicated fullscreen mode, it also captures the mouse with a call to SetCapture. This will not affect the user's ability to interact with other windows on monitor B, but it will ensure that any such de/activating interaction - like a mouse click in another application - will send a WM_LBUTTONDOWN to my application before it loses focus. Importantly, this happens immediately, unlike the WM_KILLFOCUS message that has significant latency.

When such a WM_LBUTTONDOWN message is received (while in fullscreen), the application checks whether the click happened outside its screen area. If so, it means it is about to lose focus and thus expose itself to all the complications brought up in the original question. So it temporarily exits dedicated fullscreen mode and "replaces" it with a (visually identical) borderless maximized window. When the application regains focus, it goes back into dedicated fullscreen.

This works OK, since you don't really care about the application's responsiveness when you're not interacting with it anyway. The biggest inconvenience here is the mode switch flickering that occurs on these focus transfers, but given the alternatives, I find it an acceptable price to pay for what I want to accomplish (but by all means - I'd be very interested in a better solution).


Edit 1: It is worth noting that since there are other ways for an application to lose focus than through mouse clicks, WM_KILLFOCUS is also handled.


Edit 2: I recently realized that handling the WM_BUTTONDOWN message is redundant. SetCapture alone will ensure that the WM_KILLFOCUS message is received quickly enough.

这篇关于将窗口从监视器B移动到监视器上时,双监视器设置中监视器A的全屏模式会中断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆