Skip to content

Commit

Permalink
feat: 添加模拟独占全屏的功能
Browse files Browse the repository at this point in the history
  • Loading branch information
Blinue committed Dec 27, 2021
1 parent 15fa149 commit 9328748
Show file tree
Hide file tree
Showing 15 changed files with 152 additions and 16 deletions.
4 changes: 2 additions & 2 deletions Effects/FSR_EASU_DX10.hlsl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// 适用于 DirectX 功能级别 10 的 FSR_EASU
// 比原始版本稍慢
// 适用于 DirectX 功能级别 10 的 FSR_EASU
// 比原始版本稍慢

//!MAGPIE EFFECT
//!VERSION 1
Expand Down
7 changes: 5 additions & 2 deletions Magpie/MagWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ private enum FlagMasks : uint {
NoCursor = 0x1,
AdjustCursorSpeed = 0x2,
ShowFPS = 0x4,
SimulateExclusiveFullscreen = 0x8,
DisableLowLatency = 0x10,
BreakpointMode = 0x20,
DisableWindowResizing = 0x40,
Expand Down Expand Up @@ -194,7 +195,8 @@ private enum FlagMasks : uint {
bool disableDirectFlip,
bool confineCursorIn3DGames,
bool cropTitleBarOfUWP,
bool disableEffectCache
bool disableEffectCache,
bool simulateExclusiveFullscreen
) {
if (Running) {
Logger.Info("已存在全屏窗口,取消进入全屏");
Expand Down Expand Up @@ -230,7 +232,8 @@ bool disableEffectCache
(disableDirectFlip ? (uint)FlagMasks.DisableDirectFlip : 0) |
(confineCursorIn3DGames ? (uint)FlagMasks.ConfineCursorIn3DGames : 0) |
(cropTitleBarOfUWP ? (uint)FlagMasks.CropTitleBarOfUWP : 0) |
(disableEffectCache ? (uint)FlagMasks.DisableEffectCache : 0);
(disableEffectCache ? (uint)FlagMasks.DisableEffectCache : 0) |
(simulateExclusiveFullscreen ? (uint)FlagMasks.SimulateExclusiveFullscreen : 0);

_ = runEvent.Set();
Running = true;
Expand Down
3 changes: 2 additions & 1 deletion Magpie/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,8 @@ public partial class MainWindow : Window {
Settings.Default.DisableDirectFlip,
Settings.Default.ConfineCursorIn3DGames,
Settings.Default.CropTitleBarOfUWP,
Settings.Default.DebugDisableEffectCache
Settings.Default.DebugDisableEffectCache,
Settings.Default.SimulateExclusiveFullscreen
);

prevSrcWindow = magWindow.SrcWindow;
Expand Down
9 changes: 8 additions & 1 deletion Magpie/Options/AdvancedOptionsPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,15 @@
</Page.Resources>

<StackPanel>
<CheckBox Content="{x:Static props:Resources.UI_Options_Advanced_Simulate_Exclusive_Fullscreen}"
IsChecked="{Binding Source={x:Static props:Settings.Default},Path=SimulateExclusiveFullscreen,Mode=TwoWay}"/>

<StackPanel>
<Label Content="{x:Static props:Resources.UI_Options_Advanced_Logging}" FontWeight="Bold" Padding="0" FontSize="15" />
<Label Content="{x:Static props:Resources.UI_Options_Advanced_Logging}"
FontWeight="Bold"
Padding="0"
Margin="0,20,0,0"
FontSize="15" />
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<Label Content="{x:Static p:Resources.UI_Options_Advanced_Logging_Level}" Padding="0" VerticalContentAlignment="Center" />
<ComboBox x:Name="cbbLoggingLevel" Margin="10,0,0,0" SelectedIndex="{Binding Source={x:Static props:Settings.Default},Path=LoggingLevel,Mode=TwoWay}">
Expand Down
9 changes: 9 additions & 0 deletions Magpie/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions Magpie/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@
<data name="UI_Options_Advanced_Show_All_Capture_Methods" xml:space="preserve">
<value>Show All Capture Methods</value>
</data>
<data name="UI_Options_Advanced_Simulate_Exclusive_Fullscreen" xml:space="preserve">
<value>Simulate Exclusive Fullscreen</value>
</data>
<data name="UI_Options_Application" xml:space="preserve">
<value>Application</value>
</data>
Expand Down Expand Up @@ -334,12 +337,12 @@
<data name="UI_Options_Scale_Multiple_Monitors_All" xml:space="preserve">
<value>Use All Monitors</value>
</data>
<data name="UI_Options_Scale_Multiple_Monitors_Nearest" xml:space="preserve">
<value>Use the Monitor Nearest to the Source Window</value>
</data>
<data name="UI_Options_Scale_Multiple_Monitors_Intersect" xml:space="preserve">
<value>Use the Monitors that the Source Window Intersects</value>
</data>
<data name="UI_Options_Scale_Multiple_Monitors_Nearest" xml:space="preserve">
<value>Use the Monitor Nearest to the Source Window</value>
</data>
<data name="UI_Options_Scale_No_VSync" xml:space="preserve">
<value>Disable Vsync</value>
</data>
Expand Down
9 changes: 6 additions & 3 deletions Magpie/Properties/Resources.zh-CN.resx
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,9 @@
<data name="UI_Options_Advanced_Show_All_Capture_Methods" xml:space="preserve">
<value>显示所有捕获模式</value>
</data>
<data name="UI_Options_Advanced_Simulate_Exclusive_Fullscreen" xml:space="preserve">
<value>模拟独占全屏</value>
</data>
<data name="UI_Options_Application" xml:space="preserve">
<value>应用程序</value>
</data>
Expand Down Expand Up @@ -333,12 +336,12 @@
<data name="UI_Options_Scale_Multiple_Monitors_All" xml:space="preserve">
<value>使用所有显示器</value>
</data>
<data name="UI_Options_Scale_Multiple_Monitors_Nearest" xml:space="preserve">
<value>使用距离源窗口最近的显示器</value>
</data>
<data name="UI_Options_Scale_Multiple_Monitors_Intersect" xml:space="preserve">
<value>使用源窗口跨越的所有显示器</value>
</data>
<data name="UI_Options_Scale_Multiple_Monitors_Nearest" xml:space="preserve">
<value>使用距离源窗口最近的显示器</value>
</data>
<data name="UI_Options_Scale_No_VSync" xml:space="preserve">
<value>关闭垂直同步</value>
</data>
Expand Down
12 changes: 12 additions & 0 deletions Magpie/Properties/Settings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Magpie/Properties/Settings.settings
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,8 @@
<Setting Name="MultiMonitorUsage" Type="System.UInt32" Scope="User">
<Value Profile="(Default)">0</Value>
</Setting>
<Setting Name="SimulateExclusiveFullscreen" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
</Settings>
</SettingsFile>
10 changes: 8 additions & 2 deletions Runtime/App.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "GDIFrameSource.h"
#include "DwmSharedSurfaceFrameSource.h"
#include "DesktopDuplicationFrameSource.h"
#include "ExclModeHack.h"


extern std::shared_ptr<spdlog::logger> logger;
Expand Down Expand Up @@ -142,8 +143,13 @@ bool App::Run(

_hwndSrcClient = IsCropTitleBarOfUWP() ? FindClientWindow(hwndSrc) : hwndSrc;

// 模拟独占全屏
// 必须在主窗口创建前,否则 SHQueryUserNotificationState 可能返回 QUNS_BUSY 而不是 QUNS_RUNNING_D3D_FULL_SCREEN
ExclModeHack exclMode;

if (!_CreateHostWnd()) {
SPDLOG_LOGGER_CRITICAL(logger, "创建主窗口失败");
_OnQuit();
return false;
}

Expand Down Expand Up @@ -234,7 +240,7 @@ void App::_Run() {
MSG msg;
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
_OnClose();
_OnQuit();
return;
}

Expand Down Expand Up @@ -516,7 +522,7 @@ LRESULT App::_HostWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
return DefWindowProc(hWnd, message, wParam, lParam);
}

void App::_OnClose() {
void App::_OnQuit() {
// 释放资源
_frameSource = nullptr;
_renderer = nullptr;
Expand Down
8 changes: 6 additions & 2 deletions Runtime/App.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ class App {
return _flags & (UINT)_FlagMasks::DisableEffectCache;
}

bool IsSimulateExclusiveFullscreen() const {
return _flags & (UINT)_FlagMasks::SimulateExclusiveFullscreen;
}

const char* GetErrorMsg() const {
return _errorMsg;
}
Expand Down Expand Up @@ -157,7 +161,7 @@ class App {

LRESULT _HostWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

void _OnClose();
void _OnQuit();

const char* _errorMsg = ErrorMessages::GENERIC;

Expand All @@ -184,7 +188,7 @@ class App {
NoCursor = 0x1,
AdjustCursorSpeed = 0x2,
ShowFPS = 0x4,

SimulateExclusiveFullscreen = 0x8,
DisableLowLatency = 0x10,
BreakpointMode = 0x20,
DisableWindowResizing = 0x40,
Expand Down
62 changes: 62 additions & 0 deletions Runtime/ExclModeHack.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include "pch.h"
#include "ExclModeHack.h"
#include "App.h"
#include <shellapi.h>


// 模拟 D3D 独占全屏模式,以起到免打扰的效果
// SHQueryUserNotificationState 通常被用来检测是否有 D3D 游戏独占全屏,以确定是否应该向用户推送通知/弹窗
// 此函数内部使用名为 __DDrawExclMode__ 的 mutex 检测独占全屏,因此这里直接获取该 mutex 以模拟独占全屏
// 感谢 @codehz 提供的思路 https://github.com/Blinue/Magpie/issues/245
ExclModeHack::ExclModeHack() {
if (!App::GetInstance().IsSimulateExclusiveFullscreen()) {
return;
}

QUERY_USER_NOTIFICATION_STATE state;
HRESULT hr = SHQueryUserNotificationState(&state);
if (FAILED(hr)) {
SPDLOG_LOGGER_ERROR(logger, MakeComErrorMsg("SHQueryUserNotificationState 失败", hr));
return;
}
if (state != QUNS_ACCEPTS_NOTIFICATIONS) {
SPDLOG_LOGGER_INFO(logger, "已处于免打扰状态");
return;
}

_exclModeMutex.reset(Utils::SafeHandle(
OpenMutex(SYNCHRONIZE, FALSE, L"__DDrawExclMode__")));
if (!_exclModeMutex) {
SPDLOG_LOGGER_ERROR(logger, MakeWin32ErrorMsg("OpenMutex 失败"));
return;
}

DWORD result = WaitForSingleObject(_exclModeMutex.get(), 0);
if (result != WAIT_OBJECT_0) {
SPDLOG_LOGGER_ERROR(logger, "获取 __DDrawExclMode__ 失败");
_exclModeMutex.reset();
return;
}

hr = SHQueryUserNotificationState(&state);
if (FAILED(hr)) {
SPDLOG_LOGGER_ERROR(logger, MakeComErrorMsg("SHQueryUserNotificationState 失败", hr));
ReleaseMutex(_exclModeMutex.get());
_exclModeMutex.reset();
return;
}
if (state != QUNS_RUNNING_D3D_FULL_SCREEN) {
SPDLOG_LOGGER_INFO(logger, "模拟独占全屏失败");
ReleaseMutex(_exclModeMutex.get());
_exclModeMutex.reset();
return;
}

SPDLOG_LOGGER_INFO(logger, "模拟独占全屏成功");
}

ExclModeHack::~ExclModeHack() {
if (_exclModeMutex) {
ReleaseMutex(_exclModeMutex.get());
}
}
15 changes: 15 additions & 0 deletions Runtime/ExclModeHack.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once
#include "pch.h"
#include "Utils.h"


class ExclModeHack {
public:
ExclModeHack();

~ExclModeHack();

private:
Utils::ScopedHandle _exclModeMutex;
};

2 changes: 2 additions & 0 deletions Runtime/Runtime.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@
<ClInclude Include="EffectCompiler.h" />
<ClInclude Include="EffectDesc.h" />
<ClInclude Include="ErrorMessages.h" />
<ClInclude Include="ExclModeHack.h" />
<ClInclude Include="FrameRateDrawer.h" />
<ClInclude Include="FrameSourceBase.h" />
<ClInclude Include="framework.h" />
Expand All @@ -171,6 +172,7 @@
<ClCompile Include="EffectDesc.cpp" />
<ClCompile Include="EffectDrawer.cpp" />
<ClCompile Include="EffectCompiler.cpp" />
<ClCompile Include="ExclModeHack.cpp" />
<ClCompile Include="FrameRateDrawer.cpp" />
<ClCompile Include="FrameSourceBase.cpp" />
<ClCompile Include="GDIFrameSource.cpp" />
Expand Down
6 changes: 6 additions & 0 deletions Runtime/Runtime.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@
<ClCompile Include="DesktopDuplicationFrameSource.cpp">
<Filter>捕获</Filter>
</ClCompile>
<ClCompile Include="ExclModeHack.cpp">
<Filter>应用程序</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h">
Expand Down Expand Up @@ -126,6 +129,9 @@
<ClInclude Include="DesktopDuplicationFrameSource.h">
<Filter>捕获</Filter>
</ClInclude>
<ClInclude Include="ExclModeHack.h">
<Filter>应用程序</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="cpp.hint" />
Expand Down

0 comments on commit 9328748

Please sign in to comment.