diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index 257013ccfeec..1cc2d8584fde 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -26,7 +26,6 @@ AFFINETRANSFORM affordances AFX AGGREGATABLE -ahk AHybrid akv ALarger @@ -1049,6 +1048,7 @@ NNN NOACTIVATE NOAGGREGATION NOASYNC +NOCHANGEDIR NOCLIP NOCLOSEPROCESS NOCOALESCE diff --git a/.pipelines/v2/templates/job-build-project.yml b/.pipelines/v2/templates/job-build-project.yml index 229b05998f34..0c85df303f38 100644 --- a/.pipelines/v2/templates/job-build-project.yml +++ b/.pipelines/v2/templates/job-build-project.yml @@ -205,13 +205,6 @@ jobs: - ${{ if eq(parameters.useLatestWinAppSDK, false)}}: - template: .\steps-restore-nuget.yml - - pwsh: |- - & "$(build.sourcesdirectory)\.pipelines\verifyAndSetLatestVCToolsVersion.ps1" - displayName: Work around DD-1541167 (VCToolsVersion) - ${{ if eq(parameters.useVSPreview, true) }}: - env: - VCWhereExtraVersionTarget: '-prerelease' - - pwsh: |- & "$(build.sourcesdirectory)\.pipelines\installWiX.ps1" displayName: Download and install WiX 3.14 development build diff --git a/.pipelines/verifyAndSetLatestVCToolsVersion.ps1 b/.pipelines/verifyAndSetLatestVCToolsVersion.ps1 deleted file mode 100644 index 6527b63574bc..000000000000 --- a/.pipelines/verifyAndSetLatestVCToolsVersion.ps1 +++ /dev/null @@ -1,5 +0,0 @@ -$LatestVCToolsVersion = (([xml](& 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -latest $env:VCWhereExtraVersionTarget -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -include packages -format xml)).instances.instance.packages.package | ? { $_.id -eq "Microsoft.VisualCpp.CRT.Source" }).version; - -Write-Output "Latest VCToolsVersion: $LatestVCToolsVersion" -Write-Output "Updating VCToolsVersion environment variable for job" -Write-Output "##vso[task.setvariable variable=VCToolsVersion]$LatestVCToolsVersion" diff --git a/README.md b/README.md index 11646244adef..dbb95b8c86c6 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline | [New+](https://aka.ms/PowerToysOverview_NewPlus) | [Peek](https://aka.ms/PowerToysOverview_Peek) | [Paste as Plain Text](https://aka.ms/PowerToysOverview_PastePlain) | | [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) | [Quick Accent](https://aka.ms/PowerToysOverview_QuickAccent) | | [Registry Preview](https://aka.ms/PowerToysOverview_RegistryPreview) | [Screen Ruler](https://aka.ms/PowerToysOverview_ScreenRuler) | [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) | -| [Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [Workspaces](https://aka.ms/PowerToysOverview_Workspaces) | [ZoomIt](https://aka.ms/PowerToysOverview_PowerToysOverview_ZoomIt) | +| [Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [Workspaces](https://aka.ms/PowerToysOverview_Workspaces) | [ZoomIt](https://aka.ms/PowerToysOverview_ZoomIt) | ## Installing and running Microsoft PowerToys @@ -34,19 +34,19 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline Go to the [Microsoft PowerToys GitHub releases page][github-release-link] and click on `Assets` at the bottom to show the files available in the release. Please use the appropriate PowerToys installer that matches your machine's architecture and install scope. For most, it is `x64` and per-user. -[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.88%22 -[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.87%22 -[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.87.1/PowerToysUserSetup-0.87.1-x64.exe -[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.87.1/PowerToysUserSetup-0.87.1-arm64.exe -[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.87.1/PowerToysSetup-0.87.1-x64.exe -[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.87.1/PowerToysSetup-0.87.1-arm64.exe +[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.89%22 +[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.88%22 +[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.88.0/PowerToysUserSetup-0.88.0-x64.exe +[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.88.0/PowerToysUserSetup-0.88.0-arm64.exe +[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.88.0/PowerToysSetup-0.88.0-x64.exe +[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.88.0/PowerToysSetup-0.88.0-arm64.exe | Description | Filename | sha256 hash | |----------------|----------|-------------| -| Per user - x64 | [PowerToysUserSetup-0.87.1-x64.exe][ptUserX64] | 8EFAF47ED00BF230D2C2CC3CB6765C903A6A47E0AAED0BBB329CEF918207B486 | -| Per user - ARM64 | [PowerToysUserSetup-0.87.1-arm64.exe][ptUserArm64] | 212FC8055789BD2DC4DE554B9AEE291A9C077907E263A302939266263A9D512B | -| Machine wide - x64 | [PowerToysSetup-0.87.1-x64.exe][ptMachineX64] | 69AD65DDAC6436AEF292D2CC6AB1530021CE98083CB3F5FD3380A52A3B0DBB9A | -| Machine wide - ARM64 | [PowerToysSetup-0.87.1-arm64.exe][ptMachineArm64] | AEC9F1D02F1E23F0C1FCFDF95C337C962902394F44C0568012DF78BEDB45CF19 | +| Per user - x64 | [PowerToysUserSetup-0.88.0-x64.exe][ptUserX64] | 5BBA2E06603CAAE0269DFBC991095C6664FD934130335197C1BA3120E19B7CA3 | +| Per user - ARM64 | [PowerToysUserSetup-0.88.0-arm64.exe][ptUserArm64] | E79723F9F94068C699E01334C8CC0C85F37818EB4664FC772D2B545A1C37C3FA | +| Machine wide - x64 | [PowerToysSetup-0.88.0-x64.exe][ptMachineX64] | C43742DB7AA3F8B01FE7AE1DA591F0342767AFE5BBACB72F2968CE5E8EE1E3AC | +| Machine wide - ARM64 | [PowerToysSetup-0.88.0-arm64.exe][ptMachineArm64] | AEE4A67643C886336F31F86C4117BA5F01BCA5E0E99FF34524217DC91AFA7132 | This is our preferred method. @@ -92,119 +92,141 @@ For guidance on developing for PowerToys, please read the [developer docs](/doc/ Our [prioritized roadmap][roadmap] of features and utilities that the core team is focusing on. -### 0.87 - December 2024 Update +### 0.88 - January 2025 Update In this release, we focused on new features, stability, and improvements. **Highlights** - - Advanced Paste has a new feature called "Advanced AI" that uses Semantic Kernel to allow setting up the orchestration of sequential clipboard transformations. - - Workspaces supports Progressive Web Applications. - - Workspaces has a new feature to move existing windows instead of creating new ones. - - Mouse Jump added new settings to allow customization of screens pop-up. Thanks [@mikeclayton](https://github.com/mikeclayton)! - - New+ now works on Windows 10. Thanks [@cgaarden](https://github.com/cgaarden)! - - Quick Accent allows selecting the character sets that should appear on the UI. Thanks [@Sirozha1337](https://github.com/Sirozha1337)! + - New utility: ZoomIt - a screen zoom, annotation, and recording tool for technical presentations and demos. This utility from Sysinternals has had its source code released and included in PowerToys. ZoomIt will still continue to be updated and shipped by Sysinternals for users who prefer to have it as a standalone utility outside of PowerToys. Thanks [@markrussinovich](https://github.com/markrussinovich), [@foxmsft](https://github.com/foxmsft) and [@johnstep](https://github.com/johnstep) for contributing the original code and reviewing the PowerToys integration! + - Video Conference Mute has been deprecated and was removed from PowerToys. + - .Net 9.0.1 fixed many issue in WPF, improving stability for PowerToys Run. -### Advanced Paste - - - Added a new optional feature allowing using AI to set up the orchestration of sequential clipboard transformations. +### General + - Applied a workaround for the Windows App SDK applications title bar override that was causing accent color to not be shown on the top bar of applications on Windows 10. Thanks [@pingzing](https://github.com/pingzing)! + - Improved the "admin application running" notification checking logic to be less demanding on resources. Thanks [@davidegiacometti](https://github.com/davidegiacometti)! + - Fixed an issue causing many utilities to crash when the GPO to disable data diagnostics was applied. -### Awake +### Advanced Paste - - Initialization, logging and tray icon setup improvements. Thanks [@dend](https://github.com/dend)! + - Fixed a crash when the application was exiting. (This was a hotfix for 0.87) + - Added a Json format validation step to verify if a conversion to Json should be applied. + - Fixed accessibility issues when using a screen reader. + - Added support for all BitmapDecoder supported image file types to the Image to Text functionality. Thanks [@daverayment](https://github.com/daverayment)! + - Fixed an issue causing Advanced Paste initialization errors to hang the PowerToys main process. -### File Explorer add-ons +### FancyZones - - Preview Pane extensions now use the PerMonitorV2 DPI mode to fix errors on different scales. Thanks [@davidegiacometti](https://github.com/davidegiacometti)! + - Removed Workspaces Editor from the exclusions list so it can be snapped by FancyZones. -### Keyboard Manager. +### Keyboard Manager - - Added labels to the IME On, IME Off keys. Thanks [@kit494way](https://github.com/kit494way)! - - Fixed an issue that caused the Shift key to remain stuck if a numpad key was mapped to the Shift key. + - Added an option to make a shortcut remapping only trigger with exact modifiers. ### Monaco Preview - - Added support for .ahk files to be shown as a plaintext file in Peek and File Explorer add-ons. Thanks [@daverayment](https://github.com/daverayment)! - - Added support for .ion files to be shown as a plaintext file in Peek and File Explorer add-ons. Thanks [@octastylos-pseudodipteros](https://github.com/octastylos-pseudodipteros)! - - Added support for syntax highlighting for .srt files in Peek and File Explorer add-ons. Thanks [@PesBandi](https://github.com/PesBandi)! + - Added support for .resx and .resw files in Peek and File Explorer add-ons. Thanks [@asif4318](https://github.com/asif4318)! + - Added a setting to make the code minimap toggle-able in Peek and File Explorer add-ons. Thanks [@PesBandi](https://github.com/PesBandi)! + - Fixed an issue causing Json format preview setting to not be applied correctly. + - Fixed an issue causing the wrong Monaco assets to be used at runtime. -### Mouse Jump +### Mouse Without Borders - - Allow customizing the appearance of the UI of the Mouse Jump pop-up. Thanks [@mikeclayton](https://github.com/mikeclayton)! + - Fixed an issue causing clipboard to stop working after going through a UAC screen when using the Service mode. Thanks [@YDKK](https://github.com/YDKK)! ### New+ - - Added support for Windows 10. Thanks [@cgaarden](https://github.com/cgaarden)! - - Fixed an issue causing the renaming of new files to not trigger some times. Thanks [@cgaarden](https://github.com/cgaarden)! - - Updated the New+ icons. Thanks [@niels9001](https://github.com/niels9001)! + - Fixed an issue causing New+ to override the New file or folder creation from the File Explorer Ribbon buttons or keyboard shortcuts on Windows 10. + - When creating file or folders through a template, they should now have the current time as the last modified date. Thanks [@cgaarden](https://github.com/cgaarden)! ### Peek - - Peek now checks local capabilities to decide what image formats Image Previewer is able to support. Thanks [@daverayment](https://github.com/daverayment)! - - Fixed an issue causing the Code Files Previewer to not load correctly under certain conditions. Thanks [@daverayment](https://github.com/daverayment)! - - Refactored, improved and fixed logging when loading the user settings file. Thanks [@daverayment](https://github.com/daverayment)! + - Fixed an issue causing Peek to not appear if it was previously minimized. Thanks [@asif4318](https://github.com/asif4318)! ### PowerToys Run - - Added a scoring function for proper ordering of the WindowWalker plugin results. Thanks [@andbartol](https://github.com/andbartol)! - - Added UUIDv7 support to the ValueGenerator plugin. Thanks [@frederik-hoeft](https://github.com/frederik-hoeft)! - - The calculator plugin now allows scientific notation numbers with a lowercase 'e'. Thanks [@PesBandi](https://github.com/PesBandi)! - - Ported the UI from WPF-UI to .NET 9 WPF, to fix "Desktop composition is disabled" crashes. + - Fixed a transparent border issue on Windows 10. (This was a hotfix for 0.87) + - Fixed a crash in the OneNote plugin after the .Net 9 update. (This was a hotfix for 0.87) + - Fixed an issue causing the Calculator plugin to return division by zero errors when dividing by hexadecimal numbers. Thanks [@plante-msft](https://github.com/plante-msft)! + - Updated the Calculator plugin Mages library to 3.0.0 and added support for the random integer function. Thanks [@htcfreek](https://github.com/htcfreek)! + - Improved handling of non-base 10 numbers to add support for binary and octal numbers in the Calculator plugin. Thanks [@PesBandi](https://github.com/PesBandi)! + - Added a setting to enable selection of which units to use for trigonometric functions. Thanks [@OldUser101](https://github.com/OldUser101)! + - Fixed a .NET 9 regression causing the PowerToys Run dialog to not be draggable. Thanks [@davidegiacometti](https://github.com/davidegiacometti)! + - Added context menu buttons for the VS Code Workspaces plugin, for copying the path, opening in File Explorer or in Console. Thanks [@programming-with-ia](https://github.com/programming-with-ia)! + - Added some telemetry to gather data on which hotkey is used to trigger PowerToys Run. + - Removed the workarounds that were in place to fix some WPF issues that were fixed in .NET 9.0.1. + - Fixed a typo in the Value Generator plugin messages. Thanks [@OldUser101](https://github.com/OldUser101)! ### Quick Accent - - Added a setting to allow selecting which character sets to show. Thanks [@Sirozha1337](https://github.com/Sirozha1337)! + - Added the ć character to the Slovenian character set. Thanks [@dsoklic](https://github.com/dsoklic)! + - Added the Proto-Indo-European character set. ### Screen Ruler - - Added a Setting to also allow showing measurements in inches, centimeters or millimeters. Thanks [@Sophanatprime](https://github.com/Sophanatprime)! + - Fixed an issue causing line breaks to not be parsed correctly for REG_MULTI_SZ values. Thanks [@htcfreek](https://github.com/htcfreek)! + - Added a tooltip to values to show multiple lines of data. Thanks [@htcfreek](https://github.com/htcfreek)! + - Added a context menu to enable copying type, value and key paths. Thanks [@htcfreek](https://github.com/htcfreek)! ### Settings - - Fixed an issue causing all the links to milestones in the "What's new?" OOBE page to point to the same milestone. - - Removed extra space from the Welcome page. Thanks [@agarwalishita](https://github.com/agarwalishita)! - - Updated left navigation bar icons. Thanks [@niels9001](https://github.com/niels9001)! - - Fixed accessibility issues in the dashboard page. Thanks [@davidegiacometti](https://github.com/davidegiacometti)! + - Made the Advanced Paste paste OpenAI configuration modal scrollable. + - Fixed the text on the Quick Accent page to refer to "character sets" instead of "character set". Thanks [@PesBandi](https://github.com/PesBandi)! + - Added the plugin's dll file version and website to the PowerToys Run plugin settings. Thanks [@htcfreek](https://github.com/htcfreek)! + - Added the Workspaces file to the list of files that gets backed up by the Back up / Restore functionality. + - Fixed an issue causing some of the selected character sets to be unselected when opening the character set expander in the Quick Accent page. + - Improved GPO logic, icons, info bar layout and enabled state of all modules settings pages. Thanks [@htcfreek](https://github.com/htcfreek)! + - Fixed some accessibility issues and refactored and improved quality of the code related to image sizes in the Image Resizer page. Thanks [@daverayment](https://github.com/daverayment)! + - Fixed mentions of "Backup" to "Back up" when it should be used as a verb. Thanks [@JackStuart](https://github.com/JackStuart)! + - Added a "New" label to Settings to better highlight new utilities that get released. Thanks [@niels9001](https://github.com/niels9001) for the UI tweaks! + +### Text Extractor + + - Fixed many accessibility and UI issues on the overlay UI. Thanks [@davidegiacometti](https://github.com/davidegiacometti)! ### Workspaces - - Added support for Progressive Web Applications to Workspaces. - - Implemented a feature to move existing windows instead of creating new ones. - - Fixed a crash when opening the workspaces editor that was caused by passing incorrect encoder parameters when saving Bitmap files. - - Workspaces editor position is now saved so that we can start it at the same position when we open it again. - - Fixed an issue causing many instances of the same application to be put in the same position instead of the intended position due to timer issues. - - Fixed detection of exact application version when many versions of the same application are installed. + - Fixed an issue causing the Workspaces Editor to start outside of visible desktop area. + - Fixed an issue to maintain command line arguments for applications when trying using the "Launch and Edit" feature. + +### Video Conference Mute + + - The module has been deprecated in 0.88.0, being removed from PowerToys. + +### ZoomIt + + - New utility: Zoom It - a screen zoom, annotation, and recording tool for technical presentations and demos. This utility from Sysinternals has had its source code released and included in PowerToys. ZoomIt will still continue to be updated and shipped by Sysinternals for users who prefer to have it as a standalone utility outside of PowerToys. Thanks [@markrussinovich](https://github.com/markrussinovich), [@foxmsft](https://github.com/foxmsft) and [@johnstep](https://github.com/johnstep) for contributing the original code and reviewing the PowerToys integration! ### Documentation - - Improved language in CONTRIBUTE.md. Thanks [@sanskaarz](https://github.com/sanskaarz)! - - Added Bilibili plugin mention to thirdPartyRunPlugins.md. Thanks [@Whuihuan](https://github.com/Whuihuan)! - - Added CanIUse and TailwindCSS plugins mention to thirdPartyRunPlugins.md. Thanks [@skttl](https://github.com/skttl)! - - Added HttpStatusCodes plugin mention to thirdPartyRunPlugins.md. Thanks [@grzhan](https://github.com/grzhan)! - - Updated COMMUNITY.md with more contributors. + - Updated the PowerToys Run documentation to reflect documentation pages for new plugins. + - Added YubicoOauthOTP plugin mention to thirdPartyRunPlugins.md. Thanks [@dlnilsson](https://github.com/dlnilsson)! ### Development - - Upgraded to .NET 9. Thanks [@snickler](https://github.com/snickler)! - - Fixed building on Visual Studio 17.12. - - Upgraded the System.IO.Abstractions dependency to 21.0.29. Thanks [@davidegiacometti](https://github.com/davidegiacometti)! - - Upgraded the WindowsAppSDK dependency to 1.6.241114003. Thanks [@shuaiyuanxx](https://github.com/shuaiyuanxx)! - - Upgraded the MSTest dependency to 3.6.3. Thanks [@Youssef1313](https://github.com/Youssef1313)! - - Upgraded the check-spelling CI dependency to 0.0.24 and fixed related spell checking issues. Thanks [@jsoref](https://github.com/jsoref)! - - Removed duplicate names from the spellcheck allowed names file. Thanks [@htcfreek](https://github.com/htcfreek)! - - Improved logging of asynchronous methods call stacks when logging an error. - - Created a MSBuild props file to be imported by other projects to enable AOT support. - - Made the Peek utility source code AOT compatible. - - Updated .editorconfig rules to relax squiggly IDE errors in Visual Studio 17.12. Thanks [@snickler](https://github.com/snickler)! - - Moved Xaml.Styler from the root to the src folder. + - Added fuzz testing for AdvancedPaste, with a new pipeline for OneFuzz. + - Added a new CI pipeline to build with the latest WindowsAppSDK. + - Added a new CI pipeline to build with the latest webview2 from Edge Canary. + - Made the HostsUILib project AOT compatible. Thanks [@snickler](https://github.com/snickler) for your help reviewing this! + - Made FilePreviewCommon and MarkdownPreviewHandler AOT compatible. Thanks [@snickler](https://github.com/snickler) for your help reviewing this! + - Made the PowerAccent.Core project AOT compatible. Thanks [@snickler](https://github.com/snickler) for your help reviewing this! + - Cleaned up some code for AOT compatibility in the Advanced Paste module. Thanks [@snickler](https://github.com/snickler) for your help reviewing this! + - Removed the prerelease flag from the PowerToys development DSC configurations. Thanks [@denelon](https://github.com/denelon)! + - Improved Dart CI reliability by improving error messages and retrying to the step that installs the correct dotnet version. + - Improved Dart CI reliability by fixing retries when downloading the localization files. + - Improved Dart CI build times by removing the steps to build the no longer needed abstracted utility nuget packages. + - Removed the solution.props file from the solution root. + - Fixed PowerToys Run Calculator plugin tests when running in systems with different number formats. Thanks [@htcfreek](https://github.com/htcfreek)! + - Updated many .NET packages from .NET 9.0.0 to 9.0.1 for security fixes. Thanks [@snickler](https://github.com/snickler)! + - Refactored the Mouse Without Borders Common.Log.cs and Common.Receiver.cs files. Thanks [@mikeclayton](https://github.com/mikeclayton)! #### What is being planned for version 0.88 -For [v0.88][github-next-release-work], we'll work on the items below: +For [v0.89][github-next-release-work], we'll work on the items below: - Stability / bug fixes - New module: File Actions Menu - - Integrate Sysinternals ZoomIt + - PowerToys Run v2 development work ## PowerToys Community diff --git a/src/common/ManagedTelemetry/Telemetry/DataDiagnosticsSettings.cs b/src/common/ManagedTelemetry/Telemetry/DataDiagnosticsSettings.cs index 0a9aa7c89175..0a537e899124 100644 --- a/src/common/ManagedTelemetry/Telemetry/DataDiagnosticsSettings.cs +++ b/src/common/ManagedTelemetry/Telemetry/DataDiagnosticsSettings.cs @@ -20,16 +20,16 @@ public static bool GetEnabledValue() try { registryValue = Registry.GetValue(DataDiagnosticsRegistryKey, DataDiagnosticsRegistryValueName, 0); + + if (registryValue is not null) + { + return (int)registryValue == 1 ? true : false; + } } catch { } - if (registryValue is not null) - { - return (int)registryValue == 1 ? true : false; - } - return false; } diff --git a/src/common/SettingsAPI/settings_helpers.cpp b/src/common/SettingsAPI/settings_helpers.cpp index 25d9719a6673..ad17c36caf6b 100644 --- a/src/common/SettingsAPI/settings_helpers.cpp +++ b/src/common/SettingsAPI/settings_helpers.cpp @@ -174,9 +174,8 @@ namespace PTSettingsHelper return; } - const bool value = enabled; - const size_t buf_size = sizeof(bool); - if (RegSetValueExW(key, DataDiagnosticsRegValueName, 0, REG_QWORD, reinterpret_cast(&value), buf_size) != ERROR_SUCCESS) + const DWORD value = enabled ? 1 : 0; + if (RegSetValueExW(key, DataDiagnosticsRegValueName, 0, REG_DWORD, reinterpret_cast(&value), sizeof(value)) != ERROR_SUCCESS) { RegCloseKey(key); return; diff --git a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/dllmain.cpp b/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/dllmain.cpp index 56fde2622c5f..3d4e15a91d49 100644 --- a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/dllmain.cpp +++ b/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/dllmain.cpp @@ -65,6 +65,7 @@ namespace class AdvancedPaste : public PowertoyModuleIface { private: + AdvancedPasteProcessManager m_process_manager; bool m_enabled = false; diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Clipboard.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Clipboard.cs index 7654b0452d04..3f5ace6900e5 100644 --- a/src/modules/MouseWithoutBorders/App/Class/Common.Clipboard.cs +++ b/src/modules/MouseWithoutBorders/App/Class/Common.Clipboard.cs @@ -262,6 +262,10 @@ private static void SendClipboardDataUsingTCP(byte[] bytes, bool image) new Task(() => { + // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again. + // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892 + using var asyncFlowControl = ExecutionContext.SuppressFlow(); + System.Threading.Thread thread = Thread.CurrentThread; thread.Name = $"{nameof(SendClipboardDataUsingTCP)}.{thread.ManagedThreadId}"; Thread.UpdateThreads(thread); @@ -386,6 +390,10 @@ internal static void GetRemoteClipboard(string postAction) new Task(() => { + // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again. + // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892 + using var asyncFlowControl = ExecutionContext.SuppressFlow(); + System.Threading.Thread thread = Thread.CurrentThread; thread.Name = $"{nameof(ConnectAndGetData)}.{thread.ManagedThreadId}"; Thread.UpdateThreads(thread); diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs index ccbec575081b..a27df9a073da 100644 --- a/src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs +++ b/src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs @@ -72,6 +72,10 @@ private static void WatchDogThread() private static void HelperThread() { + // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again. + // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892 + using var asyncFlowControl = System.Threading.ExecutionContext.SuppressFlow(); + try { while (true) diff --git a/src/modules/MouseWithoutBorders/App/Class/Program.cs b/src/modules/MouseWithoutBorders/App/Class/Program.cs index 011b1cfdc975..3e3795f6efd3 100644 --- a/src/modules/MouseWithoutBorders/App/Class/Program.cs +++ b/src/modules/MouseWithoutBorders/App/Class/Program.cs @@ -379,6 +379,10 @@ internal static void StartInputCallbackThread() private static void InputCallbackThread() { + // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again. + // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892 + using var asyncFlowControl = ExecutionContext.SuppressFlow(); + Common.InputCallbackThreadID = Thread.CurrentThread.ManagedThreadId; while (!Common.InitDone) { diff --git a/src/modules/MouseWithoutBorders/App/Class/SocketStuff.cs b/src/modules/MouseWithoutBorders/App/Class/SocketStuff.cs index 31b047a837e5..d7ff395ce974 100644 --- a/src/modules/MouseWithoutBorders/App/Class/SocketStuff.cs +++ b/src/modules/MouseWithoutBorders/App/Class/SocketStuff.cs @@ -681,6 +681,10 @@ internal int TcpSend(TcpSk tcp, DATA data) private void TCPServerThread(object param) { + // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again. + // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892 + using var asyncFlowControl = ExecutionContext.SuppressFlow(); + try { TcpListener server = param as TcpListener; @@ -768,6 +772,10 @@ private void StartNewTcpServer(TcpSk tcp, string machineName) { void ServerThread() { + // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again. + // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892 + using var asyncFlowControl = ExecutionContext.SuppressFlow(); + try { // Receiving packages @@ -876,6 +884,10 @@ internal void StartNewTcpClient(string machineName) { void ClientThread(object obj) { + // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again. + // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892 + using var asyncFlowControl = ExecutionContext.SuppressFlow(); + IPHostEntry host; bool useName2IP = false; List validAddresses = new(); @@ -1117,6 +1129,10 @@ private void StartNewTcpClientThread(string machineName, IPAddress ip) { void NewTcpClient() { + // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again. + // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892 + using var asyncFlowControl = ExecutionContext.SuppressFlow(); + TcpClient tcpClient = null; try @@ -1549,6 +1565,10 @@ private void MainTCPRoutine(TcpSk tcp, string machineName, bool isClient) private static void AcceptConnectionAndSendClipboardData(object param) { + // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again. + // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892 + using var asyncFlowControl = ExecutionContext.SuppressFlow(); + TcpListener server = param as TcpListener; do @@ -1590,6 +1610,10 @@ private static void AcceptConnectionAndSendClipboardData(object param) { new Task(() => { + // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again. + // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892 + using var asyncFlowControl = ExecutionContext.SuppressFlow(); + System.Threading.Thread thread = Thread.CurrentThread; thread.Name = $"{nameof(SendOrReceiveClipboardData)}.{thread.ManagedThreadId}"; Thread.UpdateThreads(thread); diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h b/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h index 66ac6deccc85..5df9dda1fea1 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h @@ -343,6 +343,21 @@ namespace newplus::utilities } } + inline void update_last_write_time(const std::filesystem::path path) + { + const std::filesystem::file_time_type now = std::filesystem::file_time_type::clock::now(); + + std::filesystem::last_write_time(path, now); + + if (std::filesystem::is_directory(path)) + { + for (const auto& entry : std::filesystem::recursive_directory_iterator(path)) + { + std::filesystem::last_write_time(entry.path(), now); + } + } + } + inline HRESULT copy_template(const template_item* template_entry, const ComPtr site_of_folder) { HRESULT hr = S_OK; @@ -376,6 +391,9 @@ namespace newplus::utilities // Copy file and determine final filename std::filesystem::path target_final_fullpath = template_entry->copy_object_to(GetActiveWindow(), target_fullpath); + // Touch all files and set last modified to "now" + update_last_write_time(target_final_fullpath); + // Consider copy completed. If we do tracing after enter_rename_mode, then rename mode won't consistently work trace.UpdateState(true); Trace::EventCopyTemplate(target_final_fullpath.extension().c_str()); diff --git a/src/modules/ZoomIt/ZoomIt/Zoomit.cpp b/src/modules/ZoomIt/ZoomIt/Zoomit.cpp index c8ac0ebcde4e..d198616bbc00 100644 --- a/src/modules/ZoomIt/ZoomIt/Zoomit.cpp +++ b/src/modules/ZoomIt/ZoomIt/Zoomit.cpp @@ -6023,6 +6023,12 @@ LRESULT APIENTRY MainWndProc( // Apply tray icon setting EnableDisableTrayIcon(hWnd, g_ShowTrayIcon); + // This is also called by ZoomIt when it starts and loads the Settings. Opacity is added after loading from registry, so we use the same pattern. + if ((g_PenColor >> 24) == 0) + { + g_PenColor |= 0xFF << 24; + } + // Apply hotkey settings UnregisterAllHotkeys(hWnd); g_ToggleMod = GetKeyMod(g_ToggleKey); @@ -7416,6 +7422,12 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance if( !ShowEula( APPNAME, NULL, NULL )) return 1; #ifdef __ZOOMIT_POWERTOYS__ + if (powertoys_gpo::getConfiguredZoomItEnabledValue() == powertoys_gpo::gpo_rule_configured_disabled) + { + Logger::warn(L"Tried to start with a GPO policy setting the utility to always be disabled. Please contact your systems administrator."); + return 1; + } + Shared::Trace::ETWTrace* trace = nullptr; std::wstring pid = std::wstring(lpCmdLine); // The PowerToys pid is the argument to the process. auto mainThreadId = GetCurrentThreadId(); @@ -7423,12 +7435,6 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance { g_StartedByPowerToys = TRUE; - if (powertoys_gpo::getConfiguredZoomItEnabledValue() == powertoys_gpo::gpo_rule_configured_disabled) - { - Logger::warn(L"Tried to start with a GPO policy setting the utility to always be disabled. Please contact your systems administrator."); - return 1; - } - trace = new Shared::Trace::ETWTrace(); Trace::RegisterProvider(); trace->UpdateState(true); diff --git a/src/modules/ZoomIt/ZoomItSettingsInterop/ZoomItSettings.cpp b/src/modules/ZoomIt/ZoomItSettingsInterop/ZoomItSettings.cpp index 3a197714b782..3eb3e235daa5 100644 --- a/src/modules/ZoomIt/ZoomItSettingsInterop/ZoomItSettings.cpp +++ b/src/modules/ZoomIt/ZoomItSettingsInterop/ZoomItSettings.cpp @@ -105,9 +105,12 @@ namespace winrt::PowerToys::ZoomItSettingsInterop::implementation } else if (special_semantics->second == SPECIAL_SEMANTICS_COLOR) { - // PowerToys settings likes colors as #FFFFFF strings. + /* PowerToys settings likes colors as #FFFFFF strings. + But currently these Settings are internal state for ZoomIt, not something that we really need to send Settings. + Code is kept here as a reference if a future color Setting ends up being configured. hstring s = winrt::to_hstring(std::format("#{:02x}{:02x}{:02x}", value & 0xFF, (value >> 8) & 0xFF, (value >> 16) & 0xFF)); _settings.add_property(curSetting->ValueName, s); + */ } } break; @@ -211,6 +214,9 @@ namespace winrt::PowerToys::ZoomItSettingsInterop::implementation } else if (special_semantics->second == SPECIAL_SEMANTICS_COLOR) { + /* PowerToys settings likes colors as #FFFFFF strings. + But currently these Settings are internal state for ZoomIt, not something that we really need to save from Settings. + Code is kept here as a reference if a future color Setting ends up being configured. auto possibleValue = valuesFromSettings.get_string_value(curSetting->ValueName); if (possibleValue.has_value()) { @@ -219,8 +225,8 @@ namespace winrt::PowerToys::ZoomItSettingsInterop::implementation { *static_cast(curSetting->Setting) = RGB(r, g, b); } - } + */ } } break; diff --git a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.Calculator/Main.cs b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.Calculator/Main.cs index cc1a61e000ea..7b109fbed983 100644 --- a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.Calculator/Main.cs +++ b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.Calculator/Main.cs @@ -13,6 +13,7 @@ using Microsoft.PowerToys.Run.Plugin.Calculator.Properties; using Microsoft.PowerToys.Settings.UI.Library; using Wox.Plugin; +using Wox.Plugin.Logger; namespace Microsoft.PowerToys.Run.Plugin.Calculator { @@ -212,8 +213,18 @@ public void UpdateSettings(PowerLauncherPluginSettings settings) var optionReplaceInput = settings.AdditionalOptions.FirstOrDefault(x => x.Key == ReplaceInput); replaceInput = optionReplaceInput?.Value ?? replaceInput; - var optionTrigMode = settings.AdditionalOptions.FirstOrDefault(x => x.Key == TrigMode); - trigMode = (CalculateEngine.TrigMode)int.Parse(optionTrigMode.ComboBoxValue.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture); + try + { + var optionTrigMode = settings.AdditionalOptions.FirstOrDefault(x => x.Key == TrigMode); + if (optionTrigMode != null) + { + trigMode = (CalculateEngine.TrigMode)int.Parse(optionTrigMode.ComboBoxValue.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture); + } + } + catch (Exception ex) + { + Log.Exception("Error while trying to load Trigonometry Mode setting: {ex.Message}", ex, GetType()); + } } _inputUseEnglishFormat = inputUseEnglishFormat; diff --git a/src/settings-ui/Settings.UI.Library/ImageSize.cs b/src/settings-ui/Settings.UI.Library/ImageSize.cs index 7bbad59726e6..017f66582014 100644 --- a/src/settings-ui/Settings.UI.Library/ImageSize.cs +++ b/src/settings-ui/Settings.UI.Library/ImageSize.cs @@ -3,241 +3,119 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Text.Json; using System.Text.Json.Serialization; +using Settings.UI.Library.Resources; -namespace Microsoft.PowerToys.Settings.UI.Library -{ - public class ImageSize : INotifyPropertyChanged - { - public ImageSize(int id) - { - Id = id; - Name = string.Empty; - Fit = ResizeFit.Fit; - Width = 0; - Height = 0; - Unit = ResizeUnit.Pixel; - } - - public ImageSize() - { - Id = 0; - Name = string.Empty; - Fit = ResizeFit.Fit; - Width = 0; - Height = 0; - Unit = ResizeUnit.Pixel; - } - - public ImageSize(int id, string name, ResizeFit fit, double width, double height, ResizeUnit unit) - { - Id = id; - Name = name; - Fit = fit; - Width = width; - Height = height; - Unit = unit; - } +namespace Microsoft.PowerToys.Settings.UI.Library; - private int _id; - private string _name; - private ResizeFit _fit; - private double _height; - private double _width; - private ResizeUnit _unit; - - public int Id - { - get - { - return _id; - } - - set - { - if (_id != value) - { - _id = value; - OnPropertyChanged(); - } - } - } - - public int ExtraBoxOpacity - { - get - { - if (Unit == ResizeUnit.Percent && Fit != ResizeFit.Stretch) - { - return 0; - } - else - { - return 100; - } - } - } +public partial class ImageSize : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler PropertyChanged; - public bool EnableEtraBoxes + private bool SetProperty(ref T field, T value, [CallerMemberName] string propertyName = null) + { + bool changed = !EqualityComparer.Default.Equals(field, value); + if (changed) { - get - { - if (Unit == ResizeUnit.Percent && Fit != ResizeFit.Stretch) - { - return false; - } - else - { - return true; - } - } + field = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(AccessibleTextHelper))); } - [JsonPropertyName("name")] - public string Name - { - get - { - return _name; - } + return changed; + } - set - { - if (_name != value) - { - _name = value; - OnPropertyChanged(); - } - } - } + public ImageSize(int id = 0, string name = "", ResizeFit fit = ResizeFit.Fit, double width = 0, double height = 0, ResizeUnit unit = ResizeUnit.Pixel) + { + Id = id; + Name = name; + Fit = fit; + Width = width; + Height = height; + Unit = unit; + } - [JsonPropertyName("fit")] - public ResizeFit Fit - { - get - { - return _fit; - } + private int _id; + private string _name; + private ResizeFit _fit; + private double _height; + private double _width; + private ResizeUnit _unit; - set - { - if (_fit != value) - { - _fit = value; - OnPropertyChanged(); - OnPropertyChanged(nameof(ExtraBoxOpacity)); - OnPropertyChanged(nameof(EnableEtraBoxes)); - } - } - } + public int Id + { + get => _id; + set => SetProperty(ref _id, value); + } - [JsonPropertyName("width")] - public double Width - { - get - { - return _width; - } + /// + /// Gets a value indicating whether the property is used. When false, the + /// property is used to evenly scale the image in both X and Y dimensions. + /// + [JsonIgnore] + public bool IsHeightUsed + { + // Height is ignored when using percentage scaling where the aspect ratio is maintained + // (i.e. non-stretch fits). In all other cases, both Width and Height are needed. + get => !(Unit == ResizeUnit.Percent && Fit != ResizeFit.Stretch); + } - set - { - double newWidth = -1; - - if (value < 0 || double.IsNaN(value)) - { - newWidth = 0; - } - else - { - newWidth = value; - } - - if (_width != newWidth) - { - _width = newWidth; - OnPropertyChanged(); - } - } - } + [JsonPropertyName("name")] + public string Name + { + get => _name; + set => SetProperty(ref _name, value); + } - [JsonPropertyName("height")] - public double Height + [JsonPropertyName("fit")] + public ResizeFit Fit + { + get => _fit; + set { - get - { - return _height; - } - - set + if (SetProperty(ref _fit, value)) { - double newHeight = -1; - - if (value < 0 || double.IsNaN(value)) - { - newHeight = 0; - } - else - { - newHeight = value; - } - - if (_height != newHeight) - { - _height = newHeight; - OnPropertyChanged(); - } + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsHeightUsed))); } } + } - [JsonPropertyName("unit")] - public ResizeUnit Unit - { - get - { - return _unit; - } - - set - { - if (_unit != value) - { - _unit = value; - OnPropertyChanged(); - OnPropertyChanged(nameof(ExtraBoxOpacity)); - OnPropertyChanged(nameof(EnableEtraBoxes)); - } - } - } + [JsonPropertyName("width")] + public double Width + { + get => _width; + set => SetProperty(ref _width, value < 0 || double.IsNaN(value) ? 0 : value); + } - public event PropertyChangedEventHandler PropertyChanged; + [JsonPropertyName("height")] + public double Height + { + get => _height; + set => SetProperty(ref _height, value < 0 || double.IsNaN(value) ? 0 : value); + } - public void OnPropertyChanged([CallerMemberName] string propertyName = null) + [JsonPropertyName("unit")] + public ResizeUnit Unit + { + get => _unit; + set { - var handler = PropertyChanged; - if (handler != null) + if (SetProperty(ref _unit, value)) { - handler(this, new PropertyChangedEventArgs(propertyName)); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsHeightUsed))); } } + } - public void Update(ImageSize modifiedSize) - { - ArgumentNullException.ThrowIfNull(modifiedSize); - - Id = modifiedSize.Id; - Name = modifiedSize.Name; - Fit = modifiedSize.Fit; - Width = modifiedSize.Width; - Height = modifiedSize.Height; - Unit = modifiedSize.Unit; - } + /// + /// Gets access to all properties for formatting accessibility descriptions. + /// + [JsonIgnore] + public ImageSize AccessibleTextHelper => this; - public string ToJsonString() - { - return JsonSerializer.Serialize(this); - } - } + public string ToJsonString() => JsonSerializer.Serialize(this); } diff --git a/src/settings-ui/Settings.UI.Library/ZoomItProperties.cs b/src/settings-ui/Settings.UI.Library/ZoomItProperties.cs index 3cd756267368..936c08689e84 100644 --- a/src/settings-ui/Settings.UI.Library/ZoomItProperties.cs +++ b/src/settings-ui/Settings.UI.Library/ZoomItProperties.cs @@ -44,12 +44,6 @@ public ZoomItProperties() public KeyboardKeysProperty SnipToggleKey { get; set; } - public StringProperty PenColor { get; set; } - - public IntProperty PenWidth { get; set; } - - public StringProperty BreakPenColor { get; set; } - public KeyboardKeysProperty BreakTimerKey { get; set; } public StringProperty Font { get; set; } @@ -80,24 +74,14 @@ public ZoomItProperties() public BoolProperty BreakShowDesktop { get; set; } - public BoolProperty BreakOnSecondary { get; set; } - - public IntProperty FontScale { get; set; } - public BoolProperty ShowExpiredTime { get; set; } public BoolProperty ShowTrayIcon { get; set; } public BoolProperty AnimnateZoom { get; set; } - public BoolProperty TelescopeZoomOut { get; set; } - - public BoolProperty SnapToGrid { get; set; } - public IntProperty ZoominSliderLevel { get; set; } - public IntProperty RecordFrameRate { get; set; } - public IntProperty RecordScaling { get; set; } public BoolProperty CaptureAudio { get; set; } diff --git a/src/settings-ui/Settings.UI.UnitTests/ViewModelTests/ImageResizer.cs b/src/settings-ui/Settings.UI.UnitTests/ViewModelTests/ImageResizer.cs index 1d2c62daecf1..c5175bc180e4 100644 --- a/src/settings-ui/Settings.UI.UnitTests/ViewModelTests/ImageResizer.cs +++ b/src/settings-ui/Settings.UI.UnitTests/ViewModelTests/ImageResizer.cs @@ -205,7 +205,7 @@ public void EncoderShouldUpdateValueWhenSuccessful() } [TestMethod] - public void AddRowShouldAddNewImageSizeWhenSuccessful() + public void AddImageSizeShouldAddNewImageSizeWhenSuccessful() { // arrange var mockSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils(); @@ -214,7 +214,7 @@ public void AddRowShouldAddNewImageSizeWhenSuccessful() int sizeOfOriginalArray = viewModel.Sizes.Count; // act - viewModel.AddRow("New size"); + viewModel.AddImageSize(); // Assert Assert.AreEqual(sizeOfOriginalArray + 1, viewModel.Sizes.Count); @@ -229,15 +229,15 @@ public void NewlyAddedImageSizeHasCorrectValues() ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils.Object, SettingsRepository.GetInstance(_mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, (string name) => name); // act - viewModel.AddRow("New size"); + viewModel.AddImageSize("New size"); // Assert ImageSize newTestSize = viewModel.Sizes.First(x => x.Id == 0); - Assert.AreEqual(newTestSize.Name, "New size 1"); - Assert.AreEqual(newTestSize.Fit, ResizeFit.Fit); - Assert.AreEqual(newTestSize.Width, 854); - Assert.AreEqual(newTestSize.Height, 480); - Assert.AreEqual(newTestSize.Unit, ResizeUnit.Pixel); + Assert.AreEqual("New size 1", newTestSize.Name); + Assert.AreEqual(ResizeFit.Fit, newTestSize.Fit); + Assert.AreEqual(1024, newTestSize.Width); + Assert.AreEqual(640, newTestSize.Height); + Assert.AreEqual(ResizeUnit.Pixel, newTestSize.Unit); } [TestMethod] @@ -247,7 +247,7 @@ public void DeleteImageSizeShouldDeleteImageSizeWhenSuccessful() var mockSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils(); Func sendMockIPCConfigMSG = msg => { return 0; }; ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils.Object, SettingsRepository.GetInstance(_mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, (string name) => name); - viewModel.AddRow("New Size"); + viewModel.AddImageSize("New Size"); int sizeOfOriginalArray = viewModel.Sizes.Count; ImageSize deleteCandidate = viewModel.Sizes.First(x => x.Id == 0); @@ -268,16 +268,16 @@ public void NameOfNewImageSizesIsIncrementedCorrectly() ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils.Object, SettingsRepository.GetInstance(_mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, (string name) => name); // act - viewModel.AddRow("New size"); // Add: "New size 1" - viewModel.AddRow("New size"); // Add: "New size 2" - viewModel.AddRow("New size"); // Add: "New size 3" + viewModel.AddImageSize("New size"); // Add: "New size 1" + viewModel.AddImageSize("New size"); // Add: "New size 2" + viewModel.AddImageSize("New size"); // Add: "New size 3" viewModel.DeleteImageSize(1); // Delete: "New size 2" - viewModel.AddRow("New size"); // Add: "New Size 4" + viewModel.AddImageSize("New size"); // Add: "New Size 4" // Assert - Assert.AreEqual(viewModel.Sizes[0].Name, "New size 1"); - Assert.AreEqual(viewModel.Sizes[1].Name, "New size 3"); - Assert.AreEqual(viewModel.Sizes[2].Name, "New size 4"); + Assert.AreEqual("New size 1", viewModel.Sizes[0].Name); + Assert.AreEqual("New size 3", viewModel.Sizes[1].Name); + Assert.AreEqual("New size 4", viewModel.Sizes[2].Name); } [TestMethod] diff --git a/src/settings-ui/Settings.UI/Converters/ImageResizerFitToStringConverter.cs b/src/settings-ui/Settings.UI/Converters/ImageResizerFitToStringConverter.cs index bfc991c07090..22ecd928436d 100644 --- a/src/settings-ui/Settings.UI/Converters/ImageResizerFitToStringConverter.cs +++ b/src/settings-ui/Settings.UI/Converters/ImageResizerFitToStringConverter.cs @@ -3,41 +3,38 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Globalization; - +using System.Windows; +using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.UI.Xaml.Data; -namespace Microsoft.PowerToys.Settings.UI.Converters +namespace Microsoft.PowerToys.Settings.UI.Converters; + +public sealed partial class ImageResizerFitToStringConverter : IValueConverter { - public sealed partial class ImageResizerFitToStringConverter : IValueConverter + // Maps each ResizeFit to its localized string. + private static readonly Dictionary FitToText = new() { - public object Convert(object value, Type targetType, object parameter, string language) - { - var toLower = false; - if ((string)parameter == "ToLower") - { - toLower = true; - } - - string targetValue = string.Empty; - switch (value) - { - case 0: targetValue = Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Fit_Fill_ThirdPersonSingular"); break; - case 1: targetValue = Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Fit_Fit_ThirdPersonSingular"); break; - case 2: targetValue = Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Fit_Stretch_ThirdPersonSingular"); break; - } - - if (toLower) - { - targetValue = targetValue.ToLower(CultureInfo.CurrentCulture); - } - - return targetValue; - } + { ResizeFit.Fill, Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Fit_Fill_ThirdPersonSingular") }, + { ResizeFit.Fit, Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Fit_Fit_ThirdPersonSingular") }, + { ResizeFit.Stretch, Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Fit_Stretch_ThirdPersonSingular") }, + }; - public object ConvertBack(object value, Type targetType, object parameter, string language) + public object Convert(object value, Type targetType, object parameter, string language) + { + if (value is ResizeFit fit && FitToText.TryGetValue(fit, out string fitText)) { - return value; + return parameter is string lowerParam && lowerParam == "ToLower" ? + fitText.ToLower(CultureInfo.CurrentCulture) : + fitText; } + + return DependencyProperty.UnsetValue; + } + + public object ConvertBack(object value, Type targetType, object parameter, string language) + { + return value; } } diff --git a/src/settings-ui/Settings.UI/Converters/ImageResizerSizeToAccessibleTextConverter.cs b/src/settings-ui/Settings.UI/Converters/ImageResizerSizeToAccessibleTextConverter.cs new file mode 100644 index 000000000000..3fd03b08d64d --- /dev/null +++ b/src/settings-ui/Settings.UI/Converters/ImageResizerSizeToAccessibleTextConverter.cs @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Windows; +using Microsoft.PowerToys.Settings.UI.Library; +using Microsoft.UI.Xaml.Data; + +namespace Microsoft.PowerToys.Settings.UI.Converters; + +/// +/// Creates accessibility text for controls related to properties. +/// +/// (Name) "Edit the Small preset" +/// (FullDescription) "Large - Fits within 1920 × 1080 pixels"" +public sealed partial class ImageResizerSizeToAccessibleTextConverter : IValueConverter +{ + private const char TimesGlyph = '\u00D7'; // Unicode "MULTIPLICATION SIGN" + + /// + /// Maps the supplied accessibility identifier to the format string of the localized accessible text. + /// + private static readonly Dictionary AccessibilityFormats = new() + { + { "Edit", Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_EditButton_Accessibility_Name") }, + { "Remove", Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_RemoveButton_Accessibility_Name") }, + }; + + private readonly ImageResizerFitToStringConverter _fitConverter = new(); + private readonly ImageResizerUnitToStringConverter _unitConverter = new(); + + public object Convert(object value, Type targetType, object parameter, string language) + { + return (value, parameter) switch + { + (string presetName, string nameId) => FormatNameText(presetName, nameId), + (ImageSize preset, string _) => FormatDescriptionText(preset), + _ => DependencyProperty.UnsetValue, + }; + } + + private object FormatNameText(string presetName, string nameId) + { + return AccessibilityFormats.TryGetValue(nameId, out string format) ? + string.Format(CultureInfo.CurrentCulture, format, presetName) : + DependencyProperty.UnsetValue; + } + + private object FormatDescriptionText(ImageSize preset) + { + if (preset == null) + { + return DependencyProperty.UnsetValue; + } + + string fitText = _fitConverter.Convert(preset.Fit, typeof(string), null, null) as string; + string unitText = _unitConverter.Convert(preset.Unit, typeof(string), null, null) as string; + + return preset.IsHeightUsed ? + $"{preset.Name} - {fitText} {preset.Width} {TimesGlyph} {preset.Height} {unitText}" : + $"{preset.Name} - {fitText} {preset.Width} {unitText}"; + } + + public object ConvertBack(object value, Type targetType, object parameter, string language) + { + throw new NotImplementedException(); + } +} diff --git a/src/settings-ui/Settings.UI/Converters/ImageResizerUnitToStringConverter.cs b/src/settings-ui/Settings.UI/Converters/ImageResizerUnitToStringConverter.cs index ab4aec819550..fca73cfa0760 100644 --- a/src/settings-ui/Settings.UI/Converters/ImageResizerUnitToStringConverter.cs +++ b/src/settings-ui/Settings.UI/Converters/ImageResizerUnitToStringConverter.cs @@ -3,42 +3,39 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Globalization; - +using System.Windows; +using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.UI.Xaml.Data; -namespace Microsoft.PowerToys.Settings.UI.Converters +namespace Microsoft.PowerToys.Settings.UI.Converters; + +public sealed partial class ImageResizerUnitToStringConverter : IValueConverter { - public sealed partial class ImageResizerUnitToStringConverter : IValueConverter + // Maps each ResizeUnit value to its localized string. + private static readonly Dictionary UnitToText = new() { - public object Convert(object value, Type targetType, object parameter, string language) - { - var toLower = false; - if ((string)parameter == "ToLower") - { - toLower = true; - } - - string targetValue = string.Empty; - switch (value) - { - case 0: targetValue = Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Unit_Centimeter"); break; - case 1: targetValue = Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Unit_Inch"); break; - case 2: targetValue = Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Unit_Percent"); break; - case 3: targetValue = Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Unit_Pixel"); break; - } - - if (toLower) - { - targetValue = targetValue.ToLower(CultureInfo.CurrentCulture); - } - - return targetValue; - } + { ResizeUnit.Centimeter, Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Unit_Centimeter") }, + { ResizeUnit.Inch, Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Unit_Inch") }, + { ResizeUnit.Percent, Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Unit_Percent") }, + { ResizeUnit.Pixel, Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Unit_Pixel") }, + }; - public object ConvertBack(object value, Type targetType, object parameter, string language) + public object Convert(object value, Type targetType, object parameter, string language) + { + if (value is ResizeUnit unit && UnitToText.TryGetValue(unit, out string unitText)) { - return value; + return parameter is string lowerParam && lowerParam == "ToLower" ? + unitText.ToLower(CultureInfo.CurrentCulture) : + unitText; } + + return DependencyProperty.UnsetValue; + } + + public object ConvertBack(object value, Type targetType, object parameter, string language) + { + return value; } } diff --git a/src/settings-ui/Settings.UI/Helpers/OpenFileName.cs b/src/settings-ui/Settings.UI/Helpers/OpenFileName.cs index 3d7c1d8e902a..2a48deecef42 100644 --- a/src/settings-ui/Settings.UI/Helpers/OpenFileName.cs +++ b/src/settings-ui/Settings.UI/Helpers/OpenFileName.cs @@ -33,4 +33,10 @@ public class OpenFileName public IntPtr Hook = IntPtr.Zero; public string Template; } + + // https://learn.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-openfilenamea + public enum OpenFileNameFlags + { + OFN_NOCHANGEDIR = 0x00000008, + } } diff --git a/src/settings-ui/Settings.UI/SettingsXAML/App.xaml b/src/settings-ui/Settings.UI/SettingsXAML/App.xaml index 6e65f31069f3..365c592d2764 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/App.xaml +++ b/src/settings-ui/Settings.UI/SettingsXAML/App.xaml @@ -11,6 +11,7 @@ + diff --git a/src/settings-ui/Settings.UI/SettingsXAML/OOBE/Views/OobeCmdPal.xaml.cs b/src/settings-ui/Settings.UI/SettingsXAML/OOBE/Views/OobeCmdPal.xaml.cs index 45298e85faa8..6db561bfbc0d 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/OOBE/Views/OobeCmdPal.xaml.cs +++ b/src/settings-ui/Settings.UI/SettingsXAML/OOBE/Views/OobeCmdPal.xaml.cs @@ -11,14 +11,14 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views { - public sealed partial class OobeCmdPal : Page + public sealed partial class OobeZoomIt : Page { public OobePowerToysModule ViewModel { get; set; } - public OobeCmdPal() + public OobeZoomIt() { this.InitializeComponent(); - ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModules.CmdPal]); + ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModules.ZoomIt]); DataContext = ViewModel; } @@ -26,7 +26,7 @@ private void SettingsLaunchButton_Click(object sender, Microsoft.UI.Xaml.RoutedE { if (OobeShellPage.OpenMainWindowCallback != null) { - OobeShellPage.OpenMainWindowCallback(typeof(CmdPalPage)); + OobeShellPage.OpenMainWindowCallback(typeof(ZoomItPage)); } ViewModel.LogOpeningSettingsEvent(); diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Styles/InfoBadge.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Styles/InfoBadge.xaml new file mode 100644 index 000000000000..a4a5a2611169 --- /dev/null +++ b/src/settings-ui/Settings.UI/SettingsXAML/Styles/InfoBadge.xaml @@ -0,0 +1,23 @@ + + + + \ No newline at end of file diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Views/DashboardPage.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Views/DashboardPage.xaml index 0e26afcaace6..b48ddf66c80d 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Views/DashboardPage.xaml +++ b/src/settings-ui/Settings.UI/SettingsXAML/Views/DashboardPage.xaml @@ -348,17 +348,28 @@ - + - + Orientation="Horizontal"> + + + - + - + Orientation="Horizontal"> + + + + + Visibility="{x:Bind IsHeightUsed, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" /> + Visibility="{x:Bind IsHeightUsed, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />