mirror of
https://github.com/Blinue/Magpie.git
synced 2026-06-24 02:04:10 +00:00
全屏缩放默认不再置顶 (#1216)
* feat: 全屏缩放时默认不再置顶,添加置顶选项 * fix: 修复消息弹窗会使窗口取消置顶的问题 * fix: 修复消息弹窗弹出动画 bug
This commit is contained in:
parent
62a41d8da8
commit
d1076bbb95
24 changed files with 179 additions and 101 deletions
|
|
@ -7,7 +7,7 @@ namespace Magpie {
|
|||
// 根据需要在交换链和 DirectComposition 两种呈现方式间切换。交换链可以触发
|
||||
// DirectFlip/IndependentFlip 以最小化延迟,DirectComposition 在调整尺寸
|
||||
// 时闪烁更少,这个呈现器旨在结合两者的优势。
|
||||
class AdaptivePresenter : public PresenterBase {
|
||||
class AdaptivePresenter final : public PresenterBase {
|
||||
protected:
|
||||
bool _Initialize(HWND hwndAttach) noexcept override;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
namespace Magpie {
|
||||
|
||||
class CompSwapchainPresenter : public PresenterBase {
|
||||
class CompSwapchainPresenter final : public PresenterBase {
|
||||
protected:
|
||||
bool _Initialize(HWND hwndAttach) noexcept override;
|
||||
|
||||
|
|
|
|||
|
|
@ -36,46 +36,6 @@ static std::string LogEffects(const std::vector<EffectOption>& effects) noexcept
|
|||
return result;
|
||||
}
|
||||
|
||||
bool ScalingOptions::Prepare() noexcept {
|
||||
if (screenshotsDir.empty()) {
|
||||
Logger::Get().Error("screenshotsDir 为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!showToast) {
|
||||
Logger::Get().Error("showToast 为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!showError) {
|
||||
Logger::Get().Error("showError 为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!save) {
|
||||
Logger::Get().Error("save 为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsWindowedMode()) {
|
||||
if (Is3DGameMode()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Desktop Duplication 不支持窗口模式缩放
|
||||
if (captureMethod == CaptureMethod::DesktopDuplication) {
|
||||
captureMethod = CaptureMethod::GraphicsCapture;
|
||||
}
|
||||
}
|
||||
|
||||
// GDI 和 DwmSharedSurface 不支持捕获标题栏
|
||||
if (captureMethod == CaptureMethod::GDI || captureMethod == CaptureMethod::DwmSharedSurface) {
|
||||
IsCaptureTitleBar(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScalingOptions::Log() const noexcept {
|
||||
Logger::Get().Info(fmt::format(R"(缩放选项
|
||||
IsWindowedMode: {}
|
||||
|
|
|
|||
|
|
@ -51,9 +51,7 @@ ScalingRuntime::~ScalingRuntime() {
|
|||
}
|
||||
|
||||
bool ScalingRuntime::Start(HWND hwndSrc, ScalingOptions&& options) {
|
||||
if (!options.Prepare()) {
|
||||
return false;
|
||||
}
|
||||
assert(!options.screenshotsDir.empty() && options.showToast && options.showError && options.save);
|
||||
|
||||
_Dispatcher().TryEnqueue([this, hwndSrc, options(std::move(options))]() mutable {
|
||||
// 初始化时视为处于缩放状态
|
||||
|
|
|
|||
|
|
@ -47,6 +47,29 @@ static void LogRects(const RECT& srcRect, const RECT& rendererRect, const RECT&
|
|||
}
|
||||
|
||||
ScalingError ScalingWindow::_StartImpl(HWND hwndSrc) noexcept {
|
||||
Logger::Get().Info(fmt::format("缩放开始\n\t程序版本: {}\n\tOS 版本: {}\n\t管理员: {}",
|
||||
#ifdef MP_VERSION_TAG
|
||||
STRING(MP_VERSION_TAG),
|
||||
#else
|
||||
"dev",
|
||||
#endif
|
||||
Win32Helper::GetOSVersion().ToString<char>(),
|
||||
Win32Helper::IsProcessElevated() ? "是" : "否"
|
||||
));
|
||||
|
||||
if (_options.IsWindowedMode()) {
|
||||
if (_options.Is3DGameMode()) {
|
||||
return ScalingError::Windowed3DGameMode;
|
||||
} else if (_options.captureMethod == CaptureMethod::DesktopDuplication) {
|
||||
return ScalingError::WindowedDesktopDuplication;
|
||||
}
|
||||
}
|
||||
|
||||
if (FindWindow(CommonSharedConstants::SCALING_WINDOW_CLASS_NAME, nullptr)) {
|
||||
Logger::Get().Error("已存在缩放窗口");
|
||||
return ScalingError::ScalingFailedGeneral;
|
||||
}
|
||||
|
||||
InitMessage();
|
||||
|
||||
_runtimeError = ScalingError::NoError;
|
||||
|
|
@ -58,21 +81,6 @@ ScalingError ScalingWindow::_StartImpl(HWND hwndSrc) noexcept {
|
|||
_areResizeHelperWindowsVisible = false;
|
||||
_isSrcRepositioning = false;
|
||||
|
||||
if (FindWindow(CommonSharedConstants::SCALING_WINDOW_CLASS_NAME, nullptr)) {
|
||||
Logger::Get().Error("已存在缩放窗口");
|
||||
return ScalingError::ScalingFailedGeneral;
|
||||
}
|
||||
|
||||
Logger::Get().Info(fmt::format("缩放开始\n\t程序版本: {}\n\tOS 版本: {}\n\t管理员: {}",
|
||||
#ifdef MP_VERSION_TAG
|
||||
STRING(MP_VERSION_TAG),
|
||||
#else
|
||||
"dev",
|
||||
#endif
|
||||
Win32Helper::GetOSVersion().ToString<char>(),
|
||||
Win32Helper::IsProcessElevated() ? "是" : "否"
|
||||
));
|
||||
|
||||
if (ScalingError error = _srcTracker.Set(hwndSrc, _options); error != ScalingError::NoError) {
|
||||
Logger::Get().Error("初始化 SrcTracker 失败");
|
||||
return error;
|
||||
|
|
@ -82,7 +90,7 @@ ScalingError ScalingWindow::_StartImpl(HWND hwndSrc) noexcept {
|
|||
if (_options.IsWindowedMode()) {
|
||||
Logger::Get().Info("已最大化的窗口不支持窗口模式缩放");
|
||||
return ScalingError::BannedInWindowedMode;
|
||||
} else if (!_options.IsAllowScalingMaximized()) {
|
||||
} else if (!_options.RealIsAllowScalingMaximized()) {
|
||||
Logger::Get().Info("源窗口已最大化");
|
||||
return ScalingError::Maximized;
|
||||
}
|
||||
|
|
@ -1190,7 +1198,7 @@ void ScalingWindow::_Show() noexcept {
|
|||
}
|
||||
|
||||
// 模拟独占全屏
|
||||
if (_options.IsSimulateExclusiveFullscreen()) {
|
||||
if (_options.RealIsSimulateExclusiveFullscreen()) {
|
||||
// 延迟 1s 以避免干扰游戏的初始化,见 #495
|
||||
([]()->winrt::fire_and_forget {
|
||||
const uint32_t runId = RunId();
|
||||
|
|
@ -1819,7 +1827,7 @@ winrt::fire_and_forget ScalingWindow::_UpdateFocusStateAsync(
|
|||
}
|
||||
|
||||
if (_srcTracker.IsOwnedWindowFocused() ||
|
||||
(!onSrcOwnedWindowFocusedChanged && !_options.IsWindowedMode()))
|
||||
(_options.RealIsKeepOnTop() && !onSrcOwnedWindowFocusedChanged))
|
||||
{
|
||||
if (!onShow) {
|
||||
const uint32_t runId = RunId();
|
||||
|
|
@ -1844,8 +1852,8 @@ winrt::fire_and_forget ScalingWindow::_UpdateFocusStateAsync(
|
|||
const HWND hwndPrev = GetWindow(_srcTracker.Handle(), GW_HWNDPREV);
|
||||
SetWindowPos(Handle(), hwndPrev,
|
||||
0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
|
||||
} else if (!onSrcOwnedWindowFocusedChanged && !_options.IsWindowedMode()) {
|
||||
// 源窗口位于前台时将缩放窗口置顶,这使不支持 MPO 的显卡更容易激活 DirectFlip
|
||||
} else if (_options.RealIsKeepOnTop() && !onSrcOwnedWindowFocusedChanged) {
|
||||
// 源窗口位于前台时将缩放窗口置顶
|
||||
if (_srcTracker.IsFocused()) {
|
||||
if (!_options.IsDebugMode()) {
|
||||
SetWindowPos(Handle(), HWND_TOPMOST,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ namespace Magpie {
|
|||
|
||||
class CursorManager;
|
||||
|
||||
class ScalingWindow : public WindowBaseT<ScalingWindow> {
|
||||
class ScalingWindow final : public WindowBaseT<ScalingWindow> {
|
||||
using base_type = WindowBaseT<ScalingWindow>;
|
||||
friend base_type;
|
||||
|
||||
|
|
|
|||
|
|
@ -435,8 +435,10 @@ ScalingError SrcTracker::_CalcSrcRect(const ScalingOptions& options, LONG border
|
|||
// DWM 绘制,前者无需裁剪,后者不能裁剪。
|
||||
_srcRect = _windowRect;
|
||||
} else {
|
||||
const bool isCaptureTitleBar = options.RealIsCaptureTitleBar();
|
||||
|
||||
// UWP 窗口都是 NoTitleBar 类型,但可能使用子窗口作为“客户区”
|
||||
if (_windowKind == SrcWindowKind::NoTitleBar && !options.IsCaptureTitleBar() && GetClientRectOfUWP(_hWnd, _srcRect)) {
|
||||
if (_windowKind == SrcWindowKind::NoTitleBar && !isCaptureTitleBar && GetClientRectOfUWP(_hWnd, _srcRect)) {
|
||||
_srcRect.top = std::max(_srcRect.top, _windowFrameRect.top + borderThicknessInFrame);
|
||||
} else {
|
||||
_srcRect.left = _windowFrameRect.left + borderThicknessInFrame;
|
||||
|
|
@ -444,7 +446,7 @@ ScalingError SrcTracker::_CalcSrcRect(const ScalingOptions& options, LONG border
|
|||
_srcRect.right = _windowFrameRect.right - borderThicknessInFrame;
|
||||
_srcRect.bottom = _windowFrameRect.bottom - borderThicknessInFrame;
|
||||
|
||||
if (!options.IsCaptureTitleBar() || _windowKind == SrcWindowKind::OnlyThickFrame) {
|
||||
if (!isCaptureTitleBar || _windowKind == SrcWindowKind::OnlyThickFrame) {
|
||||
RECT clientRect;
|
||||
if (!Win32Helper::GetClientScreenRect(_hWnd, clientRect)) {
|
||||
Logger::Get().Error("GetClientScreenRect 失败");
|
||||
|
|
|
|||
|
|
@ -56,11 +56,12 @@ struct ScalingFlags {
|
|||
static constexpr uint32_t AllowScalingMaximized = 1 << 15;
|
||||
static constexpr uint32_t EnableStatisticsForDynamicDetection = 1 << 16;
|
||||
// 只影响缩放行为,Magpie.Core 不负责启动 TouchHelper.exe
|
||||
static constexpr uint32_t IsTouchSupportEnabled = 1 << 17;
|
||||
static constexpr uint32_t TouchSupportEnabled = 1 << 17;
|
||||
static constexpr uint32_t InlineParams = 1 << 18;
|
||||
static constexpr uint32_t IsFP16Disabled = 1 << 19;
|
||||
static constexpr uint32_t FP16Disabled = 1 << 19;
|
||||
static constexpr uint32_t BenchmarkMode = 1 << 20;
|
||||
static constexpr uint32_t DeveloperMode = 1 << 21;
|
||||
static constexpr uint32_t KeepOnTop = 1 << 22;
|
||||
};
|
||||
|
||||
enum class ScalingType {
|
||||
|
|
@ -127,6 +128,8 @@ enum class ScalingError {
|
|||
TouchSupport,
|
||||
// 3D 游戏模式下不支持窗口模式缩放
|
||||
Windowed3DGameMode,
|
||||
// Desktop Duplication 不支持窗口模式缩放
|
||||
WindowedDesktopDuplication,
|
||||
// 通用的不支持缩放错误
|
||||
InvalidSourceWindow,
|
||||
// 因窗口已最大化或全屏而无法缩放,可通过更改设置强制缩放
|
||||
|
|
@ -157,24 +160,22 @@ struct ScalingOptions {
|
|||
DEFINE_FLAG_ACCESSOR(IsDeveloperMode, ScalingFlags::DeveloperMode, flags)
|
||||
DEFINE_FLAG_ACCESSOR(IsDebugMode, ScalingFlags::DebugMode, flags)
|
||||
DEFINE_FLAG_ACCESSOR(IsBenchmarkMode, ScalingFlags::BenchmarkMode, flags)
|
||||
DEFINE_FLAG_ACCESSOR(IsFP16Disabled, ScalingFlags::IsFP16Disabled, flags)
|
||||
DEFINE_FLAG_ACCESSOR(IsFP16Disabled, ScalingFlags::FP16Disabled, flags)
|
||||
DEFINE_FLAG_ACCESSOR(IsEffectCacheDisabled, ScalingFlags::DisableEffectCache, flags)
|
||||
DEFINE_FLAG_ACCESSOR(IsFontCacheDisabled, ScalingFlags::DisableFontCache, flags)
|
||||
DEFINE_FLAG_ACCESSOR(IsSaveEffectSources, ScalingFlags::SaveEffectSources, flags)
|
||||
DEFINE_FLAG_ACCESSOR(IsWarningsAreErrors, ScalingFlags::WarningsAreErrors, flags)
|
||||
DEFINE_FLAG_ACCESSOR(IsStatisticsForDynamicDetectionEnabled, ScalingFlags::EnableStatisticsForDynamicDetection, flags)
|
||||
DEFINE_FLAG_ACCESSOR(IsInlineParams, ScalingFlags::InlineParams, flags)
|
||||
DEFINE_FLAG_ACCESSOR(IsTouchSupportEnabled, ScalingFlags::IsTouchSupportEnabled, flags)
|
||||
DEFINE_FLAG_ACCESSOR(IsTouchSupportEnabled, ScalingFlags::TouchSupportEnabled, flags)
|
||||
DEFINE_FLAG_ACCESSOR(IsAllowScalingMaximized, ScalingFlags::AllowScalingMaximized, flags)
|
||||
DEFINE_FLAG_ACCESSOR(IsKeepOnTop, ScalingFlags::KeepOnTop, flags)
|
||||
DEFINE_FLAG_ACCESSOR(IsSimulateExclusiveFullscreen, ScalingFlags::SimulateExclusiveFullscreen, flags)
|
||||
DEFINE_FLAG_ACCESSOR(Is3DGameMode, ScalingFlags::Is3DGameMode, flags)
|
||||
DEFINE_FLAG_ACCESSOR(IsCaptureTitleBar, ScalingFlags::CaptureTitleBar, flags)
|
||||
DEFINE_FLAG_ACCESSOR(IsAdjustCursorSpeed, ScalingFlags::AdjustCursorSpeed, flags)
|
||||
DEFINE_FLAG_ACCESSOR(IsDirectFlipDisabled, ScalingFlags::DisableDirectFlip, flags)
|
||||
|
||||
bool Prepare() noexcept;
|
||||
void Log() const noexcept;
|
||||
|
||||
std::vector<EffectOption> effects;
|
||||
uint32_t flags = ScalingFlags::AdjustCursorSpeed;
|
||||
Cropping cropping{};
|
||||
|
|
@ -197,6 +198,26 @@ struct ScalingOptions {
|
|||
void (*showToast)(HWND hwndTarget, std::wstring_view msg) noexcept = nullptr;
|
||||
void (*showError)(HWND hwndTarget, ScalingError error) noexcept = nullptr;
|
||||
void (*save)(const ScalingOptions& options, HWND hwndScaling) noexcept = nullptr;
|
||||
|
||||
void Log() const noexcept;
|
||||
|
||||
bool RealIsCaptureTitleBar() const noexcept {
|
||||
// GDI 和 DwmSharedSurface 不支持捕获标题栏
|
||||
return IsCaptureTitleBar() &&
|
||||
captureMethod != CaptureMethod::GDI && captureMethod != CaptureMethod::DwmSharedSurface;
|
||||
}
|
||||
|
||||
bool RealIsAllowScalingMaximized() const noexcept {
|
||||
return IsAllowScalingMaximized() && !IsWindowedMode();
|
||||
}
|
||||
|
||||
bool RealIsKeepOnTop() const noexcept {
|
||||
return IsKeepOnTop() && !IsWindowedMode();
|
||||
}
|
||||
|
||||
bool RealIsSimulateExclusiveFullscreen() const noexcept {
|
||||
return IsSimulateExclusiveFullscreen() && !IsWindowedMode();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -608,6 +608,8 @@ bool AppSettings::_Save(const _AppSettingsData& data) noexcept {
|
|||
writer.Double(data._minFrameRate);
|
||||
writer.Key("disableFP16");
|
||||
writer.Bool(data._isFP16Disabled);
|
||||
writer.Key("keepOnTop");
|
||||
writer.Bool(data._isKeepOnTop);
|
||||
|
||||
ScalingModesService::Get().Export(writer);
|
||||
|
||||
|
|
@ -808,6 +810,7 @@ void AppSettings::_LoadSettings(const rapidjson::GenericObject<true, rapidjson::
|
|||
JsonHelper::ReadBool(root, "enableStatisticsForDynamicDetection", _isStatisticsForDynamicDetectionEnabled);
|
||||
JsonHelper::ReadFloat(root, "minFrameRate", _minFrameRate);
|
||||
JsonHelper::ReadBool(root, "disableFP16", _isFP16Disabled);
|
||||
JsonHelper::ReadBool(root, "keepOnTop", _isKeepOnTop);
|
||||
|
||||
[[maybe_unused]] bool result = ScalingModesService::Get().Import(root, true);
|
||||
assert(result);
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ struct _AppSettingsData {
|
|||
bool _isCheckForPreviewUpdates = false;
|
||||
bool _isStatisticsForDynamicDetectionEnabled = false;
|
||||
bool _isFP16Disabled = false;
|
||||
bool _isKeepOnTop = false;
|
||||
};
|
||||
|
||||
class AppSettings : private _AppSettingsData {
|
||||
|
|
@ -206,6 +207,15 @@ public:
|
|||
SaveAsync();
|
||||
}
|
||||
|
||||
bool IsKeepOnTop() const noexcept {
|
||||
return _isKeepOnTop;
|
||||
}
|
||||
|
||||
void IsKeepOnTop(bool value) noexcept {
|
||||
_isKeepOnTop = value;
|
||||
SaveAsync();
|
||||
}
|
||||
|
||||
bool IsAllowScalingMaximized() const noexcept {
|
||||
return _isAllowScalingMaximized;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@
|
|||
</local:SettingsCard>
|
||||
<local:SettingsExpander x:Uid="Home_Toolbar_InitialState">
|
||||
<local:SettingsExpander.HeaderIcon>
|
||||
<FontIcon Glyph="" />
|
||||
<FontIcon Glyph="" />
|
||||
</local:SettingsExpander.HeaderIcon>
|
||||
<local:SettingsExpander.Content>
|
||||
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
|
|
@ -193,12 +193,12 @@
|
|||
<ToggleSwitch x:Uid="ToggleSwitch"
|
||||
IsOn="{x:Bind ViewModel.IsAllowScalingMaximized, Mode=TwoWay}" />
|
||||
</local:SettingsCard>
|
||||
<local:SettingsCard x:Uid="Home_Advanced_InlineParams">
|
||||
<local:SettingsCard x:Uid="Home_Advanced_KeepOnTop">
|
||||
<local:SettingsCard.HeaderIcon>
|
||||
<FontIcon Glyph="" />
|
||||
<FontIcon Glyph="" />
|
||||
</local:SettingsCard.HeaderIcon>
|
||||
<ToggleSwitch x:Uid="ToggleSwitch"
|
||||
IsOn="{x:Bind ViewModel.IsInlineParams, Mode=TwoWay}" />
|
||||
IsOn="{x:Bind ViewModel.IsKeepOnTop, Mode=TwoWay}" />
|
||||
</local:SettingsCard>
|
||||
<local:SettingsCard x:Uid="Home_Advanced_SimulateExclusiveFullscreen">
|
||||
<local:SettingsCard.HeaderIcon>
|
||||
|
|
@ -211,6 +211,13 @@
|
|||
IsClosable="False"
|
||||
IsOpen="{x:Bind ViewModel.IsSimulateExclusiveFullscreen, Mode=OneWay}"
|
||||
Severity="Warning" />
|
||||
<local:SettingsCard x:Uid="Home_Advanced_InlineParams">
|
||||
<local:SettingsCard.HeaderIcon>
|
||||
<FontIcon Glyph="" />
|
||||
</local:SettingsCard.HeaderIcon>
|
||||
<ToggleSwitch x:Uid="ToggleSwitch"
|
||||
IsOn="{x:Bind ViewModel.IsInlineParams, Mode=TwoWay}" />
|
||||
</local:SettingsCard>
|
||||
<local:SettingsCard x:Uid="Home_Advanced_MinFrameRate"
|
||||
IsWrapEnabled="True">
|
||||
<local:SettingsCard.HeaderIcon>
|
||||
|
|
|
|||
|
|
@ -314,26 +314,33 @@ bool HomeViewModel::IsAllowScalingMaximized() const noexcept {
|
|||
}
|
||||
|
||||
void HomeViewModel::IsAllowScalingMaximized(bool value) {
|
||||
AppSettings::Get().IsAllowScalingMaximized(value);
|
||||
AppSettings& settings = AppSettings::Get();
|
||||
|
||||
if (settings.IsAllowScalingMaximized() == value) {
|
||||
return;
|
||||
}
|
||||
|
||||
settings.IsAllowScalingMaximized(value);
|
||||
RaisePropertyChanged(L"IsAllowScalingMaximized");
|
||||
|
||||
if (value) {
|
||||
ScalingService::Get().CheckForeground();
|
||||
}
|
||||
}
|
||||
|
||||
bool HomeViewModel::IsInlineParams() const noexcept {
|
||||
return AppSettings::Get().IsInlineParams();
|
||||
bool HomeViewModel::IsKeepOnTop() const noexcept {
|
||||
return AppSettings::Get().IsKeepOnTop();
|
||||
}
|
||||
|
||||
void HomeViewModel::IsInlineParams(bool value) {
|
||||
void HomeViewModel::IsKeepOnTop(bool value) {
|
||||
AppSettings& settings = AppSettings::Get();
|
||||
|
||||
if (settings.IsInlineParams() == value) {
|
||||
if (settings.IsKeepOnTop() == value) {
|
||||
return;
|
||||
}
|
||||
|
||||
settings.IsInlineParams(value);
|
||||
RaisePropertyChanged(L"IsInlineParams");
|
||||
settings.IsKeepOnTop(value);
|
||||
RaisePropertyChanged(L"IsKeepOnTop");
|
||||
}
|
||||
|
||||
bool HomeViewModel::IsSimulateExclusiveFullscreen() const noexcept {
|
||||
|
|
@ -351,6 +358,21 @@ void HomeViewModel::IsSimulateExclusiveFullscreen(bool value) {
|
|||
RaisePropertyChanged(L"IsSimulateExclusiveFullscreen");
|
||||
}
|
||||
|
||||
bool HomeViewModel::IsInlineParams() const noexcept {
|
||||
return AppSettings::Get().IsInlineParams();
|
||||
}
|
||||
|
||||
void HomeViewModel::IsInlineParams(bool value) {
|
||||
AppSettings& settings = AppSettings::Get();
|
||||
|
||||
if (settings.IsInlineParams() == value) {
|
||||
return;
|
||||
}
|
||||
|
||||
settings.IsInlineParams(value);
|
||||
RaisePropertyChanged(L"IsInlineParams");
|
||||
}
|
||||
|
||||
static constexpr std::array MIN_FRAME_RATE_OPTIONS{ 0,5,10,15,20,30,60 };
|
||||
|
||||
IVector<IInspectable> HomeViewModel::MinFrameRateOptions() {
|
||||
|
|
|
|||
|
|
@ -63,12 +63,15 @@ struct HomeViewModel : HomeViewModelT<HomeViewModel>, wil::notify_property_chang
|
|||
bool IsAllowScalingMaximized() const noexcept;
|
||||
void IsAllowScalingMaximized(bool value);
|
||||
|
||||
bool IsInlineParams() const noexcept;
|
||||
void IsInlineParams(bool value);
|
||||
bool IsKeepOnTop() const noexcept;
|
||||
void IsKeepOnTop(bool value);
|
||||
|
||||
bool IsSimulateExclusiveFullscreen() const noexcept;
|
||||
void IsSimulateExclusiveFullscreen(bool value);
|
||||
|
||||
bool IsInlineParams() const noexcept;
|
||||
void IsInlineParams(bool value);
|
||||
|
||||
static IVector<IInspectable> MinFrameRateOptions();
|
||||
|
||||
int MinFrameRateIndex() const noexcept;
|
||||
|
|
|
|||
|
|
@ -28,8 +28,9 @@ namespace Magpie {
|
|||
Boolean IsShowTouchSupportInfoBar { get; };
|
||||
|
||||
Boolean IsAllowScalingMaximized;
|
||||
Boolean IsInlineParams;
|
||||
Boolean IsKeepOnTop;
|
||||
Boolean IsSimulateExclusiveFullscreen;
|
||||
Boolean IsInlineParams;
|
||||
static IVector<IInspectable> MinFrameRateOptions { get; };
|
||||
Int32 MinFrameRateIndex;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
namespace Magpie {
|
||||
|
||||
class MainWindow : public XamlWindowT<MainWindow, winrt::com_ptr<winrt::Magpie::implementation::RootPage>> {
|
||||
class MainWindow final : public XamlWindowT<MainWindow, winrt::com_ptr<winrt::Magpie::implementation::RootPage>> {
|
||||
using base_type = XamlWindowT<MainWindow, winrt::com_ptr<winrt::Magpie::implementation::RootPage>>;
|
||||
friend WindowBaseT<MainWindow>;
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -184,6 +184,10 @@
|
|||
ItemsSource="{x:Bind ViewModel.CaptureMethods, Mode=OneTime}"
|
||||
SelectedIndex="{x:Bind ViewModel.CaptureMethod, Mode=TwoWay}" />
|
||||
</local:SettingsCard>
|
||||
<muxc:InfoBar x:Uid="Profile_General_DesktopDuplicationWarning"
|
||||
IsClosable="False"
|
||||
IsOpen="{x:Bind ViewModel.IsCaptureMethodDesktopDuplication, Mode=OneWay}"
|
||||
Severity="Warning" />
|
||||
<local:SettingsCard x:Name="AutoScaleSettingsCard"
|
||||
x:Uid="Profile_General_AutoScale"
|
||||
x:Load="{x:Bind ViewModel.IsNotDefaultProfile, Mode=OneTime}"
|
||||
|
|
|
|||
|
|
@ -367,11 +367,16 @@ void ProfileViewModel::CaptureMethod(int value) {
|
|||
|
||||
_data->captureMethod = captureMethod;
|
||||
RaisePropertyChanged(L"CaptureMethod");
|
||||
RaisePropertyChanged(L"IsCaptureMethodDesktopDuplication");
|
||||
RaisePropertyChanged(L"CanCaptureTitleBar");
|
||||
|
||||
AppSettings::Get().SaveAsync();
|
||||
}
|
||||
|
||||
bool ProfileViewModel::IsCaptureMethodDesktopDuplication() const noexcept {
|
||||
return _data->captureMethod == CaptureMethod::DesktopDuplication;
|
||||
}
|
||||
|
||||
int ProfileViewModel::AutoScale() const noexcept {
|
||||
return (int)_data->autoScale;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ struct ProfileViewModel : ProfileViewModelT<ProfileViewModel>,
|
|||
int CaptureMethod() const noexcept;
|
||||
void CaptureMethod(int value);
|
||||
|
||||
bool IsCaptureMethodDesktopDuplication() const noexcept;
|
||||
|
||||
int AutoScale() const noexcept;
|
||||
void AutoScale(int value);
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ namespace Magpie {
|
|||
|
||||
IVector<IInspectable> CaptureMethods { get; };
|
||||
Int32 CaptureMethod;
|
||||
Boolean IsCaptureMethodDesktopDuplication { get; };
|
||||
|
||||
Int32 AutoScale;
|
||||
Boolean Is3DGameMode;
|
||||
|
|
|
|||
|
|
@ -601,7 +601,7 @@
|
|||
<value>Make effect parameters inline</value>
|
||||
</data>
|
||||
<data name="Home_Advanced_SimulateExclusiveFullscreen.Description" xml:space="preserve">
|
||||
<value>Notifications and pop-ups from certain applications will be blocked</value>
|
||||
<value>Applies only to fullscreen scaling. Suppresses certain app notifications and pop-ups when enabled</value>
|
||||
</data>
|
||||
<data name="Home_Advanced_SimulateExclusiveFullscreen.Header" xml:space="preserve">
|
||||
<value>Simulate exclusive fullscreen when scaling</value>
|
||||
|
|
@ -872,7 +872,7 @@
|
|||
<value>Windowed scaling shortcut</value>
|
||||
</data>
|
||||
<data name="Home_Advanced_AllowScalingMaximized.Description" xml:space="preserve">
|
||||
<value>Applies to fullscreen scaling only</value>
|
||||
<value>Applies only to fullscreen scaling</value>
|
||||
</data>
|
||||
<data name="Home_Toolbar.Description" xml:space="preserve">
|
||||
<value>The toolbar appears at the top of the scaled window, providing features like FPS display and screenshot capture. In windowed mode, it also allows dragging the scaled window.</value>
|
||||
|
|
@ -1000,4 +1000,16 @@
|
|||
<data name="Home_Advanced_DeveloperOptions_LocateLogs.Header" xml:space="preserve">
|
||||
<value>Open logs location</value>
|
||||
</data>
|
||||
<data name="Home_Advanced_KeepOnTop.Description" xml:space="preserve">
|
||||
<value>Applies only to fullscreen scaling. When enabled, the scaled window stays on top while in the foreground to minimize distractions, though it may obscure menus and pop-ups. It also helps reduce latency on GPUs without Multi-Plane Overlay support</value>
|
||||
</data>
|
||||
<data name="Home_Advanced_KeepOnTop.Header" xml:space="preserve">
|
||||
<value>Keep scaled window on top</value>
|
||||
</data>
|
||||
<data name="Message_WindowedDesktopDuplication" xml:space="preserve">
|
||||
<value>Windowed scaling is not supported with Desktop Duplication capture.</value>
|
||||
</data>
|
||||
<data name="Profile_General_DesktopDuplicationWarning.Title" xml:space="preserve">
|
||||
<value>This capture method is incompatible with windowed scaling.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -601,7 +601,7 @@
|
|||
<value>内联效果参数</value>
|
||||
</data>
|
||||
<data name="Home_Advanced_SimulateExclusiveFullscreen.Description" xml:space="preserve">
|
||||
<value>可以阻止某些应用的通知和弹窗</value>
|
||||
<value>仅适用于全屏模式缩放。启用后可以阻止某些应用的通知和弹窗</value>
|
||||
</data>
|
||||
<data name="Home_Advanced_SimulateExclusiveFullscreen.Header" xml:space="preserve">
|
||||
<value>缩放时模拟独占全屏</value>
|
||||
|
|
@ -1000,4 +1000,16 @@
|
|||
<data name="Home_Advanced_DeveloperOptions_LocateLogs.Header" xml:space="preserve">
|
||||
<value>打开日志位置</value>
|
||||
</data>
|
||||
<data name="Home_Advanced_KeepOnTop.Description" xml:space="preserve">
|
||||
<value>仅适用于全屏模式缩放。启用后当缩放窗口位于前台时将置顶以减少干扰,但可能会遮挡菜单和弹窗。如果显卡不支持多平面叠加(MPO),此选项也有助于降低延迟</value>
|
||||
</data>
|
||||
<data name="Home_Advanced_KeepOnTop.Header" xml:space="preserve">
|
||||
<value>置顶缩放窗口</value>
|
||||
</data>
|
||||
<data name="Message_WindowedDesktopDuplication" xml:space="preserve">
|
||||
<value>Desktop Duplication 捕获不支持窗口模式缩放。</value>
|
||||
</data>
|
||||
<data name="Profile_General_DesktopDuplicationWarning.Title" xml:space="preserve">
|
||||
<value>此捕获方式和窗口模式缩放不兼容。</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -167,6 +167,10 @@ static void ShowError(HWND hWnd, ScalingError error) noexcept {
|
|||
key = L"Message_Windowed3DGameMode";
|
||||
isFail = false;
|
||||
break;
|
||||
case ScalingError::WindowedDesktopDuplication:
|
||||
key = L"Message_WindowedDesktopDuplication";
|
||||
isFail = false;
|
||||
break;
|
||||
case ScalingError::InvalidSourceWindow:
|
||||
key = L"Message_InvalidSourceWindow";
|
||||
break;
|
||||
|
|
@ -434,6 +438,7 @@ ScalingError ScalingService::_StartScaleImpl(HWND hWnd, const Profile& profile,
|
|||
options.IsStatisticsForDynamicDetectionEnabled(settings.IsStatisticsForDynamicDetectionEnabled());
|
||||
options.IsInlineParams(settings.IsInlineParams());
|
||||
options.IsFP16Disabled(settings.IsFP16Disabled());
|
||||
options.IsKeepOnTop(settings.IsKeepOnTop());
|
||||
|
||||
if (options.maxFrameRate) {
|
||||
// 最小帧数不能大于最大帧数
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
#pragma once
|
||||
#include <winrt/Magpie.h>
|
||||
#include <variant>
|
||||
#include "SmallVector.h"
|
||||
|
||||
namespace Magpie {
|
||||
|
||||
|
|
|
|||
|
|
@ -50,8 +50,12 @@ void ToastPage::InitializeComponent() {
|
|||
|
||||
static bool TrySetOwnder(HWND hwndToast, HWND hwndTarget) noexcept {
|
||||
// 如果源窗口挂起,SetWindowLongPtr 会卡住
|
||||
return !Win32Helper::IsWindowHung(hwndTarget) &&
|
||||
(SetWindowLongPtr(hwndToast, GWLP_HWNDPARENT, (LONG_PTR)hwndTarget) || GetLastError() == 0);
|
||||
if (!Win32Helper::IsWindowHung(hwndTarget)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SetLastError(0);
|
||||
return SetWindowLongPtr(hwndToast, GWLP_HWNDPARENT, (LONG_PTR)hwndTarget) || GetLastError() == 0;
|
||||
}
|
||||
|
||||
static void UpdateToastPosition(HWND hwndToast, const RECT& frameRect, bool updateZOrder) noexcept {
|
||||
|
|
@ -101,6 +105,8 @@ fire_and_forget ToastPage::ShowMessageOnWindow(std::wstring title, std::wstring
|
|||
MUXC::TeachingTip oldTeachingTip = MessageTeachingTip();
|
||||
if (oldTeachingTip) {
|
||||
UnloadObject(oldTeachingTip);
|
||||
// 确保卸载完成,防止弹出动画 bug
|
||||
co_await resume_foreground(dispatcher, CoreDispatcherPriority::Low);
|
||||
} else {
|
||||
oldTeachingTip = std::move(_oldTeachingTip);
|
||||
}
|
||||
|
|
@ -112,9 +118,8 @@ fire_and_forget ToastPage::ShowMessageOnWindow(std::wstring title, std::wstring
|
|||
|
||||
// 更改所有者关系使弹窗始终在 hwndTarget 上方。如果失败,改为定期将弹窗置顶,如果 hwndTarget
|
||||
// 的 IL 更高或是 UWP 窗口就会发生这种情况。
|
||||
SetLastError(0);
|
||||
const bool isOwned = TrySetOwnder(_hwndToast, hwndTarget);
|
||||
bool isTargetTopMost = GetWindowExStyle(_hwndToast) & WS_EX_TOPMOST;
|
||||
bool isTargetTopMost = GetWindowExStyle(hwndTarget) & WS_EX_TOPMOST;
|
||||
if (isOwned) {
|
||||
// _hwndToast 的输入已被附加到了 hWnd 上,这是所有者窗口的默认行为,但我们不需要。
|
||||
// 见 https://devblogs.microsoft.com/oldnewthing/20130412-00/?p=4683
|
||||
|
|
@ -249,7 +254,7 @@ fire_and_forget ToastPage::ShowMessageOnWindow(std::wstring title, std::wstring
|
|||
co_return;
|
||||
}
|
||||
|
||||
isTargetTopMost = GetWindowExStyle(_hwndToast) & WS_EX_TOPMOST;
|
||||
isTargetTopMost = GetWindowExStyle(hwndTarget) & WS_EX_TOPMOST;
|
||||
if (isTargetTopMost || (!isOwned && GetForegroundWindow() == (HWND)hwndTarget)) {
|
||||
// 如果 hwndTarget 位于前台,定期将弹窗置顶
|
||||
SetWindowPos(_hwndToast, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue