From 5874300fe53072989a127aa995045eed2338da13 Mon Sep 17 00:00:00 2001 From: Xu Date: Sun, 23 Jun 2024 10:25:21 +0800 Subject: [PATCH] test --- src/Magpie.App/AboutViewModel.cpp | 300 ----- src/Magpie.App/AboutViewModel.h | 83 -- src/Magpie.App/AboutViewModel.idl | 43 - src/Magpie.App/App.cpp | 46 - src/Magpie.App/App.h | 24 +- src/Magpie.App/App.idl | 34 - src/Magpie.App/AppSettings.cpp | 1028 ----------------- src/Magpie.App/AppSettings.h | 317 ----- src/Magpie.App/AppXReader.cpp | 785 ------------- src/Magpie.App/AppXReader.h | 44 - src/Magpie.App/AutoStartHelper.cpp | 516 --------- src/Magpie.App/AutoStartHelper.h | 11 - src/Magpie.App/BlueInfoBar.xaml | 18 - src/Magpie.App/BoolNegationConverter.cpp | 20 - src/Magpie.App/BoolNegationConverter.h | 18 - src/Magpie.App/BoolNegationConverter.idl | 5 - .../BoolToNegativeVisibilityConverter.cpp | 20 - .../BoolToNegativeVisibilityConverter.h | 18 - .../BoolToNegativeVisibilityConverter.idl | 7 - src/Magpie.App/CandidateWindowItem.cpp | 172 --- src/Magpie.App/CandidateWindowItem.h | 51 - src/Magpie.App/CandidateWindowItem.idl | 13 - src/Magpie.App/ComboBoxHelper.h | 35 - src/Magpie.App/ContentDialogHelper.cpp | 34 - src/Magpie.App/ContentDialogHelper.h | 11 - src/Magpie.App/ControlSizeTrigger.cpp | 91 -- src/Magpie.App/ControlSizeTrigger.h | 102 -- src/Magpie.App/ControlSizeTrigger.idl | 19 - src/Magpie.App/EffectHelper.h | 12 - src/Magpie.App/EffectParametersViewModel.cpp | 161 --- src/Magpie.App/EffectParametersViewModel.h | 156 --- src/Magpie.App/EffectParametersViewModel.idl | 33 - src/Magpie.App/FileDialogHelper.cpp | 36 - src/Magpie.App/FileDialogHelper.h | 12 - src/Magpie.App/HomeViewModel.cpp | 432 ------- src/Magpie.App/HomeViewModel.h | 119 -- src/Magpie.App/HomeViewModel.idl | 46 - src/Magpie.App/IconHelper.cpp | 249 ---- src/Magpie.App/IconHelper.h | 11 - src/Magpie.App/IsEqualStateTrigger.cpp | 47 - src/Magpie.App/IsEqualStateTrigger.h | 47 - src/Magpie.App/IsEqualStateTrigger.idl | 11 - src/Magpie.App/IsNullStateTrigger.cpp | 28 - src/Magpie.App/IsNullStateTrigger.h | 36 - src/Magpie.App/IsNullStateTrigger.idl | 8 - src/Magpie.App/JsonHelper.cpp | 147 --- src/Magpie.App/JsonHelper.h | 58 - src/Magpie.App/LoggerHelper.cpp | 15 - src/Magpie.App/LoggerHelper.h | 19 - src/Magpie.App/LoggerHelper.idl | 10 - src/Magpie.App/Magpie.App.vcxproj | 35 - src/Magpie.App/Magpie.App.vcxproj.filters | 77 -- src/Magpie.App/NewProfileViewModel.cpp | 181 --- src/Magpie.App/NewProfileViewModel.h | 80 -- src/Magpie.App/NewProfileViewModel.idl | 18 - src/Magpie.App/Profile.h | 79 -- src/Magpie.App/ProfileViewModel.cpp | 885 -------------- src/Magpie.App/ProfileViewModel.h | 176 --- src/Magpie.App/ProfileViewModel.idl | 67 -- src/Magpie.App/RootPage.cpp | 5 - src/Magpie.App/ScalingMode.h | 11 - src/Magpie.App/ScalingModeEffectItem.cpp | 270 ----- src/Magpie.App/ScalingModeEffectItem.h | 95 -- src/Magpie.App/ScalingModeEffectItem.idl | 35 - src/Magpie.App/ScalingModeItem.cpp | 329 ------ src/Magpie.App/ScalingModeItem.h | 122 -- src/Magpie.App/ScalingModeItem.idl | 34 - src/Magpie.App/ScalingModesViewModel.cpp | 219 ---- src/Magpie.App/ScalingModesViewModel.h | 94 -- src/Magpie.App/ScalingModesViewModel.idl | 20 - .../SettingsExpanderCornerRadiusConverter.cpp | 27 - .../SettingsExpanderCornerRadiusConverter.h | 18 - .../SettingsExpanderCornerRadiusConverter.idl | 5 - src/Magpie.App/SettingsViewModel.cpp | 187 --- src/Magpie.App/SettingsViewModel.h | 62 - src/Magpie.App/SettingsViewModel.idl | 21 - src/Magpie.App/Shortcut.cpp | 50 - src/Magpie.App/Shortcut.h | 26 - src/Magpie.App/ShortcutHelper.cpp | 138 --- src/Magpie.App/ShortcutHelper.h | 22 - src/Magpie.App/TouchHelper.cpp | 117 -- src/Magpie.App/TouchHelper.h | 11 - src/Magpie.Core/include/Magpie.Core.h | 1 - src/Magpie/XamlApp.cpp | 32 +- src/Shared/Logger.cpp | 6 - 85 files changed, 5 insertions(+), 9108 deletions(-) delete mode 100644 src/Magpie.App/AboutViewModel.cpp delete mode 100644 src/Magpie.App/AboutViewModel.h delete mode 100644 src/Magpie.App/AboutViewModel.idl delete mode 100644 src/Magpie.App/AppSettings.cpp delete mode 100644 src/Magpie.App/AppSettings.h delete mode 100644 src/Magpie.App/AppXReader.cpp delete mode 100644 src/Magpie.App/AppXReader.h delete mode 100644 src/Magpie.App/AutoStartHelper.cpp delete mode 100644 src/Magpie.App/AutoStartHelper.h delete mode 100644 src/Magpie.App/BlueInfoBar.xaml delete mode 100644 src/Magpie.App/BoolNegationConverter.cpp delete mode 100644 src/Magpie.App/BoolNegationConverter.h delete mode 100644 src/Magpie.App/BoolNegationConverter.idl delete mode 100644 src/Magpie.App/BoolToNegativeVisibilityConverter.cpp delete mode 100644 src/Magpie.App/BoolToNegativeVisibilityConverter.h delete mode 100644 src/Magpie.App/BoolToNegativeVisibilityConverter.idl delete mode 100644 src/Magpie.App/CandidateWindowItem.cpp delete mode 100644 src/Magpie.App/CandidateWindowItem.h delete mode 100644 src/Magpie.App/CandidateWindowItem.idl delete mode 100644 src/Magpie.App/ComboBoxHelper.h delete mode 100644 src/Magpie.App/ContentDialogHelper.cpp delete mode 100644 src/Magpie.App/ContentDialogHelper.h delete mode 100644 src/Magpie.App/ControlSizeTrigger.cpp delete mode 100644 src/Magpie.App/ControlSizeTrigger.h delete mode 100644 src/Magpie.App/ControlSizeTrigger.idl delete mode 100644 src/Magpie.App/EffectHelper.h delete mode 100644 src/Magpie.App/EffectParametersViewModel.cpp delete mode 100644 src/Magpie.App/EffectParametersViewModel.h delete mode 100644 src/Magpie.App/EffectParametersViewModel.idl delete mode 100644 src/Magpie.App/FileDialogHelper.cpp delete mode 100644 src/Magpie.App/FileDialogHelper.h delete mode 100644 src/Magpie.App/HomeViewModel.cpp delete mode 100644 src/Magpie.App/HomeViewModel.h delete mode 100644 src/Magpie.App/HomeViewModel.idl delete mode 100644 src/Magpie.App/IconHelper.cpp delete mode 100644 src/Magpie.App/IconHelper.h delete mode 100644 src/Magpie.App/IsEqualStateTrigger.cpp delete mode 100644 src/Magpie.App/IsEqualStateTrigger.h delete mode 100644 src/Magpie.App/IsEqualStateTrigger.idl delete mode 100644 src/Magpie.App/IsNullStateTrigger.cpp delete mode 100644 src/Magpie.App/IsNullStateTrigger.h delete mode 100644 src/Magpie.App/IsNullStateTrigger.idl delete mode 100644 src/Magpie.App/JsonHelper.cpp delete mode 100644 src/Magpie.App/JsonHelper.h delete mode 100644 src/Magpie.App/LoggerHelper.cpp delete mode 100644 src/Magpie.App/LoggerHelper.h delete mode 100644 src/Magpie.App/LoggerHelper.idl delete mode 100644 src/Magpie.App/NewProfileViewModel.cpp delete mode 100644 src/Magpie.App/NewProfileViewModel.h delete mode 100644 src/Magpie.App/NewProfileViewModel.idl delete mode 100644 src/Magpie.App/Profile.h delete mode 100644 src/Magpie.App/ProfileViewModel.cpp delete mode 100644 src/Magpie.App/ProfileViewModel.h delete mode 100644 src/Magpie.App/ProfileViewModel.idl delete mode 100644 src/Magpie.App/ScalingMode.h delete mode 100644 src/Magpie.App/ScalingModeEffectItem.cpp delete mode 100644 src/Magpie.App/ScalingModeEffectItem.h delete mode 100644 src/Magpie.App/ScalingModeEffectItem.idl delete mode 100644 src/Magpie.App/ScalingModeItem.cpp delete mode 100644 src/Magpie.App/ScalingModeItem.h delete mode 100644 src/Magpie.App/ScalingModeItem.idl delete mode 100644 src/Magpie.App/ScalingModesViewModel.cpp delete mode 100644 src/Magpie.App/ScalingModesViewModel.h delete mode 100644 src/Magpie.App/ScalingModesViewModel.idl delete mode 100644 src/Magpie.App/SettingsExpanderCornerRadiusConverter.cpp delete mode 100644 src/Magpie.App/SettingsExpanderCornerRadiusConverter.h delete mode 100644 src/Magpie.App/SettingsExpanderCornerRadiusConverter.idl delete mode 100644 src/Magpie.App/SettingsViewModel.cpp delete mode 100644 src/Magpie.App/SettingsViewModel.h delete mode 100644 src/Magpie.App/SettingsViewModel.idl delete mode 100644 src/Magpie.App/Shortcut.cpp delete mode 100644 src/Magpie.App/Shortcut.h delete mode 100644 src/Magpie.App/ShortcutHelper.cpp delete mode 100644 src/Magpie.App/ShortcutHelper.h delete mode 100644 src/Magpie.App/TouchHelper.cpp delete mode 100644 src/Magpie.App/TouchHelper.h diff --git a/src/Magpie.App/AboutViewModel.cpp b/src/Magpie.App/AboutViewModel.cpp deleted file mode 100644 index aca99582c..000000000 --- a/src/Magpie.App/AboutViewModel.cpp +++ /dev/null @@ -1,300 +0,0 @@ -#include "pch.h" -#include "AboutViewModel.h" -#if __has_include("AboutViewModel.g.cpp") -#include "AboutViewModel.g.cpp" -#endif -#include "Version.h" -#include "UpdateService.h" -#include "AppSettings.h" -#include "StrUtils.h" -#include "IconHelper.h" -#include "CommonSharedConstants.h" - -using namespace winrt; -using namespace Windows::UI::Xaml::Media::Imaging; - -namespace winrt::Magpie::App::implementation { - -AboutViewModel::AboutViewModel() { - UpdateService& service = UpdateService::Get(); - service.EnteringAboutPage(); - - _updateStatusChangedRevoker = service.StatusChanged( - auto_revoke, { this, &AboutViewModel::_UpdateService_StatusChanged }); - - if (service.Status() == UpdateStatus::Downloading) { - _downloadProgressChangedRevoker = UpdateService::Get().DownloadProgressChanged( - auto_revoke, - { this, &AboutViewModel::_UpdateService_DownloadProgressChanged } - ); - } - - // 用户查看了关于页面,主页无需再显示更新提示 - service.IsShowOnHomePage(false); - _showOnHomePageChangedRevoker = service.IsShowOnHomePageChanged(auto_revoke, [](bool value) { - if (value) { - // 在关于页面触发自动更新时主页不需要显示更新提示 - UpdateService::Get().IsShowOnHomePage(false); - } - }); - - // 异步加载 Logo - ([](AboutViewModel* that)->fire_and_forget { - auto weakThis = that->get_weak(); - SoftwareBitmapSource bitmap; - co_await bitmap.SetBitmapAsync(IconHelper::ExtractIconFromExe( - Win32Utils::GetExePath().c_str(), 256, USER_DEFAULT_SCREEN_DPI)); - - if (!weakThis.get()) { - co_return; - } - - that->_logo = std::move(bitmap); - that->RaisePropertyChanged(L"Logo"); - })(this); -} - -hstring AboutViewModel::Version() const noexcept { - ResourceLoader resourceLoader = - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID); - return hstring(StrUtils::Concat( - resourceLoader.GetString(L"About_Version_Version"), -#ifdef MAGPIE_VERSION_TAG - L" ", - WIDEN(STRING(MAGPIE_VERSION_TAG)) + 1, -#else - L" dev", -#endif -#ifdef MAGPIE_COMMIT_ID - L" | ", - resourceLoader.GetString(L"About_Version_CommitId"), - L" " WIDEN(STRING(MAGPIE_COMMIT_ID)), -#endif - L" | " -#ifdef _M_X64 - L"x64" -#elif defined(_M_ARM64) - L"ARM64" -#else - static_assert(false, "不支持的架构") -#endif - )); -} - -bool AboutViewModel::IsDeveloperMode() const noexcept { - return AppSettings::Get().IsDeveloperMode(); -} - -void AboutViewModel::IsDeveloperMode(bool value) { - AppSettings::Get().IsDeveloperMode(value); -} - -fire_and_forget AboutViewModel::CheckForUpdates() { - return UpdateService::Get().CheckForUpdatesAsync(false); -} - -bool AboutViewModel::IsCheckForPreviewUpdates() const noexcept { - return AppSettings::Get().IsCheckForPreviewUpdates(); -} - -void AboutViewModel::IsCheckForPreviewUpdates(bool value) { - AppSettings::Get().IsCheckForPreviewUpdates(value); - RaisePropertyChanged(L"IsCheckForPreviewUpdates"); -} - -bool AboutViewModel::IsCheckForUpdatesButtonEnabled() const noexcept { -#ifndef MAGPIE_VERSION_TAG - // 只有正式版本才能检查更新 - //return false; -#endif - - return !IsCheckingForUpdates() && !IsDownloadingOrLater(); -} - -bool AboutViewModel::IsAutoCheckForUpdates() const noexcept { - return AppSettings::Get().IsAutoCheckForUpdates(); -} - -void AboutViewModel::IsAutoCheckForUpdates(bool value) { - AppSettings::Get().IsAutoCheckForUpdates(value); - RaisePropertyChanged(L"IsAutoCheckForUpdates"); -} - -bool AboutViewModel::IsAnyUpdateStatus() const noexcept { - return UpdateService::Get().Status() > UpdateStatus::Checking; -} - -bool AboutViewModel::IsCheckingForUpdates() const noexcept { - return UpdateService::Get().Status() == UpdateStatus::Checking; -} - -bool AboutViewModel::IsErrorWhileChecking() const noexcept { - return UpdateService::Get().Status() == UpdateStatus::ErrorWhileChecking; -} - -void AboutViewModel::IsErrorWhileChecking(bool value) { - if (!value) { - UpdateService& service = UpdateService::Get(); - if (service.Status() == UpdateStatus::ErrorWhileChecking) { - service.Cancel(); - } - } - - RaisePropertyChanged(L"IsErrorWhileChecking"); -} - -bool AboutViewModel::IsNoUpdate() const noexcept { - return UpdateService::Get().Status() == UpdateStatus::NoUpdate; -} - -void AboutViewModel::IsNoUpdate(bool value) const noexcept { - if (!value) { - UpdateService& service = UpdateService::Get(); - if (service.Status() == UpdateStatus::NoUpdate) { - service.Cancel(); - } - } -} - -bool AboutViewModel::IsAvailable() const noexcept { - return UpdateService::Get().Status() == UpdateStatus::Available; -} - -bool AboutViewModel::IsDownloading() const noexcept { - return UpdateService::Get().Status() == UpdateStatus::Downloading; -} - -bool AboutViewModel::IsErrorWhileDownloading() const noexcept { - return UpdateService::Get().Status() == UpdateStatus::ErrorWhileDownloading; -} - -bool AboutViewModel::IsDownloadingOrLater() const noexcept { - return UpdateService::Get().Status() >= UpdateStatus::Downloading; -} - -bool AboutViewModel::IsInstalling() const noexcept { - return UpdateService::Get().Status() == UpdateStatus::Installing; -} - -bool AboutViewModel::IsUpdateCardOpen() const noexcept { - return UpdateService::Get().Status() >= UpdateStatus::Available; -} - -void AboutViewModel::IsUpdateCardOpen(bool value) { - if (!value) { - UpdateService& service = UpdateService::Get(); - UpdateStatus status = service.Status(); - if (status == UpdateStatus::Available || status == UpdateStatus::ErrorWhileDownloading) { - service.Cancel(); - } - } - - RaisePropertyChanged(L"IsUpdateCardOpen"); -} - -bool AboutViewModel::IsUpdateCardClosable() const noexcept { - UpdateStatus status = UpdateService::Get().Status(); - return status == UpdateStatus::Available || status == UpdateStatus::ErrorWhileDownloading; -} - -bool AboutViewModel::IsCancelButtonVisible() const noexcept { - UpdateStatus status = UpdateService::Get().Status(); - return status == UpdateStatus::Downloading || status == UpdateStatus::Installing; -} - -hstring AboutViewModel::UpdateCardTitle() const noexcept { - UpdateService& updateService = UpdateService::Get(); - if (updateService.Status() < UpdateStatus::Available) { - return {}; - } - - ResourceLoader resourceLoader = - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID); - hstring titleFmt = resourceLoader.GetString(L"Home_UpdateCard_Title"); - return hstring(fmt::format(fmt::runtime(std::wstring_view(titleFmt)), updateService.Tag())); -} - -bool AboutViewModel::IsNoDownloadProgress() const noexcept { - UpdateService& service = UpdateService::Get(); - switch (service.Status()) { - case UpdateStatus::Downloading: - return service.DownloadProgress() < 1e-6; - default: - return true; - } -} - -double AboutViewModel::DownloadProgress() const noexcept { - switch (UpdateService::Get().Status()) { - case UpdateStatus::Downloading: - return 0.9979917876649076; - case UpdateStatus::Installing: - return 1.0; - default: - return 0.0; - } -} - -Uri AboutViewModel::UpdateReleaseNotesLink() const noexcept { - if (!IsUpdateCardOpen()) { - return nullptr; - } - - return Uri(StrUtils::Concat(L"https://github.com/Blinue/Magpie/releases/tag/", - UpdateService::Get().Tag())); -} - -fire_and_forget AboutViewModel::DownloadAndInstall() { - return UpdateService::Get().DownloadAndInstall(); -} - -void AboutViewModel::Cancel() { - assert(UpdateService::Get().Status() == UpdateStatus::Downloading); - UpdateService::Get().Cancel(); -} - -void AboutViewModel::Retry() { - assert(UpdateService::Get().Status() == UpdateStatus::ErrorWhileDownloading); - UpdateService::Get().DownloadAndInstall(); -} - -void AboutViewModel::_UpdateService_StatusChanged(UpdateStatus status) { - RaisePropertyChanged(L"IsCheckingForUpdates"); - RaisePropertyChanged(L"IsCheckForUpdatesButtonEnabled"); - RaisePropertyChanged(L"IsAnyUpdateStatus"); - RaisePropertyChanged(L"IsErrorWhileChecking"); - RaisePropertyChanged(L"IsNoUpdate"); - RaisePropertyChanged(L"IsAvailable"); - RaisePropertyChanged(L"IsDownloading"); - RaisePropertyChanged(L"IsErrorWhileDownloading"); - RaisePropertyChanged(L"IsInstalling"); - RaisePropertyChanged(L"IsDownloadingOrLater"); - RaisePropertyChanged(L"IsUpdateCardOpen"); - RaisePropertyChanged(L"IsUpdateCardClosable"); - RaisePropertyChanged(L"IsCancelButtonVisible"); - - if (status >= UpdateStatus::Available) { - RaisePropertyChanged(L"UpdateCardTitle"); - RaisePropertyChanged(L"UpdateReleaseNotesLink"); - - if (status == UpdateStatus::Downloading) { - _downloadProgressChangedRevoker = UpdateService::Get().DownloadProgressChanged( - auto_revoke, - { this, &AboutViewModel::_UpdateService_DownloadProgressChanged } - ); - } else { - _downloadProgressChangedRevoker.Revoke(); - - if (status >= UpdateStatus::ErrorWhileDownloading) { - RaisePropertyChanged(L"IsNoDownloadProgress"); - } - } - } -} - -void AboutViewModel::_UpdateService_DownloadProgressChanged(double) { - RaisePropertyChanged(L"IsNoDownloadProgress"); - RaisePropertyChanged(L"DownloadProgress"); -} - -} diff --git a/src/Magpie.App/AboutViewModel.h b/src/Magpie.App/AboutViewModel.h deleted file mode 100644 index a8680995f..000000000 --- a/src/Magpie.App/AboutViewModel.h +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once -#include "AboutViewModel.g.h" -#include "UpdateService.h" - -namespace winrt::Magpie::App::implementation { - -struct AboutViewModel : AboutViewModelT, - wil::notify_property_changed_base { - AboutViewModel(); - - Imaging::SoftwareBitmapSource Logo() const noexcept { - return _logo; - } - - hstring Version() const noexcept; - - bool IsDeveloperMode() const noexcept; - void IsDeveloperMode(bool value); - - fire_and_forget CheckForUpdates(); - - bool IsCheckForPreviewUpdates() const noexcept; - void IsCheckForPreviewUpdates(bool value); - - bool IsCheckForUpdatesButtonEnabled() const noexcept; - - bool IsAutoCheckForUpdates() const noexcept; - void IsAutoCheckForUpdates(bool value); - - bool IsAnyUpdateStatus() const noexcept; - - bool IsCheckingForUpdates() const noexcept; - - bool IsErrorWhileChecking() const noexcept; - void IsErrorWhileChecking(bool value); - - bool IsNoUpdate() const noexcept; - void IsNoUpdate(bool value) const noexcept; - - bool IsAvailable() const noexcept; - - bool IsDownloading() const noexcept; - bool IsErrorWhileDownloading() const noexcept; - bool IsDownloadingOrLater() const noexcept; - bool IsInstalling() const noexcept; - - bool IsUpdateCardOpen() const noexcept; - void IsUpdateCardOpen(bool value); - - bool IsUpdateCardClosable() const noexcept; - bool IsCancelButtonVisible() const noexcept; - - hstring UpdateCardTitle() const noexcept; - - bool IsNoDownloadProgress() const noexcept; - double DownloadProgress() const noexcept; - - Uri UpdateReleaseNotesLink() const noexcept; - - fire_and_forget DownloadAndInstall(); - - void Cancel(); - void Retry(); - -private: - void _UpdateService_StatusChanged(UpdateStatus status); - void _UpdateService_DownloadProgressChanged(double); - - WinRTUtils::EventRevoker _updateStatusChangedRevoker; - WinRTUtils::EventRevoker _downloadProgressChangedRevoker; - WinRTUtils::EventRevoker _showOnHomePageChangedRevoker; - - Imaging::SoftwareBitmapSource _logo{ nullptr }; -}; - -} - -namespace winrt::Magpie::App::factory_implementation { - -struct AboutViewModel : AboutViewModelT { -}; - -} diff --git a/src/Magpie.App/AboutViewModel.idl b/src/Magpie.App/AboutViewModel.idl deleted file mode 100644 index e4369e51e..000000000 --- a/src/Magpie.App/AboutViewModel.idl +++ /dev/null @@ -1,43 +0,0 @@ -namespace Magpie.App { - runtimeclass AboutViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged { - AboutViewModel(); - - Windows.UI.Xaml.Media.Imaging.SoftwareBitmapSource Logo { get; }; - - String Version { get; }; - - Boolean IsDeveloperMode; - - void CheckForUpdates(); - Boolean IsCheckingForUpdates { get; }; - Boolean IsCheckForUpdatesButtonEnabled { get; }; - - Boolean IsAutoCheckForUpdates; - Boolean IsCheckForPreviewUpdates; - - Boolean IsAnyUpdateStatus { get; }; - - Boolean IsErrorWhileChecking; - Boolean IsNoUpdate; - Boolean IsAvailable { get; }; - Boolean IsDownloading { get; }; - Boolean IsErrorWhileDownloading { get; }; - Boolean IsInstalling { get; }; - Boolean IsDownloadingOrLater { get; }; - - Boolean IsUpdateCardOpen; - Boolean IsUpdateCardClosable { get; }; - Boolean IsCancelButtonVisible { get; }; - - String UpdateCardTitle { get; }; - - Boolean IsNoDownloadProgress { get; }; - Double DownloadProgress { get; }; - - Windows.Foundation.Uri UpdateReleaseNotesLink { get; }; - - void DownloadAndInstall(); - void Cancel(); - void Retry(); - } -} diff --git a/src/Magpie.App/App.cpp b/src/Magpie.App/App.cpp index c4d689019..bf31d947e 100644 --- a/src/Magpie.App/App.cpp +++ b/src/Magpie.App/App.cpp @@ -21,7 +21,6 @@ #endif #include "Win32Utils.h" #include "Logger.h" -#include "AppSettings.h" #include "CommonSharedConstants.h" #include #include @@ -69,44 +68,7 @@ void App::Close() { Exit(); } -void App::SaveSettings() { - AppSettings::Get().Save(); -} - -StartUpOptions App::Initialize(int) { - StartUpOptions result{}; - - AppSettings& settings = AppSettings::Get(); - if (!settings.Initialize()) { - result.IsError = true; - return result; - } - - result.IsError = false; - result.MainWindowCenter = settings.MainWindowCenter(); - result.MainWindowSizeInDips = settings.MainWindowSizeInDips(); - result.IsWndMaximized= settings.IsWindowMaximized(); - result.IsNeedElevated = settings.IsAlwaysRunAsAdmin(); - - return result; -} - -void App::Uninitialize() { -} - -bool App::IsShowNotifyIcon() const noexcept { - return AppSettings::Get().IsShowNotifyIcon(); -} -event_token App::IsShowNotifyIconChanged(EventHandler const& handler) { - return AppSettings::Get().IsShowNotifyIconChanged([handler(handler)](bool value) { - handler(nullptr, value); - }); -} - -void App::IsShowNotifyIconChanged(event_token const& token) { - AppSettings::Get().IsShowNotifyIconChanged(token); -} void App::RootPage(Magpie::App::RootPage const& rootPage) noexcept { if (rootPage) { @@ -118,12 +80,4 @@ void App::RootPage(Magpie::App::RootPage const& rootPage) noexcept { } } -void App::Quit() const noexcept { - PostMessage(_hwndMain, CommonSharedConstants::WM_QUIT_MAGPIE, 0, 0); -} - -void App::Restart() const noexcept { - PostMessage(_hwndMain, CommonSharedConstants::WM_RESTART_MAGPIE, 0, 0); -} - } diff --git a/src/Magpie.App/App.h b/src/Magpie.App/App.h index 16e744039..d8f516bad 100644 --- a/src/Magpie.App/App.h +++ b/src/Magpie.App/App.h @@ -11,26 +11,6 @@ class App : public App_base { void Close(); - void SaveSettings(); - - StartUpOptions Initialize(int); - - void Uninitialize(); - - bool IsShowNotifyIcon() const noexcept; - - event_token IsShowNotifyIconChanged(EventHandler const& handler); - - void IsShowNotifyIconChanged(event_token const& token); - - uint64_t HwndMain() const noexcept { - return (uint64_t)_hwndMain; - } - - void HwndMain(uint64_t value) noexcept { - _hwndMain = (HWND)value; - } - // 在由外部源引发的回调中可能返回 nullptr // 这是因为用户关闭主窗口后 RootPage 不会立刻析构 Magpie::App::RootPage RootPage() const noexcept { @@ -39,9 +19,7 @@ class App : public App_base { void RootPage(Magpie::App::RootPage const& rootPage) noexcept; - void Quit() const noexcept; - - void Restart() const noexcept; + private: Hosting::WindowsXamlManager _windowsXamlManager{ nullptr }; diff --git a/src/Magpie.App/App.idl b/src/Magpie.App/App.idl index 02d71ef66..afb06b92c 100644 --- a/src/Magpie.App/App.idl +++ b/src/Magpie.App/App.idl @@ -1,44 +1,10 @@ - -#include "LoggerHelper.idl" #include "RootPage.idl" namespace Magpie.App { - enum ShortcutAction { - Scale, - Overlay, - COUNT_OR_NONE - }; - - enum ShortcutError { - NoError, - Invalid, - Occupied - }; - - struct StartUpOptions { - Windows.Foundation.Point MainWindowCenter; - Windows.Foundation.Size MainWindowSizeInDips; - Boolean IsError; - Boolean IsWndMaximized; - Boolean IsNeedElevated; - }; runtimeclass App : Windows.UI.Xaml.Application, Windows.Foundation.IClosable { App(); - void SaveSettings(); - - StartUpOptions Initialize(Int32 notUsed); - void Uninitialize(); - - Boolean IsShowNotifyIcon { get; }; - event Windows.Foundation.EventHandler IsShowNotifyIconChanged; - - UInt64 HwndMain; - RootPage RootPage; - - void Quit(); - void Restart(); } } diff --git a/src/Magpie.App/AppSettings.cpp b/src/Magpie.App/AppSettings.cpp deleted file mode 100644 index 1ece4a155..000000000 --- a/src/Magpie.App/AppSettings.cpp +++ /dev/null @@ -1,1028 +0,0 @@ -#include "pch.h" -#include "AppSettings.h" -#include "StrUtils.h" -#include "Win32Utils.h" -#include "Logger.h" -#include "ShortcutHelper.h" -#include "Profile.h" -#include "CommonSharedConstants.h" -#include -#include "AutoStartHelper.h" -#include -#include "JsonHelper.h" -#include "ScalingMode.h" -#include - -#pragma comment(lib, "Shcore.lib") - -using namespace ::Magpie::Core; - -namespace winrt::Magpie::App { - -static constexpr uint32_t CONFIG_VERSION = 2; - -_AppSettingsData::_AppSettingsData() {} - -_AppSettingsData::~_AppSettingsData() {} - -// 将热键存储为 uint32_t -// 不能存储为字符串,因为某些键的字符相同,如句号和小键盘的点 -static uint32_t EncodeShortcut(const Shortcut& shortcut) noexcept { - uint32_t value = shortcut.code; - if (shortcut.win) { - value |= 0x100; - } - if (shortcut.ctrl) { - value |= 0x200; - } - if (shortcut.alt) { - value |= 0x400; - } - if (shortcut.shift) { - value |= 0x800; - } - return value; -} - -static void DecodeShortcut(uint32_t value, Shortcut& shortcut) noexcept { - if (value > 0xfff) { - return; - } - - shortcut.code = value & 0xff; - shortcut.win = value & 0x100; - shortcut.ctrl = value & 0x200; - shortcut.alt = value & 0x400; - shortcut.shift = value & 0x800; -} - -static void WriteProfile(rapidjson::PrettyWriter& writer, const Profile& profile) noexcept { - writer.StartObject(); - if (!profile.name.empty()) { - writer.Key("name"); - writer.String(StrUtils::UTF16ToUTF8(profile.name).c_str()); - writer.Key("packaged"); - writer.Bool(profile.isPackaged); - writer.Key("pathRule"); - writer.String(StrUtils::UTF16ToUTF8(profile.pathRule).c_str()); - writer.Key("classNameRule"); - writer.String(StrUtils::UTF16ToUTF8(profile.classNameRule).c_str()); - writer.Key("launcherPath"); - writer.String(StrUtils::UTF16ToUTF8(profile.launcherPath).c_str()); - writer.Key("autoScale"); - writer.Bool(profile.isAutoScale); - writer.Key("launchParameters"); - writer.String(StrUtils::UTF16ToUTF8(profile.launchParameters).c_str()); - } - - writer.Key("scalingMode"); - writer.Int(profile.scalingMode); - writer.Key("captureMethod"); - writer.Uint((uint32_t)profile.captureMethod); - writer.Key("multiMonitorUsage"); - writer.Uint((uint32_t)profile.multiMonitorUsage); - - writer.Key("graphicsCard"); - writer.Int(profile.graphicsCard); - writer.Key("frameRateLimiterEnabled"); - writer.Bool(profile.isFrameRateLimiterEnabled); - writer.Key("maxFrameRate"); - writer.Double(profile.maxFrameRate); - - writer.Key("disableWindowResizing"); - writer.Bool(profile.IsWindowResizingDisabled()); - writer.Key("3DGameMode"); - writer.Bool(profile.Is3DGameMode()); - writer.Key("showFPS"); - writer.Bool(profile.IsShowFPS()); - writer.Key("captureTitleBar"); - writer.Bool(profile.IsCaptureTitleBar()); - writer.Key("adjustCursorSpeed"); - writer.Bool(profile.IsAdjustCursorSpeed()); - writer.Key("drawCursor"); - writer.Bool(profile.IsDrawCursor()); - writer.Key("disableDirectFlip"); - writer.Bool(profile.IsDirectFlipDisabled()); - - writer.Key("cursorScaling"); - writer.Uint((uint32_t)profile.cursorScaling); - writer.Key("customCursorScaling"); - writer.Double(profile.customCursorScaling); - writer.Key("cursorInterpolationMode"); - writer.Uint((uint32_t)profile.cursorInterpolationMode); - - writer.Key("croppingEnabled"); - writer.Bool(profile.isCroppingEnabled); - writer.Key("cropping"); - writer.StartObject(); - writer.Key("left"); - writer.Double(profile.cropping.Left); - writer.Key("top"); - writer.Double(profile.cropping.Top); - writer.Key("right"); - writer.Double(profile.cropping.Right); - writer.Key("bottom"); - writer.Double(profile.cropping.Bottom); - writer.EndObject(); - - writer.EndObject(); -} - -static void ReplaceIcon(HINSTANCE hInst, HWND hWnd, bool large) noexcept { - HICON hIconApp = NULL; - LoadIconMetric(hInst, MAKEINTRESOURCE(CommonSharedConstants::IDI_APP), large ? LIM_LARGE : LIM_SMALL, &hIconApp); - HICON hIconOld = (HICON)SendMessage(hWnd, WM_SETICON, large ? ICON_BIG : ICON_SMALL, (LPARAM)hIconApp); - if (hIconOld) { - DestroyIcon(hIconOld); - } -} - -static HRESULT CALLBACK TaskDialogCallback( - HWND hWnd, - UINT msg, - WPARAM /*wParam*/, - LPARAM /*lParam*/, - LONG_PTR /*lpRefData*/ -) { - if (msg == TDN_CREATED) { - // 将任务栏图标替换为 Magpie 的图标 - // GetModuleHandle 获取 exe 文件的句柄 - HINSTANCE hInst = GetModuleHandle(nullptr); - ReplaceIcon(hInst, hWnd, true); - ReplaceIcon(hInst, hWnd, false); - - // 删除标题栏中的图标 - INT_PTR style = GetWindowLongPtr(hWnd, GWL_STYLE); - SetWindowLongPtr(hWnd, GWL_STYLE, style & ~WS_SYSMENU); - } - - return S_OK; -} - -static void ShowErrorMessage(const wchar_t* mainInstruction, const wchar_t* content) noexcept { - ResourceLoader resourceLoader = - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID); - const hstring errorStr = resourceLoader.GetString(L"AppSettings_Dialog_Error"); - const hstring exitStr = resourceLoader.GetString(L"AppSettings_Dialog_Exit"); - - TASKDIALOG_BUTTON button{ IDCANCEL, exitStr.c_str() }; - TASKDIALOGCONFIG tdc{ - .cbSize = sizeof(TASKDIALOGCONFIG), - .dwFlags = TDF_SIZE_TO_CONTENT, - .pszWindowTitle = errorStr.c_str(), - .pszMainIcon = TD_ERROR_ICON, - .pszMainInstruction = mainInstruction, - .pszContent = content, - .cButtons = 1, - .pButtons = &button, - .pfCallback = TaskDialogCallback - }; - TaskDialogIndirect(&tdc, nullptr, nullptr, nullptr); -} - -static bool ShowOkCancelWarningMessage( - const wchar_t* mainInstruction, - const wchar_t* content, - const wchar_t* okText, - const wchar_t* cancelText -) noexcept { - const hstring warningStr = ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID) - .GetString(L"AppSettings_Dialog_Warning"); - - TASKDIALOG_BUTTON buttons[]{ - {IDOK, okText}, - {IDCANCEL, cancelText} - }; - - TASKDIALOGCONFIG tdc{ - .cbSize = sizeof(TASKDIALOGCONFIG), - .dwFlags = TDF_SIZE_TO_CONTENT, - .pszWindowTitle = warningStr.c_str(), - .pszMainIcon = TD_WARNING_ICON, - .pszMainInstruction = mainInstruction, - .pszContent = content, - .cButtons = (UINT)std::size(buttons), - .pButtons = buttons, - .pfCallback = TaskDialogCallback - }; - - int button = 0; - TaskDialogIndirect(&tdc, &button, nullptr, nullptr); - return button == IDOK; -} - -AppSettings::~AppSettings() {} - -bool AppSettings::Initialize() noexcept { - Logger& logger = Logger::Get(); - - // 若程序所在目录存在配置文件则为便携模式 - _isPortableMode = Win32Utils::FileExists(StrUtils::Concat( - CommonSharedConstants::CONFIG_DIR, CommonSharedConstants::CONFIG_FILENAME).c_str()); - - std::wstring existingConfigPath; - if (!_UpdateConfigPath(&existingConfigPath)) { - logger.Error("_UpdateConfigPath 失败"); - return false; - } - - logger.Info(StrUtils::Concat("便携模式: ", _isPortableMode ? "是" : "否")); - - if (existingConfigPath.empty()) { - logger.Info("不存在配置文件"); - _SetDefaultScalingModes(); - _SetDefaultShortcuts(); - SaveAsync(); - return true; - } - - // 此时 ResourceLoader 使用“首选语言” - - std::string configText; - if (!Win32Utils::ReadTextFile(existingConfigPath.c_str(), configText)) { - logger.Error("读取配置文件失败"); - ResourceLoader resourceLoader = - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID); - hstring title = resourceLoader.GetString(L"AppSettings_ErrorDialog_ReadFailed"); - hstring content = resourceLoader.GetString(L"AppSettings_ErrorDialog_ConfigLocation"); - ShowErrorMessage(title.c_str(), - fmt::format(fmt::runtime(std::wstring_view(content)), existingConfigPath).c_str()); - return false; - } - - if (configText.empty()) { - Logger::Get().Info("配置文件为空"); - _SetDefaultScalingModes(); - _SetDefaultShortcuts(); - SaveAsync(); - return true; - } - - rapidjson::Document doc; - doc.ParseInsitu(configText.data()); - if (doc.HasParseError()) { - Logger::Get().Error(fmt::format("解析配置失败\n\t错误码: {}", (int)doc.GetParseError())); - ResourceLoader resourceLoader = - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID); - hstring title = resourceLoader.GetString(L"AppSettings_ErrorDialog_NotValidJson"); - hstring content = resourceLoader.GetString(L"AppSettings_ErrorDialog_ConfigLocation"); - ShowErrorMessage(title.c_str(), - fmt::format(fmt::runtime(std::wstring_view(content)), existingConfigPath).c_str()); - return false; - } - - if (!doc.IsObject()) { - Logger::Get().Error("配置文件根元素不是 Object"); - ResourceLoader resourceLoader = - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID); - hstring title = resourceLoader.GetString(L"AppSettings_ErrorDialog_ParseFailed"); - hstring content = resourceLoader.GetString(L"AppSettings_ErrorDialog_ConfigLocation"); - ShowErrorMessage(title.c_str(), - fmt::format(fmt::runtime(std::wstring_view(content)), existingConfigPath).c_str()); - return false; - } - - auto root = ((const rapidjson::Document&)doc).GetObj(); - - _LoadSettings(root); - - if (_SetDefaultShortcuts()) { - SaveAsync(); - } - return true; -} - -bool AppSettings::Save() noexcept { - _UpdateWindowPlacement(); - return _Save(*this); -} - -fire_and_forget AppSettings::SaveAsync() noexcept { - _UpdateWindowPlacement(); - - // 拷贝当前配置 - _AppSettingsData data = *this; - co_await resume_background(); - - _Save(data); -} - -void AppSettings::IsPortableMode(bool value) noexcept { - if (_isPortableMode == value) { - return; - } - - if (!value) { - // 关闭便携模式需删除本地配置文件 - if (!DeleteFile(StrUtils::Concat(_configDir, CommonSharedConstants::CONFIG_FILENAME).c_str())) { - if (GetLastError() != ERROR_FILE_NOT_FOUND) { - Logger::Get().Win32Error("删除本地配置文件失败"); - return; - } - } - } - - _isPortableMode = value; - - if (_UpdateConfigPath()) { - Logger::Get().Info(value ? "已开启便携模式" : "已关闭便携模式"); - SaveAsync(); - } else { - Logger::Get().Error(value ? "开启便携模式失败" : "关闭便携模式失败"); - _isPortableMode = !value; - } -} - -void AppSettings::Language(int value) { - if (_language == value) { - return; - } - - _language = value; - SaveAsync(); -} - -void AppSettings::Theme(Magpie::App::Theme value) { - if (_theme == value) { - return; - } - - _theme = value; - ThemeChanged.Invoke(value); - - SaveAsync(); -} - -void AppSettings::SetShortcut(ShortcutAction action, const Magpie::App::Shortcut& value) { - if (_shortcuts[(size_t)action] == value) { - return; - } - - _shortcuts[(size_t)action] = value; - Logger::Get().Info(fmt::format("热键 {} 已更改为 {}", ShortcutHelper::ToString(action), StrUtils::UTF16ToUTF8(value.ToString()))); - ShortcutChanged.Invoke(action); - - SaveAsync(); -} - -void AppSettings::IsAutoRestore(bool value) noexcept { - if (_isAutoRestore == value) { - return; - } - - _isAutoRestore = value; - IsAutoRestoreChanged.Invoke(value); - - SaveAsync(); -} - -void AppSettings::CountdownSeconds(uint32_t value) noexcept { - if (_countdownSeconds == value) { - return; - } - - _countdownSeconds = value; - CountdownSecondsChanged.Invoke(value); - - SaveAsync(); -} - -void AppSettings::IsDeveloperMode(bool value) noexcept { - _isDeveloperMode = value; - if (!value) { - // 关闭开发者模式则禁用所有开发者选项 - _isDebugMode = false; - _isEffectCacheDisabled = false; - _isFontCacheDisabled = false; - _isSaveEffectSources = false; - _isWarningsAreErrors = false; - _duplicateFrameDetectionMode = DuplicateFrameDetectionMode::Dynamic; - _isStatisticsForDynamicDetectionEnabled = false; - } - - SaveAsync(); -} - -void AppSettings::IsAlwaysRunAsAdmin(bool value) noexcept { - if (_isAlwaysRunAsAdmin == value) { - return; - } - - _isAlwaysRunAsAdmin = value; - std::wstring arguments; - if (AutoStartHelper::IsAutoStartEnabled(arguments)) { - // 更新启动任务 - AutoStartHelper::EnableAutoStart(value, _isShowNotifyIcon ? arguments.c_str() : nullptr); - } - - SaveAsync(); -} - -void AppSettings::IsShowNotifyIcon(bool value) noexcept { - if (_isShowNotifyIcon == value) { - return; - } - - _isShowNotifyIcon = value; - IsShowNotifyIconChanged.Invoke(value); - - SaveAsync(); -} - -void AppSettings::_UpdateWindowPlacement() noexcept { - HWND hwndMain = (HWND)Application::Current().as().HwndMain(); - if (!hwndMain) { - return; - } - - WINDOWPLACEMENT wp{ sizeof(wp) }; - if (!GetWindowPlacement(hwndMain, &wp)) { - Logger::Get().Win32Error("GetWindowPlacement 失败"); - return; - } - - _mainWindowCenter = { - (wp.rcNormalPosition.left + wp.rcNormalPosition.right) / 2.0f, - (wp.rcNormalPosition.top + wp.rcNormalPosition.bottom) / 2.0f - }; - - const float dpiFactor = GetDpiForWindow(hwndMain) / float(USER_DEFAULT_SCREEN_DPI); - _mainWindowSizeInDips = { - (wp.rcNormalPosition.right - wp.rcNormalPosition.left) / dpiFactor, - (wp.rcNormalPosition.bottom - wp.rcNormalPosition.top) / dpiFactor, - }; - - _isMainWindowMaximized = wp.showCmd == SW_MAXIMIZE; -} - -bool AppSettings::_Save(const _AppSettingsData& data) noexcept { - HRESULT hr = wil::CreateDirectoryDeepNoThrow(data._configDir.c_str()); - if (FAILED(hr)) { - Logger::Get().ComError("创建配置文件夹失败", hr); - return false; - } - - rapidjson::StringBuffer json; - rapidjson::PrettyWriter writer(json); - writer.StartObject(); - - writer.Key("language"); - if (_language < 0) { - writer.String(""); - } else { - } - - writer.Key("theme"); - writer.Uint((uint32_t)data._theme); - - writer.Key("windowPos"); - writer.StartObject(); - writer.Key("centerX"); - writer.Double(data._mainWindowCenter.X); - writer.Key("centerY"); - writer.Double(data._mainWindowCenter.Y); - writer.Key("width"); - writer.Double(data._mainWindowSizeInDips.Width); - writer.Key("height"); - writer.Double(data._mainWindowSizeInDips.Height); - writer.Key("maximized"); - writer.Bool(data._isMainWindowMaximized); - writer.EndObject(); - - writer.Key("shortcuts"); - writer.StartObject(); - writer.Key("scale"); - writer.Uint(EncodeShortcut(data._shortcuts[(size_t)ShortcutAction::Scale])); - writer.Key("overlay"); - writer.Uint(EncodeShortcut(data._shortcuts[(size_t)ShortcutAction::Overlay])); - writer.EndObject(); - - writer.Key("autoRestore"); - writer.Bool(data._isAutoRestore); - writer.Key("countdownSeconds"); - writer.Uint(data._countdownSeconds); - writer.Key("developerMode"); - writer.Bool(data._isDeveloperMode); - writer.Key("debugMode"); - writer.Bool(data._isDebugMode); - writer.Key("disableEffectCache"); - writer.Bool(data._isEffectCacheDisabled); - writer.Key("disableFontCache"); - writer.Bool(data._isFontCacheDisabled); - writer.Key("saveEffectSources"); - writer.Bool(data._isSaveEffectSources); - writer.Key("warningsAreErrors"); - writer.Bool(data._isWarningsAreErrors); - writer.Key("allowScalingMaximized"); - writer.Bool(data._isAllowScalingMaximized); - writer.Key("simulateExclusiveFullscreen"); - writer.Bool(data._isSimulateExclusiveFullscreen); - writer.Key("alwaysRunAsAdmin"); - writer.Bool(data._isAlwaysRunAsAdmin); - writer.Key("showNotifyIcon"); - writer.Bool(data._isShowNotifyIcon); - writer.Key("inlineParams"); - writer.Bool(data._isInlineParams); - writer.Key("autoCheckForUpdates"); - writer.Bool(data._isAutoCheckForUpdates); - writer.Key("checkForPreviewUpdates"); - writer.Bool(data._isCheckForPreviewUpdates); - writer.Key("updateCheckDate"); - writer.Int64(data._updateCheckDate.time_since_epoch().count()); - writer.Key("duplicateFrameDetectionMode"); - writer.Uint((uint32_t)data._duplicateFrameDetectionMode); - writer.Key("enableStatisticsForDynamicDetection"); - writer.Bool(data._isStatisticsForDynamicDetectionEnabled); - - writer.Key("profiles"); - writer.StartArray(); - WriteProfile(writer, data._defaultProfile); - for (const Profile& rule : data._profiles) { - WriteProfile(writer, rule); - } - writer.EndArray(); - - writer.EndObject(); - - // 防止并行写入 - auto lock = _saveLock.lock_exclusive(); - if (!Win32Utils::WriteTextFile(data._configPath.c_str(), { json.GetString(), json.GetLength() })) { - Logger::Get().Error("保存配置失败"); - return false; - } - - return true; -} - -// 永远不会失败,遇到不合法的配置项时静默忽略 -void AppSettings::_LoadSettings(const rapidjson::GenericObject& root) noexcept { - { - } - - { - uint32_t theme = (uint32_t)Theme::System; - JsonHelper::ReadUInt(root, "theme", theme); - if (theme <= 2) { - _theme = (Magpie::App::Theme)theme; - } else { - _theme = Theme::System; - } - } - - auto windowPosNode = root.FindMember("windowPos"); - if (windowPosNode != root.MemberEnd() && windowPosNode->value.IsObject()) { - const auto& windowPosObj = windowPosNode->value.GetObj(); - - Point center{}; - Size size{}; - if (JsonHelper::ReadFloat(windowPosObj, "centerX", center.X, true) && - JsonHelper::ReadFloat(windowPosObj, "centerY", center.Y, true) && - JsonHelper::ReadFloat(windowPosObj, "width", size.Width, true) && - JsonHelper::ReadFloat(windowPosObj, "height", size.Height, true)) { - _mainWindowCenter = center; - _mainWindowSizeInDips = size; - } else { - // 尽最大努力和旧版本兼容 - int x = 0; - int y = 0; - uint32_t width = 0; - uint32_t height = 0; - if (JsonHelper::ReadInt(windowPosObj, "x", x, true) && - JsonHelper::ReadInt(windowPosObj, "y", y, true) && - JsonHelper::ReadUInt(windowPosObj, "width", width, true) && - JsonHelper::ReadUInt(windowPosObj, "height", height, true)) { - _mainWindowCenter = { - x + width / 2.0f, - y + height / 2.0f - }; - - // 如果窗口位置不存在屏幕则使用主屏幕的缩放,猜错的后果仅是窗口尺寸错误, - // 无论如何原始缩放信息已经丢失。 - const HMONITOR hMon = MonitorFromPoint( - { std::lroundf(_mainWindowCenter.X), std::lroundf(_mainWindowCenter.Y) }, - MONITOR_DEFAULTTOPRIMARY - ); - - UINT dpi = USER_DEFAULT_SCREEN_DPI; - GetDpiForMonitor(hMon, MDT_EFFECTIVE_DPI, &dpi, &dpi); - const float dpiFactor = dpi / float(USER_DEFAULT_SCREEN_DPI); - _mainWindowSizeInDips = { - width / dpiFactor, - height / dpiFactor - }; - } - } - - JsonHelper::ReadBool(windowPosObj, "maximized", _isMainWindowMaximized); - } - - auto shortcutsNode = root.FindMember("shortcuts"); - if (shortcutsNode == root.MemberEnd()) { - // v0.10.0-preview1 使用 hotkeys - shortcutsNode= root.FindMember("hotkeys"); - } - if (shortcutsNode != root.MemberEnd() && shortcutsNode->value.IsObject()) { - const auto& shortcutsObj = shortcutsNode->value.GetObj(); - - auto scaleNode = shortcutsObj.FindMember("scale"); - if (scaleNode != shortcutsObj.MemberEnd() && scaleNode->value.IsUint()) { - DecodeShortcut(scaleNode->value.GetUint(), _shortcuts[(size_t)ShortcutAction::Scale]); - } - - auto overlayNode = shortcutsObj.FindMember("overlay"); - if (overlayNode != shortcutsObj.MemberEnd() && overlayNode->value.IsUint()) { - DecodeShortcut(overlayNode->value.GetUint(), _shortcuts[(size_t)ShortcutAction::Overlay]); - } - } - - JsonHelper::ReadBool(root, "autoRestore", _isAutoRestore); - if (!JsonHelper::ReadUInt(root, "countdownSeconds", _countdownSeconds, true)) { - // v0.10.0-preview1 使用 downCount - JsonHelper::ReadUInt(root, "downCount", _countdownSeconds); - } - if (_countdownSeconds == 0 || _countdownSeconds > 5) { - _countdownSeconds = 3; - } - JsonHelper::ReadBool(root, "developerMode", _isDeveloperMode); - JsonHelper::ReadBool(root, "debugMode", _isDebugMode); - JsonHelper::ReadBool(root, "disableEffectCache", _isEffectCacheDisabled); - JsonHelper::ReadBool(root, "disableFontCache", _isFontCacheDisabled); - JsonHelper::ReadBool(root, "saveEffectSources", _isSaveEffectSources); - JsonHelper::ReadBool(root, "warningsAreErrors", _isWarningsAreErrors); - JsonHelper::ReadBool(root, "allowScalingMaximized", _isAllowScalingMaximized); - JsonHelper::ReadBool(root, "simulateExclusiveFullscreen", _isSimulateExclusiveFullscreen); - if (!JsonHelper::ReadBool(root, "alwaysRunAsAdmin", _isAlwaysRunAsAdmin, true)) { - // v0.10.0-preview1 使用 alwaysRunAsElevated - JsonHelper::ReadBool(root, "alwaysRunAsElevated", _isAlwaysRunAsAdmin); - } - if (!JsonHelper::ReadBool(root, "showNotifyIcon", _isShowNotifyIcon, true)) { - // v0.10 使用 showTrayIcon - JsonHelper::ReadBool(root, "showTrayIcon", _isShowNotifyIcon); - } - JsonHelper::ReadBool(root, "inlineParams", _isInlineParams); - JsonHelper::ReadBool(root, "autoCheckForUpdates", _isAutoCheckForUpdates); - JsonHelper::ReadBool(root, "checkForPreviewUpdates", _isCheckForPreviewUpdates); - { - int64_t d = 0; - JsonHelper::ReadInt64(root, "updateCheckDate", d); - - using std::chrono::system_clock; - _updateCheckDate = system_clock::time_point(system_clock::duration(d)); - } - { - uint32_t duplicateFrameDetectionMode = (uint32_t)DuplicateFrameDetectionMode::Dynamic; - JsonHelper::ReadUInt(root, "duplicateFrameDetectionMode", duplicateFrameDetectionMode); - if (duplicateFrameDetectionMode > 2) { - duplicateFrameDetectionMode = (uint32_t)DuplicateFrameDetectionMode::Dynamic; - } - _duplicateFrameDetectionMode = (::Magpie::Core::DuplicateFrameDetectionMode)duplicateFrameDetectionMode; - } - JsonHelper::ReadBool(root, "enableStatisticsForDynamicDetection", _isStatisticsForDynamicDetectionEnabled); - - - auto scaleProfilesNode = root.FindMember("profiles"); - if (scaleProfilesNode == root.MemberEnd()) { - // v0.10.0-preview1 使用 scalingProfiles - scaleProfilesNode = root.FindMember("scalingProfiles"); - } - if (scaleProfilesNode != root.MemberEnd() && scaleProfilesNode->value.IsArray()) { - const auto& scaleProfilesArray = scaleProfilesNode->value.GetArray(); - - const rapidjson::SizeType size = scaleProfilesArray.Size(); - if (size > 0) { - if (scaleProfilesArray[0].IsObject()) { - // 解析默认缩放配置不会失败 - _LoadProfile(scaleProfilesArray[0].GetObj(), _defaultProfile, true); - } - - if (size > 1) { - _profiles.reserve((size_t)size - 1); - for (rapidjson::SizeType i = 1; i < size; ++i) { - if (!scaleProfilesArray[i].IsObject()) { - continue; - } - - Profile& rule = _profiles.emplace_back(); - if (!_LoadProfile(scaleProfilesArray[i].GetObj(), rule)) { - _profiles.pop_back(); - continue; - } - } - } - } - } -} - -bool AppSettings::_LoadProfile( - const rapidjson::GenericObject& profileObj, - Profile& profile, - bool isDefault -) const noexcept { - if (!isDefault) { - if (!JsonHelper::ReadString(profileObj, "name", profile.name, true)) { - return false; - } - - { - std::wstring_view nameView(profile.name); - StrUtils::Trim(nameView); - if (nameView.empty()) { - return false; - } - } - - if (!JsonHelper::ReadBool(profileObj, "packaged", profile.isPackaged, true)) { - return false; - } - - if (!JsonHelper::ReadString(profileObj, "pathRule", profile.pathRule, true) - || profile.pathRule.empty()) { - return false; - } - - if (!JsonHelper::ReadString(profileObj, "classNameRule", profile.classNameRule, true) - || profile.classNameRule.empty()) { - return false; - } - - JsonHelper::ReadString(profileObj, "launcherPath", profile.launcherPath); - JsonHelper::ReadBool(profileObj, "autoScale", profile.isAutoScale); - JsonHelper::ReadString(profileObj, "launchParameters", profile.launchParameters); - } - - JsonHelper::ReadInt(profileObj, "scalingMode", profile.scalingMode); - if (profile.scalingMode < -1 || profile.scalingMode >= _scalingModes.size()) { - profile.scalingMode = -1; - } - - { - uint32_t captureMethod = (uint32_t)CaptureMethod::GraphicsCapture; - if (!JsonHelper::ReadUInt(profileObj, "captureMethod", captureMethod, true)) { - // v0.10.0-preview1 使用 captureMode - JsonHelper::ReadUInt(profileObj, "captureMode", captureMethod); - } - - if (captureMethod > 3) { - captureMethod = (uint32_t)CaptureMethod::GraphicsCapture; - } else if (captureMethod == (uint32_t)CaptureMethod::DesktopDuplication) { - // Desktop Duplication 捕获模式要求 Win10 20H1+ - if (!Win32Utils::GetOSVersion().Is20H1OrNewer()) { - captureMethod = (uint32_t)CaptureMethod::GraphicsCapture; - } - } - profile.captureMethod = (CaptureMethod)captureMethod; - } - - { - uint32_t multiMonitorUsage = (uint32_t)MultiMonitorUsage::Closest; - JsonHelper::ReadUInt(profileObj, "multiMonitorUsage", multiMonitorUsage); - if (multiMonitorUsage > 2) { - multiMonitorUsage = (uint32_t)MultiMonitorUsage::Closest; - } - profile.multiMonitorUsage = (MultiMonitorUsage)multiMonitorUsage; - } - - if (!JsonHelper::ReadInt(profileObj, "graphicsCard", profile.graphicsCard, true)) { - // v0.10.0-preview1 使用 graphicsAdapter - uint32_t graphicsAdater = 0; - JsonHelper::ReadUInt(profileObj, "graphicsAdapter", graphicsAdater); - profile.graphicsCard = (int)graphicsAdater - 1; - } - - JsonHelper::ReadBool(profileObj, "frameRateLimiterEnabled", profile.isFrameRateLimiterEnabled); - JsonHelper::ReadFloat(profileObj, "maxFrameRate", profile.maxFrameRate); - if (profile.maxFrameRate < 10.0f || profile.maxFrameRate > 1000.0f) { - profile.maxFrameRate = 60.0f; - } - - JsonHelper::ReadBoolFlag(profileObj, "disableWindowResizing", ScalingFlags::DisableWindowResizing, profile.scalingFlags); - JsonHelper::ReadBoolFlag(profileObj, "3DGameMode", ScalingFlags::Is3DGameMode, profile.scalingFlags); - JsonHelper::ReadBoolFlag(profileObj, "showFPS", ScalingFlags::ShowFPS, profile.scalingFlags); - if (!JsonHelper::ReadBoolFlag(profileObj, "captureTitleBar", ScalingFlags::CaptureTitleBar, profile.scalingFlags, true)) { - // v0.10.0-preview1 使用 reserveTitleBar - JsonHelper::ReadBoolFlag(profileObj, "reserveTitleBar", ScalingFlags::CaptureTitleBar, profile.scalingFlags); - } - JsonHelper::ReadBoolFlag(profileObj, "adjustCursorSpeed", ScalingFlags::AdjustCursorSpeed, profile.scalingFlags); - JsonHelper::ReadBoolFlag(profileObj, "drawCursor", ScalingFlags::DrawCursor, profile.scalingFlags); - JsonHelper::ReadBoolFlag(profileObj, "disableDirectFlip", ScalingFlags::DisableDirectFlip, profile.scalingFlags); - - { - uint32_t cursorScaling = (uint32_t)CursorScaling::NoScaling; - JsonHelper::ReadUInt(profileObj, "cursorScaling", cursorScaling); - if (cursorScaling > 7) { - cursorScaling = (uint32_t)CursorScaling::NoScaling; - } - profile.cursorScaling = (CursorScaling)cursorScaling; - } - - JsonHelper::ReadFloat(profileObj, "customCursorScaling", profile.customCursorScaling); - if (profile.customCursorScaling < 0) { - profile.customCursorScaling = 1.0f; - } - - { - uint32_t cursorInterpolationMode = (uint32_t)CursorInterpolationMode::NearestNeighbor; - JsonHelper::ReadUInt(profileObj, "cursorInterpolationMode", cursorInterpolationMode); - if (cursorInterpolationMode > 1) { - cursorInterpolationMode = (uint32_t)CursorInterpolationMode::NearestNeighbor; - } - profile.cursorInterpolationMode = (CursorInterpolationMode)cursorInterpolationMode; - } - - JsonHelper::ReadBool(profileObj, "croppingEnabled", profile.isCroppingEnabled); - - auto croppingNode = profileObj.FindMember("cropping"); - if (croppingNode != profileObj.MemberEnd() && croppingNode->value.IsObject()) { - const auto& croppingObj = croppingNode->value.GetObj(); - - if (!JsonHelper::ReadFloat(croppingObj, "left", profile.cropping.Left, true) - || profile.cropping.Left < 0 - || !JsonHelper::ReadFloat(croppingObj, "top", profile.cropping.Top, true) - || profile.cropping.Top < 0 - || !JsonHelper::ReadFloat(croppingObj, "right", profile.cropping.Right, true) - || profile.cropping.Right < 0 - || !JsonHelper::ReadFloat(croppingObj, "bottom", profile.cropping.Bottom, true) - || profile.cropping.Bottom < 0 - ) { - profile.cropping = {}; - } - } - - return true; -} - -bool AppSettings::_SetDefaultShortcuts() noexcept { - bool changed = false; - - Shortcut& scaleShortcut = _shortcuts[(size_t)ShortcutAction::Scale]; - if (scaleShortcut.IsEmpty()) { - scaleShortcut.win = true; - scaleShortcut.shift = true; - scaleShortcut.code = 'A'; - - changed = true; - } - - Shortcut& overlayShortcut = _shortcuts[(size_t)ShortcutAction::Overlay]; - if (overlayShortcut.IsEmpty()) { - overlayShortcut.win = true; - overlayShortcut.shift = true; - overlayShortcut.code = 'D'; - - changed = true; - } - - return changed; -} - -void AppSettings::_SetDefaultScalingModes() noexcept { - _scalingModes.resize(7); - - // Lanczos - { - auto& lanczos = _scalingModes[0]; - lanczos.name = L"Lanczos"; - - auto& lanczosEffect = lanczos.effects.emplace_back(); - lanczosEffect.name = L"Lanczos"; - lanczosEffect.scalingType = ::Magpie::Core::ScalingType::Fit; - } - // FSR - { - auto& fsr = _scalingModes[1]; - fsr.name = L"FSR"; - - fsr.effects.resize(2); - auto& easu = fsr.effects[0]; - easu.name = L"FSR\\FSR_EASU"; - easu.scalingType = ::Magpie::Core::ScalingType::Fit; - auto& rcas = fsr.effects[1]; - rcas.name = L"FSR\\FSR_RCAS"; - rcas.parameters[L"sharpness"] = 0.87f; - } - // FSRCNNX - { - auto& fsrcnnx = _scalingModes[2]; - fsrcnnx.name = L"FSRCNNX"; - fsrcnnx.effects.emplace_back().name = L"FSRCNNX\\FSRCNNX"; - } - // ACNet - { - auto& acnet = _scalingModes[3]; - acnet.name = L"ACNet"; - acnet.effects.emplace_back().name = L"ACNet"; - } - // Anime4K - { - auto& anime4k = _scalingModes[4]; - anime4k.name = L"Anime4K"; - anime4k.effects.emplace_back().name = L"Anime4K\\Anime4K_Upscale_Denoise_L"; - } - // CRT-Geom - { - auto& crtGeom = _scalingModes[5]; - crtGeom.name = L"CRT-Geom"; - - auto& crtGeomEffect = crtGeom.effects.emplace_back(); - crtGeomEffect.name = L"CRT\\CRT_Geom"; - crtGeomEffect.scalingType = ::Magpie::Core::ScalingType::Fit; - crtGeomEffect.parameters[L"curvature"] = 0.0f; - crtGeomEffect.parameters[L"cornerSize"] = 0.001f; - crtGeomEffect.parameters[L"CRTGamma"] = 1.5f; - crtGeomEffect.parameters[L"monitorGamma"] = 2.2f; - crtGeomEffect.parameters[L"interlace"] = 0.0f; - } - // Integer Scale 2x - { - auto& integer2x = _scalingModes[6]; - integer2x.name = L"Integer Scale 2x"; - - auto& nearest = integer2x.effects.emplace_back(); - nearest.name = L"Nearest"; - nearest.scalingType = ::Magpie::Core::ScalingType::Normal; - nearest.scale = { 2.0f,2.0f }; - } - - // 全局缩放模式默认为 Lanczos - _defaultProfile.scalingMode = 0; -} - -static std::wstring FindOldConfig(const wchar_t* localAppDataDir) noexcept { - for (uint32_t version = CONFIG_VERSION - 1; version >= 2; --version) { - std::wstring oldConfigPath = fmt::format( - L"{}\\Magpie\\{}v{}\\{}", - localAppDataDir, - CommonSharedConstants::CONFIG_DIR, - version, - CommonSharedConstants::CONFIG_FILENAME - ); - - if (Win32Utils::FileExists(oldConfigPath.c_str())) { - return oldConfigPath; - } - } - - // v1 版本的配置文件不在子目录中 - std::wstring v1ConfigPath = StrUtils::Concat( - localAppDataDir, - L"\\Magpie\\", - CommonSharedConstants::CONFIG_DIR, - CommonSharedConstants::CONFIG_FILENAME - ); - - if (Win32Utils::FileExists(v1ConfigPath.c_str())) { - return v1ConfigPath; - } - - return {}; -} - -bool AppSettings::_UpdateConfigPath(std::wstring* existingConfigPath) noexcept { - if (_isPortableMode) { - HRESULT hr = wil::GetFullPathNameW(CommonSharedConstants::CONFIG_DIR, _configDir); - if (FAILED(hr)) { - Logger::Get().ComError("GetFullPathNameW 失败", hr); - return false; - } - - _configPath = _configDir + CommonSharedConstants::CONFIG_FILENAME; - - if (existingConfigPath) { - if (Win32Utils::FileExists(_configPath.c_str())) { - *existingConfigPath = _configPath; - } - } - } else { - wil::unique_cotaskmem_string localAppDataDir; - HRESULT hr = SHGetKnownFolderPath( - FOLDERID_LocalAppData, KF_FLAG_DEFAULT, NULL, localAppDataDir.put()); - if (FAILED(hr)) { - Logger::Get().ComError("SHGetKnownFolderPath 失败", hr); - return false; - } - - _configDir = fmt::format(L"{}\\Magpie\\{}v{}\\", - localAppDataDir.get(), CommonSharedConstants::CONFIG_DIR, CONFIG_VERSION); - _configPath = _configDir + CommonSharedConstants::CONFIG_FILENAME; - - if (existingConfigPath) { - if (Win32Utils::FileExists(_configPath.c_str())) { - *existingConfigPath = _configPath; - } else { - // 查找旧版本配置文件 - *existingConfigPath = FindOldConfig(localAppDataDir.get()); - } - } - } - - // 确保配置文件夹存在 - HRESULT hr = wil::CreateDirectoryDeepNoThrow(_configDir.c_str()); - if (FAILED(hr)) { - Logger::Get().ComError("创建配置文件夹失败", hr); - return false; - } - - return true; -} - -} diff --git a/src/Magpie.App/AppSettings.h b/src/Magpie.App/AppSettings.h deleted file mode 100644 index c05a982f4..000000000 --- a/src/Magpie.App/AppSettings.h +++ /dev/null @@ -1,317 +0,0 @@ -#pragma once -#include -#include "WinRTUtils.h" -#include "Shortcut.h" -#include "Profile.h" -#include -#include -#include "Win32Utils.h" -#include - -namespace winrt::Magpie::App { - -struct ScalingMode; - -enum class Theme { - Light, - Dark, - System -}; - -struct _AppSettingsData { - _AppSettingsData(); - virtual ~_AppSettingsData(); - - std::array _shortcuts; - - std::vector _scalingModes; - - Profile _defaultProfile; - std::vector _profiles; - - std::wstring _configDir; - std::wstring _configPath; - - // LocalizationService::SupportedLanguages 索引 - // -1 表示使用系统设置 - int _language = -1; - - // 保存窗口中心点和 DPI 无关的窗口尺寸 - Point _mainWindowCenter{}; - // 小于零表示默认位置和尺寸 - Size _mainWindowSizeInDips{ -1.0f,-1.0f }; - - Theme _theme = Theme::System; - // 必须在 1~5 之间 - uint32_t _countdownSeconds = 3; - - // 上一次自动检查更新的日期 - std::chrono::system_clock::time_point _updateCheckDate; - - ::Magpie::Core::DuplicateFrameDetectionMode _duplicateFrameDetectionMode = - ::Magpie::Core::DuplicateFrameDetectionMode::Dynamic; - - bool _isPortableMode = false; - bool _isAlwaysRunAsAdmin = false; - bool _isDeveloperMode = false; - bool _isDebugMode = false; - bool _isEffectCacheDisabled = false; - bool _isFontCacheDisabled = false; - bool _isSaveEffectSources = false; - bool _isWarningsAreErrors = false; - bool _isAllowScalingMaximized = false; - bool _isSimulateExclusiveFullscreen = false; - bool _isInlineParams = false; - bool _isShowNotifyIcon = true; - bool _isAutoRestore = false; - bool _isMainWindowMaximized = false; - bool _isAutoCheckForUpdates = true; - bool _isCheckForPreviewUpdates = false; - bool _isStatisticsForDynamicDetectionEnabled = false; -}; - -class AppSettings : private _AppSettingsData { -public: - static AppSettings& Get() noexcept { - static AppSettings instance; - return instance; - } - - virtual ~AppSettings(); - - bool Initialize() noexcept; - - bool Save() noexcept; - - fire_and_forget SaveAsync() noexcept; - - const std::wstring& ConfigDir() const noexcept { - return _configDir; - } - - bool IsPortableMode() const noexcept { - return _isPortableMode; - } - - void IsPortableMode(bool value) noexcept; - - int Language() const noexcept { - return _language; - } - - void Language(int); - - Theme Theme() const noexcept { - return _theme; - } - void Theme(Magpie::App::Theme value); - - Point MainWindowCenter() const noexcept { - return _mainWindowCenter; - } - - Size MainWindowSizeInDips() const noexcept { - return _mainWindowSizeInDips; - } - - bool IsWindowMaximized() const noexcept { - return _isMainWindowMaximized; - } - - const Shortcut& GetShortcut(ShortcutAction action) const { - return _shortcuts[(size_t)action]; - } - - void SetShortcut(ShortcutAction action, const Shortcut& value); - - bool IsAutoRestore() const noexcept { - return _isAutoRestore; - } - - void IsAutoRestore(bool value) noexcept; - - uint32_t CountdownSeconds() const noexcept { - return _countdownSeconds; - } - - void CountdownSeconds(uint32_t value) noexcept; - - bool IsDeveloperMode() const noexcept { - return _isDeveloperMode; - } - - void IsDeveloperMode(bool value) noexcept; - - bool IsDebugMode() const noexcept { - return _isDebugMode; - } - - void IsDebugMode(bool value) noexcept { - _isDebugMode = value; - SaveAsync(); - } - - bool IsEffectCacheDisabled() const noexcept { - return _isEffectCacheDisabled; - } - - void IsEffectCacheDisabled(bool value) noexcept { - _isEffectCacheDisabled = value; - SaveAsync(); - } - - bool IsFontCacheDisabled() const noexcept { - return _isFontCacheDisabled; - } - - void IsFontCacheDisabled(bool value) noexcept { - _isFontCacheDisabled = value; - SaveAsync(); - } - - bool IsSaveEffectSources() const noexcept { - return _isSaveEffectSources; - } - - void IsSaveEffectSources(bool value) noexcept { - _isSaveEffectSources = value; - SaveAsync(); - } - - bool IsWarningsAreErrors() const noexcept { - return _isWarningsAreErrors; - } - - void IsWarningsAreErrors(bool value) noexcept { - _isWarningsAreErrors = value; - SaveAsync(); - } - - bool IsAllowScalingMaximized() const noexcept { - return _isAllowScalingMaximized; - } - - void IsAllowScalingMaximized(bool value) noexcept { - _isAllowScalingMaximized = value; - SaveAsync(); - } - - bool IsSimulateExclusiveFullscreen() const noexcept { - return _isSimulateExclusiveFullscreen; - } - - void IsSimulateExclusiveFullscreen(bool value) noexcept { - _isSimulateExclusiveFullscreen = value; - SaveAsync(); - } - - Profile& DefaultProfile() noexcept { - return _defaultProfile; - } - - std::vector& Profiles() noexcept { - return _profiles; - } - - bool IsAlwaysRunAsAdmin() const noexcept { - return _isAlwaysRunAsAdmin; - } - - void IsAlwaysRunAsAdmin(bool value) noexcept; - - bool IsShowNotifyIcon() const noexcept { - return _isShowNotifyIcon; - } - - void IsShowNotifyIcon(bool value) noexcept; - - bool IsInlineParams() const noexcept { - return _isInlineParams; - } - - void IsInlineParams(bool value) noexcept { - _isInlineParams = value; - SaveAsync(); - } - - std::vector& ScalingModes() noexcept { - return _scalingModes; - } - - bool IsAutoCheckForUpdates() const noexcept { - return _isAutoCheckForUpdates; - } - - void IsAutoCheckForUpdates(bool value) noexcept { - _isAutoCheckForUpdates = value; - IsAutoCheckForUpdatesChanged.Invoke(value); - SaveAsync(); - } - - bool IsCheckForPreviewUpdates() const noexcept { - return _isCheckForPreviewUpdates; - } - - void IsCheckForPreviewUpdates(bool value) noexcept { - _isCheckForPreviewUpdates = value; - SaveAsync(); - } - - std::chrono::system_clock::time_point UpdateCheckDate() const noexcept { - return _updateCheckDate; - } - - void UpdateCheckDate(std::chrono::system_clock::time_point value) noexcept { - _updateCheckDate = value; - } - - ::Magpie::Core::DuplicateFrameDetectionMode DuplicateFrameDetectionMode() const noexcept { - return _duplicateFrameDetectionMode; - } - - void DuplicateFrameDetectionMode(::Magpie::Core::DuplicateFrameDetectionMode value) noexcept { - _duplicateFrameDetectionMode = value; - SaveAsync(); - } - - bool IsStatisticsForDynamicDetectionEnabled() const noexcept { - return _isStatisticsForDynamicDetectionEnabled; - } - - void IsStatisticsForDynamicDetectionEnabled(bool value) noexcept { - _isStatisticsForDynamicDetectionEnabled = value; - SaveAsync(); - } - - WinRTUtils::Event> ThemeChanged; - WinRTUtils::Event> ShortcutChanged; - WinRTUtils::Event> IsAutoRestoreChanged; - WinRTUtils::Event> CountdownSecondsChanged; - WinRTUtils::Event> IsShowNotifyIconChanged; - WinRTUtils::Event> IsAutoCheckForUpdatesChanged; - -private: - AppSettings() = default; - - AppSettings(const AppSettings&) = delete; - AppSettings(AppSettings&&) = delete; - - void _UpdateWindowPlacement() noexcept; - bool _Save(const _AppSettingsData& data) noexcept; - - void _LoadSettings(const rapidjson::GenericObject& root) noexcept; - bool _LoadProfile( - const rapidjson::GenericObject& profileObj, - Profile& profile, - bool isDefault = false - ) const noexcept; - bool _SetDefaultShortcuts() noexcept; - void _SetDefaultScalingModes() noexcept; - - bool _UpdateConfigPath(std::wstring* existingConfigPath = nullptr) noexcept; - - // 用于同步保存 - wil::srwlock _saveLock; -}; - -} diff --git a/src/Magpie.App/AppXReader.cpp b/src/Magpie.App/AppXReader.cpp deleted file mode 100644 index f241f2267..000000000 --- a/src/Magpie.App/AppXReader.cpp +++ /dev/null @@ -1,785 +0,0 @@ -#include "pch.h" -#include "AppXReader.h" -#include "Win32Utils.h" -#include "StrUtils.h" -#include "Logger.h" -#include -#include -#include -#include -#include -#include - -using namespace winrt; -using namespace Windows::Graphics::Imaging; -using namespace Windows::UI; -using namespace Windows::UI::Xaml::Media::Imaging; -using namespace Windows::UI::ViewManagement; - - -namespace winrt::Magpie::App { - -struct AppxCacheData { - std::wstring praid; - std::wstring packageFullName; - std::wstring packagePath; - std::wstring displayName; - std::wstring executable; - std::wstring square44x44Logo; -}; -static phmap::flat_hash_map appxCache; -// 用于同步对 appxCache 的访问 -static wil::srwlock appxCacheLock; - - -static std::wstring ResourceFromPri(std::wstring_view packageFullName, std::wstring_view resourceReference) { - // 移植自 https://github.com/microsoft/PowerToys/blob/c36a80dad571db26d6cf9e40e70099815ed56049/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Programs/UWPApplication.cs#L299 - - std::wstring_view prefix = L"ms-resource:"; - - StrUtils::Trim(resourceReference); - - std::wstring lowerCaseResourceReference = StrUtils::ToLowerCase(resourceReference); - - // Using OrdinalIgnoreCase since this is used internally - if (!lowerCaseResourceReference.starts_with(prefix)) { - return std::wstring(resourceReference); - } - - // magic comes from @talynone - // https://github.com/talynone/Wox.Plugin.WindowsUniversalAppLauncher/blob/master/StoreAppLauncher/Helpers/NativeApiHelper.cs#L139-L153 - std::wstring_view key = resourceReference.substr(prefix.size()); - - std::wstring parsed; - std::wstring parsedFallback; - - // Using Ordinal/OrdinalIgnoreCase since these are used internally - if (key.starts_with(L"//")) { - parsed = StrUtils::Concat(prefix, key); - } else if (key.starts_with(L'/')) { - parsed = StrUtils::Concat(prefix, L"//", key); - } else { - std::wstring_view lowerCaseKey( - lowerCaseResourceReference.begin() + prefix.size(), - lowerCaseResourceReference.end() - ); - - if (lowerCaseKey.starts_with(L"resources")) { - parsed = StrUtils::Concat(prefix, key); - } else { - parsed = StrUtils::Concat(prefix, L"///resources/", key); - - // e.g. for Windows Terminal version >= 1.12 DisplayName and Description resources are not in the 'resources' subtree - parsedFallback = StrUtils::Concat(prefix, L"///", key); - } - } - - std::wstring source = fmt::format(L"@{{{}? {}}}", packageFullName, parsed); - - std::wstring result(128, 0); - HRESULT hr = SHLoadIndirectString(source.c_str(), result.data(), (UINT)result.size() + 1, nullptr); - if (FAILED(hr)) { - if (parsedFallback.empty()) { - return {}; - } - - source = fmt::format(L"@{{{}? {}}}", packageFullName, parsedFallback); - hr = SHLoadIndirectString(source.c_str(), result.data(), (UINT)result.size() + 1, nullptr); - if (FAILED(hr)) { - Logger::Get().ComError("SHLoadIndirectString 失败", hr); - return {}; - } - } - - result.resize(StrUtils::StrLen(result.c_str())); - return result; -} - -bool AppXReader::Initialize(HWND hWnd) noexcept { - bool isSuspended = false; - if (Win32Utils::GetWndClassName(hWnd) == L"ApplicationFrameWindow") { - // UWP 应用被托管在 ApplicationFrameHost 进程中 - HWND childHwnd = NULL; - EnumChildWindows( - hWnd, - [](HWND hWnd, LPARAM lParam) { - if (Win32Utils::GetWndClassName(hWnd) != L"Windows.UI.Core.CoreWindow") { - return TRUE; - } - - *(HWND*)lParam = hWnd; - return FALSE; - }, - (LPARAM)&childHwnd - ); - - if (childHwnd == NULL) { - // 特殊情况下 UWP 应用无法通过子窗口找到 - // 比如被最小化(挂起)或尚未完成初始化 - isSuspended = true; - } else { - hWnd = childHwnd; - } - } - - if (isSuspended) { - // 窗口被挂起,此时 UWP 进程无法通过子窗口找到 - // 回落到从窗口的 PropertyStore 中检索 AUMID - // 来自 https://github.com/valinet/sws/blob/bc8b04e451649964ee3d74255f9e9eda13ef24c3/SimpleWindowSwitcher/sws_IconPainter.c#L257 - com_ptr propStore; - HRESULT hr = SHGetPropertyStoreForWindow(hWnd, IID_PPV_ARGS(&propStore)); - if (FAILED(hr)) { - Logger::Get().ComError("SHGetPropertyStoreForWindow 失败", hr); - return false; - } - - wil::unique_prop_variant prop; - hr = propStore->GetValue(PKEY_AppUserModel_ID, &prop); - if (FAILED(hr) || prop.vt != VT_LPWSTR || !prop.pwszVal) { - return false; - } - - return Initialize(prop.pwszVal); - } - - // 使用 GetApplicationUserModelId 获取 AUMID - DWORD dwProcId = 0; - if (!GetWindowThreadProcessId(hWnd, &dwProcId)) { - Logger::Get().Win32Error("GetWindowThreadProcessId 失败"); - return false; - } - - wil::unique_process_handle hProc(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwProcId)); - if (!hProc) { - Logger::Get().Win32Error("OpenProcess 失败"); - return false; - } - - std::wstring aumid; - HRESULT hr = wil::AdaptFixedSizeToAllocatedResult( - aumid, [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT { - UINT32 length = (UINT32)valueLength; - LONG rc = GetApplicationUserModelId(hProc.get(), &length, value); - if (rc != ERROR_SUCCESS && rc != ERROR_INSUFFICIENT_BUFFER) { - return HRESULT_FROM_WIN32(rc); - } - - *valueLengthNeededWithNul = length; - return S_OK; - } - ); - if (FAILED(hr)) { - return false; - } - - return Initialize(aumid); -} - -bool AppXReader::Initialize(std::wstring_view aumid) noexcept { - { - auto lock = appxCacheLock.lock_exclusive(); - - auto it = appxCache.find(aumid); - if (it != appxCache.end()) { - if (it->second.packagePath.empty()) { - // 之前的解析失败 - return false; - } - - _aumid = aumid; - _praid = it->second.praid; - _packageFullName = it->second.packageFullName; - _packagePath = it->second.packagePath; - _displayName = it->second.displayName; - _executable = it->second.executable; - _square44x44Logo = it->second.square44x44Logo; - return true; - } - - appxCache.emplace(aumid, AppxCacheData()); - } - - _aumid = aumid; - - if (!_ResolvePackagePath()) { - Logger::Get().Error("_ResolvePackagePath 失败"); - return false; - } - - com_ptr factory = try_create_instance(CLSID_AppxFactory); - if (!factory) { - Logger::Get().Error("创建 AppxFactory 失败"); - return false; - } - - com_ptr inputStream; - HRESULT hr = SHCreateStreamOnFileEx( - (_packagePath + L"AppXManifest.xml").c_str(), - STGM_READ | STGM_SHARE_DENY_WRITE, - 0, - FALSE, - nullptr, - inputStream.put() - ); - if (FAILED(hr)) { - Logger::Get().ComError("打开 AppXManifest.xml 失败", hr); - return false; - } - - com_ptr manifestReader; - hr = factory->CreateManifestReader( - inputStream.get(), - manifestReader.put() - ); - if (FAILED(hr)) { - Logger::Get().ComError("CreateManifestReader 失败", hr); - return false; - } - - com_ptr appEnumerator; - hr = manifestReader->GetApplications(appEnumerator.put()); - if (FAILED(hr)) { - Logger::Get().ComError("GetApplications 失败", hr); - return false; - } - - // 枚举所有应用查找 praid - BOOL hasCurrent = FALSE; - hr = appEnumerator->GetHasCurrent(&hasCurrent); - - while (SUCCEEDED(hr) && hasCurrent) { - com_ptr appxApp; - if (FAILED(appEnumerator->GetCurrent(appxApp.put()))) { - break; - } - - wil::unique_cotaskmem_string curPraid; - if (FAILED(appxApp->GetStringValue(L"Id", curPraid.put()))) { - break; - } - - if (curPraid && _praid == curPraid.get()) { - wil::unique_cotaskmem_string value; - if (SUCCEEDED(appxApp->GetStringValue(L"DisplayName", value.put())) && value) { - _displayName = value.get(); - } - - value = nullptr; - if (SUCCEEDED(appxApp->GetStringValue(L"Executable", value.put())) && value) { - _executable = value.get(); - } - - value = nullptr; - if (SUCCEEDED(appxApp->GetStringValue(L"Square44x44Logo", value.put())) && value) { - _square44x44Logo = value.get(); - } - - auto lock = appxCacheLock.lock_exclusive(); - AppxCacheData& cacheData = appxCache[aumid]; - cacheData.praid = _praid; - cacheData.packageFullName = _packageFullName; - cacheData.packagePath = _packagePath; - cacheData.displayName = _displayName; - cacheData.executable = _executable; - cacheData.square44x44Logo = _square44x44Logo; - return true; - } - - hr = appEnumerator->MoveNext(&hasCurrent); - } - - // 未找到 Id 为 praid 的应用 - return false; -} - -std::wstring AppXReader::GetDisplayName() noexcept { - assert(!_packagePath.empty()); - - if (_displayName.empty()) { - return {}; - } - - return ResourceFromPri(_packageFullName, _displayName); -} - -const std::wstring& AppXReader::GetPackagePath() noexcept { - assert(!_packagePath.empty()); - return _packagePath; -} - -std::wstring AppXReader::GetExecutablePath() noexcept { - assert(!_packagePath.empty()); - - if (_executable.empty()) { - return {}; - } - - return _packagePath + _executable; -} - -class CandidateIcon { -public: - CandidateIcon(const wchar_t* fileName) : _fileName(fileName) { - size_t firstPointPos = _fileName.find_first_of(L'.'); - if (firstPointPos == std::wstring::npos) { - _isValid = false; - return; - } - - size_t secondPointPos = _fileName.find_last_of(L'.'); - if (secondPointPos == firstPointPos) { - _size = 44; - return; - } else if (secondPointPos == std::wstring::npos || secondPointPos <= firstPointPos + 1) { - _isValid = false; - return; - } - - std::wstring_view suffix(_fileName.begin() + firstPointPos + 1, _fileName.begin() + secondPointPos); - assert(suffix.find(L'.') == std::wstring_view::npos); - - for (std::wstring_view qualifier : StrUtils::Split(suffix, L'_')) { - size_t delimPos = qualifier.find_first_of(L'-'); - if (delimPos == std::wstring_view::npos) { - _isValid = false; - return; - } - - std::wstring_view name(qualifier.begin(), qualifier.begin() + delimPos); - std::wstring_view value(qualifier.begin() + delimPos + 1, qualifier.end()); - - if (name == L"targetsize") { - _isTargetSize = true; - - if (value == L"16") { - _size = 16; - } else if (value == L"24") { - _size = 24; - } else if (value == L"30") { - _size = 30; - } else if (value == L"32") { - _size = 32; - } else if (value == L"36") { - _size = 36; - } else if (value == L"44") { - _size = 44; - } else if (value == L"48") { - _size = 48; - } else if (value == L"60") { - _size = 60; - } else if (value == L"72") { - _size = 72; - } else if (value == L"96") { - _size = 96; - } else if (value == L"128") { - _size = 128; - } else if (value == L"180") { - _size = 180; - } else if (value == L"256") { - _size = 256; - } else { - _isValid = false; - } - } else if (name == L"scale") { - _isScale = true; - - if (value == L"100") { - _size = 44; - } else if (value == L"125") { - _size = 55; - } else if (value == L"150") { - _size = 66; - } else if (value == L"200") { - _size = 88; - } else if (value == L"400") { - _size = 176; - } else { - _isValid = false; - } - } else if (name == L"altform") { - if (value == L"lightunplated") { - _isLightTheme = true; - _isUnplated = true; - } else if (value == L"unplated") { - _isUnplated = true; - } - } else if (name == L"theme") { - if (value == L"light") { - _isLightTheme = true; - } - } else if (name == L"contrast") { - _isValid = false; - return; - } - } - } - - const std::wstring& FileName() const noexcept { - return _fileName; - } - - bool IsValid() const noexcept { - return _isValid; - } - - // 用以选择更合适的图标。规则: - // 1. 匹配当前主题的优先 - // 2. 没有边框的优先 - // 3. 和 preferredSize 相同的优先 - // 4. 如果一个过大,另一个过小,取大的 - // 5. 如果都过大或过小,取更接近 preferredSize 的 - // 6. 优先选择 targetsize 前缀,然后是 scale 前缀 - static bool Compare(const CandidateIcon& l, const CandidateIcon& r, uint32_t preferredSize, bool isLightTheme) { - if (l._isLightTheme != r._isLightTheme) { - return l._isLightTheme == isLightTheme; - } - - // 优先选择没有边框的图标 - if (l._isUnplated != r._isUnplated) { - return l._isUnplated; - } - - if (l._size != r._size) { - if (l._size == preferredSize) { - return true; - } - if (r._size == preferredSize) { - return false; - } - - if (l._size > preferredSize) { - if (r._size > preferredSize) { - return l._size < r._size; - } else { - return true; - } - } else { - if (r._size > preferredSize) { - return false; - } else { - return l._size > r._size; - } - } - } - - if (l._isTargetSize != r._isTargetSize) { - return l._isTargetSize; - } - - if (l._isScale != r._isScale) { - return l._isScale; - } - - return false; - } - -private: - bool _isTargetSize = false; - bool _isScale = false; - bool _isValid = true; - std::wstring _fileName; - uint32_t _size = 0; - bool _isLightTheme = false; - bool _isUnplated = false; -}; - -// 如果图标和背景的对比度太低,使用主题色填充背景 -static SoftwareBitmap AutoFillBackground(const std::wstring& iconPath, bool isLightTheme, bool noPath) { - com_ptr wicImgFactory = try_create_instance(CLSID_WICImagingFactory); - if (!wicImgFactory) { - Logger::Get().Error("创建 WICImagingFactory2 失败"); - return nullptr; - } - - // 读取图像文件 - winrt::com_ptr decoder; - HRESULT hr = wicImgFactory->CreateDecoderFromFilename( - iconPath.c_str(), nullptr, GENERIC_READ, WICDecodeMetadataCacheOnDemand, decoder.put()); - if (FAILED(hr)) { - Logger::Get().ComError("CreateDecoderFromFilename 失败", hr); - return nullptr; - } - - winrt::com_ptr frame; - hr = decoder->GetFrame(0, frame.put()); - if (FAILED(hr)) { - Logger::Get().ComError("IWICBitmapFrameDecode::GetFrame 失败", hr); - return nullptr; - } - - // 转换格式 - winrt::com_ptr formatConverter; - hr = wicImgFactory->CreateFormatConverter(formatConverter.put()); - if (FAILED(hr)) { - Logger::Get().ComError("CreateFormatConverter 失败", hr); - return nullptr; - } - - hr = formatConverter->Initialize(frame.get(), - GUID_WICPixelFormat32bppBGRA, WICBitmapDitherTypeNone, nullptr, 0, WICBitmapPaletteTypeCustom); - if (FAILED(hr)) { - Logger::Get().ComError("IWICFormatConverter::Initialize 失败", hr); - return nullptr; - } - - UINT width, height; - hr = formatConverter->GetSize(&width, &height); - if (FAILED(hr)) { - Logger::Get().ComError("GetSize 失败", hr); - return nullptr; - } - - UINT stride = width * 4; - UINT size = stride * height; - std::unique_ptr buf(new uint8_t[size]); - - hr = formatConverter->CopyPixels(nullptr, stride, size, buf.get()); - if (FAILED(hr)) { - Logger::Get().ComError("CopyPixels 失败", hr); - return nullptr; - } - - // 计算平均亮度 - float lumaTotal = 0; - uint32_t lumaCount = 0; - for (uint32_t i = 0, len = width * height; i < len; ++i) { - uint8_t* pixel = &buf.get()[i * 4]; - - uint8_t alpha = pixel[3]; - if (alpha == 0) { - continue; - } - - float luma = 0.299f * pixel[0] + 0.587f * pixel[1] + 0.114f * pixel[2]; - if (alpha != 255) { - float alphaNorm = alpha / 255.0f; - luma = luma * alphaNorm + (isLightTheme ? 255 : 0) * (1 - alphaNorm); - } - - lumaTotal += luma; - ++lumaCount; - } - - const float lumaAvg = lumaTotal / lumaCount; - if (isLightTheme ? lumaAvg <= 220 : lumaAvg >= 30) { - if (!noPath) { - return nullptr; - } - - SoftwareBitmap bitmap(BitmapPixelFormat::Bgra8, width, height, BitmapAlphaMode::Premultiplied); - { - BitmapBuffer buffer = bitmap.LockBuffer(BitmapBufferAccessMode::Write); - uint8_t* pixels = buffer.CreateReference().data(); - - const uint8_t* origin = buf.get(); - for (size_t i = 0, pixelsSize = static_cast(width) * height * 4; i < pixelsSize; i += 4) { - // 预乘 Alpha 通道 - const float alpha = origin[i + 3] / 255.0f; - - pixels[i] = (BYTE)std::lround(origin[i] * alpha); - pixels[i + 1] = (BYTE)std::lround(origin[i + 1] * alpha); - pixels[i + 2] = (BYTE)std::lround(origin[i + 2] * alpha); - pixels[i + 3] = origin[i + 3]; - } - } - return bitmap; - } - - // 和背景的对比度太低,需要填充背景 - const uint32_t borderWidth = width / 6; - const uint32_t borderHeight = height / 6; - const uint32_t totalWidth = width + borderWidth * 2; - const uint32_t totalHeight = height + borderHeight * 2; - - const Color accentColor = UISettings().GetColorValue(UIColorType::Accent); - - SoftwareBitmap bitmap(BitmapPixelFormat::Bgra8, totalWidth, totalHeight, BitmapAlphaMode::Premultiplied); - { - BitmapBuffer buffer = bitmap.LockBuffer(BitmapBufferAccessMode::Write); - uint8_t* pixels = buffer.CreateReference().data(); - - const uint32_t fillColor = (0xff << 24) | (accentColor.R << 16) | (accentColor.G << 8) | accentColor.B; - std::fill_n((uint32_t*)pixels, totalWidth * totalHeight, fillColor); - - pixels += (borderHeight * totalWidth + borderWidth) * 4; - const uint8_t* origin = buf.get(); - for (UINT i = 0; i < height; ++i) { - for (UINT j = 0; j < width; ++j, origin += 4, pixels += 4) { - float alpha = origin[3] / 255.0f; - if (alpha < 1e-5) { - continue; - } - - float reverseAlpha = 1 - alpha; - if (reverseAlpha < 1e-5) { - pixels[0] = origin[0]; - pixels[1] = origin[1]; - pixels[2] = origin[2]; - pixels[3] = 255; - continue; - } - - pixels[0] = (uint8_t)std::lroundf(origin[0] * alpha + accentColor.B * reverseAlpha); - pixels[1] = (uint8_t)std::lroundf(origin[1] * alpha + accentColor.G * reverseAlpha); - pixels[2] = (uint8_t)std::lroundf(origin[2] * alpha + accentColor.R * reverseAlpha); - pixels[3] = 255; - } - - pixels += borderWidth * 2 * 4; - } - } - return bitmap; -} - -std::variant AppXReader::GetIcon( - uint32_t preferredSize, - bool isLightTheme, - bool noPath -) noexcept { - assert(!_packagePath.empty()); - - if (_square44x44Logo.empty()) { - return {}; - } - - std::wstring iconFileName; - if (_square44x44Logo.find(L'\\') != std::wstring_view::npos) { - iconFileName = _packagePath + _square44x44Logo; - } else { - iconFileName = StrUtils::Concat(_packagePath, L"Assets\\", _square44x44Logo);; - } - - size_t delimPos = iconFileName.find_last_of(L'\\'); - if (delimPos == std::wstring::npos) { - return {}; - } - size_t extensionPointPos = iconFileName.find_last_of(L'.'); - if (extensionPointPos == std::wstring::npos || extensionPointPos <= delimPos) { - return {}; - } - - std::wstring_view prefix(iconFileName.begin(), iconFileName.begin() + extensionPointPos); - std::wstring_view extension(iconFileName.begin() + extensionPointPos, iconFileName.end()); - - std::wstring_view iconName(iconFileName.begin() + delimPos + 1, iconFileName.begin() + extensionPointPos); - std::wstring iconNameExt = StrUtils::Concat(iconName, extension); - - std::wregex regex(fmt::format(L"^{}\\.[^\\.]+\\{}$", iconName, extension), std::wregex::nosubs); - - std::vector candidateIcons; - - WIN32_FIND_DATA findData{}; - wil::unique_hfind hFind(FindFirstFileEx(StrUtils::Concat(prefix, L"*").c_str(), - FindExInfoBasic, &findData, FindExSearchNameMatch, nullptr, FIND_FIRST_EX_LARGE_FETCH)); - if (hFind) { - do { - if (findData.cFileName != iconNameExt && !std::regex_match(findData.cFileName, regex)) { - continue; - } - - CandidateIcon ci(findData.cFileName); - if (!ci.IsValid()) { - continue; - } - - candidateIcons.emplace_back(std::move(ci)); - } while (FindNextFile(hFind.get(), &findData)); - } - - if (candidateIcons.empty()) { - return {}; - } - - auto it = std::min_element( - candidateIcons.begin(), - candidateIcons.end(), - [=](const CandidateIcon& l, const CandidateIcon& r) { - return CandidateIcon::Compare(l, r, preferredSize, isLightTheme); - } - ); - - std::wstring iconPath = StrUtils::Concat( - std::wstring_view(iconFileName.begin(), iconFileName.begin() + delimPos + 1), - it->FileName() - ); - SoftwareBitmap bkgIcon = AutoFillBackground(iconPath, isLightTheme, noPath); - if (bkgIcon || noPath) { - return std::move(bkgIcon); - } else { - return std::move(iconPath); - } -} - -void AppXReader::ClearCache() noexcept { - auto lock = appxCacheLock.lock_exclusive(); - appxCache.clear(); -} - -bool AppXReader::_ResolvePackagePath() { - if (!_packagePath.empty()) { - return true; - } - - uint32_t pfnLen = 0, praidLen = 0; - std::ignore = ParseApplicationUserModelId(_aumid.c_str(), &pfnLen, nullptr, &praidLen, nullptr); - if (pfnLen == 0 || praidLen == 0) { - Logger::Get().Error("ParseApplicationUserModelId 失败"); - return false; - } - - std::wstring packageFamilyName(pfnLen - 1, 0); - _praid.assign((size_t)praidLen - 1, 0); - if (ParseApplicationUserModelId(_aumid.c_str(), &pfnLen, packageFamilyName.data(), - &praidLen, _praid.data()) != ERROR_SUCCESS) - { - Logger::Get().Error("ParseApplicationUserModelId 失败"); - return false; - } - - //使用 PackageFamilyName 检索 PackageFullName - uint32_t packageCount = 0; - uint32_t bufferLength = 0; - std::ignore = FindPackagesByPackageFamily(packageFamilyName.c_str(), PACKAGE_FILTER_HEAD, - &packageCount, nullptr, &bufferLength, nullptr, nullptr); - if (packageCount == 0 || bufferLength == 0) { - Logger::Get().Error("FindPackagesByPackageFamily 失败"); - return false; - } - - std::unique_ptr packageFullNames(new wchar_t* [packageCount]); - std::unique_ptr buffer(new wchar_t[bufferLength]); - if (FindPackagesByPackageFamily(packageFamilyName.c_str(), PACKAGE_FILTER_HEAD, - &packageCount, packageFullNames.get(), &bufferLength, buffer.get(), nullptr) != ERROR_SUCCESS) - { - Logger::Get().Error("FindPackagesByPackageFamily 失败"); - return false; - } - - // 只使用第一个包,一般也只有一个 - _packageFullName = packageFullNames[0]; - - HRESULT hr = wil::AdaptFixedSizeToAllocatedResult( - _packagePath, [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT { - UINT32 length = (UINT32)valueLength; - LONG rc = GetPackagePathByFullName(_packageFullName.c_str(), &length, value); - if (rc != ERROR_SUCCESS && rc != ERROR_INSUFFICIENT_BUFFER) { - return HRESULT_FROM_WIN32(rc); - } - - *valueLengthNeededWithNul = length; - return S_OK; - } - ); - if (FAILED(hr)) { - Logger::Get().ComError("GetPackagePathByFullName 失败", hr); - return false; - } - - if (_packagePath.back() != L'\\') { - _packagePath.push_back(L'\\'); - } - - return true; -} - -} diff --git a/src/Magpie.App/AppXReader.h b/src/Magpie.App/AppXReader.h deleted file mode 100644 index 834076589..000000000 --- a/src/Magpie.App/AppXReader.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once -#include - -namespace winrt::Magpie::App { - -// 用于解析打包应用 -// 通常较为耗时(50 ms 左右),应在后台执行 -class AppXReader { -public: - bool Initialize(HWND hWnd) noexcept; - - bool Initialize(std::wstring_view aumid) noexcept; - - const std::wstring& AUMID() const noexcept { - return _aumid; - } - - std::wstring GetDisplayName() noexcept; - - const std::wstring& GetPackagePath() noexcept; - - std::wstring GetExecutablePath() noexcept; - - std::variant GetIcon( - uint32_t preferredSize, - bool isLightTheme, - bool noPath = false - ) noexcept; - - static void ClearCache() noexcept; - -private: - bool _ResolvePackagePath(); - - std::wstring _aumid; - std::wstring _praid; - std::wstring _packageFullName; - std::wstring _packagePath; - std::wstring _displayName; - std::wstring _executable; - std::wstring _square44x44Logo; -}; - -} diff --git a/src/Magpie.App/AutoStartHelper.cpp b/src/Magpie.App/AutoStartHelper.cpp deleted file mode 100644 index 7bd74517d..000000000 --- a/src/Magpie.App/AutoStartHelper.cpp +++ /dev/null @@ -1,516 +0,0 @@ -#include "pch.h" -#include "AutoStartHelper.h" -#include -#include -#include "Logger.h" -#include "StrUtils.h" -#include "Win32Utils.h" -#include - -#pragma comment(lib, "Taskschd.lib") - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 实现开机启动 -// -// 首先尝试使用任务计划程序,此方案的优点是以管理员身份启动时不会显示 UAC。 -// 如果创建任务失败,则回落到在当前用户的启动文件夹中创建快捷方式。 -// -// 任务计划程序的使用参考自 -// https://github.com/microsoft/PowerToys/blob/3d54cb838504c12f59516afaf1a00fde2dd5d01b/src/runner/auto_start_helper.cpp -// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -namespace winrt::Magpie::App { - -static constexpr DWORD USERNAME_DOMAIN_LEN = DNLEN + UNLEN + 2; // Domain Name + '\' + User Name + '\0' -static constexpr DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0' - - -static std::wstring GetTaskName(std::wstring_view userName) noexcept { - return StrUtils::Concat(L"Autorun for ", userName); -} - -static com_ptr CreateTaskService() noexcept { - com_ptr taskService = try_create_instance(CLSID_TaskScheduler); - if (!taskService) { - Logger::Get().Error("创建 TaskService 失败"); - return nullptr; - } - - HRESULT hr = taskService->Connect(Win32Utils::Variant(), Win32Utils::Variant(), - Win32Utils::Variant(), Win32Utils::Variant()); - if (FAILED(hr)) { - Logger::Get().ComError("ITaskService::Connect 失败", hr); - return nullptr; - } - - return taskService; -} - -static bool CreateAutoStartTask(bool runElevated, const wchar_t* arguments) noexcept { - WCHAR usernameDomain[USERNAME_DOMAIN_LEN]; - WCHAR username[USERNAME_LEN]; - - // 检索用户域和用户名 - if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) { - Logger::Get().Win32Error("获取用户名失败"); - return false; - } - if (!GetEnvironmentVariable(L"USERDOMAIN", usernameDomain, USERNAME_DOMAIN_LEN)) { - Logger::Get().Win32Error("获取用户域失败"); - return false; - } - - wcscat_s(usernameDomain, L"\\"); - wcscat_s(usernameDomain, username); - - com_ptr taskService = CreateTaskService(); - if (!taskService) { - return false; - } - - // 获取/创建 Magpie 文件夹 - com_ptr taskFolder; - HRESULT hr = taskService->GetFolder(wil::make_bstr_nothrow(L"\\Magpie").get(), taskFolder.put()); - if (FAILED(hr)) { - com_ptr rootFolder = NULL; - hr = taskService->GetFolder(wil::make_bstr_nothrow(L"\\").get(), rootFolder.put()); - if (FAILED(hr)) { - Logger::Get().ComError("获取根目录失败", hr); - return false; - } - - hr = rootFolder->CreateFolder(wil::make_bstr_nothrow(L"\\Magpie").get(), Win32Utils::Variant(L""), taskFolder.put()); - if (FAILED(hr)) { - Logger::Get().ComError("创建 Magpie 任务文件夹失败", hr); - return false; - } - } - - // Create the task builder object to create the task. - com_ptr task; - hr = taskService->NewTask(0, task.put()); - if (FAILED(hr)) { - Logger::Get().ComError("创建 ITaskDefinition 失败", hr); - return false; - } - - // ------------------------------------------------------ - // Get the registration info for setting the identification. - com_ptr regInfo; - hr = task->get_RegistrationInfo(regInfo.put()); - if (FAILED(hr)) { - Logger::Get().ComError("获取 IRegistrationInfo 失败", hr); - return false; - } - - hr = regInfo->put_Author(wil::make_bstr_nothrow(usernameDomain).get()); - if (FAILED(hr)) { - Logger::Get().ComError("IRegistrationInfo::put_Author 失败", hr); - return false; - } - - // ------------------------------------------------------ - // Create the settings for the task - com_ptr taskSettings; - hr = task->get_Settings(taskSettings.put()); - if (FAILED(hr)) { - Logger::Get().ComError("获取 ITaskSettings 失败", hr); - return false; - } - - hr = taskSettings->put_StartWhenAvailable(VARIANT_FALSE); - if (FAILED(hr)) { - Logger::Get().ComError("ITaskSettings::put_StartWhenAvailable 失败", hr); - return false; - } - hr = taskSettings->put_StopIfGoingOnBatteries(VARIANT_FALSE); - if (FAILED(hr)) { - Logger::Get().ComError("ITaskSettings::put_StopIfGoingOnBatteries 失败", hr); - return false; - } - hr = taskSettings->put_ExecutionTimeLimit(wil::make_bstr_nothrow(L"PT0S").get()); //Unlimited - if (FAILED(hr)) { - Logger::Get().ComError("ITaskSettings::put_ExecutionTimeLimit 失败", hr); - return false; - } - hr = taskSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE); - if (FAILED(hr)) { - Logger::Get().ComError("ITaskSettings::put_DisallowStartIfOnBatteries 失败", hr); - return false; - } - - // ------------------------------------------------------ - // Get the trigger collection to insert the logon trigger. - com_ptr triggerCollection; - hr = task->get_Triggers(triggerCollection.put()); - if (FAILED(hr)) { - Logger::Get().ComError("获取 ITriggerCollection 失败", hr); - return false; - } - - // Add the logon trigger to the task. - { - com_ptr trigger; - hr = triggerCollection->Create(TASK_TRIGGER_LOGON, trigger.put()); - if (FAILED(hr)) { - Logger::Get().ComError("创建 ITrigger 失败", hr); - return false; - } - - com_ptr logonTrigger = trigger.try_as(); - if (!logonTrigger) { - Logger::Get().Error("获取 ILogonTrigger 失败"); - return false; - } - - logonTrigger->put_Id(wil::make_bstr_nothrow(L"Trigger1").get()); - - // Timing issues may make explorer not be started when the task runs. - // Add a little delay to mitigate this. - logonTrigger->put_Delay(wil::make_bstr_nothrow(L"PT03S").get()); - - // Define the user. The task will execute when the user logs on. - // The specified user must be a user on this computer. - hr = logonTrigger->put_UserId(wil::make_bstr_nothrow(usernameDomain).get()); - if (FAILED(hr)) { - Logger::Get().ComError("ILogonTrigger::put_UserId 失败", hr); - return false; - } - } - - // ------------------------------------------------------ - // Add an Action to the task. This task will execute the path passed to this custom action. - { - com_ptr actionCollection; - - // Get the task action collection pointer. - hr = task->get_Actions(actionCollection.put()); - if (FAILED(hr)) { - Logger::Get().ComError("获取 IActionCollection 失败", hr); - return false; - } - - // Create the action, specifying that it is an executable action. - com_ptr action; - hr = actionCollection->Create(TASK_ACTION_EXEC, action.put()); - if (FAILED(hr)) { - Logger::Get().ComError("创建 IAction 失败", hr); - return false; - } - - // QI for the executable task pointer. - com_ptr execAction = action.try_as(); - if (!execAction) { - Logger::Get().Error("获取 IExecAction 失败"); - return false; - } - - // Set the path of the executable to Magpie (passed as CustomActionData). - const std::wstring& exePath = Win32Utils::GetExePath(); - hr = execAction->put_Path(wil::make_bstr_nothrow(exePath.c_str()).get()); - if (FAILED(hr)) { - Logger::Get().ComError("设置可执行文件路径失败", hr); - return false; - } - - if (arguments) { - execAction->put_Arguments(wil::make_bstr_nothrow(arguments).get()); - } - } - - // ------------------------------------------------------ - // Create the principal for the task - { - com_ptr principal; - hr = task->get_Principal(principal.put()); - if (FAILED(hr)) { - Logger::Get().ComError("获取 IPrincipal 失败", hr); - return false; - } - - // Set up principal information: - principal->put_Id(wil::make_bstr_nothrow(L"Principal1").get()); - principal->put_UserId(wil::make_bstr_nothrow(usernameDomain).get()); - principal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN); - - if (runElevated) { - hr = principal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_HIGHEST); - } else { - hr = principal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_LUA); - } - - if (FAILED(hr)) { - Logger::Get().ComError("IPrincipal::put_RunLevel 失败", hr); - return false; - } - } - - // ------------------------------------------------------ - // Save the task in the Magpie folder. - { - com_ptr registeredTask; - static constexpr const wchar_t* SDDL_FULL_ACCESS_FOR_EVERYONE = L"D:(A;;FA;;;WD)"; - - // 如果用户是 Administrator 账户,但 Magpie 不是以提升权限运行的,此调用会因权限问题失败 - std::wstring taskName = GetTaskName(username); - hr = taskFolder->RegisterTaskDefinition( - wil::make_bstr_nothrow(taskName.c_str()).get(), - task.get(), - TASK_CREATE_OR_UPDATE, - Win32Utils::Variant(usernameDomain), - Win32Utils::Variant(), - TASK_LOGON_INTERACTIVE_TOKEN, - Win32Utils::Variant(SDDL_FULL_ACCESS_FOR_EVERYONE), - registeredTask.put() - ); - if (FAILED(hr)) { - Logger::Get().ComError("注册任务失败", hr); - return false; - } - - registeredTask->put_Enabled(VARIANT_TRUE); - } - - return true; -} - -static bool DeleteAutoStartTask() noexcept { - WCHAR username[USERNAME_LEN]; - if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) { - Logger::Get().Win32Error("获取用户名失败"); - return false; - } - - com_ptr taskService = CreateTaskService(); - if (!taskService) { - return false; - } - - com_ptr taskFolder; - HRESULT hr = taskService->GetFolder(wil::make_bstr_nothrow(L"\\Magpie").get(), taskFolder.put()); - if (FAILED(hr)) { - return true; - } - - wil::unique_bstr taskName = wil::make_bstr_nothrow(GetTaskName(username).c_str()); - - { - com_ptr existingRegisteredTask; - hr = taskFolder->GetTask(taskName.get(), existingRegisteredTask.put()); - if (FAILED(hr)) { - // 不存在任务 - return true; - } - } - - hr = taskFolder->DeleteTask(taskName.get(), 0); - if (FAILED(hr)) { - Logger::Get().ComError("删除任务失败", hr); - return false; - } - - return true; -} - -static bool IsAutoStartTaskActive(std::wstring& arguements) noexcept { - WCHAR username[USERNAME_LEN]; - if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) { - Logger::Get().Win32Error("获取用户名失败"); - return false; - } - - com_ptr taskService = CreateTaskService(); - if (!taskService) { - return false; - } - - com_ptr taskFolder; - HRESULT hr = taskService->GetFolder(wil::make_bstr_nothrow(L"\\Magpie").get(), taskFolder.put()); - if (FAILED(hr)) { - return false; - } - - com_ptr existingRegisteredTask; - hr = taskFolder->GetTask(wil::make_bstr_nothrow(GetTaskName(username).c_str()).get(), existingRegisteredTask.put()); - if (FAILED(hr)) { - return false; - } - - VARIANT_BOOL isEnabled; - hr = existingRegisteredTask->get_Enabled(&isEnabled); - if (FAILED(hr)) { - Logger::Get().ComError("IRegisteredTask::get_Enabled 失败", hr); - return false; - } - - com_ptr task; - hr = existingRegisteredTask->get_Definition(task.put()); - if (FAILED(hr)) { - Logger::Get().ComError("获取 ITaskDefinition 失败", hr); - return false; - } - - com_ptr actionCollection; - task->get_Actions(actionCollection.put()); - if (FAILED(hr)) { - Logger::Get().ComError("获取 IActionCollection 失败", hr); - return false; - } - - com_ptr action; - // 索引从 1 开始 - hr = actionCollection->get_Item(1, action.put()); - if (FAILED(hr)) { - Logger::Get().ComError("获取 IAction 失败", hr); - return false; - } - - com_ptr execAction = action.try_as(); - wil::unique_bstr args; - hr = execAction->get_Arguments(args.put()); - if (FAILED(hr)) { - Logger::Get().ComError("获取参数失败", hr); - return false; - } - arguements = args ? args.get() : L""; - - return isEnabled == VARIANT_TRUE; -} - -static std::wstring GetShortcutPath() noexcept { - // 获取用户的启动文件夹路径 - wil::unique_cotaskmem_string startupDir; - HRESULT hr = SHGetKnownFolderPath(FOLDERID_Startup, 0, NULL, startupDir.put()); - if (FAILED(hr)) { - Logger::Get().ComError("获取启动文件夹失败", hr); - return {}; - } - - return StrUtils::Concat(startupDir.get(), L"\\Magpie.lnk"); -} - -static bool CreateAutoStartShortcut(const wchar_t* arguments) noexcept { - com_ptr shellLink = try_create_instance(CLSID_ShellLink); - if (!shellLink) { - Logger::Get().Error("创建 ShellLink 失败"); - return false; - } - - shellLink->SetPath(Win32Utils::GetExePath().c_str()); - - if (arguments) { - shellLink->SetArguments(arguments); - } - - com_ptr persistFile = shellLink.try_as(); - if (!persistFile) { - Logger::Get().Error("获取 IPersistFile 失败"); - return false; - } - - HRESULT hr = persistFile->Save(GetShortcutPath().c_str(), TRUE); - if (FAILED(hr)) { - Logger::Get().ComError("保存快捷方式失败", hr); - return false; - } - - return true; -} - -static bool DeleteAutoStartShortcut() noexcept { - std::wstring shortcutPath = GetShortcutPath(); - if (shortcutPath.empty()) { - return false; - } - - if (!DeleteFile(shortcutPath.c_str()) && GetLastError() != ERROR_FILE_NOT_FOUND) { - Logger::Get().Win32Error("删除快捷方式失败"); - return false; - } - - return true; -} - -static bool IsAutoStartShortcutExist(std::wstring& arguments) noexcept { - std::wstring shortcutPath = GetShortcutPath(); - if (shortcutPath.empty()) { - return false; - } - - if (!Win32Utils::FileExists(shortcutPath.c_str())) { - return false; - } - - com_ptr shellLink = try_create_instance(CLSID_ShellLink); - if (!shellLink) { - Logger::Get().Error("创建 ShellLink 失败"); - return false; - } - - com_ptr persistFile = shellLink.try_as(); - if (!persistFile) { - Logger::Get().Error("获取 IPersistFile 失败"); - return false; - } - - HRESULT hr = persistFile->Load(shortcutPath.c_str(), STGM_READ); - if (FAILED(hr)) { - Logger::Get().ComError("读取快捷方式失败", hr); - return false; - } - - hr = shellLink->Resolve(NULL, SLR_NO_UI); - if (FAILED(hr)) { - Logger::Get().ComError("解析快捷方式失败", hr); - return false; - } - - // https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ishelllinka-getarguments - // 推荐从 IPropertyStore 检索参数 - com_ptr propertyStore = shellLink.as(); - if (!propertyStore) { - Logger::Get().Error("获取 IPropertyStore 失败"); - return false; - } - - wil::unique_prop_variant prop; - hr = propertyStore->GetValue(PKEY_Link_Arguments, &prop); - if (FAILED(hr)) { - Logger::Get().ComError("检索 Arguments 参数失败", hr); - return false; - } - - if (prop.vt == VT_LPWSTR) { - arguments = prop.pwszVal; - } else if (prop.vt == VT_BSTR) { - arguments = prop.bstrVal; - } - - return true; -} - -bool AutoStartHelper::EnableAutoStart(bool runElevated, const wchar_t* arguments) noexcept { - if (CreateAutoStartTask(runElevated, arguments)) { - DeleteAutoStartShortcut(); - return true; - } - - return CreateAutoStartShortcut(arguments); -} - -bool AutoStartHelper::DisableAutoStart() noexcept { - // 避免或运算符的短路,确保两者都被删除 - bool result1 = DeleteAutoStartTask(); - bool result2 = DeleteAutoStartShortcut(); - return result1 || result2; -} - -bool AutoStartHelper::IsAutoStartEnabled(std::wstring& arguments) noexcept { - return IsAutoStartTaskActive(arguments) || IsAutoStartShortcutExist(arguments); -} - -} diff --git a/src/Magpie.App/AutoStartHelper.h b/src/Magpie.App/AutoStartHelper.h deleted file mode 100644 index b58a3297c..000000000 --- a/src/Magpie.App/AutoStartHelper.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -namespace winrt::Magpie::App { - -struct AutoStartHelper { - static bool EnableAutoStart(bool runElevated, const wchar_t* arguments) noexcept; - static bool DisableAutoStart() noexcept; - static bool IsAutoStartEnabled(std::wstring& arguments) noexcept; -}; - -} diff --git a/src/Magpie.App/BlueInfoBar.xaml b/src/Magpie.App/BlueInfoBar.xaml deleted file mode 100644 index 542387170..000000000 --- a/src/Magpie.App/BlueInfoBar.xaml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - #FF5fb2f2 - - - - - #FF0063b1 - - - diff --git a/src/Magpie.App/BoolNegationConverter.cpp b/src/Magpie.App/BoolNegationConverter.cpp deleted file mode 100644 index 0e7c43a9e..000000000 --- a/src/Magpie.App/BoolNegationConverter.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "pch.h" -#include "BoolNegationConverter.h" -#if __has_include("BoolNegationConverter.g.cpp") -#include "BoolNegationConverter.g.cpp" -#endif - -using namespace winrt; -using namespace Windows::UI::Xaml::Interop; - -namespace winrt::Magpie::App::implementation { - -IInspectable BoolNegationConverter::Convert(IInspectable const& value, TypeName const&, IInspectable const&, hstring const&) { - return box_value(!unbox_value(value)); -} - -IInspectable BoolNegationConverter::ConvertBack(IInspectable const& value, TypeName const&, IInspectable const&, hstring const&) { - return box_value(!unbox_value(value)); -} - -} diff --git a/src/Magpie.App/BoolNegationConverter.h b/src/Magpie.App/BoolNegationConverter.h deleted file mode 100644 index 7b8242aa9..000000000 --- a/src/Magpie.App/BoolNegationConverter.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include "BoolNegationConverter.g.h" - -namespace winrt::Magpie::App::implementation { - -struct BoolNegationConverter : BoolNegationConverterT { - IInspectable Convert(IInspectable const& value, Interop::TypeName const&, IInspectable const&, hstring const&); - IInspectable ConvertBack(IInspectable const& value, Interop::TypeName const&, IInspectable const&, hstring const&); -}; - -} - -namespace winrt::Magpie::App::factory_implementation { - -struct BoolNegationConverter : BoolNegationConverterT { -}; - -} diff --git a/src/Magpie.App/BoolNegationConverter.idl b/src/Magpie.App/BoolNegationConverter.idl deleted file mode 100644 index 30aa4b322..000000000 --- a/src/Magpie.App/BoolNegationConverter.idl +++ /dev/null @@ -1,5 +0,0 @@ -namespace Magpie.App { - runtimeclass BoolNegationConverter : [default] Windows.UI.Xaml.Data.IValueConverter { - BoolNegationConverter(); - } -} diff --git a/src/Magpie.App/BoolToNegativeVisibilityConverter.cpp b/src/Magpie.App/BoolToNegativeVisibilityConverter.cpp deleted file mode 100644 index d5a9d6bd9..000000000 --- a/src/Magpie.App/BoolToNegativeVisibilityConverter.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "pch.h" -#include "BoolToNegativeVisibilityConverter.h" -#if __has_include("BoolToNegativeVisibilityConverter.g.cpp") -#include "BoolToNegativeVisibilityConverter.g.cpp" -#endif - -using namespace winrt; -using namespace Windows::UI::Xaml::Interop; - -namespace winrt::Magpie::App::implementation { - -IInspectable BoolToNegativeVisibilityConverter::Convert(IInspectable const& value, TypeName const&, IInspectable const&, hstring const&) { - return box_value(unbox_value(value) ? Visibility::Collapsed : Visibility::Visible); -} - -IInspectable BoolToNegativeVisibilityConverter::ConvertBack(IInspectable const& value, TypeName const&, IInspectable const&, hstring const&) { - return box_value(unbox_value(value) == Visibility::Collapsed); -} - -} diff --git a/src/Magpie.App/BoolToNegativeVisibilityConverter.h b/src/Magpie.App/BoolToNegativeVisibilityConverter.h deleted file mode 100644 index 93353b0ce..000000000 --- a/src/Magpie.App/BoolToNegativeVisibilityConverter.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include "BoolToNegativeVisibilityConverter.g.h" - -namespace winrt::Magpie::App::implementation { - -struct BoolToNegativeVisibilityConverter : BoolToNegativeVisibilityConverterT { - IInspectable Convert(IInspectable const& value, Interop::TypeName const&, IInspectable const&, hstring const&); - IInspectable ConvertBack(IInspectable const& value, Interop::TypeName const&, IInspectable const&, hstring const&); -}; - -} - -namespace winrt::Magpie::App::factory_implementation { - -struct BoolToNegativeVisibilityConverter : BoolToNegativeVisibilityConverterT { -}; - -} diff --git a/src/Magpie.App/BoolToNegativeVisibilityConverter.idl b/src/Magpie.App/BoolToNegativeVisibilityConverter.idl deleted file mode 100644 index aa32dbc6d..000000000 --- a/src/Magpie.App/BoolToNegativeVisibilityConverter.idl +++ /dev/null @@ -1,7 +0,0 @@ -namespace Magpie.App { - // true -> Visibility::Collapsed - // false -> Visibility::Visible - runtimeclass BoolToNegativeVisibilityConverter : [default] Windows.UI.Xaml.Data.IValueConverter { - BoolToNegativeVisibilityConverter(); - } -} diff --git a/src/Magpie.App/CandidateWindowItem.cpp b/src/Magpie.App/CandidateWindowItem.cpp deleted file mode 100644 index 40666d55e..000000000 --- a/src/Magpie.App/CandidateWindowItem.cpp +++ /dev/null @@ -1,172 +0,0 @@ -#include "pch.h" -#include "CandidateWindowItem.h" -#if __has_include("CandidateWindowItem.g.cpp") -#include "CandidateWindowItem.g.cpp" -#endif -#include "Win32Utils.h" -#include "AppXReader.h" -#include "IconHelper.h" -#include "StrUtils.h" - -using namespace winrt; -using namespace Windows::UI::ViewManagement; -using namespace Windows::UI::Xaml::Controls; -using namespace Windows::UI::Xaml::Media::Imaging; -using namespace Windows::Graphics::Imaging; -using namespace Windows::Graphics::Display; - -namespace winrt::Magpie::App::implementation { - -static std::wstring GetProcessDesc(HWND hWnd) { - if (Win32Utils::GetWndClassName(hWnd) == L"ApplicationFrameWindow") { - // 跳过 UWP 窗口 - return {}; - } - - // 移植自 https://github.com/dotnet/runtime/blob/4a63cb28b69e1c48bccf592150be7ba297b67950/src/libraries/System.Diagnostics.FileVersionInfo/src/System/Diagnostics/FileVersionInfo.Windows.cs - std::wstring fileName = Win32Utils::GetPathOfWnd(hWnd); - if (fileName.empty()) { - return {}; - } - - DWORD dummy; - DWORD infoSize = GetFileVersionInfoSizeEx(FILE_VER_GET_LOCALISED, fileName.c_str(), &dummy); - if (infoSize == 0) { - return {}; - } - - std::unique_ptr infoData = std::make_unique(infoSize); - if (!GetFileVersionInfoEx(FILE_VER_GET_LOCALISED, fileName.c_str(), 0, infoSize, infoData.get())) { - return {}; - } - - std::wstring codePage; - uint8_t* langId = nullptr; - uint32_t len; - if (VerQueryValue(infoData.get(), L"\\VarFileInfo\\Translation", (void**)&langId, &len)) { - codePage = fmt::format(L"{:08X}", uint32_t((*(uint16_t*)langId << 16) | *(uint16_t*)(langId + 2))); - } else { - codePage = L"040904E4"; - } - - wchar_t* description = nullptr; - std::wstring descPath = fmt::format(L"\\StringFileInfo\\{}\\FileDescription", codePage); - if (!VerQueryValue(infoData.get(), descPath.c_str(), (void**)&description, &len)) { - return {}; - } - - return description; -} - -CandidateWindowItem::CandidateWindowItem(uint64_t hWnd, uint32_t dpi, bool isLightTheme, CoreDispatcher const& dispatcher) { - _title = Win32Utils::GetWndTitle((HWND)hWnd); - _defaultProfileName = _title; - - _className = Win32Utils::GetWndClassName((HWND)hWnd); - _path = Win32Utils::GetPathOfWnd((HWND)hWnd); - - MUXC::ImageIcon placeholder; - placeholder.Width(16); - placeholder.Height(16); - _icon = std::move(placeholder); - - _ResolveWindow(true, true, (HWND)hWnd, isLightTheme, dpi, dispatcher); -} - -IconElement CandidateWindowItem::Icon() const noexcept { - // 返回副本,否则在 ComboBox 中绑定会导致崩溃 - if (MUXC::ImageIcon imageIcon = _icon.try_as()) { - MUXC::ImageIcon icon; - icon.Source(imageIcon.Source()); - icon.Width(imageIcon.Width()); - icon.Height(imageIcon.Height()); - return std::move(icon); - } else if (FontIcon fontIcon = _icon.try_as()) { - FontIcon icon; - icon.Glyph(fontIcon.Glyph()); - icon.FontSize(fontIcon.FontSize()); - return std::move(icon); - } - - return nullptr; -} - -fire_and_forget CandidateWindowItem::_ResolveWindow(bool resolveIcon, bool resolveName, HWND hWnd, bool isLightTheme, uint32_t dpi, CoreDispatcher dispatcher) { - assert(resolveIcon || resolveName); - - auto weakThis = get_weak(); - - // 解析名称和图标非常耗时,转到后台进行 - co_await resume_background(); - - AppXReader reader; - const bool isPackaged = reader.Initialize(hWnd); - if (resolveName) { - std::wstring defaultProfileName = isPackaged ? reader.GetDisplayName() : GetProcessDesc(hWnd); - StrUtils::Trim(defaultProfileName); - - auto strongThis = weakThis.get(); - if (!strongThis) { - co_return; - } - - [](com_ptr that, std::wstring&& defaultProfileName, const std::wstring& aumid, CoreDispatcher const& dispatcher) -> fire_and_forget { - co_await dispatcher.TryRunAsync( - CoreDispatcherPriority::Normal, - [that, defaultProfileName(std::move(defaultProfileName)), aumid(aumid)]() { - if (!defaultProfileName.empty()) { - that->_defaultProfileName = defaultProfileName; - } - // 即使 defaultProfileName 为空也通知 DefaultProfileName 已更改 - // 这是为了正确设置 CandidateWindowIndex - that->RaisePropertyChanged(L"DefaultProfileName"); - - that->_aumid = aumid; - } - ); - }(strongThis, std::move(defaultProfileName), reader.AUMID(), dispatcher); - } - - if (!resolveIcon) { - co_return; - } - - SoftwareBitmap iconBitmap{ nullptr }; - - if (isPackaged) { - std::variant uwpIcon = - reader.GetIcon((uint32_t)std::ceil(dpi * 16.0 / USER_DEFAULT_SCREEN_DPI), isLightTheme, true); - if (uwpIcon.index() == 1) { - iconBitmap = std::get<1>(uwpIcon); - } - } else { - iconBitmap = IconHelper::ExtractIconFormWnd(hWnd, 16, dpi); - } - - // 切换到主线程 - co_await dispatcher; - - if (auto strongThis = weakThis.get()) { - if (iconBitmap) { - SoftwareBitmapSource imageSource; - co_await imageSource.SetBitmapAsync(iconBitmap); - - MUXC::ImageIcon imageIcon; - imageIcon.Width(16); - imageIcon.Height(16); - imageIcon.Source(imageSource); - - strongThis->_icon = std::move(imageIcon); - } else { - FontIcon fontIcon; - fontIcon.Glyph(L"\uE737"); - fontIcon.FontSize(16); - - strongThis->_icon = std::move(fontIcon); - } - - strongThis->RaisePropertyChanged(L"Icon"); - } -} - -} diff --git a/src/Magpie.App/CandidateWindowItem.h b/src/Magpie.App/CandidateWindowItem.h deleted file mode 100644 index e873d3645..000000000 --- a/src/Magpie.App/CandidateWindowItem.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once -#include "CandidateWindowItem.g.h" - -namespace winrt::Magpie::App::implementation { - -struct CandidateWindowItem : CandidateWindowItemT, - wil::notify_property_changed_base { - CandidateWindowItem(uint64_t hWnd, uint32_t dpi, bool isLightTheme, CoreDispatcher const& dispatcher); - - hstring Title() const noexcept { - return _title; - } - - Controls::IconElement Icon() const noexcept; - - hstring DefaultProfileName() const noexcept { - return _defaultProfileName; - } - - hstring AUMID() const noexcept { - return _aumid; - } - - hstring Path() const noexcept { - return _path; - } - - hstring ClassName() const noexcept { - return _className; - } - -private: - fire_and_forget _ResolveWindow(bool resolveIcon, bool resolveName, HWND hWnd, bool isLightTheme, uint32_t dpi, CoreDispatcher dispatcher); - - hstring _title; - Controls::IconElement _icon{ nullptr }; - hstring _defaultProfileName; - - hstring _aumid; - hstring _path; - hstring _className; -}; - -} - -namespace winrt::Magpie::App::factory_implementation { - -struct CandidateWindowItem : CandidateWindowItemT { -}; - -} diff --git a/src/Magpie.App/CandidateWindowItem.idl b/src/Magpie.App/CandidateWindowItem.idl deleted file mode 100644 index ec8ca17ba..000000000 --- a/src/Magpie.App/CandidateWindowItem.idl +++ /dev/null @@ -1,13 +0,0 @@ -namespace Magpie.App { - runtimeclass CandidateWindowItem : Windows.UI.Xaml.Data.INotifyPropertyChanged { - CandidateWindowItem(UInt64 hWnd, UInt32 dpi, Boolean isLightTheme, Windows.UI.Core.CoreDispatcher dispatcher); - - String Title { get; }; - Windows.UI.Xaml.Controls.IconElement Icon { get; }; - String DefaultProfileName { get; }; - - String AUMID { get; }; - String Path { get; }; - String ClassName { get; }; - } -} diff --git a/src/Magpie.App/ComboBoxHelper.h b/src/Magpie.App/ComboBoxHelper.h deleted file mode 100644 index 95a9128de..000000000 --- a/src/Magpie.App/ComboBoxHelper.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once -#include "XamlUtils.h" - -namespace winrt::Magpie::App { - -struct ComboBoxHelper { - // 用于修复 ComboBox 中存在的问题 - // 因为官方毫无作为,我不得不使用这些 hack - template - static void DropDownOpened(T const& page, IInspectable const& sender) { - using namespace Windows::UI::Xaml::Controls; - - // 修复下拉框不适配主题的问题 - // https://github.com/microsoft/microsoft-ui-xaml/issues/6622 - XamlUtils::UpdateThemeOfXamlPopups(page.XamlRoot(), page.ActualTheme()); - - // 修复下拉框位置不正确的问题 - // https://github.com/microsoft/microsoft-ui-xaml/issues/4551 - ComboBox comboBox = sender.as(); - IInspectable selectedItem = comboBox.SelectedItem(); - if (!selectedItem) { - return; - } - - if (std::optional str = selectedItem.try_as()) { - comboBox.PlaceholderText(*str); - } else if (ContentControl container = selectedItem.try_as()) { - if (std::optional strContent = container.Content().try_as()) { - comboBox.PlaceholderText(*strContent); - } - } - } -}; - -} diff --git a/src/Magpie.App/ContentDialogHelper.cpp b/src/Magpie.App/ContentDialogHelper.cpp deleted file mode 100644 index d8bb93e78..000000000 --- a/src/Magpie.App/ContentDialogHelper.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "pch.h" -#include "ContentDialogHelper.h" - -using namespace winrt; -using namespace Windows::UI::Xaml::Controls; - -namespace winrt::Magpie::App { - -static weak_ref activeDialog; - -IAsyncOperation ContentDialogHelper::ShowAsync(ContentDialog dialog) { - assert(activeDialog == nullptr); - - activeDialog = dialog; - ContentDialogResult result = co_await dialog.ShowAsync(); - activeDialog = nullptr; - co_return result; -} - -bool ContentDialogHelper::IsAnyDialogOpen() noexcept { - return activeDialog != nullptr; -} - -void ContentDialogHelper::CloseActiveDialog() { - if (activeDialog == nullptr) { - return; - } - - if (auto dialog = activeDialog.get()) { - dialog.Hide(); - } -} - -} diff --git a/src/Magpie.App/ContentDialogHelper.h b/src/Magpie.App/ContentDialogHelper.h deleted file mode 100644 index a94677ec4..000000000 --- a/src/Magpie.App/ContentDialogHelper.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -namespace winrt::Magpie::App { - -struct ContentDialogHelper { - static IAsyncOperation ShowAsync(Controls::ContentDialog dialog); - static bool IsAnyDialogOpen() noexcept; - static void CloseActiveDialog(); -}; - -} diff --git a/src/Magpie.App/ControlSizeTrigger.cpp b/src/Magpie.App/ControlSizeTrigger.cpp deleted file mode 100644 index 5fb45afbc..000000000 --- a/src/Magpie.App/ControlSizeTrigger.cpp +++ /dev/null @@ -1,91 +0,0 @@ -// 移植自 https://github.com/CommunityToolkit/Windows/blob/bef863ca70bb1edf8c940198dd5cc74afa5d2aab/components/Triggers/src/ControlSizeTrigger.cs - -#include "pch.h" -#include "ControlSizeTrigger.h" -#if __has_include("ControlSizeTrigger.g.cpp") -#include "ControlSizeTrigger.g.cpp" -#endif - -namespace winrt::Magpie::App::implementation { - -const DependencyProperty ControlSizeTrigger::_canTriggerProperty = DependencyProperty::Register( - L"CanTrigger", - xaml_typename(), - xaml_typename(), - PropertyMetadata(box_value(true), &ControlSizeTrigger::_OnPropertyChanged) -); - -const DependencyProperty ControlSizeTrigger::_maxWidthProperty = DependencyProperty::Register( - L"MaxWidth", - xaml_typename(), - xaml_typename(), - PropertyMetadata(box_value(std::numeric_limits::infinity()), &ControlSizeTrigger::_OnPropertyChanged) -); - -const DependencyProperty ControlSizeTrigger::_minWidthProperty = DependencyProperty::Register( - L"MinWidth", - xaml_typename(), - xaml_typename(), - PropertyMetadata(box_value(0.0), &ControlSizeTrigger::_OnPropertyChanged) -); - -const DependencyProperty ControlSizeTrigger::_maxHeightProperty = DependencyProperty::Register( - L"MaxHeight", - xaml_typename(), - xaml_typename(), - PropertyMetadata(box_value(std::numeric_limits::infinity()), &ControlSizeTrigger::_OnPropertyChanged) -); - -const DependencyProperty ControlSizeTrigger::_minHeightProperty = DependencyProperty::Register( - L"MinHeight", - xaml_typename(), - xaml_typename(), - PropertyMetadata(box_value(0.0), &ControlSizeTrigger::_OnPropertyChanged) -); - -const DependencyProperty ControlSizeTrigger::_targetElementProperty = DependencyProperty::Register( - L"TargetElement", - xaml_typename(), - xaml_typename(), - PropertyMetadata(nullptr, &ControlSizeTrigger::_OnTargetElementChanged) -); - -void ControlSizeTrigger::_OnPropertyChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&) { - get_self(sender.as())->_UpdateTrigger(); -} - -void ControlSizeTrigger::_OnTargetElementChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const& e) { - ControlSizeTrigger* that = get_self(sender.as()); - - that->_targetElementSizeChangedRevoker.revoke(); - - if (IInspectable newValue = e.NewValue()) { - that->_targetElementSizeChangedRevoker = newValue.as().SizeChanged(auto_revoke, - [that](IInspectable const&, SizeChangedEventArgs const&) { - that->_UpdateTrigger(); - } - ); - } - - that->_UpdateTrigger(); -} - -void ControlSizeTrigger::_UpdateTrigger() { - const FrameworkElement targetElement = TargetElement(); - - if (!targetElement || !CanTrigger()) { - SetActive(false); - return; - } - - const double actualWidth = targetElement.ActualWidth(); - const double actualHeight = targetElement.ActualHeight(); - SetActive( - actualWidth >= MinWidth() && - actualWidth < MaxWidth() && - actualHeight >= MinHeight() && - actualHeight < MaxHeight() - ); -} - -} diff --git a/src/Magpie.App/ControlSizeTrigger.h b/src/Magpie.App/ControlSizeTrigger.h deleted file mode 100644 index 4cf0e0943..000000000 --- a/src/Magpie.App/ControlSizeTrigger.h +++ /dev/null @@ -1,102 +0,0 @@ -#pragma once -#include "ControlSizeTrigger.g.h" - -namespace winrt::Magpie::App::implementation { - -struct ControlSizeTrigger : ControlSizeTriggerT { - bool CanTrigger() { - return GetValue(_canTriggerProperty).as(); - } - - void CanTrigger(bool value) { - SetValue(_canTriggerProperty, box_value(value)); - } - - double MaxWidth() { - return GetValue(_maxWidthProperty).as(); - } - - void MaxWidth(double value) { - SetValue(_maxWidthProperty, box_value(value)); - } - - double MinWidth() { - return GetValue(_minWidthProperty).as(); - } - - void MinWidth(double value) { - SetValue(_minWidthProperty, box_value(value)); - } - - double MaxHeight() { - return GetValue(_maxHeightProperty).as(); - } - - void MaxHeight(double value) { - SetValue(_maxHeightProperty, box_value(value)); - } - - double MinHeight() { - return GetValue(_minHeightProperty).as(); - } - - void MinHeight(double value) { - SetValue(_minHeightProperty, box_value(value)); - } - - FrameworkElement TargetElement() { - return GetValue(_targetElementProperty).as(); - } - - void TargetElement(FrameworkElement const& value) { - SetValue(_targetElementProperty, box_value(value)); - } - - static DependencyProperty CanTriggerProperty() { - return _canTriggerProperty; - } - - static DependencyProperty MaxWidthProperty() { - return _maxWidthProperty; - } - - static DependencyProperty MinWidthProperty() { - return _minWidthProperty; - } - - static DependencyProperty MaxHeightProperty() { - return _maxHeightProperty; - } - - static DependencyProperty MinHeightProperty() { - return _minHeightProperty; - } - - static DependencyProperty TargetElementProperty() { - return _targetElementProperty; - } - -private: - static const DependencyProperty _canTriggerProperty; - static const DependencyProperty _maxWidthProperty; - static const DependencyProperty _minWidthProperty; - static const DependencyProperty _maxHeightProperty; - static const DependencyProperty _minHeightProperty; - static const DependencyProperty _targetElementProperty; - - static void _OnPropertyChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&); - static void _OnTargetElementChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const& ); - - void _UpdateTrigger(); - - FrameworkElement::SizeChanged_revoker _targetElementSizeChangedRevoker; -}; - -} - -namespace winrt::Magpie::App::factory_implementation { - -struct ControlSizeTrigger : ControlSizeTriggerT { -}; - -} diff --git a/src/Magpie.App/ControlSizeTrigger.idl b/src/Magpie.App/ControlSizeTrigger.idl deleted file mode 100644 index f4d9c0f63..000000000 --- a/src/Magpie.App/ControlSizeTrigger.idl +++ /dev/null @@ -1,19 +0,0 @@ -namespace Magpie.App { - runtimeclass ControlSizeTrigger : Windows.UI.Xaml.StateTriggerBase { - ControlSizeTrigger(); - - Boolean CanTrigger; - Double MaxWidth; - Double MinWidth; - Double MaxHeight; - Double MinHeight; - Windows.UI.Xaml.FrameworkElement TargetElement; - - static Windows.UI.Xaml.DependencyProperty CanTriggerProperty { get; }; - static Windows.UI.Xaml.DependencyProperty MaxWidthProperty { get; }; - static Windows.UI.Xaml.DependencyProperty MinWidthProperty { get; }; - static Windows.UI.Xaml.DependencyProperty MaxHeightProperty { get; }; - static Windows.UI.Xaml.DependencyProperty MinHeightProperty { get; }; - static Windows.UI.Xaml.DependencyProperty TargetElementProperty{ get; }; - } -} diff --git a/src/Magpie.App/EffectHelper.h b/src/Magpie.App/EffectHelper.h deleted file mode 100644 index d40de0540..000000000 --- a/src/Magpie.App/EffectHelper.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -namespace winrt::Magpie::App { - -struct EffectHelper { - static std::wstring_view GetDisplayName(std::wstring_view fullName) noexcept { - size_t delimPos = fullName.find_last_of(L'\\'); - return delimPos != std::wstring::npos ? fullName.substr(delimPos + 1) : fullName; - } -}; - -} diff --git a/src/Magpie.App/EffectParametersViewModel.cpp b/src/Magpie.App/EffectParametersViewModel.cpp deleted file mode 100644 index 23f7bbc1e..000000000 --- a/src/Magpie.App/EffectParametersViewModel.cpp +++ /dev/null @@ -1,161 +0,0 @@ -#include "pch.h" -#include "EffectParametersViewModel.h" -#if __has_include("ScalingModeBoolParameter.g.cpp") -#include "ScalingModeBoolParameter.g.cpp" -#endif -#if __has_include("ScalingModeFloatParameter.g.cpp") -#include "ScalingModeFloatParameter.g.cpp" -#endif -#if __has_include("EffectParametersViewModel.g.cpp") -#include "EffectParametersViewModel.g.cpp" -#endif -#include -#include "StrUtils.h" -#include "AppSettings.h" -#include "ScalingModesService.h" -#include "ScalingMode.h" -#include "EffectsService.h" - -using namespace Magpie::Core; - -namespace winrt::Magpie::App::implementation { - -// 限制保存频率 -// 1 秒内没有新的调用才执行保存 -static fire_and_forget LazySaveAppSettings() { - using namespace std::chrono; - - static steady_clock::time_point lastInvokeTime; - static bool sleeping = false; - - lastInvokeTime = steady_clock::now(); - - if (sleeping) { - co_return; - } - - sleeping = true; - CoreDispatcher dispatcher = CoreWindow::GetForCurrentThread().Dispatcher(); - - co_await 1s; - - while (true) { - int duration = (int)duration_cast(steady_clock::now() - lastInvokeTime).count(); - if (duration >= 999) { - break; - } - - // 如果与 lastInvokeTime 相差不到 1s,则继续等待 - co_await milliseconds(1000 - duration); - } - - // 回到主线程 - co_await dispatcher; - - sleeping = false; - AppSettings::Get().SaveAsync(); -} - -EffectParametersViewModel::EffectParametersViewModel(uint32_t scalingModeIdx, uint32_t effectIdx) - : _scalingModeIdx(scalingModeIdx), _effectIdx(effectIdx) -{ - ScalingMode& scalingMode = ScalingModesService::Get().GetScalingMode(_scalingModeIdx); - _effectInfo = EffectsService::Get().GetEffect(scalingMode.effects[_effectIdx].name); - - phmap::flat_hash_map& params = _Data(); - - std::vector boolParams; - std::vector floatParams; - for (uint32_t i = 0, size = (uint32_t)_effectInfo->params.size(); i < size; ++i) { - const EffectParameterDesc& param = _effectInfo->params[i]; - - std::optional paramValue; - { - auto it = params.find(StrUtils::UTF8ToUTF16(param.name)); - if (it != params.end()) { - paramValue = it->second; - } - } - - if (param.constant.index() == 0) { - const EffectConstant& constant = std::get<0>(param.constant); - Magpie::App::ScalingModeFloatParameter floatParamItem( - i, - StrUtils::UTF8ToUTF16(param.label.empty() ? param.name : param.label), - paramValue.has_value() ? *paramValue : constant.defaultValue, - constant.minValue, - constant.maxValue, - constant.step - ); - floatParamItem.PropertyChanged({ this, &EffectParametersViewModel::_ScalingModeFloatParameter_PropertyChanged }); - floatParams.push_back(floatParamItem); - } else { - const EffectConstant& constant = std::get<1>(param.constant); - if (constant.minValue == 0 && constant.maxValue == 1 && constant.step == 1) { - Magpie::App::ScalingModeBoolParameter boolParamItem( - i, - StrUtils::UTF8ToUTF16(param.label.empty() ? param.name : param.label), - paramValue.has_value() ? std::abs(*paramValue) > 1e-6 : (bool)constant.defaultValue - ); - boolParamItem.PropertyChanged({ this, &EffectParametersViewModel::_ScalingModeBoolParameter_PropertyChanged }); - boolParams.push_back(boolParamItem); - } else { - Magpie::App::ScalingModeFloatParameter floatParamItem( - i, - StrUtils::UTF8ToUTF16(param.label.empty() ? param.name : param.label), - paramValue.has_value() ? *paramValue : (float)constant.defaultValue, - (float)constant.minValue, - (float)constant.maxValue, - (float)constant.step - ); - floatParamItem.PropertyChanged({ this, &EffectParametersViewModel::_ScalingModeFloatParameter_PropertyChanged }); - floatParams.push_back(floatParamItem); - } - } - } - if (!boolParams.empty()) { - _boolParams = single_threaded_vector(std::move(boolParams)); - } - if (!floatParams.empty()) { - _floatParams = single_threaded_vector(std::move(floatParams)); - } -} - -void EffectParametersViewModel::_ScalingModeBoolParameter_PropertyChanged( - IInspectable const& sender, - PropertyChangedEventArgs const& args -) { - if (args.PropertyName() != L"Value") { - return; - } - - ScalingModeBoolParameter* boolParamImpl = - get_self(sender.as()); - const std::string& effectName = _effectInfo->params[boolParamImpl->Index()].name; - _Data()[StrUtils::UTF8ToUTF16(effectName)] = (float)boolParamImpl->Value(); - - LazySaveAppSettings(); -} - -void EffectParametersViewModel::_ScalingModeFloatParameter_PropertyChanged( - IInspectable const& sender, - PropertyChangedEventArgs const& args -) { - if (args.PropertyName() != L"Value") { - return; - } - - ScalingModeFloatParameter* floatParamImpl = - get_self(sender.as()); - const std::string& effectName = _effectInfo->params[floatParamImpl->Index()].name; - _Data()[StrUtils::UTF8ToUTF16(effectName)] = (float)floatParamImpl->Value(); - - LazySaveAppSettings(); -} - -phmap::flat_hash_map& EffectParametersViewModel::_Data() { - ScalingMode& scalingMode = ScalingModesService::Get().GetScalingMode(_scalingModeIdx); - return scalingMode.effects[_effectIdx].parameters; -} - -} diff --git a/src/Magpie.App/EffectParametersViewModel.h b/src/Magpie.App/EffectParametersViewModel.h deleted file mode 100644 index b4cbd7fe0..000000000 --- a/src/Magpie.App/EffectParametersViewModel.h +++ /dev/null @@ -1,156 +0,0 @@ -#pragma once -#include "EffectParametersViewModel.g.h" -#include "ScalingModeBoolParameter.g.h" -#include "ScalingModeFloatParameter.g.h" -#include - -namespace winrt::Magpie::App { -struct EffectInfo; -} - -namespace winrt::Magpie::App::implementation { - -struct ScalingModeBoolParameter : ScalingModeBoolParameterT, - wil::notify_property_changed_base { - ScalingModeBoolParameter(uint32_t index, const hstring& label, bool initValue) - : _index(index), _label(box_value(label)), _value(initValue) { - } - uint32_t Index() const noexcept { - return _index; - } - - bool Value() const noexcept { - return _value; - } - - void Value(bool value) { - _value = value; - RaisePropertyChanged(L"Value"); - } - - IInspectable Label() const noexcept { - return _label; - } - -private: - const uint32_t _index; - IInspectable _label; - bool _value; -}; - -struct ScalingModeFloatParameter : ScalingModeFloatParameterT, - wil::notify_property_changed_base { - ScalingModeFloatParameter(uint32_t index, const hstring& label, float initValue, float minimum, float maximum, float step) - : _index(index), _label(label), _value(initValue), _minimum(minimum), _maximum(maximum), _step(step) { - } - - uint32_t Index() const noexcept { - return _index; - } - - double Value() const noexcept { - return _value; - } - - void Value(double value) { - _value = value; - RaisePropertyChanged(L"Value"); - RaisePropertyChanged(L"ValueText"); - } - - hstring ValueText() const noexcept { - return ScalingModesPage::NumberFormatter().FormatDouble(_value); - } - - hstring Label() const noexcept { - return _label; - } - - double Minimum() const noexcept { - return _minimum; - } - - double Maximum() const noexcept { - return _maximum; - } - - double Step() const noexcept { - return _step; - } - -private: - const uint32_t _index; - const hstring _label; - const double _minimum; - const double _maximum; - const double _step; - double _value; -}; - -struct EffectParametersViewModel : EffectParametersViewModelT { - EffectParametersViewModel() : EffectParametersViewModel( - std::numeric_limits::max(), std::numeric_limits::max()) {} - - EffectParametersViewModel(uint32_t scalingModeIdx, uint32_t effectIdx); - - uint32_t ScalingModeIdx() const noexcept { - return _scalingModeIdx; - } - - void ScalingModeIdx(uint32_t value) noexcept { - _scalingModeIdx = value; - } - - uint32_t EffectIdx() const noexcept { - return _effectIdx; - } - - void EffectIdx(uint32_t value) noexcept { - _effectIdx = value; - } - - IVector BoolParams() const noexcept { - return _boolParams; - } - - IVector FloatParams() const noexcept { - return _floatParams; - } - - bool HasBoolParams() const noexcept { - return _boolParams != nullptr; - } - - bool HasFloatParams() const noexcept { - return _floatParams != nullptr; - } - -private: - void _ScalingModeBoolParameter_PropertyChanged(IInspectable const& sender, PropertyChangedEventArgs const& args); - - void _ScalingModeFloatParameter_PropertyChanged(IInspectable const& sender, PropertyChangedEventArgs const& args); - - phmap::flat_hash_map& _Data(); - - IVector _boolParams{ nullptr }; - IVector _floatParams{ nullptr }; - - uint32_t _scalingModeIdx; - uint32_t _effectIdx; - const EffectInfo* _effectInfo = nullptr; -}; - -} - -namespace winrt::Magpie::App::factory_implementation { - -struct ScalingModeBoolParameter : ScalingModeBoolParameterT { -}; - -struct ScalingModeFloatParameter : ScalingModeFloatParameterT { -}; - -struct EffectParametersViewModel : EffectParametersViewModelT { -}; - -} diff --git a/src/Magpie.App/EffectParametersViewModel.idl b/src/Magpie.App/EffectParametersViewModel.idl deleted file mode 100644 index c4c4db697..000000000 --- a/src/Magpie.App/EffectParametersViewModel.idl +++ /dev/null @@ -1,33 +0,0 @@ -namespace Magpie.App { - runtimeclass ScalingModeBoolParameter : Windows.UI.Xaml.Data.INotifyPropertyChanged { - ScalingModeBoolParameter(UInt32 index, String label, Boolean initValue); - - Boolean Value; - // Bind to CheckBox.Content - Object Label { get; }; - } - - runtimeclass ScalingModeFloatParameter : Windows.UI.Xaml.Data.INotifyPropertyChanged { - ScalingModeFloatParameter(UInt32 index, String label, Single initValue, Single minimum, Single maximum, Single step); - - Double Value; - String Label { get; }; - String ValueText { get; }; - Double Minimum { get; }; - Double Maximum { get; }; - Double Step { get; }; - } - - runtimeclass EffectParametersViewModel { - EffectParametersViewModel(); - EffectParametersViewModel(UInt32 scalingModeIdx, UInt32 effectIdx); - - UInt32 ScalingModeIdx; - UInt32 EffectIdx; - - IVector BoolParams { get; }; - IVector FloatParams { get; }; - Boolean HasBoolParams { get; }; - Boolean HasFloatParams { get; }; - } -} diff --git a/src/Magpie.App/FileDialogHelper.cpp b/src/Magpie.App/FileDialogHelper.cpp deleted file mode 100644 index 7021d95f3..000000000 --- a/src/Magpie.App/FileDialogHelper.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "pch.h" -#include "FileDialogHelper.h" -#include "Logger.h" -#include "App.h" - -namespace winrt::Magpie::App { - -// 出错返回空,取消返回空字符串 -std::optional FileDialogHelper::OpenFileDialog(IFileDialog* fileDialog, FILEOPENDIALOGOPTIONS options) noexcept { - FILEOPENDIALOGOPTIONS options1{}; - fileDialog->GetOptions(&options1); - fileDialog->SetOptions(options1 | options | FOS_FORCEFILESYSTEM); - - if (fileDialog->Show((HWND)Application::Current().as().HwndMain()) != S_OK) { - // 被用户取消 - return std::wstring(); - } - - com_ptr file; - HRESULT hr = fileDialog->GetResult(file.put()); - if (FAILED(hr)) { - Logger::Get().ComError("IFileSaveDialog::GetResult 失败", hr); - return std::nullopt; - } - - wil::unique_cotaskmem_string fileName; - hr = file->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, fileName.put()); - if (FAILED(hr)) { - Logger::Get().ComError("IShellItem::GetDisplayName 失败", hr); - return std::nullopt; - } - - return std::wstring(fileName.get()); -} - -} diff --git a/src/Magpie.App/FileDialogHelper.h b/src/Magpie.App/FileDialogHelper.h deleted file mode 100644 index d96a3ec9f..000000000 --- a/src/Magpie.App/FileDialogHelper.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -namespace winrt::Magpie::App { - -struct FileDialogHelper { - static std::optional OpenFileDialog( - IFileDialog* fileDialog, - FILEOPENDIALOGOPTIONS options = 0 - ) noexcept; -}; - -} diff --git a/src/Magpie.App/HomeViewModel.cpp b/src/Magpie.App/HomeViewModel.cpp deleted file mode 100644 index 4e2ddb0ef..000000000 --- a/src/Magpie.App/HomeViewModel.cpp +++ /dev/null @@ -1,432 +0,0 @@ -#include "pch.h" -#include "HomeViewModel.h" -#if __has_include("HomeViewModel.g.cpp") -#include "HomeViewModel.g.cpp" -#endif -#include "AppSettings.h" -#include "ScalingService.h" -#include "Win32Utils.h" -#include "StrUtils.h" -#include "UpdateService.h" -#include "CommonSharedConstants.h" -#include "TouchHelper.h" -#include "LocalizationService.h" - -namespace winrt::Magpie::App::implementation { - -HomeViewModel::HomeViewModel() { - ScalingService& ScalingService = ScalingService::Get(); - - _isRunningChangedRevoker = ScalingService.IsRunningChanged( - auto_revoke, { this, &HomeViewModel::_ScalingService_IsRunningChanged }); - _isTimerOnRevoker = ScalingService.IsTimerOnChanged( - auto_revoke, { this, &HomeViewModel::_ScalingService_IsTimerOnChanged }); - _timerTickRevoker = ScalingService.TimerTick( - auto_revoke, { this, &HomeViewModel::_ScalingService_TimerTick }); - _wndToRestoreChangedRevoker = ScalingService.WndToRestoreChanged( - auto_revoke, { this, &HomeViewModel::_ScalingService_WndToRestoreChanged }); - - UpdateService& updateService = UpdateService::Get(); - _showUpdateCard = updateService.IsShowOnHomePage(); - _isShowOnHomePageChangedRevoker = updateService.IsShowOnHomePageChanged( - auto_revoke, - [this](bool value) { - if (value) { - ShowUpdateCard(true); - } - } - ); -} - -bool HomeViewModel::IsTimerOn() const noexcept { - return ScalingService::Get().IsTimerOn(); -} - -double HomeViewModel::TimerProgressRingValue() const noexcept { - ScalingService& ScalingService = ScalingService::Get(); - return ScalingService.IsTimerOn() ? ScalingService.TimerProgress() : 1.0f; -} - -hstring HomeViewModel::TimerLabelText() const noexcept { - ScalingService& ScalingService = ScalingService::Get(); - return to_hstring((int)std::ceil(ScalingService.SecondsLeft())); -} - -hstring HomeViewModel::TimerButtonText() const noexcept { - ScalingService& ScalingService = ScalingService::Get(); - ResourceLoader resourceLoader = - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID); - if (ScalingService.IsTimerOn()) { - return resourceLoader.GetString(L"Home_Activation_Timer_Cancel"); - } else { - hstring fmtStr = resourceLoader.GetString(L"Home_Activation_Timer_ButtonText"); - return hstring(fmt::format( - fmt::runtime(std::wstring_view(fmtStr)), - AppSettings::Get().CountdownSeconds() - )); - } -} - -bool HomeViewModel::IsNotRunning() const noexcept { - return !ScalingService::Get().IsRunning(); -} - -void HomeViewModel::ToggleTimer() const noexcept { - ScalingService& ScalingService = ScalingService::Get(); - if (ScalingService.IsTimerOn()) { - ScalingService.StopTimer(); - } else { - ScalingService.StartTimer(); - } -} - -uint32_t HomeViewModel::Delay() const noexcept { - return AppSettings::Get().CountdownSeconds(); -} - -void HomeViewModel::Delay(uint32_t value) { - AppSettings::Get().CountdownSeconds(value); - RaisePropertyChanged(L"Delay"); - RaisePropertyChanged(L"TimerButtonText"); -} - -bool HomeViewModel::IsAutoRestore() const noexcept { - return AppSettings::Get().IsAutoRestore(); -} - -void HomeViewModel::IsAutoRestore(bool value) { - AppSettings& settings = AppSettings::Get(); - - if (settings.IsAutoRestore() == value) { - return; - } - - settings.IsAutoRestore(value); - RaisePropertyChanged(L"IsAutoRestore"); -} - -bool HomeViewModel::IsWndToRestore() const noexcept { - return (bool)ScalingService::Get().WndToRestore(); -} - -void HomeViewModel::ActivateRestore() const noexcept { - HWND wndToRestore = (HWND)ScalingService::Get().WndToRestore(); - if (wndToRestore) { - Win32Utils::SetForegroundWindow(wndToRestore); - } -} - -void HomeViewModel::ClearRestore() const { - ScalingService::Get().ClearWndToRestore(); -} - -hstring HomeViewModel::RestoreWndDesc() const noexcept { - HWND wndToRestore = (HWND)ScalingService::Get().WndToRestore(); - if (!wndToRestore) { - return L""; - } - - std::wstring title(GetWindowTextLength(wndToRestore), L'\0'); - GetWindowText(wndToRestore, title.data(), (int)title.size() + 1); - - ResourceLoader resourceLoader = - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID); - hstring curWindow = resourceLoader.GetString(L"Home_Activation_AutoRestore_CurWindow"); - if (title.empty()) { - hstring emptyTitle = resourceLoader.GetString(L"Home_Activation_AutoRestore_EmptyTitle"); - return hstring(StrUtils::Concat(curWindow, L"<", emptyTitle, L">")); - } else { - return curWindow + title; - } -} - -inline void HomeViewModel::ShowUpdateCard(bool value) noexcept { - _showUpdateCard = value; - if (!value) { - UpdateService::Get().IsShowOnHomePage(false); - } - - RaisePropertyChanged(L"ShowUpdateCard"); - RaisePropertyChanged(L"UpdateCardTitle"); -} - -hstring HomeViewModel::UpdateCardTitle() const noexcept { - UpdateService& updateService = UpdateService::Get(); - if (updateService.Status() < UpdateStatus::Available) { - return {}; - } - - ResourceLoader resourceLoader = - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID); - hstring titleFmt = resourceLoader.GetString(L"About_Version_UpdateCard_Title"); - return hstring(fmt::format(fmt::runtime(std::wstring_view(titleFmt)), updateService.Tag())); -} - -bool HomeViewModel::IsAutoCheckForUpdates() const noexcept { - return AppSettings::Get().IsAutoCheckForUpdates(); -} - -void HomeViewModel::IsAutoCheckForUpdates(bool value) noexcept { - AppSettings::Get().IsAutoCheckForUpdates(value); -} - -void HomeViewModel::DownloadAndInstall() { - UpdateService::Get().DownloadAndInstall(); - Application::Current().as().RootPage().NavigateToAboutPage(); -} - -void HomeViewModel::ReleaseNotes() { - std::wstring url = StrUtils::Concat( - L"https://github.com/Blinue/Magpie/releases/tag/", - UpdateService::Get().Tag() - ); - Win32Utils::ShellOpen(url.c_str()); -} - -void HomeViewModel::RemindMeLater() { - ShowUpdateCard(false); -} - -bool HomeViewModel::IsTouchSupportEnabled() const noexcept { - // 不检查版本号是否匹配 - return TouchHelper::IsTouchSupportEnabled(); -} - -fire_and_forget HomeViewModel::IsTouchSupportEnabled(bool value) { - if (IsTouchSupportEnabled() == value) { - co_return; - } - - auto weakThis = get_weak(); - CoreDispatcher dispatcher = CoreWindow::GetForCurrentThread().Dispatcher(); - - // UAC 可能导致 XAML Islands 崩溃,因此不能在主线程上执行 ShellExecute, - // 见 https://github.com/microsoft/microsoft-ui-xaml/issues/4952 - co_await resume_background(); - - TouchHelper::IsTouchSupportEnabled(value); - - co_await dispatcher; - - if (weakThis.get()) { - RaisePropertyChanged(L"IsTouchSupportEnabled"); - RaisePropertyChanged(L"IsShowTouchSupportInfoBar"); - } -} - -Uri HomeViewModel::TouchSupportLearnMoreUrl() const noexcept { - if (LocalizationService::Get().Language() == L"zh-hans"sv) { - return Uri(L"https://github.com/Blinue/Magpie/blob/dev/docs/%E5%85%B3%E4%BA%8E%E8%A7%A6%E6%8E%A7%E6%94%AF%E6%8C%81.md"); - } else { - return Uri(L"https://github.com/Blinue/Magpie/blob/dev/docs/About%20touch%20support.md"); - } -} - -bool HomeViewModel::IsShowTouchSupportInfoBar() const noexcept { - return !Win32Utils::IsProcessElevated() && IsTouchSupportEnabled(); -} - -bool HomeViewModel::IsAllowScalingMaximized() const noexcept { - return AppSettings::Get().IsAllowScalingMaximized(); -} - -void HomeViewModel::IsAllowScalingMaximized(bool value) { - AppSettings::Get().IsAllowScalingMaximized(value); - - if (value) { - ScalingService::Get().CheckForeground(); - } -} - -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"); -} - -bool HomeViewModel::IsSimulateExclusiveFullscreen() const noexcept { - return AppSettings::Get().IsSimulateExclusiveFullscreen(); -} - -void HomeViewModel::IsSimulateExclusiveFullscreen(bool value) { - AppSettings& settings = AppSettings::Get(); - - if (settings.IsSimulateExclusiveFullscreen() == value) { - return; - } - - settings.IsSimulateExclusiveFullscreen(value); - RaisePropertyChanged(L"IsSimulateExclusiveFullscreen"); -} - -bool HomeViewModel::IsDeveloperMode() const noexcept { - return AppSettings::Get().IsDeveloperMode(); -} - -void HomeViewModel::IsDeveloperMode(bool value) { - AppSettings& settings = AppSettings::Get(); - - if (settings.IsDeveloperMode() == value) { - return; - } - - settings.IsDeveloperMode(value); - RaisePropertyChanged(L"IsDeveloperMode"); -} - -bool HomeViewModel::IsDebugMode() const noexcept { - return AppSettings::Get().IsDebugMode(); -} - -void HomeViewModel::IsDebugMode(bool value) { - AppSettings& settings = AppSettings::Get(); - - if (settings.IsDebugMode() == value) { - return; - } - - settings.IsDebugMode(value); - RaisePropertyChanged(L"IsDebugMode"); -} - -bool HomeViewModel::IsEffectCacheDisabled() const noexcept { - return AppSettings::Get().IsEffectCacheDisabled(); -} - -void HomeViewModel::IsEffectCacheDisabled(bool value) { - AppSettings& settings = AppSettings::Get(); - - if (settings.IsEffectCacheDisabled() == value) { - return; - } - - settings.IsEffectCacheDisabled(value); - RaisePropertyChanged(L"IsEffectCacheDisabled"); -} - -bool HomeViewModel::IsFontCacheDisabled() const noexcept { - return AppSettings::Get().IsFontCacheDisabled(); -} - -void HomeViewModel::IsFontCacheDisabled(bool value) { - AppSettings& settings = AppSettings::Get(); - - if (settings.IsFontCacheDisabled() == value) { - return; - } - - settings.IsFontCacheDisabled(value); - RaisePropertyChanged(L"IsFontCacheDisabled"); -} - -bool HomeViewModel::IsSaveEffectSources() const noexcept { - return AppSettings::Get().IsSaveEffectSources(); -} - -void HomeViewModel::IsSaveEffectSources(bool value) { - AppSettings& settings = AppSettings::Get(); - - if (settings.IsSaveEffectSources() == value) { - return; - } - - settings.IsSaveEffectSources(value); - RaisePropertyChanged(L"IsSaveEffectSources"); -} - -bool HomeViewModel::IsWarningsAreErrors() const noexcept { - return AppSettings::Get().IsWarningsAreErrors(); -} - -void HomeViewModel::IsWarningsAreErrors(bool value) { - AppSettings& settings = AppSettings::Get(); - - if (settings.IsWarningsAreErrors() == value) { - return; - } - - settings.IsWarningsAreErrors(value); - RaisePropertyChanged(L"IsWarningsAreErrors"); -} - -int HomeViewModel::DuplicateFrameDetectionMode() const noexcept { - return (int)AppSettings::Get().DuplicateFrameDetectionMode(); -} - -void HomeViewModel::DuplicateFrameDetectionMode(int value) { - if (value < 0) { - return; - } - - const auto mode = (::Magpie::Core::DuplicateFrameDetectionMode)value; - - AppSettings& settings = AppSettings::Get(); - if (settings.DuplicateFrameDetectionMode() == mode) { - return; - } - - settings.DuplicateFrameDetectionMode(mode); - - RaisePropertyChanged(L"DuplicateFrameDetectionMode"); - RaisePropertyChanged(L"IsDynamicDection"); - - if (mode != ::Magpie::Core::DuplicateFrameDetectionMode::Dynamic) { - settings.IsStatisticsForDynamicDetectionEnabled(false); - RaisePropertyChanged(L"IsStatisticsForDynamicDetectionEnabled"); - } -} - -bool HomeViewModel::IsDynamicDection() const noexcept { - return AppSettings::Get().DuplicateFrameDetectionMode() == ::Magpie::Core::DuplicateFrameDetectionMode::Dynamic; -} - -bool HomeViewModel::IsStatisticsForDynamicDetectionEnabled() const noexcept { - return AppSettings::Get().IsStatisticsForDynamicDetectionEnabled(); -} - -void HomeViewModel::IsStatisticsForDynamicDetectionEnabled(bool value) { - AppSettings& settings = AppSettings::Get(); - - if (settings.IsStatisticsForDynamicDetectionEnabled() == value) { - return; - } - - settings.IsStatisticsForDynamicDetectionEnabled(value); - RaisePropertyChanged(L"IsStatisticsForDynamicDetectionEnabled"); -} - -void HomeViewModel::_ScalingService_IsTimerOnChanged(bool value) { - if (!value) { - RaisePropertyChanged(L"TimerProgressRingValue"); - } - - RaisePropertyChanged(L"TimerProgressRingValue"); - RaisePropertyChanged(L"TimerLabelText"); - RaisePropertyChanged(L"TimerButtonText"); - RaisePropertyChanged(L"IsTimerOn"); -} - -void HomeViewModel::_ScalingService_TimerTick(double) { - RaisePropertyChanged(L"TimerProgressRingValue"); - RaisePropertyChanged(L"TimerLabelText"); -} - -void HomeViewModel::_ScalingService_IsRunningChanged(bool) { - RaisePropertyChanged(L"IsNotRunning"); -} - -void HomeViewModel::_ScalingService_WndToRestoreChanged(HWND) { - RaisePropertyChanged(L"IsWndToRestore"); - RaisePropertyChanged(L"RestoreWndDesc"); -} - -} diff --git a/src/Magpie.App/HomeViewModel.h b/src/Magpie.App/HomeViewModel.h deleted file mode 100644 index a43aee31f..000000000 --- a/src/Magpie.App/HomeViewModel.h +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once -#include "HomeViewModel.g.h" -#include "WinRTUtils.h" - -namespace winrt::Magpie::App::implementation { - -struct HomeViewModel : HomeViewModelT, wil::notify_property_changed_base { - HomeViewModel(); - - bool IsTimerOn() const noexcept; - - double TimerProgressRingValue() const noexcept; - - hstring TimerLabelText() const noexcept; - - hstring TimerButtonText() const noexcept; - - bool IsNotRunning() const noexcept; - - void ToggleTimer() const noexcept; - - uint32_t Delay() const noexcept; - void Delay(uint32_t value); - - bool IsAutoRestore() const noexcept; - void IsAutoRestore(bool value); - - bool IsWndToRestore() const noexcept; - - void ActivateRestore() const noexcept; - - void ClearRestore() const; - - hstring RestoreWndDesc() const noexcept; - - bool ShowUpdateCard() const noexcept { - return _showUpdateCard; - } - - void ShowUpdateCard(bool value) noexcept; - - hstring UpdateCardTitle() const noexcept; - - bool IsAutoCheckForUpdates() const noexcept; - void IsAutoCheckForUpdates(bool value) noexcept; - - void DownloadAndInstall(); - - void ReleaseNotes(); - - void RemindMeLater(); - - bool IsTouchSupportEnabled() const noexcept; - fire_and_forget IsTouchSupportEnabled(bool value); - - Uri TouchSupportLearnMoreUrl() const noexcept; - - bool IsShowTouchSupportInfoBar() const noexcept; - - bool IsAllowScalingMaximized() const noexcept; - void IsAllowScalingMaximized(bool value); - - bool IsInlineParams() const noexcept; - void IsInlineParams(bool value); - - bool IsSimulateExclusiveFullscreen() const noexcept; - void IsSimulateExclusiveFullscreen(bool value); - - bool IsDeveloperMode() const noexcept; - void IsDeveloperMode(bool value); - - bool IsDebugMode() const noexcept; - void IsDebugMode(bool value); - - bool IsEffectCacheDisabled() const noexcept; - void IsEffectCacheDisabled(bool value); - - bool IsFontCacheDisabled() const noexcept; - void IsFontCacheDisabled(bool value); - - bool IsSaveEffectSources() const noexcept; - void IsSaveEffectSources(bool value); - - bool IsWarningsAreErrors() const noexcept; - void IsWarningsAreErrors(bool value); - - int DuplicateFrameDetectionMode() const noexcept; - void DuplicateFrameDetectionMode(int value); - - bool IsDynamicDection() const noexcept; - - bool IsStatisticsForDynamicDetectionEnabled() const noexcept; - void IsStatisticsForDynamicDetectionEnabled(bool value); -private: - void _ScalingService_IsTimerOnChanged(bool value); - - void _ScalingService_TimerTick(double); - - void _ScalingService_IsRunningChanged(bool); - - void _ScalingService_WndToRestoreChanged(HWND); - - WinRTUtils::EventRevoker _isTimerOnRevoker; - WinRTUtils::EventRevoker _timerTickRevoker; - WinRTUtils::EventRevoker _isRunningChangedRevoker; - WinRTUtils::EventRevoker _wndToRestoreChangedRevoker; - WinRTUtils::EventRevoker _isShowOnHomePageChangedRevoker; - - bool _showUpdateCard = false; -}; - -} - -namespace winrt::Magpie::App::factory_implementation { - -struct HomeViewModel : HomeViewModelT { -}; - -} diff --git a/src/Magpie.App/HomeViewModel.idl b/src/Magpie.App/HomeViewModel.idl deleted file mode 100644 index 29f4c6806..000000000 --- a/src/Magpie.App/HomeViewModel.idl +++ /dev/null @@ -1,46 +0,0 @@ -namespace Magpie.App { - runtimeclass HomeViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged { - HomeViewModel(); - - Boolean ShowUpdateCard; - String UpdateCardTitle{ get; }; - Boolean IsAutoCheckForUpdates; - void DownloadAndInstall(); - void ReleaseNotes(); - void RemindMeLater(); - - Boolean IsTimerOn { get; }; - Double TimerProgressRingValue { get; }; - String TimerLabelText { get; }; - String TimerButtonText { get; }; - Boolean IsNotRunning { get; }; - UInt32 Delay; - - void ToggleTimer(); - - Boolean IsAutoRestore; - Boolean IsWndToRestore { get; }; - String RestoreWndDesc { get; }; - - void ActivateRestore(); - void ClearRestore(); - - Boolean IsTouchSupportEnabled; - Windows.Foundation.Uri TouchSupportLearnMoreUrl { get; }; - Boolean IsShowTouchSupportInfoBar { get; }; - - Boolean IsAllowScalingMaximized; - Boolean IsInlineParams; - Boolean IsSimulateExclusiveFullscreen; - - Boolean IsDeveloperMode; - Boolean IsDebugMode; - Boolean IsEffectCacheDisabled; - Boolean IsFontCacheDisabled; - Boolean IsSaveEffectSources; - Boolean IsWarningsAreErrors; - Int32 DuplicateFrameDetectionMode; - Boolean IsDynamicDection{ get; }; - Boolean IsStatisticsForDynamicDetectionEnabled; - } -} diff --git a/src/Magpie.App/IconHelper.cpp b/src/Magpie.App/IconHelper.cpp deleted file mode 100644 index 03f629b86..000000000 --- a/src/Magpie.App/IconHelper.cpp +++ /dev/null @@ -1,249 +0,0 @@ -#include "pch.h" -#include "IconHelper.h" -#include "Logger.h" -#include "Utils.h" -#include "Win32Utils.h" -#include "StrUtils.h" - -using namespace winrt; -using namespace Windows::Graphics::Imaging; -using namespace Windows::UI::Xaml::Media::Imaging; - - -namespace winrt::Magpie::App { - -static bool CopyPixelsOfHBmp(HBITMAP hBmp, LONG width, LONG height, void* data) noexcept { - BITMAPINFO bi = { - .bmiHeader = { - .biSize = sizeof(BITMAPINFOHEADER), - .biWidth = width, - .biHeight = -height, - .biPlanes = 1, - .biBitCount = 32, - .biCompression = BI_RGB, - .biSizeImage = DWORD(width * height * 4) - } - }; - - wil::unique_hdc_window hdc(wil::window_dc(GetDC(NULL))); - if (GetDIBits(hdc.get(), hBmp, 0, height, data, &bi, DIB_RGB_COLORS) != height) { - Logger::Get().Win32Error("GetDIBits 失败"); - return false; - } - - return true; -} - -static SoftwareBitmap HIcon2SoftwareBitmap(HICON hIcon) { - // 单色图标: 不处理 - // 彩色掩码图标: 忽略掩码 - - ICONINFO iconInfo{}; - if (!GetIconInfo(hIcon, &iconInfo)) { - Logger::Get().Win32Error("GetIconInfo 失败"); - return nullptr; - } - - wil::unique_hbitmap hbmpColor(iconInfo.hbmColor); - wil::unique_hbitmap hbmpMask(iconInfo.hbmMask); - - if (!iconInfo.fIcon) { - return nullptr; - } - - BITMAP bmp{}; - GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmp); - - SoftwareBitmap bitmap(BitmapPixelFormat::Bgra8, bmp.bmWidth, bmp.bmHeight, BitmapAlphaMode::Premultiplied); - { - BitmapBuffer buffer = bitmap.LockBuffer(BitmapBufferAccessMode::Write); - uint8_t* pixels = buffer.CreateReference().data(); - - if (!CopyPixelsOfHBmp(iconInfo.hbmColor, bmp.bmWidth, bmp.bmHeight, pixels)) { - return nullptr; - } - - const uint32_t pixelsSize = bmp.bmWidth * bmp.bmHeight * 4; - - // 若颜色掩码有 A 通道,则是彩色图标,否则是彩色掩码图标 - bool hasAlpha = false; - for (uint32_t i = 3; i < pixelsSize; i += 4) { - if (pixels[i] != 0) { - hasAlpha = true; - break; - } - } - - if (hasAlpha) { - // 彩色图标 - for (size_t i = 0; i < pixelsSize; i += 4) { - // 预乘 Alpha 通道 - const float alpha = pixels[i + 3] / 255.0f; - - pixels[i] = (uint8_t)std::lroundf(pixels[i] * alpha); - pixels[i + 1] = (uint8_t)std::lroundf(pixels[i + 1] * alpha); - pixels[i + 2] = (uint8_t)std::lroundf(pixels[i + 2] * alpha); - } - } else { - // 彩色掩码图标 - for (uint32_t i = 3; i < pixelsSize; i += 4) { - pixels[i] = 255; - } - } - } - - return bitmap; -} - -static SIZE GetSizeOfIcon(HICON hIcon) noexcept { - ICONINFO iconInfo{}; - if (!GetIconInfo(hIcon, &iconInfo)) { - Logger::Get().Win32Error("GetIconInfo 失败"); - return {}; - } - - wil::unique_hbitmap hbmpColor(iconInfo.hbmColor); - wil::unique_hbitmap hbmpMask(iconInfo.hbmMask); - - if (!iconInfo.fIcon) { - return {}; - } - - BITMAP bmp{}; - GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmp); - return { bmp.bmWidth, bmp.bmHeight }; -} - -static HICON GetHIconOfWnd(HWND hWnd, LONG preferredSize) noexcept { - HICON result = NULL; - - HICON candidateSmallIcon = NULL; - - result = (HICON)SendMessage(hWnd, WM_GETICON, ICON_SMALL, 0); - if (result) { - if (GetSizeOfIcon(result).cx >= preferredSize) { - // 小图标尺寸足够 - return result; - } else { - // 否则继续检索大图标 - candidateSmallIcon = result; - } - } - - result = (HICON)SendMessage(hWnd, WM_GETICON, ICON_BIG, 0); - if (result) { - return result; - } - - if (!candidateSmallIcon) { - result = (HICON)GetClassLongPtr(hWnd, GCLP_HICONSM); - if (result) { - if (GetSizeOfIcon(result).cx >= preferredSize) { - return result; - } else { - candidateSmallIcon = result; - } - } - } - - result = (HICON)GetClassLongPtr(hWnd, GCLP_HICON); - if (result) { - return result; - } - - if (candidateSmallIcon) { - // 不存在大图标则回落到小图标 - return candidateSmallIcon; - } - - // 此窗口无图标则回落到所有者窗口 - HWND hwndOwner = GetWindow(hWnd, GW_OWNER); - if (!hwndOwner) { - return NULL; - } - - return GetHIconOfWnd(hwndOwner, preferredSize); -} - -SoftwareBitmap IconHelper::ExtractIconFormWnd(HWND hWnd, uint32_t preferredSize, uint32_t dpi) { - if (HICON hIcon = GetHIconOfWnd(hWnd, std::lround(preferredSize * dpi / double(USER_DEFAULT_SCREEN_DPI)))) { - return HIcon2SoftwareBitmap(hIcon); - } - - return ExtractIconFromExe(Win32Utils::GetPathOfWnd(hWnd).c_str(), preferredSize, dpi); -} - -SoftwareBitmap IconHelper::ExtractIconFromExe(const wchar_t* fileName, uint32_t preferredSize, uint32_t dpi) { - preferredSize = (uint32_t)std::lround(preferredSize * dpi / double(USER_DEFAULT_SCREEN_DPI)); - - { - wil::unique_hicon hIcon = NULL; - SHDefExtractIcon(fileName, 0, 0, hIcon.put(), NULL, preferredSize); - if (hIcon) { - return HIcon2SoftwareBitmap(hIcon.get()); - } - } - - // 回落到 IShellItemImageFactory,此接口存在以下问题: - // 1. 速度较慢 - // 2. SIIGBF_BIGGERSIZEOK 不起作用,在我的测试里它始终在内部执行低质量的 GDI 缩放 - // 3. 不能可靠的并发使用,有时会得到错误的结果 - // 4. 据说它返回的位图有时已经预乘透明通道,没有区分的办法 - - wil::unique_hbitmap hBmp; - { - static wil::srwlock srwLock; - auto lock = srwLock.lock_exclusive(); - - com_ptr factory; - HRESULT hr = SHCreateItemFromParsingName(fileName, nullptr, IID_PPV_ARGS(&factory)); - if (FAILED(hr)) { - return nullptr; - } - - while (true) { - hr = factory->GetImage( - { (LONG)preferredSize, (LONG)preferredSize }, - SIIGBF_BIGGERSIZEOK | SIIGBF_ICONONLY, - hBmp.put() - ); - - if (hr == E_PENDING) { - // 等待提取完成 - Sleep(0); - continue; - } else if (FAILED(hr)) { - return nullptr; - } else { - break; - } - } - } - - BITMAP bmp{}; - GetObject(hBmp.get(), sizeof(BITMAP), &bmp); - - SoftwareBitmap bitmap(BitmapPixelFormat::Bgra8, bmp.bmWidth, bmp.bmHeight, BitmapAlphaMode::Premultiplied); - { - BitmapBuffer buffer = bitmap.LockBuffer(BitmapBufferAccessMode::Write); - uint8_t* pixels = buffer.CreateReference().data(); - - if (!CopyPixelsOfHBmp(hBmp.get(), bmp.bmWidth, bmp.bmHeight, pixels)) { - return nullptr; - } - - const size_t pixelsSize = size_t(bmp.bmWidth * bmp.bmHeight * 4); - for (size_t i = 0; i < pixelsSize; i += 4) { - // 预乘 Alpha 通道 - float alpha = pixels[i + 3] / 255.0f; - - pixels[i] = (BYTE)std::lroundf(pixels[i] * alpha); - pixels[i + 1] = (BYTE)std::lroundf(pixels[i + 1] * alpha); - pixels[i + 2] = (BYTE)std::lroundf(pixels[i + 2] * alpha); - } - } - - return bitmap; -} - -} diff --git a/src/Magpie.App/IconHelper.h b/src/Magpie.App/IconHelper.h deleted file mode 100644 index 0aab34968..000000000 --- a/src/Magpie.App/IconHelper.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -namespace winrt::Magpie::App { - -struct IconHelper { - static Windows::Graphics::Imaging::SoftwareBitmap ExtractIconFormWnd(HWND hWnd, uint32_t preferredSize, uint32_t dpi); - - static Windows::Graphics::Imaging::SoftwareBitmap ExtractIconFromExe(const wchar_t* fileName, uint32_t preferredSize, uint32_t dpi); -}; - -} diff --git a/src/Magpie.App/IsEqualStateTrigger.cpp b/src/Magpie.App/IsEqualStateTrigger.cpp deleted file mode 100644 index 83543dd92..000000000 --- a/src/Magpie.App/IsEqualStateTrigger.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "pch.h" -#include "IsEqualStateTrigger.h" -#if __has_include("IsEqualStateTrigger.g.cpp") -#include "IsEqualStateTrigger.g.cpp" -#endif - -namespace winrt::Magpie::App::implementation { - -const DependencyProperty IsEqualStateTrigger::_valueProperty = DependencyProperty::Register( - L"Value", - xaml_typename(), - xaml_typename(), - PropertyMetadata(nullptr, &IsEqualStateTrigger::_OnPropertyChanged) -); - -const DependencyProperty IsEqualStateTrigger::_toProperty = DependencyProperty::Register( - L"To", - xaml_typename(), - xaml_typename(), - PropertyMetadata(nullptr, &IsEqualStateTrigger::_OnPropertyChanged) -); - -void IsEqualStateTrigger::_OnPropertyChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&) { - get_self(sender.as())->_UpdateTrigger(); -} - -static bool AreValuesEqual(IInspectable const& value1, IInspectable const& value2) { - if (value1 == value2) { - return true; - } - - if (!value1 || !value2) { - return false; - } - - if (get_class_name(value1) != get_class_name(value2)) { - return false; - } - - return false; -} - -void IsEqualStateTrigger::_UpdateTrigger() { - SetActive(AreValuesEqual(Value(), To())); -} - -} diff --git a/src/Magpie.App/IsEqualStateTrigger.h b/src/Magpie.App/IsEqualStateTrigger.h deleted file mode 100644 index b9a86824c..000000000 --- a/src/Magpie.App/IsEqualStateTrigger.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once -#include "IsEqualStateTrigger.g.h" - -namespace winrt::Magpie::App::implementation { - -struct IsEqualStateTrigger : IsEqualStateTriggerT { - IInspectable Value() const { - return GetValue(_valueProperty); - } - - void Value(IInspectable const& value) { - SetValue(_valueProperty, value); - } - - IInspectable To() const { - return GetValue(_toProperty); - } - - void To(IInspectable const& value) { - SetValue(_toProperty, value); - } - - static DependencyProperty ValueProperty() { - return _valueProperty; - } - - static DependencyProperty ToProperty() { - return _toProperty; - } - -private: - static const DependencyProperty _valueProperty; - static const DependencyProperty _toProperty; - - static void _OnPropertyChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&); - - void _UpdateTrigger(); -}; - -} - -namespace winrt::Magpie::App::factory_implementation { - -struct IsEqualStateTrigger : IsEqualStateTriggerT { -}; - -} diff --git a/src/Magpie.App/IsEqualStateTrigger.idl b/src/Magpie.App/IsEqualStateTrigger.idl deleted file mode 100644 index bb7aca5b7..000000000 --- a/src/Magpie.App/IsEqualStateTrigger.idl +++ /dev/null @@ -1,11 +0,0 @@ -namespace Magpie.App { - runtimeclass IsEqualStateTrigger : Windows.UI.Xaml.StateTriggerBase { - IsEqualStateTrigger(); - - Object Value; - Object To; - - static Windows.UI.Xaml.DependencyProperty ValueProperty { get; }; - static Windows.UI.Xaml.DependencyProperty ToProperty { get; }; - } -} diff --git a/src/Magpie.App/IsNullStateTrigger.cpp b/src/Magpie.App/IsNullStateTrigger.cpp deleted file mode 100644 index 3fc194ecf..000000000 --- a/src/Magpie.App/IsNullStateTrigger.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "pch.h" -#include "IsNullStateTrigger.h" -#if __has_include("IsNullStateTrigger.g.cpp") -#include "IsNullStateTrigger.g.cpp" -#endif - -namespace winrt::Magpie::App::implementation { - -const DependencyProperty IsNullStateTrigger::_valueProperty = DependencyProperty::Register( - L"Value", - xaml_typename(), - xaml_typename(), - PropertyMetadata(nullptr, &IsNullStateTrigger::_OnValueChanged) -); - -IsNullStateTrigger::IsNullStateTrigger() { - _UpdateTrigger(); -} - -void IsNullStateTrigger::_OnValueChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&) { - get_self(sender.as())->_UpdateTrigger(); -} - -void IsNullStateTrigger::_UpdateTrigger() { - SetActive(!Value()); -} - -} diff --git a/src/Magpie.App/IsNullStateTrigger.h b/src/Magpie.App/IsNullStateTrigger.h deleted file mode 100644 index 7f929e6c3..000000000 --- a/src/Magpie.App/IsNullStateTrigger.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include "IsNullStateTrigger.g.h" - -namespace winrt::Magpie::App::implementation { - -struct IsNullStateTrigger : IsNullStateTriggerT { - IsNullStateTrigger(); - - IInspectable Value() const { - return GetValue(_valueProperty); - } - - void Value(IInspectable const& value) { - SetValue(_valueProperty, value); - } - - static DependencyProperty ValueProperty() { - return _valueProperty; - } - -private: - static const DependencyProperty _valueProperty; - - static void _OnValueChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&); - - void _UpdateTrigger(); -}; - -} - -namespace winrt::Magpie::App::factory_implementation { - -struct IsNullStateTrigger : IsNullStateTriggerT { -}; - -} diff --git a/src/Magpie.App/IsNullStateTrigger.idl b/src/Magpie.App/IsNullStateTrigger.idl deleted file mode 100644 index 51dfacd0f..000000000 --- a/src/Magpie.App/IsNullStateTrigger.idl +++ /dev/null @@ -1,8 +0,0 @@ -namespace Magpie.App { - runtimeclass IsNullStateTrigger : Windows.UI.Xaml.StateTriggerBase { - IsNullStateTrigger(); - - Object Value; - static Windows.UI.Xaml.DependencyProperty ValueProperty { get; }; - } -} diff --git a/src/Magpie.App/JsonHelper.cpp b/src/Magpie.App/JsonHelper.cpp deleted file mode 100644 index 706537b75..000000000 --- a/src/Magpie.App/JsonHelper.cpp +++ /dev/null @@ -1,147 +0,0 @@ -#include "pch.h" -#include "JsonHelper.h" -#include "StrUtils.h" - - -namespace winrt::Magpie::App { - -bool JsonHelper::ReadBool( - const rapidjson::GenericObject& obj, - const char* name, - bool& result, - bool required -) noexcept { - auto node = obj.FindMember(name); - if (node == obj.MemberEnd()) { - return !required; - } - - if (!node->value.IsBool()) { - return false; - } - - result = node->value.GetBool(); - return true; -} - -bool JsonHelper::ReadBoolFlag( - const rapidjson::GenericObject& obj, - const char* nodeName, - uint32_t flagBit, - uint32_t& flags, - bool required -) noexcept { - auto node = obj.FindMember(nodeName); - if (node == obj.MemberEnd()) { - return !required; - } - - if (!node->value.IsBool()) { - return false; - } - - if (node->value.GetBool()) { - flags |= flagBit; - } else { - flags &= ~flagBit; - } - - return true; -} - -bool JsonHelper::ReadUInt( - const rapidjson::GenericObject& obj, - const char* name, - uint32_t& result, - bool required -) noexcept { - auto node = obj.FindMember(name); - if (node == obj.MemberEnd()) { - return !required; - } - - if (!node->value.IsUint()) { - return false; - } - - result = node->value.GetUint(); - return true; -} - -bool JsonHelper::ReadInt( - const rapidjson::GenericObject& obj, - const char* name, - int& result, - bool required -) noexcept { - auto node = obj.FindMember(name); - if (node == obj.MemberEnd()) { - return !required; - } - - if (!node->value.IsInt()) { - return false; - } - - result = node->value.GetInt(); - return true; -} - -bool JsonHelper::ReadInt64( - const rapidjson::GenericObject& obj, - const char* name, - int64_t& result, - bool required -) noexcept { - auto node = obj.FindMember(name); - if (node == obj.MemberEnd()) { - return !required; - } - - if (!node->value.IsInt64()) { - return false; - } - - result = node->value.GetInt64(); - return true; -} - -bool JsonHelper::ReadFloat( - const rapidjson::GenericObject& obj, - const char* name, - float& result, - bool required -) noexcept { - auto node = obj.FindMember(name); - if (node == obj.MemberEnd()) { - return !required; - } - - if (!node->value.IsNumber()) { - return false; - } - - result = node->value.GetFloat(); - return true; -} - -bool JsonHelper::ReadString( - const rapidjson::GenericObject& obj, - const char* name, - std::wstring& result, - bool required -) noexcept { - auto node = obj.FindMember(name); - if (node == obj.MemberEnd()) { - return !required; - } - - if (!node->value.IsString()) { - return false; - } - - result = StrUtils::UTF8ToUTF16(node->value.GetString()); - return true; -} - -} diff --git a/src/Magpie.App/JsonHelper.h b/src/Magpie.App/JsonHelper.h deleted file mode 100644 index 7c3081572..000000000 --- a/src/Magpie.App/JsonHelper.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once -#include - -namespace winrt::Magpie::App { - -struct JsonHelper { - static bool ReadBool( - const rapidjson::GenericObject& obj, - const char* name, - bool& result, - bool required = false - ) noexcept; - - static bool ReadBoolFlag( - const rapidjson::GenericObject& obj, - const char* nodeName, - uint32_t flagBit, - uint32_t& flags, - bool required = false - ) noexcept; - - static bool ReadUInt( - const rapidjson::GenericObject& obj, - const char* name, - uint32_t& result, - bool required = false - ) noexcept; - - static bool ReadInt( - const rapidjson::GenericObject& obj, - const char* name, - int& result, - bool required = false - ) noexcept; - - static bool ReadInt64( - const rapidjson::GenericObject& obj, - const char* name, - int64_t& result, - bool required = false - ) noexcept; - - static bool ReadFloat( - const rapidjson::GenericObject& obj, - const char* name, - float& result, - bool required = false - ) noexcept; - - static bool ReadString( - const rapidjson::GenericObject& obj, - const char* name, - std::wstring& result, - bool required = false - ) noexcept; -}; - -} diff --git a/src/Magpie.App/LoggerHelper.cpp b/src/Magpie.App/LoggerHelper.cpp deleted file mode 100644 index b98436b62..000000000 --- a/src/Magpie.App/LoggerHelper.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "pch.h" -#include "LoggerHelper.h" -#if __has_include("LoggerHelper.g.cpp") -#include "LoggerHelper.g.cpp" -#endif -#include "Logger.h" - - -namespace winrt::Magpie::App::implementation { - -void LoggerHelper::Initialize(uint64_t pLogger) { - Logger::Get().Initialize(*(Logger*)pLogger); -} - -} diff --git a/src/Magpie.App/LoggerHelper.h b/src/Magpie.App/LoggerHelper.h deleted file mode 100644 index 9f782adc4..000000000 --- a/src/Magpie.App/LoggerHelper.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include "LoggerHelper.g.h" - -namespace winrt::Magpie::App::implementation { - -struct LoggerHelper : LoggerHelperT { - LoggerHelper() = default; - - static void Initialize(uint64_t pLogger); -}; - -} - -namespace winrt::Magpie::App::factory_implementation { - -struct LoggerHelper : LoggerHelperT { -}; - -} diff --git a/src/Magpie.App/LoggerHelper.idl b/src/Magpie.App/LoggerHelper.idl deleted file mode 100644 index 3023e7d73..000000000 --- a/src/Magpie.App/LoggerHelper.idl +++ /dev/null @@ -1,10 +0,0 @@ -namespace Magpie.App -{ - [default_interface] - runtimeclass LoggerHelper - { - LoggerHelper(); - - static void Initialize(UInt64 pLogger); - } -} diff --git a/src/Magpie.App/Magpie.App.vcxproj b/src/Magpie.App/Magpie.App.vcxproj index 5a2859485..f0d832daf 100644 --- a/src/Magpie.App/Magpie.App.vcxproj +++ b/src/Magpie.App/Magpie.App.vcxproj @@ -65,23 +65,6 @@ - - - - - - - - - - - - - - - LoggerHelper.idl - Code - RootPage.xaml Code @@ -90,7 +73,6 @@ App.xaml - @@ -98,19 +80,6 @@ - - - - - - - - - - - LoggerHelper.idl - Code - RootPage.xaml Code @@ -122,13 +91,9 @@ App.xaml - - - Designer - App.xaml diff --git a/src/Magpie.App/Magpie.App.vcxproj.filters b/src/Magpie.App/Magpie.App.vcxproj.filters index 8e4423ab1..9762ab821 100644 --- a/src/Magpie.App/Magpie.App.vcxproj.filters +++ b/src/Magpie.App/Magpie.App.vcxproj.filters @@ -9,95 +9,18 @@ - - Helpers - - - - Models - - - Helpers - - - Helpers - - - Helpers - - - Helpers - - - Helpers - - - Helpers - - - Helpers - - - Helpers - - - Helpers - - - - Models - - - Models - - - Helpers - - - Helpers - - - Helpers - - - Models - - - Helpers - - - Helpers - - - Helpers - - - Helpers - - - Helpers - - - {8d78810f-671d-4793-9320-65078af2d7ec} - {66be9bb7-57ad-4efd-82b1-ac88ca76677f} - - {36c62660-b63e-423f-a335-8566a408f26b} - - - Helpers - diff --git a/src/Magpie.App/NewProfileViewModel.cpp b/src/Magpie.App/NewProfileViewModel.cpp deleted file mode 100644 index 58841b54f..000000000 --- a/src/Magpie.App/NewProfileViewModel.cpp +++ /dev/null @@ -1,181 +0,0 @@ -#include "pch.h" -#include "NewProfileViewModel.h" -#if __has_include("NewProfileViewModel.g.cpp") -#include "NewProfileViewModel.g.cpp" -#endif -#include "AppSettings.h" -#include "Win32Utils.h" -#include -#include "ProfileService.h" -#include "AppXReader.h" -#include "CommonSharedConstants.h" - -namespace winrt::Magpie::App::implementation { - -static bool IsCandidateWindow(HWND hWnd) noexcept { - // 跳过不可见的窗口 - if (!IsWindowVisible(hWnd)) { - return false; - } - - // 跳过不接受点击的窗口 - if (GetWindowLongPtr(hWnd, GWL_EXSTYLE) & WS_EX_TRANSPARENT) { - return false; - } - - RECT frameRect{}; - - HRESULT hr = DwmGetWindowAttribute(hWnd, - DWMWA_EXTENDED_FRAME_BOUNDS, &frameRect, sizeof(frameRect)); - if (FAILED(hr)) { - return false; - } - - SIZE frameSize = Win32Utils::GetSizeOfRect(frameRect); - if (frameSize.cx < 50 && frameSize.cy < 50) { - return false; - } - - // 标题不能为空 - if (Win32Utils::GetWndTitle(hWnd).empty()) { - return false; - } - - // 排除后台 UWP 窗口 - // https://stackoverflow.com/questions/43927156/enumwindows-returns-closed-windows-store-applications - UINT isCloaked{}; - DwmGetWindowAttribute(hWnd, DWMWA_CLOAKED, &isCloaked, sizeof(isCloaked)); - if (isCloaked != 0) { - return false; - } - - std::wstring className = Win32Utils::GetWndClassName(hWnd); - if (className == L"Progman" || // Program Manager - className == L"Xaml_WindowedPopupClass" // 主机弹出窗口 - ) { - return false; - } - - // 检查是否和已有配置重复 - AppXReader appxReader; - if (appxReader.Initialize(hWnd)) { - return ProfileService::Get().TestNewProfile(true, appxReader.AUMID(), className); - } else { - std::wstring fileName = Win32Utils::GetPathOfWnd(hWnd); - if (fileName.empty()) { - return false; - } - - return ProfileService::Get().TestNewProfile(false, fileName, className); - } -} - -static SmallVector GetDesktopWindows() noexcept { - SmallVector windows; - - // EnumWindows 可以枚举到 UWP 窗口,官方文档已经过时。无法枚举到全屏状态下的 UWP 窗口 - EnumWindows( - [](HWND hWnd, LPARAM lParam) { - if (IsCandidateWindow(hWnd)) { - ((SmallVector*)lParam)->push_back(hWnd); - } - - return TRUE; - }, - (LPARAM)&windows - ); - - return windows; -} - -template -static void SortCandidateWindows(It begin, It end) { - const std::collate& col = std::use_facet >(std::locale()); - - // 根据用户的区域设置排序,对于中文为拼音顺序 - std::sort(begin, end, [&col](Magpie::App::CandidateWindowItem const& l, Magpie::App::CandidateWindowItem const& r) { - const hstring& titleL = l.Title(); - const hstring& titleR = r.Title(); - - // 忽略大小写,忽略半/全角 - return CompareStringEx( - LOCALE_NAME_USER_DEFAULT, - NORM_IGNORECASE | NORM_IGNOREWIDTH | NORM_LINGUISTIC_CASING, - titleL.c_str(), titleL.size(), - titleR.c_str(), titleR.size(), - nullptr, nullptr, 0 - ) == CSTR_LESS_THAN; - }); -} - -void NewProfileViewModel::PrepareForOpen(uint32_t dpi, bool isLightTheme, CoreDispatcher const& dispatcher) { - std::vector candidateWindows; - for (HWND hWnd : GetDesktopWindows()) { - candidateWindows.emplace_back((uint64_t)hWnd, dpi, isLightTheme, dispatcher); - } - - SortCandidateWindows(candidateWindows.begin(), candidateWindows.end()); - - std::vector items; - items.reserve(candidateWindows.size()); - std::copy(candidateWindows.begin(), candidateWindows.end(), std::insert_iterator(items, items.begin())); - _candidateWindows = single_threaded_vector(std::move(items)); - RaisePropertyChanged(L"CandidateWindows"); - RaisePropertyChanged(L"IsNoCandidateWindow"); - RaisePropertyChanged(L"IsAnyCandidateWindow"); - - CandidateWindowIndex(-1); - if (_candidateWindows.Size() == 1) { - _candidateWindows.GetAt(0) - .as() - .PropertyChanged([this](IInspectable const&, PropertyChangedEventArgs const& args) { - if (args.PropertyName() == L"DefaultProfileName") { - CandidateWindowIndex(0); - return; - } - }); - } - - std::vector profiles; - profiles.push_back(box_value(ResourceLoader::GetForCurrentView( - CommonSharedConstants::APP_RESOURCE_MAP_ID).GetString(L"Root_Defaults/Content"))); - for (const Profile& profile : AppSettings::Get().Profiles()) { - profiles.push_back(box_value(profile.name)); - } - - _profiles = single_threaded_vector(std::move(profiles)); - RaisePropertyChanged(L"Profiles"); - - ProfileIndex(0); -} - -void NewProfileViewModel::CandidateWindowIndex(int value) { - _candidateWindowIndex = value; - RaisePropertyChanged(L"CandidateWindowIndex"); - - if (value >= 0) { - Name(_candidateWindows.GetAt(value).as().DefaultProfileName()); - } else { - Name({}); - } -} - -void NewProfileViewModel::Name(const hstring& value) noexcept { - _name = value; - RaisePropertyChanged(L"Name"); - - _IsConfirmButtonEnabled(!value.empty() && _candidateWindowIndex >= 0); -} - -void NewProfileViewModel::Confirm() const noexcept { - if (_candidateWindowIndex < 0 || _name.empty()) { - return; - } - - CandidateWindowItem selectedItem = _candidateWindows.GetAt(_candidateWindowIndex).as(); - hstring aumid = selectedItem.AUMID(); - ProfileService::Get().AddProfile(!aumid.empty(), aumid.empty() ? selectedItem.Path() : aumid, - selectedItem.ClassName(), _name, _profileIndex - 1); -} - -} diff --git a/src/Magpie.App/NewProfileViewModel.h b/src/Magpie.App/NewProfileViewModel.h deleted file mode 100644 index 3e87bfddd..000000000 --- a/src/Magpie.App/NewProfileViewModel.h +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once -#include "NewProfileViewModel.g.h" - -namespace winrt::Magpie::App::implementation { - -struct NewProfileViewModel : NewProfileViewModelT, - wil::notify_property_changed_base { - NewProfileViewModel() = default; - - void PrepareForOpen(uint32_t dpi, bool isLightTheme, CoreDispatcher const& dispatcher); - - IVector CandidateWindows() const noexcept { - return _candidateWindows; - } - - int CandidateWindowIndex() const noexcept { - return _candidateWindowIndex; - } - - void CandidateWindowIndex(int value); - - hstring Name() const noexcept { - return _name; - } - - void Name(const hstring& value) noexcept; - - IVector Profiles() const noexcept { - return _profiles; - } - - int ProfileIndex() const noexcept { - return _profileIndex; - } - - void ProfileIndex(int value) { - _profileIndex = value; - RaisePropertyChanged(L"ProfileIndex"); - } - - bool IsConfirmButtonEnabled() const noexcept { - return _isConfirmButtonEnabled; - } - - bool IsNoCandidateWindow() const noexcept { - return !_candidateWindows || _candidateWindows.Size() == 0; - } - - bool IsAnyCandidateWindow() const noexcept { - return _candidateWindows && _candidateWindows.Size() != 0; - } - - void Confirm() const noexcept; - -private: - void _IsConfirmButtonEnabled(bool value) noexcept { - if (_isConfirmButtonEnabled == value) { - return; - } - - _isConfirmButtonEnabled = value; - RaisePropertyChanged(L"IsConfirmButtonEnabled"); - } - - IVector _candidateWindows{ nullptr }; - int _candidateWindowIndex = -1; - hstring _name; - IVector _profiles{ nullptr }; - int _profileIndex = 0; - bool _isConfirmButtonEnabled = false; -}; - -} - -namespace winrt::Magpie::App::factory_implementation { - -struct NewProfileViewModel : NewProfileViewModelT { -}; - -} diff --git a/src/Magpie.App/NewProfileViewModel.idl b/src/Magpie.App/NewProfileViewModel.idl deleted file mode 100644 index 0766aa0de..000000000 --- a/src/Magpie.App/NewProfileViewModel.idl +++ /dev/null @@ -1,18 +0,0 @@ -namespace Magpie.App { - runtimeclass NewProfileViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged { - NewProfileViewModel(); - - void PrepareForOpen(UInt32 dpi, Boolean isLightTheme, Windows.UI.Core.CoreDispatcher dispatcher); - - IVector CandidateWindows { get; }; - Int32 CandidateWindowIndex; - String Name; - IVector Profiles { get; }; - Int32 ProfileIndex; - Boolean IsConfirmButtonEnabled { get; }; - Boolean IsNoCandidateWindow { get; }; - Boolean IsAnyCandidateWindow { get; }; - - void Confirm(); - } -} diff --git a/src/Magpie.App/Profile.h b/src/Magpie.App/Profile.h deleted file mode 100644 index 9a6c71eee..000000000 --- a/src/Magpie.App/Profile.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once -#include - -namespace winrt::Magpie::App { - -enum class CursorScaling { - x0_5, - x0_75, - NoScaling, - x1_25, - x1_5, - x2, - Source, - Custom -}; - -// 默认规则 Name、PathRule、ClassNameRule 均为空 -struct Profile { - void Copy(const Profile& other) noexcept { - // 不复制自动缩放选项 - scalingMode = other.scalingMode; - cursorScaling = other.cursorScaling; - customCursorScaling = other.customCursorScaling; - isCroppingEnabled = other.isCroppingEnabled; - cropping = other.cropping; - captureMethod = other.captureMethod; - graphicsCard = other.graphicsCard; - isFrameRateLimiterEnabled = other.isFrameRateLimiterEnabled; - maxFrameRate = other.maxFrameRate; - multiMonitorUsage = other.multiMonitorUsage; - cursorInterpolationMode = other.cursorInterpolationMode; - launchParameters = other.launchParameters; - scalingFlags = other.scalingFlags; - } - - DEFINE_FLAG_ACCESSOR(IsWindowResizingDisabled, ::Magpie::Core::ScalingFlags::DisableWindowResizing, scalingFlags) - DEFINE_FLAG_ACCESSOR(Is3DGameMode, ::Magpie::Core::ScalingFlags::Is3DGameMode, scalingFlags) - DEFINE_FLAG_ACCESSOR(IsShowFPS, ::Magpie::Core::ScalingFlags::ShowFPS, scalingFlags) - DEFINE_FLAG_ACCESSOR(IsCaptureTitleBar, ::Magpie::Core::ScalingFlags::CaptureTitleBar, scalingFlags) - DEFINE_FLAG_ACCESSOR(IsAdjustCursorSpeed, ::Magpie::Core::ScalingFlags::AdjustCursorSpeed, scalingFlags) - DEFINE_FLAG_ACCESSOR(IsDrawCursor, ::Magpie::Core::ScalingFlags::DrawCursor, scalingFlags) - DEFINE_FLAG_ACCESSOR(IsDirectFlipDisabled, ::Magpie::Core::ScalingFlags::DisableDirectFlip, scalingFlags) - - std::wstring name; - - // 若为打包应用,PathRule 存储 AUMID - std::wstring pathRule; - std::wstring classNameRule; - - // 如果在同一个驱动器上则存储相对路径,否则存储绝对路径 - // 若为空使用 pathRule - std::wstring launcherPath; - - CursorScaling cursorScaling = CursorScaling::NoScaling; - float customCursorScaling = 1.0; - - ::Magpie::Core::Cropping cropping{}; - // -1 表示原样 - int scalingMode = -1; - ::Magpie::Core::CaptureMethod captureMethod = ::Magpie::Core::CaptureMethod::GraphicsCapture; - // -1 表示默认,大于等于 0 为图形适配器的索引 - int graphicsCard = -1; - ::Magpie::Core::MultiMonitorUsage multiMonitorUsage = ::Magpie::Core::MultiMonitorUsage::Closest; - ::Magpie::Core::CursorInterpolationMode cursorInterpolationMode = ::Magpie::Core::CursorInterpolationMode::NearestNeighbor; - - // 10~1000 - float maxFrameRate = 60.0f; - - std::wstring launchParameters; - - uint32_t scalingFlags = ::Magpie::Core::ScalingFlags::AdjustCursorSpeed | ::Magpie::Core::ScalingFlags::DrawCursor; - - bool isPackaged = false; - bool isCroppingEnabled = false; - bool isAutoScale = false; - bool isFrameRateLimiterEnabled = false; -}; - -} diff --git a/src/Magpie.App/ProfileViewModel.cpp b/src/Magpie.App/ProfileViewModel.cpp deleted file mode 100644 index ab6764f62..000000000 --- a/src/Magpie.App/ProfileViewModel.cpp +++ /dev/null @@ -1,885 +0,0 @@ -#include "pch.h" -#include "ProfileViewModel.h" -#if __has_include("ProfileViewModel.g.cpp") -#include "ProfileViewModel.g.cpp" -#endif -#include "Profile.h" -#include "AppXReader.h" -#include "IconHelper.h" -#include "ProfileService.h" -#include "StrUtils.h" -#include -#include "Win32Utils.h" -#include "AppSettings.h" -#include "Logger.h" -#include "ScalingMode.h" -#include -#include "ScalingService.h" -#include "FileDialogHelper.h" -#include "CommonSharedConstants.h" - -using namespace winrt; -using namespace Windows::Graphics::Display; -using namespace Windows::Graphics::Imaging; -using namespace Windows::UI::Xaml::Controls; -using namespace Windows::UI::Xaml::Media::Imaging; -using namespace ::Magpie::Core; - -namespace winrt::Magpie::App::implementation { - -static SmallVector GetAllGraphicsCards() { - com_ptr dxgiFactory; - HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)); - if (FAILED(hr)) { - return {}; - } - - SmallVector result; - - com_ptr adapter; - for (UINT adapterIndex = 0; - SUCCEEDED(dxgiFactory->EnumAdapters1(adapterIndex, adapter.put())); - ++adapterIndex - ) { - DXGI_ADAPTER_DESC1 desc; - hr = adapter->GetDesc1(&desc); - - // 不包含 WARP - if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) { - continue; - } - - result.emplace_back(SUCCEEDED(hr) ? desc.Description : L"???"); - } - - return result; -} - -ProfileViewModel::ProfileViewModel(int profileIdx) : _isDefaultProfile(profileIdx < 0) { - if (_isDefaultProfile) { - _data = &ProfileService::Get().DefaultProfile(); - } else { - _index = (uint32_t)profileIdx; - _data = &ProfileService::Get().GetProfile(profileIdx); - - // 占位 - _icon = FontIcon(); - - App app = Application::Current().as(); - RootPage rootPage = app.RootPage(); - _themeChangedRevoker = rootPage.ActualThemeChanged( - auto_revoke, - [this](FrameworkElement const& sender, IInspectable const&) { - _LoadIcon(sender); - } - ); - - _displayInformation = DisplayInformation::GetForCurrentView(); - _dpiChangedRevoker = _displayInformation.DpiChanged( - auto_revoke, - [this](DisplayInformation const&, IInspectable const&) { - if (RootPage rootPage = Application::Current().as().RootPage()) { - _LoadIcon(rootPage); - } - } - ); - - if (_data->isPackaged) { - AppXReader appxReader; - _isProgramExist = appxReader.Initialize(_data->pathRule); - } else { - _isProgramExist = Win32Utils::FileExists(_data->pathRule.c_str()); - } - - _LoadIcon(rootPage); - } - - ResourceLoader resourceLoader = - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID); - { - std::vector scalingModes; - scalingModes.push_back(box_value(resourceLoader.GetString(L"Profile_General_ScalingMode_None"))); - for (const Magpie::App::ScalingMode& sm : AppSettings::Get().ScalingModes()) { - scalingModes.push_back(box_value(sm.name)); - } - _scalingModes = single_threaded_vector(std::move(scalingModes)); - } - - { - std::vector captureMethods; - captureMethods.reserve(4); - captureMethods.push_back(box_value(L"Graphics Capture")); - if (Win32Utils::GetOSVersion().Is20H1OrNewer()) { - // Desktop Duplication 要求 Win10 20H1+ - captureMethods.push_back(box_value(L"Desktop Duplication")); - } - captureMethods.push_back(box_value(L"GDI")); - captureMethods.push_back(box_value(L"DwmSharedSurface")); - - _captureMethods = single_threaded_vector(std::move(captureMethods)); - } - - _graphicsCards = GetAllGraphicsCards(); - if (_data->graphicsCard >= _graphicsCards.size()) { - _data->graphicsCard = -1; - } -} - -ProfileViewModel::~ProfileViewModel() {} - -bool ProfileViewModel::IsNotDefaultProfile() const noexcept { - return !_data->name.empty(); -} - -bool ProfileViewModel::IsNotPackaged() const noexcept { - return !_data->isPackaged; -} - -fire_and_forget ProfileViewModel::OpenProgramLocation() const noexcept { - if (!_isProgramExist) { - co_return; - } - - std::wstring programLocation; - if (_data->isPackaged) { - AppXReader appxReader; - [[maybe_unused]] bool result = appxReader.Initialize(_data->pathRule); - assert(result); - - programLocation = appxReader.GetExecutablePath(); - if (programLocation.empty()) { - // 找不到可执行文件则打开应用文件夹 - Win32Utils::ShellOpen(appxReader.GetPackagePath().c_str()); - co_return; - } - } else { - programLocation = _data->pathRule; - } - - co_await resume_background(); - Win32Utils::OpenFolderAndSelectFile(programLocation.c_str()); -} - -static std::wstring GetStartFolderForSettingLauncher(const Profile& profile) noexcept { - if (profile.launcherPath.empty()) { - // 没有指定启动器 - size_t delimPos = profile.pathRule.find_last_of(L'\\'); - return delimPos == std::wstring::npos ? std::wstring() : profile.pathRule.substr(0, delimPos); - } - - if (!PathIsRelative(profile.launcherPath.c_str())) { - // 位于不同的驱动器上 - size_t delimPos = profile.launcherPath.find_last_of(L'\\'); - return delimPos == std::wstring::npos ? std::wstring() : profile.launcherPath.substr(0, delimPos); - } - - size_t delimPos = profile.pathRule.find_last_of(L'\\'); - if (delimPos == std::wstring::npos) { - return {}; - } - - // 相对路径转绝对路径 - wil::unique_hlocal_string combinedPath; - HRESULT hr = PathAllocCombine( - profile.pathRule.substr(0, delimPos).c_str(), - profile.launcherPath.c_str(), - PATHCCH_ALLOW_LONG_PATHS, - combinedPath.put() - ); - if (FAILED(hr)) { - Logger::Get().ComError("PathAllocCombine 失败", hr); - return {}; - } - - delimPos = std::wstring_view(combinedPath.get()).find_last_of(L'\\'); - if (delimPos == std::wstring::npos) { - return {}; - } - - return std::wstring(combinedPath.get(), delimPos); -} - -void ProfileViewModel::ChangeExeForLaunching() const noexcept { - if (!_isProgramExist || _data->isPackaged) { - return; - } - - com_ptr fileDialog = try_create_instance(CLSID_FileOpenDialog); - if (!fileDialog) { - Logger::Get().Error("创建 FileSaveDialog 失败"); - return; - } - - ResourceLoader resourceLoader = - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID); - static std::wstring titleStr(resourceLoader.GetString(L"SelectLauncherDialog_Title")); - fileDialog->SetTitle(titleStr.c_str()); - - static std::wstring exeFileStr(resourceLoader.GetString(L"FileDialog_ExeFile")); - const COMDLG_FILTERSPEC fileType{ exeFileStr.c_str(), L"*.exe"}; - fileDialog->SetFileTypes(1, &fileType); - fileDialog->SetDefaultExtension(L"exe"); - - std::wstring startFolder = GetStartFolderForSettingLauncher(*_data); - if (!startFolder.empty() && Win32Utils::DirExists(startFolder.c_str())) { - com_ptr shellItem; - SHCreateItemFromParsingName(startFolder.c_str(), nullptr, IID_PPV_ARGS(&shellItem)); - fileDialog->SetFolder(shellItem.get()); - } - - std::optional exePath = FileDialogHelper::OpenFileDialog(fileDialog.get(), FOS_STRICTFILETYPES); - if (!exePath || exePath->empty() || *exePath == _data->pathRule) { - return; - } - - if (PathIsSameRoot(exePath->c_str(), _data->pathRule.c_str())) { - // 绝对路径转相对路径 - _data->launcherPath.clear(); - _data->launcherPath.resize(MAX_PATH, 0); - PathRelativePathTo( - _data->launcherPath.data(), - _data->pathRule.c_str(), - FILE_ATTRIBUTE_NORMAL, - exePath->c_str(), - FILE_ATTRIBUTE_NORMAL - ); - _data->launcherPath.resize(StrUtils::StrLen(_data->launcherPath.c_str())); - } else { - // 位于不同的驱动器上 - _data->launcherPath = std::move(*exePath); - } - - AppSettings::Get().SaveAsync(); -} - -hstring ProfileViewModel::Name() const noexcept { - if (_data->name.empty()) { - return ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID) - .GetString(L"Root_Defaults/Content"); - } else { - return hstring(_data->name); - } -} - -static void LaunchPackagedApp(const Profile& profile) noexcept { - // 关于启动打包应用的讨论: - // https://github.com/microsoft/WindowsAppSDK/issues/2856#issuecomment-1224409948 - // 使用 CLSCTX_LOCAL_SERVER 以在独立的进程中启动应用 - // 见 https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-iapplicationactivationmanager - com_ptr aam = - try_create_instance(CLSID_ApplicationActivationManager, CLSCTX_LOCAL_SERVER); - if (!aam) { - Logger::Get().Error("创建 ApplicationActivationManager 失败"); - return; - } - - // 确保启动为前台窗口 - HRESULT hr = CoAllowSetForegroundWindow(aam.get(), nullptr); - if (FAILED(hr)) { - Logger::Get().ComError("创建 CoAllowSetForegroundWindow 失败", hr); - } - - DWORD procId; - hr = aam->ActivateApplication(profile.pathRule.c_str(), profile.launchParameters.c_str(), AO_NONE, &procId); - if (FAILED(hr)) { - Logger::Get().ComError("IApplicationActivationManager::ActivateApplication 失败", hr); - return; - } -} - -static void LaunchWin32App(const Profile& profile) noexcept { - if (profile.launcherPath.empty()) { - Win32Utils::ShellOpen(profile.pathRule.c_str(), profile.launchParameters.c_str()); - return; - } - - if (!PathIsRelative(profile.launcherPath.c_str())) { - // 位于不同的驱动器上 - if (Win32Utils::FileExists(profile.launcherPath.c_str())) { - Win32Utils::ShellOpen(profile.launcherPath.c_str(), profile.launchParameters.c_str()); - } else { - Win32Utils::ShellOpen(profile.pathRule.c_str(), profile.launchParameters.c_str()); - } - return; - } - - size_t delimPos = profile.pathRule.find_last_of(L'\\'); - if (delimPos == std::wstring::npos) { - return; - } - - // 相对路径转绝对路径 - wil::unique_hlocal_string combinedPath; - HRESULT hr = PathAllocCombine( - profile.pathRule.substr(0, delimPos).c_str(), - profile.launcherPath.c_str(), - PATHCCH_ALLOW_LONG_PATHS, - combinedPath.put() - ); - if (FAILED(hr)) { - Logger::Get().ComError("PathAllocCombine 失败", hr); - return; - } - - if (!Win32Utils::FileExists(combinedPath.get())) { - Logger::Get().ComError("可执行文件不存在", hr); - return; - } - - Win32Utils::ShellOpen(combinedPath.get(), profile.launchParameters.c_str()); -} - -void ProfileViewModel::Launch() const noexcept { - if (!_isProgramExist) { - return; - } - - if (_data->isPackaged) { - LaunchPackagedApp(*_data); - } else { - LaunchWin32App(*_data); - } -} - -void ProfileViewModel::RenameText(const hstring& value) { - _renameText = value; - RaisePropertyChanged(L"RenameText"); - - _trimedRenameText = value; - StrUtils::Trim(_trimedRenameText); - bool newEnabled = !_trimedRenameText.empty() && _trimedRenameText != _data->name; - if (_isRenameConfirmButtonEnabled != newEnabled) { - _isRenameConfirmButtonEnabled = newEnabled; - RaisePropertyChanged(L"IsRenameConfirmButtonEnabled"); - } -} - -void ProfileViewModel::Rename() { - if (_isDefaultProfile || !_isRenameConfirmButtonEnabled) { - return; - } - - ProfileService::Get().RenameProfile(_index, _trimedRenameText); - RaisePropertyChanged(L"Name"); -} - -bool ProfileViewModel::CanMoveUp() const noexcept { - return !_isDefaultProfile && _index != 0; -} - -bool ProfileViewModel::CanMoveDown() const noexcept { - return !_isDefaultProfile && _index + 1 < ProfileService::Get().GetProfileCount(); -} - -void ProfileViewModel::MoveUp() { - if (_isDefaultProfile) { - return; - } - - ProfileService& profileService = ProfileService::Get(); - if (!profileService.MoveProfile(_index, true)) { - return; - } - - --_index; - _data = &profileService.GetProfile(_index); - - RaisePropertyChanged(L"CanMoveUp"); - RaisePropertyChanged(L"CanMoveDown"); -} - -void ProfileViewModel::MoveDown() { - if (_isDefaultProfile) { - return; - } - - ProfileService& profileService = ProfileService::Get(); - if (!profileService.MoveProfile(_index, false)) { - return; - } - - ++_index; - _data = &profileService.GetProfile(_index); - - RaisePropertyChanged(L"CanMoveUp"); - RaisePropertyChanged(L"CanMoveDown"); -} - -void ProfileViewModel::Delete() { - if (_isDefaultProfile) { - return; - } - - ProfileService::Get().RemoveProfile(_index); - _data = nullptr; -} - -int ProfileViewModel::ScalingMode() const noexcept { - return _data->scalingMode + 1; -} - -void ProfileViewModel::ScalingMode(int value) { - _data->scalingMode = value - 1; - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"ScalingMode"); -} - -int ProfileViewModel::CaptureMethod() const noexcept { - if (Win32Utils::GetOSVersion().Is20H1OrNewer() || _data->captureMethod < CaptureMethod::DesktopDuplication) { - return (int)_data->captureMethod; - } else { - return (int)_data->captureMethod - 1; - } -} - -void ProfileViewModel::CaptureMethod(int value) { - if (value < 0) { - return; - } - - if (!Win32Utils::GetOSVersion().Is20H1OrNewer() && value >= (int)CaptureMethod::DesktopDuplication) { - ++value; - } - - ::Magpie::Core::CaptureMethod captureMethod = (::Magpie::Core::CaptureMethod)value; - if (_data->captureMethod == captureMethod) { - return; - } - - _data->captureMethod = captureMethod; - RaisePropertyChanged(L"CaptureMethod"); - RaisePropertyChanged(L"CanCaptureTitleBar"); - - AppSettings::Get().SaveAsync(); -} - -bool ProfileViewModel::IsAutoScale() const noexcept { - return _data->isAutoScale; -} - -void ProfileViewModel::IsAutoScale(bool value) { - if (_data->isAutoScale == value) { - return; - } - - _data->isAutoScale = value; - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"IsAutoScale"); - - if (value) { - // 立即检查前台窗口是否应自动缩放 - ScalingService::Get().CheckForeground(); - } -} - -bool ProfileViewModel::Is3DGameMode() const noexcept { - return _data->Is3DGameMode(); -} - -void ProfileViewModel::Is3DGameMode(bool value) { - if (_data->Is3DGameMode() == value) { - return; - } - - _data->Is3DGameMode(value); - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"Is3DGameMode"); -} - -bool ProfileViewModel::HasMultipleMonitors() const noexcept { - return GetSystemMetrics(SM_CMONITORS) > 1; -} - -int ProfileViewModel::MultiMonitorUsage() const noexcept { - return (int)_data->multiMonitorUsage; -} - -void ProfileViewModel::MultiMonitorUsage(int value) { - if (value < 0) { - return; - } - - ::Magpie::Core::MultiMonitorUsage multiMonitorUsage = (::Magpie::Core::MultiMonitorUsage)value; - if (_data->multiMonitorUsage == multiMonitorUsage) { - return; - } - - _data->multiMonitorUsage = multiMonitorUsage; - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"MultiMonitorUsage"); -} - -IVector ProfileViewModel::GraphicsCards() const noexcept { - std::vector graphicsCards; - graphicsCards.reserve(_graphicsCards.size() + 1); - - ResourceLoader resourceLoader = - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID); - hstring defaultStr = resourceLoader.GetString(L"Profile_General_CaptureMethod_Default"); - graphicsCards.push_back(box_value(defaultStr)); - - for (const std::wstring& graphicsCard : _graphicsCards) { - graphicsCards.push_back(box_value(graphicsCard)); - } - - return single_threaded_vector(std::move(graphicsCards)); -} - -int ProfileViewModel::GraphicsCard() const noexcept { - return _data->graphicsCard + 1; -} - -void ProfileViewModel::GraphicsCard(int value) { - if (value < 0) { - return; - } - - --value; - if (_data->graphicsCard == value) { - return; - } - - _data->graphicsCard = value; - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"GraphicsCard"); -} - -bool ProfileViewModel::IsShowGraphicsCardSettingsCard() const noexcept { - return _graphicsCards.size() > 1; -} - -bool ProfileViewModel::IsFrameRateLimiterEnabled() const noexcept { - return _data->isFrameRateLimiterEnabled; -} - -void ProfileViewModel::IsFrameRateLimiterEnabled(bool value) { - if (_data->isFrameRateLimiterEnabled == value) { - return; - } - - _data->isFrameRateLimiterEnabled = value; - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"IsFrameRateLimiterEnabled"); -} - -double ProfileViewModel::MaxFrameRate() const noexcept { - return _data->maxFrameRate; -} - -void ProfileViewModel::MaxFrameRate(double value) { - if (_data->maxFrameRate == value) { - return; - } - - // 用户已清空数字框则重置为 60 - _data->maxFrameRate = std::isnan(value) ? 60.0f : (float)value; - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"MaxFrameRate"); -} - -bool ProfileViewModel::IsShowFPS() const noexcept { - return _data->IsShowFPS(); -} - -void ProfileViewModel::IsShowFPS(bool value) { - if (_data->IsShowFPS() == value) { - return; - } - - _data->IsShowFPS(value); - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"IsShowFPS"); -} - -bool ProfileViewModel::IsWindowResizingDisabled() const noexcept { - return _data->IsWindowResizingDisabled(); -} - -void ProfileViewModel::IsWindowResizingDisabled(bool value) { - if (_data->IsWindowResizingDisabled() == value) { - return; - } - - _data->IsWindowResizingDisabled(value); - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"IsWindowResizingDisabled"); -} - -bool ProfileViewModel::IsCaptureTitleBar() const noexcept { - return _data->IsCaptureTitleBar(); -} - -void ProfileViewModel::IsCaptureTitleBar(bool value) { - if (_data->IsCaptureTitleBar() == value) { - return; - } - - _data->IsCaptureTitleBar(value); - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"IsCaptureTitleBar"); -} - -bool ProfileViewModel::CanCaptureTitleBar() const noexcept { - return _data->captureMethod == CaptureMethod::GraphicsCapture - || _data->captureMethod == CaptureMethod::DesktopDuplication; -} - -bool ProfileViewModel::IsCroppingEnabled() const noexcept { - return _data->isCroppingEnabled; -} - -void ProfileViewModel::IsCroppingEnabled(bool value) { - if (_data->isCroppingEnabled == value) { - return; - } - - _data->isCroppingEnabled = value; - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"IsCroppingEnabled"); -} - -double ProfileViewModel::CroppingLeft() const noexcept { - return _data->cropping.Left; -} - -void ProfileViewModel::CroppingLeft(double value) { - if (_data->cropping.Left == value) { - return; - } - - _data->cropping.Left = std::isnan(value) ? 0.0f : (float)value; - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"CroppingLeft"); -} - -double ProfileViewModel::CroppingTop() const noexcept { - return _data->cropping.Top; -} - -void ProfileViewModel::CroppingTop(double value) { - if (_data->cropping.Top == value) { - return; - } - - // 用户已清空数字框则重置为 0 - _data->cropping.Top = std::isnan(value) ? 0.0f : (float)value; - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"CroppingTop"); -} - -double ProfileViewModel::CroppingRight() const noexcept { - return _data->cropping.Right; -} - -void ProfileViewModel::CroppingRight(double value) { - if (_data->cropping.Right == value) { - return; - } - - _data->cropping.Right = std::isnan(value) ? 0.0f : (float)value; - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"CroppingRight"); -} - -double ProfileViewModel::CroppingBottom() const noexcept { - return _data->cropping.Bottom; -} - -void ProfileViewModel::CroppingBottom(double value) { - if (_data->cropping.Bottom == value) { - return; - } - - _data->cropping.Bottom = std::isnan(value) ? 0.0f : (float)value; - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"CroppingBottom"); -} - -bool ProfileViewModel::IsAdjustCursorSpeed() const noexcept { - return _data->IsAdjustCursorSpeed(); -} - -void ProfileViewModel::IsAdjustCursorSpeed(bool value) { - if (_data->IsAdjustCursorSpeed() == value) { - return; - } - - _data->IsAdjustCursorSpeed(value); - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"IsAdjustCursorSpeed"); -} - -bool ProfileViewModel::IsDrawCursor() const noexcept { - return _data->IsDrawCursor(); -} - -void ProfileViewModel::IsDrawCursor(bool value) { - if (_data->IsDrawCursor() == value) { - return; - } - - _data->IsDrawCursor(value); - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"IsDrawCursor"); -} - -int ProfileViewModel::CursorScaling() const noexcept { - return (int)_data->cursorScaling; -} - -void ProfileViewModel::CursorScaling(int value) { - if (value < 0) { - return; - } - - Magpie::App::CursorScaling cursorScaling = (Magpie::App::CursorScaling)value; - if (_data->cursorScaling == cursorScaling) { - return; - } - - _data->cursorScaling = cursorScaling; - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"CursorScaling"); -} - -double ProfileViewModel::CustomCursorScaling() const noexcept { - return _data->customCursorScaling; -} - -void ProfileViewModel::CustomCursorScaling(double value) { - if (_data->customCursorScaling == value) { - return; - } - - _data->customCursorScaling = std::isnan(value) ? 1.0f : (float)value; - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"CustomCursorScaling"); -} - -int ProfileViewModel::CursorInterpolationMode() const noexcept { - return (int)_data->cursorInterpolationMode; -} - -void ProfileViewModel::CursorInterpolationMode(int value) { - if (value < 0) { - return; - } - - ::Magpie::Core::CursorInterpolationMode cursorInterpolationMode = (::Magpie::Core::CursorInterpolationMode)value; - if (_data->cursorInterpolationMode == cursorInterpolationMode) { - return; - } - - _data->cursorInterpolationMode = cursorInterpolationMode; - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"CursorInterpolationMode"); -} - -hstring ProfileViewModel::LaunchParameters() const noexcept { - return hstring(_data->launchParameters); -} - -void ProfileViewModel::LaunchParameters(const hstring& value) { - std::wstring_view trimmed(value); - StrUtils::Trim(trimmed); - _data->launchParameters = trimmed; - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"LaunchParameters"); -} - -bool ProfileViewModel::IsDirectFlipDisabled() const noexcept { - return _data->IsDirectFlipDisabled(); -} - -void ProfileViewModel::IsDirectFlipDisabled(bool value) { - if (_data->IsDirectFlipDisabled() == value) { - return; - } - - _data->IsDirectFlipDisabled(value); - AppSettings::Get().SaveAsync(); - - RaisePropertyChanged(L"IsDirectFlipDisabled"); -} - -fire_and_forget ProfileViewModel::_LoadIcon(FrameworkElement const& rootPage) { - std::wstring iconPath; - SoftwareBitmap iconBitmap{ nullptr }; - - if (_isProgramExist) { - auto weakThis = get_weak(); - - const bool preferLightTheme = rootPage.ActualTheme() == ElementTheme::Light; - const bool isPackaged = _data->isPackaged; - const std::wstring path = _data->pathRule; - CoreDispatcher dispatcher = rootPage.Dispatcher(); - const uint32_t dpi = (uint32_t)std::lroundf(_displayInformation.LogicalDpi()); - - co_await resume_background(); - - static constexpr UINT ICON_SIZE = 32; - if (isPackaged) { - AppXReader appxReader; - [[maybe_unused]] bool result = appxReader.Initialize(path); - assert(result); - - std::variant uwpIcon = - appxReader.GetIcon((uint32_t)std::ceil(dpi * ICON_SIZE / double(USER_DEFAULT_SCREEN_DPI)), preferLightTheme); - if (uwpIcon.index() == 0) { - iconPath = std::get<0>(uwpIcon); - } else { - iconBitmap = std::get<1>(uwpIcon); - } - } else { - iconBitmap = IconHelper::ExtractIconFromExe(path.c_str(), ICON_SIZE, dpi); - } - - co_await dispatcher; - if (!weakThis.get()) { - co_return; - } - } - - if (!iconPath.empty()) { - BitmapIcon icon; - icon.ShowAsMonochrome(false); - icon.UriSource(Uri(iconPath)); - - _icon = std::move(icon); - } else if (iconBitmap) { - SoftwareBitmapSource imageSource; - co_await imageSource.SetBitmapAsync(iconBitmap); - - MUXC::ImageIcon imageIcon; - imageIcon.Source(imageSource); - - _icon = std::move(imageIcon); - } else { - _icon = nullptr; - } - - RaisePropertyChanged(L"Icon"); -} - -} diff --git a/src/Magpie.App/ProfileViewModel.h b/src/Magpie.App/ProfileViewModel.h deleted file mode 100644 index 84d90f36b..000000000 --- a/src/Magpie.App/ProfileViewModel.h +++ /dev/null @@ -1,176 +0,0 @@ -#pragma once -#include "ProfileViewModel.g.h" -#include "SmallVector.h" - -namespace winrt::Magpie::App { -struct Profile; -} - -namespace winrt::Magpie::App::implementation { - -struct ProfileViewModel : ProfileViewModelT, - wil::notify_property_changed_base { - ProfileViewModel(int profileIdx); - ~ProfileViewModel(); - - Controls::IconElement Icon() const noexcept { - return _icon; - } - - bool IsNotDefaultProfile() const noexcept; - - bool IsProgramExist() const noexcept { - return _isProgramExist; - } - - bool IsNotPackaged() const noexcept; - - fire_and_forget OpenProgramLocation() const noexcept; - - void ChangeExeForLaunching() const noexcept; - - hstring Name() const noexcept; - - void Launch() const noexcept; - - hstring RenameText() const noexcept { - return _renameText; - } - - void RenameText(const hstring& value); - - bool IsRenameConfirmButtonEnabled() const noexcept { - return _isRenameConfirmButtonEnabled; - } - - void Rename(); - - bool CanMoveUp() const noexcept; - - bool CanMoveDown() const noexcept; - - void MoveUp(); - - void MoveDown(); - - void Delete(); - - IVector ScalingModes() const noexcept { - return _scalingModes; - } - - int ScalingMode() const noexcept; - void ScalingMode(int value); - - IVector CaptureMethods() const noexcept { - return _captureMethods; - } - - int CaptureMethod() const noexcept; - void CaptureMethod(int value); - - bool IsAutoScale() const noexcept; - void IsAutoScale(bool value); - - bool Is3DGameMode() const noexcept; - void Is3DGameMode(bool value); - - bool HasMultipleMonitors() const noexcept; - - int MultiMonitorUsage() const noexcept; - void MultiMonitorUsage(int value); - - IVector GraphicsCards() const noexcept; - - int GraphicsCard() const noexcept; - void GraphicsCard(int value); - - bool IsShowGraphicsCardSettingsCard() const noexcept; - - bool IsFrameRateLimiterEnabled() const noexcept; - void IsFrameRateLimiterEnabled(bool value); - - double MaxFrameRate() const noexcept; - void MaxFrameRate(double value); - - bool IsShowFPS() const noexcept; - void IsShowFPS(bool value); - - bool IsWindowResizingDisabled() const noexcept; - void IsWindowResizingDisabled(bool value); - - bool IsCaptureTitleBar() const noexcept; - void IsCaptureTitleBar(bool value); - - bool CanCaptureTitleBar() const noexcept; - - bool IsCroppingEnabled() const noexcept; - void IsCroppingEnabled(bool value); - - double CroppingLeft() const noexcept; - void CroppingLeft(double value); - - double CroppingTop() const noexcept; - void CroppingTop(double value); - - double CroppingRight() const noexcept; - void CroppingRight(double value); - - double CroppingBottom() const noexcept; - void CroppingBottom(double value); - - bool IsAdjustCursorSpeed() const noexcept; - void IsAdjustCursorSpeed(bool value); - - bool IsDrawCursor() const noexcept; - void IsDrawCursor(bool value); - - int CursorScaling() const noexcept; - void CursorScaling(int value); - - double CustomCursorScaling() const noexcept; - void CustomCursorScaling(double value); - - int CursorInterpolationMode() const noexcept; - void CursorInterpolationMode(int value); - - hstring LaunchParameters() const noexcept; - void LaunchParameters(const hstring& value); - - bool IsDirectFlipDisabled() const noexcept; - void IsDirectFlipDisabled(bool value); - -private: - fire_and_forget _LoadIcon(FrameworkElement const& rootPage); - - bool _isProgramExist = true; - - hstring _renameText; - std::wstring_view _trimedRenameText; - - IVector _scalingModes{ nullptr }; - IVector _captureMethods{ nullptr }; - SmallVector _graphicsCards; - - uint32_t _index = 0; - // 可以保存此指针的原因是: 用户停留在此页面时不会有缩放配置被创建或删除 - Profile* _data = nullptr; - - RootPage::ActualThemeChanged_revoker _themeChangedRevoker; - Windows::Graphics::Display::DisplayInformation _displayInformation{ nullptr }; - Windows::Graphics::Display::DisplayInformation::DpiChanged_revoker _dpiChangedRevoker; - - Controls::IconElement _icon{ nullptr }; - - const bool _isDefaultProfile = true; - bool _isRenameConfirmButtonEnabled = false; -}; - -} - -namespace winrt::Magpie::App::factory_implementation { - -struct ProfileViewModel : ProfileViewModelT { -}; - -} diff --git a/src/Magpie.App/ProfileViewModel.idl b/src/Magpie.App/ProfileViewModel.idl deleted file mode 100644 index 5b2cf578b..000000000 --- a/src/Magpie.App/ProfileViewModel.idl +++ /dev/null @@ -1,67 +0,0 @@ -namespace Magpie.App { - runtimeclass ProfileViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged { - ProfileViewModel(Int32 profileIdx); - - Windows.UI.Xaml.Controls.IconElement Icon { get; }; - String Name { get; }; - Boolean IsNotDefaultProfile { get; }; - - void Launch(); - - Boolean IsProgramExist { get; }; - Boolean IsNotPackaged { get; }; - - void OpenProgramLocation(); - void ChangeExeForLaunching(); - - String RenameText; - Boolean IsRenameConfirmButtonEnabled { get; }; - void Rename(); - - Boolean CanMoveUp { get; }; - Boolean CanMoveDown { get; }; - void MoveUp(); - void MoveDown(); - - void Delete(); - - IVector ScalingModes { get; }; - Int32 ScalingMode; - - IVector CaptureMethods { get; }; - Int32 CaptureMethod; - - Boolean IsAutoScale; - Boolean Is3DGameMode; - - Boolean HasMultipleMonitors { get; }; - Int32 MultiMonitorUsage; - - IVector GraphicsCards { get; }; - Int32 GraphicsCard; - Boolean IsShowGraphicsCardSettingsCard { get; }; - - Boolean IsShowFPS; - Boolean IsFrameRateLimiterEnabled; - Double MaxFrameRate; - - Boolean IsWindowResizingDisabled; - Boolean IsCaptureTitleBar; - Boolean CanCaptureTitleBar { get; }; - - Boolean IsCroppingEnabled; - Double CroppingLeft; - Double CroppingTop; - Double CroppingRight; - Double CroppingBottom; - - Boolean IsAdjustCursorSpeed; - Boolean IsDrawCursor; - Int32 CursorScaling; - Double CustomCursorScaling; - Int32 CursorInterpolationMode; - - String LaunchParameters; - Boolean IsDirectFlipDisabled; - } -} diff --git a/src/Magpie.App/RootPage.cpp b/src/Magpie.App/RootPage.cpp index 555eaf5a9..ad4c4d133 100644 --- a/src/Magpie.App/RootPage.cpp +++ b/src/Magpie.App/RootPage.cpp @@ -8,12 +8,7 @@ #include "Logger.h" #include "StrUtils.h" #include "Win32Utils.h" -#include "AppSettings.h" -#include "AppXReader.h" -#include "IconHelper.h" -#include "ComboBoxHelper.h" #include "CommonSharedConstants.h" -#include "ContentDialogHelper.h" using namespace winrt; using namespace Windows::Graphics::Display; diff --git a/src/Magpie.App/ScalingMode.h b/src/Magpie.App/ScalingMode.h deleted file mode 100644 index 7e532dcf2..000000000 --- a/src/Magpie.App/ScalingMode.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include - -namespace winrt::Magpie::App { - -struct ScalingMode { - std::wstring name; - std::vector<::Magpie::Core::EffectOption> effects; -}; - -} diff --git a/src/Magpie.App/ScalingModeEffectItem.cpp b/src/Magpie.App/ScalingModeEffectItem.cpp deleted file mode 100644 index d2e1f271c..000000000 --- a/src/Magpie.App/ScalingModeEffectItem.cpp +++ /dev/null @@ -1,270 +0,0 @@ -#include "pch.h" -#include "ScalingModeEffectItem.h" -#if __has_include("ScalingModeEffectItem.g.cpp") -#include "ScalingModeEffectItem.g.cpp" -#endif -#include -#include "ScalingModesService.h" -#include "EffectsService.h" -#include "EffectHelper.h" -#include "AppSettings.h" -#include "Logger.h" -#include "ScalingMode.h" -#include "StrUtils.h" -#include "CommonSharedConstants.h" - -using namespace ::Magpie::Core; -namespace MagpieCore = ::Magpie::Core; - -namespace winrt::Magpie::App::implementation { - -ScalingModeEffectItem::ScalingModeEffectItem(uint32_t scalingModeIdx, uint32_t effectIdx) - : _scalingModeIdx(scalingModeIdx), _effectIdx(effectIdx) -{ - EffectOption& data = _Data(); - - _effectInfo = EffectsService::Get().GetEffect(data.name); - - if (_effectInfo) { - _name = EffectHelper::GetDisplayName(data.name); - _parametersViewModel = EffectParametersViewModel(scalingModeIdx, effectIdx); - } else { - ResourceLoader resourceLoader = - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID); - _name = StrUtils::Concat( - resourceLoader.GetString(L"ScalingModes_Description_UnknownEffect"), - L" (", - data.name, - L")" - ); - } -} - -void ScalingModeEffectItem::ScalingModeIdx(uint32_t value) noexcept { - _scalingModeIdx = value; - - if (_parametersViewModel) { - _parametersViewModel.ScalingModeIdx(value); - } -} - -void ScalingModeEffectItem::EffectIdx(uint32_t value) noexcept { - _effectIdx = value; - - if (_parametersViewModel) { - _parametersViewModel.EffectIdx(value); - } -} - -bool ScalingModeEffectItem::CanScale() const noexcept { - return _effectInfo && _effectInfo->CanScale(); -} - -bool ScalingModeEffectItem::HasParameters() const noexcept { - return _effectInfo && !_effectInfo->params.empty(); -} - -IVector ScalingModeEffectItem::ScalingTypes() noexcept { - using Windows::ApplicationModel::Resources::ResourceLoader; - ResourceLoader resourceLoader = - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID); - - return single_threaded_vector(std::vector{ - Magpie::App::ScalingType( - resourceLoader.GetString(L"ScalingModes_ScaleFlyout_Type_Factor"), - resourceLoader.GetString(L"ScalingModes_ScaleFlyout_Type_Factor_Description") - ), - Magpie::App::ScalingType( - resourceLoader.GetString(L"ScalingModes_ScaleFlyout_Type_Fit"), - resourceLoader.GetString(L"ScalingModes_ScaleFlyout_Type_Fit_Description") - ), - Magpie::App::ScalingType( - resourceLoader.GetString(L"ScalingModes_ScaleFlyout_Type_Absolute"), - resourceLoader.GetString(L"ScalingModes_ScaleFlyout_Type_Absolute_Description") - ), - Magpie::App::ScalingType( - resourceLoader.GetString(L"ScalingModes_ScaleFlyout_Type_Fill"), - resourceLoader.GetString(L"ScalingModes_ScaleFlyout_Type_Fill_Description") - ), - }); -} - -int ScalingModeEffectItem::ScalingType() const noexcept { - return (int)_Data().scalingType; -} - -static SIZE GetMonitorSize() noexcept { - // 使用距离主窗口最近的显示器 - HWND hwndMain = (HWND)Application::Current().as().HwndMain(); - HMONITOR hMonitor = MonitorFromWindow(hwndMain, MONITOR_DEFAULTTONEAREST); - if (!hMonitor) { - Logger::Get().Win32Error("MonitorFromWindow 失败"); - return { 400,300 }; - } - - MONITORINFO mi{ .cbSize = sizeof(mi) }; - if (!GetMonitorInfo(hMonitor, &mi)) { - Logger::Get().Win32Error("GetMonitorInfo 失败"); - return { 400,300 }; - } - - return { - mi.rcMonitor.right - mi.rcMonitor.left, - mi.rcMonitor.bottom - mi.rcMonitor.top - }; -} - -void ScalingModeEffectItem::ScalingType(int value) { - if (value < 0) { - return; - } - - EffectOption& data = _Data(); - const MagpieCore::ScalingType scalingType = (MagpieCore::ScalingType)value; - if (data.scalingType == scalingType) { - return; - } - - if (data.scalingType == MagpieCore::ScalingType::Absolute) { - data.scale = { 1.0f,1.0f }; - RaisePropertyChanged(L"ScalingFactorX"); - RaisePropertyChanged(L"ScalingFactorY"); - } else if (scalingType == MagpieCore::ScalingType::Absolute) { - SIZE monitorSize = GetMonitorSize(); - data.scale = { (float)monitorSize.cx,(float)monitorSize.cy }; - - RaisePropertyChanged(L"ScalingPixelsX"); - RaisePropertyChanged(L"ScalingPixelsY"); - } - - data.scalingType = scalingType; - RaisePropertyChanged(L"ScalingType"); - RaisePropertyChanged(L"IsShowScalingFactors"); - RaisePropertyChanged(L"IsShowScalingPixels"); - - AppSettings::Get().SaveAsync(); -} - -bool ScalingModeEffectItem::IsShowScalingFactors() const noexcept { - MagpieCore::ScalingType scalingType = _Data().scalingType; - return scalingType == MagpieCore::ScalingType::Normal || scalingType == MagpieCore::ScalingType::Fit; -} - -bool ScalingModeEffectItem::IsShowScalingPixels() const noexcept { - return _Data().scalingType == MagpieCore::ScalingType::Absolute; -} - -double ScalingModeEffectItem::ScalingFactorX() const noexcept { - return _Data().scale.first; -} - -void ScalingModeEffectItem::ScalingFactorX(double value) { - EffectOption& data = _Data(); - if (data.scalingType != MagpieCore::ScalingType::Normal && data.scalingType != MagpieCore::ScalingType::Fit) { - return; - } - - // 用户将 NumberBox 清空时会传入 nan - if (!std::isnan(value) && value + std::numeric_limits::epsilon() > 1e-4) { - data.scale.first = (float)value; - } - - RaisePropertyChanged(L"ScalingFactorX"); - AppSettings::Get().SaveAsync(); -} - -double ScalingModeEffectItem::ScalingFactorY() const noexcept { - return _Data().scale.second; -} - -void ScalingModeEffectItem::ScalingFactorY(double value) { - EffectOption& data = _Data(); - if (data.scalingType != MagpieCore::ScalingType::Normal && data.scalingType != MagpieCore::ScalingType::Fit) { - return; - } - - if (!std::isnan(value) && value + std::numeric_limits::epsilon() > 1e-4) { - data.scale.second = (float)value; - } - - RaisePropertyChanged(L"ScalingFactorY"); - AppSettings::Get().SaveAsync(); -} - -double ScalingModeEffectItem::ScalingPixelsX() const noexcept { - return _Data().scale.first; -} - -void ScalingModeEffectItem::ScalingPixelsX(double value) { - EffectOption& data = _Data(); - if (data.scalingType != MagpieCore::ScalingType::Absolute) { - return; - } - - if (!std::isnan(value) && value > 0.5) { - data.scale.first = (float)std::round(value); - } - - RaisePropertyChanged(L"ScalingPixelsX"); - AppSettings::Get().SaveAsync(); -} - -double ScalingModeEffectItem::ScalingPixelsY() const noexcept { - return _Data().scale.second; -} - -void ScalingModeEffectItem::ScalingPixelsY(double value) { - EffectOption& data = _Data(); - if (data.scalingType != MagpieCore::ScalingType::Absolute) { - return; - } - - if (!std::isnan(value) && value > 0.5) { - data.scale.second = (float)std::round(value); - } - - RaisePropertyChanged(L"ScalingPixelsY"); - AppSettings::Get().SaveAsync(); -} - -void ScalingModeEffectItem::Remove() { - Removed.invoke(*this, _effectIdx); -} - -bool ScalingModeEffectItem::CanMove() const noexcept { - const ScalingMode& mode = ScalingModesService::Get().GetScalingMode(_scalingModeIdx); - return mode.effects.size() > 1 && Win32Utils::IsProcessElevated(); -} - -bool ScalingModeEffectItem::CanMoveUp() const noexcept { - return _effectIdx > 0; -} - -bool ScalingModeEffectItem::CanMoveDown() const noexcept { - const ScalingMode& mode = ScalingModesService::Get().GetScalingMode(_scalingModeIdx); - return _effectIdx + 1 < (uint32_t)mode.effects.size(); -} - -void ScalingModeEffectItem::MoveUp() noexcept { - Moved.invoke(*this, true); -} - -void ScalingModeEffectItem::MoveDown() noexcept { - Moved.invoke(*this, false); -} - -void ScalingModeEffectItem::RefreshMoveState() { - RaisePropertyChanged(L"CanMove"); - RaisePropertyChanged(L"CanMoveUp"); - RaisePropertyChanged(L"CanMoveDown"); -} - -EffectOption& ScalingModeEffectItem::_Data() noexcept { - return ScalingModesService::Get().GetScalingMode(_scalingModeIdx).effects[_effectIdx]; -} - -const EffectOption& ScalingModeEffectItem::_Data() const noexcept { - return ScalingModesService::Get().GetScalingMode(_scalingModeIdx).effects[_effectIdx]; -} - -} diff --git a/src/Magpie.App/ScalingModeEffectItem.h b/src/Magpie.App/ScalingModeEffectItem.h deleted file mode 100644 index 2c5ec89da..000000000 --- a/src/Magpie.App/ScalingModeEffectItem.h +++ /dev/null @@ -1,95 +0,0 @@ -#pragma once -#include "ScalingModeEffectItem.g.h" - -namespace Magpie::Core { -struct EffectOption; -} - -namespace winrt::Magpie::App { -struct EffectInfo; -} - -namespace winrt::Magpie::App::implementation { - -struct ScalingModeEffectItem : ScalingModeEffectItemT, - wil::notify_property_changed_base { - ScalingModeEffectItem(uint32_t scalingModeIdx, uint32_t effectIdx); - - hstring Name() const noexcept { - return _name; - } - - uint32_t ScalingModeIdx() const noexcept { - return _scalingModeIdx; - } - - void ScalingModeIdx(uint32_t value) noexcept; - - uint32_t EffectIdx() const noexcept { - return _effectIdx; - } - - void EffectIdx(uint32_t value) noexcept; - - bool CanScale() const noexcept; - - bool HasParameters() const noexcept; - - IVector ScalingTypes() noexcept; - - int ScalingType() const noexcept; - void ScalingType(int value); - - bool IsShowScalingFactors() const noexcept; - bool IsShowScalingPixels() const noexcept; - - double ScalingFactorX() const noexcept; - void ScalingFactorX(double value); - - double ScalingFactorY() const noexcept; - void ScalingFactorY(double value); - - double ScalingPixelsX() const noexcept; - void ScalingPixelsX(double value); - - double ScalingPixelsY() const noexcept; - void ScalingPixelsY(double value); - - Magpie::App::EffectParametersViewModel Parameters() const noexcept { - return _parametersViewModel; - } - - void Remove(); - - bool CanMove() const noexcept; - bool CanMoveUp() const noexcept; - bool CanMoveDown() const noexcept; - void MoveUp() noexcept; - void MoveDown() noexcept; - - void RefreshMoveState(); - - // 上移为 true,下移为 false - wil::typed_event Moved; - wil::untyped_event Removed; - -private: - ::Magpie::Core::EffectOption& _Data() noexcept; - const ::Magpie::Core::EffectOption& _Data() const noexcept; - - uint32_t _scalingModeIdx = 0; - uint32_t _effectIdx = 0; - hstring _name; - const EffectInfo* _effectInfo = nullptr; - - Magpie::App::EffectParametersViewModel _parametersViewModel{ nullptr }; -}; - -} - -namespace winrt::Magpie::App::factory_implementation { - -struct ScalingModeEffectItem : ScalingModeEffectItemT { -}; - -} diff --git a/src/Magpie.App/ScalingModeEffectItem.idl b/src/Magpie.App/ScalingModeEffectItem.idl deleted file mode 100644 index 9be952700..000000000 --- a/src/Magpie.App/ScalingModeEffectItem.idl +++ /dev/null @@ -1,35 +0,0 @@ -namespace Magpie.App { - runtimeclass ScalingModeEffectItem : Windows.UI.Xaml.Data.INotifyPropertyChanged { - ScalingModeEffectItem(UInt32 scalingModeIdx, UInt32 effectIdx); - - UInt32 ScalingModeIdx; - UInt32 EffectIdx; - String Name { get; }; - - Boolean CanScale { get; }; - Boolean HasParameters { get; }; - - IVector ScalingTypes { get; }; - Int32 ScalingType; - Boolean IsShowScalingFactors { get; }; - Boolean IsShowScalingPixels { get; }; - Double ScalingFactorX; - Double ScalingFactorY; - Double ScalingPixelsX; - Double ScalingPixelsY; - - EffectParametersViewModel Parameters { get; }; - - void Remove(); - event Windows.Foundation.EventHandler Removed; - - Boolean CanMove { get; }; - Boolean CanMoveUp { get; }; - Boolean CanMoveDown { get; }; - void MoveUp(); - void MoveDown(); - event Windows.Foundation.TypedEventHandler Moved; - - void RefreshMoveState(); - } -} diff --git a/src/Magpie.App/ScalingModeItem.cpp b/src/Magpie.App/ScalingModeItem.cpp deleted file mode 100644 index dfd4f984c..000000000 --- a/src/Magpie.App/ScalingModeItem.cpp +++ /dev/null @@ -1,329 +0,0 @@ -#include "pch.h" -#include "ScalingModeItem.h" -#if __has_include("ScalingModeItem.g.cpp") -#include "ScalingModeItem.g.cpp" -#endif -#include "ScalingMode.h" -#include "StrUtils.h" -#include "XamlUtils.h" -#include "AppSettings.h" -#include "EffectsService.h" -#include "EffectHelper.h" -#include "CommonSharedConstants.h" - -using namespace Magpie::Core; - -namespace winrt::Magpie::App::implementation { - -ScalingModeItem::ScalingModeItem(uint32_t index, bool isInitialExpanded) - : _index(index), _isInitialExpanded(isInitialExpanded) -{ - { - std::vector linkedProfiles; - const Profile& defaultProfile = AppSettings::Get().DefaultProfile(); - if (defaultProfile.scalingMode == (int)index) { - hstring defaults = ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID) - .GetString(L"Root_Defaults/Content"); - linkedProfiles.push_back(box_value(defaults)); - } - for (const Profile& profile : AppSettings::Get().Profiles()) { - if (profile.scalingMode == (int)index) { - linkedProfiles.push_back(box_value(profile.name)); - } - } - _linkedProfiles = single_threaded_vector(std::move(linkedProfiles)); - } - - _scalingModeAddedRevoker = ScalingModesService::Get().ScalingModeAdded( - auto_revoke, { this, &ScalingModeItem::_ScalingModesService_Added }); - _scalingModeMovedRevoker = ScalingModesService::Get().ScalingModeMoved( - auto_revoke, { this, &ScalingModeItem::_ScalingModesService_Moved }); - _scalingModeRemovedRevoker = ScalingModesService::Get().ScalingModeRemoved( - auto_revoke, { this, &ScalingModeItem::_ScalingModesService_Removed }); - - ScalingMode& data = _Data(); - { - std::vector effects; - effects.reserve(data.effects.size()); - for (uint32_t i = 0; i < data.effects.size(); ++i) { - effects.push_back(_CreateScalingModeEffectItem(_index, i)); - } - _effects = single_threaded_observable_vector(std::move(effects)); - } - _effects.VectorChanged({ this, &ScalingModeItem::_Effects_VectorChanged }); -} - -void ScalingModeItem::_Index(uint32_t value) noexcept { - _index = value; - for (const IInspectable& item : _effects) { - item.as().ScalingModeIdx(value); - } - RaisePropertyChanged(L"CanMoveUp"); - RaisePropertyChanged(L"CanMoveDown"); -} - -void ScalingModeItem::_ScalingModesService_Added(EffectAddedWay) { - if (_index + 2 == ScalingModesService::Get().GetScalingModeCount()) { - RaisePropertyChanged(L"CanMoveDown"); - } -} - -void ScalingModeItem::_ScalingModesService_Moved(uint32_t index, bool isMoveUp) { - uint32_t targetIndex = isMoveUp ? index - 1 : index + 1; - if (_index == index) { - _Index(targetIndex); - } else if (_index == targetIndex) { - _Index(index); - } -} - -void ScalingModeItem::_ScalingModesService_Removed(uint32_t index) { - if (_index > index) { - _Index(_index - 1); - } else { - RaisePropertyChanged(L"CanMoveUp"); - RaisePropertyChanged(L"CanMoveDown"); - } -} - -void ScalingModeItem::_Effects_VectorChanged(IObservableVector const&, IVectorChangedEventArgs const& args) { - if (!_isMovingEffects) { - RaisePropertyChanged(L"Description"); - RaisePropertyChanged(L"CanReorderEffects"); - RaisePropertyChanged(L"IsShowMoveButtons"); - return; - } - - // 移动元素时先删除再插入 - if (args.CollectionChange() == CollectionChange::ItemRemoved) { - _movingFromIdx = args.Index(); - return; - } - - assert(args.CollectionChange() == CollectionChange::ItemInserted); - uint32_t movingToIdx = args.Index(); - - std::vector& effects = _Data().effects; - EffectOption removedEffect = std::move(effects[_movingFromIdx]); - effects.erase(effects.begin() + _movingFromIdx); - effects.emplace(effects.begin() + movingToIdx, std::move(removedEffect)); - - uint32_t minIdx, maxIdx; - if (_movingFromIdx < movingToIdx) { - minIdx = _movingFromIdx; - maxIdx = movingToIdx; - } else { - minIdx = movingToIdx; - maxIdx = _movingFromIdx; - } - - for (uint32_t i = minIdx; i <= maxIdx; ++i) { - _effects.GetAt(i).as().EffectIdx(i); - } - - RaisePropertyChanged(L"Description"); - AppSettings::Get().SaveAsync(); -} - -void ScalingModeItem::_ScalingModeEffectItem_Removed(IInspectable const&, uint32_t index) { - std::vector& effects = _Data().effects; - effects.erase(effects.begin() + index); - - _isMovingEffects = false; - _effects.RemoveAt(index); - _isMovingEffects = true; - - for (uint32_t i = index; i < effects.size(); ++i) { - _effects.GetAt(i).as().EffectIdx(i); - } - - if (index > 0) { - _effects.GetAt(index - 1).as().RefreshMoveState(); - } - if (index < _effects.Size()) { - _effects.GetAt(index).as().RefreshMoveState(); - } - - RaisePropertyChanged(L"HasUnkownEffects"); - - AppSettings::Get().SaveAsync(); -} - -void ScalingModeItem::_ScalingModeEffectItem_Moved(ScalingModeEffectItem const& sender, bool isUp) { - uint32_t idx = sender.EffectIdx(); - - if (isUp) { - assert(idx > 0); - IInspectable prev = _effects.GetAt(idx - 1); - // 状态更新由 _Effects_VectorChanged 处理 - _effects.RemoveAt(idx - 1); - _effects.InsertAt(idx, prev); - - prev.as().RefreshMoveState(); - } else { - assert(idx + 1 < _effects.Size()); - IInspectable next = _effects.GetAt(idx + 1); - _effects.RemoveAt(idx + 1); - _effects.InsertAt(idx, next); - - next.as().RefreshMoveState(); - } - sender.RefreshMoveState(); -} - -ScalingModeEffectItem ScalingModeItem::_CreateScalingModeEffectItem(uint32_t scalingModeIdx, uint32_t effectIdx) { - ScalingModeEffectItem item(scalingModeIdx, effectIdx); - item.Removed({ this, &ScalingModeItem::_ScalingModeEffectItem_Removed }); - item.Moved({ this, &ScalingModeItem::_ScalingModeEffectItem_Moved }); - return item; -} - -void ScalingModeItem::AddEffect(const hstring& fullName) { - EffectOption& effect = _Data().effects.emplace_back(); - effect.name = fullName; - - const EffectInfo* effectInfo = EffectsService::Get().GetEffect(fullName); - assert(effectInfo); - if (effectInfo->CanScale()) { - // 支持缩放的效果默认等比缩放到充满屏幕 - effect.scalingType = ::Magpie::Core::ScalingType::Fit; - } - - ScalingModeEffectItem item = _CreateScalingModeEffectItem(_index, (uint32_t)_Data().effects.size() - 1); - _isMovingEffects = false; - _effects.Append(item); - _isMovingEffects = true; - - uint32_t size = _effects.Size(); - _effects.GetAt(size - 1).as().RefreshMoveState(); - if (size > 1) { - _effects.GetAt(size - 2).as().RefreshMoveState(); - } - - AppSettings::Get().SaveAsync(); -} - -hstring ScalingModeItem::Name() const noexcept { - if (_index == std::numeric_limits::max()) { - // 特殊情况下被删除后依然可能被获取 Name 和 Description,可能是 ListView 的 bug - return {}; - } - - return hstring(_Data().name); -} - -void ScalingModeItem::Name(const hstring& value) noexcept { - _Data().name = value; - AppSettings::Get().SaveAsync(); -} - -hstring ScalingModeItem::Description() const noexcept { - if (_index == std::numeric_limits::max()) { - return {}; - } - - std::wstring result; - for (const EffectOption& effect : _Data().effects) { - if (!result.empty()) { - result.append(L" > "); - } - - if (const EffectInfo* effectInfo = EffectsService::Get().GetEffect(effect.name)) { - result += EffectHelper::GetDisplayName(effect.name); - } else { - ResourceLoader resourceLoader = - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID); - result += L'('; - result += resourceLoader.GetString(L"ScalingModes_Description_UnknownEffect"); - result += L')'; - } - } - return hstring(result); -} - -bool ScalingModeItem::HasUnkownEffects() const noexcept { - for (const EffectOption& effect : _Data().effects) { - if (!EffectsService::Get().GetEffect(effect.name)) { - return true; - } - } - return false; -} - -void ScalingModeItem::RenameText(const hstring& value) noexcept { - _renameText = value; - RaisePropertyChanged(L"RenameText"); - - _trimedRenameText = value; - StrUtils::Trim(_trimedRenameText); - bool newEnabled = !_trimedRenameText.empty() && _trimedRenameText != _Data().name; - if (_isRenameButtonEnabled != newEnabled) { - _isRenameButtonEnabled = newEnabled; - RaisePropertyChanged(L"IsRenameButtonEnabled"); - } -} - -void ScalingModeItem::RenameFlyout_Opening() { - RenameText(hstring(_Data().name)); - RaisePropertyChanged(L"RenameTextBoxSelectionStart"); -} - -void ScalingModeItem::RenameTextBox_KeyDown(IInspectable const&, Input::KeyRoutedEventArgs const& args) { - if (args.Key() == VirtualKey::Enter) { - RenameButton_Click(); - } -} - -void ScalingModeItem::RenameButton_Click() { - if (!_isRenameButtonEnabled) { - return; - } - - // Flyout 没有 IsOpen 可供绑定,只能用变通方法关闭 - XamlUtils::ClosePopups(Application::Current().as().RootPage().XamlRoot()); - - _Data().name = _trimedRenameText; - RaisePropertyChanged(L"Name"); - - AppSettings::Get().SaveAsync(); -} - -bool ScalingModeItem::CanMoveUp() const noexcept { - return _index != 0; -} - -bool ScalingModeItem::CanMoveDown() const noexcept { - return _index + 1 < ScalingModesService::Get().GetScalingModeCount(); -} - -void ScalingModeItem::MoveUp() noexcept { - ScalingModesService::Get().MoveScalingMode(_index, true); -} - -void ScalingModeItem::MoveDown() noexcept { - ScalingModesService::Get().MoveScalingMode(_index, false); -} - -bool ScalingModeItem::CanReorderEffects() const noexcept { - // 管理员身份下不支持拖拽排序 - return _effects.Size() > 1 && !Win32Utils::IsProcessElevated(); -} - -bool ScalingModeItem::IsShowMoveButtons() const noexcept { - return _effects.Size() > 1 && Win32Utils::IsProcessElevated(); -} - -void ScalingModeItem::Remove() { - ScalingModesService::Get().RemoveScalingMode(_index); - _index = std::numeric_limits::max(); -} - -ScalingMode& ScalingModeItem::_Data() noexcept { - return ScalingModesService::Get().GetScalingMode(_index); -} - -const ScalingMode& ScalingModeItem::_Data() const noexcept { - return ScalingModesService::Get().GetScalingMode(_index); -} - -} diff --git a/src/Magpie.App/ScalingModeItem.h b/src/Magpie.App/ScalingModeItem.h deleted file mode 100644 index a773c9e13..000000000 --- a/src/Magpie.App/ScalingModeItem.h +++ /dev/null @@ -1,122 +0,0 @@ -#pragma once -#include "ScalingModeItem.g.h" -#include "WinRTUtils.h" -#include "ScalingModesService.h" - -namespace winrt::Magpie::App { -struct ScalingMode; -} - -namespace winrt::Magpie::App::implementation { - -struct ScalingModeItem : ScalingModeItemT, - wil::notify_property_changed_base { - ScalingModeItem(uint32_t index, bool isInitialExpanded); - - void AddEffect(const hstring& fullName); - - bool IsInitialExpanded() const noexcept { - return _isInitialExpanded; - } - - hstring Name() const noexcept; - - void Name(const hstring& value) noexcept; - - hstring Description() const noexcept; - - bool HasUnkownEffects() const noexcept; - - IObservableVector Effects() const noexcept { - return _effects; - } - - hstring RenameText() const noexcept { - return _renameText; - } - - void RenameText(const hstring& value) noexcept; - - bool IsRenameButtonEnabled() const noexcept { - return _isRenameButtonEnabled; - } - - void RenameFlyout_Opening(); - - void RenameTextBox_KeyDown(IInspectable const&, Input::KeyRoutedEventArgs const& args); - - int RenameTextBoxSelectionStart() { - return _renameText.size(); - } - - void RenameButton_Click(); - - bool CanMoveUp() const noexcept; - - bool CanMoveDown() const noexcept; - - void MoveUp() noexcept; - - void MoveDown() noexcept; - - bool CanReorderEffects() const noexcept; - - bool IsShowMoveButtons() const noexcept; - - void Remove(); - - IVector LinkedProfiles() const noexcept { - return _linkedProfiles; - } - - bool IsInUse() const noexcept { - return _linkedProfiles.Size() > 0; - } - -private: - void _Index(uint32_t value) noexcept; - - void _ScalingModesService_Added(EffectAddedWay); - - void _ScalingModesService_Moved(uint32_t index, bool isMoveUp); - - void _ScalingModesService_Removed(uint32_t index); - - void _Effects_VectorChanged(IObservableVector const&, IVectorChangedEventArgs const& args); - - void _ScalingModeEffectItem_Removed(IInspectable const&, uint32_t index); - - void _ScalingModeEffectItem_Moved(ScalingModeEffectItem const& sender, bool isUp); - - ScalingModeEffectItem _CreateScalingModeEffectItem(uint32_t scalingModeIdx, uint32_t effectIdx); - - ScalingMode& _Data() noexcept; - const ScalingMode& _Data() const noexcept; - - uint32_t _index = 0; - IObservableVector _effects{ nullptr }; - - uint32_t _movingFromIdx = 0; - - WinRTUtils::EventRevoker _scalingModeAddedRevoker; - WinRTUtils::EventRevoker _scalingModeMovedRevoker; - WinRTUtils::EventRevoker _scalingModeRemovedRevoker; - - hstring _renameText; - std::wstring_view _trimedRenameText; - - IVector _linkedProfiles{ nullptr }; - - bool _isMovingEffects = true; - bool _isRenameButtonEnabled = false; - bool _isInitialExpanded = false; -}; - -} - -namespace winrt::Magpie::App::factory_implementation { - -struct ScalingModeItem : ScalingModeItemT { -}; - -} diff --git a/src/Magpie.App/ScalingModeItem.idl b/src/Magpie.App/ScalingModeItem.idl deleted file mode 100644 index aa992b1c3..000000000 --- a/src/Magpie.App/ScalingModeItem.idl +++ /dev/null @@ -1,34 +0,0 @@ -namespace Magpie.App { - runtimeclass ScalingModeItem : Windows.UI.Xaml.Data.INotifyPropertyChanged { - ScalingModeItem(UInt32 index, Boolean isInitialExpanded); - - void AddEffect(String fullName); - void RenameFlyout_Opening(); - void RenameTextBox_KeyDown(Object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs args); - void RenameButton_Click(); - - Boolean IsInitialExpanded { get; }; - - String Name; - String Description { get; }; - - Boolean HasUnkownEffects { get; }; - IObservableVector Effects { get; }; - - String RenameText; - Int32 RenameTextBoxSelectionStart { get; }; - Boolean IsRenameButtonEnabled { get; }; - - Boolean CanMoveUp { get; }; - Boolean CanMoveDown { get; }; - void MoveUp(); - void MoveDown(); - - void Remove(); - IVector LinkedProfiles { get; }; - Boolean IsInUse { get; }; - - Boolean CanReorderEffects { get; }; - Boolean IsShowMoveButtons { get; }; - } -} diff --git a/src/Magpie.App/ScalingModesViewModel.cpp b/src/Magpie.App/ScalingModesViewModel.cpp deleted file mode 100644 index 041745631..000000000 --- a/src/Magpie.App/ScalingModesViewModel.cpp +++ /dev/null @@ -1,219 +0,0 @@ -#include "pch.h" -#include "ScalingModesViewModel.h" -#if __has_include("ScalingModesViewModel.g.cpp") -#include "ScalingModesViewModel.g.cpp" -#endif -#include "EffectsService.h" -#include "AppSettings.h" -#include "EffectHelper.h" -#include "Logger.h" -#include "StrUtils.h" -#include "Win32Utils.h" -#include "ScalingMode.h" -#include "FileDialogHelper.h" -#include "CommonSharedConstants.h" - -using namespace ::Magpie::Core; - -namespace winrt::Magpie::App::implementation { - -ScalingModesViewModel::ScalingModesViewModel() { - _AddScalingModes(); - - _scalingModeAddedRevoker = ScalingModesService::Get().ScalingModeAdded( - auto_revoke, { this, &ScalingModesViewModel::_ScalingModesService_Added }); - _scalingModeMovedRevoker = ScalingModesService::Get().ScalingModeMoved( - auto_revoke, { this, &ScalingModesViewModel::_ScalingModesService_Moved }); - _scalingModeRemovedRevoker = ScalingModesService::Get().ScalingModeRemoved( - auto_revoke, { this, &ScalingModesViewModel::_ScalingModesService_Removed }); -} - -static std::optional OpenFileDialogForJson(IFileDialog* fileDialog) noexcept { - static std::wstring jsonFileStr( - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID) - .GetString(L"FileDialog_JsonFile")); - - const COMDLG_FILTERSPEC fileType{ jsonFileStr.c_str(), L"*.json"}; - fileDialog->SetFileTypes(1, &fileType); - fileDialog->SetDefaultExtension(L"json"); - - return FileDialogHelper::OpenFileDialog(fileDialog, FOS_STRICTFILETYPES); -} - -void ScalingModesViewModel::Export() const noexcept { - com_ptr fileDialog = try_create_instance(CLSID_FileSaveDialog); - if (!fileDialog) { - Logger::Get().Error("创建 FileSaveDialog 失败"); - return; - } - - fileDialog->SetFileName(L"ScalingModes"); - static std::wstring title( - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID) - .GetString(L"ExportDialog_Title")); - fileDialog->SetTitle(title.c_str()); - - std::optional fileName = OpenFileDialogForJson(fileDialog.get()); - if (!fileName.has_value() || fileName->empty()) { - return; - } - - rapidjson::StringBuffer json; - rapidjson::PrettyWriter writer(json); - writer.StartObject(); - ScalingModesService::Get().Export(writer); - writer.EndObject(); - - Win32Utils::WriteTextFile(fileName->c_str(), {json.GetString(), json.GetLength()}); -} - -static bool ImportImpl(bool legacy) noexcept { - com_ptr fileDialog = try_create_instance(CLSID_FileOpenDialog); - if (!fileDialog) { - Logger::Get().Error("创建 FileOpenDialog 失败"); - return false; - } - - ResourceLoader resourceLoader = - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID); - hstring title = resourceLoader.GetString(legacy ? L"ImportLegacyDialog_Title" : L"ImportDialog_Title"); - fileDialog->SetTitle(title.c_str()); - - std::optional fileName = OpenFileDialogForJson(fileDialog.get()); - if (!fileName.has_value()) { - return false; - } - if (fileName->empty()) { - return true; - } - - std::string json; - if (!Win32Utils::ReadTextFile(fileName->c_str(), json)) { - return false; - } - - rapidjson::Document doc; - // 导入时放宽 json 格式限制 - doc.ParseInsitu(json.data()); - if (doc.HasParseError()) { - Logger::Get().Error(fmt::format("解析缩放模式失败\n\t错误码: {}", (int)doc.GetParseError())); - return false; - } - - if (legacy) { - return ScalingModesService::Get().ImportLegacy(doc); - } - - if (!doc.IsObject()) { - return false; - } - - return ScalingModesService::Get().Import(((const rapidjson::Document&)doc).GetObj(), false); -} - -void ScalingModesViewModel::_Import(bool legacy) { - ShowErrorMessage(false); - if (!ImportImpl(legacy)) { - ShowErrorMessage(true); - } -} - -void ScalingModesViewModel::PrepareForAdd() { - std::vector copyFromList; - - ResourceLoader resourceLoader = - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID); - copyFromList.push_back(box_value(resourceLoader.GetString( - L"ScalingModes_NewScalingModeFlyout_CopyFrom_None"))); - - for (const auto& scalingMode : AppSettings::Get().ScalingModes()) { - copyFromList.push_back(box_value(scalingMode.name)); - } - _newScalingModeCopyFromList = single_threaded_vector(std::move(copyFromList)); - RaisePropertyChanged(L"NewScalingModeCopyFromList"); - - _newScalingModeName.clear(); - RaisePropertyChanged(L"NewScalingModeName"); - - _newScalingModeCopyFrom = 0; - RaisePropertyChanged(L"NewScalingModeCopyFrom"); -} - -void ScalingModesViewModel::NewScalingModeName(const hstring& value) noexcept { - _newScalingModeName = value; - RaisePropertyChanged(L"NewScalingModeName"); - RaisePropertyChanged(L"IsAddButtonEnabled"); -} - -void ScalingModesViewModel::AddScalingMode() { - ScalingModesService::Get().AddScalingMode(_newScalingModeName, _newScalingModeCopyFrom - 1); -} - -fire_and_forget ScalingModesViewModel::_AddScalingModes(bool isInitialExpanded) { - if (_addingScalingModes) { - co_return; - } - _addingScalingModes = true; - - ScalingModesService& scalingModesService = ScalingModesService::Get(); - uint32_t total = scalingModesService.GetScalingModeCount(); - uint32_t curSize = _scalingModes.Size(); - - CoreDispatcher dispatcher(nullptr); - - if (total - curSize <= 5) { - for (; curSize < total; ++curSize) { - _scalingModes.Append(ScalingModeItem(curSize, isInitialExpanded)); - } - } else { - assert(!isInitialExpanded); - - // 延迟加载 - for (int j = 0; j < 5; ++j) { - _scalingModes.Append(ScalingModeItem(curSize++, false)); - } - - dispatcher = CoreWindow::GetForCurrentThread().Dispatcher(); - auto weakThis = get_weak(); - - while (true) { - co_await 10ms; - co_await dispatcher; - - if (!weakThis.get()) { - co_return; - } - - total = scalingModesService.GetScalingModeCount(); - curSize = _scalingModes.Size(); - - if (curSize < total) { - _scalingModes.Append(ScalingModeItem(curSize++, false)); - } - - if (curSize >= total) { - break; - } - } - } - - _addingScalingModes = false; -} - -void ScalingModesViewModel::_ScalingModesService_Added(EffectAddedWay way) { - _AddScalingModes(way == EffectAddedWay::Add); -} - -void ScalingModesViewModel::_ScalingModesService_Moved(uint32_t index, bool isMoveUp) { - const uint32_t targetIndex = isMoveUp ? index - 1 : index + 1; - - ScalingModeItem targetItem = _scalingModes.GetAt(targetIndex).as(); - _scalingModes.RemoveAt(targetIndex); - _scalingModes.InsertAt(index, targetItem); -} - -void ScalingModesViewModel::_ScalingModesService_Removed(uint32_t index) { - _scalingModes.RemoveAt(index); -} - -} diff --git a/src/Magpie.App/ScalingModesViewModel.h b/src/Magpie.App/ScalingModesViewModel.h deleted file mode 100644 index a8a4fbd58..000000000 --- a/src/Magpie.App/ScalingModesViewModel.h +++ /dev/null @@ -1,94 +0,0 @@ -#pragma once -#include "ScalingModesViewModel.g.h" -#include "WinRTUtils.h" -#include "ScalingModesService.h" - -namespace winrt::Magpie::App::implementation { - -struct ScalingModesViewModel : ScalingModesViewModelT, - wil::notify_property_changed_base { - ScalingModesViewModel(); - - void Export() const noexcept; - - void Import() { - _Import(false); - } - - void ImportLegacy() { - _Import(true); - } - - bool ShowErrorMessage() const noexcept { - return _showErrorMessage; - } - - void ShowErrorMessage(bool value) { - _showErrorMessage = value; - RaisePropertyChanged(L"ShowErrorMessage"); - } - - IObservableVector ScalingModes() const noexcept { - return _scalingModes; - } - - void PrepareForAdd(); - - hstring NewScalingModeName() const noexcept { - return _newScalingModeName; - } - - void NewScalingModeName(const hstring& value) noexcept; - - IVector NewScalingModeCopyFromList() const noexcept { - return _newScalingModeCopyFromList; - } - - int NewScalingModeCopyFrom() const noexcept { - return _newScalingModeCopyFrom; - } - - void NewScalingModeCopyFrom(int value) noexcept { - _newScalingModeCopyFrom = value; - RaisePropertyChanged(L"NewScalingModeCopyFrom"); - } - - bool IsAddButtonEnabled() const noexcept { - return !_newScalingModeName.empty(); - } - - void AddScalingMode(); - -private: - fire_and_forget _AddScalingModes(bool isInitialExpanded = false); - - void _ScalingModesService_Added(EffectAddedWay way); - - void _ScalingModesService_Moved(uint32_t index, bool isMoveUp); - - void _ScalingModesService_Removed(uint32_t index); - - void _Import(bool legacy); - - IObservableVector _scalingModes = single_threaded_observable_vector(); - - WinRTUtils::EventRevoker _scalingModeAddedRevoker; - WinRTUtils::EventRevoker _scalingModeMovedRevoker; - WinRTUtils::EventRevoker _scalingModeRemovedRevoker; - - hstring _newScalingModeName; - IVector _newScalingModeCopyFromList{ nullptr }; - int _newScalingModeCopyFrom = 0; - - bool _showErrorMessage = false; - bool _addingScalingModes = false; -}; - -} - -namespace winrt::Magpie::App::factory_implementation { - -struct ScalingModesViewModel : ScalingModesViewModelT { -}; - -} diff --git a/src/Magpie.App/ScalingModesViewModel.idl b/src/Magpie.App/ScalingModesViewModel.idl deleted file mode 100644 index 608b03deb..000000000 --- a/src/Magpie.App/ScalingModesViewModel.idl +++ /dev/null @@ -1,20 +0,0 @@ -namespace Magpie.App { - runtimeclass ScalingModesViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged { - ScalingModesViewModel(); - - void Export(); - void Import(); - void ImportLegacy(); - - Boolean ShowErrorMessage; - - IObservableVector ScalingModes { get; }; - - void PrepareForAdd(); - String NewScalingModeName; - IVector NewScalingModeCopyFromList { get; }; - Int32 NewScalingModeCopyFrom; - Boolean IsAddButtonEnabled { get; }; - void AddScalingMode(); - } -} diff --git a/src/Magpie.App/SettingsExpanderCornerRadiusConverter.cpp b/src/Magpie.App/SettingsExpanderCornerRadiusConverter.cpp deleted file mode 100644 index 9b1f0ebfe..000000000 --- a/src/Magpie.App/SettingsExpanderCornerRadiusConverter.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "pch.h" -#include "SettingsExpanderCornerRadiusConverter.h" -#if __has_include("SettingsExpanderCornerRadiusConverter.g.cpp") -#include "SettingsExpanderCornerRadiusConverter.g.cpp" -#endif - -using namespace winrt; -using namespace Windows::UI::Xaml::Interop; - -namespace winrt::Magpie::App::implementation { - -IInspectable SettingsExpanderCornerRadiusConverter::Convert(IInspectable const& value, TypeName const&, IInspectable const&, hstring const&) { - auto cornerRadius = value.try_as(); - if (!cornerRadius) { - return value; - } - - cornerRadius->TopLeft = 0; - cornerRadius->TopRight = 0; - return box_value(*cornerRadius); -} - -IInspectable SettingsExpanderCornerRadiusConverter::ConvertBack(IInspectable const& value, TypeName const&, IInspectable const&, hstring const&) { - return value; -} - -} diff --git a/src/Magpie.App/SettingsExpanderCornerRadiusConverter.h b/src/Magpie.App/SettingsExpanderCornerRadiusConverter.h deleted file mode 100644 index db37a0f20..000000000 --- a/src/Magpie.App/SettingsExpanderCornerRadiusConverter.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include "SettingsExpanderCornerRadiusConverter.g.h" - -namespace winrt::Magpie::App::implementation { - -struct SettingsExpanderCornerRadiusConverter : SettingsExpanderCornerRadiusConverterT { - IInspectable Convert(IInspectable const& value, Interop::TypeName const&, IInspectable const&, hstring const&); - IInspectable ConvertBack(IInspectable const& value, Interop::TypeName const&, IInspectable const&, hstring const&); -}; - -} - -namespace winrt::Magpie::App::factory_implementation { - -struct SettingsExpanderCornerRadiusConverter : SettingsExpanderCornerRadiusConverterT { -}; - -} diff --git a/src/Magpie.App/SettingsExpanderCornerRadiusConverter.idl b/src/Magpie.App/SettingsExpanderCornerRadiusConverter.idl deleted file mode 100644 index 2c2b7d532..000000000 --- a/src/Magpie.App/SettingsExpanderCornerRadiusConverter.idl +++ /dev/null @@ -1,5 +0,0 @@ -namespace Magpie.App { - runtimeclass SettingsExpanderCornerRadiusConverter : [default] Windows.UI.Xaml.Data.IValueConverter { - SettingsExpanderCornerRadiusConverter(); - } -} diff --git a/src/Magpie.App/SettingsViewModel.cpp b/src/Magpie.App/SettingsViewModel.cpp deleted file mode 100644 index d3d8f191b..000000000 --- a/src/Magpie.App/SettingsViewModel.cpp +++ /dev/null @@ -1,187 +0,0 @@ -#include "pch.h" -#include "SettingsViewModel.h" -#if __has_include("SettingsViewModel.g.cpp") -#include "SettingsViewModel.g.cpp" -#endif -#include "AppSettings.h" -#include "AutoStartHelper.h" -#include "Win32Utils.h" -#include "CommonSharedConstants.h" -#include "LocalizationService.h" -#include "ScalingService.h" - -namespace winrt::Magpie::App::implementation { - -SettingsViewModel::SettingsViewModel() { - _UpdateStartupOptions(); -} - -IVector SettingsViewModel::Languages() const { - std::span tags = LocalizationService::Get().SupportedLanguages(); - - std::vector languages; - languages.reserve(tags.size() + 1); - - ResourceLoader resourceLoader = - ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID); - languages.push_back(box_value(resourceLoader.GetString(L"Settings_General_Language_System"))); - for (const wchar_t* tag : tags) { - Windows::Globalization::Language language(tag); - languages.push_back(box_value(language.NativeName())); - } - return single_threaded_vector(std::move(languages));; -} - -int SettingsViewModel::Language() const noexcept { - return AppSettings::Get().Language() + 1; -} - -void SettingsViewModel::Language(int value) { - if (value < 0) { - return; - } - - AppSettings::Get().Language(value - 1); - RaisePropertyChanged(L"Language"); - RaisePropertyChanged(L"RequireRestart"); -} - -bool SettingsViewModel::RequireRestart() const noexcept { - static int initLanguage = AppSettings::Get().Language(); - return AppSettings::Get().Language() != initLanguage; -} - -void SettingsViewModel::Restart() const { - Application::Current().as().Restart(); -} - -int SettingsViewModel::Theme() const noexcept { - switch (AppSettings::Get().Theme()) { - case Theme::System: - return 0; - case Theme::Light: - return 1; - case Theme::Dark: - return 2; - default: - return 0; - } -} - -void SettingsViewModel::Theme(int value) { - if (value < 0) { - return; - } - - Magpie::App::Theme theme; - switch (value) { - case 1: - theme = Theme::Light; - break; - case 2: - theme = Theme::Dark; - break; - default: - theme = Theme::System; - break; - } - - AppSettings::Get().Theme(theme); - RaisePropertyChanged(L"Theme"); -} - -void SettingsViewModel::IsRunAtStartup(bool value) { - if (value) { - AutoStartHelper::EnableAutoStart( - AppSettings::Get().IsAlwaysRunAsAdmin(), - _isMinimizeAtStartup ? CommonSharedConstants::OPTION_LAUNCH_WITHOUT_WINDOW : nullptr - ); - } else { - AutoStartHelper::DisableAutoStart(); - } - - _UpdateStartupOptions(); - - RaisePropertyChanged(L"IsMinimizeAtStartupEnabled"); -} - -void SettingsViewModel::IsMinimizeAtStartup(bool value) { - if (!_isRunAtStartup) { - return; - } - - AutoStartHelper::EnableAutoStart( - AppSettings::Get().IsAlwaysRunAsAdmin(), - value ? CommonSharedConstants::OPTION_LAUNCH_WITHOUT_WINDOW : nullptr - ); - - _UpdateStartupOptions(); -} - -bool SettingsViewModel::IsMinimizeAtStartupEnabled() const noexcept { - return IsRunAtStartup() && IsShowNotifyIcon(); -} - -bool SettingsViewModel::IsPortableMode() const noexcept { - return AppSettings::Get().IsPortableMode(); -} - -void SettingsViewModel::IsPortableMode(bool value) { - AppSettings& settings = AppSettings::Get(); - - if (settings.IsPortableMode() == value) { - return; - } - - settings.IsPortableMode(value); - RaisePropertyChanged(L"IsPortableMode"); -} - -fire_and_forget SettingsViewModel::OpenConfigLocation() const noexcept { - std::wstring configPath = AppSettings::Get().ConfigDir() + CommonSharedConstants::CONFIG_FILENAME; - co_await resume_background(); - Win32Utils::OpenFolderAndSelectFile(configPath.c_str()); -} - -bool SettingsViewModel::IsShowNotifyIcon() const noexcept { - return AppSettings::Get().IsShowNotifyIcon(); -} - -void SettingsViewModel::IsShowNotifyIcon(bool value) { - AppSettings::Get().IsShowNotifyIcon(value); - RaisePropertyChanged(L"IsShowNotifyIcon"); - - if (_isRunAtStartup) { - AutoStartHelper::EnableAutoStart(AppSettings::Get().IsAlwaysRunAsAdmin(), nullptr); - _UpdateStartupOptions(); - } - - RaisePropertyChanged(L"IsMinimizeAtStartupEnabled"); -} - -bool SettingsViewModel::IsProcessElevated() const noexcept { - return Win32Utils::IsProcessElevated(); -} - -bool SettingsViewModel::IsAlwaysRunAsAdmin() const noexcept { - return AppSettings::Get().IsAlwaysRunAsAdmin(); -} - -void SettingsViewModel::IsAlwaysRunAsAdmin(bool value) { - AppSettings::Get().IsAlwaysRunAsAdmin(value); -} - -void SettingsViewModel::_UpdateStartupOptions() { - std::wstring arguments; - _isRunAtStartup = AutoStartHelper::IsAutoStartEnabled(arguments); - if (_isRunAtStartup) { - _isMinimizeAtStartup = arguments == CommonSharedConstants::OPTION_LAUNCH_WITHOUT_WINDOW; - } else { - _isMinimizeAtStartup = false; - } - - RaisePropertyChanged(L"IsRunAtStartup"); - RaisePropertyChanged(L"IsMinimizeAtStartup"); -} - -} diff --git a/src/Magpie.App/SettingsViewModel.h b/src/Magpie.App/SettingsViewModel.h deleted file mode 100644 index 34e1a6e0b..000000000 --- a/src/Magpie.App/SettingsViewModel.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once -#include "SettingsViewModel.g.h" - -namespace winrt::Magpie::App::implementation { - -struct SettingsViewModel : SettingsViewModelT, - wil::notify_property_changed_base { - SettingsViewModel(); - - IVector Languages() const; - - int Language() const noexcept; - void Language(int value); - - bool RequireRestart() const noexcept; - void Restart() const; - - int Theme() const noexcept; - void Theme(int value); - - bool IsRunAtStartup() const noexcept { - return _isRunAtStartup; - } - - void IsRunAtStartup(bool value); - - bool IsMinimizeAtStartup() const noexcept { - return _isMinimizeAtStartup; - } - - void IsMinimizeAtStartup(bool value); - - bool IsMinimizeAtStartupEnabled() const noexcept; - - bool IsPortableMode() const noexcept; - void IsPortableMode(bool value); - - fire_and_forget OpenConfigLocation() const noexcept; - - bool IsShowNotifyIcon() const noexcept; - void IsShowNotifyIcon(bool value); - - bool IsProcessElevated() const noexcept; - - bool IsAlwaysRunAsAdmin() const noexcept; - void IsAlwaysRunAsAdmin(bool value); - -private: - void _UpdateStartupOptions(); - - bool _isRunAtStartup = false; - bool _isMinimizeAtStartup = false; -}; - -} - -namespace winrt::Magpie::App::factory_implementation { - -struct SettingsViewModel : SettingsViewModelT { -}; - -} diff --git a/src/Magpie.App/SettingsViewModel.idl b/src/Magpie.App/SettingsViewModel.idl deleted file mode 100644 index a0a116847..000000000 --- a/src/Magpie.App/SettingsViewModel.idl +++ /dev/null @@ -1,21 +0,0 @@ -namespace Magpie.App { - runtimeclass SettingsViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged { - SettingsViewModel(); - - IVector Languages { get; }; - Int32 Language; - Boolean RequireRestart { get; }; - void Restart(); - - Int32 Theme; - Boolean IsRunAtStartup; - Boolean IsMinimizeAtStartup; - Boolean IsMinimizeAtStartupEnabled { get; }; - Boolean IsPortableMode; - void OpenConfigLocation(); - Boolean IsShowNotifyIcon; - - Boolean IsProcessElevated { get; }; - Boolean IsAlwaysRunAsAdmin; - } -} diff --git a/src/Magpie.App/Shortcut.cpp b/src/Magpie.App/Shortcut.cpp deleted file mode 100644 index 727849285..000000000 --- a/src/Magpie.App/Shortcut.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "pch.h" -#include "Shortcut.h" -#include "Win32Utils.h" -#include "StrUtils.h" -#include "ShortcutHelper.h" -#include "SmallVector.h" - -namespace winrt::Magpie::App { - -bool Shortcut::IsEmpty() const noexcept { - return !win && !ctrl && !alt && !shift && code == 0; -} - -void Shortcut::Clear() noexcept { - win = false; - ctrl = false; - alt = false; - shift = false; - code = 0; -} - -std::wstring Shortcut::ToString() const noexcept { - std::wstring output; - - if (win) { - output.append(L"Win+"); - } - - if (ctrl) { - output.append(L"Ctrl+"); - } - - if (alt) { - output.append(L"Alt+"); - } - - if (shift) { - output.append(L"Shift+"); - } - - if (code > 0) { - output.append(Win32Utils::GetKeyName(code)); - } else if (output.size() > 1) { - output.pop_back(); - } - - return output; -} - -} diff --git a/src/Magpie.App/Shortcut.h b/src/Magpie.App/Shortcut.h deleted file mode 100644 index 6c2cf3932..000000000 --- a/src/Magpie.App/Shortcut.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include -#include -#include "SmallVector.h" - -namespace winrt::Magpie::App { - -struct Shortcut { - bool operator==(const Shortcut&) const noexcept = default; - - bool IsEmpty() const noexcept; - - void Clear() noexcept; - - std::wstring ToString() const noexcept; - - // 0 表示无 Virtual Key - uint8_t code = 0; - - bool win = false; - bool ctrl = false; - bool alt = false; - bool shift = false; -}; - -} diff --git a/src/Magpie.App/ShortcutHelper.cpp b/src/Magpie.App/ShortcutHelper.cpp deleted file mode 100644 index 7240b086e..000000000 --- a/src/Magpie.App/ShortcutHelper.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "pch.h" -#include "ShortcutHelper.h" -#include "Win32Utils.h" -#include - -namespace winrt::Magpie::App { - -std::string ShortcutHelper::ToString(winrt::Magpie::App::ShortcutAction action) noexcept { - using winrt::Magpie::App::ShortcutAction; - - switch (action) { - case ShortcutAction::Scale: - return "Scale"; - case ShortcutAction::Overlay: - return "Overlay"; - case ShortcutAction::COUNT_OR_NONE: - return "None"; - default: - break; - } - - return {}; -} - -bool ShortcutHelper::IsValidKeyCode(uint8_t code) noexcept { - static phmap::flat_hash_set validKeyCodes = []() { - phmap::flat_hash_set keyCodes; - keyCodes.reserve(99); - - // 字母 - for (uint8_t i = 'A'; i <= 'Z'; ++i) { - keyCodes.insert(i); - } - - // 数字(顶部) - for (uint8_t i = '0'; i <= '9'; ++i) { - keyCodes.insert(i); - } - - // 数字(小键盘) - for (uint8_t i = VK_NUMPAD0; i <= VK_NUMPAD9; ++i) { - keyCodes.insert(i); - } - - // F1~F24 - for (uint8_t i = VK_F1; i <= VK_F24; ++i) { - keyCodes.insert(i); - } - - // 空格、Page Up/Down、End、Home、方向键 - for (uint8_t i = VK_SPACE; i <= VK_DOWN; ++i) { - keyCodes.insert(i); - } - - // 分号、等号、逗号、-、句号、/、` - for (uint8_t i = VK_OEM_1; i <= VK_OEM_3; ++i) { - keyCodes.insert(i); - } - - // [、\、]、' - for (uint8_t i = VK_OEM_4; i <= VK_OEM_7; ++i) { - keyCodes.insert(i); - } - - keyCodes.insert((uint8_t)VK_INSERT); // Insert - keyCodes.insert((uint8_t)VK_DELETE); // Delete - keyCodes.insert((uint8_t)VK_ADD); // 加(小键盘) - keyCodes.insert((uint8_t)VK_SUBTRACT); // 减(小键盘) - keyCodes.insert((uint8_t)VK_MULTIPLY); // 乘(小键盘) - keyCodes.insert((uint8_t)VK_DIVIDE); // 除(小键盘) - keyCodes.insert((uint8_t)VK_DECIMAL); // .(小键盘) - keyCodes.insert((uint8_t)VK_BACK); // Backspace - keyCodes.insert((uint8_t)VK_RETURN); // 回车 - - return keyCodes; - }(); - - return validKeyCodes.contains(code); -} - -ShortcutError ShortcutHelper::CheckShortcut(Shortcut shortcut) noexcept { - UINT modifiers = MOD_NOREPEAT; - UINT modCount = 0; - - if (shortcut.win) { - ++modCount; - modifiers |= MOD_WIN; - } - if (shortcut.ctrl) { - ++modCount; - modifiers |= MOD_CONTROL; - } - if (shortcut.alt) { - ++modCount; - modifiers |= MOD_ALT; - } - if (shortcut.shift) { - ++modCount; - modifiers |= MOD_SHIFT; - } - - if (modCount == 0 || (modCount == 1 && shortcut.code == 0)) { - // 必须存在 Modifier - // 如果只有一个 Modifier 则必须存在 Virtual Key - return ShortcutError::Invalid; - } - - // 检测快捷键是否被占用 - if (!RegisterHotKey(NULL, (int)ShortcutAction::COUNT_OR_NONE, modifiers, shortcut.code)) { - return ShortcutError::Occupied; - } - - UnregisterHotKey(NULL, (int)ShortcutAction::COUNT_OR_NONE); - return ShortcutError::NoError; -} - -} // namespace winrt::Magpie::App - -namespace winrt { - -using Magpie::App::ShortcutAction; - -hstring to_hstring(ShortcutAction action) { - switch (action) { - case ShortcutAction::Scale: - return L"Scale"; - case ShortcutAction::Overlay: - return L"Overlay"; - case ShortcutAction::COUNT_OR_NONE: - return L"None"; - default: - break; - } - - return {}; -} - -} // namespace winrt diff --git a/src/Magpie.App/ShortcutHelper.h b/src/Magpie.App/ShortcutHelper.h deleted file mode 100644 index 2d842af61..000000000 --- a/src/Magpie.App/ShortcutHelper.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include -#include "Shortcut.h" - -namespace winrt::Magpie::App { - -struct ShortcutHelper { - static std::string ToString(winrt::Magpie::App::ShortcutAction action) noexcept; - - static bool IsValidKeyCode(uint8_t code) noexcept; - - static ShortcutError CheckShortcut(Shortcut shortcut) noexcept; -}; - -} - -namespace winrt { - -// 将 ShortcutAction 映射为字符串 -hstring to_hstring(Magpie::App::ShortcutAction action); - -} diff --git a/src/Magpie.App/TouchHelper.cpp b/src/Magpie.App/TouchHelper.cpp deleted file mode 100644 index d021664c3..000000000 --- a/src/Magpie.App/TouchHelper.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include "pch.h" -#include "TouchHelper.h" -#include "Logger.h" -#include "StrUtils.h" -#include "Win32Utils.h" -#include "CommonSharedConstants.h" - -namespace winrt::Magpie::App { - -static std::wstring GetTouchHelperPath() noexcept { - wil::unique_cotaskmem_string system32Dir; - HRESULT hr = SHGetKnownFolderPath( - FOLDERID_System, KF_FLAG_DEFAULT, NULL, system32Dir.put()); - if (FAILED(hr)) { - Logger::Get().ComError("SHGetKnownFolderPath 失败", hr); - return {}; - } - - return StrUtils::Concat(system32Dir.get(), - L"\\Magpie\\", CommonSharedConstants::TOUCH_HELPER_EXE_NAME); -} - -bool TouchHelper::IsTouchSupportEnabled() noexcept { - // 不检查版本号 - return Win32Utils::FileExists(GetTouchHelperPath().c_str()); -} - -void TouchHelper::IsTouchSupportEnabled(bool value) noexcept { - SHELLEXECUTEINFO execInfo{ - .cbSize = sizeof(execInfo), - .fMask = SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS, - .lpVerb = L"runas", - .lpFile = Win32Utils::GetExePath().c_str(), - .lpParameters = value ? L" -r" : L" -ur" - }; - - if (ShellExecuteEx(&execInfo)) { - wil::unique_process_handle hProcess(execInfo.hProcess); - if (hProcess) { - wil::handle_wait(hProcess.get()); - } - } else if (GetLastError() != ERROR_CANCELLED) { - Logger::Get().Win32Error("ShellExecuteEx 失败"); - } -} - -static bool CheckAndFixTouchHelper(std::wstring& path) noexcept { - // 检查版本号 - path += L".ver"; - - std::vector versionData; - - const auto checkVersion = [&]() { - if (!Win32Utils::ReadFile(path.c_str(), versionData)) { - Logger::Get().Error("读取版本号失败"); - } - - return versionData.size() == 4 && - *(uint32_t*)versionData.data() == CommonSharedConstants::TOUCH_HELPER_VERSION; - }; - - if (!checkVersion()) { - // 版本号不匹配,尝试修复,这会请求管理员权限 - TouchHelper::IsTouchSupportEnabled(true); - - if (!checkVersion()) { - Logger::Get().Error("修复触控支持失败"); - return false; - } - } - - path.erase(path.size() - 4); - return true; -} - -bool TouchHelper::TryLaunchTouchHelper(bool& isTouchSupportEnabled) noexcept { - std::wstring path = GetTouchHelperPath(); - isTouchSupportEnabled = Win32Utils::FileExists(path.c_str()); - if (!isTouchSupportEnabled) { - // 未启用触控支持 - return true; - } - - wil::unique_mutex_nothrow hSingleInstanceMutex; - - bool alreadyExists = false; - if (!hSingleInstanceMutex.try_create( - CommonSharedConstants::TOUCH_HELPER_SINGLE_INSTANCE_MUTEX_NAME, - CREATE_MUTEX_INITIAL_OWNER, - MUTEX_ALL_ACCESS, - nullptr, - &alreadyExists - ) || alreadyExists) { - Logger::Get().Info("TouchHelper.exe 正在运行"); - return true; - } - - hSingleInstanceMutex.ReleaseMutex(); - - // TouchHelper.exe 未在运行则启动它 - - // 检查版本是否匹配并尝试修复 - if (!CheckAndFixTouchHelper(path)) { - // 修复失败 - Logger::Get().Error("CheckAndFixTouchHelper 失败"); - return false; - } - - if (!Win32Utils::ShellOpen(path.c_str(), nullptr, false)) { - Logger::Get().Error("启动 TouchHelper.exe 失败"); - return false; - } - - return true; -} - -} diff --git a/src/Magpie.App/TouchHelper.h b/src/Magpie.App/TouchHelper.h deleted file mode 100644 index c72e65303..000000000 --- a/src/Magpie.App/TouchHelper.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -namespace winrt::Magpie::App { - -struct TouchHelper { - static bool IsTouchSupportEnabled() noexcept; - static void IsTouchSupportEnabled(bool value) noexcept; - static bool TryLaunchTouchHelper(bool& isTouchSupportEnabled) noexcept; -}; - -} diff --git a/src/Magpie.Core/include/Magpie.Core.h b/src/Magpie.Core/include/Magpie.Core.h index f5a4d1ef7..fdb8f0385 100644 --- a/src/Magpie.Core/include/Magpie.Core.h +++ b/src/Magpie.Core/include/Magpie.Core.h @@ -1,7 +1,6 @@ #pragma once #include "../ScalingOptions.h" #include "../ScalingRuntime.h" -#include "../LoggerHelper.h" #include "../EffectCompiler.h" #include "../EffectDesc.h" #include "../WindowHelper.h" diff --git a/src/Magpie/XamlApp.cpp b/src/Magpie/XamlApp.cpp index b87fa26e8..5776f28cf 100644 --- a/src/Magpie/XamlApp.cpp +++ b/src/Magpie/XamlApp.cpp @@ -58,10 +58,6 @@ bool XamlApp::Initialize(HINSTANCE hInstance, const wchar_t* arguments) { winrt::init_apartment(winrt::apartment_type::single_threaded); FixThreadPoolCrash(); - - // 初始化 Magpie.App.dll 中的 Logger - // 单例无法在 exe 和 dll 间共享 - winrt::LoggerHelper::Initialize((uint64_t)&Logger::Get()); InitMessages(); @@ -74,30 +70,15 @@ bool XamlApp::Initialize(HINSTANCE hInstance, const wchar_t* arguments) { // 初始化 UWP 应用 _uwpApp = winrt::App(); - winrt::StartUpOptions options = _uwpApp.Initialize(0); - if (options.IsError) { - Logger::Get().Error("初始化失败"); - return false; - } - - if (options.IsNeedElevated && !Win32Utils::IsProcessElevated()) { - Restart(true, arguments); - return false; - } - - _mainWindowCenter = options.MainWindowCenter; - _mainWindowSizeInDips = options.MainWindowSizeInDips; - _isMainWndMaximized = options.IsWndMaximized; + _mainWindowCenter = { 500,500 }; + _mainWindowSizeInDips = { 1026.66663,730.000000 }; + _isMainWndMaximized = false; ThemeHelper::Initialize(); NotifyIconService& notifyIconService = NotifyIconService::Get(); notifyIconService.Initialize(); - notifyIconService.IsShow(_uwpApp.IsShowNotifyIcon()); - _uwpApp.IsShowNotifyIconChanged([](winrt::IInspectable const&, bool value) { - NotifyIconService::Get().IsShow(value); - }); - + notifyIconService.IsShow(false); _mainWindow.Destroyed({ this, &XamlApp::_MainWindow_Destoryed }); // 不显示托盘图标时忽略 -t 参数 @@ -180,8 +161,6 @@ void XamlApp::SaveSettings() { Logger::Get().Win32Error("GetWindowPlacement 失败"); } } - - _uwpApp.SaveSettings(); } XamlApp::XamlApp() {} @@ -245,7 +224,6 @@ bool XamlApp::_CreateMainWindow() noexcept { return false; } - _uwpApp.HwndMain((uint64_t)_mainWindow.Handle()); _uwpApp.RootPage(_mainWindow.Content()); return true; @@ -262,7 +240,6 @@ void XamlApp::ShowMainWindow() noexcept { void XamlApp::_QuitWithoutMainWindow() { NotifyIconService::Get().Uninitialize(); - _uwpApp.Uninitialize(); // 不能调用 Close,否则切换页面时关闭主窗口会导致崩溃 _uwpApp = nullptr; @@ -273,7 +250,6 @@ void XamlApp::_QuitWithoutMainWindow() { } void XamlApp::_MainWindow_Destoryed() { - _uwpApp.HwndMain(0); _uwpApp.RootPage(nullptr); if (!NotifyIconService::Get().IsShow()) { diff --git a/src/Shared/Logger.cpp b/src/Shared/Logger.cpp index b324e79c2..a6d3d4a43 100644 --- a/src/Shared/Logger.cpp +++ b/src/Shared/Logger.cpp @@ -67,10 +67,4 @@ void Logger::_Log(spdlog::level::level_enum logLevel, std::string_view msg, cons OutputDebugString(StrUtils::Concat(L"[LOG] ", StrUtils::UTF8ToUTF16(msg), L"\n").c_str()); } } - - _logger->log( - spdlog::source_loc{ location.FileName(), (int)location.Line(), location.FunctionName() }, - logLevel, - msg - ); }