MIT License
Copyright © 2020 Xander Frangos
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
## NuGet Packages used by PowerToys
- AdaptiveCards.ObjectModel.WinUI3
- AdaptiveCards.Rendering.WinUI3
- AdaptiveCards.Templating
- Appium.WebDriver
- CoenM.ImageSharp.ImageHash
- CommunityToolkit.Common
- CommunityToolkit.Labs.WinUI.Controls.MarkdownTextBlock
- CommunityToolkit.Labs.WinUI.Controls.OpacityMaskView
- CommunityToolkit.Mvvm
- CommunityToolkit.WinUI.Animations
- CommunityToolkit.WinUI.Collections
- CommunityToolkit.WinUI.Controls.Primitives
- CommunityToolkit.WinUI.Controls.Segmented
- CommunityToolkit.WinUI.Controls.SettingsControls
- CommunityToolkit.WinUI.Controls.Sizers
- CommunityToolkit.WinUI.Converters
- CommunityToolkit.WinUI.Extensions
- CommunityToolkit.WinUI.UI.Controls.DataGrid
- ControlzEx
- HelixToolkit
- HelixToolkit.Core.Wpf
- hyjiacan.pinyin4net
- Interop.Microsoft.Office.Interop.OneNote
- LazyCache
- Mages
- Markdig.Signed
- MessagePack
- ModernWpfUI
- Moq
- MSTest
- MSTest.TestFramework
- NJsonSchema
- NLog
- NLog.Extensions.Logging
- NLog.Schema
- OpenAI
- Polly.Core
- ReverseMarkdown
- ScipBe.Common.Office.OneNote
- SharpCompress
- Shmuelie.WinRTServer
- SkiaSharp.Views.WinUI
- StreamJsonRpc
- StyleCop.Analyzers
- ToolGood.Words.Pinyin
- UnicodeInformation
- UnitsNet
- UTF.Unknown
- WinUIEx
- WmiLight
- WPF-UI
- WyHash
================================================
FILE: PowerToys.slnx
================================================
================================================
FILE: README.md
================================================
Microsoft PowerToys
Microsoft PowerToys is a collection of utilities that help you customize Windows and streamline everyday tasks.
## 🔨 Utilities
PowerToys includes over 30 utilities to help you customize and optimize your Windows experience:
| | | |
| --- | --- | --- |
| [ Advanced Paste](https://aka.ms/PowerToysOverview_AdvancedPaste) | [ Always on Top](https://aka.ms/PowerToysOverview_AoT) | [ Awake](https://aka.ms/PowerToysOverview_Awake) |
| [ Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) | [ Command Not Found](https://aka.ms/PowerToysOverview_CmdNotFound) | [ Command Palette](https://aka.ms/PowerToysOverview_CmdPal) |
| [ Crop And Lock](https://aka.ms/PowerToysOverview_CropAndLock) | [ Environment Variables](https://aka.ms/PowerToysOverview_EnvironmentVariables) | [ FancyZones](https://aka.ms/PowerToysOverview_FancyZones) |
| [ File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) | [ File Locksmith](https://aka.ms/PowerToysOverview_FileLocksmith) | [ Hosts File Editor](https://aka.ms/PowerToysOverview_HostsFileEditor) |
| [ Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [ Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) | [ Light Switch](https://aka.ms/PowerToysOverview_LightSwitch) |
| [ Mouse Utilities](https://aka.ms/PowerToysOverview_MouseUtilities) | [ Mouse Without Borders](https://aka.ms/PowerToysOverview_MouseWithoutBorders) | [ New+](https://aka.ms/PowerToysOverview_NewPlus) |
| [ Peek](https://aka.ms/PowerToysOverview_Peek) | [ 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_ZoomIt) | | |
## 📦 Installation
For detailed installation instructions and system requirements, visit the [installation docs](https://learn.microsoft.com/windows/powertoys/install).
But to get started quickly, choose one of the installation methods below:
Download the .exe file from GitHub
Go to the [PowerToys GitHub releases](https://aka.ms/installPowerToys), select **Assets** to reveal the installation files, and choose the one that matches your architecture and install scope. For most devices, that would be _x64 per-user_.
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.99%22
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.98.1/PowerToysUserSetup-0.98.1-x64.exe
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.98.1/PowerToysUserSetup-0.98.1-arm64.exe
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.98.1/PowerToysSetup-0.98.1-x64.exe
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.98.1/PowerToysSetup-0.98.1-arm64.exe
| Description | Filename |
| --- | --- |
| Per user - x64 | [PowerToysUserSetup-0.98.1-x64.exe][ptUserX64] |
| Per user - ARM64 | [PowerToysUserSetup-0.98.1-arm64.exe][ptUserArm64] |
| Machine wide - x64 | [PowerToysSetup-0.98.1-x64.exe][ptMachineX64] |
| Machine wide - ARM64 | [PowerToysSetup-0.98.1-arm64.exe][ptMachineArm64] |
Microsoft Store
You can easily install PowerToys from the Microsoft Store:
WinGet
Download PowerToys from [WinGet](https://github.com/microsoft/winget-cli#installing-the-client). Updating PowerToys via winget will respect the current PowerToys installation scope. To install PowerToys, run the following command from the command line / PowerShell:
- User scope installer (default)
```powershell
winget install Microsoft.PowerToys -s winget
```
- Machine-wide scope installer
```powershell
winget install --scope machine Microsoft.PowerToys -s winget
```
Other methods
There are [community driven install methods](https://learn.microsoft.com/windows/powertoys/install#community-driven-install-tools) such as Chocolatey and Scoop. If these are your preferred install solutions, you can find the install instructions there.
## ✨ What's new?
[](https://github.com/microsoft/PowerToys/releases)
To see what's new, check out the [release notes](https://github.com/microsoft/PowerToys/releases/tag/v0.98.1).
## 🛣️ Roadmap
We are planning some nice new features and improvements for the next releases – PowerDisplay, Command Palette improvements and a brand-new Shortcut Guide experience! Stay tuned for [v0.99][github-next-release-work]!
## ❤️ PowerToys Community
The PowerToys team is extremely grateful to have the [support of an amazing active community][community-link]. The work you do is incredibly important. PowerToys wouldn't be nearly what it is today without your help filing bugs, updating documentation, guiding the design, or writing features. We want to say thank you and take time to recognize your work. Your contributions and feedback improve PowerToys month after month!
## Contributing
This project welcomes contributions of all types. Besides coding features / bug fixes, other ways to assist include spec writing, design, documentation, and finding bugs. We are excited to work with the power user community to build a set of tools for helping you get the most out of Windows. We ask that **before you start work on a feature that you would like to contribute**, please read our [Contributor's Guide](CONTRIBUTING.md). We would be happy to work with you to figure out the best approach, provide guidance and mentorship throughout feature development, and help avoid any wasted or duplicate effort. Most contributions require you to agree to a [Contributor License Agreement (CLA)][oss-CLA] declaring that you grant us the rights to use your contribution and that you have permission to do so. For guidance on developing for PowerToys, please read the [developer docs](./doc/devdocs) for a detailed breakdown. This includes how to setup your computer to compile.
## Code of conduct
This project has adopted the [Microsoft Open Source Code of Conduct][oss-conduct-code].
## Privacy statement
The application logs basic diagnostic data (telemetry). For more privacy information and what we collect, see our [PowerToys Data and Privacy documentation](https://aka.ms/powertoys-data-and-privacy-documentation).
[oss-CLA]: https://cla.opensource.microsoft.com
[oss-conduct-code]: CODE_OF_CONDUCT.md
[community-link]: COMMUNITY.md
================================================
FILE: SECURITY.md
================================================
# Security
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin).
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below.
## Reporting security issues
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report).
If you prefer to submit without logging in, send an email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp).
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
- Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
- Full paths of source file(s) related to the manifestation of the issue
- The location of the affected source code (tag/branch/commit or direct URL)
- Any special configuration required to reproduce the issue
- Step-by-step instructions to reproduce the issue
- Proof-of-concept or exploit code (if possible)
- Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs.
## Preferred languages
We prefer all communications to be in English.
## Policy
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd).
================================================
FILE: SUPPORT.md
================================================
# Support
## How to use Microsoft PowerToys
For more information about PowerToys overviews, how to use the utilities, and other tools and resources for [Windows development environments](https://learn.microsoft.com/windows/dev-environment/overview), visit [learn.microsoft.com][usingPowerToys-docs-link].
## How to file issues and get help
This project uses [GitHub Issues][gh-issue] to [track bugs][gh-bug] and [feature requests][gh-feature]. Please search the existing issues before filing new issues to avoid duplicates. For new issues, file your bug or feature request as a new issue.
For help and questions about using this project, please visit our documentation and [Contributor's Guide][contributor] if you want to contribute to PowerToys.
## Microsoft support policy
Support for PowerToys is limited to the resources listed above.
[gh-issue]: https://github.com/microsoft/PowerToys/issues/new/choose
[gh-bug]: https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=Issue-Bug&template=bug_report.md
[gh-feature]: https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=&template=feature_request.md
[contributor]: https://github.com/microsoft/PowerToys/blob/main/CONTRIBUTING.md
[usingPowerToys-docs-link]: https://aka.ms/powertoys-docs
================================================
FILE: deps/expected.props
================================================
$(MSBuildThisFileDirectory)expected-lite\include\nonstd\;%(AdditionalIncludeDirectories)
================================================
FILE: deps/spdlog.props
================================================
$(MSBuildThisFileDirectory)spdlog\include;%(AdditionalIncludeDirectories)
SPDLOG_WCHAR_TO_UTF8_SUPPORT;SPDLOG_COMPILED_LIB;SPDLOG_WCHAR_FILENAMES;%(PreprocessorDefinitions)
================================================
FILE: doc/devdocs/akaLinks.md
================================================
# Full list of aka links
| ShortUrl | TargetUrl |
|----------|----------|
| getpowertoys | ms-windows-store://pdp/?productid=XP89DCGQ3K6VLD |
| installpowertoys | https://github.com/microsoft/PowerToys/releases/latest |
| powertoys-license | https://github.com/microsoft/PowerToys/blob/main/LICENSE |
| powertoys | https://github.com/microsoft/PowerToys |
| PowerToysAppCompat | https://github.com/microsoft/PowerToys/wiki/Application-Compatibility |
| powerToysCannotRemapKeys | https://learn.microsoft.com/windows/powertoys/keyboard-manager#keys-that-cannot-be-remapped |
| powerToysColorPickerImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/ColorPicker_small.png |
| powerToysColorPickerSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/ColorPicker_large.png |
| powertoysDetectedElevatedHelp | https://learn.microsoft.com/windows/powertoys/administrator |
| powertoys-docs | https://learn.microsoft.com/windows/powertoys |
| powerToysFancyZoneImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/FancyZones_small.png |
| powerToysFancyZoneSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/FancyZones_large.png |
| powerToysGiveFeedback | https://github.com/microsoft/PowerToys/issues |
| powerToysImageResizerImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/ImageResizer_small.png |
| powerToysImageResizerSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/ImageResizer_large.png |
| powerToysKBMImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/KBM_small.png |
| powerToysKBMSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/KBM_large.png |
| PowerToysOverview | https://learn.microsoft.com/windows/powertoys/ |
| PowerToysOverview_ColorPicker | https://learn.microsoft.com/windows/powertoys/color-picker |
| PowerToysOverview_FancyZones | https://learn.microsoft.com/windows/powertoys/fancyzones |
| PowerToysOverview_FileExplorerAddOns | https://learn.microsoft.com/windows/powertoys/file-explorer |
| PowerToysOverview_ImageResizer | https://learn.microsoft.com/windows/powertoys/image-resizer |
| PowerToysOverview_KeyboardManager | https://learn.microsoft.com/windows/powertoys/keyboard-manager |
| PowerToysOverview_MouseUtilities | https://learn.microsoft.com/windows/powertoys/mouse-utilities |
| PowerToysOverview_PowerRename | https://learn.microsoft.com/windows/powertoys/powerrename |
| PowerToysOverview_PowerToysRun | https://learn.microsoft.com/windows/powertoys/run |
| PowerToysOverview_ShortcutGuide | https://learn.microsoft.com/windows/powertoys/shortcut-guide |
| powerToysPowerLauncherImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/PowerLauncher_small.png |
| powerToysPowerLauncherSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/PowerLauncher_large.png |
| powerToysPowerPreviewImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/PowerPreview_small.png |
| powerToysPowerPreviewSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/PowerPreview_large.png |
| powerToysPowerRenameImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/PowerRename_small.png |
| powerToysPowerRenameSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/PowerRename_large.png |
| powerToysPTImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/PT_small.png |
| powerToysPTSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/PT_large.png |
| powerToysReportBug | https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=Issue-Bug%2CTriage-Needed&template=bug_report.yml&title= |
| powerToysRequestFeature | https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=&template=feature_request.md&title= |
| powerToysShortcutGuideImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/ShortcutGuide_small.png |
| powerToysShortcutGuideSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/ShortcutGuide_large.png |
| powertoyswiki | https://github.com/microsoft/PowerToys/wiki |
================================================
FILE: doc/devdocs/cli-conventions.md
================================================
# CLI Conventions
This document describes the conventions for implementing command-line interfaces (CLI) in PowerToys modules.
## Library
Use the **System.CommandLine** library for CLI argument parsing. This is already defined in `Directory.Packages.props`:
```xml
```
Add the reference to your project:
```xml
```
## Option Naming and Definition
- Use `--kebab-case` for long form (e.g., `--shrink-only`).
- Use single `-x` for short form (e.g., `-s`, `-w`).
- Define aliases as static readonly arrays: `["--silent", "-s"]`.
- Create options using `Option` with descriptive help text.
- Add validators for options that require range or format checking.
## RootCommand Setup
- Create a `RootCommand` with a brief description.
- Add all options and arguments to the command.
## Parsing
- Use `Parser(rootCommand).Parse(args)` to parse CLI arguments.
- Extract option values using `parseResult.GetValueForOption()`.
- Note: Use `Parser` directly; `RootCommand.Parse()` may not be available with the pinned System.CommandLine version.
### Parse/Validation Errors
- On parse/validation errors, print error messages and usage, then exit with non-zero code.
## Examples
Reference implementations:
- Awake: `src/modules/Awake/Awake/Program.cs`
- ImageResizer: `src/modules/imageresizer/ui/Cli/`
## Help Output
- Provide a `PrintUsage()` method for custom help formatting if needed.
## Best Practices
1. **Consistency**: Follow existing module patterns.
2. **Documentation**: Always provide help text for each option.
3. **Validation**: Validate input and provide clear error messages.
4. **Atomicity**: Make one logical change per PR; avoid drive-by refactors.
5. **Build/Test Discipline**: Build and test synchronously, one terminal per operation.
6. **Style**: Follow repo analyzers (`.editorconfig`, StyleCop) and formatting rules.
## Logging Requirements
- Use `ManagedCommon.Logger` for consistent logging.
- Initialize logging early in `Main()`.
- Use dual output (console + log file) for errors and warnings to ensure visibility.
- Reference: `src/modules/imageresizer/ui/Cli/CliLogger.cs`
## Error Handling
### Exit Codes
- `0`: Success
- `1`: General error (parsing, validation, runtime)
- `2`: Invalid arguments (optional)
### Exception Handling
- Always wrap `Main()` in try-catch for unhandled exceptions.
- Log exceptions before exiting with non-zero code.
- Display user-friendly error messages to stderr.
- Preserve detailed stack traces in log files only.
## Testing Requirements
- Include tests for argument parsing, validation, and edge cases.
- Place CLI tests in module-specific test projects (e.g., `src/modules/[module]/tests/*CliTests.cs`).
## Signing and Deployment
- CLI executables are signed automatically in CI/CD.
- **New CLI tools**: Add your executable and dll to `.pipelines/ESRPSigning_core.json` in the signing list.
- CLI executables are deployed alongside their parent module (e.g., `C:\Program Files\PowerToys\modules\[ModuleName]\`).
- Use self-contained deployment (import `Common.SelfContained.props`).
================================================
FILE: doc/devdocs/commands.md
================================================
# Issue/PR commands
The PowerToys repository uses some special keywords to help manage issues and pull requests. Here is a list of the most important commands you can use in issue and PR descriptions or comments.
| Command | Description |
|---------|-------------|
| `/azp run` | Triggers the Azure Pipelines CI build for the current PR. Useful if you want to re-run the build without creating a new commit. |
| `/bugreport` / `/reportbug` | Adds a comment with a manual for the Bug Report Tool, which helps users collect logs and system information for debugging purposes. It requests to upload this file and adds the `Needs-Author-Feedback` label. |
| `/feedbackhub` | Adds a comment with a link to the Feedback Hub app on Windows, where users can submit feedback about PowerToys. Closes the issue and adds the `Resolution-Please File on Feedback Hub` label. |
| `/dup #...` / `/duplicate #...` / `/dup https://...` / `/duplicate https://...` | Marks the current issue as a duplicate of another issue. It closes the current issue and applies the `Resolution-Duplicate` label. Replace `#...` with the issue number or a link to the issue. |
| `/needinfo` | Adds the `Needs-Author-Feedback` label to the issue or PR, indicating that more information is needed from the author. |
| `/helped` | Closes the issue and adds the `Resolution-Helped User` label. Furthermore a comment is added with a link to the PowerToys user documentation. |
| `/loc` | Adds a comment informing the user that the issue was forwarded to the localization team and will soon be fixed. It adds the `Loc-Sent To Team` label. |
## Defining new commands
Most of these commands are using the [Microsoft GitHub Policy Service](https://github.com/apps/microsoft-github-policy-service) bot. Its commands are defined in the [PowerToys policy configuration file](/.github/policies/resourceManagement.yml).
## Other automated tasks
### Automatic labeling
The bot can automatically apply the correct `product-...` label for any opened issue.
> [!NOTE]
> This feature is currently only available for the Workspaces module as a test.
### The `Needs-Author-Feedback` label
If an issue has this label and had no activity for 5 days, the bot will post a comment reminding the author to provide the needed information. It also adds the `Status-No recent activity` label. If no further activity occurs for another 5 days, the bot will close the issue.
### Filtering users that want to contribute
If a user utters their intention to contribute (e.g., by using the phrase "I want to contribute" in an issue or PR), the bot will add a comment with a link to the ["Would you like to contribute to PowerToys?" thread](https://github.com/microsoft/PowerToys/issues/28769).
================================================
FILE: doc/devdocs/common/FilePreviewCommon.md
================================================
# [FilePreviewCommon](/src/common/FilePreviewCommon)
This project contains common code used for previewing and displaying files.
## Monaco preview
Monaco preview enables to display developer files. It is based on [Microsoft's Monaco Editor](https://microsoft.github.io/monaco-editor/) which is maintained by the Visual Studio Code team.
This previewer is used for the File Explorer Dev File Previewer, as well as PowerToys Peek.
For a general overview of how Monaco is used in PowerToys, see the [Monaco Editor documentation](monaco-editor.md).
### Update Monaco Editor
1. Download Monaco editor with [npm](https://www.npmjs.com/): Run `npm i monaco-editor` in the command prompt.
2. Delete everything except the `min` folder (the minimised code) from the downloaded files.
3. Copy the `min` folder into the `/src/Monaco/monacoSRC` folder of the PowerToys project.
4. Generate the JSON file as described in the generate [monaco_languages.json file](#monaco_languagesjson) section.
### Add a new language definition
As an example on how to add a new language definition you can look at the one for [registry files](/src/Monaco/customLanguages/reg.js).
1. Add the new language definition (written with [Monarch](https://microsoft.github.io/monaco-editor/monarch.html)) as a new file to the [folder containing Monaco custom languages](/src/Monaco/customLanguages/) (Remember the file name and the string you used for "idDefinition" as you need it later.). The file should be formatted like in the example below. (Please change `idDefinition` to the name of your language.)
```javascript
export function idDefinition() {
return {
...
}
}
```
2. Add the following line to the [`monacoSpecialLanguages.js`](/src/Monaco/monacoSpecialLanguages.js) file, after the other import statements:
```javascript
import { idDefinition } from './customLanguages/file.js';
```
> Replace file.js with the name of your definition file from step 1. Please replace idDefinition with the string you used in step 1.
3. In the [`monacoSpecialLanguages.js`](/src/Monaco/monacoSpecialLanguages.js) file add the following line into the `registerAdditionalLanguages` function:
```javascript
registerAdditionalNewLanguage("id", [".fileExtension"], idDefinition(), monaco)
```
> Replace id and idDefinition with your id and string used in step 1. Replace fileExtension with a set of file extensions you want the language to register to.
* The id can be anything. Recommended is one of the file extensions. For example "php" or "reg".
4. In case you wish to add a custom color for a token, you can do so by adding the following line to [`customTokenThemeRules.js`](/src/Monaco/customTokenThemeRules.js):
```javascript
{token: 'token-name', foreground: 'ff0000'}
```
> Replace `token-name` with the name of the token and `ff0000` with the hex code of the desired color.
> Note: you can also specify a `background` and a `fontStyle` attribute for your token.
* Keep in mind that these rules apply to all languages. Therefore, you should not change the colors of any default tokens. Instead, create new tokens specific to the language you are adding.
5. Execute the steps described in the [monaco_languages.json](#monaco_languagesjson) section.
### Add a new file extension to an existing language
1. In the [`monacoSpecialLanguages.js`](/src/Monaco/monacoSpecialLanguages.js) file add the following line to the `registerAdditionalLanguages` function. (`existingId` is the id of the language you want to add the extension to. You can find these id's in the [`monaco_languages.json`](/src/Monaco/monaco_languages.json) file):
```javascript
registerAdditionalLanguage("id", [".fileExtension"], "existingId", monaco)
```
* If for instance you want to add more extensions to the php language set the id to `phpExt` and the existingId to `php`.
2. Copy the existing language definition into the `languageDefinitions` function in the same file. You can find the existing definitions in the following folder: [`/src/Monaco/monacoSRC/min/vs/basic-languages/`](/src/Monaco/monacoSRC/min/vs/basic-languages/).
3. Execute the steps described in the [monaco_languages.json](#monaco_languagesjson) section.
### monaco_languages.json
[`monaco_languages.json`](/src/Monaco/monaco_languages.json) contains all extensions and IDs for the languages supported by Monaco. The [`MonacoHelper`](/src/common/FilePreviewCommon/MonacoHelper.cs) class and the installer are using this file to register preview handlers for the defined extensions.
After updating Monaco Editor and/or adding a new language you should update the [`monaco_languages.json`](/src/Monaco/monaco_languages.json) file.
1. Run the [`generateLanguagesJson.html`](/src/Monaco/generateLanguagesJson.html) file on a local webserver (as webbrowsers will block certain needed features when running the file locally.)
* This can for example be achieved by using the [Preview Server](https://marketplace.visualstudio.com/items?itemName=yuichinukiyama.vscode-preview-server) extension for Visual Studio Code: Open the file in Visual Studio Code, right click in the code editor and select `vscode-preview-server: Launch on browser`. The file will be opened in a browser.
2. The browser will download the new `monaco_languages.json` file
3. Replace the old file with the newly downloaded one in the source code folder.
================================================
FILE: doc/devdocs/common/common.md
================================================
# Classes and structures
> This document is outdated and will soon be renewed.
#### class Animation: [header](/src/common/animation.h) [source](/src/common/animation.cpp)
Animation helper class with two easing-in animations: linear and exponential.
#### class AsyncMessageQueue: [header](/src/common/async_message_queue.h)
Header-only asynchronous message queue. Used by `TwoWayPipeMessageIPC`.
#### class TwoWayPipeMessageIPC: [header](/src/common/two_way_pipe_message_ipc.h)
Header-only asynchronous IPC messaging class. Used by the runner to communicate with the settings window.
#### class DPIAware: [header](/src/common/dpi_aware.h) [source](/src/common/dpi_aware.cpp)
Helper class for creating DPI-aware applications.
#### struct MonitorInfo: [header](/src/common/monitors.h) [source](/src/common/monitors.cpp)
Class for obtaining information about physical displays connected to the machine.
#### class Settings, class PowerToyValues, class CustomActionObject: [header](/src/common/settings_objects.h) [source](/src/common/settings_objects.cpp)
Classes used to define settings screens for the PowerToys modules.
#### class Tasklist: [header](/src/common/tasklist_positions.h) [source](/src/common/tasklist_positions.cpp)
Class that can detect the position of the windows buttons on the taskbar. It also detects which window will react to pressing `WinKey + number`.
#### struct WindowsColors: [header](/src/common/windows_colors.h) [source](/src/common/windows_colors.cpp)
Class for detecting the current Windows color scheme.
# Helpers
#### Common helpers: [header](/src/common/common.h) [source](/src/common/common.cpp)
Various helper functions.
#### Settings helpers: [header](/src/common/settings_helpers.h)
Helper methods for the settings.
#### Start visible helper: [header](/src/common/start_visible.h) [source](/src/common/start_visible.cpp)
Contains function to test if the Start menu is visible.
# Toast Notifications
#### Notifications API [header](/src/common/notifications.h) [source](/src/common/notifications.cpp)
To use UWP-style toast notifications, simply include the header and call one of these functions:
```cpp
void show_toast(std::wstring_view message); // #1
void show_toast_background_activated( // #2
std::wstring_view message,
std::wstring_view background_handler_id,
std::vector button_labels);
```
We might add more functions in the future if the need arises, e.g. `show_toast_xml` which will accept raw XML for rich customization.
Description:
- `#1` is for sending simple notifications without any callbacks or buttons
- `#2` is capable of showing a toast with multiple buttons and background activation
- `message` is a plain-text argument
Implement a toast activation handler/callback as a function in [handler_functions.cpp](/src/common/notifications_winrt/handler_functions.cpp) and register its `background_handler_id` via `handlers_map`, e.g.:
```cpp
// Your .cpp where you'd like to show a toast
#include
void some_func() {
// ...
notifications::show_toast_background_activated(
L"Toast message!", // text displayed in a toast
L"awesome_toast", // activation handler id
{L"Press me!", L"Also could press me!", L"I'm here to be pressed!"} // buttons in a toast
);
```
```cpp
// handler_functions.cpp
void awesome_toast_handler(IBackgroundTaskInstance, const size_t button_id)
{
switch(button_id)
{
case 0:
// handle "Press me!" button click
case 1:
// handle "Also could press me!" button click
case 2:
// handle "I'm here to be pressed!" button click
}
}
namespace
{
const std::unordered_map handlers_map = {
// ...other handlers...
{L"awesome_toast", awesome_toast_handler}
};}
```
Note: since _background activation_ implies that your toast handler will be invoked in a separate process, you can't share data directly from within a handler and your PT process. Also, since PT is currently a Desktop Bridge app, _foreground activation_ is [handled the same as background](https://learn.microsoft.com/windows/uwp/design/shell/tiles-and-notifications/send-local-toast-desktop-cpp-wrl#foreground-vs-background-activation), therefore we don't make a dedicated API for it. You can read more on the [rationale of the current design](https://github.com/microsoft/PowerToys/pull/1178#issue-368768337).
================================================
FILE: doc/devdocs/common/context-menus.md
================================================
# PowerToys Context Menu Handlers
This document describes how context menu handlers are implemented in PowerToys, covering both Windows 10 and Windows 11 approaches.
## Context Menu Implementation Types
PowerToys implements two types of context menu handlers:
1. **Old-Style Context Menu Handlers**
- Used for Windows 10 compatibility
- Registered via registry entries
- Implemented as COM objects exposing the `IContextMenu` interface
- Registered for specific file extensions
2. **Windows 11 Context Menu Handlers**
- Implemented as sparse MSIX packages
- Exposing the `IExplorerCommand` interface
- Located in `PowerToys\x64\Debug\modules\\.msix`
- Registered for all file types and filtered in code
- Requires signing to be installed
## Context Menu Handler Registration Approaches
PowerToys modules use two different approaches for registering context menu handlers:
### 1. Dual Registration (e.g., ImageResizer, PowerRename)
- Both old-style and Windows 11 context menu handlers are registered
- Results in duplicate entries in Windows 11's expanded context menu
- Ensures functionality even if Windows 11 handler fails to appear
- Old-style handlers appear in the "Show more options" expanded menu
### 2. Selective Registration (e.g., NewPlus)
- Windows 10: Uses old-style context menu handler
- Windows 11: Uses new MSIX-based context menu handler
- Avoids duplicates but can cause issues if Windows 11 handler fails to register
## Windows 11 Context Menu Handler Implementation
### Package Registration
- MSIX packages are defined in `AppManifest.xml` in each context menu project
- Registration happens in `DllMain` of the module interface DLL when the module is enabled
- Explorer restart may be required after registration for changes to take effect
- Registration can be verified with `Get-AppxPackage` PowerShell command:
```powershell
Get-AppxPackage -Name *PowerToys*
```
### Technical Implementation
- Handlers implement the `IExplorerCommand` interface
- Key methods:
- `GetState`: Determines visibility based on file type
- `Invoke`: Handles the action when the menu item is clicked
- `GetTitle`: Provides the text to display in the context menu
- For selective filtering (showing only for certain file types), the logic is implemented in the `GetState` method
### Example Implementation Flow
1. Build generates an MSIX package from the context menu project
2. When the module is enabled, PowerToys installs the package using `PackageManager.AddPackageAsync`
3. The package references the DLL that implements the actual context menu handler
4. When the user right-clicks, Explorer loads the DLL and calls into its methods
## Debugging Context Menu Handlers
### Debugging Old-Style (Windows 10) Handlers
1. Update the registry to point to your debug build
2. Restart Explorer
3. Attach the debugger to explorer.exe
4. Set breakpoints and test by right-clicking in File Explorer
### Debugging Windows 11 Handlers
1. Build PowerToys to get the MSIX packages
2. Sign the MSIX package with a self-signed certificate
3. Replace files in the PowerToys installation directory
4. Use PowerToys to install the package
5. Restart Explorer
6. Run Visual Studio as administrator
7. Set breakpoints in relevant code
8. Attach to DllHost.exe process when context menu is triggered
### Debugging Challenges
- Windows 11 handlers require signing and reinstalling for each code change
- DllHost loads the DLL only when context menu is triggered and unloads after
- For efficient development, use logging or message boxes instead of breakpoints
- Consider debugging the Windows 10 handler by removing OS version checks
## Common Issues
- Context menu entries not showing in Windows 11
- Usually due to package not being removed/updated properly on PowerToys update
- Fix: Uninstall and reinstall the package or restart Explorer
- Registering packages requires signing
- For local testing, create and install a signing certificate
- Duplicate entries in Windows 11 context menu
- By design for some modules to ensure availability if Windows 11 handler fails
================================================
FILE: doc/devdocs/common/monaco-editor.md
================================================
# Monaco Editor in PowerToys
## Overview
Monaco is the text editor that powers Visual Studio Code. In PowerToys, Monaco is integrated as a component to provide advanced text editing capabilities with features like syntax highlighting, line numbering, and intelligent code editing.
## Where Monaco is Used in PowerToys
Monaco is primarily used in:
- Registry Preview module - For editing registry files
- File Preview handlers - For syntax highlighting when previewing code files
- Peek module - For preview a file
## Technical Implementation
Monaco is embedded into PowerToys' WinUI 3 applications using WebView2. This integration allows PowerToys to leverage Monaco's web-based capabilities within desktop applications.
### Directory Structure
The Monaco editor files are located in the relevant module directories. For example, in Registry Preview, Monaco files are bundled with the application resources.
## Versioning and Updates
### Current Version
The current Monaco version can be found in the `loader.js` file, specifically in the variable named `versionMonaco`.
### Update Process
Updating Monaco requires several steps:
1. Download the latest version of Monaco
2. Replace/override the main folder with the new version
3. Generate the new Monaco language JSON file
4. Override the existing JSON file
For detailed step-by-step instructions, see the [FilePreviewCommon documentation](FilePreviewCommon.md#update-monaco-editor).
#### Estimated Time for Update
The Monaco update process typically takes approximately 30 minutes.
#### Reference PRs
When updating Monaco, you can refer to previous Monaco update PRs as examples, as they mostly involve copy-pasting the Monaco source code with minor adjustments.
## Customizing Monaco
### Adding New Language Definitions
Monaco can be customized to support new language definitions for syntax highlighting:
1. Identify the language you want to add
2. Create or modify the appropriate language definition files
3. Update the Monaco configuration to recognize the new language
For detailed instructions on adding language definitions, see the [FilePreviewCommon documentation](FilePreviewCommon.md#add-a-new-language-definition).
### Adding File Extensions to Existing Languages
To make Monaco handle additional file extensions using existing language definitions:
1. Locate the language mapping configuration
2. Add the new file extension to the appropriate language entry
3. Update the file extension registry
For detailed instructions on adding file extensions, see the [FilePreviewCommon documentation](FilePreviewCommon.md#add-a-new-file-extension-to-an-existing-language).
Example: If Monaco processes TXT files and you want it to preview LOG files the same way, you can add LOG extensions to the TXT language definition.
## Installer Handling
Monaco source files are managed via a script (`Generate-Monaco-wxs.ps1`) that:
1. Automatically generates the installer manifest to include all Monaco files
2. Avoids manually listing all Monaco files in the installer configuration
This approach simplifies maintenance and updates of the Monaco editor within PowerToys.
================================================
FILE: doc/devdocs/common/readme.md
================================================
# Common
The [common](/src/common) folder contains projects with code, that is used in multiple projects.
## [FilePreviewCommon](FilePreviewCommon.md)
This project contains common code for file previewing.
================================================
FILE: doc/devdocs/core/architecture.md
================================================
# PowerToys Architecture
## Module Interface Overview
Each PowerToys utility is defined by a module interface (DLL) that provides a standardized way for the PowerToys Runner to interact with it. The module interface defines:
- Structure for hotkeys
- Name and key for the utility
- Configuration management
- Enable/disable functionality
- Telemetry settings
- Group Policy Object (GPO) configuration
### Types of Modules
1. **Simple Modules** (like Mouse Pointer Crosshairs, Find My Mouse)
- Entirely contained in the module interface
- No external application
- Example: Mouse Pointer Crosshairs implements the module interface directly
2. **External Application Launchers** (like Color Picker)
- Start a separate application (e.g., WPF application in C#)
- Handle events when hotkeys are pressed
- Communication via named pipes or other IPC mechanisms
3. **Context Handler Modules** (like Power Rename)
- Shell extensions for File Explorer
- Add right-click context menu entries
- Windows 11 context menu integration through MSIX
4. **Registry-based Modules** (like Power Preview)
- Register preview handlers and thumbnail providers
- Modify registry keys during enable/disable operations
## Common Dependencies and Libraries
- SPD logs for C++ (centralized logging system)
- CPP Win RT (used by most utilities)
- Common utilities in `common` folder for reuse across modules
- Interop library for C++/C# communication (converted to C++ Win RT)
- Common.UI library has WPF and WinForms dependencies
## Resource Management
- For C++ applications and module interfaces:
- Resource files (.resx) need to be converted to .rc
- Use conversion tools before building
- Different resource approaches:
- WPF applications use .resx files
- WinUI 3 apps use .resw files
- PRI file naming requirements:
- Need to override default names to avoid conflicts during flattening
## Implementation details
### [`Runner`](runner.md)
The PowerToys Runner contains the project for the PowerToys.exe executable.
It's responsible for:
- Loading the individual PowerToys modules.
- Passing registered events to the PowerToys.
- Showing a system tray icon to manage the PowerToys.
- Bridging between the PowerToys modules and the Settings editor.
### [`Interface`](../modules/interface.md)
The definition of the interface used by the [`runner`](/src/runner) to manage the PowerToys. All PowerToys must implement this interface.
### [`Common`](../common.md)
The common lib, as the name suggests, contains code shared by multiple PowerToys components and modules, e.g. [json parsing](/src/common/utils/json.h) and [IPC primitives](/src/common/interop/two_way_pipe_message_ipc.h).
### [`Settings`](settings/readme.md)
Settings v2 is our current settings implementation. Please head over to the dev docs that describe the current settings system.
================================================
FILE: doc/devdocs/core/installer.md
================================================
# PowerToys Installer
## Installer Architecture (WiX 5)
- Uses a bootstrapper to check dependencies and close PowerToys
- MSI defined in product.wxs
- Custom actions in C++ for special operations:
- Getting install folder
- User impersonation
- PowerShell module path retrieval
- GPO checking
- Process termination
### Installer Components
- Separate builds for machine-wide and user-scope installation
- Supports x64 and ARM64
- Custom actions DLL must be signed separately before installer build
- WXS files generated during build process for file components
- Localization handling for resource DLLs
- Firewall exceptions for certain modules
### MSI Installer Build Process
- First builds `PowerToysSetupCustomActionsVNext` DLL and signs it
- Then builds the installer without cleaning, to reuse the signed DLL
- Uses PowerShell scripts to modify .wxs files before build
- Restores original .wxs files after build completes
- Scripts (`applyBuildInfo.ps1` and `generateFileList.ps1`) dynamically update files list for installer
- Helps manage all self-contained dependencies (.NET, WinAppSDK DLLs, etc.)
- Avoids manual maintenance of file lists
### Special Build Processes
- .NET applications need publishing for correct WebView2 DLL inclusion
- WXS files backed up and regenerated during build
- Monaco UI components (JavaScript/HTML) generated during build
- Localization files downloaded from server during CI release builds
## Per-User vs Per-Machine Installation
- Functionality is identical
- Differences:
- Per-User:
- Installed to `%LOCALAPPDATA%\PowerToys`
- Registry entries in HKCU
- Different users can have different installations/settings
- Per-Machine:
- Installed to `Program Files\PowerToys`
- Registry entries in HKLM
- Single installation shared by all users
- Default is now Per-User installation
- Guards prevent installing both types simultaneously
## MSIX Usage in PowerToys
- Context menu handlers for Windows 11 use sparse MSIX packages
- Previous attempts to create full MSIX installers were abandoned
- Command Palette will use MSIX when merged into PowerToys
- The main PowerToys application still uses MSI for installation
### MSIX Packaging and Extensions
- MSIX packages for extensions (like context menus) are included in the PowerToys installer
- The MSIX files are built as part of the PowerToys build process
- MSIX files are saved directly into the root folder with base application files
- The installer includes MSIX files but doesn't install them automatically
- Packages are registered when a module is enabled
- Code in `package.h` checks if a package is registered and verifies the version
- Packages will be installed if a version mismatch is detected
- When uninstalling PowerToys, the system checks for installed packages with matching display names and attempts to uninstall them
## GPO Files (Group Policy Objects)
- GPO files for x64 and ARM64 are identical
- Only one set is needed
- GPO files in pipeline are copies of files in source
## Installer Debugging
- Can only build installer in Release mode
- Typically debug using logs and message boxes
- Logs located in:
- `%LOCALAPPDATA%\Temp\PowerToys_bootstrapper_*.log` - MSI tool logs
- `%LOCALAPPDATA%\Temp\PowerToys_*.log` - Custom installer logs
- Logs in Bug Reports are useful for troubleshooting installation issues
### Building PowerToys Locally
#### One stop script for building installer
1. Open `Developer PowerShell for VS`.
2. Run tools\build\build-installer.ps1
> For the first-time setup, please run the installer as an administrator. This ensures that the Wix tool can move wix.target to the desired location and trust the certificate used to sign the MSIX packages.
The following manual steps will not install the MSIX apps (such as Command Palette) on your local installer.
#### Prerequisites for building the MSI installer
PowerToys uses WiX v5 for creating installers. The WiX v5 tools are automatically installed during the build process via dotnet tool.
For manual installation of WiX v5 tools:
```powershell
dotnet tool install --global wix --version 5.0.2
```
> **Note:** As of release 0.94, PowerToys has migrated from WiX v3 to WiX v5. The WiX v3 toolset is no longer required.
#### Building prerequisite projects
##### From the command line
1. From the start menu, open a `Developer Command Prompt for VS`
1. Ensure `nuget.exe` is in your `%path%`
1. In the repo root, run these commands:
```
nuget restore .\tools\BugReportTool\BugReportTool.sln
msbuild -p:Platform=x64 -p:Configuration=Release .\tools\BugReportTool\BugReportTool.sln
nuget restore .\tools\StylesReportTool\StylesReportTool.sln
msbuild -p:Platform=x64 -p:Configuration=Release .\tools\StylesReportTool\StylesReportTool.sln
```
##### From Visual Studio
If you prefer, you can alternatively build prerequisite projects for the installer using the Visual Studio UI.
1. Open `tools\BugReportTool\BugReportTool.sln`
1. In Visual Studio, in the `Solutions Configuration` drop-down menu select `Release`
1. From the `Build` menu, choose `Build Solution`.
1. Open `tools\StylesReportTool\StylesReportTool.sln`
1. In Visual Studio, in the `Solutions Configuration` drop-down menu select `Release`
1. From the `Build` menu, choose `Build Solution`.
#### Locally compiling the installer
1. Open `installer\PowerToysSetup.slnx`
1. In Visual Studio, in the `Solutions Configuration` drop-down menu select `Release`
1. From the `Build` menu choose `Build Solution`.
The resulting installer will be available in the `installer\PowerToysSetupVNext\x64\Release\` folder.
To build the installer from the command line, run `Developer Command Prompt for VS` in admin mode and execute the following commands. The generated installer package will be located at `\installer\PowerToysSetupVNext\{platform}\Release\MachineSetup`.
```
git clean -xfd -e *exe -- .\installer\
MSBuild -t:restore .\installer\PowerToysSetup.slnx -p:RestorePackagesConfig=true /p:Platform="x64" /p:Configuration=Release
MSBuild -t:Restore -m .\installer\PowerToysSetup.slnx /t:PowerToysInstallerVNext /p:Configuration=Release /p:Platform="x64"
MSBuild -t:Restore -m .\installer\PowerToysSetup.slnx /t:PowerToysBootstrapperVNext /p:Configuration=Release /p:Platform="x64"
```
### Supported arguments for the .EXE Bootstrapper installer
Head over to the wiki to see the [full list of supported installer arguments][installerArgWiki].
[installerArgWiki]: https://github.com/microsoft/PowerToys/wiki/Installer-arguments
================================================
FILE: doc/devdocs/core/runner.md
================================================
# PowerToys Runner
The PowerToys Runner is the main executable (`PowerToys.exe`) that loads and manages all PowerToys modules.
## Runner Architecture
The Runner is responsible for:
- Managing the tray icon
- Loading and managing module interfaces
- Handling enabling/disabling modules
- Processing global hotkeys
- Managing updates and settings
### Key Components
- Main CPP file manages the tray icon and modules
- Creates a list of modules with DLL paths
- Special handling for WinUI 3 apps (separated in different folder)
- DLLs flattening for consistent versions
- Runs as part of the Windows message loop
- Creates a window handle with a specific class name
- Registers itself as the window handler for components requiring a window handler
### Process Flow
1. Initialize logger
2. Create single instance application mutex
3. Initialize common utility code
4. Parse command line arguments
5. Start the tray icon
6. Initialize low-level keyboard hooks
7. Load module interfaces from DLLs
8. Start enabled modules
9. Enter Windows message loop
10. On exit, stop modules and clean up resources
## System Tray Icon Implementation
The system tray icon is one of the first components that starts when calling the `render_main` function:
- Defined in `tray_icon.h` and `tray_icon.cpp`
- Creates a popup window and registers as window handler via `start_tray_icon()`
- Processes window messages through `tray_icon_window_proc()`
- Uses `WM_COMMAND` and tray icon notifications for handling menu options
- Handles left mouse clicks (distinguishes between single and double clicks)
- Monitors taskbar creation to re-register the icon if needed
- Uses `shell_notify_icon` to register with the system tray
### Tray Icon Initialization and Message Processing
- `start_tray_icon()` initializes the tray icon by:
- Creating a window with the specified class name
- Setting up the notification icon data structure (NOTIFYICONDATA)
- Registering for taskbar recreate messages
- Adding the icon to the system tray
- `tray_icon_window_proc()` processes window messages, including:
- Handling `wm_icon_notify` messages from tray icon interactions
- Distinguishing between left-click, double-click, and right-click actions
- Showing context menus or opening Settings windows based on interaction type
### Communication with Settings UI
When the tray icon is clicked or a menu option is selected, the Runner communicates with the Settings UI:
- For quick access flyout (left-click):
```cpp
current_settings_ipc->send(L"{\"ShowYourself\":\"flyout\"}");
```
- For the main dashboard (menu option or double-click):
```cpp
current_settings_ipc->send(L"{\"ShowYourself\":\"Dashboard\"}");
```
### IPC Communication Mechanism
- The Runner and Settings UI communicate through Windows Named Pipes
- A two-way pipe (TwoWayPipeMessageIPC) is established between processes
- JSON messages are sent through this pipe to control UI behavior
- The Settings UI initializes the pipe connection on startup:
```csharp
ipcmanager = new TwoWayPipeMessageIPCManaged(cmdArgs[(int)Arguments.SettingsPipeName],
cmdArgs[(int)Arguments.PTPipeName],
(string message) => {
if (IPCMessageReceivedCallback != null && message.Length > 0) {
IPCMessageReceivedCallback(message);
}
});
```
### Settings UI Message Processing
The Settings UI processes incoming IPC messages through a callback chain:
1. Messages from the Runner are received through the IPC callback
2. Messages are parsed as JSON objects
3. Registered handlers in `ShellPage.ShellHandler.IPCResponseHandleList` process the messages
4. The `ReceiveMessage` method in `ShellPage` interprets commands:
- For flyout display: `"ShowYourself": "flyout"`
- For main window: `"ShowYourself": "Dashboard"` or other page names
When showing the flyout, the tray icon can also send position coordinates to place the flyout near the tray icon:
```json
{
"ShowYourself": "flyout",
"x_position": 1234,
"y_position": 567
}
```
The flyout window is then activated and brought to the foreground using native Windows APIs to ensure visibility.
### Tray Icon Menu
- Menus are defined in `.RC` files (Resource files)
- `base.h` defines IDs
- `resources.resx` contains localized strings
- The tray icon window proc handles showing the popup menu
## Centralized Keyboard Hook
- Located in "centralized_keyboard_hook.cpp"
- Handles hotkeys for multiple modules to prevent performance issues
- Contains optimizations to exit early when possible:
- Ignores keystrokes generated by PowerToys itself
- Ignores when no keys are actually pressed
- Uses metadata to avoid re-processing modified inputs
- Performance consideration: handler must run very fast as it's called on every keystroke
## Module Loading Process
1. Scan module directory for DLLs
2. Create the module interface object for each module
3. Load settings for each module
4. Initialize each module
5. Check GPO policies to determine which modules can start
6. Start enabled modules that aren't disabled by policy
## Finding and Messaging the Tray Icon
The tray icon class is used when sending messages to the runner. For example, to close the runner:
```cpp
// Find the window with the PowerToys tray icon class and send it a close message
WM_CLOSE
```
## Key Files and Their Purposes
#### [`main.cpp`](/src/runner/main.cpp)
Contains the executable starting point, initialization code and the list of known PowerToys. All singletons are also initialized here at the start. Loads all the powertoys by scanning the `./modules` folder and `enable()`s those marked as enabled in `%LOCALAPPDATA%\Microsoft\PowerToys\settings.json` config. Then it runs [a message loop](https://learn.microsoft.com/windows/win32/winmsg/using-messages-and-message-queues) for the tray UI. Note that this message loop also [handles lowlevel_keyboard_hook events](https://github.com/microsoft/PowerToys/blob/1760af50c8803588cb575167baae0439af38a9c1/src/runner/lowlevel_keyboard_event.cpp#L24).
#### [`powertoy_module.h`](/src/runner/powertoy_module.h) and [`powertoy_module.cpp`](/src/runner/powertoy_module.cpp)
Contains code for initializing and managing the PowerToy modules. `PowertoyModule` is a RAII-style holder for the `PowertoyModuleIface` pointer, which we got by [invoking module DLL's `powertoy_create` function](https://github.com/microsoft/PowerToys/blob/1760af50c8803588cb575167baae0439af38a9c1/src/runner/powertoy_module.cpp#L13-L24).
#### [`tray_icon.cpp`](/src/runner/tray_icon.cpp)
Contains code for managing the PowerToys tray icon and its menu commands. Note that `dispatch_run_on_main_ui_thread` is used to
transfer received json message from the [Settings window](/doc/devdocs/settings.md) to the main thread, since we're communicating with it from [a dedicated thread](https://github.com/microsoft/PowerToys/blob/7357e40d3f54de51176efe54fda6d57028837b8c/src/runner/settings_window.cpp#L267-L271).
#### [`settings_window.cpp`](/src/runner/settings_window.cpp)
Contains code for starting the PowerToys settings window and communicating with it. Settings window is a separate process, so we're using [Windows pipes](https://learn.microsoft.com/windows/win32/ipc/pipes) as a transport for json messages.
#### [`general_settings.cpp`](/src/runner/general_settings.cpp)
Contains code for loading, saving and applying the general settings.
#### [`auto_start_helper.cpp`](/src/runner/auto_start_helper.cpp)
Contains helper code for registering and unregistering PowerToys to run when the user logs in.
#### [`unhandled_exception_handler.cpp`](/src/runner/unhandled_exception_handler.cpp)
Contains helper code to get stack traces in builds. Can be used by adding a call to `init_global_error_handlers` in [`WinMain`](./main.cpp).
#### [`trace.cpp`](/src/runner/trace.cpp)
Contains code for telemetry.
#### [`svgs`](/src/runner/svgs/)
Contains the SVG assets used by the PowerToys modules.
#### [`bug_report.cpp`](/src/runner/bug_report.cpp)
Contains logic to start bug report tool.
#### [`centralized_hotkeys.cpp`](/src/runner/centralized_hotkeys.cpp)
Contains hot key logic registration and un-registration.
#### [`centralized_kb_hook.cpp`](/src/runner/centralized_kb_hook.cpp)
Contains logic to handle PowerToys' keyboard shortcut functionality.
#### [`restart_elevated.cpp`](/src/runner/restart_elevated.cpp)
Contains logic for restarting the current process with different elevation levels.
#### [`RestartManagement.cpp`](/src/runner/RestartManagement.cpp)
Contains code for restarting a process.
#### [`settings_telemetry.cpp`](/src/runner/settings_telemetry.cpp)
Contains logic that periodically triggers module-specific setting's telemetry delivery and manages timing and error handling for the process.
#### [`UpdateUtils.cpp`](/src/runner/UpdateUtils.cpp)
Contains code to handle the automatic update checking, notification, and installation process for PowerToys.
================================================
FILE: doc/devdocs/core/settings/communication-with-modules.md
================================================
# Communication with modules
## Through runner
- The settings process communicates changes in the UI to most modules using the runner through delegates.
- More details on this are mentioned in [`runner-ipc.md`](runner-ipc.md).
## PT Run
- Any changes to the UI are saved by the settings process in the `settings.json` file located within the `/Local/Microsoft/PowerToys/Launcher/` folder.
- PT Run watches for any changes within this file and updates its general settings or propagates the information to the plugins, depending on the type of information.
Eg: The maximum number of results drop down updates the maximum number of rows in the results list which updates the general settings of PT Run whereas the drive detection checkbox details are dispatched to the indexer plugin.
## Keyboard Manager
- The Settings process and keyboard manager share access to a common `default.json` file which contains information about the remapped keys and shortcuts.
- To ensure that there is no contention while both processes try to access the common file, there is a named file mutex.
- The settings process expects the keyboard manager process to create the `default.json` file if it does not exist. It does not create the file in case it is not present.
================================================
FILE: doc/devdocs/core/settings/compatibility-legacy-settings.md
================================================
# Compatibility with legacy settings and runner
The following must be kept in mind regarding compatibility with settings v1 and runner.
### 1. Folder Naming structure
- Each of the modules has a folder within the `Local/Microsoft/PowerToys` directory which contains the module configurations within the `settings.json` file. The name of this folder must be the same across settingsv1 and settingsv2.
- The name of the settings folder for each powertoy is the same as the `ModuleName`. It is set within each of the viewModel files. This name must not be changed to ensure that the user configurations for each of the powertoys rolls over on update.
### 2. Communication with runner
- The status of each of the modules is communicated with the runner in the form of a json object. The names of all the powerToys is set in the [`EnableModules.cs`](src/settings-ui/Settings.UI.Library/EnabledModules.cs) file. The `JsonPropertyName` must not be changed to ensure that the information is dispatched properly to all the modules by the runner.
### ImageResizer anomaly
All the powertoys have the same folder name as well as JsonPropertyName to communicate information with the runner. However that is not the case with ImageResizer. The folder name is `ImageResizer` whereas the JsonPropertyName has an additional space: `Image Resizer`. This should not be changed to ensure backward compatibility as well as proper functioning of the module.
================================================
FILE: doc/devdocs/core/settings/dsc-configure.md
================================================
# What is it
We would like to enable our users to use [`winget configure`](https://learn.microsoft.com/en-us/windows/package-manager/winget/configure) command to install PowerToys and configure its settings with a [WinGet configuration file](https://learn.microsoft.com/en-us/windows/package-manager/configuration/create). For example:
```yaml
properties:
resources:
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Install PowerToys
allowPrerelease: true
settings:
id: PowerToys (Preview)
source: winget
- resource: PowerToysConfigure
directives:
description: Configure PowerToys
settings:
ShortcutGuide:
Enabled: false
OverlayOpacity: 1
FancyZones:
Enabled: true
FancyzonesEditorHotkey: "Shift+Ctrl+Alt+F"
configurationVersion: 0.2.0
```
This should install PowerToys and make `PowerToysConfigure` resource available. We can use it in the same file.
# How it works
`PowerToysConfigure` is a [class-based DSC resource](https://learn.microsoft.com/en-us/powershell/dsc/concepts/class-based-resources?view=dsc-2.0). It looks up whether each setting was specified or not by checking whether it's `$null` or `0` for `enum`s and invokes `PowerToys.Settings.exe` with the updated value like so:
```
PowerToys.Settings.exe set .
```
So for example the config above should perform 3 following invocations:
```
PowerToys.Settings.exe set ShortcutGuide.Enabled false
PowerToys.Settings.exe set FancyZones.Enabled true
PowerToys.Settings.exe set FancyZones.FancyzonesEditorHotkey "Shift+Ctrl+Alt+F"
```
`PowerToys.Settings` uses dotnet reflection capabilities to determine `SettingName` type and tries to convert the supplied `SettingValue` string accordingly. We use `ICmdReprParsable` for custom setting types.
# How DSC is implemented
We use `PowerToys.Settings.DSC.Schema.Generator` to generate the bulk of `PowerToysConfigure.psm1` and `PowerToysConfigure.psd1` files. It also uses dotnet reflection capabilities to inspect `PowerToys.Settings.UI.Lib.dll` assembly and generate properties for the modules we have. The actual generation is done as a `PowerToys.Settings.DSC.Schema.Generator.csproj` post-build action.
# Debugging DSC resources
First, make sure that PowerShell 7.4+ is installed. Then make sure that you have DSC installed:
```ps
Install-Module -Name PSDesiredStateConfiguration -RequiredVersion 2.0.7
```
After that, start a new `pwsh` session and `cd` to `src\dsc\Microsoft.PowerToys.Configure\Generated` directory. From there, you should execute:
```ps
$env:PSModulePath += ";$pwd"
```
You should have the generated `Microsoft.PowerToys.Configure.psm1` and `Microsoft.PowerToys.Configure.psd1` files inside the `src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\0.0.1\` folder.
This will allow DSC to discover our DSC Resource module. See [PSModulePath](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_psmodulepath?view=powershell-7.4#long-description) for more info.
If everything works, you should see that your module is discovered by executing the following command:
```ps
Get-Module -ListAvailable | grep PowerToys
```
The resource itself should also be available:
```ps
Get-DSCResource | grep PowerToys
```
Otherwise, you can force-import the module to diagnose issues:
```
Import-Module .\Microsoft.PowerToys.Configure.psd1
```
If it's imported successfully, you could also try to invoke it directly:
```ps
Invoke-DscResource -Name PowerToysConfigure -Method Set -ModuleName Microsoft.PowerToys.Configure -Property @{ Debug = $true; Awake = @{ Enabled = $false; Mode = "TIMED"; IntervalMinutes = "10" } }
```
Note that we've supplied `Debug` option, so a `%TEMP\PowerToys.DSC.TestConfigure.txt` is created with the supplied properties, a current timestamp, and other debug output.
Finally, you can test it with winget by invoking it as such:
```ps
winget configure .\configuration.winget --accept-configuration-agreements --disable-interactivity
```
================================================
FILE: doc/devdocs/core/settings/gpo-integration.md
================================================
# Group Policy Integration
PowerToys settings can be controlled and enforced via Group Policy. This document describes how Group Policy integration is implemented in the settings system.
## Overview
Group Policy settings for PowerToys allow administrators to:
- Enable or disable PowerToys entirely
- Control which modules are available
- Configure specific settings for individual modules
- Enforce settings across an organization
## Implementation Details
When a setting is controlled by Group Policy:
1. The UI shows the setting as locked (disabled)
2. The module checks GPO settings before applying user settings
3. GPO settings take precedence over user settings
## Group Policy Settings Detection
The settings UI checks for Group Policy settings during initialization:
```csharp
// Example code for checking if a setting is controlled by GPO
bool isControlledByPolicy = RegistryHelper.GetGPOValue("PolicyKeyPath", "PolicyValueName", out object value);
if (isControlledByPolicy)
{
// Use the policy value and disable UI controls
setting.IsEnabled = false;
setting.Value = (bool)value;
}
```
## UI Indication for Managed Settings
When a setting is managed by Group Policy, the UI indicates this to the user:
- Controls are disabled (grayed out)
- A tooltip indicates the setting is managed by policy
- The actual policy value is displayed
## Testing Group Policy Settings
To test Group Policy integration:
1. Create a test GPO using the PowerToys ADMX template
2. Apply settings in the Group Policy Editor
3. Verify that the settings UI correctly reflects the policy settings
4. Verify that the modules honor the policy settings
## GPO Settings vs. User Settings
The precedence order for settings is:
1. Group Policy settings (highest priority)
2. User settings (lower priority)
3. Default settings (lowest priority)
When a setting is controlled by Group Policy, attempts to modify it through the settings UI or programmatically will not persist, as the policy value will always take precedence.
For more information on PowerToys Group Policy implementation, see the [GPO Implementation](/doc/devdocs/processes/gpo.md) documentation.
================================================
FILE: doc/devdocs/core/settings/hotkeycontrol.md
================================================
# Custom HotKey Control
The Settings project provides a custom hotkey control which consumes key presses. This control can be used to set the hotkey of any PowerToy.
## HotKey Control in FancyZones

## Hotkey related files
#### [`HotkeySettingsControlHook.cs`](/src/settings-ui/Settings.UI.Library/HotkeySettingsControlHook.cs)
- This function initializes and starts the [`keyboardHook`](src/common/interop/KeyboardHook.cpp) for the hotkey control.
```csharp
public HotkeySettingsControlHook(KeyEvent keyDown, KeyEvent keyUp, IsActive isActive, FilterAccessibleKeyboardEvents filterAccessibleKeyboardEvents)
{
_keyDown = keyDown;
_keyUp = keyUp;
_isActive = isActive;
_filterKeyboardEvent = filterAccessibleKeyboardEvents;
_hook = new KeyboardHook(HotkeySettingsHookCallback, IsActive, FilterKeyboardEvents);
_hook.Start();
}
```
#### [`HotkeySettingsControl.xaml.cs`](/src/settings-ui/Settings.UI/HotkeySettingsControl.xaml.cs)
- The function of this class is to update the state of the keys being pressed within the custom control. This information is stored in `internalSettings`.
- It provides the following callbacks to the `HotKeySettingsControlHook`:
- `KeyUp`: Resets the key state in `internalSettings` when a key is released.
- `KeyDown`: Updates the user facing text of the hotkey control as soon as a key is pressed.
- `isActive`: Sets the current status of the keyboard hook.
- `FilterAccessibleKeyboardEvents`: This function is used to ignore the `Tab` and `Shift+Tab` key presses to meet the accessibility requirements.
#### [`HotkeySettings.cs`](/src/settings-ui/Settings.UI.Library/HotkeySettings.cs)
- Contains the structure of a HotKey where it is represented as a combination of one of the modifier keys (`Alt`, `Shift`, `Win` and `Ctrl`) and a non-modifier key.
#### Note
- The control displays all key presses to the user (except Tab and Shift+Tab which move focus out of the control). However, when the focus is being lost from the control, the `lastValidHotkeySettings` is set as the user facing text.
================================================
FILE: doc/devdocs/core/settings/project-overview.md
================================================
# Overview
`Settings` is Windows App Sdk WinUI3 .Net Unpackaged desktop application. More details about Windows App Sdk can be found in [Windows App SDK - Calling all Windows developers!](https://github.com/microsoft/WindowsAppSDK#windows-app-sdk---calling-all-windows-developers). More details about WinUI can be found in [Build apps with WinUI](https://developer.microsoft.com/en-us/windows/develop/).
## Settings V2 Project structure
The Settings project .Net WinUI3 based project which
follows the [MVVM architectural pattern][MVVM] where the graphical user interface is separated from the view models.
#### [UI Components:](/src/settings-ui/Settings.UI/)
The UI Components are part of PowerToys.Settings project. It contains the xaml files for each of the UI components. It also contains the Hotkey logic for the settings control.
#### [Viewmodels:](/src/settings-ui/Settings.UI.Library)
The Settings.UI.Library project contains the data that is to be rendered by the UI components.
#### [Settings Runner:](/src/settings-ui/Settings.UI)
The function of the settings runner project is to communicate all changes that the user makes in the user interface, to the runner so that it can be dispatched and reflected in all the modules.
[MVVM]: https://learn.microsoft.com/windows/uwp/data-binding/data-binding-and-mvvm
================================================
FILE: doc/devdocs/core/settings/readme.md
================================================
# PowerToys Settings System
PowerToys provides a comprehensive settings system that allows users to configure various aspects of the application and its modules. This document provides an overview of the settings system architecture and links to more detailed documentation.
# Table of Contents
1. [Settings overview](/doc/devdocs/core/settings/project-overview.md)
2. [UI Architecture](/doc/devdocs/core/settings/ui-architecture.md)
3. [ViewModels](/doc/devdocs/core/settings/viewmodels.md)
4. [Settings Implementation](/doc/devdocs/core/settings/settings-implementation.md)
5. [Group Policy Integration](/doc/devdocs/core/settings/gpo-integration.md)
6. Data flow
- [Inter-Process Communication with runner](/doc/devdocs/core/settings/runner-ipc.md)
- [Communication with modules](/doc/devdocs/core/settings/communication-with-modules.md)
7. [Settings Utilities](/doc/devdocs/core/settings/settings-utilities.md)
8. [Custom Hotkey control and keyboard hook handling](hotkeycontrol.md)
9. [Compatibility with legacy settings and runner](/doc/devdocs/core/settings/compatibility-legacy-settings.md)
10. [XAML Island tweaks](/doc/devdocs/core/settings/xaml-island-tweaks.md)
11. [Telemetry](/doc/devdocs/core/settings/telemetry.md)
12. [DSC Configuration](/doc/devdocs/core/settings/dsc-configure.md)
================================================
FILE: doc/devdocs/core/settings/runner-ipc.md
================================================
# Inter-Process Communication with Runner
The Settings v2 process uses two way IPC to communicate with the runner process.
## Initialization
- On the settings' side, the two way IPC delegates are contained with the [`ShellPage.xaml.cs`](/src/settings-ui/Settings.UI/SettingsXAML/Views/ShellPage.xaml.cs) file. The delegates are static and the views for all the powerToys send the ipc information to the viewmodels as `ShellPage.DefaultSndMSGCallBack`.
- These delegates are initialized within the [`MainWindow.xaml.cs`](/src/settings-ui/Settings.UI/SettingsXAML/MainWindow.xaml.cs) file in the `Settings.Runner` project.
## Types of IPC delegates
- There are three types of delegates for the settings to communicate with the runner:
1. `SendDefaultMessage` - This is used by all the viewmodels to communicate changes in the UI to the runner so that the information can be dispatched to the modules.
2. `RestartAsAdmin`
3. `CheckForUpdates`
## Sending information to runner
- The settings process communicates with the runner by using the delegates defined within the [`ShellPage.xaml.cs`](/src/settings-ui/Settings.UI/SettingsXAML/Views/ShellPage.xaml.cs) file.
- Depending on the type of object sending the information, the json is created accordingly.
- If any information has been modified by the user in the GeneralSettings page, then the json file sent to the runner has the name set to `general`, whereas if any information has been modified by the user in any powertoy related settings page, the name of the json file being communicated with the runner is set to `powertoy`.
## Receiving information from runner
- The `ShellPage` object has a `IPCResponseHandleList` which is a list of functions which handle IPC responses.
```csharp
// receive IPC Message
Program.IPCMessageReceivedCallback = (string msg) =>
{
if (ShellPage.ShellHandler.IPCResponseHandleList != null)
{
try
{
JsonObject json = JsonObject.Parse(msg);
foreach (Action handle in ShellPage.ShellHandler.IPCResponseHandleList)
{
handle(json);
}
}
catch (Exception)
{
}
}
};
```
- Whenever any information is sent from the runner each of the functions in the handle list perform their action on that json object.
- One example of where information sent from the runner is being processed by the settings is in [`GeneralPage.xaml.cs`](/src/settings-ui/Settings.UI/SettingsXAML/Views/GeneralPage.xaml.cs) when the user clicks the check for updates button. The information displayed after, such as the user has the latest version installed is a result of this handle.
================================================
FILE: doc/devdocs/core/settings/settings-implementation.md
================================================
# Settings Implementation
This document describes how settings are implemented in PowerToys modules, including code examples for C++ and C# modules, and details on debugging settings issues.
## C++ Settings Implementation
For C++ modules, the settings system is implemented in the following files:
- `settings_objects.h` and `settings_objects.cpp`: Define the basic settings objects
- `settings_helpers.h` and `settings_helpers.cpp`: Helper functions for reading/writing settings
- `settings_manager.h` and `settings_manager.cpp`: Main interface for managing settings
### Reading Settings in C++
```cpp
#include
#include
auto settings = PowerToysSettings::Settings::LoadSettings(L"ModuleName");
bool enabled = settings.GetValue(L"enabled", true);
```
### Writing Settings in C++
```cpp
PowerToysSettings::Settings settings(L"ModuleName");
settings.SetValue(L"setting_name", true);
settings.Save();
```
## C# Settings Implementation
For C# modules, the settings are accessed through the `SettingsUtils` class in the `Microsoft.PowerToys.Settings.UI.Library` namespace:
### Reading Settings in C#
```csharp
using Microsoft.PowerToys.Settings.UI.Library;
// Read settings
var settings = SettingsUtils.Default.GetSettings("ModuleName");
bool enabled = settings.Enabled;
```
### Writing Settings in C#
```csharp
using Microsoft.PowerToys.Settings.UI.Library;
// Write settings
settings.Enabled = true;
SettingsUtils.Default.SaveSettings(settings.ToJsonString(), "ModuleName");
```
## Settings Handling in Modules
Each PowerToys module must implement settings-related functions in its module interface:
```cpp
// Get the module's settings
virtual PowertoyModuleSettings get_settings() = 0;
// Called when settings are changed
virtual void set_config(const wchar_t* config_string) = 0;
```
When the user changes settings in the UI:
1. The settings UI serializes the settings to JSON
2. The JSON is sent to the PowerToys runner via IPC
3. The runner calls the `set_config` function on the appropriate module
4. The module parses the JSON and applies the new settings
# Shortcut Conflict Detection
Steps to enable conflict detection for a hotkey:
### 1. Implement module interface for hotkeys
Ensure the module interface provides either `size_t get_hotkeys(Hotkey* hotkeys, size_t buffer_size)` or `std::optional GetHotkeyEx()`.
- If not yet implemented, you need to add it so that it returns all hotkeys used by the module.
- **Important**: The order of the returned hotkeys matters. This order is used as an index to uniquely identify each hotkey for conflict detection and lookup.
- For reference, see: `src/modules/AdvancedPaste/AdvancedPasteModuleInterface/dllmain.cpp`
### 2. Implement IHotkeyConfig in the module settings (UI side)
Make sure the module’s settings file inherits from `IHotkeyConfig` and implements `HotkeyAccessor[] GetAllHotkeyAccessors()`.
- This method should return all hotkeys used in the module.
- **Important**: The order of the returned hotkeys must be consistent with step 1 (`get_hotkeys()` or `GetHotkeyEx()`).
- For reference, see: `src/settings-ui/Settings.UI.Library/AdvancedPasteSettings.cs`
- **_Note:_** `HotkeyAccessor` is a wrapper around HotkeySettings.
It provides both `getter` and `setter` methods to read and update the corresponding hotkey.
Additionally, each `HotkeyAccessor` requires a resource string that describes the purpose of the hotkey.
This string is typically defined in: `src/settings-ui/Settings.UI/Strings/en-us/Resources.resw`
### 3. Update the module’s ViewModel
The corresponding ViewModel should inherit from `PageViewModelBase` and implement `Dictionary GetAllHotkeySettings()`.
- This method should return all hotkeys, maintaining the same order as in steps 1 and 2.
- For reference, see: `src/settings-ui/Settings.UI/ViewModels/AdvancedPasteViewModel.cs`
### 4. Ensure the module’s Views call `OnPageLoaded()`
Once the module’s view is loaded, make sure to invoke the ViewModel’s `OnPageLoaded()` method:
```cs
Loaded += (s, e) => ViewModel.OnPageLoaded();
```
- For reference, see: `src/settings-ui/Settings.UI/SettingsXAML/Views/AdvancedPaste.xaml.cs`
## Debugging Settings
To debug settings issues:
1. Check the settings files in `%LOCALAPPDATA%\Microsoft\PowerToys\`
2. Ensure JSON is well-formed
3. Monitor IPC communication between settings UI and runner using debugger breakpoints at key points:
- In the Settings UI when sending configuration changes
- In the Runner when receiving and dispatching changes
- In the Module when applying changes
4. Look for log messages related to settings changes in the PowerToys logs
### Common Issues
- **Settings not saving**: Check file permissions or conflicts with other processes accessing the file
- **Settings not applied**: Verify IPC communication is working and the module is properly handling the configuration
- **Incorrect settings values**: Check JSON parsing and type conversion in the module code
## Adding a New Module with Settings
Adding a new module with settings requires changes across multiple projects. Here's a step-by-step guide with references to real implementation examples:
### 1. Settings UI Library (Data Models)
Define the data models for your module's settings in the Settings UI Library project. These data models will be serialized to JSON configuration files stored in `%LOCALAPPDATA%\Microsoft\PowerToys\`.
Example: [Settings UI Library implementation](https://github.com/shuaiyuanxx/PowerToys/pull/3/files#diff-9be1cb88a52ce119e5ff990811e5fbb476c15d0d6b7d5de4877b1fd51d9241c3)
### 2. Settings UI (User Interface)
#### 2.1 Add a navigation item in ShellPage.xaml
The ShellPage.xaml is the entry point for the PowerToys settings, providing a navigation view of all modules. Add a navigation item for your new module.
Example: [Adding navigation item](https://github.com/shuaiyuanxx/PowerToys/pull/3/files#diff-5a06e6e7a5c99ae327c350c9dcc10036b49a2d66d66eac79a8364b4c99719c6b)
#### 2.2 Create a settings page for your module
Create a new XAML page that contains all the settings controls for your module.
Example: [New settings page](https://github.com/shuaiyuanxx/PowerToys/pull/3/files#diff-310fd49eba464ddf6a876dcf61f06a6f000ca6744f3a1f915c48c58384d7bacb)
#### 2.3 Implement the ViewModel
Create a ViewModel class that handles the settings data and operations for your module.
Example: [ViewModel implementation](https://github.com/shuaiyuanxx/PowerToys/pull/3/files#diff-409472a53326f2288c5b76b87c7ea8b5527c43ede12214a15b6caabe0403c1d0)
### 3. Module Implementation
#### 3.1 Implement PowertoyModuleIface in dllmain.cpp
The module interface must implement the PowertoyModuleIface to allow the runner to interact with it.
Reference: [PowertoyModuleIface definition](https://github.com/microsoft/PowerToys/blob/cc644b19982d09fcd2122fe7590c77496c4973b9/src/modules/interface/powertoy_module_interface.h#L6C1-L35C4)
#### 3.2 Implement Module UI
Create a UI for your module using either WPF (like ColorPicker) or WinUI3 (like Advanced Paste).
### 4. Runner Integration
Add your module to the known modules list in the runner so it can be brought up and initialized.
Example: [Runner integration](https://github.com/shuaiyuanxx/PowerToys/pull/3/files#diff-c07e4e5e9ce3c371d4c47f496b5f66734978a3c4f355c7e446c1ef19e086a4d6)
### 5. Testing and Debugging
1. Test each component individually:
- Verify settings serialization/deserialization
- Test module activation/deactivation
- Test IPC communication
2. For signal-related issues, ensure all modules work correctly before debugging signal handling.
3. You can debug each module directly in Visual Studio or by attaching to running processes.
### Recommended Implementation Order
1. Module/ModuleUI implementation
2. Module interface (dllmain.cpp)
3. Runner integration
4. Settings UI implementation
5. OOBE (Out of Box Experience) integration
6. Other components
================================================
FILE: doc/devdocs/core/settings/settings-utilities.md
================================================
# Settings Utilities
- Abstractions for each of the file/folder related operations are present in [`SettingsUtils.cs`](src/settings-ui/Settings.UI.Library/SettingsUtils.cs).
- To reduce contention between the settings process and runner while trying to access the `settings.json` file of any powertoy, the settings process tries to access the file only when it needs to load the information for the first time. However, there is still no mechanism in place which ensures that both the settings and runner processes do not access the information simultaneously leading to `IOExceptions`.
## Utilities
### `GetSettings(powertoy, filename)`
- The GetSettings function tries to read the file in the powertoy settings folder and creates a new file with default configurations if it does not exist.
- Ideally this function should only be called by the [`SettingsRepository`](src/settings-ui/Settings.UI.Library/SettingsRepository`1.cs) which would be accessed only when a powertoy settings object is being loaded for the first time.
- The reason behind ensuring that it is not accessed elsewhere is to avoid contention with the runner during file access.
- Each of the objects which are deserialized using this function must implement the `ISettingsConfig` interface.
================================================
FILE: doc/devdocs/core/settings/telemetry.md
================================================
# Telemetry
## Overview
[`Settings.UI.Library/Telemetry`](/src/settings-ui/Settings.UI.Library/Telemetry) contains telemetry events generated by `Settingsv2.` These event classes are derived from the [`EventBase`](/src/common/ManagedTelemetry/Telemetry/Events/EventBase.cs) class and [`IEvent`](/src/common/ManagedTelemetry/Telemetry/Events/IEvent.cs) class. [`IEvent`](/src/common/ManagedTelemetry/Telemetry/Events/IEvent.cs) class provides the lowest level abstraction, containing attributes such as privacy tags needed for every telemetry data. [`EventBase`](/src/common/ManagedTelemetry/Telemetry/Events/EventBase.cs) class provides a higher-level abstraction, having attributes common to all `PowerToys` telemetry events.
## Events
The following events are generated by `Settingsv2`:
1. [`SettingsBootEvent`](/src/settings-ui/Settings.UI.Library/Telemetry/Events/SettingsBootEvent.cs): This event captures the time taken by `Settingsv2` to initialize `MainWindow` UI control.
2. [`SettingsEnabledEvent.cs`](/src/settings-ui/Settings.UI.Library/Telemetry/Events/SettingsEnabledEvent.cs): This event is generated when a module is enabled or disabled.
================================================
FILE: doc/devdocs/core/settings/ui-architecture.md
================================================
# UI Architecture
The UI code is distributed between two projects: [`PowerToys.Settings`](/src/settings-ui/Settings.UI) and [`Settings.UI`](/src/settings-ui/Settings.UI.Library). [`PowerToys.Settings`](/src/settings-ui/Settings.UI) is a Windows App Sdk .net Unpackaged application. It contains the views for base navigation and modules. Parent display window and corresponding code is present in [`MainWindow.xaml`](/src/settings-ui/Settings.UI/SettingsXAML/MainWindow.xaml). Fig 1 provides a description of the UI controls hierarchy and each of the controls have been summarized below :
- [`ShellPage.xaml`](/src/settings-ui/Settings.UI/SettingsXAML/Views/ShellPage.xaml) is a WinUI control, consisting of a side navigation panel with an icon for each module. Clicking on a module icon loads the corresponding `setting.json` file and displays the data in the UI.

**Fig 1: UI Architecture for settingsv2**
================================================
FILE: doc/devdocs/core/settings/viewmodels.md
================================================
# View Models
The view models are located within the [`Settings.UI.Library`](/src/settings-ui/Settings.UI.Library) project.
## Components
- Each view model takes in the general `settingsRepository`, the `moduleSettingsRepository` if it exists and the delegates for IPC communication.
- The general `settingsRepository` contains the general configurations of all powertoys whereas the `moduleSettingsRepository` is specific to the module. This is to ensure that the configuration details are shared amongst the viewmodels without having to re-open the `settings.json` file.
- Whenever there is a change in the UI, the `OnPropertyChanged` event is invoked and the view model sends a corresponding IPC message to the runner which would perform the designated action such as dispatching the change to the modules or enabling/disabling the powertoy, etc.
#### Difference between view models
- The [`GeneralViewModel`](/src/settings-ui/Settings.UI.Library/ViewModels/GeneralViewModel.cs) is different from the rest of the view models with regard to the IPC communication wherein it sends special IPC messages to the runner to check for updates and to restart as admin.
- Each of the powerToy view models have two types of IPC communications, one for the general status of the powerToy and the other for communication powerToy specific change in properties to the runner.
## [`SettingsRepository`](src/settings-ui/Settings.UI.Library/SettingsRepository`1.cs)
- The [`SettingsRepository`](src/settings-ui/Settings.UI.Library/SettingsRepository`1.cs) is a generic singleton which contains the configurations for each view model.
- As it is a generic singleton, there can only be one instance of the settings repository of a particular type. This ensures that all the view models are modifying a common object and a change made in one locations reflects everywhere.
- The singleton implementation is thread-safe. Unit tests have been added for the same.
### Settings view model anomalies
- The reason behind using the `SettingsRepository` is to ensure that the settings process does not try to access the `settings.json` files directly but rather does it through this class which encapsulates all the file operations from the view models.
- However, this could not be expanded to all the view models directly for the following reasons. Some refactoring must be done to unify these cases and to bring them under the same model:
- The PowerRename view model does not save the settings configurations in the same format as the rest of the powertoys, i.e. {name, version, properties}. However, it only stores the properties directly.
- Some view models expect the runner to create the file instead of creating the file themselves, like in keyboard manager.
- The colorpicker powertoy creates the `settings.json` within the module. This must be taken care of when encapsulated within the settingsRepository.
- Currently, all modules use the `SettingsRepository` to access the General Settings config.
- However, only FancyZones, ShortcutGuide and PowerPreview use the `SettingsRepository` to access the module properties.
================================================
FILE: doc/devdocs/development/debugging.md
================================================
# Debugging PowerToys
This document covers techniques and tools for debugging PowerToys.
## Pre-Debugging Setup
Before you can start debugging PowerToys, you need to set up your development environment:
1. Fork the repository and clone it to your machine
2. Navigate to the repository root directory
3. Run `git submodule update --init --recursive` to initialize all submodules
4. Change directory to `.config` and run `winget configure .\configuration.vsEnterprise.winget` (pick the configuration file that matches your Visual Studio distribution)
### Optional: Building Outside Visual Studio
You can build the entire solution from the command line, which is sometimes faster than building within Visual Studio:
1. Open `Developer Command Prompt for VS`
2. Navigate to the repository root directory
3. Run the following command(don't forget to set the correct platform):
```pwsh
msbuild -restore -p:RestorePackagesConfig=true -p:Platform=ARM64 -m PowerToys.slnx /tl /p:NuGetInteractive="true"
```
4. This process should complete in approximately 13-14 minutes for a full build
## Debugging Techniques
### Visual Studio Debugging
To debug the PowerToys application in Visual Studio, set the `runner` project as your start-up project, then start the debugger.
Some PowerToys modules must be run with the highest permission level if the current user is a member of the Administrators group. The highest permission level is required to be able to perform some actions when an elevated application (e.g. Task Manager) is in the foreground or is the target of an action. Without elevated privileges some PowerToys modules will still work but with some limitations:
- The `FancyZones` module will not be able to move an elevated window to a zone.
- The `Shortcut Guide` module will not appear if the foreground window belongs to an elevated application.
Therefore, it is recommended to run Visual Studio with elevated privileges when debugging these scenarios. If you want to avoid running Visual Studio with elevated privileges and don't mind the limitations described above, you can do the following: open the `runner` project properties and navigate to the `Linker -> Manifest File` settings, edit the `UAC Execution Level` property and change it from `highestAvailable (level='highestAvailable')` to `asInvoker (/level='asInvoker').
### Shell Process Debugging Tool
The Shell Process Debugging Tool is a Visual Studio extension that helps debug multiple processes, which is especially useful for PowerToys modules started by the runner.
#### Debugging Setup Process
1. Install ["Debug Child Processes"](https://marketplace.visualstudio.com/items?itemName=vsdbgplat.MicrosoftChildProcessDebuggingPowerTool2022) Visual Studio extension
2. Configure which processes to debug and what debugger to use for each
3. Start PowerToys from Visual Studio
4. The extension will automatically attach to specified child processes when launched
#### Debugging Color Picker Example
1. Set breakpoints in both ColorPicker and its module interface
2. Use Shell Process Debugging to attach to ColorPickerUI.exe
3. Debug .NET and native code together
4. Runner needs to be running to properly test activation
#### Debugging DLL Main/Module Interface
- Breakpoints in DLL code will be hit when loaded by runner
- No special setup needed as DLL is loaded into runner process
#### Debugging Short-Lived Processes
- For processes with short lifetimes (like in Workspaces)
- List all processes explicitly in debugging configuration
- Set correct debugger type (.NET debugger for C# code)
### Finding Registered Events
1. Run WinObj tool from SysInternals as administrator
2. Search for event name
3. Shows handles to the event (typically runner and module)
### Common Debugging Usage Patterns
#### Debugging with Bug Report
1. Check module-specific logs for exceptions/crashes
2. Copy user's settings to your AppData to reproduce their configuration
3. Check Event Viewer XML files if logs don't show crashes
4. Compare installation_folder_structure.txt to detect corrupted installations
5. Check installer logs for installation-related issues
6. Look at Windows version and language settings for patterns across users
#### Installer Debugging
- Can only build installer in Release mode
- Typically debug using logs and message boxes
- Logs located in:
- `%LOCALAPPDATA%\Temp\PowerToys_bootstrapper_*.log` - MSI tool logs
- `%LOCALAPPDATA%\Temp\PowerToys_*.log` - Custom installer logs
- Logs in Bug Reports are useful for troubleshooting installation issues
#### Settings UI Debugging
- Use shell process debugging to connect to newly created processes
- Debug the `PowerToys.Settings.exe` process
- Add breakpoints as needed for troubleshooting
- Logs are stored in the local app directory: `%LOCALAPPDATA%\Microsoft\PowerToys`
- Check Event Viewer for application crashes related to `PowerToys.Settings.exe`
- Crash dumps can be obtained from Event Viewer
## Troubleshooting Build Errors
### Missing Image Files or Corrupted Build State
If you encounter build errors about missing image files (e.g., `.png`, `.ico`, or other assets), this typically indicates a corrupted build state. To resolve:
1. **Clean the solution in Visual Studio**: Build > Clean Solution
Or from the command line (`Developer Command Prompt for VS`):
```pwsh
msbuild PowerToys.slnx /t:Clean /p:Platform=x64 /p:Configuration=Debug
```
2. **Delete build output and package folders** from the repository root:
- `x64/`
- `ARM64/`
- `Debug/`
- `Release/`
- `packages/`
3. **Rebuild the solution**
#### Helper Script
A PowerShell script is available to automate this cleanup:
```pwsh
.\tools\build\clean-artifacts.ps1
```
This script will run MSBuild Clean and remove the build folders listed above. Use `-SkipMSBuildClean` if you only want to delete the folders without running MSBuild Clean.
After cleaning, rebuild with:
```pwsh
msbuild -restore -p:RestorePackagesConfig=true -p:Platform=x64 -m PowerToys.slnx
```
================================================
FILE: doc/devdocs/development/dev-with-vscode.md
================================================
## Developing PowerToys with Visual Studio Code
This guide shows how to build, debug, and contribute to PowerToys using VS Code instead of (or alongside) full Visual Studio. It focuses on common inner‑loop tasks for C++, .NET, and mixed scenarios present in the solution.
> PowerToys is a large mixed C++ / C# / WinAppSDK solution. VS Code works well for incremental development and quick module iterations, but occasionally you may still prefer full Visual Studio for designer tooling or specialized diagnostics.
---
VS Code extensions Needed:
| Area | Extension | Notes |
|------|-----------|-------|
| C++ | ms-vscode.cpptools | IntelliSense, debugging (cppvsdbg) |
| C# | ms-dotnettools.csdevkit (or C#) | Language service / test explorer |
---
## Building in VS Code
### Configure Developer PowerShell for VS for more convenient development experience in VS Code
1. Configure profile in settings, entry: `terminal.integrated.profiles.windows`
2. Add below config as entry (choose VS 2026 or VS 2022 based on your installation):
**For Visual Studio 2026 (recommended):**
```json
"Developer PowerShell for VS": {
// Configure based on your preference
"path": "C:\\Program Files\\WindowsApps\\Microsoft.PowerShell_7.5.2.0_arm64__8wekyb3d8bbwe\\pwsh.exe",
"args": [
"-NoExit",
"-Command",
"& {",
"$orig = Get-Location;",
// Adjust path based on your edition (Community/Professional/Enterprise)
"& 'C:\\Program Files\\Microsoft Visual Studio\\18\\Enterprise\\Common7\\Tools\\Launch-VsDevShell.ps1';",
"Set-Location $orig",
"}"
]
},
```
**For Visual Studio 2022:**
```json
"Developer PowerShell for VS 2022": {
// Configure based on your preference
"path": "C:\\Program Files\\WindowsApps\\Microsoft.PowerShell_7.5.2.0_arm64__8wekyb3d8bbwe\\pwsh.exe",
"args": [
"-NoExit",
"-Command",
"& {",
"$orig = Get-Location;",
// Adjust path based on your edition (Community/Professional/Enterprise)
"& 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Common7\\Tools\\Launch-VsDevShell.ps1';",
"Set-Location $orig",
"}"
]
},
```
3. [Optional] Set your Developer PowerShell profile as the default, so that you can get a deep integration with vscode coding agent.
4. Now you can build with plain `msbuild` or configure tasks.json in below section.
Or reach out to "tools\build\BUILD-GUIDELINES.md"
### Sample plain msbuild command
```powershell
# Restore:
msbuild powertoys.slnx -t:restore -p:configuration=debug -p:platform=x64 -m
# Build powertoys slnx
msbuild powertoys.slnx -p:configuration=debug -p:platform=x64 -m
# dotnet project
msbuild src\settings-ui\Settings.UI\PowerToys.Settings.csproj -p:Platform=x64 -p:Configuration=Debug -m
# native project
msbuild "src\modules\MouseUtils\FindMyMouse\FindMyMouse.vcxproj" -p:Configuration=Debug -p:Platform=x64 -m
```
---
## Debugging
### Existing launch configuration
The repo provides `.vscode/launch.json` with:
- `Run PowerToys.exe (no build)`: Launches the already-built executable at `x64/Debug/PowerToys.exe` using `cppvsdbg`.
Build first, then press F5. To switch configuration (Release / ARM64) either edit the path or create additional launch entries.
### Attaching to a running instance
If PowerToys is already running, you can attach to that process:
2. VS Code command palette: “C/C++: (Windows) Attach to Process”.
3. Filter for `PowerToys.exe` / module-specific processes.
### Debugging managed components
Many modules have a managed component loaded into the PowerToys process. `cppvsdbg` can debug mixed mode, but if you need richer .NET inspection you can create a second configuration using `type: coreclr` and `processId` attachment after the native launch, or just attach separately:
Similar for attach to managed code.
> Note: In arm64 machine, can only debug arm64 code.
```jsonc
{
"version": "0.2.0",
"configurations": [
{
"name": "Run native executable (no build)",
"type": "cppvsdbg",
"request": "launch",
"program": "${workspaceFolder}\\x64\\Debug\\PowerToys.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"console": "integratedTerminal"
},
{
"name": "C/C++ Attach to PowerToys Process (native)",
"type": "cppvsdbg",
"request": "attach",
"processId": "${command:pickProcess}",
"symbolSearchPath": "${workspaceFolder}\\x64\\Debug;${workspaceFolder}\\Debug;${workspaceFolder}\\symbols"
},
{
"name": "Run managed code (managed, no build)",
"type": "coreclr",
"request": "launch",
"program": "${workspaceFolder}\\arm64\\Debug\\WinUI3Apps\\PowerToys.Settings.exe",
"args": [],
"cwd": "${workspaceFolder}",
"env": {},
"console": "internalConsole",
"stopAtEntry": false
}
]
}
```
---
## 6. Common tasks & tips
| Task | Command / Action | Notes |
|------|------------------|-------|
| Clean | `git clean -xdf` (careful) or `msbuild /t:Clean PowerToys.slnx` | Deep clean removes packages & build outputs |
| Rebuild single project | `msbuild path\to\proj.vcxproj /t:Rebuild -p:Platform=x64 -p:Configuration=Debug` | Faster than whole solution |
| Generate installer (rare in inner loop) | See `tools\build\build-installer.ps1` | Usually not needed for local debug |
| Resource conversion errors | Re-run restore + build | Triggers custom PowerShell targets |
================================================
FILE: doc/devdocs/development/guidelines.md
================================================
# PowerToys Development Guidelines
## Using Open Source Packages and Libraries
### License Considerations
- MIT license is generally acceptable for inclusion in the project
- For any license other than MIT, double check with the PM team
- All external packages or projects must be mentioned in the `notice.md` file
- Even if a license permits free use, it's better to verify with the team
### Safety and Quality Considerations
- Ensure the code being included is safe to use
- Avoid repositories or packages that are not widely used
- Check for packages with significant downloads/usage and good ratings
- Important because our pipeline signs external DLLs with Microsoft certificate
- Unsafe code signed with Microsoft certificate can cause serious issues
## Code Signing
### Signing JSON File
- Modifications to the signing JSON file are typically done manually
- When adding new DLLs (internal PowerToys modules or external libraries)
- When the release pipeline fails with a list of unsigned DLLs/executables:
- For PowerToys DLLs, manually add them to the list
- For external DLLs, verify they're safe to sign before including
### File Signing Requirements
- All DLLs and executables must be signed
- New files need to be added to the signing configuration
- CI checks if all files are signed
- Even Microsoft-sourced dependencies are signed if they aren't already
## Performance Measurement
- Currently no built-in timers to measure PowerToys startup time
- Startup measurement could be added in the runner:
- At the start of the main method
- After all module interface DLLs are loaded
- Alternative: use profilers or Visual Studio profiler
- Startup currently takes some time due to:
- Approximately 20 module interface DLLs that need to be loaded
- Modules that are started during loading
- No dashboards or dedicated tools for performance measurement
- Uses System.Diagnostics.Stopwatch in code
- Performance data is logged to default PowerToys logs
- Can search logs for stopwatch-related messages to diagnose performance issues
- Some telemetry events contain performance information
## Dependency Management
### WinRT SDK and CS/WinRT
- Updates to WinRT SDK and CS/WinRT are done periodically
- WinRT SDK often requires higher versions of CS/WinRT or vice versa
- Check for new versions in NuGet.org or Visual Studio's NuGet Package Explorer
- Prefer stable versions over preview versions
- Best practice: Update early in the release cycle to catch potential regressions
### WebView2
- Used for components like monotone file preview
- WebView2 version is related to the WebView runtime in Windows
- Previous issues with Windows Update installing new WebView runtime versions
- WebView team now includes PowerToys testing in their release cycle
- When updating WebView2:
- Update the version
- Open a PR
- Perform sanity checks on components that use WebView2
### General Dependency Update Process
- When updating via Visual Studio, it will automatically update dependencies
- After updates, perform:
- Clean build
- Sanity check that all modules still work
- Open PR with changes
## Testing Requirements
### Multiple Computers
- **Mouse Without Borders**: Requires multiple physical computers for proper testing
- Testing with VMs is not recommended as it may cause confusion between host and guest mouse input
- At least 2 computers are needed, sometimes testing with 3 is done
- Testing is usually assigned to team members known to have multiple computers
### Multiple Monitors
- Some utilities require multiple monitors for testing
- At least 2 monitors are recommended
- One monitor should be able to use different DPI settings
### Fuzzing Testing
- Security team requires fuzzing testing for modules that handle file I/O or user input
- Helps identify vulnerabilities and bugs by feeding random, invalid, or unexpected data
- PowerToys integrates with Microsoft's OneFuzz service for automated testing
- Both .NET (C#) and C++ modules have different fuzzing implementation approaches
- New modules handling file I/O or user input should implement fuzzing tests
- For detailed setup instructions, see [Fuzzing Testing in PowerToys](../tools/fuzzingtesting.md)
### Testing Process
- For reporting bugs during the release candidate testing:
1. Discuss in team chat
2. Determine if it's a regression (check if bug exists in previous version)
3. Check if an issue is already open
4. Open a new issue if needed
5. Decide on criticality for the release (if regression)
### Release Testing
- Team follows a release checklist
- Includes testing for WinGet configuration
- Sign-off process:
- Teams sign off on modules independently
- Regressions found in first release candidates lead to PRs
- Second release candidate verified fixes
- Command Palette needs separate sign-off
- Final verification ensures modules don't crash with Command Palette integration
## PR Management and Release Process
### PR Review Process
- PM team typically tags PRs with "need review"
- Small fixes from community that don't change much are usually accepted
- PM team adds tags like "need review" to highlight PRs
- PMs set priorities (sometimes using "info.90" tags)
- PMs decide which PRs to prioritize
- Team members can help get PRs merged when there's flexibility
### PR Approval Requirements
- PRs need approval from code owners before merging
- New team members can approve PRs but final approval comes from code owners
### PR Priority Handling
- Old PRs sometimes "slip through the cracks" if not high priority
- PMs tag important PRs with "priority one" to indicate they should be included in release
- Draft PRs are generally not prioritized
### Specific PR Types
- CI-related PRs need review and code owner approval
- Feature additions (like GPO support) need PM decision on whether the feature is wanted
- Bug fixes related to Watson errors sometimes don't have corresponding issue links
- Command Palette is considered high priority for the upcoming release
## Project Management Notes
- Be careful about not merging incomplete features into main
- Feature branches should be used for work in progress
- PRs touching installer files should be carefully reviewed
- Incomplete features should not be merged into main
- Use feature branches (feature/name-of-feature) for work-in-progress features
- Only merge to main when complete or behind experimentation flags
================================================
FILE: doc/devdocs/development/localization.md
================================================
# Localization
## Table of Contents
1. [Localization on the pipeline (CDPX)](#localization-on-the-pipeline-cdpx)
1. [UWP Special case](#uwp-special-case)
2. [Enabling localization on a new project](#enabling-localization-on-a-new-project)
1. [C++](#c)
2. [C#](#c-1)
3. [UWP](#uwp)
3. [Lcl Files](#lcl-files)
4. [Possible Issues in localization PRs (LEGO)](#possible-issues-in-localization-prs-lego)
5. [Enabling localized MSI for a new project](#enabling-localized-msi-for-a-new-project)
## Localization on the pipeline (CDPX)
[The localization step](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L45-L52) is run on the pipeline before the solution is built. This step runs the [build-localization](https://github.com/microsoft/PowerToys/blob/main/.pipelines/build-localization.cmd) script, which generates resx files for all the projects with localization enabled using the `Localization.XLoc` package.
The [`Localization.XLoc`](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/build-localization.cmd#L24-L25) tool is run on the repo root, and it checks for all occurrences of `LocProject.json`. Each localized project has a `LocProject.json` file in the project root, which contains the location of the English resx file, list of languages for localization, and the output path where the localized resx files are to be copied to. In addition to this, some other parameters can be set, such as whether the language ID should be added as a folder in the file path or in the file name. When the CDPX pipeline is run, the localization team is notified of changes in the English resx files. For each project with localization enabled, a `loc` folder (see [the loc folder in the Microsoft.Launcher module](https://github.com/microsoft/PowerToys/tree/main/src/modules/launcher/Microsoft.Launcher/loc) for example) is created in the same directory as the `LocProject.json` file. The folder contains language specific folders which in turn have a nested folder path equivalent to `OutputPath` in the `LocProject.json`. Each of these folders contain one `lcl` file. The `lcl` files contain the English resources along with their translation for that language. These are described in more detail in the [Lcl files section](#lcl-files). Once the `.resx` files are generated, they will be used during the `Build PowerToys` step for localized versions of the modules.
Since the localization script requires certain nuget packages, the [`restore-localization`](https://github.com/microsoft/PowerToys/blob/main/.pipelines/restore-localization.cmd) script is run before running `build-localization` to install all the required packages. This script must [run in the `restore` step](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L37-L39) of pipeline because [the host is network isolated](https://onebranch.visualstudio.com/Pipeline/_wiki/wikis/Pipeline.wiki/2066/Consuming-Packages-in-a-CDPx-Pipeline?anchor=overview) at the `build` step. The [Toolset package source](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L23) is used for this.
The process and variables that can be tweaked on the pipeline are described in more detail on [onebranch (account required) under Localization](https://onebranch.visualstudio.com/Pipeline/_wiki/wikis/Pipeline.wiki/290/Localization).
The localized resource dlls for C# projects are added to the MSI only for build on the pipeline. This is done by checking if the [`IsPipeline` variable is defined](https://github.com/microsoft/PowerToys/blob/f92bd6ffd38014c228544bb8d68d0937ce4c2b6d/installer/PowerToysSetup/Product.wxs#L804-L805), which gets defined before [building the installer on the pipeline](https://github.com/microsoft/PowerToys/blob/f92bd6ffd38014c228544bb8d68d0937ce4c2b6d/.pipelines/build-installer.cmd#L4). This is done because the localized resx files are only present on the pipeline, and not having this check would result in the installer project failing to build locally.
## Enabling localization on a new project
To enable localization on a new project, the first step is to create a file `LocProject.json` in the project root.
For example, for a project in the folder `src\path` where the resx file is present in `resources\Resources.resx`, the LocProject.json file will contain the following:
```
{
"Projects": [
{
"LanguageSet": "Azure_Languages",
"LocItems": [
{
"SourceFile": "src\\path\\resources\\Resources.resx",
"CopyOption": "LangIDOnName",
"OutputPath": "src\\path\\resources"
}
]
}
]
}
```
The rest of the steps depend on the project type and are covered in the sections below. The steps to add the localized files to the MSI can be found in [Enabling localized MSI for a new project](#Enabling-localized-MSI-for-a-new-project).
### C++
C++ projects do not support `resx` files, and instead use `rc` files along with `resource.h` files. The CDPX pipeline however doesn't support localizing `rc` files and the other alternative they support is directly translating the resources from the binary which makes it harder to maintain resources. To avoid this, a custom script has been added which expects a resx file and converts the entries to an rc file with a string table and adds resource declarations to a resource.h file so that the resources can be compiled with the C++ project.
If you already have a .rc file, copy the string table to a separate txt file and run the [convert-stringtable-to-resx.ps1](https://github.com/microsoft/PowerToys/blob/main/tools/build/convert-stringtable-to-resx.ps1) script on it. This script is not very robust to input, and requires the data in a specific format, where `IDS_ResName L"ResourceValue"` and any number of spaces can be present in between. The script converts this file to the format expected by [`resgen`](https://learn.microsoft.com/dotnet/framework/tools/resgen-exe-resource-file-generator#Convert), which will convert it to resx. The resource names are changed from all uppercase to title case, and the `IDS_` prefix is removed. Escape characters might have to be manually replaced, for example .rc files would have escaped double quotes as `""`, so this should be replaced with just `"` before converting to the resx files.
After generating the resx file, rename the existing rc and h files to ProjName.base.rc and resource.base.h. In the rc file remove the string table which is to be localized and in the .h file remove all `#define`s corresponding to localized resources. In the vcxproj of the C++ project, add the following build event:
```
```
This event runs a script which generates a resource.h and ProjName.rc in the `Generated Files` folder using the strings in all the resx files along with the existing information in resource.base.h and ProjName.base.rc. The script is [convert-resx-to-rc.ps1](https://github.com/microsoft/PowerToys/blob/main/tools/build/convert-resx-to-rc.ps1). The script uses [`resgen`](https://learn.microsoft.com/dotnet/framework/tools/resgen-exe-resource-file-generator#Convert) to convert the resx file to a string table expected in the .rc file format. When the resources are added to the rc file the `IDS_` prefix is added and resource names are in upper case (as it was originally). Any occurrences of `"` in the string resource is escaped as `""` to prevent build errors. The string tables are added to the rc file in the following format:
```
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
STRINGTABLE
BEGIN
strings
END
#endif
```
Since there is no API to identify the `AFX_TARG_*`, `LANG_*` or `SUBLANG_*` values from each langId from the pipeline, these are hardcoded in the script (for each language) as done in [lines 50-77 of `convert-resx-to-rc.ps1`](https://github.com/microsoft/PowerToys/blob/f92bd6ffd38014c228544bb8d68d0937ce4c2b6d/tools/build/convert-resx-to-rc.ps1#L50-L77). **If any other languages are added in the future, this script will have to be updated.** In order to determine what are the language codes, you can open the rc file in Resource View, right click the string table and press `Insert Copy` and choose the corresponding language. This autogenerates the required code and can be used to figure out the language codes. The files also add the resource declarations to a resource.h file, starting from 101 by default(this can be changed by an optional argument). Since the output files will be generated in `Generated Files`, any includes in these two files will require an additional `..\` and wherever resource.h is used, it will have to be included as `Generated Files\resource.h`. While adding `resource.base.h` and `ProjName.base.rc` to the vcxproj, these should be modified to not participate in the build to avoid build errors:
```
```
Some rc/resource.h files might be used in multiple projects (for example, KBM). To ensure the projects build for these cases, the build event can be added to the entire directory so that the rc files are generated before any project is built. See [Directory.Build.targets](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/Directory.Build.targets) for an example.
Check [this PR](https://github.com/microsoft/PowerToys/pull/6104) for an example for making these changes for a C++ project.
### C#
Since C# projects natively support `resx` files, the only step required here is to include all the resx files in the build. For .NET Core projects this is done automatically and the .csproj does not need to be modified. For other projects, the following line needs to be added:
```
```
**Note:** Building with localized resources may cause a build warning `Referenced assembly 'mscorlib.dll' targets a different processor` which is a VS bug. More details can be found in [PowerToys issue #7269](https://github.com/microsoft/PowerToys/issues/7269).
**Note:** If a project needs to be migrated from XAML resources to resx, the easiest way to convert the resources would be to change to format to `=` separates resources by either manually (by Ctrl+H on a text editor), or by a script, and then running [`resgen`](https://learn.microsoft.com/dotnet/framework/tools/resgen-exe-resource-file-generator#Convert) on `Developer Command Prompt for VS` to convert it to resx format.
```
Calculator
Allows to do mathematical calculations.(Try 5*3-2 in Wox)
Not a number (NaN)
```
to
```
wox_plugin_calculator_plugin_name=Calculator
wox_plugin_calculator_plugin_description=Allows to do mathematical calculations.(Try 5*3-2 in Wox)
wox_plugin_calculator_not_a_number=Not a number (NaN)
```
After adding the resx file to the project along with the resource generator, references to the strings will have to be replaced with `Properties.Resources.resName` rather than the custom APIs. Check [this PR](https://github.com/microsoft/PowerToys/pull/6165) for an example of the changes required.
### UWP
UWP projects expect `resw` files rather than `resx` (the format is almost the same). Unlike other C# projects, the files are expected in the format `fullLangId\Resources.resw`. To include these files in the build, replace the following line in the csproj:
```
```
to
```
```
## Lcl Files
Lcl files contain all the resources that are present in the English resx file, along with a translation if it has been added.
For example, an entry for a resource in the lcl file looks like this:
```
-
```
The `` element would not be present in the initial commits of the lcl files, as only the English version of the string would be present.
**Note:** The CDPX Localization system has a fail-safe check on the lcl files, where if the English string value which is present inside ` ` does not match the value present in the English Resources.resx file then the translated value will not be copied to the localized resx file. This is present so that obsolete translations would not be loaded when the English resource has changed, and the English string will be used rather than the obsolete translation.
## Possible Issues in localization PRs (LEGO)
Since the LEGO PRs update some of the strings in LCL files at a time, there can be multiple PRs which modify the same files, leading to merge conflicts. In most cases this would show up on GitHub as a merge conflict, but sometimes a bad git merge may occur, and the file could end up with incorrect formatting, such as two `` elements for a single resource. These can be fixed by ensuring the elements follow the format described in [this section](#lcl-files). To catch such errors, the build farm should be run for every LEGO PR and if any error occurs in the localization step, we should check the corresponding resx/lcl files for conflicts.
## Enabling localized MSI for a new project
For C++ and UWP projects no additional files are generated with localization that need to be added to the MSI. For C++ projects all the resources are added to the dll/exe, while for UWP projects they are added to the `resources.pri` file (which is present even for an unlocalized project). To verify if the localized resources are added to the `resources.pri` file the following steps can be done:
- Open `Developer Command Prompt for VS`
- After navigating to the folder containing the pri file, run the following command:
makepri.exe dump /if .\resources.pri
- Check the contents of the `resources.pri.xml` file that is generated from the command. The last section of the file will contain the resources with the strings in all the languages:
```