Полноэкранный режим на мониторе А в настройке с двумя мониторами прерывается при перемещении окон с монитора Б на него

Я создаю настольное приложение Win7/8/10 x64 Direct3D11, которое позволяет пользователю переключаться между оконным и полноэкранным режимами (правильный выделенный полноэкранный режим, а не просто развернутое окно*). При настройке с двумя мониторами я сталкиваюсь с некоторыми проблемами.

Само переключение выполняется вручную с помощью IDXGISwapChain::SetFullscreenState и работает по назначению: монитор, занимающий львиную долю площади окна (назовем его монитором А), переходит в выделенный полноэкранный режим, а другой (монитор Б) остается без изменений, позволяя пользователю нормально взаимодействовать с окнами на B, а также с полноэкранным приложением на A.

Однако, если окно на B перетаскивается или изменяется в размере так, что оно переходит в A, полноэкранное состояние приложения нарушается: иногда оно просто возвращается обратно в оконный режим (оставляя внутреннюю переменную отслеживания приложения не синхронизированной), иногда оно остается в квазиполноэкранный режим, в котором он, по-видимому, отказывается от дальнейших переключений режима и так далее. То же самое происходит, если окно, которое перекрывает окна A и B до того, как приложение перешло в полноэкранный режим, получает фокус.

Есть ли способ предотвратить это?

Я бы хотел, чтобы ОС учитывала выделенный полноэкранный режим моего приложения и поддерживала его в надежном состоянии, даже если другие окна перетаскиваются на этот монитор. Я бы хотел, чтобы поведение было похоже на наличие «всегда наверху, развернутого окна без полей» вместо него, то есть чтобы другие окна просто «исчезали за ним» и вообще не влияли на состояние моего полноэкранного окна.

Я пробовал некоторые обходные пути, такие как ответ на WM_KILLFOCUS и временное переключение моего приложения в «максимально смешанное окно без полей», пока оно снова не получит WM_SETFOCUS, но сообщение WM_KILLFOCUS имеет задержку, в течение которой у пользователя есть время перетащить другое окно в область то есть все еще в полноэкранном режиме, тем самым возвращая меня к исходной точке.


* Причина, по которой мне нужна эта функция, а не просто использование развернутого окна без полей (которое также является поддерживаемым режимом, кстати), связана с тем, что она позволяет значительно снизить задержку от движения мыши до рендеринга, управление вертикальной синхронизацией (ВКЛ / ВЫКЛ) и т. д.. короче говоря, все это важно для характера этого приложения (которое не является игрой).


person d7samurai    schedule 16.08.2015    source источник


Ответы (1)


Хотя это и не идеально (идеально было бы, если бы ОС сама справлялась с этим должным образом), я нашел разумный обходной путь, с которым, полагаю, пока могу жить. Это вариант концепции, упомянутой в вопросе («... например, ответ на WM_KILLFOCUS и временное переключение моего приложения в максимиксированное окно без полей..»), но без проблемы с задержкой:

Всякий раз, когда приложение входит в выделенный полноэкранный режим, оно также захватывает мышь вызовом SetCapture. Это не повлияет на способность пользователя взаимодействовать с другими окнами на мониторе B, но гарантирует, что любое такое деактивирующее взаимодействие — например, щелчок мышью в другом приложении — отправит WM_LBUTTONDOWN моему приложению. прежде чем он потеряет фокус. Важно отметить, что это происходит немедленно, в отличие от сообщения WM_KILLFOCUS, которое имеет значительную задержку.

Когда такое WM_LBUTTONDOWN сообщение получено (в полноэкранном режиме), приложение проверяет, не произошло ли нажатие за пределами его области экрана. Если это так, это означает, что он вот-вот потеряет фокус и, таким образом, подвергнется всем осложнениям, поднятым в исходном вопросе. Таким образом, он временно выходит из выделенного полноэкранного режима и «заменяет» его (визуально идентичным) развернутым окном без полей. Когда приложение восстанавливает фокус, оно возвращается в выделенный полноэкранный режим.

Это работает нормально, поскольку вас не волнует скорость отклика приложения, когда вы все равно не взаимодействуете с ним. Самым большим неудобством здесь является мерцание переключателя режима, возникающее при этих передачах фокуса, но, учитывая альтернативы, я считаю, что это приемлемая цена за то, чего я хочу достичь (но во что бы то ни стало - я был бы очень< /em> интересует лучшее решение).


Редактировать 1: Стоит отметить, что, поскольку существуют другие способы потери фокуса приложения, кроме щелчков мыши, WM_KILLFOCUS также обрабатывается.


Редактировать 2: недавно я понял, что обработка сообщения WM_BUTTONDOWN избыточна. Только SetCapture гарантирует, что сообщение WM_KILLFOCUS будет получено достаточно быстро.

person d7samurai    schedule 17.08.2015