Compare commits

...

98 Commits

Author SHA1 Message Date
Yu Leng (from Dev Box)
53eb4b8592 init 2025-04-01 17:08:35 +08:00
Hao Liu
721c84d3a6 Install .NET 9 for MSStore release (#38361)
fix dotnet 9
2025-04-01 10:08:25 +08:00
Hao Liu
96ba445cfa 0.90 changelog (#38072)
* First draft. Some PRs are still under review.

* update wording

* remove the Svg thumbnail since it has been reverted

* update cmdpal

* add cmdpal

* clear old hashes

* address comments

* Update README.md

Co-authored-by: Jay <65828559+Jay-o-Way@users.noreply.github.com>

* address more comments

* Update README.md

Co-authored-by: Mike Griese <migrie@microsoft.com>

* Add Command Palette gif to README

* upload gif of cmdpal

* Update README.md

Co-authored-by: Mike Griese <migrie@microsoft.com>

* Address comments

Co-authored-by: Kayla Cinnamon <cinnamon@microsoft.com>

* Update README.md

Co-authored-by: Kayla Cinnamon <cinnamon@microsoft.com>

* Update CmdPal description

Co-authored-by: Kayla Cinnamon <cinnamon@microsoft.com>

* Remove extra spacing

Co-authored-by: PesBandi <127593627+PesBandi@users.noreply.github.com>

* update hash

* update gif with new icon

---------

Co-authored-by: Jay <65828559+Jay-o-Way@users.noreply.github.com>
Co-authored-by: Clint Rutkas <clint@rutkas.com>
Co-authored-by: Mike Griese <migrie@microsoft.com>
Co-authored-by: Kayla Cinnamon <cinnamon@microsoft.com>
Co-authored-by: PesBandi <127593627+PesBandi@users.noreply.github.com>
2025-03-31 16:09:26 -07:00
Kai Tao
16157231d4 [CmdPlt] [Bug template] Update issue template for command palette (#38189)
Update issue template for command palette
2025-03-27 15:19:01 +08:00
Niels Laute
a641b46f57 [CmdPal] Updating icon (#38184)
* Replacing dev icons

* Replacing stable icons

* Adding icon to UI

* Replacing release assets

* Adding svg

* Minor margin tweak to app icon in searchbar

* Update icon in Settings

* Remove margin from settingswindow icon
2025-03-26 15:09:31 -07:00
Mike Griese
51e9e9d46a CmdPal: Update the alias tags, before triggering the UI to change (#38172)
Yea, this one hurts. Pretty obviously, we're sending the PropChanged
_before_ the `Tags` are actually updated.

Noticed on 0.0.16+ builds
2025-03-26 14:18:18 -07:00
Mike Griese
5157ffc895 cmdpal: Skip dependency installs for extensions (#38175)
It appears there are two issues in WinGet regarding the installation of dependencies.

https://github.com/microsoft/winget-cli/issues/4661 https://github.com/microsoft/winget-cli/issues/4679

For CmdPal 0.1, we're going to skip installing dependencies to make extension installation more robust. This will mostly work because extensions will depend on the same frameworks as the command palette itself (for now).

We will revert this once these two issues are fixed.
2025-03-26 14:16:34 -07:00
Mike Griese
60bbf070e1 Update Fallback commands async, once (#38157)
The problem: 

> * we need to go update all the Fallback commands. (these are ones that extensions can use to react to the search text - basically, "what the user typed wasn't found immediately, but here's something they can fall back on"
>   * this is wacky, because the way I had it, I update each item, and if it "changes visibility", then we need to update the main list, because we've already removed it from the list. So we need to re-update the list to account for that
>     * you missed it reading that (and i missed it writing it) but that basically means we re-populate the list F={num fallbacks} times, because each one sends the "do it again" message
>     * That results in us basically creating (F+1)*(N=num items+apps) view models, initializing them, and not needing most of them

The crux here being a single thread, to update all the fallback items,
that then only raises _one_ items changed at the very end.

I don't love this, one misbehaving fallback could stop all the others. In theory, we should do a parallel update of all these things, with a like, 1s timeout on each leg. 

But it has gotta be faster till we can do #38140 (or similar)

Closes: (not sure I filed one). But the first typed character _felt_ slow.
2025-03-26 04:36:37 -07:00
Mike Griese
d597bd267d Hide commands with whitespace only names better (#38159)
This is a much tidier solution. Don't default _everything_ to a weight of 1 if the query is whitespace. Instead, do a simple string contains check (because FuzzySearch will beef it on just whitespace)

Closes #38133

I originally based this off of #38157, so I know these two won't collide
2025-03-26 04:36:32 -07:00
Dustin L. Howett
2623eb10f3 CmdPal: add appLicensing for offline install; disable startup (#38152)
- `appLicensing` avoids the issue where installation requires access to the store servers for licensing.
- It was decided that PowerToys would manage CmdPal's startup.
2025-03-26 04:35:53 -07:00
Mike Griese
8e27940b77 Fixes a race in extension startup (#38156)
This only repros on my desktop, so I suppose that means a slower machine is needed

I was mistaken, and assumed we were already operating on a copy here. We weren't. That meant that it was possible for another extension to be detected, change the list, and crash the whole palette.

## Validation Steps Performed

No longer does my desktop crash on startup
2025-03-26 04:35:41 -07:00
moooyo
c6750d3a62 [cmdpal] Fix windows service extension crash issue (#38166)
repro step:
change language to non-english language. stably reproducible.

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
2025-03-26 04:34:59 -07:00
Davide Giacometti
37836c656d [CmdPal] Fix Layout cycle detected. Layout could not complete (#38162)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request

Attempt to fix `Layout cycle detected. Layout could not complete` exception when CmdPal is moved on a screen with different DPI.
I can repro almost 100% and no longer occurs after switching tags `ItemsView` with `ItemsControl`.

Doesn't seem to break visual and don't expect a huge number of tags so use an `ItemsControl` shouldn't be a problem.

<img width="491" alt="image" src="https://github.com/user-attachments/assets/05b698b2-ebe7-4356-bdaa-4de93aea13e6" />

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] **Closes:** #xxx
- [ ] **Communication:** I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end user facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
   - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries
   - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder
   - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects
   - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2025-03-26 03:11:43 -07:00
Stefan Markovic
39e8231831 [CmdPal] Windows Services restart kb shortcuts (#38150)
* [CmdPal] Windows Services open/restart kb shortcuts

* Given both restart and stop has its shortcut, only do for open with the shortcut "ctr+o"
2025-03-26 15:55:40 +08:00
Mike Griese
2cb63f5fbe CmdPal: Fix opening SUI pages in other languages (#38153)
What we were doing only worked in English. The `.ToString` would get
you the text of the nav item, not the `Tag`

`InvokedItemContainer` gets you the `NavigationViewItem`.
2025-03-26 15:23:59 +08:00
Niels Laute
e931135d50 [CmdPal] Disabling RequestedShortcut in XAML (#38158)
Update CommandBar.xaml
2025-03-26 15:21:56 +08:00
Jaime Bernardo
5b39d1551d [CmdPal]Fix Calc and Command extension fallback command icons (#38146) 2025-03-26 15:21:28 +08:00
Seraphima Zykova
5e88d47f3d [CmdPal] Registry: typing "\" causes the page to throw an exception (#38151)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request

Calling `string.Replace` with an empty string as the first parameter was raising an exception. Added a check to prevent this.

![image](https://github.com/user-attachments/assets/42ee67f2-a648-4543-9994-0e37de50dcdf)

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] **Closes:** #xxx
- [ ] **Communication:** I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end user facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
   - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries
   - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder
   - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects
   - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2025-03-25 13:13:07 -07:00
Jaime Bernardo
aeec3a967f [CmdPal]Fix resetting the hotkey in Settings (#38149)
Fix resetting the hotkey in Settings
2025-03-25 18:58:46 +00:00
Niels Laute
be1968aaa5 [CmdPal] Minor tweaks to the General settingspage (#38120)
Minor tweaks to the General settingspage
2025-03-24 21:13:24 +01:00
Heiko
33cc612e40 [CmdPal] Fixes for Exts: All Apps, System Commands, Time And Date (#38103)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request

All apps:
- Fix missing second command for opnening settings page

Time and Date plugin:
- fix for missing settings list in global plugin manager
- fix for wrong page title

system plugin
- fix for missing settings page in global plugin manager
- fix for missing open button on plugin list
- ~fix for wrong icon for firmware boot~
- fix for wrong subtitle for ipv6
- fix for wrong details for mac address
- fix for wrong layout of network details
- layout improvements for network details
- change default value for "hide disconected networks" to $false
- rename empty recycle bin setting to "Hide Empty Recycle Bin command"

![image](https://github.com/user-attachments/assets/fba608ca-3229-408e-9efb-596ead03ac19)

![image](https://github.com/user-attachments/assets/8b3a4ab1-499a-4e3c-8c2e-be19162d971b)

![image](https://github.com/user-attachments/assets/fd5d2a3c-6a9a-4990-a006-70646405d165)



<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] **Closes:** #xxx
- [ ] **Communication:** I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end user facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
   - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries
   - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder
   - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects
   - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2025-03-24 11:39:08 -07:00
Davide Giacometti
a9a41ca1a2 [CmdPal] Settings UI polishing (#38094)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request

Settings window UI polishing:
- Make the navigation view toggle button move in the title bar when navigation view mode is compact or minimal
- Center settings card in the window
- Properly set windows icon in order to make it visible in task manager and task view

_main branch_
![image](https://github.com/user-attachments/assets/792f0779-016a-4056-81b0-04244d903909)

![image](https://github.com/user-attachments/assets/81ac2761-2a9c-4fe7-a122-2f69f900e656)

_PR_
![image](https://github.com/user-attachments/assets/029b95a0-9629-4732-9f0c-bf586954e887)

![image](https://github.com/user-attachments/assets/81bb2beb-9a07-42cf-8594-16ba5a9cda1b)

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] **Closes:**: https://github.com/zadjii-msft/PowerToys/issues/581

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
2025-03-24 07:32:59 -07:00
Mike Griese
4e7bd34c4d Pass FG rights to extensions when we access them (#38068)
Calling Win32 APIs from C# is usually easy! but mixing C#+WinRT+COM is dark and full of terrors

Closes https://github.com/zadjii-msft/PowerToys/issues/546


Co-authored-by: Manodasan Wignarajah <mawign@microsoft.com>
2025-03-24 04:29:40 -07:00
Mike Griese
43783d2cff Use Shmueli's COM server to fix ARM (#38090)
More than a couple people hit mYsTeRiOuS iSsUeS on ARM. Extensions would load the first time, but never again. Their processes would start, but the objects would fail to load.

Fortunately, @azchohfi discovered that using `Shmuelie.WinRTServer`, rather than the one pilfered from devhome, doesn't have this problem.

I don't have an ARM machine to validate the changes, but @lauren-ciha thankfully did the groundwork to get this validated in their extension, so I think this should work. 

Closes https://github.com/zadjii-msft/PowerToys/issues/97
2025-03-24 03:43:47 -07:00
Niels Laute
79bd825f91 [cmdpal] UX tweaks (#38087)
- Removing the redundant icon + text in the bottom left corner
- Minor styling tweaks
- Adding subtle show/hide animations
- Improved narrator support for Settings button
- Minor design tweaks to the tags for better visibility (still needs more work in the future)

![SubtleAnimations](https://github.com/user-attachments/assets/d2f6bec3-f8d6-48a4-a533-c0f2e0c81f8c)
2025-03-24 03:13:19 -07:00
Niels Laute
69c2e9c568 [CmdPal] Adding colored extension icons (#38085)
* Updating run icon
* Bookmark
* System
* WindowWalker
* Extensions
* CreateExtensions
* Services
* Replacing icon

This PR updates the Segoe Fluent icons with colored Fluent icons.

![image](https://github.com/user-attachments/assets/8c1350a1-963b-4deb-9029-966ba0a3c0fb)
2025-03-24 03:01:33 -07:00
Felipe G
df3e3414d2 Fixing command duplicates when loading commands from provider (#38091)
There is a bug in command palette where the top level commands from extensions gets duplicated after the extension raises items changed, or when it is requested by CmdPal for any reason. This didn't happen when we kill CmdPal and open it again.

When investigating, I noticed that the `UpdateCommandsForProvider` method was not deleting the top level commands for the extension.
This seems to be happening because the comparison `var isTheSame = wrapper == firstCommand;` is not comparing objects of the same type. It was comparing a `TopLevelViewModel` with a `CommandItem`, and it was never set to `true`.

I change it to compare the `TopLevelViewModel` of both commands, and now it seems to be detecting correctly.

Another option of fix could be comparing the `CommandItem`s. 

closes https://github.com/zadjii-msft/PowerToys/issues/511

---

Another bug that I found while testing today is that when a user uninstalled or updated an extension, it was still being listed as an enabled extension. This was generating duplicates in the top level commands in case of updating an extension, and resulting in unpredictable behavior and occasional crashes in CmdPal.

Added a fix for that on `ExtensionService`, removing the uninstalled extensions also from the `_enabledExtensions` list.

---------

Co-authored-by: Mike Griese <migrie@microsoft.com>
2025-03-24 03:00:34 -07:00
Davide Giacometti
7368458a72 [CmdPal] Single settings window (#38069)
## Summary of the Pull Request

Make settings window single.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] **Closes:** https://github.com/zadjii-msft/PowerToys/issues/581

## Validation Steps Performed

Manual test.
- Open settings windows multiple times
- Activate minimized settings window
2025-03-21 12:58:47 -07:00
moooyo
4d7691a56f [cmdpal] Fix winget extension crash issue (#38074)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
I don't know why defaultInstalledVersion becomes null. But, at least we need to fix it...


Test case: vscode.
![image](https://github.com/user-attachments/assets/17d14d62-066d-4032-b40c-f7339c25f899)


Closes https://github.com/zadjii-msft/PowerToys/issues/572

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
2025-03-21 08:37:17 -07:00
Stefan Markovic
2f9fea2287 [Installer]Fix msix package removal for per-user installer (#38079) 2025-03-21 14:45:46 +00:00
moooyo
29551898ca [cmdpal] Fix some i18n issues for built-in extensions (#38078)
Fix some i18n issues for built-in extensions.



Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
2025-03-21 03:48:28 -07:00
Jaime Bernardo
048b07c1ce [Installer]Properly update CmdPal on upgrade (#38070)
* [Installer]Properly update CmdPal on upgrade

* Update installer/PowerToysSetupCustomActions/CustomAction.cpp
2025-03-21 10:39:27 +00:00
moooyo
7575c040f8 [cmdpal] Fix "copy file path" function in file search extension (#38077)
The original code not work. It will throw com exception.

I prefer to use ClipboardHelper one.

-----

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
2025-03-21 03:35:00 -07:00
Jaime Bernardo
e52dd68fe4 [OOBE]Show actual CmdPal hotkey (#38067)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request

Update OOBE's CmdPal page to show the actual hotkey and style it similar to other OOBE pages.

![image](https://github.com/user-attachments/assets/c92beafc-52c2-4896-90bb-c4a8252f9768)


<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Open OOBE and verify it looks like other OOBE pages.
2025-03-20 13:37:33 -07:00
Stefan Markovic
3e9a6a1e64 [cmdpal] WIP add telemetry (#38032)
Related to https://github.com/microsoft/PowerToys/pull/37908

Closes https://github.com/zadjii-msft/PowerToys/issues/520
---------

Co-authored-by: Mike Griese <migrie@microsoft.com>
2025-03-20 13:36:58 -07:00
Mike Griese
14919dff10 CmdPal: Fix SUI crash ; Allow extensions to be disabled (#38040)
Both `TopLevelCommandItemWrapper` and `TopLevelViewModel` were really the same thing. The latter was from an earlier prototype, and the former is a more correct, safer abstraction. We really should have only ever used the former, but alas, we only used it for the SUI, and it piggy-backed off the latter, and that meant the latter's bugs became the former's.


tldr: I made the icon access safe in the SUI. 

And while I was doing this, because we now have a cleaner VM abstraction here in the host, we can actually cleanly disable extensions, because the `CommandProviderWrapper` knows which `ViewModel`s it made. 

Closes https://github.com/zadjii-msft/PowerToys/issues/426
Closes https://github.com/zadjii-msft/PowerToys/issues/478
Closes https://github.com/zadjii-msft/PowerToys/issues/577
2025-03-20 13:36:10 -07:00
Mike Griese
57cbcc2c3e CmdPal: Disable registry virtualization (#38055)
I forgot that packages write to a virtualized registry, rather than the
real one. As it turn out, the registry plugin requires being able to
write to the registry to be able to open the correct location

Closes #38053
2025-03-20 11:30:56 -07:00
leileizhang
5d03667bcf Revert "Svg thumbnail failed rendering (#32936)" as it caused a regression (#38058)
Revert "Svg thumbnail failed rendering (#32936)"

This reverts commit 1d358af600.
2025-03-20 17:50:20 +00:00
Jaime Bernardo
2b4d13ccb9 [GPO]Fix missing resource string for NewPlus in 0.90 (#38064) 2025-03-20 17:00:01 +00:00
Stefan Markovic
665e957cde [settings] Show uneditable shortcut in CmdPal page (#38060)
* [settings] Show CmdPal shortcut
* show in dashboard as well


![image](https://github.com/user-attachments/assets/395d112d-162c-412c-99c2-2625b23cc451)

![image](https://github.com/user-attachments/assets/a0362e2b-e647-4a19-b4ff-fdb501e236d7)

As noted in #37908
2025-03-20 08:20:19 -07:00
Stefan Markovic
dadd306555 Do not show CmdPal on startup (#38027)
Adds a command line arg to not show CmdPal on startup. When starting from PT Run, we won't immediately show the window. 

as noted in #37908
2025-03-20 07:48:15 -07:00
Mike Griese
68f76409ab Add docs link to nuget README (#38042)
The nuget package needs a README without a TODO! link.

This is just a docs change.

(already validated that it works with CI run 118608202)
2025-03-19 18:00:47 -07:00
Mike Griese
bf877c4e40 Update the OOBE text for CmdPal (#38041)
* Update the OOBE text for CmdPal
* Tweak format to align with other OOBE pages

---------

Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
2025-03-19 17:59:30 -07:00
Stefan Markovic
53003b9969 Localize CmdPal settings page (#38026)
* Localize CmdPal settings page
* Xaml format
* Fix it

Follow up to #37908
2025-03-19 14:00:25 -07:00
Heiko
394583fca9 Fix NOTICE.md (#38034)
Update NOTICE.md
2025-03-19 11:36:48 -07:00
Jaime Bernardo
20cd0ec7f4 [CI]Bring back .NET 6 for signing tasks to fix pipelines (#38036) 2025-03-19 18:33:36 +00:00
Jaime Bernardo
dfb727f9a3 [Settings]Add the New badge to CmdPal (#38037) 2025-03-19 17:51:58 +00:00
Stefan Markovic
a13abc3803 [cmdpal] Bring back editorconfig (#38031)
* Bring back .editorconfig
* Remove exclusion.dic
2025-03-19 06:43:32 -07:00
Mike Griese
f68f408be3 Add the Command Palette module (#37908)
Windows Command Palette ("CmdPal") is the next iteration of PowerToys Run. With extensibility at its core, the Command Palette is your one-stop launcher to start _anything_.

By default, CmdPal is bound to <kbd>Win+Alt+Space</kbd>.

![cmdpal-pr-002](https://github.com/user-attachments/assets/5077ec04-1009-478a-92d6-0a30989d44ac)
![cmdpal-pr-003](https://github.com/user-attachments/assets/63b4762a-9c19-48eb-9242-18ea48240ba0)

----

This brings the current preview version of CmdPal into the upstream PowerToys repo. There are still lots of bugs to work out, but it's reached the state we're ready to start sharing it with the world. From here, we can further collaborate with the community on the features that are important, and ensuring that we've got a most robust API to enable developers to build whatever extensions they want. 

Most of the built-in PT Run modules have already been ported to CmdPal's extension API. Those include:
* Installed apps
* Shell commands
* File search (powered by the indexer)
* Windows Registry search
* Web search
* Windows Terminal Profiles
* Windows Services
* Windows settings


There are a couple new extensions built-in
* You can now search for packages on `winget` and install them right from the palette. This also powers searching for extensions for the palette
* The calculator has an entirely new implementation. This is currently less feature complete than the original PT Run one - we're looking forward to updating it to be more complete for future ingestion in Windows
* "Bookmarks" allow you to save shortcuts to files, folders, and webpages as top-level commands in the palette. 

We've got a bunch of other samples too, in this repo and elsewhere

### PowerToys specific notes

CmdPal will eventually graduate out of PowerToys to live as its own application, which is why it's implemented just a little differently than most other modules. Enabling CmdPal will install its `msix` package. 

The CI was minorly changed to support CmdPal version numbers independent of PowerToys itself. It doesn't make sense for us to start CmdPal at v0.90, and in the future, we want to be able to rev CmdPal independently of PT itself. 


Closes #3200, closes #3600, closes #7770, closes #34273, closes #36471, closes #20976, closes #14495
  
  
-----

TODOs et al


**Blocking:**
- [ ] Images and descriptions in Settings and OOBE need to be properly defined, as mentioned before
  - [ ] Niels is on it
- [x] Doesn't start properly from PowerToys unless the fix PR is merged.
  - https://github.com/zadjii-msft/PowerToys/pull/556 merged
- [x] I seem to lose focus a lot when I press on some limits, like between the search bar and the results.
  - This is https://github.com/zadjii-msft/PowerToys/issues/427
- [x] Turned off an extension like Calculator and it was still working.
  - Need to get rid of that toggle, it doesn't do anything currently
- [x] `ListViewModel.<FetchItems>` crash
  - Pretty confident that was fixed in https://github.com/zadjii-msft/PowerToys/pull/553

**Not blocking / improvements:**
- Show the shortcut through settings, as mentioned before, or create a button that would open CmdPalette settings.
- When PowerToys starts, CmdPalette is always shown if enabled. That's weird when just starting PowerToys/ logging in to the computer with PowerToys auto-start activated. I think this should at least be a setting.
- Needing to double press a result for it to do the default action seems quirky. If one is already selected, I think just pressing should be enough for it to do the action.
  - This is currently a setting, though we're thinking of changing the setting even more: https://github.com/zadjii-msft/PowerToys/issues/392
- There's no URI extension. Was surprised when typing a URL that it only proposed a web search.
- [x] There's no System commands extension. Was expecting to be able to quickly restart the computer by typing restart but it wasn't there.
  - This is in PR https://github.com/zadjii-msft/PowerToys/pull/452  
  
---------

Co-authored-by: joadoumie <98557455+joadoumie@users.noreply.github.com>
Co-authored-by: Jordi Adoumie <jordiadoumie@microsoft.com>
Co-authored-by: Mike Griese <zadjii@gmail.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Michael Hawker <24302614+michael-hawker@users.noreply.github.com>
Co-authored-by: Stefan Markovic <57057282+stefansjfw@users.noreply.github.com>
Co-authored-by: Seraphima <zykovas91@gmail.com>
Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
Co-authored-by: Kristen Schau <47155823+krschau@users.noreply.github.com>
Co-authored-by: Eric Johnson <ericjohnson327@gmail.com>
Co-authored-by: Ethan Fang <ethanfang@microsoft.com>
Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Clint Rutkas <clint@rutkas.com>
2025-03-19 01:39:57 -07:00
PesBandi
a62acf7a71 [PTRun][UnitConverter]Add support for sq prefix for square units (#37862)
* [PTRun][UnitConverter]Add support for `sq` prefix for square quantities
2025-03-19 08:37:43 +08:00
Davide Giacometti
648c3eb0bf [OOBE] Fix release notes error InfoBars (#37804)
* fix infobars not visible
* minor changes and retry button when there is error to loading the release note page
2025-03-19 08:12:29 +08:00
Clint Rutkas
f6b53d1088 Adding in monaco usage for Reg preview (#37947)
* Adding in monaco usage for Reg preview

Looks like this was missed, adding in

* Add Monaco Editor license to NOTICE.md

adding in with peek

* Adding Registry Preview to top bullet list
2025-03-18 15:31:01 -07:00
Jaime Bernardo
8862b22c45 [ImageResizer]Fix use without initializing warning (#29236)
[ImageResizer]Fix use without initializing warn
2025-03-19 00:24:34 +08:00
dreamstart
4377de260f [AOT] add some mudole editor open time, timestamp telemetry code (#38008)
* add some mudole editor open time, timestamp telemetry code

* fix spelling error

* fix namespace warrning

---------

Co-authored-by: Zhaopeng Wang (from Dev Box) <zhaopengwang@microsoft.com>
2025-03-18 21:52:24 +08:00
Christian Gaarden Gaardmark
1f81d14000 [New+]Support for variables in template filenames (#37074)
* Add variable support - initial version without UI

* Add variable in template filename support in New+

* Fix XAML style

* Addressed code review feedback
2025-03-18 11:52:51 +00:00
gokcekantarci
1d358af600 Svg thumbnail failed rendering (#32936)
* [SVGThumbnail] Check fill-rule in SVG file and apply it.

* [SVGThumbnail] Comment added

* [SVGThumbnail] SvgContents is used instead of all html content.

* [SVGThumbnail] - Use SvgContents to extract and modify SVG styles efficiently
- Add retry logic and error handling for WebView2 initialization

* use Linq

---------

Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
Co-authored-by: Leilei Zhang <leilzh@microsoft.com>
2025-03-18 19:25:51 +08:00
Laszlo Nemeth
18a1107ec4 [Workspaces]Fix snapshotting minimized apps (#37598)
* Fix snapshotting minimized packaged apps

* Fix window arranger to work with the same windows as the snapshot tool.

* spell checker

* optimising code

* Remove filter condition.
2025-03-18 11:21:40 +00:00
Dave Rayment
8e90d8e4c5 [Peek]Add Delete functionality (#35418)
* Add Delete functionality for Peek.

* Updated the "No More Files" text block to use a Uid to load its resource text. Also altered the text style to be consistent with the FailedFallbackPreviewControl error page.

* Revert "Delete Directory.Packages.props"

This reverts commit 3a10918c9f91de64785722e4bdb33c58d1c2daea.

* Attempt to appease the spell-checking bot by renaming flag const.

* Show error message InfoBar if file deletion failed.

* Resolve XAML styling.

* XAML styling fix.

* Settings app updates for new delete confirmation setting.

* Add delete confirmation dialog and settings to Peek. Add shell notification event after delete operation.

* Spelling updates.

* Spelling update.

* Remove permanent delete parameter, YAGNI. Add hwnd parameter to delete so warning dialogs are correctly parented. Fix flags to not hide permanent delete warning.

* Simplify delete confirmation dialog. Remove workaround for focus visual issue. Ensure delete confirmation dialog is closed when the main window visibility is toggled.

* Fix delete delay. Do not regard user cancellations of permanent deletes as an error, but log them as info anyway. More descriptive name for delete confirmation dialog checkbox.

* Fix multiple Content_KeyUp events being raised for MainWindow.

* Synchronise ConfirmFileDelete setting between Peek and Settings app.

* Update following review: split System usings from others; do not log deleted item name.

* Fix XAML style
2025-03-18 08:59:20 +00:00
moooyo
abd6314b2e [PT Run] Async the OnRename to unblock thread (#37987)
* Rename name to async and try catch to handle exception.

* Fix ut

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
2025-03-18 15:51:34 +08:00
Ionuț Manța
a298f67b81 [PTRun] Fix round corners crashing on 22000 (#36681)
Fix round corners crashing on 22000
2025-03-17 23:15:41 +00:00
Michael Clayton
c89280cd9e [MWB] - refactoring "Common" classes (Part 4) (#37579)
* [MouseWithoutBorders] - moving Common.Event.cs -> Core\Event.cs - #35155

* [MouseWithoutBorders] - moving Common.Service.cs -> Core\Service.cs - #35155

* [MouseWithoutBorders] - moving Common.Launch.cs -> Core\Launch.cs - #35155

* [MouseWithoutBorders] - moving Common.Helper.cs -> Core\Helper.cs - #35155

* [MouseWithoutBorders] - refactoring and fixes for logger unit test - #35155

* [MouseWithoutBorders] - cleaning up changes - #35155

* [MouseWithoutBorders] - re-[Ignore]-ing test - #35155
2025-03-17 22:05:36 +00:00
Davide Giacometti
0e62e2ddd4 [CI] Upgrade XamlStyler and remove .NET6 dependency (#37574)
* Bump XamlStyler and remove .NET6 CI dep

* XamlStyler failure test

* fix xaml formatting

* Bump dotnet-consolidate
2025-03-17 20:15:18 +01:00
Heiko
7bdd6c660a [Settings > PT Run > Plugin settings] Disable spell check in text boxes (#37744)
Add SpellCheck property in xaml
2025-03-17 00:30:27 +08:00
dreamstart
53f8499434 Dev/zhaopengwang/test/37733 UI test fancyzones editor (#37769)
* first launch test

* add FancyZonesEditorHelper

* click monitor test and add FindByAccessibilityId function

* add ui initialization tests and add exit scope exe function

* add cleanup test function and change file init

* add TemplateLayoutsTest and add LayoutTypeEnumExtension.cs and Element class add sendkey function

* add UI Initialize Test

* add OpenEditLayoutDialog test case and add By type

* add LayoutHotkeysTest

* add EditLayoutTests and add element drag function

* add DeleteLayouTest and change cleanup to base class and change FindByAccessibilityId to By.AccessibilityId

* add DefaultLayoutsTest

* add CustomLayoutsTest

* add CreateLayoutTest

* add CopyLayoutTest

* add ApplyLayoutTest

* add some cleanup code

* fix spelling error

* fix DeleteLayoutWithHotkey test code bug

* change code

* fix restart exe some bug

* move first lunch text code to new file

* test write file error

* fix test code init fancyzone file error

* test maxsize button

* get current window size

* change layout count

* change test case work windows size

* change fancyzone editor window size

* change fancyzone editor window size and change element move rule

* change window size

---------

Co-authored-by: Zhaopeng Wang <zhaopengwang@microsoft.com>
2025-03-14 17:04:23 +08:00
moooyo
39073f0467 Fix the problem which Powertoys Run shows duplicated applications. (#37924)
init

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
2025-03-14 10:33:15 +08:00
dreamstart
924898ae94 [FancyZones][Bug Fix] Layout hotkey show bug and update file bug (#37902)
fix Layout hotkey show bug and update file bug

Co-authored-by: Zhaopeng Wang <zhaopengwang@microsoft.com>
2025-03-14 00:48:21 +08:00
chenmy77
a00f56e317 [Fuzz] Add Fuzz testing for RegistryPreview (#37607)
* Add fuzz test cases

* add fuzz tests framework in registrypreview

* add registrypreview fuzzing code

* add annotations and change net7.0--net8.0

* merge main into code

* add registry fuzz sln

* change fuzzing tests scope

* remove unuse annotations

* fix typos

* change public parser to internel and private

* fix linelower error and modify filenametext to registryContent

* Revert "fix linelower error and modify filenametext to registryContent"

This reverts commit e8269b8af2.

* add fuzz tests in sln

* modify typos

* clean code

Co-authored-by: leileizhang <leilzh@microsoft.com>

* add annotations

---------

Co-authored-by: leileizhang <leilzh@microsoft.com>
2025-03-13 10:23:02 +08:00
dreamstart
2b7307d32e [FancyZones][Bug Fix] fix fancyzone editor layout hotkeys show error (#37877)
fix fancyzone editor layout hotkeys show error

Co-authored-by: Zhaopeng Wang <zhaopengwang@microsoft.com>
2025-03-13 02:54:59 +08:00
Ionuț Manța
92fb931e1e [ColorPicker]Port UI from WPF-UI to .net 9 WPF (#37149)
* Initial implementation

* fix style

* Added border to popup

* More changes

* Now use accent color for select button

* Addressed feedback

* fix formatting

* Fix pressing the select in HC mode hiding its text

* Fix W10 hc1 and hc2 hover select button text invisible

* Update src/modules/colorPicker/ColorPickerUI/Controls/ColorPickerControl.xaml

Co-authored-by: Niels Laute <niels.laute@live.nl>

* Addresed feedback regarding FontFamily

* Made the titlebar part of the body

* fix wrong variable

* Added system menu option on right click on toolbar.
Fixed hide then show removing Mica effect

* Fix spell-check

* Fix xaml styling

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
2025-03-12 12:15:17 +00:00
Kai Tao
82bc3b7c85 [MWB][Logger] Make logger actually track the code (#37896)
Make logger actually track the code
2025-03-12 16:44:05 +08:00
Gordon Lam
ccb77ff601 The default generated file path exceeds the length limit 260 for EnvironmentVariablesUILib.csproj (#37685)
The default generated file path exceeds the length limit 260 on the build agent. Using a shorter path as a workaround.
2025-03-12 10:15:04 +08:00
Jaime Bernardo
bbc8beb006 [Deps]Update dependencies to .NET 9.0.3 (#37887) 2025-03-11 22:12:54 +00:00
Jaime Bernardo
3b05cf127a [Deps]Upgrade Windows App SDK to 1.6.250205002 and CsWinRT to 2.2.0 (#37879)
* [Deps]Upgrade WindowsAppSDK to 1.6.250205002 and CsWinRT

* Upgrade WindowsSdkPackageVersion as well
2025-03-11 14:12:32 +00:00
Sameer Singh
8494858314 [PTRun][Docs] Add SVGL to Third-Party plugins (#37718)
* add: SVGL to Third-Party plugins

* resolve spellcheck, new words
2025-03-10 16:32:03 -07:00
8LWXpg
04c80c40a2 [PTRun][Docs] Add FirefoxBookmark to Third-Party plugins (#37414)
Update thirdPartyRunPlugins.md
2025-03-10 16:27:04 -07:00
Clint Rutkas
42edf9da97 Remove bypass for MD files w/ CI (#37825)
* removing precheck as we need all flows to have CI checked off now

* adding catch by dustin
2025-03-10 12:48:45 -07:00
Mario Hewardt
c38faa959a Test ZoomIt PR (#37809)
* Test ZoomIt PR

* Test ZoomIt PR

* Test ZoomIt PR

* Test ZoomIt PR
2025-03-07 12:35:44 -08:00
dreamstart
fc94cd758e [FancyZones][Fix Bug] delete layout write wrong date to json file (#37763)
fix delete layout write json file bug

Co-authored-by: Zhaopeng Wang (from Dev Box) <zhaopengwang@microsoft.com>
2025-03-05 20:43:36 +08:00
Gordon Lam
61a00aa669 0.89 changelog (#37736)
* First Draft

* Update according to comments as well as re-reading

* Finished multiple wording comments

* Removed the module name that appeared at the beginning of the sentence, as it was already included in the section name.
2025-03-04 21:31:18 -05:00
Muhammad Danish
cca3f442e2 Update WinGet configuration file location & extension (#37673)
Update configuration file location & extension
2025-03-03 20:47:57 -08:00
Jerry Xu
22e29d1253 [Hosts] Converting manual release-check-list tests to UI-Test Automation and Adding more UI-Test-cases (#37657)
* Add more UI-Test, refactor UITestAutomation

* Convert manual test-case to automation

UI-Tests:

Validating Empty-view is shown if no entries in the list.
Validating Empty-view is NOT shown if 1 or more entries in the list.
Validating Add-an-entry HyperlinkButton in Empty-view works correctly.
Validating Adding-entry Button works correctly.
Validating the Add button should be Disabled if more than 9 hosts in one entry.
Validating the Add button should be Enabled if less or equal 9 hosts in one entry.
Validating error message should be shown if not run as admin.
Validating Warning-Dialog will be shown if 'Show a warning at startup' toggle is On.
Validating Warning-Dialog will NOT be shown if 'Show a warning at startup' toggle is Off.
Validating click 'Quit' button in Warning-Dialog, the Hosts File Editor window would be closed.
Validating click 'Accept' button in Warning-Dialog, the Hosts File Editor window would NOT be closed.

---------

Co-authored-by: Jerry Xu <nxu@microsoft.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-02-28 19:08:08 +08:00
Laszlo Nemeth
8a2d4745fa [PTRun]Fix locking link files for MSI installers. Warning 1946 (#37654)
* [Runner] fix MSI installer issue. Warning 1946

* Fix catching exceptions

* Better error handling

* Revert "Better error handling"

This reverts commit 0f3ec2a3ef.
2025-02-27 19:17:43 +00:00
leileizhang
bf2685757a [CI] Use Download Task for X64 and Bypass ARM Testing for Forked Repositories (#37617)
* use x64

* add conditation for arm tests

* check repo

* use System.PullRequest.IsFork

* remove print

* remove condition
2025-02-27 16:39:25 +08:00
Laszlo Nemeth
b8cef42776 [Workspaces] Fix regression when capturing minimized apps (#37599) 2025-02-26 12:51:46 +01:00
Jerry Xu
959a54bcd9 Revert "[Hosts] Add UITest Cases for Hosts Module" (#37619)
* Revert "[Hosts] Add UITest Cases for Hosts Module (#37600)"

This reverts commit c656dcc9c5.

* Matching all UITest projects and UITestAutomation project

* Add back Hosts UITests

---------

Co-authored-by: Jerry Xu <nxu@microsoft.com>
2025-02-26 07:55:15 +08:00
Smeagol
491d51afaf [QuickAccent]Add final sigma ( ς ) to the Greek character set (#37611) 2025-02-25 22:35:22 +00:00
Ani
f263042aeb [AdvancedPaste]Add paste actions to allow transcoding of media files (#37188)
* [AdvancedPaste] Additional actions, including Image to text

* Spellcheck issue

* [AdvancedPaste] Paste as file and many other improvements

* Fixed typo

* Fixed typo

* [AdvancedPaste] Improved paste window menu layout

* [AdvancedPaste] Improved settings window layout

* [AdvancedPaste] Removed AudioToText for the moment

* Code cleanup

* Minor fixes

* [AdvancedPaste] Semantic Kernel support

* Changed log-line with potentially sensitive info

* Spellcheck issues

* Various improvements for Semantic Kernel

* Spellcheck issue

* Refactored Clipboard routines

* Added integration tests for KernelService

* Extra telemetry for AdvancedPaste

* Added 'Hotkey' suffix to AdvancedPaste_Settings telemetry event

* Added IsSavedQuery

* Added KernelQueryCache

* Refactoring

* Added KernelQueryCache to BugReportTool delete list

* Added opt-n for Semantic Kernel

* Fixed bug with KernelQueryCache

* Ability to view last AI chat message on error

* Improved kernel query cache

* Used System.IO.Abstractions and improved tests

* Fixed under-count of token usage

* Used Semantic Kernel icon

* Cleanup

* Add missing EndProject line

* Fix dependency version conflicts

* Fix NOTICE.md

* Correct place of SemanticKernel in NOTICE.md

* Unlinked CustomPreview toggle from AI

* Added Microsoft.Bcl.AsyncInterfaces dependency to AdvancedPaste

* Fixed NOTICE.md order

* Moved Custom Preview to behaviour section

* Made Image to Text raise error on empty output

* Added AIServiceBatchIntegrationTests

* Updated AIServiceBatchIntegrationTests

* Added prompt moderation

* [AdvancedPaste] Media Transcoding support

* Spellcheck issue

* Improved transcoding output profile and added tests

* Moved GPO Infobar to better location

* Added cancel button and minor bug fixes

* Fixed crash

* Minor cleanups

* Improved transcoding error messages

* Used software back when transcoding fails with hardware accerlation

* Added Reencode to spellcheck

* Spellcheck issue

---------

Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
Co-authored-by: Dustin L. Howett <dustin@howett.net>
Co-authored-by: Jeremy Sinclair <4016293+snickler@users.noreply.github.com>
2025-02-25 21:33:39 +00:00
moooyo
c09a5337c4 [AOT] Refactor Logger function to improve performance and mark managedCommon as AOT compatible (#36327)
* Use function to init static value

* Replace GetFileName with GetFileNameWithoutExtension

* Add exception catch for GetCallerInfo

* Remove sourceLineNumber

* Add kernal to allow list

* Remove unused commit

* Add new folder to place source generation context

* update

* fix build issue

* Move line number back

* Use fileName to replace full path

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
2025-02-26 00:12:38 +08:00
Ionuț Manța
9a658eb884 [PTRun] Disable CETCompat in Launcher (#37550)
* Disable CETCompat in Launcher

* Added comment

* Improved comment
2025-02-25 11:34:30 +00:00
Kai Tao
4eb11d6f9b [Workspaces][ARM64] Bring icon to packaged apps (#37625)
Bring icon to packaged apps
2025-02-25 19:17:41 +08:00
Dave Rayment
a5a354a70f [ImageResizer] Fix issues with blank Width and Height controls (#37373)
* Allow custom preset's dimensions to be blank in the UI while still persisted as 0.

* XAML formatting - reorder namespaces.

* Add "(auto)" text to zero-value Width/Height in Settings. Ensure Width and Height fields in flyout are formatted to empty when their value is 0.
2025-02-25 16:23:30 +08:00
Ionuț Manța
744316c400 [Settings]Fix ColorPicker dashboard shortcut (#37547)
* Fix color picker dashboard shortcut

* remove not needed code

* Remove comment
2025-02-24 23:14:45 +00:00
Jaime Bernardo
f2370912f3 [ci]Sign and fix KeyboardManagerEditorLibraryWrapper.dll (#37601)
* [ci]Sign KeyboardManagerEditorLibraryWrapper.dll

* Fix dll metadata
2025-02-24 21:12:42 +00:00
moooyo
5cc30df4db [AOT] Clean up AOT build issue in Common.UI (#36376)
* init commit

* Use path.combine

* Add useWPF and useWindowsForms back

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
2025-02-25 02:56:04 +08:00
moooyo
f81f65db3d [AOT] clean up AOT issue in Settings.UI (#36559)
* Rename source generation context file

* fix build issue

* fix path bug

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
2025-02-25 02:48:54 +08:00
leileizhang
9f008a65d6 [Build] Revert "[Hosts] Add UITest Cases for Hosts Module (#37600)" to fix CI issue (#37606)
Revert "[Hosts] Add UITest Cases for Hosts Module (#37600)"

This reverts commit c656dcc9c5.
2025-02-24 16:30:33 +00:00
Jerry Xu
c656dcc9c5 [Hosts] Add UITest Cases for Hosts Module (#37600)
* Add UI-Tests for Host Module
2025-02-24 19:32:13 +08:00
Jerry Xu
83cea39b66 Update UI-Test Automation Framework (#37597)
* Improve UITest Automation

* Improve UITest Automation

* Exclude all UI-Test projects instead of just fancyZone UITest

* Exclude all UI-Test projects instead of just fancyZone UITest

* Fix code-style
2025-02-24 18:05:55 +08:00
1286 changed files with 84006 additions and 3126 deletions

View File

@@ -3,13 +3,13 @@
"isRoot": true,
"tools": {
"dotnet-consolidate": {
"version": "2.0.0",
"version": "4.2.0",
"commands": [
"dotnet-consolidate"
]
},
"xamlstyler.console": {
"version": "3.2404.2",
"version": "3.2501.8",
"commands": [
"xstyler"
]

View File

@@ -53,6 +53,7 @@ body:
- Awake
- ColorPicker
- Command not found
- Command Palette
- Crop and Lock
- Environment Variables
- FancyZones

View File

@@ -89,6 +89,7 @@ onefuzzingestionpreparationtool
OTP
Yubi
Yubico
svgl
# KEYS
@@ -232,6 +233,9 @@ SWAPBUTTON
SYSTEMDOCKED
TABLETPC
# Units
nmi
# MATH
artanh

View File

@@ -79,6 +79,7 @@ Gershaft
Giordani
Gokce
gordon
Griese
grzhan
Guo
hanselman
@@ -153,6 +154,7 @@ Santossio
Schoen
Sekan
Seraphima
Shmuelie
skttl
somil
Soref
@@ -184,6 +186,7 @@ zhaopy
zhaoqpcn
Zoltan
Zykova
Sameerjs
# OTHERS
@@ -196,6 +199,7 @@ cortana
dlnilsson
fancymouse
firefox
fudan
gpt
Inkscape
Markdig
@@ -211,6 +215,7 @@ regedit
roslyn
Spotify
Vanara
wangyi
WEX
windowwalker
winui
@@ -218,7 +223,9 @@ winuiex
wix
wordpad
WWL
wyhash
xamlstyler
Xavalon
Xbox
Youdao
zadjii

View File

@@ -96,10 +96,11 @@
^\Qdoc/devdocs/localization.md\E$
^\Qsrc/common/ManagedCommon/ColorFormatHelper.cs\E$
^\Qsrc/common/notifications/BackgroundActivatorDLL/cpp.hint\E$
^\Qsrc/modules/cmdpal/doc/initial-sdk-spec/list-elements-mock-002.pdn\E$
^\Qsrc/modules/colorPicker/ColorPickerUI/Assets/ColorPicker/colorPicker.cur\E$
^\Qsrc/modules/colorPicker/ColorPickerUI/Shaders/GridShader.cso\E$
^\Qsrc/modules/MouseUtils/MouseJumpUI/MainForm.resx\E$
^\Qsrc/modules/MouseUtils/MouseJump.Common/NativeMethods/User32/UI/WindowsAndMessaging/User32.SYSTEM_METRICS_INDEX.cs\E$
^\Qsrc/modules/MouseUtils/MouseJumpUI/MainForm.resx\E$
^\Qsrc/modules/MouseWithoutBorders/App/Form/frmAbout.cs\E$
^\Qsrc/modules/MouseWithoutBorders/App/Form/frmInputCallback.resx\E$
^\Qsrc/modules/MouseWithoutBorders/App/Form/frmLogon.resx\E$

File diff suppressed because it is too large Load Diff

View File

@@ -232,6 +232,15 @@ _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING
# ignore long runs of a single character:
\b([A-Za-z])\g{-1}{3,}\b
# Amazon
\bamazon\.com/[-\w]+/(?:dp/[0-9A-Z]+|)
# imgur
\bimgur\.com/[^.]+
# Process Process (typename varname)
Process Process
# ZoomIt menu items with accelerator keys
E&xit
St&yle
St&yle

View File

@@ -39,6 +39,11 @@ jobs:
echo powerToysInstallerX64Url=$(jq -n "$powerToysSetup" | jq -r '[.[]|select(.name | contains("x64"))][0].browser_download_url') >> $GITHUB_OUTPUT
echo powerToysInstallerArm64Url=$(jq -n "$powerToysSetup" | jq -r '[.[]|select(.name | contains("arm64"))][0].browser_download_url') >> $GITHUB_OUTPUT
- name: Setup .NET 9.0
uses: actions/setup-dotnet@v3
with:
dotnet-version: '9.0.x'
- uses: microsoft/setup-msstore-cli@v1
- name: Fetch Store Credential

6
.gitignore vendored
View File

@@ -224,7 +224,7 @@ ClientBin/
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
@@ -322,7 +322,7 @@ ImageResizer/tools/**
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
@@ -331,7 +331,7 @@ ASALocalRun/
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Temp build files

View File

@@ -0,0 +1,51 @@
{
"Version": "1.0.0",
"UseMinimatch": false,
"SignBatches": [
{
"MatchedPath": [
"*.dll",
"*.exe"
],
"SigningInfo": {
"Operations": [
{
"KeyCode": "CP-230012",
"OperationSetCode": "SigntoolSign",
"Parameters": [
{
"parameterName": "OpusName",
"parameterValue": "Microsoft"
},
{
"parameterName": "OpusInfo",
"parameterValue": "http://www.microsoft.com"
},
{
"parameterName": "FileDigest",
"parameterValue": "/fd \"SHA256\""
},
{
"parameterName": "PageHash",
"parameterValue": "/NPH"
},
{
"parameterName": "TimeStamp",
"parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
}
],
"ToolName": "sign",
"ToolVersion": "1.0"
},
{
"KeyCode": "CP-230012",
"OperationSetCode": "SigntoolVerify",
"Parameters": [],
"ToolName": "sign",
"ToolVersion": "1.0"
}
]
}
}
]
}

View File

@@ -128,6 +128,7 @@
"PowerToys.KeyboardManager.dll",
"KeyboardManagerEditor\\PowerToys.KeyboardManagerEditor.exe",
"KeyboardManagerEngine\\PowerToys.KeyboardManagerEngine.exe",
"PowerToys.KeyboardManagerEditorLibraryWrapper.dll",
"PowerToys.Launcher.dll",
"PowerToys.PowerLauncher.dll",
@@ -216,7 +217,10 @@
"PowerToys.ZoomItSettingsInterop.dll",
"WinUI3Apps\\PowerToys.Settings.dll",
"WinUI3Apps\\PowerToys.Settings.exe"
"WinUI3Apps\\PowerToys.Settings.exe",
"PowerToys.CmdPalModuleInterface.dll",
"*Microsoft.CmdPal.UI_*.msix"
],
"SigningInfo": {
"Operations": [

View File

@@ -0,0 +1,51 @@
{
"Version": "1.0.0",
"UseMinimatch": false,
"SignBatches": [
{
"MatchedPath": [
"Microsoft.CommandPalette.Extensions.dll",
"Microsoft.CommandPalette.Extensions.Toolkit.dll"
],
"SigningInfo": {
"Operations": [
{
"KeyCode": "CP-230012",
"OperationSetCode": "SigntoolSign",
"Parameters": [
{
"parameterName": "OpusName",
"parameterValue": "Microsoft"
},
{
"parameterName": "OpusInfo",
"parameterValue": "http://www.microsoft.com"
},
{
"parameterName": "FileDigest",
"parameterValue": "/fd \"SHA256\""
},
{
"parameterName": "PageHash",
"parameterValue": "/NPH"
},
{
"parameterName": "TimeStamp",
"parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
}
],
"ToolName": "sign",
"ToolVersion": "1.0"
},
{
"KeyCode": "CP-230012",
"OperationSetCode": "SigntoolVerify",
"Parameters": [],
"ToolName": "sign",
"ToolVersion": "1.0"
}
]
}
}
]
}

View File

@@ -20,6 +20,16 @@ parameters:
type: string
default: '0.0.1'
- name: cmdPalVersionNumber
displayName: "Command Palette Version Number"
type: string
default: '0.0.1'
- name: cmdPalSdkVersionNumber
displayName: "Command Palette SDK Version Number"
type: string
default: '0.0.1'
- name: buildConfigurations
displayName: "Build Configurations"
type: object
@@ -78,6 +88,7 @@ extends:
buildPlatforms: ${{ parameters.buildPlatforms }}
buildConfigurations: ${{ parameters.buildConfigurations }}
versionNumber: ${{ parameters.versionNumber }}
cmdPalVersionNumber: ${{ parameters.cmdPalVersionNumber }}
publishArtifacts: false # 1ES PT handles publication for us.
codeSign: true
runTests: false
@@ -95,7 +106,7 @@ extends:
beforeBuildSteps:
# Sets versions for all PowerToy created DLLs
- pwsh: |-
.pipelines/versionSetting.ps1 -versionNumber '${{ parameters.versionNumber }}' -DevEnvironment ''
.pipelines/versionSetting.ps1 -versionNumber '${{ parameters.versionNumber }}' -DevEnvironment '' -cmdPalVersionNumber '${{ parameters.cmdPalVersionNumber }}'
displayName: Prepare versioning
# Prepare the localizations and telemetry config before the release build
@@ -107,6 +118,28 @@ extends:
move /Y "Microsoft.PowerToys.Telemetry.2.0.2\build\include\TelemetryBase.cs" "src\common\Telemetry\TelemetryBase.cs" || exit /b 1
displayName: Emplace telemetry files
- stage: Build_SDK
displayName: Build SDK
dependsOn: []
jobs:
- template: .pipelines/v2/templates/job-build-sdk.yml@self
parameters:
pool:
name: SHINE-INT-L
image: SHINE-VS17-Latest
os: windows
codeSign: true
sdkVersionNumber: ${{ parameters.cmdPalSdkVersionNumber }}
signingIdentity:
serviceName: $(SigningServiceName)
appId: $(SigningAppId)
tenantId: $(SigningTenantId)
akvName: $(SigningAKVName)
authCertName: $(SigningAuthCertName)
signCertName: $(SigningSignCertName)
useManagedIdentity: $(SigningUseManagedIdentity)
clientId: $(SigningOriginalClientId)
- stage: Publish
displayName: Publish
dependsOn: [Build]

View File

@@ -56,6 +56,9 @@ parameters:
- name: versionNumber
type: string
default: '0.0.1'
- name: cmdPalVersionNumber
type: string
default: '0.0.1'
- name: useLatestWinAppSDK
type: boolean
default: false
@@ -96,6 +99,7 @@ jobs:
${{ else }}:
OutputBuildPlatform: ${{ platform }}
variables:
MakeAppxPath: 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x86\MakeAppx.exe'
# Azure DevOps abhors a vacuum
# If these are blank, expansion will fail later on... which will result in direct substitution of the variable *names*
# later on. We'll just... set them to a single space and if we need to, check IsNullOrWhiteSpace.
@@ -145,7 +149,7 @@ jobs:
- template: steps-ensure-dotnet-version.yml
parameters:
sdk: true
version: '6.0'
version: '6.0' # .NET 6.0 is required in CI for ESRP code signing tasks. Please do not remove.
- template: steps-ensure-dotnet-version.yml
parameters:
@@ -242,6 +246,32 @@ jobs:
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
- task: CopyFiles@2
displayName: Stage SDK/build
inputs:
contents: |-
"**/cmdpal/extensionsdk/nuget/Microsoft.CommandPalette.Extensions.SDK.props"
"**/cmdpal/extensionsdk/nuget/Microsoft.CommandPalette.Extensions.SDK.targets"
flattenFolders: True
targetFolder: $(JobOutputDirectory)/sdk/build
- task: CopyFiles@2
displayName: Stage SDK/lib
inputs:
contents: |-
"**/Microsoft.CommandPalette.Extensions.Toolkit/$(BuildPlatform)/release/WinUI3Apps/CmdPal/Microsoft.CommandPalette.Extensions.Toolkit.dll"
"**/Microsoft.CommandPalette.Extensions.Toolkit/$(BuildPlatform)/release/WinUI3Apps/CmdPal/Microsoft.CommandPalette.Extensions.Toolkit.deps.json"
flattenFolders: True
targetFolder: $(JobOutputDirectory)/sdk/lib/net8.0-windows10.0.19041.0
- task: CopyFiles@2
displayName: Stage SDK/winmd
inputs:
contents: |-
"**/Microsoft.CommandPalette.Extensions/$(BuildPlatform)/release/Microsoft.CommandPalette.Extensions/Microsoft.CommandPalette.Extensions.winmd"
flattenFolders: True
targetFolder: $(JobOutputDirectory)/sdk/winmd
- task: VSBuild@1
displayName: Build BugReportTool
inputs:
@@ -309,7 +339,7 @@ jobs:
displayName: HACK Copy core WebView2 ARM64 dll to output directory
condition: eq(variables['BuildPlatform'],'arm64')
inputs:
contents: packages/Microsoft.Web.WebView2.1.0.2739.15/runtimes/win-ARM64/native_uap/Microsoft.Web.WebView2.Core.dll
contents: packages/Microsoft.Web.WebView2.1.0.2903.40/runtimes/win-ARM64/native_uap/Microsoft.Web.WebView2.Core.dll
targetFolder: $(Build.SourcesDirectory)/ARM64/Release/WinUI3Apps/
flattenFolders: True
OverWrite: True
@@ -360,6 +390,33 @@ jobs:
!**\obj\**
- ${{ if eq(parameters.codeSign, true) }}:
- pwsh: |-
$Package = (Get-ChildItem -Recurse -Filter "Microsoft.CmdPal.UI_*.msix" | Select -First 1)
$PackageFilename = $Package.FullName
Write-Host "##vso[task.setvariable variable=CmdPalPackagePath]${PackageFilename}"
displayName: Locate the MSIX
- pwsh: |-
& "$(MakeAppxPath)" unpack /p "$(CmdPalPackagePath)" /d "$(JobOutputDirectory)/CmdPalPackageContents"
displayName: Unpack the MSIX for signing
- template: steps-esrp-signing.yml
parameters:
displayName: Sign CmdPal MSIX content
signingIdentity: ${{ parameters.signingIdentity }}
inputs:
FolderPath: '$(JobOutputDirectory)/CmdPalPackageContents'
signType: batchSigning
batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_cmdpal_msix_content.json'
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
- pwsh: |-
$outDir = New-Item -Type Directory "$(JobOutputDirectory)/_appx" -ErrorAction:Ignore
$PackageFilename = Join-Path $outDir.FullName (Split-Path -Leaf "$(CmdPalPackagePath)")
& "$(MakeAppxPath)" pack /h SHA256 /o /p $PackageFilename /d "$(JobOutputDirectory)/CmdPalPackageContents"
Copy-Item -Force $PackageFilename "$(CmdPalPackagePath)"
displayName: Re-pack the new CmdPal package after signing
- template: steps-esrp-signing.yml
parameters:
displayName: Sign Core PowerToys
@@ -435,7 +492,7 @@ jobs:
$machinePlat = "hash_machine_$(BuildPlatform).txt";
$combinedUserPath = $p + $userPlat;
$combinedMachinePath = $p + $machinePlat;
echo $p
echo $userPlat
@@ -445,7 +502,7 @@ jobs:
echo $machinePlat
echo $machineHash
echo $combinedMachinePath
$userHash | out-file -filepath $combinedUserPath
$machineHash | out-file -filepath $combinedMachinePath
displayName: Calculate file hashes

View File

@@ -0,0 +1,91 @@
parameters:
- name: buildConfigurations
type: object
default:
- Release
- name: codeSign
type: boolean
default: false
- name: pool
type: object
default: []
- name: signingIdentity
type: object
default: {}
- name: sdkVersionNumber
type: string
default: '0.0.1'
jobs:
- job: "BuildSDK"
${{ if ne(length(parameters.pool), 0) }}:
pool: ${{ parameters.pool }}
displayName: Build SDK
timeoutInMinutes: 240
cancelTimeoutInMinutes: 1
templateContext: # Required when this template is hosted in 1ES PT
outputs:
- output: pipelineArtifact
artifactName: SDK
targetPath: $(Build.ArtifactStagingDirectory)
steps:
- checkout: self
clean: true
submodules: true
persistCredentials: True
fetchTags: false
fetchDepth: 1
- pwsh: |-
& "$(build.sourcesdirectory)\src\modules\cmdpal\extensionsdk\nuget\BuildSDKHelper.ps1" -Configuration "Release" -VersionOfSDK ${{ parameters.sdkVersionNumber }} -BuildStep "build" -IsAzurePipelineBuild
displayName: Build SDK
- ${{ if eq(parameters.codeSign, true) }}:
- template: steps-esrp-signing.yml
parameters:
displayName: Sign SDK
signingIdentity: ${{ parameters.signingIdentity }}
inputs:
FolderPath: 'src/modules'
signType: batchSigning
batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_sdk.json'
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
- pwsh: |-
& "$(build.sourcesdirectory)\src\modules\cmdpal\extensionsdk\nuget\BuildSDKHelper.ps1" -Configuration "Release" -VersionOfSDK ${{ parameters.sdkVersionNumber }} -BuildStep "pack" -IsAzurePipelineBuild
displayName: Pack SDK
- task: CopyFiles@2
displayName: Copy Nuget to Artifact Staging
inputs:
sourceFolder: "$(build.sourcesdirectory)/src/modules/cmdpal/extensionsdk/_build"
contents: '*.nupkg'
targetFolder: '$(Build.ArtifactStagingDirectory)'
- ${{ if eq(parameters.codeSign, true) }}:
- template: steps-esrp-signing.yml
parameters:
displayName: Sign NuGet packages
signingIdentity: ${{ parameters.signingIdentity }}
inputs:
FolderPath: $(Build.ArtifactStagingDirectory)
Pattern: '*.nupkg'
UseMinimatch: true
signConfigType: inlineSignParams
inlineOperation: >-
[
{
"KeyCode": "CP-401405",
"OperationCode": "NuGetSign",
"Parameters": {},
"ToolName": "sign",
"ToolVersion": "1.0"
},
{
"KeyCode": "CP-401405",
"OperationCode": "NuGetVerify",
"Parameters": {},
"ToolName": "sign",
"ToolVersion": "1.0"
}
]

View File

@@ -1,30 +0,0 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/microsoft/azure-pipelines-vscode/master/service-schema.json
jobs:
- job: Precheck
pool:
vmImage: windows-2022
steps:
- checkout: none
- pwsh: |-
try {
# Try based on pull request first
$pullRequestNumber = "$(system.pullRequest.pullRequestNumber)";
$gitHubPullRequest = Invoke-RestMethod -Method Get "https://api.github.com/repos/microsoft/PowerToys/pulls/$pullRequestNumber/files"
# If there are no files updated in the commit that are .md, set skipBuild variable
if(([array]($gitHubPullRequest.filename) -notmatch ".md|.txt").Length -eq 0) {
Write-Host '##vso[task.setvariable variable=skipBuild;isOutput=true]Yes'
Write-Host 'Skipping Build'
}
}
catch {
# Fall back to the latest commit otherwise.
$commit = "$(build.sourceVersion)";
$gitHubCommit = Invoke-RestMethod -Method Get "https://api.github.com/repos/microsoft/PowerToys/commits/$commit"
if(([array]($githubCommit.files.filename) -notmatch ".md|.txt").Length -eq 0) {
Write-Host '##vso[task.setvariable variable=skipBuild;isOutput=true]Yes'
Write-Host 'Skipping Build'
}
}
displayName: Verify whether we need to build at all
name: verifyBuildRequest

View File

@@ -61,9 +61,18 @@ jobs:
reg add "HKLM\Software\Policies\Microsoft\Edge\WebView2\ReleaseChannels" /v PowerToys.exe /t REG_SZ /d "3"
displayName: "Enable WebView2 Canary Channel"
- template: steps-download-artifacts-with-azure-cli.yml
parameters:
artifactName: $(TestArtifactsName)
- ${{ if ne(parameters.platform, 'arm64') }}:
- download: current
displayName: Download artifacts
artifact: $(TestArtifactsName)
patterns: |-
**
!**\*.pdb
!**\*.lib
- ${{ else }}:
- template: steps-download-artifacts-with-azure-cli.yml
parameters:
artifactName: $(TestArtifactsName)
- template: steps-ensure-dotnet-version.yml
parameters:
@@ -96,4 +105,4 @@ jobs:
**\UITests-FancyZones.dll
**\UITests-FancyZonesEditor.dll
!**\obj\**
!**\ref\**
!**\ref\**

View File

@@ -36,20 +36,10 @@ parameters:
default: false
stages:
# Allow manual builds to skip pre-check
- ${{ if ne(variables['Build.Reason'], 'Manual') }}:
- stage: Precheck
jobs:
- template: job-ci-precheck.yml
- ${{ each platform in parameters.buildPlatforms }}:
- stage: Build_${{ platform }}
displayName: Build ${{ platform }}
${{ if ne(variables['Build.Reason'], 'Manual') }}:
dependsOn: [Precheck]
condition: and(succeeded(), ne(dependencies.Precheck.outputs['Precheck.verifyBuildRequest.skipBuild'], 'Yes'))
${{ else }}:
dependsOn: []
dependsOn: []
jobs:
- template: job-build-project.yml
parameters:
@@ -72,7 +62,7 @@ stages:
winAppSDKVersionNumber: ${{ parameters.winAppSDKVersionNumber }}
useExperimentalVersion: ${{ parameters.useExperimentalVersion }}
- ${{ if eq(parameters.runTests, true) }}:
- ${{ if and(eq(parameters.runTests, true), not(and(eq(platform, 'arm64'), eq(variables['System.PullRequest.IsFork'], true)))) }}:
- stage: Test_${{ platform }}
displayName: Test ${{ platform }}
dependsOn:

View File

@@ -87,6 +87,30 @@ steps:
dir $(build.sourcesdirectory)\extractedMsi
displayName: "${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Extract and verify MSI"
# Extract CmdPal msix package to check if its content is signed
- pwsh: |-
Write-Host "Extracting CmdPal MSIX package"
# Define the directory to search
$searchDir = "extractedMsi\File"
# Define the regex pattern for MSIX files
$pattern = '^Microsoft.CmdPal.UI.*\.msix$'
# Get all files in the directory and subdirectories
$msixFile = Get-ChildItem -Path $searchDir -Recurse -File | Where-Object {
$_.Name -match $pattern
}
Write-Host "MSIX file found: " $msixFile
$destinationDir = "$(build.sourcesdirectory)\extractedMsi\File\extractedCmdPalMsix"
Expand-Archive -Path $msixFile -DestinationPath $destinationDir
Get-ChildItem -Path $destinationDir -Recurse -File
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Extract CmdPal MSIX package
# Check if deps.json files don't reference different dll versions.
- pwsh: |-
& '.pipelines/verifyDepsJsonLibraryVersions.ps1' -targetDir '$(build.sourcesdirectory)\extractedMsi\File'

View File

@@ -15,9 +15,14 @@ Param(
$referencedFileVersionsPerDll = @{}
$totalFailures = 0
Get-ChildItem $targetDir -Recurse -Filter *.deps.json -Exclude UITests-FancyZones*,MouseJump.Common.UnitTests*,*.FuzzTests* | ForEach-Object {
# Temporarily exclude FancyZones UI tests because of Appium.WebDriver dependencies
Get-ChildItem $targetDir -Recurse -Filter *.deps.json -Exclude *UITest*,MouseJump.Common.UnitTests*,*.FuzzTests* | ForEach-Object {
# Temporarily exclude All UI-Test, Fuzzer-Test projects because of Appium.WebDriver dependencies
$depsJsonFullFileName = $_.FullName
if ($depsJsonFullFileName -like "*CmdPal*") {
return
}
$depsJsonFileName = $_.Name
$depsJson = Get-Content $depsJsonFullFileName | ConvertFrom-Json

View File

@@ -22,7 +22,11 @@ $versionExceptions = @(
"TraceReloggerLib.dll",
"Microsoft.WindowsAppRuntime.Release.Net.dll",
"Microsoft.Windows.Widgets.Projection.dll",
"WinRT.Host.Shim.dll") -join '|';
"WinRT.Host.Shim.dll",
"WyHash.dll",
"Microsoft.Recognizers.Text.DataTypes.TimexExpression.dll",
"ObjectModelCsProjection.dll",
"RendererCsProjection.dll") -join '|';
$nullVersionExceptions = @(
"codicon.ttf",
"e_sqlite3.dll",
@@ -43,12 +47,14 @@ $nullVersionExceptions = @(
"PushNotificationsLongRunningTask.ProxyStub.dll",
"WindowsAppSdk.AppxDeploymentExtensions.Desktop.dll",
"System.Diagnostics.EventLog.Messages.dll",
"Microsoft.Windows.Widgets.dll") -join '|';
"Microsoft.Windows.Widgets.dll",
"AdaptiveCards.ObjectModel.WinUI3.dll",
"AdaptiveCards.Rendering.WinUI3.dll") -join '|';
$totalFailure = 0;
Write-Host $DirPath;
if (-not (Test-Path $DirPath)) {
if (-not (Test-Path $DirPath)) {
Write-Error "Folder does not exist!"
}
@@ -70,7 +76,7 @@ $items | ForEach-Object {
Write-Host "Version set to 1.0.0.0: " + $_.FullName
$totalFailure++;
}
elseif ($_.VersionInfo.FileVersion -eq $null -and $_.Name -notmatch $nullVersionExceptions) {
elseif ($_.VersionInfo.FileVersion -eq $null -and $_.Name -notmatch $nullVersionExceptions) {
# These items are exceptions that actually a version not set.
Write-Host "Version not set: " + $_.FullName
$totalFailure++;

View File

@@ -5,7 +5,10 @@ Param(
[Parameter(Mandatory=$True,Position=2)]
[AllowEmptyString()]
[string]$DevEnvironment = "Local"
[string]$DevEnvironment = "Local",
[Parameter(Mandatory=$True,Position=3)]
[string]$cmdPalVersionNumber = "0.0.1"
)
Write-Host $PSScriptRoot
@@ -38,9 +41,20 @@ $verPropReadFileLocation = $verPropWriteFileLocation;
$verProps.Project.PropertyGroup.Version = $versionNumber;
$verProps.Project.PropertyGroup.DevEnvironment = $DevEnvironment;
Write-Host "xml" $verProps.Project.PropertyGroup.Version
Write-Host "xml" $verProps.Project.PropertyGroup.Version
$verProps.Save($verPropWriteFileLocation);
#### The same thing as above, but for the CmdPal version
$verPropWriteFileLocation = $PSScriptRoot + '/../src/CmdPalVersion.props';
$verPropReadFileLocation = $verPropWriteFileLocation;
[XML]$verProps = Get-Content $verPropReadFileLocation
$verProps.Project.PropertyGroup.CmdPalVersion = $cmdPalVersionNumber;
$verProps.Project.PropertyGroup.DevEnvironment = $DevEnvironment;
Write-Host "xml" $verProps.Project.PropertyGroup.Version
$verProps.Save($verPropWriteFileLocation);
#######
# Set PowerRenameContextMenu package version in AppManifest.xml
$powerRenameContextMenuAppManifestWriteFileLocation = $PSScriptRoot + '/../src/modules/powerrename/PowerRenameContextMenu/AppxManifest.xml';
$powerRenameContextMenuAppManifestReadFileLocation = $powerRenameContextMenuAppManifestWriteFileLocation;
@@ -76,3 +90,12 @@ $newPlusContextMenuAppManifestReadFileLocation = $newPlusContextMenuAppManifestW
$newPlusContextMenuAppManifest.Package.Identity.Version = $versionNumber + '.0'
Write-Host "NewPlusContextMenu version" $newPlusContextMenuAppManifest.Package.Identity.Version
$newPlusContextMenuAppManifest.Save($newPlusContextMenuAppManifestWriteFileLocation);
# Set package version in Package.appxmanifest
$cmdPalAppManifestWriteFileLocation = $PSScriptRoot + '/../src/modules/cmdpal/Microsoft.CmdPal.UI/Package.appxmanifest';
$cmdPalAppManifestReadFileLocation = $cmdPalAppManifestWriteFileLocation;
[XML]$cmdPalAppManifest = Get-Content $cmdPalAppManifestReadFileLocation
$cmdPalAppManifest.Package.Identity.Version = $cmdPalVersionNumber + '.0'
Write-Host "CmdPal Package version: " $cmdPalAppManifest.Package.Identity.Version
$cmdPalAppManifest.Save($cmdPalAppManifestWriteFileLocation);

View File

@@ -1,12 +1,13 @@
{
"version": "1.0",
"components": [
"components": [
"Microsoft.VisualStudio.Component.CoreEditor",
"Microsoft.VisualStudio.Workload.CoreEditor",
"Microsoft.VisualStudio.Workload.NativeDesktop",
"Microsoft.VisualStudio.Workload.ManagedDesktop",
"Microsoft.VisualStudio.Workload.Universal",
"Microsoft.VisualStudio.Component.Windows10SDK.19041",
"Microsoft.VisualStudio.Component.Windows10SDK.20348",
"Microsoft.VisualStudio.Component.Windows10SDK.22621",
"Microsoft.VisualStudio.ComponentGroup.UWP.VC",
"Microsoft.VisualStudio.Component.UWP.VC.ARM64",
@@ -18,4 +19,4 @@
"Microsoft.VisualStudio.Component.VC.ATL.Spectre",
"Microsoft.VisualStudio.ComponentGroup.WindowsAppSDK.Cs"
]
}
}

View File

@@ -3,17 +3,21 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="AdaptiveCards.ObjectModel.WinUI3" Version="2.0.0-beta" />
<PackageVersion Include="AdaptiveCards.Rendering.WinUI3" Version="2.1.0-beta" />
<PackageVersion Include="AdaptiveCards.Templating" Version="2.0.2" />
<PackageVersion Include="Appium.WebDriver" Version="4.4.5" />
<PackageVersion Include="Azure.AI.OpenAI" Version="1.0.0-beta.17" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageVersion Include="CommunityToolkit.WinUI.Animations" Version="8.0.240109" />
<PackageVersion Include="CommunityToolkit.WinUI.Collections" Version="8.0.240109" />
<PackageVersion Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.0.240109" />
<PackageVersion Include="CommunityToolkit.WinUI.Controls.SettingsControls" Version="8.0.240109" />
<PackageVersion Include="CommunityToolkit.WinUI.Controls.Segmented" Version="8.0.240109" />
<PackageVersion Include="CommunityToolkit.WinUI.Controls.Sizers" Version="8.0.240109" />
<PackageVersion Include="CommunityToolkit.WinUI.Converters" Version="8.0.240109" />
<PackageVersion Include="CommunityToolkit.WinUI.Extensions" Version="8.0.240109" />
<PackageVersion Include="CommunityToolkit.Common" Version="8.4.0" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageVersion Include="CommunityToolkit.WinUI.Animations" Version="8.2.250129-preview2" />
<PackageVersion Include="CommunityToolkit.WinUI.Collections" Version="8.2.250129-preview2" />
<PackageVersion Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.2.250129-preview2" />
<PackageVersion Include="CommunityToolkit.WinUI.Controls.SettingsControls" Version="8.2.250129-preview2" />
<PackageVersion Include="CommunityToolkit.WinUI.Controls.Segmented" Version="8.2.250129-preview2" />
<PackageVersion Include="CommunityToolkit.WinUI.Controls.Sizers" Version="8.2.250129-preview2" />
<PackageVersion Include="CommunityToolkit.WinUI.Converters" Version="8.2.250129-preview2" />
<PackageVersion Include="CommunityToolkit.WinUI.Extensions" Version="8.2.250129-preview2" />
<PackageVersion Include="CommunityToolkit.WinUI.UI.Controls.DataGrid" Version="7.1.2" />
<PackageVersion Include="CommunityToolkit.WinUI.UI.Controls.Markdown" Version="7.1.2" />
<PackageVersion Include="ControlzEx" Version="6.0.0" />
@@ -27,30 +31,31 @@
<!-- Including MessagePack to force version, since it's used by StreamJsonRpc but contains vulnerabilities. After StreamJsonRpc updates the version of MessagePack, we can upgrade StreamJsonRpc instead. -->
<PackageVersion Include="MessagePack" Version="2.5.187" />
<PackageVersion Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="9.0.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.2" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.3" />
<!-- Including Microsoft.Bcl.AsyncInterfaces to force version, since it's used by Microsoft.SemanticKernel. -->
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.2" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.3" />
<PackageVersion Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="3.1.16" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.2" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.2" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.2" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.2" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.3" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.3" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.3" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.3" />
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.3" />
<PackageVersion Include="Microsoft.SemanticKernel" Version="1.15.0" />
<PackageVersion Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.2739.15" />
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.2903.40" />
<!-- Package Microsoft.Win32.SystemEvents added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Drawing.Common but the 8.0.1 version wasn't published to nuget. -->
<PackageVersion Include="Microsoft.Win32.SystemEvents" Version="9.0.2" />
<PackageVersion Include="Microsoft.Windows.Compatibility" Version="9.0.2" />
<PackageVersion Include="Microsoft.Win32.SystemEvents" Version="9.0.3" />
<PackageVersion Include="Microsoft.WindowsPackageManager.ComInterop" Version="1.10.120-preview" />
<PackageVersion Include="Microsoft.Windows.Compatibility" Version="9.0.3" />
<PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.2.46-beta" />
<!-- CsWinRT version needs to be set to have a WinRT.Runtime.dll at the same version contained inside the NET SDK we're currently building on CI. -->
<!--
TODO: in Common.Dotnet.CsWinRT.props, on upgrade, verify RemoveCsWinRTPackageAnalyzer is no longer needed.
This is present due to a bug in CsWinRT where WPF projects cause the analyzer to fail.
-->
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.1.5" />
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.6.241114003" />
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.6.250205002" />
<PackageVersion Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
<PackageVersion Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
<PackageVersion Include="ModernWpfUI" Version="0.9.4" />
@@ -67,35 +72,36 @@
<PackageVersion Include="StreamJsonRpc" Version="2.19.27" />
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
<!-- Package System.CodeDom added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Management but the 8.0.1 version wasn't published to nuget. -->
<PackageVersion Include="System.CodeDom" Version="9.0.2" />
<PackageVersion Include="System.CodeDom" Version="9.0.3" />
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<PackageVersion Include="System.ComponentModel.Composition" Version="9.0.2" />
<PackageVersion Include="System.Configuration.ConfigurationManager" Version="9.0.2" />
<PackageVersion Include="System.Data.OleDb" Version="9.0.2" />
<PackageVersion Include="System.ComponentModel.Composition" Version="9.0.3" />
<PackageVersion Include="System.Configuration.ConfigurationManager" Version="9.0.3" />
<PackageVersion Include="System.Data.OleDb" Version="9.0.3" />
<!-- Package System.Data.SqlClient added to force it as a dependency of Microsoft.Windows.Compatibility to the latest version available at this time. -->
<PackageVersion Include="System.Data.SqlClient" Version="4.8.6" />
<!-- Package System.Diagnostics.EventLog added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Data.OleDb but the 8.0.1 version wasn't published to nuget. -->
<PackageVersion Include="System.Diagnostics.EventLog" Version="9.0.2" />
<PackageVersion Include="System.Diagnostics.EventLog" Version="9.0.3" />
<!-- Package System.Diagnostics.PerformanceCounter added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.11. -->
<PackageVersion Include="System.Diagnostics.PerformanceCounter" Version="9.0.2" />
<PackageVersion Include="System.Drawing.Common" Version="9.0.2" />
<PackageVersion Include="System.Diagnostics.PerformanceCounter" Version="9.0.3" />
<PackageVersion Include="System.Drawing.Common" Version="9.0.3" />
<PackageVersion Include="System.IO.Abstractions" Version="21.0.29" />
<PackageVersion Include="System.IO.Abstractions.TestingHelpers" Version="21.0.29" />
<PackageVersion Include="System.Management" Version="9.0.2" />
<PackageVersion Include="System.Management" Version="9.0.3" />
<PackageVersion Include="System.Reactive" Version="6.0.1" />
<PackageVersion Include="System.Runtime.Caching" Version="9.0.2" />
<PackageVersion Include="System.ServiceProcess.ServiceController" Version="9.0.2" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.2" />
<PackageVersion Include="System.Text.Json" Version="9.0.2" />
<PackageVersion Include="System.Runtime.Caching" Version="9.0.3" />
<PackageVersion Include="System.ServiceProcess.ServiceController" Version="9.0.3" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.3" />
<PackageVersion Include="System.Text.Json" Version="9.0.3" />
<PackageVersion Include="UnicodeInformation" Version="2.6.0" />
<PackageVersion Include="UnitsNet" Version="5.56.0" />
<PackageVersion Include="UTF.Unknown" Version="2.5.1" />
<PackageVersion Include="WinUIEx" Version="2.2.0" />
<PackageVersion Include="WPF-UI" Version="3.0.5" />
<PackageVersion Include="WyHash" Version="1.0.5" />
</ItemGroup>
<ItemGroup Condition="'$(IsExperimentationLive)'!=''">
<!-- Additional dependencies used by experimentation -->
<PackageVersion Include="Microsoft.VariantAssignment.Client" Version="2.4.17140001" />
<PackageVersion Include="Microsoft.VariantAssignment.Contract" Version="3.0.16990001" />
</ItemGroup>
</Project>
</Project>

170
NOTICE.md
View File

@@ -3,12 +3,14 @@
This software incorporates material from third parties.
- Color Picker
- Command Palette
- File Explorer Add-ins
- ImageResizer
- PowerToys Run
- Installer/Runner
- Measure tool
- Peek
- Registry Preview
## Utility: Color Picker
@@ -38,6 +40,41 @@ 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.
## Utility: Command Palette
### wyhash
We use the WyHash NuGet package for calculating stable hashes for strings.
**Source**: [https://github.com/wangyi-fudan/wyhash](https://github.com/wangyi-fudan/wyhash)
```
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
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 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.
For more information, please refer to <http://unlicense.org/>
```
## Utility: File Explorer Add-ins
### Monaco Editor
@@ -788,6 +825,34 @@ SOFTWARE.
## Utility: Peek
### Monaco Editor
**Source**: https://github.com/Microsoft/monaco-editor
**Additional third party notifications:** https://github.com/microsoft/monaco-editor/blob/main/ThirdPartyNotices.txt
The MIT License (MIT)
Copyright (c) 2016 - present Microsoft Corporation
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.
### The Quite OK Image Format reference decoder
**Source**: https://github.com/phoboslab/qoi
@@ -1294,19 +1359,56 @@ EXHIBIT A -Mozilla Public License.
Original Code Source Code for Your Modifications.]
```
## Utility: Registry Preview
### Monaco Editor
**Source**: https://github.com/Microsoft/monaco-editor
**Additional third party notifications:** https://github.com/microsoft/monaco-editor/blob/main/ThirdPartyNotices.txt
```
The MIT License (MIT)
Copyright (c) 2016 - present Microsoft Corporation
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 2.0.0-beta
- AdaptiveCards.Rendering.WinUI3 2.1.0-beta
- AdaptiveCards.Templating 2.0.2
- Appium.WebDriver 4.4.5
- Azure.AI.OpenAI 1.0.0-beta.17
- CommunityToolkit.Mvvm 8.2.2
- CommunityToolkit.WinUI.Animations 8.0.240109
- CommunityToolkit.WinUI.Collections 8.0.240109
- CommunityToolkit.WinUI.Controls.Primitives 8.0.240109
- CommunityToolkit.WinUI.Controls.Segmented 8.0.240109
- CommunityToolkit.WinUI.Controls.SettingsControls 8.0.240109
- CommunityToolkit.WinUI.Controls.Sizers 8.0.240109
- CommunityToolkit.WinUI.Converters 8.0.240109
- CommunityToolkit.WinUI.Extensions 8.0.240109
- CommunityToolkit.Common 8.4.0
- CommunityToolkit.Mvvm 8.4.0
- CommunityToolkit.WinUI.Animations 8.2.250129-preview2
- CommunityToolkit.WinUI.Collections 8.2.250129-preview2
- CommunityToolkit.WinUI.Controls.Primitives 8.2.250129-preview2
- CommunityToolkit.WinUI.Controls.Segmented 8.2.250129-preview2
- CommunityToolkit.WinUI.Controls.SettingsControls 8.2.250129-preview2
- CommunityToolkit.WinUI.Controls.Sizers 8.2.250129-preview2
- CommunityToolkit.WinUI.Converters 8.2.250129-preview2
- CommunityToolkit.WinUI.Extensions 8.2.250129-preview2
- CommunityToolkit.WinUI.UI.Controls.DataGrid 7.1.2
- CommunityToolkit.WinUI.UI.Controls.Markdown 7.1.2
- ControlzEx 6.0.0
@@ -1318,26 +1420,27 @@ EXHIBIT A -Mozilla Public License.
- Mages 3.0.0
- Markdig.Signed 0.34.0
- MessagePack 2.5.187
- Microsoft.Bcl.AsyncInterfaces 9.0.2
- Microsoft.Bcl.AsyncInterfaces 9.0.3
- Microsoft.CodeAnalysis.NetAnalyzers 9.0.0
- Microsoft.Data.Sqlite 9.0.2
- Microsoft.Data.Sqlite 9.0.3
- Microsoft.Diagnostics.Tracing.TraceEvent 3.1.16
- Microsoft.DotNet.ILCompiler (A)
- Microsoft.Extensions.DependencyInjection 9.0.2
- Microsoft.Extensions.Hosting 9.0.2
- Microsoft.Extensions.Hosting.WindowsServices 9.0.2
- Microsoft.Extensions.Logging 9.0.2
- Microsoft.Extensions.Logging.Abstractions 9.0.2
- Microsoft.Extensions.DependencyInjection 9.0.3
- Microsoft.Extensions.Hosting 9.0.3
- Microsoft.Extensions.Hosting.WindowsServices 9.0.3
- Microsoft.Extensions.Logging 9.0.3
- Microsoft.Extensions.Logging.Abstractions 9.0.3
- Microsoft.NET.ILLink.Tasks (A)
- Microsoft.SemanticKernel 1.15.0
- Microsoft.Toolkit.Uwp.Notifications 7.1.2
- Microsoft.Web.WebView2 1.0.2739.15
- Microsoft.Win32.SystemEvents 9.0.2
- Microsoft.Windows.Compatibility 9.0.2
- Microsoft.Web.WebView2 1.0.2903.40
- Microsoft.Win32.SystemEvents 9.0.3
- Microsoft.Windows.Compatibility 9.0.3
- Microsoft.Windows.CsWin32 0.2.46-beta
- Microsoft.Windows.CsWinRT 2.1.5
- Microsoft.Windows.CsWinRT 2.2.0
- Microsoft.Windows.SDK.BuildTools 10.0.22621.2428
- Microsoft.WindowsAppSDK 1.6.241114003
- Microsoft.WindowsAppSDK 1.6.250205002
- Microsoft.WindowsPackageManager.ComInterop 1.10.120-preview
- Microsoft.Xaml.Behaviors.WinUI.Managed 2.0.9
- Microsoft.Xaml.Behaviors.Wpf 1.1.39
- ModernWpfUI 0.9.4
@@ -1351,25 +1454,26 @@ EXHIBIT A -Mozilla Public License.
- SharpCompress 0.37.2
- StreamJsonRpc 2.19.27
- StyleCop.Analyzers 1.2.0-beta.556
- System.CodeDom 9.0.2
- System.CodeDom 9.0.3
- System.CommandLine 2.0.0-beta4.22272.1
- System.ComponentModel.Composition 9.0.2
- System.Configuration.ConfigurationManager 9.0.2
- System.Data.OleDb 9.0.2
- System.ComponentModel.Composition 9.0.3
- System.Configuration.ConfigurationManager 9.0.3
- System.Data.OleDb 9.0.3
- System.Data.SqlClient 4.8.6
- System.Diagnostics.EventLog 9.0.2
- System.Diagnostics.PerformanceCounter 9.0.2
- System.Drawing.Common 9.0.2
- System.Diagnostics.EventLog 9.0.3
- System.Diagnostics.PerformanceCounter 9.0.3
- System.Drawing.Common 9.0.3
- System.IO.Abstractions 21.0.29
- System.IO.Abstractions.TestingHelpers 21.0.29
- System.Management 9.0.2
- System.Management 9.0.3
- System.Reactive 6.0.1
- System.Runtime.Caching 9.0.2
- System.ServiceProcess.ServiceController 9.0.2
- System.Text.Encoding.CodePages 9.0.2
- System.Text.Json 9.0.2
- System.Runtime.Caching 9.0.3
- System.ServiceProcess.ServiceController 9.0.3
- System.Text.Encoding.CodePages 9.0.3
- System.Text.Json 9.0.3
- UnicodeInformation 2.6.0
- UnitsNet 5.56.0
- UTF.Unknown 2.5.1
- WinUIEx 2.2.0
- WPF-UI 3.0.5
- WyHash 1.0.5

View File

@@ -620,10 +620,64 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EtwTrace", "src\common\Tele
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MouseWithoutBorders.UnitTests", "src\modules\MouseWithoutBorders\MouseWithoutBorders.UnitTests\MouseWithoutBorders.UnitTests.csproj", "{66614C26-314C-4B91-9071-76133422CFEF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CommandPalette", "CommandPalette", "{3846508C-77EB-4034-A702-F8BB263C4F79}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Built-in Extensions", "Built-in Extensions", "{ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Apps", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.Apps\Microsoft.CmdPal.Ext.Apps.csproj", "{6CE438DF-C245-4997-A360-0A0939E4BA34}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Bookmarks", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.Bookmark\Microsoft.CmdPal.Ext.Bookmarks.csproj", "{E09AA983-C755-474F-83D6-A5CDF528C070}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Calc", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.Calc\Microsoft.CmdPal.Ext.Calc.csproj", "{6D56B64D-FF1F-488F-AFED-9B9854A5D399}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Registry", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.Registry\Microsoft.CmdPal.Ext.Registry.csproj", "{92EC89E4-9972-453A-8A1A-3A9E230C146A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.WindowsServices", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.WindowsServices\Microsoft.CmdPal.Ext.WindowsServices.csproj", "{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.WindowsSettings", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.WindowsSettings\Microsoft.CmdPal.Ext.WindowsSettings.csproj", "{D1160404-D3D1-497A-883A-4059C07C2273}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.WindowsTerminal", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.WindowsTerminal\Microsoft.CmdPal.Ext.WindowsTerminal.csproj", "{40F6D69D-E321-400F-A767-5628C7AE453D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extension SDK", "Extension SDK", "{F3D09629-59A2-4924-A4B9-D6BFAA2C1B49}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.CommandPalette.Extensions", "src\modules\cmdpal\extensionsdk\Microsoft.CommandPalette.Extensions\Microsoft.CommandPalette.Extensions.vcxproj", "{305DD37E-C85D-4B08-AAFE-7381FA890463}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CommandPalette.Extensions.Toolkit", "src\modules\cmdpal\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj", "{CA4D810F-C8F4-4B61-9DA9-71807E0B9F24}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Common", "src\modules\cmdpal\Microsoft.CmdPal.Common\Microsoft.CmdPal.Common.csproj", "{14E62033-58D0-4A7D-8990-52F50A08BBBD}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.UI", "src\modules\cmdpal\Microsoft.Terminal.UI\Microsoft.Terminal.UI.vcxproj", "{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sample Extensions", "Sample Extensions", "{071E18A4-A530-46B8-AB7D-B862EE55E24E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProcessMonitorExtension", "src\modules\cmdpal\Exts\ProcessMonitorExtension\ProcessMonitorExtension.csproj", "{C846F7A7-792A-47D9-B0CB-417C900EE03D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SamplePagesExtension", "src\modules\cmdpal\Exts\SamplePagesExtension\SamplePagesExtension.csproj", "{C831231F-891C-4572-9694-45062534B42A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UI", "UI", "{7520A2FE-00A2-49B8-83ED-DB216E874C04}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.UI", "src\modules\cmdpal\Microsoft.CmdPal.UI\Microsoft.CmdPal.UI.csproj", "{8FBDABA4-40EE-4C0E-9BC8-2F6444A6EF90}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.UI.ViewModels", "src\modules\cmdpal\Microsoft.CmdPal.UI.ViewModels\Microsoft.CmdPal.UI.ViewModels.csproj", "{C66020D1-CB10-4CF7-8715-84C97FD5E5E2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.ClipboardHistory", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.ClipboardHistory\Microsoft.CmdPal.Ext.ClipboardHistory.csproj", "{79775343-7A3D-445D-9104-3DD5B2893DF9}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdPalModuleInterface", "src\modules\cmdpal\CmdPalModuleInterface\CmdPalModuleInterface.vcxproj", "{0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkspacesCsharpLibrary", "src\modules\Workspaces\WorkspacesCsharpLibrary\WorkspacesCsharpLibrary.csproj", "{89D0E199-B17A-418C-B2F8-7375B6708357}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NewPlus.ShellExtension.win10", "src\modules\NewPlus\NewShellExtensionContextMenu.win10\NewPlus.ShellExtension.win10.vcxproj", "{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Indexer", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.Indexer\Microsoft.CmdPal.Ext.Indexer.csproj", "{453CBB73-A3CB-4D0B-8D24-6940B86FE21D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Shell", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.Shell\Microsoft.CmdPal.Ext.Shell.csproj", "{C0CE3B5E-16D3-495D-B335-CA791B660162}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.WindowWalker", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.WindowWalker\Microsoft.CmdPal.Ext.WindowWalker.csproj", "{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.WebSearch", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.WebSearch\Microsoft.CmdPal.Ext.WebSearch.csproj", "{605E914B-7232-4789-AF46-BF5D3DDFC14E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.WinGet", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.WinGet\Microsoft.CmdPal.Ext.WinGet.csproj", "{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvancedPaste.UnitTests", "src\modules\AdvancedPaste\AdvancedPaste.UnitTests\AdvancedPaste.UnitTests.csproj", "{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvancedPaste.FuzzTests", "src\modules\AdvancedPaste\AdvancedPaste.FuzzTests\AdvancedPaste.FuzzTests.csproj", "{7F5B9557-5878-4438-A721-3E28296BA193}"
@@ -636,6 +690,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZoomItModuleInterface", "sr
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZoomItSettingsInterop", "src\modules\ZoomIt\ZoomItSettingsInterop\ZoomItSettingsInterop.vcxproj", "{CA7D8106-30B9-4AEC-9D05-B69B31B8C461}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.TimeDate", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.TimeDate\Microsoft.CmdPal.Ext.TimeDate.csproj", "{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UITestAutomation", "src\common\UITestAutomation\UITestAutomation.csproj", "{A558C25D-2007-498E-8B6F-43405AFAE9E2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeyboardManagerEditorUI", "src\modules\keyboardmanager\KeyboardManagerEditorUI\KeyboardManagerEditorUI.csproj", "{08F9155D-B6DC-46E5-9C83-AF60B655898B}"
@@ -644,6 +700,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEditorLibrar
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hosts.FuzzTests", "src\modules\Hosts\Hosts.FuzzTests\Hosts.FuzzTests.csproj", "{EBED240C-8702-452D-B764-6DB9DA9179AF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hosts.UITests", "src\modules\Hosts\Hosts.UITests\Hosts.UITests.csproj", "{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RegistryPreview.FuzzTests", "src\modules\registrypreview\RegistryPreview.FuzzTests\RegistryPreview.FuzzTests.csproj", "{5702B3CC-8575-48D5-83D8-15BB42269CD3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.System", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.System\Microsoft.CmdPal.Ext.System.csproj", "{64B88F02-CD88-4ED8-9624-989A800230F9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
@@ -2196,6 +2258,154 @@ Global
{66614C26-314C-4B91-9071-76133422CFEF}.Release|ARM64.Build.0 = Release|ARM64
{66614C26-314C-4B91-9071-76133422CFEF}.Release|x64.ActiveCfg = Release|x64
{66614C26-314C-4B91-9071-76133422CFEF}.Release|x64.Build.0 = Release|x64
{6CE438DF-C245-4997-A360-0A0939E4BA34}.Debug|ARM64.ActiveCfg = Debug|ARM64
{6CE438DF-C245-4997-A360-0A0939E4BA34}.Debug|ARM64.Build.0 = Debug|ARM64
{6CE438DF-C245-4997-A360-0A0939E4BA34}.Debug|x64.ActiveCfg = Debug|x64
{6CE438DF-C245-4997-A360-0A0939E4BA34}.Debug|x64.Build.0 = Debug|x64
{6CE438DF-C245-4997-A360-0A0939E4BA34}.Release|ARM64.ActiveCfg = Release|ARM64
{6CE438DF-C245-4997-A360-0A0939E4BA34}.Release|ARM64.Build.0 = Release|ARM64
{6CE438DF-C245-4997-A360-0A0939E4BA34}.Release|x64.ActiveCfg = Release|x64
{6CE438DF-C245-4997-A360-0A0939E4BA34}.Release|x64.Build.0 = Release|x64
{E09AA983-C755-474F-83D6-A5CDF528C070}.Debug|ARM64.ActiveCfg = Debug|ARM64
{E09AA983-C755-474F-83D6-A5CDF528C070}.Debug|ARM64.Build.0 = Debug|ARM64
{E09AA983-C755-474F-83D6-A5CDF528C070}.Debug|x64.ActiveCfg = Debug|x64
{E09AA983-C755-474F-83D6-A5CDF528C070}.Debug|x64.Build.0 = Debug|x64
{E09AA983-C755-474F-83D6-A5CDF528C070}.Release|ARM64.ActiveCfg = Release|ARM64
{E09AA983-C755-474F-83D6-A5CDF528C070}.Release|ARM64.Build.0 = Release|ARM64
{E09AA983-C755-474F-83D6-A5CDF528C070}.Release|x64.ActiveCfg = Release|x64
{E09AA983-C755-474F-83D6-A5CDF528C070}.Release|x64.Build.0 = Release|x64
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Debug|ARM64.ActiveCfg = Debug|ARM64
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Debug|ARM64.Build.0 = Debug|ARM64
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Debug|x64.ActiveCfg = Debug|x64
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Debug|x64.Build.0 = Debug|x64
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Release|ARM64.ActiveCfg = Release|ARM64
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Release|ARM64.Build.0 = Release|ARM64
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Release|x64.ActiveCfg = Release|x64
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Release|x64.Build.0 = Release|x64
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Debug|ARM64.ActiveCfg = Debug|ARM64
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Debug|ARM64.Build.0 = Debug|ARM64
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Debug|x64.ActiveCfg = Debug|x64
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Debug|x64.Build.0 = Debug|x64
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Release|ARM64.ActiveCfg = Release|ARM64
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Release|ARM64.Build.0 = Release|ARM64
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Release|x64.ActiveCfg = Release|x64
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Release|x64.Build.0 = Release|x64
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}.Debug|ARM64.ActiveCfg = Debug|ARM64
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}.Debug|ARM64.Build.0 = Debug|ARM64
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}.Debug|x64.ActiveCfg = Debug|x64
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}.Debug|x64.Build.0 = Debug|x64
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}.Release|ARM64.ActiveCfg = Release|ARM64
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}.Release|ARM64.Build.0 = Release|ARM64
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}.Release|x64.ActiveCfg = Release|x64
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}.Release|x64.Build.0 = Release|x64
{D1160404-D3D1-497A-883A-4059C07C2273}.Debug|ARM64.ActiveCfg = Debug|ARM64
{D1160404-D3D1-497A-883A-4059C07C2273}.Debug|ARM64.Build.0 = Debug|ARM64
{D1160404-D3D1-497A-883A-4059C07C2273}.Debug|x64.ActiveCfg = Debug|x64
{D1160404-D3D1-497A-883A-4059C07C2273}.Debug|x64.Build.0 = Debug|x64
{D1160404-D3D1-497A-883A-4059C07C2273}.Release|ARM64.ActiveCfg = Release|ARM64
{D1160404-D3D1-497A-883A-4059C07C2273}.Release|ARM64.Build.0 = Release|ARM64
{D1160404-D3D1-497A-883A-4059C07C2273}.Release|x64.ActiveCfg = Release|x64
{D1160404-D3D1-497A-883A-4059C07C2273}.Release|x64.Build.0 = Release|x64
{40F6D69D-E321-400F-A767-5628C7AE453D}.Debug|ARM64.ActiveCfg = Debug|ARM64
{40F6D69D-E321-400F-A767-5628C7AE453D}.Debug|ARM64.Build.0 = Debug|ARM64
{40F6D69D-E321-400F-A767-5628C7AE453D}.Debug|x64.ActiveCfg = Debug|x64
{40F6D69D-E321-400F-A767-5628C7AE453D}.Debug|x64.Build.0 = Debug|x64
{40F6D69D-E321-400F-A767-5628C7AE453D}.Release|ARM64.ActiveCfg = Release|ARM64
{40F6D69D-E321-400F-A767-5628C7AE453D}.Release|ARM64.Build.0 = Release|ARM64
{40F6D69D-E321-400F-A767-5628C7AE453D}.Release|x64.ActiveCfg = Release|x64
{40F6D69D-E321-400F-A767-5628C7AE453D}.Release|x64.Build.0 = Release|x64
{305DD37E-C85D-4B08-AAFE-7381FA890463}.Debug|ARM64.ActiveCfg = Debug|ARM64
{305DD37E-C85D-4B08-AAFE-7381FA890463}.Debug|ARM64.Build.0 = Debug|ARM64
{305DD37E-C85D-4B08-AAFE-7381FA890463}.Debug|x64.ActiveCfg = Debug|x64
{305DD37E-C85D-4B08-AAFE-7381FA890463}.Debug|x64.Build.0 = Debug|x64
{305DD37E-C85D-4B08-AAFE-7381FA890463}.Release|ARM64.ActiveCfg = Release|ARM64
{305DD37E-C85D-4B08-AAFE-7381FA890463}.Release|ARM64.Build.0 = Release|ARM64
{305DD37E-C85D-4B08-AAFE-7381FA890463}.Release|x64.ActiveCfg = Release|x64
{305DD37E-C85D-4B08-AAFE-7381FA890463}.Release|x64.Build.0 = Release|x64
{CA4D810F-C8F4-4B61-9DA9-71807E0B9F24}.Debug|ARM64.ActiveCfg = Debug|ARM64
{CA4D810F-C8F4-4B61-9DA9-71807E0B9F24}.Debug|ARM64.Build.0 = Debug|ARM64
{CA4D810F-C8F4-4B61-9DA9-71807E0B9F24}.Debug|x64.ActiveCfg = Debug|x64
{CA4D810F-C8F4-4B61-9DA9-71807E0B9F24}.Debug|x64.Build.0 = Debug|x64
{CA4D810F-C8F4-4B61-9DA9-71807E0B9F24}.Release|ARM64.ActiveCfg = Release|ARM64
{CA4D810F-C8F4-4B61-9DA9-71807E0B9F24}.Release|ARM64.Build.0 = Release|ARM64
{CA4D810F-C8F4-4B61-9DA9-71807E0B9F24}.Release|x64.ActiveCfg = Release|x64
{CA4D810F-C8F4-4B61-9DA9-71807E0B9F24}.Release|x64.Build.0 = Release|x64
{14E62033-58D0-4A7D-8990-52F50A08BBBD}.Debug|ARM64.ActiveCfg = Debug|ARM64
{14E62033-58D0-4A7D-8990-52F50A08BBBD}.Debug|ARM64.Build.0 = Debug|ARM64
{14E62033-58D0-4A7D-8990-52F50A08BBBD}.Debug|x64.ActiveCfg = Debug|x64
{14E62033-58D0-4A7D-8990-52F50A08BBBD}.Debug|x64.Build.0 = Debug|x64
{14E62033-58D0-4A7D-8990-52F50A08BBBD}.Release|ARM64.ActiveCfg = Release|ARM64
{14E62033-58D0-4A7D-8990-52F50A08BBBD}.Release|ARM64.Build.0 = Release|ARM64
{14E62033-58D0-4A7D-8990-52F50A08BBBD}.Release|x64.ActiveCfg = Release|x64
{14E62033-58D0-4A7D-8990-52F50A08BBBD}.Release|x64.Build.0 = Release|x64
{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Debug|ARM64.ActiveCfg = Debug|ARM64
{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Debug|ARM64.Build.0 = Debug|ARM64
{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Debug|x64.ActiveCfg = Debug|x64
{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Debug|x64.Build.0 = Debug|x64
{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Release|ARM64.ActiveCfg = Release|ARM64
{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Release|ARM64.Build.0 = Release|ARM64
{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Release|x64.ActiveCfg = Release|x64
{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Release|x64.Build.0 = Release|x64
{C846F7A7-792A-47D9-B0CB-417C900EE03D}.Debug|ARM64.ActiveCfg = Debug|ARM64
{C846F7A7-792A-47D9-B0CB-417C900EE03D}.Debug|ARM64.Build.0 = Debug|ARM64
{C846F7A7-792A-47D9-B0CB-417C900EE03D}.Debug|ARM64.Deploy.0 = Debug|ARM64
{C846F7A7-792A-47D9-B0CB-417C900EE03D}.Debug|x64.ActiveCfg = Debug|x64
{C846F7A7-792A-47D9-B0CB-417C900EE03D}.Debug|x64.Build.0 = Debug|x64
{C846F7A7-792A-47D9-B0CB-417C900EE03D}.Debug|x64.Deploy.0 = Debug|x64
{C846F7A7-792A-47D9-B0CB-417C900EE03D}.Release|ARM64.ActiveCfg = Release|ARM64
{C846F7A7-792A-47D9-B0CB-417C900EE03D}.Release|ARM64.Build.0 = Release|ARM64
{C846F7A7-792A-47D9-B0CB-417C900EE03D}.Release|ARM64.Deploy.0 = Release|ARM64
{C846F7A7-792A-47D9-B0CB-417C900EE03D}.Release|x64.ActiveCfg = Release|x64
{C846F7A7-792A-47D9-B0CB-417C900EE03D}.Release|x64.Build.0 = Release|x64
{C846F7A7-792A-47D9-B0CB-417C900EE03D}.Release|x64.Deploy.0 = Release|x64
{C831231F-891C-4572-9694-45062534B42A}.Debug|ARM64.ActiveCfg = Debug|ARM64
{C831231F-891C-4572-9694-45062534B42A}.Debug|ARM64.Build.0 = Debug|ARM64
{C831231F-891C-4572-9694-45062534B42A}.Debug|ARM64.Deploy.0 = Debug|ARM64
{C831231F-891C-4572-9694-45062534B42A}.Debug|x64.ActiveCfg = Debug|x64
{C831231F-891C-4572-9694-45062534B42A}.Debug|x64.Build.0 = Debug|x64
{C831231F-891C-4572-9694-45062534B42A}.Debug|x64.Deploy.0 = Debug|x64
{C831231F-891C-4572-9694-45062534B42A}.Release|ARM64.ActiveCfg = Release|ARM64
{C831231F-891C-4572-9694-45062534B42A}.Release|ARM64.Build.0 = Release|ARM64
{C831231F-891C-4572-9694-45062534B42A}.Release|ARM64.Deploy.0 = Release|ARM64
{C831231F-891C-4572-9694-45062534B42A}.Release|x64.ActiveCfg = Release|x64
{C831231F-891C-4572-9694-45062534B42A}.Release|x64.Build.0 = Release|x64
{C831231F-891C-4572-9694-45062534B42A}.Release|x64.Deploy.0 = Release|x64
{8FBDABA4-40EE-4C0E-9BC8-2F6444A6EF90}.Debug|ARM64.ActiveCfg = Debug|ARM64
{8FBDABA4-40EE-4C0E-9BC8-2F6444A6EF90}.Debug|ARM64.Build.0 = Debug|ARM64
{8FBDABA4-40EE-4C0E-9BC8-2F6444A6EF90}.Debug|ARM64.Deploy.0 = Debug|ARM64
{8FBDABA4-40EE-4C0E-9BC8-2F6444A6EF90}.Debug|x64.ActiveCfg = Debug|x64
{8FBDABA4-40EE-4C0E-9BC8-2F6444A6EF90}.Debug|x64.Build.0 = Debug|x64
{8FBDABA4-40EE-4C0E-9BC8-2F6444A6EF90}.Debug|x64.Deploy.0 = Debug|x64
{8FBDABA4-40EE-4C0E-9BC8-2F6444A6EF90}.Release|ARM64.ActiveCfg = Release|ARM64
{8FBDABA4-40EE-4C0E-9BC8-2F6444A6EF90}.Release|ARM64.Build.0 = Release|ARM64
{8FBDABA4-40EE-4C0E-9BC8-2F6444A6EF90}.Release|ARM64.Deploy.0 = Release|ARM64
{8FBDABA4-40EE-4C0E-9BC8-2F6444A6EF90}.Release|x64.ActiveCfg = Release|x64
{8FBDABA4-40EE-4C0E-9BC8-2F6444A6EF90}.Release|x64.Build.0 = Release|x64
{8FBDABA4-40EE-4C0E-9BC8-2F6444A6EF90}.Release|x64.Deploy.0 = Release|x64
{C66020D1-CB10-4CF7-8715-84C97FD5E5E2}.Debug|ARM64.ActiveCfg = Debug|ARM64
{C66020D1-CB10-4CF7-8715-84C97FD5E5E2}.Debug|ARM64.Build.0 = Debug|ARM64
{C66020D1-CB10-4CF7-8715-84C97FD5E5E2}.Debug|x64.ActiveCfg = Debug|x64
{C66020D1-CB10-4CF7-8715-84C97FD5E5E2}.Debug|x64.Build.0 = Debug|x64
{C66020D1-CB10-4CF7-8715-84C97FD5E5E2}.Release|ARM64.ActiveCfg = Release|ARM64
{C66020D1-CB10-4CF7-8715-84C97FD5E5E2}.Release|ARM64.Build.0 = Release|ARM64
{C66020D1-CB10-4CF7-8715-84C97FD5E5E2}.Release|x64.ActiveCfg = Release|x64
{C66020D1-CB10-4CF7-8715-84C97FD5E5E2}.Release|x64.Build.0 = Release|x64
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Debug|ARM64.ActiveCfg = Debug|ARM64
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Debug|ARM64.Build.0 = Debug|ARM64
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Debug|x64.ActiveCfg = Debug|x64
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Debug|x64.Build.0 = Debug|x64
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Release|ARM64.ActiveCfg = Release|ARM64
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Release|ARM64.Build.0 = Release|ARM64
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Release|x64.ActiveCfg = Release|x64
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Release|x64.Build.0 = Release|x64
{0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Debug|ARM64.ActiveCfg = Debug|ARM64
{0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Debug|ARM64.Build.0 = Debug|ARM64
{0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Debug|x64.ActiveCfg = Debug|x64
{0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Debug|x64.Build.0 = Debug|x64
{0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Release|ARM64.ActiveCfg = Release|ARM64
{0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Release|ARM64.Build.0 = Release|ARM64
{0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Release|x64.ActiveCfg = Release|x64
{0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Release|x64.Build.0 = Release|x64
{89D0E199-B17A-418C-B2F8-7375B6708357}.Debug|ARM64.ActiveCfg = Debug|ARM64
{89D0E199-B17A-418C-B2F8-7375B6708357}.Debug|ARM64.Build.0 = Debug|ARM64
{89D0E199-B17A-418C-B2F8-7375B6708357}.Debug|x64.ActiveCfg = Debug|x64
@@ -2212,6 +2422,54 @@ Global
{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|ARM64.Build.0 = Release|ARM64
{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|x64.ActiveCfg = Release|x64
{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|x64.Build.0 = Release|x64
{453CBB73-A3CB-4D0B-8D24-6940B86FE21D}.Debug|ARM64.ActiveCfg = Debug|ARM64
{453CBB73-A3CB-4D0B-8D24-6940B86FE21D}.Debug|ARM64.Build.0 = Debug|ARM64
{453CBB73-A3CB-4D0B-8D24-6940B86FE21D}.Debug|ARM64.Deploy.0 = Debug|ARM64
{453CBB73-A3CB-4D0B-8D24-6940B86FE21D}.Debug|x64.ActiveCfg = Debug|x64
{453CBB73-A3CB-4D0B-8D24-6940B86FE21D}.Debug|x64.Build.0 = Debug|x64
{453CBB73-A3CB-4D0B-8D24-6940B86FE21D}.Debug|x64.Deploy.0 = Debug|x64
{453CBB73-A3CB-4D0B-8D24-6940B86FE21D}.Release|ARM64.ActiveCfg = Release|ARM64
{453CBB73-A3CB-4D0B-8D24-6940B86FE21D}.Release|ARM64.Build.0 = Release|ARM64
{453CBB73-A3CB-4D0B-8D24-6940B86FE21D}.Release|ARM64.Deploy.0 = Release|ARM64
{453CBB73-A3CB-4D0B-8D24-6940B86FE21D}.Release|x64.ActiveCfg = Release|x64
{453CBB73-A3CB-4D0B-8D24-6940B86FE21D}.Release|x64.Build.0 = Release|x64
{453CBB73-A3CB-4D0B-8D24-6940B86FE21D}.Release|x64.Deploy.0 = Release|x64
{C0CE3B5E-16D3-495D-B335-CA791B660162}.Debug|ARM64.ActiveCfg = Debug|ARM64
{C0CE3B5E-16D3-495D-B335-CA791B660162}.Debug|ARM64.Build.0 = Debug|ARM64
{C0CE3B5E-16D3-495D-B335-CA791B660162}.Debug|x64.ActiveCfg = Debug|x64
{C0CE3B5E-16D3-495D-B335-CA791B660162}.Debug|x64.Build.0 = Debug|x64
{C0CE3B5E-16D3-495D-B335-CA791B660162}.Release|ARM64.ActiveCfg = Release|ARM64
{C0CE3B5E-16D3-495D-B335-CA791B660162}.Release|ARM64.Build.0 = Release|ARM64
{C0CE3B5E-16D3-495D-B335-CA791B660162}.Release|x64.ActiveCfg = Release|x64
{C0CE3B5E-16D3-495D-B335-CA791B660162}.Release|x64.Build.0 = Release|x64
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}.Debug|ARM64.ActiveCfg = Debug|ARM64
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}.Debug|ARM64.Build.0 = Debug|ARM64
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}.Debug|x64.ActiveCfg = Debug|x64
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}.Debug|x64.Build.0 = Debug|x64
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}.Release|ARM64.ActiveCfg = Release|ARM64
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}.Release|ARM64.Build.0 = Release|ARM64
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}.Release|x64.ActiveCfg = Release|x64
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}.Release|x64.Build.0 = Release|x64
{605E914B-7232-4789-AF46-BF5D3DDFC14E}.Debug|ARM64.ActiveCfg = Debug|ARM64
{605E914B-7232-4789-AF46-BF5D3DDFC14E}.Debug|ARM64.Build.0 = Debug|ARM64
{605E914B-7232-4789-AF46-BF5D3DDFC14E}.Debug|x64.ActiveCfg = Debug|x64
{605E914B-7232-4789-AF46-BF5D3DDFC14E}.Debug|x64.Build.0 = Debug|x64
{605E914B-7232-4789-AF46-BF5D3DDFC14E}.Release|ARM64.ActiveCfg = Release|ARM64
{605E914B-7232-4789-AF46-BF5D3DDFC14E}.Release|ARM64.Build.0 = Release|ARM64
{605E914B-7232-4789-AF46-BF5D3DDFC14E}.Release|x64.ActiveCfg = Release|x64
{605E914B-7232-4789-AF46-BF5D3DDFC14E}.Release|x64.Build.0 = Release|x64
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Debug|ARM64.ActiveCfg = Debug|ARM64
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Debug|ARM64.Build.0 = Debug|ARM64
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Debug|ARM64.Deploy.0 = Debug|ARM64
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Debug|x64.ActiveCfg = Debug|x64
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Debug|x64.Build.0 = Debug|x64
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Debug|x64.Deploy.0 = Debug|x64
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Release|ARM64.ActiveCfg = Release|ARM64
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Release|ARM64.Build.0 = Release|ARM64
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Release|ARM64.Deploy.0 = Release|ARM64
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Release|x64.ActiveCfg = Release|x64
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Release|x64.Build.0 = Release|x64
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Release|x64.Deploy.0 = Release|x64
{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Debug|ARM64.ActiveCfg = Debug|ARM64
{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Debug|ARM64.Build.0 = Debug|ARM64
{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Debug|x64.ActiveCfg = Debug|x64
@@ -2252,20 +2510,26 @@ Global
{CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Release|ARM64.Build.0 = Release|ARM64
{CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Release|x64.ActiveCfg = Release|x64
{CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Release|x64.Build.0 = Release|x64
{CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Release|x86.ActiveCfg = Release|x64
{CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Release|x86.Build.0 = Release|x64
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Debug|ARM64.ActiveCfg = Debug|ARM64
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Debug|ARM64.Build.0 = Debug|ARM64
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Debug|ARM64.Deploy.0 = Debug|ARM64
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Debug|x64.ActiveCfg = Debug|x64
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Debug|x64.Build.0 = Debug|x64
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Debug|x64.Deploy.0 = Debug|x64
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Release|ARM64.ActiveCfg = Release|ARM64
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Release|ARM64.Build.0 = Release|ARM64
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Release|ARM64.Deploy.0 = Release|ARM64
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Release|x64.ActiveCfg = Release|x64
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Release|x64.Build.0 = Release|x64
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Release|x64.Deploy.0 = Release|x64
{A558C25D-2007-498E-8B6F-43405AFAE9E2}.Debug|ARM64.ActiveCfg = Debug|ARM64
{A558C25D-2007-498E-8B6F-43405AFAE9E2}.Debug|ARM64.Build.0 = Debug|ARM64
{A558C25D-2007-498E-8B6F-43405AFAE9E2}.Debug|x64.ActiveCfg = Debug|x64
{A558C25D-2007-498E-8B6F-43405AFAE9E2}.Debug|x64.Build.0 = Debug|x64
{A558C25D-2007-498E-8B6F-43405AFAE9E2}.Debug|x86.ActiveCfg = Debug|x64
{A558C25D-2007-498E-8B6F-43405AFAE9E2}.Debug|x86.Build.0 = Debug|x64
{A558C25D-2007-498E-8B6F-43405AFAE9E2}.Release|ARM64.ActiveCfg = Release|ARM64
{A558C25D-2007-498E-8B6F-43405AFAE9E2}.Release|ARM64.Build.0 = Release|ARM64
{A558C25D-2007-498E-8B6F-43405AFAE9E2}.Release|x64.ActiveCfg = Release|x64
{A558C25D-2007-498E-8B6F-43405AFAE9E2}.Release|x64.Build.0 = Release|x64
{A558C25D-2007-498E-8B6F-43405AFAE9E2}.Release|x86.ActiveCfg = Release|x64
{A558C25D-2007-498E-8B6F-43405AFAE9E2}.Release|x86.Build.0 = Release|x64
{08F9155D-B6DC-46E5-9C83-AF60B655898B}.Debug|ARM64.ActiveCfg = Debug|ARM64
{08F9155D-B6DC-46E5-9C83-AF60B655898B}.Debug|ARM64.Build.0 = Debug|ARM64
{08F9155D-B6DC-46E5-9C83-AF60B655898B}.Debug|x64.ActiveCfg = Debug|x64
@@ -2290,6 +2554,34 @@ Global
{EBED240C-8702-452D-B764-6DB9DA9179AF}.Release|ARM64.Build.0 = Release|ARM64
{EBED240C-8702-452D-B764-6DB9DA9179AF}.Release|x64.ActiveCfg = Release|x64
{EBED240C-8702-452D-B764-6DB9DA9179AF}.Release|x64.Build.0 = Release|x64
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0}.Debug|ARM64.ActiveCfg = Debug|ARM64
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0}.Debug|ARM64.Build.0 = Debug|ARM64
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0}.Debug|x64.ActiveCfg = Debug|x64
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0}.Debug|x64.Build.0 = Debug|x64
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0}.Release|ARM64.ActiveCfg = Release|ARM64
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0}.Release|ARM64.Build.0 = Release|ARM64
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0}.Release|x64.ActiveCfg = Release|x64
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0}.Release|x64.Build.0 = Release|x64
{5702B3CC-8575-48D5-83D8-15BB42269CD3}.Debug|ARM64.ActiveCfg = Debug|ARM64
{5702B3CC-8575-48D5-83D8-15BB42269CD3}.Debug|ARM64.Build.0 = Debug|ARM64
{5702B3CC-8575-48D5-83D8-15BB42269CD3}.Debug|x64.ActiveCfg = Debug|x64
{5702B3CC-8575-48D5-83D8-15BB42269CD3}.Debug|x64.Build.0 = Debug|x64
{5702B3CC-8575-48D5-83D8-15BB42269CD3}.Release|ARM64.ActiveCfg = Release|ARM64
{5702B3CC-8575-48D5-83D8-15BB42269CD3}.Release|ARM64.Build.0 = Release|ARM64
{5702B3CC-8575-48D5-83D8-15BB42269CD3}.Release|x64.ActiveCfg = Release|x64
{5702B3CC-8575-48D5-83D8-15BB42269CD3}.Release|x64.Build.0 = Release|x64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|ARM64.ActiveCfg = Debug|ARM64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|ARM64.Build.0 = Debug|ARM64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|x64.ActiveCfg = Debug|x64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|x64.Build.0 = Debug|x64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|x86.ActiveCfg = Debug|x64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|x86.Build.0 = Debug|x64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|ARM64.ActiveCfg = Release|ARM64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|ARM64.Build.0 = Release|ARM64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x64.ActiveCfg = Release|x64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x64.Build.0 = Release|x64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x86.ActiveCfg = Release|x64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x86.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2517,18 +2809,49 @@ Global
{37D07516-4185-43A4-924F-3C7A5D95ECF6} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
{8F021B46-362B-485C-BFBA-CCF83E820CBD} = {8F62026A-294B-41C6-8839-87463613F216}
{66614C26-314C-4B91-9071-76133422CFEF} = {B6C42F16-73EB-477E-8B0D-4E6CF6C20AAC}
{3846508C-77EB-4034-A702-F8BB263C4F79} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2} = {3846508C-77EB-4034-A702-F8BB263C4F79}
{6CE438DF-C245-4997-A360-0A0939E4BA34} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{E09AA983-C755-474F-83D6-A5CDF528C070} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{6D56B64D-FF1F-488F-AFED-9B9854A5D399} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{92EC89E4-9972-453A-8A1A-3A9E230C146A} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{D1160404-D3D1-497A-883A-4059C07C2273} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{40F6D69D-E321-400F-A767-5628C7AE453D} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{F3D09629-59A2-4924-A4B9-D6BFAA2C1B49} = {3846508C-77EB-4034-A702-F8BB263C4F79}
{305DD37E-C85D-4B08-AAFE-7381FA890463} = {F3D09629-59A2-4924-A4B9-D6BFAA2C1B49}
{CA4D810F-C8F4-4B61-9DA9-71807E0B9F24} = {F3D09629-59A2-4924-A4B9-D6BFAA2C1B49}
{14E62033-58D0-4A7D-8990-52F50A08BBBD} = {7520A2FE-00A2-49B8-83ED-DB216E874C04}
{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F} = {7520A2FE-00A2-49B8-83ED-DB216E874C04}
{071E18A4-A530-46B8-AB7D-B862EE55E24E} = {3846508C-77EB-4034-A702-F8BB263C4F79}
{C846F7A7-792A-47D9-B0CB-417C900EE03D} = {071E18A4-A530-46B8-AB7D-B862EE55E24E}
{C831231F-891C-4572-9694-45062534B42A} = {071E18A4-A530-46B8-AB7D-B862EE55E24E}
{7520A2FE-00A2-49B8-83ED-DB216E874C04} = {3846508C-77EB-4034-A702-F8BB263C4F79}
{8FBDABA4-40EE-4C0E-9BC8-2F6444A6EF90} = {7520A2FE-00A2-49B8-83ED-DB216E874C04}
{C66020D1-CB10-4CF7-8715-84C97FD5E5E2} = {7520A2FE-00A2-49B8-83ED-DB216E874C04}
{79775343-7A3D-445D-9104-3DD5B2893DF9} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8} = {3846508C-77EB-4034-A702-F8BB263C4F79}
{89D0E199-B17A-418C-B2F8-7375B6708357} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E} = {CA716AE6-FE5C-40AC-BB8F-2C87912687AC}
{453CBB73-A3CB-4D0B-8D24-6940B86FE21D} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{C0CE3B5E-16D3-495D-B335-CA791B660162} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{605E914B-7232-4789-AF46-BF5D3DDFC14E} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE} = {9873BA05-4C41-4819-9283-CF45D795431B}
{7F5B9557-5878-4438-A721-3E28296BA193} = {9873BA05-4C41-4819-9283-CF45D795431B}
{DD6E12FE-5509-4ABC-ACC2-3D6DC98A238C} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{0A84F764-3A88-44CD-AA96-41BDBD48627B} = {DD6E12FE-5509-4ABC-ACC2-3D6DC98A238C}
{E4585179-2AC1-4D5F-A3FF-CFC5392F694C} = {DD6E12FE-5509-4ABC-ACC2-3D6DC98A238C}
{CA7D8106-30B9-4AEC-9D05-B69B31B8C461} = {DD6E12FE-5509-4ABC-ACC2-3D6DC98A238C}
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{A558C25D-2007-498E-8B6F-43405AFAE9E2} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{08F9155D-B6DC-46E5-9C83-AF60B655898B} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{4382A954-179A-4078-92AF-715187DFFF50} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{EBED240C-8702-452D-B764-6DB9DA9179AF} = {F05E590D-AD46-42BE-9C25-6A63ADD2E3EA}
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0} = {F05E590D-AD46-42BE-9C25-6A63ADD2E3EA}
{5702B3CC-8575-48D5-83D8-15BB42269CD3} = {929C1324-22E8-4412-A9A8-80E85F3985A5}
{64B88F02-CD88-4ED8-9624-989A800230F9} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}

184
README.md
View File

@@ -11,14 +11,15 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
| | Current utilities: | |
|--------------|--------------------|--------------|
| [Advanced Paste](https://aka.ms/PowerToysOverview_AdvancedPaste) | [Always on Top](https://aka.ms/PowerToysOverview_AoT) | [PowerToys Awake](https://aka.ms/PowerToysOverview_Awake) |
| [Command Not Found](https://aka.ms/PowerToysOverview_CmdNotFound) | [Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) | [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) | [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) | [Paste as Plain Text](https://aka.ms/PowerToysOverview_PastePlain) |
| [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) | [Quick Accent](https://aka.ms/PowerToysOverview_QuickAccent) |
| [Registry Preview](https://aka.ms/PowerToysOverview_RegistryPreview) | [Screen Ruler](https://aka.ms/PowerToysOverview_ScreenRuler) | [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) |
| [Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [Workspaces](https://aka.ms/PowerToysOverview_Workspaces) | [ZoomIt](https://aka.ms/PowerToysOverview_ZoomIt) |
| [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) | [Mouse utilities](https://aka.ms/PowerToysOverview_MouseUtilities) |
| [Mouse Without Borders](https://aka.ms/PowerToysOverview_MouseWithoutBorders) | [New+](https://aka.ms/PowerToysOverview_NewPlus) | [Paste as Plain Text](https://aka.ms/PowerToysOverview_PastePlain) |
| [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) |
## Installing and running Microsoft PowerToys
@@ -34,19 +35,19 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
Go to the [Microsoft PowerToys GitHub releases page][github-release-link] and click on `Assets` at the bottom to show the files available in the release. Please use the appropriate PowerToys installer that matches your machine's architecture and install scope. For most, it is `x64` and per-user.
<!-- items that need to be updated release to release -->
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.89%22
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.88%22
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.88.0/PowerToysUserSetup-0.88.0-x64.exe
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.88.0/PowerToysUserSetup-0.88.0-arm64.exe
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.88.0/PowerToysSetup-0.88.0-x64.exe
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.88.0/PowerToysSetup-0.88.0-arm64.exe
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.91%22
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.90%22
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.90.0/PowerToysUserSetup-0.90.0-x64.exe
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.90.0/PowerToysUserSetup-0.90.0-arm64.exe
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.90.0/PowerToysSetup-0.90.0-x64.exe
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.90.0/PowerToysSetup-0.90.0-arm64.exe
| Description | Filename | sha256 hash |
|----------------|----------|-------------|
| Per user - x64 | [PowerToysUserSetup-0.88.0-x64.exe][ptUserX64] | 5BBA2E06603CAAE0269DFBC991095C6664FD934130335197C1BA3120E19B7CA3 |
| Per user - ARM64 | [PowerToysUserSetup-0.88.0-arm64.exe][ptUserArm64] | E79723F9F94068C699E01334C8CC0C85F37818EB4664FC772D2B545A1C37C3FA |
| Machine wide - x64 | [PowerToysSetup-0.88.0-x64.exe][ptMachineX64] | C43742DB7AA3F8B01FE7AE1DA591F0342767AFE5BBACB72F2968CE5E8EE1E3AC |
| Machine wide - ARM64 | [PowerToysSetup-0.88.0-arm64.exe][ptMachineArm64] | AEE4A67643C886336F31F86C4117BA5F01BCA5E0E99FF34524217DC91AFA7132 |
| Per user - x64 | [PowerToysUserSetup-0.90.0-x64.exe][ptUserX64] | 2A6036F5B2D454084E55816C306E1E57EF1D14C916691CBDA42B469797605CE0 |
| Per user - ARM64 | [PowerToysUserSetup-0.90.0-arm64.exe][ptUserArm64] | AB2E4DC87A9D764BE897C5170E2890E174C89CA912A1916FA3AE1E427536EA4A |
| Machine wide - x64 | [PowerToysSetup-0.90.0-x64.exe][ptMachineX64] | 12801C44F43D0CC61E90DF1EFDC40E4F3C88341E0199D5B20791042D9B173DCF |
| Machine wide - ARM64 | [PowerToysSetup-0.90.0-arm64.exe][ptMachineArm64] | 2998007C8FCD7BD2770767C6502AAA2CC75B85EC30DE62986EC7005EB0014EDB |
This is our preferred method.
@@ -92,141 +93,96 @@ For guidance on developing for PowerToys, please read the [developer docs](/doc/
Our [prioritized roadmap][roadmap] of features and utilities that the core team is focusing on.
### 0.88 - January 2025 Update
### 0.90 - March 2025 Update
In this release, we focused on new features, stability, and improvements.
In this release, we focused on new features, stability, and automation.
**Highlights**
**Highlights**
- New utility: ZoomIt - a screen zoom, annotation, and recording tool for technical presentations and demos. This utility from Sysinternals has had its source code released and included in PowerToys. ZoomIt will still continue to be updated and shipped by Sysinternals for users who prefer to have it as a standalone utility outside of PowerToys. Thanks [@markrussinovich](https://github.com/markrussinovich), [@foxmsft](https://github.com/foxmsft) and [@johnstep](https://github.com/johnstep) for contributing the original code and reviewing the PowerToys integration!
- Video Conference Mute has been deprecated and was removed from PowerToys.
- .Net 9.0.1 fixed many issue in WPF, improving stability for PowerToys Run.
![Gif for Command Palette](doc/images/overview/CmdPal_Hero.gif)
### General
- Applied a workaround for the Windows App SDK applications title bar override that was causing accent color to not be shown on the top bar of applications on Windows 10. Thanks [@pingzing](https://github.com/pingzing)!
- Improved the "admin application running" notification checking logic to be less demanding on resources. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
- Fixed an issue causing many utilities to crash when the GPO to disable data diagnostics was applied.
- New module: Command Palette ("CmdPal") - Created as the evolution of PowerToys Run with extensibility at the forefront, Command Palette is a quick launcher with a richer display and additional capabilities without sacrificing performance, allowing you to start anything with the shortcut **Win+Alt+Space**! Thanks [@zadjii-msft](https://github.com/zadjii-msft), [@niels9001](https://github.com/niels9001), [@joadoumie](https://github.com/joadoumie), [@plante-msft](https://github.com/plante-msft), [@ethanfangg](https://github.com/ethanfangg) and [@krschau](https://github.com/krschau)!
- Enhanced the Color Picker by switching from WPF UI to .NET WPF, resulting in improved themes and visual consistency across different modes. Thanks [@mantaionut](https://github.com/mantaionut)! Thanks [@Jay-o-Way](https://github.com/Jay-o-Way) and [@niels9001](https://github.com/niels9001) for helping with the review!
- Added the ability to delete files directly from Peek, enhancing file management efficiency. Thanks [@daverayment](https://github.com/daverayment) and thanks [@htcfreek](https://github.com/htcfreek) for the review!
- Added support for variables in template filenames, enabling dynamic elements like date components and environment variables for enhanced customization in New+. Thanks [@cgaarden](https://github.com/cgaarden)!
### Advanced Paste
### Color Picker
- Fixed a crash when the application was exiting. (This was a hotfix for 0.87)
- Added a Json format validation step to verify if a conversion to Json should be applied.
- Fixed accessibility issues when using a screen reader.
- Added support for all BitmapDecoder supported image file types to the Image to Text functionality. Thanks [@daverayment](https://github.com/daverayment)!
- Fixed an issue causing Advanced Paste initialization errors to hang the PowerToys main process.
- Replaced WPF UI with .NET WPF for the Color Picker, enhancing compatibility and improving theme support. Thanks [@mantaionut](https://github.com/mantaionut)! Thanks [@Jay-o-Way](https://github.com/Jay-o-Way) and [@niels9001](https://github.com/niels9001) for helping with the review!
### Command Palette
- Introduced the Windows Command Palette ("CmdPal"), the next iteration of PowerToys Run, designed with extensibility at its core. CmdPal includes features such as searching for installed apps, shell commands, files and WinGet package installation. This module aims to provide a more powerful and flexible launcher experience. Thanks [@zadjii-msft](https://github.com/zadjii-msft), [@niels9001](https://github.com/niels9001), [@joadoumie](https://github.com/joadoumie), [@plante-msft](https://github.com/plante-msft), and the whole team!
### FancyZones
- Removed Workspaces Editor from the exclusions list so it can be snapped by FancyZones.
- Fixed a bug where deleting a layout resulted in incorrect data being written to the JSON file.
- Fixed a bug where layout hotkeys were displayed incorrectly, ensuring the hotkey list does not include invalid entries.
- Fixed an issue where the "None" option was missing in the editor layout.
### Keyboard Manager
### Image Resizer
- Added an option to make a shortcut remapping only trigger with exact modifiers.
### Monaco Preview
- Added support for .resx and .resw files in Peek and File Explorer add-ons. Thanks [@asif4318](https://github.com/asif4318)!
- Added a setting to make the code minimap toggle-able in Peek and File Explorer add-ons. Thanks [@PesBandi](https://github.com/PesBandi)!
- Fixed an issue causing Json format preview setting to not be applied correctly.
- Fixed an issue causing the wrong Monaco assets to be used at runtime.
- Fixed warnings in ImageResizer regarding the use of variables "shellItem" and "itemName" without being initialized.
### Mouse Without Borders
- Fixed an issue causing clipboard to stop working after going through a UAC screen when using the Service mode. Thanks [@YDKK](https://github.com/YDKK)!
- Enhanced the logger to properly track the file path for easier debugging.
- Refactored the "Common" class into distinct individual classes to enhance maintainability, and updated all references and unit tests to reflect these changes. Thanks [@mikeclayton](https://github.com/mikeclayton) for this!
### New+
- Fixed an issue causing New+ to override the New file or folder creation from the File Explorer Ribbon buttons or keyboard shortcuts on Windows 10.
- When creating file or folders through a template, they should now have the current time as the last modified date. Thanks [@cgaarden](https://github.com/cgaarden)!
- Added support for variables in template filenames, including date/time components, parent folder name, and environment variables. Thanks [@cgaarden](https://github.com/cgaarden)!
### Peek
- Fixed an issue causing Peek to not appear if it was previously minimized. Thanks [@asif4318](https://github.com/asif4318)!
- Added the ability to delete the file currently being previewed in Peek, including navigation updates and handling for deleted items. Thanks [@daverayment](https://github.com/daverayment) and thanks [@htcfreek](https://github.com/htcfreek) for your help reviewing this!
### PowerToys Run
- Fixed a transparent border issue on Windows 10. (This was a hotfix for 0.87)
- Fixed a crash in the OneNote plugin after the .Net 9 update. (This was a hotfix for 0.87)
- Fixed an issue causing the Calculator plugin to return division by zero errors when dividing by hexadecimal numbers. Thanks [@plante-msft](https://github.com/plante-msft)!
- Updated the Calculator plugin Mages library to 3.0.0 and added support for the random integer function. Thanks [@htcfreek](https://github.com/htcfreek)!
- Improved handling of non-base 10 numbers to add support for binary and octal numbers in the Calculator plugin. Thanks [@PesBandi](https://github.com/PesBandi)!
- Added a setting to enable selection of which units to use for trigonometric functions. Thanks [@OldUser101](https://github.com/OldUser101)!
- Fixed a .NET 9 regression causing the PowerToys Run dialog to not be draggable. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
- Added context menu buttons for the VS Code Workspaces plugin, for copying the path, opening in File Explorer or in Console. Thanks [@programming-with-ia](https://github.com/programming-with-ia)!
- Added some telemetry to gather data on which hotkey is used to trigger PowerToys Run.
- Removed the workarounds that were in place to fix some WPF issues that were fixed in .NET 9.0.1.
- Fixed a typo in the Value Generator plugin messages. Thanks [@OldUser101](https://github.com/OldUser101)!
### Quick Accent
- Added the ć character to the Slovenian character set. Thanks [@dsoklic](https://github.com/dsoklic)!
- Added the Proto-Indo-European character set.
### Registry Preview
- Fixed an issue causing line breaks to not be parsed correctly for REG_MULTI_SZ values. Thanks [@htcfreek](https://github.com/htcfreek)!
- Added a tooltip to values to show multiple lines of data. Thanks [@htcfreek](https://github.com/htcfreek)!
- Added a context menu to enable copying type, value and key paths. Thanks [@htcfreek](https://github.com/htcfreek)!
- Fixed an issue where duplicated applications were shown by ensuring the shell link helper opens .ink files non-exclusively and correctly retrieves the "FullPath". Thanks [@htcfreek](https://github.com/htcfreek) and [@davidegiacometti](https://github.com/davidegiacometti) for review!
- Fixed an issue where applying round corners on Windows 11 build 22000 caused crashes.
- Async the OnRename method to unblock the thread. Thanks [@davidegiacometti](https://github.com/davidegiacometti) for review!
- Added support for using `sq` instead of `^2` in the Unit Converter. Thanks [@PesBandi](https://github.com/PesBandi)!
### Settings
- Made the Advanced Paste paste OpenAI configuration modal scrollable.
- Fixed the text on the Quick Accent page to refer to "character sets" instead of "character set". Thanks [@PesBandi](https://github.com/PesBandi)!
- Added the plugin's dll file version and website to the PowerToys Run plugin settings. Thanks [@htcfreek](https://github.com/htcfreek)!
- Added the Workspaces file to the list of files that gets backed up by the Back up / Restore functionality.
- Fixed an issue causing some of the selected character sets to be unselected when opening the character set expander in the Quick Accent page.
- Improved GPO logic, icons, info bar layout and enabled state of all modules settings pages. Thanks [@htcfreek](https://github.com/htcfreek)!
- Fixed some accessibility issues and refactored and improved quality of the code related to image sizes in the Image Resizer page. Thanks [@daverayment](https://github.com/daverayment)!
- Fixed mentions of "Backup" to "Back up" when it should be used as a verb. Thanks [@JackStuart](https://github.com/JackStuart)!
- Added a "New" label to Settings to better highlight new utilities that get released. Thanks [@niels9001](https://github.com/niels9001) for the UI tweaks!
### Text Extractor
- Fixed many accessibility and UI issues on the overlay UI. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
- Disabled the spell check feature in the text boxes of plugin settings for PowerToys Run. Thanks [@htcfreek](https://github.com/htcfreek)!
- Fixed an issue where InfoBars for release notes errors were not displayed properly, and added a retry button. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
### Workspaces
- Fixed an issue causing the Workspaces Editor to start outside of visible desktop area.
- Fixed an issue to maintain command line arguments for applications when trying using the "Launch and Edit" feature.
### Video Conference Mute
- The module has been deprecated in 0.88.0, being removed from PowerToys.
### ZoomIt
- New utility: Zoom It - a screen zoom, annotation, and recording tool for technical presentations and demos. This utility from Sysinternals has had its source code released and included in PowerToys. ZoomIt will still continue to be updated and shipped by Sysinternals for users who prefer to have it as a standalone utility outside of PowerToys. Thanks [@markrussinovich](https://github.com/markrussinovich), [@foxmsft](https://github.com/foxmsft) and [@johnstep](https://github.com/johnstep) for contributing the original code and reviewing the PowerToys integration!
- Fixed an issue where some minimized packaged apps (e.g., Microsoft ToDo, Settings) were not snapshotted.
### Documentation
- Updated the PowerToys Run documentation to reflect documentation pages for new plugins.
- Added YubicoOauthOTP plugin mention to thirdPartyRunPlugins.md. Thanks [@dlnilsson](https://github.com/dlnilsson)!
- Added the FirefoxBookmark plugin to the list of Third-Party plugins for PowerToys Run. Thanks [@8LWXpg](https://github.com/8LWXpg)!
- Added the SVGL third-party plugin to PowerToys Run, enabling users to search, browse, and copy SVG logos. Thanks [@SameerJS6](https://github.com/SameerJS6)!
- Added Monaco usage for the Registry Preview.
### Development
- Added fuzz testing for AdvancedPaste, with a new pipeline for OneFuzz.
- Added a new CI pipeline to build with the latest WindowsAppSDK.
- Added a new CI pipeline to build with the latest webview2 from Edge Canary.
- Made the HostsUILib project AOT compatible. Thanks [@snickler](https://github.com/snickler) for your help reviewing this!
- Made FilePreviewCommon and MarkdownPreviewHandler AOT compatible. Thanks [@snickler](https://github.com/snickler) for your help reviewing this!
- Made the PowerAccent.Core project AOT compatible. Thanks [@snickler](https://github.com/snickler) for your help reviewing this!
- Cleaned up some code for AOT compatibility in the Advanced Paste module. Thanks [@snickler](https://github.com/snickler) for your help reviewing this!
- Removed the prerelease flag from the PowerToys development DSC configurations. Thanks [@denelon](https://github.com/denelon)!
- Improved Dart CI reliability by improving error messages and retrying to the step that installs the correct dotnet version.
- Improved Dart CI reliability by fixing retries when downloading the localization files.
- Improved Dart CI build times by removing the steps to build the no longer needed abstracted utility nuget packages.
- Removed the solution.props file from the solution root.
- Fixed PowerToys Run Calculator plugin tests when running in systems with different number formats. Thanks [@htcfreek](https://github.com/htcfreek)!
- Updated many .NET packages from .NET 9.0.0 to 9.0.1 for security fixes. Thanks [@snickler](https://github.com/snickler)!
- Refactored the Mouse Without Borders Common.Log.cs and Common.Receiver.cs files. Thanks [@mikeclayton](https://github.com/mikeclayton)!
- Updated WinGet configuration file location and extension. Thanks [@mdanish-kh](https://github.com/mdanish-kh)!
- Removed the Markdown file bypass to ensure CI runs for commits that only update Markdown files.
- Fixed an issue where the default generated file path exceeded the length limit of 260 characters for EnvironmentVariablesUILib.csproj, causing build failures.
- Upgraded WindowsAppSDK to 1.6.250205002 and CsWinRT to 2.2.0. Thanks [@htcfreek](https://github.com/htcfreek) for review!
- Upgraded XamlStyler to 3.2501.8 and dotnet-consolidate to 4.2.0. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
- Updated .NET Packages from 9.0.2 to 9.0.3.
- Optimized the UI Test Automation Framework and added UI test cases for the Hosts File Editor module.
- Added fuzz testing for RegistryPreview.
- Added new UI tests for the FancyZones editor, including tests for creating, duplicating, editing, and deleting layouts.
- Added telemetry code to measure the module editor open time and evaluate the benefits of applying AOT.
#### What is being planned for version 0.89
For [v0.89][github-next-release-work], we'll work on the items below:
### What is being planned for version 0.91
For [v0.91][github-next-release-work], we'll work on the items below:
- Stability / bug fixes
- New module: File Actions Menu
- PowerToys Run v2 development work
- New UI Automation tests
- Working on installer upgrades
- Upgrading Keyboard Manager's editor UI
- Stability / bug fixes
## PowerToys Community

View File

@@ -94,5 +94,5 @@ Note that we've supplied `Debug` option, so a `%TEMP\PowerToys.DSC.TestConfigure
Finally, you can test it with winget by invoking it as such:
```ps
winget configure .\configuration.dsc.yaml --accept-configuration-agreements --disable-interactivity
winget configure .\configuration.winget --accept-configuration-agreements --disable-interactivity
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

View File

@@ -42,6 +42,7 @@ Contact the developers of a plugin directly for assistance with a specific plugi
| [CanIUse](https://github.com/skttl/ptrun-caniuse) | [skttl](https://github.com/skttl) | Look up browser feature support with caniuse.com |
| [TailwindCSS](https://github.com/skttl/ptrun-tailwindcss) | [skttl](https://github.com/skttl) | Search the documentation of TailwindCSS |
| [HttpStatusCodes](https://github.com/grzhan/HttpStatusCodePowerToys) | [grzhan](https://github.com/grzhan) | Search for http status codes |
| [SVGL](https://github.com/Sameerjs6/powertoys-svgl) | [SameerJS6](https://github.com/SameerJS6) | Search, Browse and copy SVG logos from SVGL. |
## Extending software plugins
@@ -63,3 +64,4 @@ Below are community created plugins that target a website or software. They are
| [SSH](https://github.com/8LWXpg/PowerToysRun-SSH) | [8LWXpg](https://github.com/8LWXpg) | Connect to ssh clients |
| [Bilibili](https://github.com/Whuihuan/PowerToysRun-Bilibili) | [Whuihuan](https://github.com/Whuihuan) | Use AVID or BVID to parse and jump to Bilibili |
| [YubicoOauthOTP](https://github.com/dlnilsson/Community.PowerToys.Run.Plugin.YubicoOauthOTP) | [dlnilsson](https://github.com/dlnilsson) | Display generated codes from OATH accounts stored on the YubiKey in powerToys Run |
| [Firefox Bookmark](https://github.com/8LWXpg/PowerToysRun-FirefoxBookmark) | [8LWXpg](https://github.com/8LWXpg) | Open bookmarks in Firefox based browser |

View File

@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<?include $(sys.CURRENTDIR)\Common.wxi?>
<?define CmdPalBuildDir="$(var.BinDir)\WinUI3Apps\CmdPal\"?>
<Fragment>
<DirectoryRef Id="WinUI3AppsInstallFolder">
<Directory Id="CmdPalInstallFolder" Name="CmdPal">
<Directory Id="CmdPalDepsInstallFolder" Name="Dependencies">
<?if $(sys.BUILDARCH) = x64 ?>
<Directory Id="CmdPalDepsX64InstallFolder" Name="x64" />
<?else ?>
<Directory Id="CmdPalDepsArm64InstallFolder" Name="arm64" />
<?endif ?>
</Directory>
</Directory>
</DirectoryRef>
<DirectoryRef Id="CmdPalInstallFolder" FileSource="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion).0_Test">
<Component Id="Module_CmdPal" Win64="yes" Guid="3A4942B2-1A86-4182-B3B4-65157365A980">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="Module_CmdPal" Value="" KeyPath="yes"/>
</RegistryKey>
<?if $(sys.BUILDARCH) = x64 ?>
<File Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion).0_Test\Microsoft.CmdPal.UI_$(var.CmdPalVersion).0_x64.msix" />
<?else ?>
<File Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion).0_Test\Microsoft.CmdPal.UI_$(var.CmdPalVersion).0_arm64.msix" />
<?endif ?>
</Component>
</DirectoryRef>
<?if $(sys.BUILDARCH) = x64 ?>
<DirectoryRef Id="CmdPalDepsX64InstallFolder" FileSource="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion).0_Test\Dependencies\x64">
<Component Id="Module_CmdPal_Deps" Win64="yes" Guid="C2790FC4-0665-4462-947A-D942A2AABFF0">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="Module_CmdPal_Deps" Value="" KeyPath="yes"/>
</RegistryKey>
<File Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion).0_Test\Dependencies\x64\Microsoft.VCLibs.x64.14.00.Desktop.appx" />
<File Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion).0_Test\Dependencies\x64\Microsoft.WindowsAppRuntime.1.6.msix" />
</Component>
</DirectoryRef>
<?else ?>
<DirectoryRef Id="CmdPalDepsArm64InstallFolder" FileSource="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion).0_Test\Dependencies\arm64">
<Component Id="Module_CmdPal_Deps" Win64="yes" Guid="C2790FC4-0665-4462-947A-D942A2AABFF0">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="Module_CmdPal_Deps" Value="" KeyPath="yes"/>
</RegistryKey>
<File Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion).0_Test\Dependencies\arm64\Microsoft.VCLibs.ARM64.14.00.Desktop.appx" />
<File Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion).0_Test\Dependencies\arm64\Microsoft.WindowsAppRuntime.1.6.msix" />
</Component>
</DirectoryRef>
<?endif ?>
<ComponentGroup Id="CmdPalComponentGroup">
<Component Id="RemoveCmdPalFolder" Guid="2DF90C08-CC75-4245-A14E-B82904636C53" Directory="INSTALLFOLDER">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="RemoveCmdPalFolder" Value="" KeyPath="yes"/>
</RegistryKey>
<RemoveFolder Id="RemoveCmdPalInstallDirFolder" Directory="CmdPalInstallFolder" On="uninstall"/>
<RemoveFolder Id="RemoveCmdPalDepsInstallDirFolder" Directory="CmdPalDepsInstallFolder" On="uninstall"/>
<?if $(sys.BUILDARCH) = x64 ?>
<RemoveFolder Id="RemoveCmdPalDepsX64InstallDirFolder" Directory="CmdPalDepsX64InstallFolder" On="uninstall"/>
<?else ?>
<RemoveFolder Id="RemoveCmdPalDepsArm64InstallDirFolder" Directory="CmdPalDepsArm64InstallFolder" On="uninstall"/>
<?endif ?>
</Component>
<ComponentRef Id="Module_CmdPal" />
<ComponentRef Id="Module_CmdPal_Deps" />
</ComponentGroup>
</Fragment>
</Wix>

View File

@@ -17,6 +17,12 @@
<PropertyGroup Label="UserMacros" Condition=" '$(PerUser)' != 'true' ">
<DefineConstants>$(DefineConstants);PerUser=false</DefineConstants>
</PropertyGroup>
<PropertyGroup Label="UserMacros" Condition=" '$(CIBuild)' == 'true' ">
<DefineConstants>$(DefineConstants);CIBuild=true</DefineConstants>
</PropertyGroup>
<PropertyGroup Label="UserMacros" Condition=" '$(CIBuild)' != 'true' ">
<DefineConstants>$(DefineConstants);CIBuild=false</DefineConstants>
</PropertyGroup>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform Condition="'$(Platform)'=='x64'">x64</Platform>

View File

@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" InitialTargets="EnsureNuGetPackageBuildImports" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="4.0" DefaultTargets="Build" InitialTargets="EnsureNuGetPackageBuildImports"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\src\Version.props" Condition="Exists('..\..\src\Version.props')" />
<Import Project="..\..\src\CmdPalVersion.props" Condition="Exists('..\..\src\CmdPalVersion.props')" />
<Import Project="..\wix.props" Condition="Exists('..\wix.props')" />
<PropertyGroup Condition="'$(Platform)' == 'x64'">
<DefineConstants>Version=$(Version);MonacoSRCHarvestPath=$(ProjectDir)..\..\x64\$(Configuration)\Assets\Monaco\monacoSRC</DefineConstants>
<DefineConstants>Version=$(Version);MonacoSRCHarvestPath=$(ProjectDir)..\..\x64\$(Configuration)\Assets\Monaco\monacoSRC;CmdPalVersion=$(CmdPalVersion)</DefineConstants>
<!-- THIS IS AN INNER LOOP OPTIMIZATION
The build pipeline builds the Settings and Launcher projects for Publication
using a specific profile. If you're doing local installer builds, this will
@@ -17,7 +19,7 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
</PreBuildEvent>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)' != 'x64'">
<DefineConstants>Version=$(Version);MonacoSRCHarvestPath=$(ProjectDir)..\..\ARM64\$(Configuration)\Assets\Monaco\monacoSRC</DefineConstants>
<DefineConstants>Version=$(Version);MonacoSRCHarvestPath=$(ProjectDir)..\..\ARM64\$(Configuration)\Assets\Monaco\monacoSRC;CmdPalVersion=$(CmdPalVersion);</DefineConstants>
<PreBuildEvent>IF NOT DEFINED IsPipeline (
call "$([MSBuild]::GetVsInstallRoot())\Common7\Tools\VsDevCmd.bat" -arch=arm64 -host_arch=amd64 -winsdk=10.0.19041.0 -vcvars_ver=$(VCToolsVersion)
SET PTRoot=$(SolutionDir)\..
@@ -32,6 +34,7 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
call move /Y ..\..\..\AdvancedPaste.wxs.bk ..\..\..\AdvancedPaste.wxs
call move /Y ..\..\..\Awake.wxs.bk ..\..\..\Awake.wxs
call move /Y ..\..\..\BaseApplications.wxs.bk ..\..\..\BaseApplications.wxs
call move /Y ..\..\..\CmdPal.wxs.bk ..\..\..\CmdPal.wxs
call move /Y ..\..\..\ColorPicker.wxs.bk ..\..\..\ColorPicker.wxs
call move /Y ..\..\..\Core.wxs.bk ..\..\..\Core.wxs
call move /Y ..\..\..\EnvironmentVariables.wxs.bk ..\..\..\EnvironmentVariables.wxs
@@ -54,7 +57,7 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
call move /Y ..\..\..\WinAppSDK.wxs.bk ..\..\..\WinAppSDK.wxs
call move /Y ..\..\..\WinUI3Applications.wxs.bk ..\..\..\WinUI3Applications.wxs
call move /Y ..\..\..\Workspaces.wxs.bk ..\..\..\Workspaces.wxs
</PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<PropertyGroup>
<Name>PowerToysInstaller</Name>
@@ -65,6 +68,12 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
<PropertyGroup Label="UserMacros" Condition=" '$(PerUser)' != 'true' ">
<DefineConstants>$(DefineConstants);PerUser=false</DefineConstants>
</PropertyGroup>
<PropertyGroup Label="UserMacros" Condition=" '$(CIBuild)' == 'true' ">
<DefineConstants>$(DefineConstants);CIBuild=true</DefineConstants>
</PropertyGroup>
<PropertyGroup Label="UserMacros" Condition=" '$(CIBuild)' != 'true' ">
<DefineConstants>$(DefineConstants);CIBuild=false</DefineConstants>
</PropertyGroup>
<PropertyGroup>
<!-- We do not support debug installer builds -->
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
@@ -104,6 +113,7 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
<Compile Include="AdvancedPaste.wxs" />
<Compile Include="Awake.wxs" />
<Compile Include="BaseApplications.wxs" />
<Compile Include="CmdPal.wxs" />
<Compile Include="ColorPicker.wxs" />
<Compile Include="EnvironmentVariables.wxs" />
<Compile Include="FileExplorerPreview.wxs" />
@@ -188,4 +198,4 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
</ItemGroup>
</Target>
<Target Name="Restore" />
</Project>
</Project>

View File

@@ -79,6 +79,10 @@
<ComponentGroupRef Id="ToolComponentGroup" />
<ComponentGroupRef Id="MonacoSRCHeatGenerated" />
<ComponentGroupRef Id="WorkspacesComponentGroup" />
<?if $(var.CIBuild) = "true" ?>
<ComponentGroupRef Id="CmdPalComponentGroup" />
<?endif?>
</Feature>
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLFOLDER]" After="CostFinalize" />
@@ -135,6 +139,7 @@
<InstallExecuteSequence>
<Custom Action="DetectPrevInstallPath" After="AppSearch" />
<Custom Action="SetLaunchPowerToysParam" Before="LaunchPowerToys" />
<Custom Action="SetInstallCmdPalPackageParam" Before="InstallCmdPalPackage" />
<Custom Action="SetUninstallCommandNotFoundParam" Before="UninstallCommandNotFound" />
<Custom Action="SetUpgradeCommandNotFoundParam" Before="UpgradeCommandNotFound" />
<Custom Action="SetApplyModulesRegistryChangeSetsParam" Before="ApplyModulesRegistryChangeSets" />
@@ -150,6 +155,9 @@
<Custom Action="ApplyModulesRegistryChangeSets" After="InstallFiles">
NOT Installed
</Custom>
<Custom Action="InstallCmdPalPackage" After="InstallFiles">
NOT Installed
</Custom>
<Custom Action="WixCloseApplications" Before="RemoveFiles" />
<Custom Action="RemovePowerToysSchTasks" After="RemoveFiles" />
<!-- TODO: Use to activate embedded MSIX -->
@@ -171,6 +179,9 @@
<Custom Action="UnRegisterContextMenuPackages" Before="RemoveFiles">
Installed AND (REMOVE="ALL")
</Custom>
<Custom Action="UnRegisterCmdPalPackage" Before="RemoveFiles">
Installed AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
</Custom>
<Custom Action="UnsetAdvancedPasteAPIKey" Before="RemoveFiles">
Installed AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
</Custom>
@@ -204,6 +215,10 @@
Property="LaunchPowerToys"
Value="[INSTALLFOLDER]" />
<CustomAction Id="SetInstallCmdPalPackageParam"
Property="InstallCmdPalPackage"
Value="[INSTALLFOLDER]" />
<CustomAction
Id="LaunchPowerToys"
Return="ignore"
@@ -427,6 +442,14 @@
DllEntry="UnRegisterContextMenuPackagesCA"
/>
<CustomAction Id="UnRegisterCmdPalPackage"
Return="ignore"
Impersonate="yes"
Execute="deferred"
BinaryKey="PTCustomActions"
DllEntry="UnRegisterCmdPalPackageCA"
/>
<CustomAction Id="CheckGPO"
Return="check"
Impersonate="yes"
@@ -434,6 +457,14 @@
DllEntry="CheckGPOCA"
/>
<CustomAction Id="InstallCmdPalPackage"
Return="ignore"
Impersonate="yes"
Execute="deferred"
BinaryKey="PTCustomActions"
DllEntry="InstallCmdPalPackageCA"
/>
<!-- Close 'PowerToys.exe' before uninstall-->
<Property Id="MSIRESTARTMANAGERCONTROL" Value="DisableShutdown" />
<Property Id="MSIFASTINSTALL" Value="DisableShutdown" />

View File

@@ -11,6 +11,7 @@
#include "../../src/common/updating/installer.h"
#include "../../src/common/version/version.h"
#include "../../src/common/Telemetry/EtwTrace/EtwTrace.h"
#include "../../src/common/utils/package.h"
#include "../../src/common/utils/clean_video_conference.h"
#include <winrt/Windows.ApplicationModel.h>
@@ -35,13 +36,13 @@ TRACELOGGING_DEFINE_PROVIDER(
TraceLoggingOptionProjectTelemetry());
const DWORD USERNAME_DOMAIN_LEN = DNLEN + UNLEN + 2; // Domain Name + '\' + User Name + '\0'
const DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0'
const DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0'
static const wchar_t* POWERTOYS_EXE_COMPONENT = L"{A2C66D91-3485-4D00-B04D-91844E6B345B}";
static const wchar_t* POWERTOYS_UPGRADE_CODE = L"{42B84BF7-5FBF-473B-9C8B-049DC16F7708}";
static const wchar_t *POWERTOYS_EXE_COMPONENT = L"{A2C66D91-3485-4D00-B04D-91844E6B345B}";
static const wchar_t *POWERTOYS_UPGRADE_CODE = L"{42B84BF7-5FBF-473B-9C8B-049DC16F7708}";
constexpr inline const wchar_t* DataDiagnosticsRegKey = L"Software\\Classes\\PowerToys";
constexpr inline const wchar_t* DataDiagnosticsRegValueName = L"AllowDataDiagnostics";
constexpr inline const wchar_t *DataDiagnosticsRegKey = L"Software\\Classes\\PowerToys";
constexpr inline const wchar_t *DataDiagnosticsRegValueName = L"AllowDataDiagnostics";
#define TraceLoggingWriteWrapper(provider, eventName, ...) \
if (isDataDiagnosticEnabled()) \
@@ -52,16 +53,16 @@ constexpr inline const wchar_t* DataDiagnosticsRegValueName = L"AllowDataDiagnos
trace.UpdateState(false); \
}
static Shared::Trace::ETWTrace trace{ L"PowerToys_Installer" };
static Shared::Trace::ETWTrace trace{L"PowerToys_Installer"};
inline bool isDataDiagnosticEnabled()
{
HKEY key{};
if (RegOpenKeyExW(HKEY_CURRENT_USER,
DataDiagnosticsRegKey,
0,
KEY_READ,
&key) != ERROR_SUCCESS)
DataDiagnosticsRegKey,
0,
KEY_READ,
&key) != ERROR_SUCCESS)
{
return false;
}
@@ -86,8 +87,7 @@ inline bool isDataDiagnosticEnabled()
return isDataDiagnosticsEnabled == 1;
}
HRESULT getInstallFolder(MSIHANDLE hInstall, std::wstring& installationDir)
HRESULT getInstallFolder(MSIHANDLE hInstall, std::wstring &installationDir)
{
DWORD len = 0;
wchar_t _[1];
@@ -116,13 +116,13 @@ BOOL IsLocalSystem()
// open process token
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_QUERY,
&hToken))
TOKEN_QUERY,
&hToken))
return FALSE;
// retrieve user SID
if (!GetTokenInformation(hToken, TokenUser, pTokenUser,
sizeof(bTokenUser), &cbTokenUser))
sizeof(bTokenUser), &cbTokenUser))
{
CloseHandle(hToken);
return FALSE;
@@ -132,7 +132,7 @@ BOOL IsLocalSystem()
// allocate LocalSystem well-known SID
if (!AllocateAndInitializeSid(&siaNT, 1, SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0, &pSystemSid))
0, 0, 0, 0, 0, 0, 0, &pSystemSid))
return FALSE;
// compare the user SID from the token with the LocalSystem SID
@@ -194,7 +194,7 @@ static std::filesystem::path GetUserPowerShellModulesPath()
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &myDocumentsBlockPtr)))
{
const std::wstring myDocuments{ myDocumentsBlockPtr };
const std::wstring myDocuments{myDocumentsBlockPtr};
CoTaskMemFree(myDocumentsBlockPtr);
return std::filesystem::path(myDocuments) / "PowerShell" / "Modules";
}
@@ -227,10 +227,12 @@ UINT __stdcall LaunchPowerToysCA(MSIHANDLE hInstall)
BOOL isSystemUser = IsLocalSystem();
if (isSystemUser) {
if (isSystemUser)
{
auto action = [&commandLine](HANDLE userToken) {
STARTUPINFO startupInfo{ .cb = sizeof(STARTUPINFO), .wShowWindow = SW_SHOWNORMAL };
auto action = [&commandLine](HANDLE userToken)
{
STARTUPINFO startupInfo{.cb = sizeof(STARTUPINFO), .wShowWindow = SW_SHOWNORMAL};
PROCESS_INFORMATION processInformation;
PVOID lpEnvironment = NULL;
@@ -269,7 +271,7 @@ UINT __stdcall LaunchPowerToysCA(MSIHANDLE hInstall)
}
else
{
STARTUPINFO startupInfo{ .cb = sizeof(STARTUPINFO), .wShowWindow = SW_SHOWNORMAL };
STARTUPINFO startupInfo{.cb = sizeof(STARTUPINFO), .wShowWindow = SW_SHOWNORMAL};
PROCESS_INFORMATION processInformation;
@@ -313,7 +315,7 @@ UINT __stdcall CheckGPOCA(MSIHANDLE hInstall)
LPWSTR currentScope = nullptr;
hr = WcaGetProperty(L"InstallScope", &currentScope);
if (std::wstring{ currentScope } == L"perUser")
if (std::wstring{currentScope} == L"perUser")
{
if (powertoys_gpo::getDisablePerUserInstallationValue() == powertoys_gpo::gpo_rule_configured_enabled)
{
@@ -354,7 +356,7 @@ UINT __stdcall ApplyModulesRegistryChangeSetsCA(MSIHANDLE hInstall)
hr = getInstallFolder(hInstall, installationFolder);
ExitOnFailure(hr, "Failed to get installFolder.");
for (const auto& changeSet : getAllOnByDefaultModulesChangeSets(installationFolder))
for (const auto &changeSet : getAllOnByDefaultModulesChangeSets(installationFolder))
{
if (!changeSet.apply())
{
@@ -382,7 +384,7 @@ UINT __stdcall UnApplyModulesRegistryChangeSetsCA(MSIHANDLE hInstall)
ExitOnFailure(hr, "Failed to initialize");
hr = getInstallFolder(hInstall, installationFolder);
ExitOnFailure(hr, "Failed to get installFolder.");
for (const auto& changeSet : getAllModulesChangeSets(installationFolder))
for (const auto &changeSet : getAllModulesChangeSets(installationFolder))
{
changeSet.unApply();
}
@@ -396,8 +398,8 @@ LExit:
return WcaFinalize(er);
}
const wchar_t* DSC_CONFIGURE_PSD1_NAME = L"Microsoft.PowerToys.Configure.psd1";
const wchar_t* DSC_CONFIGURE_PSM1_NAME = L"Microsoft.PowerToys.Configure.psm1";
const wchar_t *DSC_CONFIGURE_PSD1_NAME = L"Microsoft.PowerToys.Configure.psd1";
const wchar_t *DSC_CONFIGURE_PSM1_NAME = L"Microsoft.PowerToys.Configure.psm1";
UINT __stdcall InstallDSCModuleCA(MSIHANDLE hInstall)
{
@@ -429,7 +431,7 @@ UINT __stdcall InstallDSCModuleCA(MSIHANDLE hInstall)
ExitOnFailure(hr, "Unable to create Powershell modules folder");
}
for (const auto* filename : { DSC_CONFIGURE_PSD1_NAME, DSC_CONFIGURE_PSM1_NAME })
for (const auto *filename : {DSC_CONFIGURE_PSD1_NAME, DSC_CONFIGURE_PSM1_NAME})
{
fs::copy_file(fs::path(installationFolder) / "DSCModules" / filename, modulesPath / filename, fs::copy_options::overwrite_existing, errorCode);
@@ -477,7 +479,7 @@ UINT __stdcall UninstallDSCModuleCA(MSIHANDLE hInstall)
std::error_code errorCode;
for (const auto* filename : { DSC_CONFIGURE_PSD1_NAME, DSC_CONFIGURE_PSM1_NAME })
for (const auto *filename : {DSC_CONFIGURE_PSD1_NAME, DSC_CONFIGURE_PSM1_NAME})
{
fs::remove(versionedModulePath / filename, errorCode);
@@ -488,7 +490,7 @@ UINT __stdcall UninstallDSCModuleCA(MSIHANDLE hInstall)
}
}
for (const auto* modulePath : { &versionedModulePath, &powerToysModulePath })
for (const auto *modulePath : {&versionedModulePath, &powerToysModulePath})
{
fs::remove(*modulePath, errorCode);
@@ -535,7 +537,7 @@ UINT __stdcall InstallEmbeddedMSIXCA(MSIHANDLE hInstall)
using namespace winrt::Windows::Management::Deployment;
using namespace winrt::Windows::Foundation;
Uri msix_uri{ msix_path.wstring() };
Uri msix_uri{msix_path.wstring()};
PackageManager pm;
auto result = pm.AddPackageAsync(msix_uri, nullptr, DeploymentOptions::None).get();
if (!result)
@@ -569,7 +571,7 @@ UINT __stdcall UninstallEmbeddedMSIXCA(MSIHANDLE hInstall)
hr = WcaInitialize(hInstall, "UninstallEmbeddedMSIXCA");
ExitOnFailure(hr, "Failed to initialize");
for (const auto& p : pm.FindPackagesForUser({}, package_name, publisher))
for (const auto &p : pm.FindPackagesForUser({}, package_name, publisher))
{
auto result = pm.RemovePackageAsync(p.Id().FullName()).get();
if (result)
@@ -683,7 +685,6 @@ UINT __stdcall UninstallCommandNotFoundModuleCA(MSIHANDLE hInstall)
command += "-NoProfile -NonInteractive -NoLogo -WindowStyle Hidden -ExecutionPolicy Unrestricted -File \"" + winrt::to_string(installationFolder) + "\\WinUI3Apps\\Assets\\Settings\\Scripts\\DisableModule.ps1" + "\"";
#endif
system(command.c_str());
LExit:
@@ -738,10 +739,10 @@ UINT __stdcall RemoveScheduledTasksCA(MSIHANDLE hInstall)
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
ITaskService* pService = nullptr;
ITaskFolder* pTaskFolder = nullptr;
IRegisteredTaskCollection* pTaskCollection = nullptr;
ITaskFolder* pRootFolder = nullptr;
ITaskService *pService = nullptr;
ITaskFolder *pTaskFolder = nullptr;
IRegisteredTaskCollection *pTaskCollection = nullptr;
ITaskFolder *pRootFolder = nullptr;
LONG numTasks = 0;
hr = WcaInitialize(hInstall, "RemoveScheduledTasksCA");
@@ -754,10 +755,10 @@ UINT __stdcall RemoveScheduledTasksCA(MSIHANDLE hInstall)
// ------------------------------------------------------
// Create an instance of the Task Service.
hr = CoCreateInstance(CLSID_TaskScheduler,
nullptr,
CLSCTX_INPROC_SERVER,
IID_ITaskService,
reinterpret_cast<void**>(&pService));
nullptr,
CLSCTX_INPROC_SERVER,
IID_ITaskService,
reinterpret_cast<void **>(&pService));
ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr);
// Connect to the task service.
@@ -785,7 +786,7 @@ UINT __stdcall RemoveScheduledTasksCA(MSIHANDLE hInstall)
{
// Delete all the tasks found.
// If some tasks can't be deleted, the folder won't be deleted later and the user will still be notified.
IRegisteredTask* pRegisteredTask = nullptr;
IRegisteredTask *pRegisteredTask = nullptr;
hr = pTaskCollection->get_Item(_variant_t(i + 1), &pRegisteredTask);
if (SUCCEEDED(hr))
{
@@ -861,8 +862,7 @@ UINT __stdcall TelemetryLogInstallSuccessCA(MSIHANDLE hInstall)
TraceLoggingWideString(get_product_version().c_str(), "Version"),
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)
);
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
@@ -1028,7 +1028,7 @@ UINT __stdcall DetectPrevInstallPathCA(MSIHANDLE hInstall)
try
{
if (auto install_path = GetMsiPackageInstalledPath(std::wstring{ currentScope } == L"perUser"))
if (auto install_path = GetMsiPackageInstalledPath(std::wstring{currentScope} == L"perUser"))
{
MsiSetPropertyW(hInstall, L"PREVIOUSINSTALLFOLDER", install_path->data());
}
@@ -1040,6 +1040,82 @@ UINT __stdcall DetectPrevInstallPathCA(MSIHANDLE hInstall)
return WcaFinalize(er);
}
UINT __stdcall InstallCmdPalPackageCA(MSIHANDLE hInstall)
{
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Management::Deployment;
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
std::wstring installationFolder;
hr = WcaInitialize(hInstall, "InstallCmdPalPackage");
hr = getInstallFolder(hInstall, installationFolder);
try
{
auto msix = package::FindMsixFile(installationFolder + L"\\WinUI3Apps\\CmdPal\\", false);
auto dependencies = package::FindMsixFile(installationFolder + L"\\WinUI3Apps\\CmdPal\\Dependencies\\", true);
if (!msix.empty())
{
auto msixPath = msix[0];
if (!package::RegisterPackage(msixPath, dependencies))
{
Logger::error(L"Failed to install CmdPal package");
er = ERROR_INSTALL_FAILURE;
}
}
}
catch (std::exception &e)
{
std::string errorMessage{"Exception thrown while trying to install CmdPal package: "};
errorMessage += e.what();
Logger::error(errorMessage);
er = ERROR_INSTALL_FAILURE;
}
er = er == ERROR_SUCCESS ? (SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE) : er;
return WcaFinalize(er);
}
UINT __stdcall UnRegisterCmdPalPackageCA(MSIHANDLE hInstall)
{
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Management::Deployment;
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
hr = WcaInitialize(hInstall, "UnRegisterCmdPalPackageCA");
try
{
// Packages to unregister
std::wstring packageToRemoveDisplayName {L"Microsoft.CommandPalette"};
if (!package::UnRegisterPackage(packageToRemoveDisplayName))
{
Logger::error(L"Failed to unregister package: " + packageToRemoveDisplayName);
er = ERROR_INSTALL_FAILURE;
}
}
catch (std::exception &e)
{
std::string errorMessage{"Exception thrown while trying to unregister the CmdPal package: "};
errorMessage += e.what();
Logger::error(errorMessage);
er = ERROR_INSTALL_FAILURE;
}
er = er == ERROR_SUCCESS ? (SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE) : er;
return WcaFinalize(er);
}
UINT __stdcall UnRegisterContextMenuPackagesCA(MSIHANDLE hInstall)
{
using namespace winrt::Windows::Foundation;
@@ -1053,54 +1129,20 @@ UINT __stdcall UnRegisterContextMenuPackagesCA(MSIHANDLE hInstall)
try
{
// Packages to unregister
const std::vector<std::wstring> packagesToRemoveDisplayName{ { L"PowerRenameContextMenu" }, { L"ImageResizerContextMenu" }, { L"FileLocksmithContextMenu" }, { L"NewPlusContextMenu" } };
const std::vector<std::wstring> packagesToRemoveDisplayName{{L"PowerRenameContextMenu"}, {L"ImageResizerContextMenu"}, {L"FileLocksmithContextMenu"}, {L"NewPlusContextMenu"}};
PackageManager packageManager;
for (auto const& package : packageManager.FindPackages())
for (auto const &package : packagesToRemoveDisplayName)
{
const auto& packageFullName = std::wstring{ package.Id().FullName() };
for (const auto& packageToRemove : packagesToRemoveDisplayName)
if (!package::UnRegisterPackage(package))
{
if (packageFullName.contains(packageToRemove))
{
auto deploymentOperation{ packageManager.RemovePackageAsync(packageFullName) };
deploymentOperation.get();
// Check the status of the operation
if (deploymentOperation.Status() == AsyncStatus::Error)
{
auto deploymentResult{ deploymentOperation.GetResults() };
auto errorCode = deploymentOperation.ErrorCode();
auto errorText = deploymentResult.ErrorText();
Logger::error(L"Unregister {} package failed. ErrorCode: {}, ErrorText: {}", packageFullName, std::to_wstring(errorCode), errorText);
er = ERROR_INSTALL_FAILURE;
}
else if (deploymentOperation.Status() == AsyncStatus::Canceled)
{
Logger::error(L"Unregister {} package canceled.", packageFullName);
er = ERROR_INSTALL_FAILURE;
}
else if (deploymentOperation.Status() == AsyncStatus::Completed)
{
Logger::info(L"Unregister {} package completed.", packageFullName);
}
else
{
Logger::debug(L"Unregister {} package started.", packageFullName);
}
}
Logger::error(L"Failed to unregister package: " + package);
er = ERROR_INSTALL_FAILURE;
}
}
}
catch (std::exception& e)
catch (std::exception &e)
{
std::string errorMessage{ "Exception thrown while trying to unregister sparse packages: " };
std::string errorMessage{"Exception thrown while trying to unregister sparse packages: "};
errorMessage += e.what();
Logger::error(errorMessage);
@@ -1128,7 +1170,7 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
}
processes.resize(bytes / sizeof(processes[0]));
std::array<std::wstring_view, 38> processesToTerminate = {
std::array<std::wstring_view, 39> processesToTerminate = {
L"PowerToys.PowerLauncher.exe",
L"PowerToys.Settings.exe",
L"PowerToys.AdvancedPaste.exe",
@@ -1165,6 +1207,7 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
L"PowerToys.WorkspacesLauncherUI.exe",
L"PowerToys.WorkspacesEditor.exe",
L"PowerToys.WorkspacesWindowArranger.exe",
L"Microsoft.CmdPal.UI.exe",
L"PowerToys.ZoomIt.exe",
L"PowerToys.exe",
};
@@ -1177,7 +1220,7 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
}
wchar_t processName[MAX_PATH] = L"<unknown>";
HANDLE hProcess{ OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE, FALSE, procID) };
HANDLE hProcess{OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE, FALSE, procID)};
if (!hProcess)
{
continue;
@@ -1197,8 +1240,9 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
if (processName == processToTerminate)
{
const DWORD timeout = 500;
auto windowEnumerator = [](HWND hwnd, LPARAM procIDPtr) -> BOOL {
auto targetProcID = *reinterpret_cast<const DWORD*>(procIDPtr);
auto windowEnumerator = [](HWND hwnd, LPARAM procIDPtr) -> BOOL
{
auto targetProcID = *reinterpret_cast<const DWORD *>(procIDPtr);
DWORD windowProcID = 0;
GetWindowThreadProcessId(hwnd, &windowProcID);
if (windowProcID == targetProcID)
@@ -1224,15 +1268,15 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
void initSystemLogger()
{
static std::once_flag initLoggerFlag;
std::call_once(initLoggerFlag, []() {
WCHAR temp_path[MAX_PATH];
auto ret = GetTempPath(MAX_PATH, temp_path);
std::call_once(initLoggerFlag, []()
{
WCHAR temp_path[MAX_PATH];
auto ret = GetTempPath(MAX_PATH, temp_path);
if (ret)
{
Logger::init("PowerToysMSI", std::wstring{ temp_path } + L"\\PowerToysMSIInstaller", L"");
}
});
if (ret)
{
Logger::init("PowerToysMSI", std::wstring{ temp_path } + L"\\PowerToysMSIInstaller", L"");
} });
}
// DllMain - Initialize and cleanup WiX custom action utils.

View File

@@ -18,7 +18,9 @@ EXPORTS
TerminateProcessesCA
InstallEmbeddedMSIXCA
InstallDSCModuleCA
InstallCmdPalPackageCA
UnApplyModulesRegistryChangeSetsCA
UnRegisterCmdPalPackageCA
UnRegisterContextMenuPackagesCA
UninstallEmbeddedMSIXCA
UninstallDSCModuleCA

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="15.0" DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
<Import Project="..\wix.props" Condition="Exists('..\wix.props')" />
<PropertyGroup Label="Globals">
@@ -54,6 +55,7 @@
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\AdvancedPaste.wxs"" ""$(ProjectDir)..\PowerToysSetup\AdvancedPaste.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\Awake.wxs"" ""$(ProjectDir)..\PowerToysSetup\Awake.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\BaseApplications.wxs"" ""$(ProjectDir)..\PowerToysSetup\BaseApplications.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\CmdPal.wxs"" ""$(ProjectDir)..\PowerToysSetup\CmdPal.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\ColorPicker.wxs"" ""$(ProjectDir)..\PowerToysSetup\ColorPicker.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\Core.wxs"" ""$(ProjectDir)..\PowerToysSetup\Core.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\EnvironmentVariables.wxs"" ""$(ProjectDir)..\PowerToysSetup\EnvironmentVariables.wxs.bk""""

10
src/CmdPalVersion.props Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CmdPalVersion>0.0.1</CmdPalVersion>
<DevEnvironment>Local</DevEnvironment>
<!-- Forcing for every DLL on by default -->
<ChecksumAlgorithm>SHA256</ChecksumAlgorithm>
</PropertyGroup>
</Project>

View File

@@ -5,5 +5,8 @@
<IsAotCompatible>true</IsAotCompatible>
<CsWinRTAotOptimizerEnabled>true</CsWinRTAotOptimizerEnabled>
<CsWinRTAotWarningLevel>2</CsWinRTAotWarningLevel>
<!-- Suppress DynamicallyAccessedMemberTypes.PublicParameterlessConstructor in fallback code path of Windows SDK projection -->
<WarningsNotAsErrors>IL2081</WarningsNotAsErrors>
</PropertyGroup>
</Project>

View File

@@ -2,7 +2,7 @@
<!-- Some items may be set in Directory.Build.props in root -->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WindowsSdkPackageVersion>10.0.22621.48</WindowsSdkPackageVersion>
<WindowsSdkPackageVersion>10.0.22621.57</WindowsSdkPackageVersion>
<TargetFramework>net9.0-windows10.0.22621.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
@@ -14,7 +14,7 @@
<WarningLevel>4</WarningLevel>
<NoWarn></NoWarn>
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
<WarningsNotAsErrors>CA1720;CA1859;CA2263;CA2022</WarningsNotAsErrors>
<WarningsNotAsErrors>CA1720;CA1859;CA2263;CA2022;MVVMTK0045;MVVMTK0049</WarningsNotAsErrors>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">

View File

@@ -12,10 +12,10 @@ using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:PrefixLocalCallsWithThis", Justification = "We follow the C# Core Coding Style which avoids using `this` unless absolutely necessary.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:ElementsMustAppearInTheCorrectOrder", Justification = "It is not a priority and have hight impact in code changes.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:ElementsMustBeOrderedByAccess", Justification = "It is not a priority and have hight impact in code changes.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1203:ConstantsMustAppearBeforeFields", Justification = "It is not a priority and have hight impact in code changes.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1204:StaticElementsMustAppearBeforeInstanceElements", Justification = "It is not a priority and have hight impact in code changes.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:ElementsMustAppearInTheCorrectOrder", Justification = "It is not a priority and has high impact in code changes.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:ElementsMustBeOrderedByAccess", Justification = "It is not a priority and has high impact in code changes.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1203:ConstantsMustAppearBeforeFields", Justification = "It is not a priority and has high impact in code changes.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1204:StaticElementsMustAppearBeforeInstanceElements", Justification = "It is not a priority and has high impact in code changes.")]
[assembly: SuppressMessage("StyleCop.CSharp.NamingRules", "SA1309:FieldNamesMustNotBeginWithUnderscore", Justification = "We follow the C# Core Coding Style which uses underscores as prefixes rather than using `this.`.")]
@@ -62,3 +62,9 @@ using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "<Dotnet port with style preservation>", Scope = "namespaceanddescendants", Target = "MouseWithoutBorders")]
[assembly: SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "<Dotnet port with style preservation>", Scope = "namespaceanddescendants", Target = "MouseWithoutBorders")]
[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1649:File name should match first type name", Justification = "<Dotnet port with style preservation>", Scope = "namespaceanddescendants", Target = "MouseWithoutBorders")]
// AOT
[assembly: SuppressMessage("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "MVVMTK0045:Using [ObservableProperty] on fields is not AOT compatible for WinRT", Justification = "Updated MVVM toolkit package introduced this.", Scope = "namespaceanddescendants", Target = "HostsUILib")]
[assembly: SuppressMessage("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "MVVMTK0045:Using [ObservableProperty] on fields is not AOT compatible for WinRT", Justification = "Updated MVVM toolkit package introduced this.", Scope = "namespaceanddescendants", Target = "Peek.UI")]
[assembly: SuppressMessage("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "MVVMTK0045:Using [ObservableProperty] on fields is not AOT compatible for WinRT", Justification = "Updated MVVM toolkit package introduced this.", Scope = "namespaceanddescendants", Target = "Peek.UI.Views")]
[assembly: SuppressMessage("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "MVVMTK0049:Using [INotifyPropertyChanged] is not AOT compatible for WinRT", Justification = "Updated MVVM toolkit package introduced this.", Scope = "type", Target = "~T:Peek.UI.Views.TitleBar")]

View File

@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\Common.Dotnet.AotCompatibility.props" />
<PropertyGroup>
<UseWPF>true</UseWPF>

View File

@@ -31,6 +31,7 @@ namespace Common.UI
Dashboard,
AdvancedPaste,
Workspaces,
CmdPal,
ZoomIt,
}
@@ -78,6 +79,8 @@ namespace Common.UI
return "AdvancedPaste";
case SettingsWindow.Workspaces:
return "Workspaces";
case SettingsWindow.CmdPal:
return "CmdPal";
case SettingsWindow.ZoomIt:
return "ZoomIt";
default:
@@ -91,20 +94,20 @@ namespace Common.UI
{
try
{
var assemblyPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
var fullPath = new DirectoryInfo(assemblyPath).FullName;
var directoryPath = System.AppContext.BaseDirectory;
if (mainExecutableIsOnTheParentFolder)
{
// Need to go into parent folder for PowerToys.exe. Likely a WinUI3 App SDK application.
fullPath = fullPath + "\\..\\PowerToys.exe";
directoryPath = Path.Combine(directoryPath, "..");
directoryPath = Path.Combine(directoryPath, "PowerToys.exe");
}
else
{
// PowerToys.exe is in the same path as the application.
fullPath = fullPath + "\\PowerToys.exe";
directoryPath = Path.Combine(directoryPath, "PowerToys.exe");
}
Process.Start(new ProcessStartInfo(fullPath) { Arguments = "--open-settings=" + SettingsWindowNameToString(window) });
Process.Start(new ProcessStartInfo(directoryPath) { Arguments = "--open-settings=" + SettingsWindowNameToString(window) });
}
catch
{

View File

@@ -11,7 +11,7 @@ using Microsoft.Win32;
namespace Common.UI
{
public class ThemeManager : IDisposable
public partial class ThemeManager : IDisposable
{
private readonly Application _app;
private const string LightTheme = "Light.Accent1";

View File

@@ -16,6 +16,10 @@ namespace winrt::PowerToys::GPOWrapper::implementation
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredCmdNotFoundEnabledValue());
}
GpoRuleConfigured GPOWrapper::GetConfiguredCmdPalEnabledValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredCmdPalEnabledValue());
}
GpoRuleConfigured GPOWrapper::GetConfiguredColorPickerEnabledValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredColorPickerEnabledValue());
@@ -232,6 +236,10 @@ namespace winrt::PowerToys::GPOWrapper::implementation
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowDataDiagnosticsValue());
}
GpoRuleConfigured GPOWrapper::GetConfiguredNewPlusReplaceVariablesValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredNewPlusReplaceVariablesValue());
}
GpoRuleConfigured GPOWrapper::GetConfiguredRunAtStartupValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredRunAtStartupValue());

View File

@@ -10,6 +10,7 @@ namespace winrt::PowerToys::GPOWrapper::implementation
static GpoRuleConfigured GetConfiguredAlwaysOnTopEnabledValue();
static GpoRuleConfigured GetConfiguredAwakeEnabledValue();
static GpoRuleConfigured GetConfiguredCmdNotFoundEnabledValue();
static GpoRuleConfigured GetConfiguredCmdPalEnabledValue();
static GpoRuleConfigured GetConfiguredColorPickerEnabledValue();
static GpoRuleConfigured GetConfiguredCropAndLockEnabledValue();
static GpoRuleConfigured GetConfiguredFancyZonesEnabledValue();
@@ -64,6 +65,7 @@ namespace winrt::PowerToys::GPOWrapper::implementation
static GpoRuleConfigured GetConfiguredNewPlusHideTemplateFilenameExtensionValue();
static GpoRuleConfigured GetAllowDataDiagnosticsValue();
static GpoRuleConfigured GetConfiguredRunAtStartupValue();
static GpoRuleConfigured GetConfiguredNewPlusReplaceVariablesValue();
};
}

View File

@@ -14,6 +14,7 @@ namespace PowerToys
static GpoRuleConfigured GetConfiguredAlwaysOnTopEnabledValue();
static GpoRuleConfigured GetConfiguredAwakeEnabledValue();
static GpoRuleConfigured GetConfiguredCmdNotFoundEnabledValue();
static GpoRuleConfigured GetConfiguredCmdPalEnabledValue();
static GpoRuleConfigured GetConfiguredColorPickerEnabledValue();
static GpoRuleConfigured GetConfiguredCropAndLockEnabledValue();
static GpoRuleConfigured GetConfiguredFancyZonesEnabledValue();
@@ -68,6 +69,7 @@ namespace PowerToys
static GpoRuleConfigured GetConfiguredNewPlusHideTemplateFilenameExtensionValue();
static GpoRuleConfigured GetAllowDataDiagnosticsValue();
static GpoRuleConfigured GetConfiguredRunAtStartupValue();
static GpoRuleConfigured GetConfiguredNewPlusReplaceVariablesValue();
}
}
}

View File

@@ -6,6 +6,7 @@ using System;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
using ManagedCommon.Serialization;
namespace ManagedCommon
{
@@ -35,7 +36,7 @@ namespace ManagedCommon
inputStream.Close();
reader.Dispose();
return JsonSerializer.Deserialize<OutGoingLanguageSettings>(data).LanguageTag;
return JsonSerializer.Deserialize<OutGoingLanguageSettings>(data, SourceGenerationContext.Default.OutGoingLanguageSettings).LanguageTag;
}
catch (Exception)
{

View File

@@ -15,15 +15,23 @@ namespace ManagedCommon
{
public static class Logger
{
private static readonly Assembly Assembly = Assembly.GetExecutingAssembly();
private static readonly string Version = FileVersionInfo.GetVersionInfo(Assembly.Location).ProductVersion;
private static readonly string Error = "Error";
private static readonly string Warning = "Warning";
private static readonly string Info = "Info";
private static readonly string Debug = "Debug";
private static readonly string TraceFlag = "Trace";
private static readonly Assembly Assembly = Assembly.GetExecutingAssembly();
/*
* Please pay more attention!
* If you want to publish it with Native AOT enabled (or publish as a single file).
* You need to find another way to remove Assembly.Location usage.
*/
#pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file
private static readonly string Version = FileVersionInfo.GetVersionInfo(Assembly.Location).ProductVersion;
#pragma warning restore IL3000 // Avoid accessing Assembly file path when publishing as a single file
/// <summary>
/// Initializes the logger and sets the path for logging.
/// </summary>
@@ -53,18 +61,16 @@ namespace ManagedCommon
Trace.AutoFlush = true;
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void LogError(string message)
public static void LogError(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
Log(message, Error);
Log(message, Error, memberName, sourceFilePath, sourceLineNumber);
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void LogError(string message, Exception ex)
public static void LogError(string message, Exception ex, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
if (ex == null)
{
Log(message, Error);
Log(message, Error, memberName, sourceFilePath, sourceLineNumber);
}
else
{
@@ -83,38 +89,33 @@ namespace ManagedCommon
"Stack trace: " + Environment.NewLine +
ex.StackTrace;
Log(exMessage, Error);
Log(exMessage, Error, memberName, sourceFilePath, sourceLineNumber);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void LogWarning(string message)
public static void LogWarning(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
Log(message, Warning);
Log(message, Warning, memberName, sourceFilePath, sourceLineNumber);
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void LogInfo(string message)
public static void LogInfo(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
Log(message, Info);
Log(message, Info, memberName, sourceFilePath, sourceLineNumber);
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void LogDebug(string message)
public static void LogDebug(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
Log(message, Debug);
Log(message, Debug, memberName, sourceFilePath, sourceLineNumber);
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void LogTrace()
public static void LogTrace([System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
Log(string.Empty, TraceFlag);
Log(string.Empty, TraceFlag, memberName, sourceFilePath, sourceLineNumber);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void Log(string message, string type)
private static void Log(string message, string type, string memberName, string sourceFilePath, int sourceLineNumber)
{
Trace.WriteLine("[" + DateTime.Now.TimeOfDay + "] [" + type + "] " + GetCallerInfo());
Trace.WriteLine("[" + DateTime.Now.TimeOfDay + "] [" + type + "] " + GetCallerInfo(memberName, sourceFilePath, sourceLineNumber));
Trace.Indent();
if (message != string.Empty)
{
@@ -124,49 +125,27 @@ namespace ManagedCommon
Trace.Unindent();
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static string GetCallerInfo()
private static string GetCallerInfo(string memberName, string sourceFilePath, int sourceLineNumber)
{
StackTrace stackTrace = new();
var callerMethod = GetCallerMethod(stackTrace);
return $"{callerMethod?.DeclaringType?.Name}::{callerMethod.Name}";
}
private static MethodBase GetCallerMethod(StackTrace stackTrace)
{
const int topFrame = 3;
var topMethod = stackTrace.GetFrame(topFrame)?.GetMethod();
string callerFileName = "Unknown";
try
{
if (topMethod?.Name == nameof(IAsyncStateMachine.MoveNext) && typeof(IAsyncStateMachine).IsAssignableFrom(topMethod?.DeclaringType))
string fileName = Path.GetFileName(sourceFilePath);
if (!string.IsNullOrEmpty(fileName))
{
// Async method; return actual method as determined by heuristic:
// "Nearest method on stack to async state-machine's MoveNext() in same namespace but in a different type".
// There are tighter ways of determining the actual method, but this is good enough and probably faster.
for (int deepFrame = topFrame + 1; deepFrame < stackTrace.FrameCount; deepFrame++)
{
var deepMethod = stackTrace.GetFrame(deepFrame)?.GetMethod();
if (deepMethod?.DeclaringType != topMethod?.DeclaringType && deepMethod?.DeclaringType?.Namespace == topMethod?.DeclaringType?.Namespace)
{
return deepMethod;
}
}
callerFileName = fileName;
}
}
catch (Exception)
{
// Ignore exceptions in Release. The code above won't throw, but if it does, we don't want to crash the app.
callerFileName = "Unknown";
#if DEBUG
throw;
#endif
}
return topMethod;
return $"{callerFileName}::{memberName}::{sourceLineNumber}";
}
}
}

View File

@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\Common.Dotnet.AotCompatibility.props" />
<PropertyGroup>
<Description>PowerToys ManagedCommon</Description>

View File

@@ -10,6 +10,7 @@ namespace ManagedCommon
AlwaysOnTop,
Awake,
ColorPicker,
CmdPal,
CropAndLock,
EnvironmentVariables,
FancyZones,

View File

@@ -53,7 +53,7 @@ namespace ManagedCommon
internal static int Size
{
get { return Marshal.SizeOf(typeof(INPUT)); }
get { return Marshal.SizeOf<INPUT>(); }
}
}

View File

@@ -14,12 +14,11 @@ namespace ManagedCommon
{
public static class RunnerHelper
{
public static void WaitForPowerToysRunner(int powerToysPID, Action act)
public static void WaitForPowerToysRunner(int powerToysPID, Action act, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "")
{
var stackTrace = new StackTrace();
var assembly = Assembly.GetCallingAssembly().GetName();
var callingMethod = stackTrace.GetFrame(1).GetMethod().Name;
PowerToysTelemetry.Log.WriteEvent(new DebugEvent() { Message = $"[{assembly}][{callingMethod}]WaitForPowerToysRunner waiting for Event powerToysPID={powerToysPID}" });
PowerToysTelemetry.Log.WriteEvent(new DebugEvent() { Message = $"[{assembly}][{memberName}]WaitForPowerToysRunner waiting for Event powerToysPID={powerToysPID}" });
Task.Run(() =>
{
const uint INFINITE = 0xFFFFFFFF;
@@ -29,7 +28,7 @@ namespace ManagedCommon
IntPtr powerToysProcHandle = NativeMethods.OpenProcess(SYNCHRONIZE, false, powerToysPID);
if (NativeMethods.WaitForSingleObject(powerToysProcHandle, INFINITE) == WAIT_OBJECT_0)
{
PowerToysTelemetry.Log.WriteEvent(new DebugEvent() { Message = $"[{assembly}][{callingMethod}]WaitForPowerToysRunner Event Notified powerToysPID={powerToysPID}" });
PowerToysTelemetry.Log.WriteEvent(new DebugEvent() { Message = $"[{assembly}][{memberName}]WaitForPowerToysRunner Event Notified powerToysPID={powerToysPID}" });
act.Invoke();
}
});

View File

@@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.Json.Serialization;
using static ManagedCommon.LanguageHelper;
namespace ManagedCommon.Serialization;
[JsonSerializable(typeof(OutGoingLanguageSettings))]
internal sealed partial class SourceGenerationContext : JsonSerializerContext
{
}

View File

@@ -14,7 +14,7 @@ namespace ManagedCommon
/// <param name="sender">Sender ThemeListener</param>
public delegate void ThemeChangedEvent(ThemeListener sender);
public class ThemeListener : IDisposable
public partial class ThemeListener : IDisposable
{
/// <summary>
/// Gets the App Theme.

View File

@@ -2,13 +2,6 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Interactions;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium.Support.Events;
namespace Microsoft.PowerToys.UITest
{
/// <summary>
@@ -16,5 +9,14 @@ namespace Microsoft.PowerToys.UITest
/// </summary>
public class Button : Element
{
private static readonly string ExpectedControlType = "ControlType.Button";
/// <summary>
/// Initializes a new instance of the <see cref="Button"/> class.
/// </summary>
public Button()
{
this.TargetControlType = Button.ExpectedControlType;
}
}
}

View File

@@ -11,13 +11,42 @@ namespace Microsoft.PowerToys.UITest
/// </summary>
public class By
{
private readonly OpenQA.Selenium.By by;
private readonly OpenQA.Selenium.By? by;
private readonly bool isAccessibilityId;
private readonly string? accessibilityId;
private By(OpenQA.Selenium.By by)
{
isAccessibilityId = false;
this.by = by;
}
private By(string accessibilityId)
{
isAccessibilityId = true;
this.accessibilityId = accessibilityId;
}
public override string ToString()
{
// override ToString to return detailed debugging content provided by OpenQA.Selenium.By
return this.GetAccessibilityId();
}
public bool GetIsAccessibilityId() => this.isAccessibilityId;
public string GetAccessibilityId()
{
if (this.isAccessibilityId)
{
return this.accessibilityId!;
}
else
{
return this.by!.ToString();
}
}
/// <summary>
/// Creates a By object using the name attribute.
/// </summary>
@@ -25,6 +54,13 @@ namespace Microsoft.PowerToys.UITest
/// <returns>A By object.</returns>
public static By Name(string name) => new By(OpenQA.Selenium.By.Name(name));
/// <summary>
/// Creates a By object using the className attribute.
/// </summary>
/// <param name="className">The className attribute to search for.</param>
/// <returns>A By object.</returns>
public static By ClassName(string className) => new By(OpenQA.Selenium.By.ClassName(className));
/// <summary>
/// Creates a By object using the ID attribute.
/// </summary>
@@ -32,6 +68,13 @@ namespace Microsoft.PowerToys.UITest
/// <returns>A By object.</returns>
public static By Id(string id) => new By(OpenQA.Selenium.By.Id(id));
/// <summary>
/// Creates a By object using the ID attribute.
/// </summary>
/// <param name="accessibilityId">The ID attribute to search for.</param>
/// <returns>A By object.</returns>
public static By AccessibilityId(string accessibilityId) => new By(accessibilityId);
/// <summary>
/// Creates a By object using the XPath expression.
/// </summary>
@@ -64,6 +107,6 @@ namespace Microsoft.PowerToys.UITest
/// Converts the By object to an OpenQA.Selenium.By object.
/// </summary>
/// <returns>An OpenQA.Selenium.By object.</returns>
internal OpenQA.Selenium.By ToSeleniumBy() => by;
internal OpenQA.Selenium.By ToSeleniumBy() => by!;
}
}

View File

@@ -3,16 +3,16 @@
// See the LICENSE file in the project root for more information.
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.CompilerServices;
using System.Xml.Linq;
using ABI.Windows.Foundation;
using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Interactions;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium.Support.Events;
using static Microsoft.PowerToys.UITest.UITestBase;
[assembly: InternalsVisibleTo("Session")]
@@ -24,8 +24,17 @@ namespace Microsoft.PowerToys.UITest
public class Element
{
private WindowsElement? windowsElement;
private WindowsDriver<WindowsElement>? driver;
protected string? TargetControlType { get; set; }
internal bool IsMatchingTarget()
{
var ct = this.ControlType;
return string.IsNullOrEmpty(this.TargetControlType) || this.TargetControlType == this.ControlType;
}
internal void SetWindowsElement(WindowsElement windowsElement) => this.windowsElement = windowsElement;
internal void SetSession(WindowsDriver<WindowsElement> driver) => this.driver = driver;
@@ -43,7 +52,28 @@ namespace Microsoft.PowerToys.UITest
/// </summary>
public string Text
{
get { return GetAttribute("Value"); }
get { return this.windowsElement?.Text ?? string.Empty; }
}
/// <summary>
/// Gets a value indicating whether the UI element is Enabled or not.
/// </summary>
public bool Enabled
{
get { return this.windowsElement?.Enabled ?? false; }
}
public bool Selected
{
get { return this.windowsElement?.Selected ?? false; }
}
/// <summary>
/// Gets the Rect of the UI element.
/// </summary>
public Rectangle? Rect
{
get { return this.windowsElement?.Rect; }
}
/// <summary>
@@ -78,26 +108,19 @@ namespace Microsoft.PowerToys.UITest
get { return GetAttribute("ControlType"); }
}
/// <summary>
/// Checks if the UI element is enabled.
/// </summary>
/// <returns>True if the element is enabled; otherwise, false.</returns>
public bool IsEnabled() => GetAttribute("IsEnabled") == "True";
/// <summary>
/// Checks if the UI element is selected.
/// </summary>
/// <returns>True if the element is selected; otherwise, false.</returns>
public bool IsSelected() => GetAttribute("IsSelected") == "True";
/// <summary>
/// Click the UI element.
/// </summary>
/// <param name="rightClick">If true, performs a right-click; otherwise, performs a left-click.</param>
public void Click(bool rightClick = false)
/// <param name="rightClick">If true, performs a right-click; otherwise, performs a left-click. Default value is false</param>
public virtual void Click(bool rightClick = false)
{
PerformAction(actions =>
PerformAction((actions, windowElement) =>
{
actions.MoveToElement(windowElement);
// Move 2by2 offset to make click more stable instead of click on the border of the element
actions.MoveByOffset(2, 2);
if (rightClick)
{
actions.ContextClick();
@@ -106,6 +129,73 @@ namespace Microsoft.PowerToys.UITest
{
actions.Click();
}
actions.Build().Perform();
});
}
/// <summary>
/// Double Click the UI element.
/// </summary>
public virtual void DoubleClick()
{
PerformAction((actions, windowElement) =>
{
actions.MoveToElement(windowElement);
// Move 2by2 offset to make click more stable instead of click on the border of the element
actions.MoveByOffset(2, 2);
actions.DoubleClick();
actions.Build().Perform();
});
}
/// <summary>
/// Drag element move offset.
/// </summary>
/// <param name="offsetX">The offsetX to move.</param>
/// <param name="offsetY">The offsetY to move.</param>
public void Drag(int offsetX, int offsetY)
{
PerformAction((actions, windowElement) =>
{
actions.MoveToElement(windowElement).MoveByOffset(10, 10).ClickAndHold(windowElement).MoveByOffset(offsetX, offsetY).Release();
actions.Build().Perform();
});
}
/// <summary>
/// Drag element move to other element.
/// </summary>
/// <param name="element">Move to this element.</param>
public void Drag(Element element)
{
PerformAction((actions, windowElement) =>
{
actions.MoveToElement(windowElement).ClickAndHold();
Assert.IsNotNull(element.windowsElement, "element is null");
int dx = (element.windowsElement.Rect.X - windowElement.Rect.X) / 10;
int dy = (element.windowsElement.Rect.Y - windowElement.Rect.Y) / 10;
for (int i = 0; i < 10; i++)
{
actions.MoveByOffset(dx, dy);
}
actions.Release();
actions.Build().Perform();
});
}
/// <summary>
/// Send Key of the element.
/// </summary>
/// <param name="key">The Key to Send.</param>
public void SendKeys(string key)
{
PerformAction((actions, windowElement) =>
{
windowElement.SendKeys(key);
});
}
@@ -118,7 +208,6 @@ namespace Microsoft.PowerToys.UITest
{
Assert.IsNotNull(this.windowsElement, $"WindowsElement is null in method GetAttribute with parameter: attributeName = {attributeName}");
var attributeValue = this.windowsElement.GetAttribute(attributeName);
Assert.IsNotNull(attributeValue, $"Attribute '{attributeName}' is null.");
return attributeValue;
}
@@ -133,17 +222,51 @@ namespace Microsoft.PowerToys.UITest
where T : Element, new()
{
Assert.IsNotNull(this.windowsElement, $"WindowsElement is null in method Find<{typeof(T).Name}> with parameters: by = {by}, timeoutMS = {timeoutMS}");
var foundElement = FindElementHelper.Find<T, AppiumWebElement>(
() =>
{
var element = this.windowsElement.FindElement(by.ToSeleniumBy());
Assert.IsNotNull(element, $"Element not found using selector: {by}");
return element;
},
this.driver,
timeoutMS);
return foundElement;
// leverage findAll to filter out mismatched elements
var collection = this.FindAll<T>(by, timeoutMS);
Assert.IsTrue(collection.Count > 0, $"Element not found using selector: {by}");
return collection[0];
}
/// <summary>
/// Finds an element by the selector.
/// Shortcut for this.Find<T>(By.Name(name), timeoutMS)
/// </summary>
/// <typeparam name="T">The class type of the element to find.</typeparam>
/// <param name="name">The name for finding the element.</param>
/// <param name="timeoutMS">The timeout in milliseconds.</param>
/// <returns>The found element.</returns>
public T Find<T>(string name, int timeoutMS = 3000)
where T : Element, new()
{
return this.Find<T>(By.Name(name), timeoutMS);
}
/// <summary>
/// Finds an element by the selector.
/// Shortcut for this.Find<Element>(by, timeoutMS)
/// </summary>
/// <param name="by">The selector to use for finding the element.</param>
/// <param name="timeoutMS">The timeout in milliseconds.</param>
/// <returns>The found element.</returns>
public Element Find(By by, int timeoutMS = 3000)
{
return this.Find<Element>(by, timeoutMS);
}
/// <summary>
/// Finds an element by the selector.
/// Shortcut for this.Find<Element>(By.Name(name), timeoutMS)
/// </summary>
/// <param name="name">The name for finding the element.</param>
/// <param name="timeoutMS">The timeout in milliseconds.</param>
/// <returns>The found element.</returns>
public Element Find(string name, int timeoutMS = 3000)
{
return this.Find<Element>(By.Name(name), timeoutMS);
}
/// <summary>
@@ -153,33 +276,89 @@ namespace Microsoft.PowerToys.UITest
/// <param name="by">The selector to use for finding the elements.</param>
/// <param name="timeoutMS">The timeout in milliseconds.</param>
/// <returns>A read-only collection of the found elements.</returns>
public ReadOnlyCollection<T>? FindAll<T>(By by, int timeoutMS = 3000)
public ReadOnlyCollection<T> FindAll<T>(By by, int timeoutMS = 3000)
where T : Element, new()
{
Assert.IsNotNull(this.windowsElement, $"WindowsElement is null in method FindAll<{typeof(T).Name}> with parameters: by = {by}, timeoutMS = {timeoutMS}");
var foundElements = FindElementHelper.FindAll<T, AppiumWebElement>(
var foundElements = FindHelper.FindAll<T, AppiumWebElement>(
() =>
{
var elements = this.windowsElement.FindElements(by.ToSeleniumBy());
Assert.IsTrue(elements.Count > 0, $"Elements not found using selector: {by}");
return elements;
if (by.GetIsAccessibilityId())
{
var elements = this.windowsElement.FindElementsByAccessibilityId(by.GetAccessibilityId());
return elements;
}
else
{
var elements = this.windowsElement.FindElements(by.ToSeleniumBy());
return elements;
}
},
this.driver,
timeoutMS);
return foundElements;
return foundElements ?? new ReadOnlyCollection<T>([]);
}
/// <summary>
/// Finds all elements by the selector.
/// Shortcut for this.FindAll<T>(By.Name(name), timeoutMS)
/// </summary>
/// <typeparam name="T">The class type of the elements to find.</typeparam>
/// <param name="name">The name for finding the element.</param>
/// <param name="timeoutMS">The timeout in milliseconds.</param>
/// <returns>A read-only collection of the found elements.</returns>
public ReadOnlyCollection<T> FindAll<T>(string name, int timeoutMS = 3000)
where T : Element, new()
{
return this.FindAll<T>(By.Name(name), timeoutMS);
}
/// <summary>
/// Finds all elements by the selector.
/// Shortcut for this.FindAll<Element>(by, timeoutMS)
/// </summary>
/// <param name="by">The selector to use for finding the elements.</param>
/// <param name="timeoutMS">The timeout in milliseconds.</param>
/// <returns>A read-only collection of the found elements.</returns>
public ReadOnlyCollection<Element> FindAll(By by, int timeoutMS = 3000)
{
return this.FindAll<Element>(by, timeoutMS);
}
/// <summary>
/// Finds all elements by the selector.
/// Shortcut for this.FindAll<Element>(By.Name(name), timeoutMS)
/// </summary>
/// <param name="name">The name for finding the element.</param>
/// <param name="timeoutMS">The timeout in milliseconds.</param>
/// <returns>A read-only collection of the found elements.</returns>
public ReadOnlyCollection<Element> FindAll(string name, int timeoutMS = 3000)
{
return this.FindAll<Element>(By.Name(name), timeoutMS);
}
/// <summary>
/// Simulates a manual operation on the element.
/// </summary>
private void PerformAction(Action<Actions> action)
/// <param name="action">The action to perform on the element.</param>
/// <param name="msPreAction">The number of milliseconds to wait before the action. Default value is 500 ms</param>
/// <param name="msPostAction">The number of milliseconds to wait after the action. Default value is 500 ms</param>
protected void PerformAction(Action<Actions, WindowsElement> action, int msPreAction = 500, int msPostAction = 500)
{
var element = this.windowsElement;
if (msPreAction > 0)
{
Task.Delay(msPreAction).Wait();
}
var windowElement = this.windowsElement!;
Actions actions = new Actions(this.driver);
actions.MoveToElement(element);
action(actions);
actions.Build().Perform();
action(actions, windowElement);
if (msPostAction > 0)
{
Task.Delay(msPostAction).Wait();
}
}
}
}

View File

@@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Microsoft.PowerToys.UITest
{
/// <summary>
/// Represents a HyperLinkButton in the UI test environment.
/// HyperLinkButton represents a button control that functions as a hyperlink.
/// </summary>
public class HyperlinkButton : Button
{
private static readonly string ExpectedControlType = "ControlType.HyperLink";
/// <summary>
/// Initializes a new instance of the <see cref="HyperlinkButton"/> class.
/// </summary>
public HyperlinkButton()
{
this.TargetControlType = HyperlinkButton.ExpectedControlType;
}
}
}

View File

@@ -0,0 +1,59 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Microsoft.PowerToys.UITest
{
/// <summary>
/// Represents a NavigationViewItem in the UI test environment.
/// NavigationViewItem represents the container for an item in a NavigationView control.
/// </summary>
public class NavigationViewItem : Element
{
private static readonly string ExpectedControlType = "ControlType.ListItem";
/// <summary>
/// Initializes a new instance of the <see cref="NavigationViewItem"/> class.
/// </summary>
public NavigationViewItem()
{
this.TargetControlType = NavigationViewItem.ExpectedControlType;
}
/// <summary>
/// Click the ListItem element.
/// </summary>
/// <param name="rightClick">If true, performs a right-click; otherwise, performs a left-click. Default value is false</param>
public override void Click(bool rightClick = false)
{
PerformAction((actions, windowElement) =>
{
actions.MoveToElement(windowElement, 10, 10);
if (rightClick)
{
actions.ContextClick();
}
else
{
actions.Click();
}
actions.Build().Perform();
});
}
/// <summary>
/// Double Click the ListItem element.
/// </summary>
public override void DoubleClick()
{
PerformAction((actions, windowElement) =>
{
actions.MoveToElement(windowElement, 10, 10);
actions.DoubleClick();
actions.Build().Perform();
});
}
}
}

View File

@@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Microsoft.PowerToys.UITest
{
/// <summary>
/// Represents a TextBlock in the UI test environment.
/// TextBlock provides a lightweight control for displaying small amounts of flow content.
/// </summary>
public class TextBlock : Element
{
private static readonly string ExpectedControlType = "ControlType.Text";
/// <summary>
/// Initializes a new instance of the <see cref="TextBlock"/> class.
/// </summary>
public TextBlock()
{
this.TargetControlType = TextBlock.ExpectedControlType;
}
}
}

View File

@@ -0,0 +1,51 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using OpenQA.Selenium;
namespace Microsoft.PowerToys.UITest
{
/// <summary>
/// Represents a TextBox in the UI test environment.
/// TextBox represents a control that can be used to display and edit plain text (single or multi-line).
/// </summary>
public class TextBox : Element
{
private static readonly string ExpectedControlType = "ControlType.Edit";
/// <summary>
/// Initializes a new instance of the <see cref="TextBox"/> class.
/// </summary>
public TextBox()
{
this.TargetControlType = TextBox.ExpectedControlType;
}
/// <summary>
/// Sets the text of the textbox.
/// </summary>
/// <param name="value">The text to set.</param>
/// <param name="clearText">A value indicating whether to clear the text before setting it. Default value is true</param>
/// <returns>The current TextBox instance.</returns>
public TextBox SetText(string value, bool clearText = true)
{
if (clearText)
{
PerformAction((actions, windowElement) =>
{
// select all text and delete it
windowElement.SendKeys(Keys.Control + "a");
windowElement.SendKeys(Keys.Delete);
});
}
PerformAction((actions, windowElement) =>
{
windowElement.SendKeys(value);
});
return this;
}
}
}

View File

@@ -0,0 +1,41 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Newtonsoft.Json.Linq;
namespace Microsoft.PowerToys.UITest
{
/// <summary>
/// Represents a ToggleSwitch in the UI test environment.
/// </summary>
public class ToggleSwitch : Button
{
/// <summary>
/// Gets a value indicating whether the ToggleSwitch is on.
/// </summary>
public bool IsOn
{
get
{
return this.Selected;
}
}
/// <summary>
/// Sets the ToggleSwitch to the specified value.
/// </summary>
/// <param name="value">A value indicating whether the ToggleSwitch should be active. Default is true</param>
/// <returns>The current ToggleSwitch instance.</returns>
public ToggleSwitch Toggle(bool value = true)
{
if (this.IsOn != value)
{
// Toggle the switch
this.Click();
}
return this;
}
}
}

View File

@@ -2,13 +2,6 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Interactions;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium.Support.Events;
namespace Microsoft.PowerToys.UITest
{
/// <summary>
@@ -25,7 +18,7 @@ namespace Microsoft.PowerToys.UITest
{
if (byClickButton)
{
Find<Button>(By.Name("Maximize")).Click();
Find<Button>("Maximize").Click();
}
else
{
@@ -44,7 +37,7 @@ namespace Microsoft.PowerToys.UITest
{
if (byClickButton)
{
Find<Button>(By.Name("Restore")).Click();
Find<Button>("Restore").Click();
}
else
{
@@ -63,7 +56,7 @@ namespace Microsoft.PowerToys.UITest
{
if (byClickButton)
{
Find<Button>(By.Name("Minimize")).Click();
Find<Button>("Minimize").Click();
}
else
{
@@ -81,7 +74,7 @@ namespace Microsoft.PowerToys.UITest
{
if (byClickButton)
{
Find<Button>(By.Name("Close")).Click();
Find<Button>("Close").Click();
}
else
{

View File

@@ -2,16 +2,9 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Windows;
[assembly: InternalsVisibleTo("Element")]
@@ -22,13 +15,19 @@ namespace Microsoft.PowerToys.UITest
/// <summary>
/// Helper class for finding elements.
/// </summary>
internal static class FindElementHelper
internal static class FindHelper
{
public static T Find<T, TW>(Func<TW> findElementFunc, WindowsDriver<WindowsElement>? driver, int timeoutMS)
public static ReadOnlyCollection<T>? FindAll<T, TW>(Func<IReadOnlyCollection<TW>> findElementsFunc, WindowsDriver<WindowsElement>? driver, int timeoutMS)
where T : Element, new()
{
var item = findElementFunc() as WindowsElement;
return NewElement<T>(item, driver, timeoutMS);
var items = findElementsFunc();
var res = items.Select(item =>
{
var element = item as WindowsElement;
return NewElement<T>(element, driver, timeoutMS);
}).Where(item => item.IsMatchingTarget()).ToList();
return new ReadOnlyCollection<T>(res);
}
public static ReadOnlyCollection<T>? FindAll<T, TW>(Func<ReadOnlyCollection<TW>> findElementsFunc, WindowsDriver<WindowsElement>? driver, int timeoutMS)
@@ -39,7 +38,7 @@ namespace Microsoft.PowerToys.UITest
{
var element = item as WindowsElement;
return NewElement<T>(element, driver, timeoutMS);
}).ToList();
}).Where(item => item.IsMatchingTarget()).ToList();
return new ReadOnlyCollection<T>(res);
}
@@ -51,7 +50,12 @@ namespace Microsoft.PowerToys.UITest
Assert.IsNotNull(element, $"New Element {typeof(T).Name} error: element is null.");
T newElement = new T();
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromMilliseconds(timeoutMS);
if (timeoutMS > 0)
{
// Only set timeout if it is positive value
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromMilliseconds(timeoutMS);
}
newElement.SetSession(driver);
newElement.SetWindowsElement(element);
return newElement;

View File

@@ -2,14 +2,10 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Interactions;
@@ -45,17 +41,48 @@ namespace Microsoft.PowerToys.UITest
where T : Element, new()
{
Assert.IsNotNull(this.WindowsDriver, $"WindowsElement is null in method Find<{typeof(T).Name}> with parameters: by = {by}, timeoutMS = {timeoutMS}");
var foundElement = FindElementHelper.Find<T, WindowsElement>(
() =>
{
var element = this.WindowsDriver.FindElement(by.ToSeleniumBy());
Assert.IsNotNull(element, $"Element not found using selector: {by}");
return element;
},
this.WindowsDriver,
timeoutMS);
return foundElement;
// leverage findAll to filter out mismatched elements
var collection = this.FindAll<T>(by, timeoutMS);
Assert.IsTrue(collection.Count > 0, $"Element not found using selector: {by}");
return collection[0];
}
/// <summary>
/// Shortcut for this.Find<T>(By.Name(name), timeoutMS)
/// </summary>
/// <typeparam name="T">The class of the element, should be Element or its derived class.</typeparam>
/// <param name="name">The name of the element.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
/// <returns>The found element.</returns>
public T Find<T>(string name, int timeoutMS = 3000)
where T : Element, new()
{
return this.Find<T>(By.Name(name), timeoutMS);
}
/// <summary>
/// Shortcut for this.Find<Element>(by, timeoutMS)
/// </summary>
/// <param name="by">The selector to find the element.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
/// <returns>The found element.</returns>
public Element Find(By by, int timeoutMS = 3000)
{
return this.Find<Element>(by, timeoutMS);
}
/// <summary>
/// Shortcut for this.Find<Element>(By.Name(name), timeoutMS)
/// </summary>
/// <param name="name">The name of the element.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
/// <returns>The found element.</returns>
public Element Find(string name, int timeoutMS = 3000)
{
return this.Find<Element>(By.Name(name), timeoutMS);
}
/// <summary>
@@ -65,21 +92,99 @@ namespace Microsoft.PowerToys.UITest
/// <param name="by">The selector to find the elements.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
/// <returns>A read-only collection of the found elements.</returns>
public ReadOnlyCollection<T>? FindAll<T>(By by, int timeoutMS = 3000)
public ReadOnlyCollection<T> FindAll<T>(By by, int timeoutMS = 3000)
where T : Element, new()
{
Assert.IsNotNull(this.WindowsDriver, $"WindowsElement is null in method FindAll<{typeof(T).Name}> with parameters: by = {by}, timeoutMS = {timeoutMS}");
var foundElements = FindElementHelper.FindAll<T, WindowsElement>(
var foundElements = FindHelper.FindAll<T, WindowsElement>(
() =>
{
var elements = this.WindowsDriver.FindElements(by.ToSeleniumBy());
Assert.IsTrue(elements.Count > 0, $"Elements not found using selector: {by}");
return elements;
if (by.GetIsAccessibilityId())
{
var elements = this.WindowsDriver.FindElementsByAccessibilityId(by.GetAccessibilityId());
return elements;
}
else
{
var elements = this.WindowsDriver.FindElements(by.ToSeleniumBy());
return elements;
}
},
this.WindowsDriver,
timeoutMS);
return foundElements;
return foundElements ?? new ReadOnlyCollection<T>([]);
}
/// <summary>
/// Finds all elements by selector.
/// Shortcut for this.FindAll<T>(By.Name(name), timeoutMS)
/// </summary>
/// <typeparam name="T">The class of the elements, should be Element or its derived class.</typeparam>
/// <param name="name">The name to find the elements.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
/// <returns>A read-only collection of the found elements.</returns>
public ReadOnlyCollection<T> FindAll<T>(string name, int timeoutMS = 3000)
where T : Element, new()
{
return this.FindAll<T>(By.Name(name), timeoutMS);
}
/// <summary>
/// Finds all elements by selector.
/// Shortcut for this.FindAll<Element>(by, timeoutMS)
/// </summary>
/// <param name="by">The selector to find the elements.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
/// <returns>A read-only collection of the found elements.</returns>
public ReadOnlyCollection<Element> FindAll(By by, int timeoutMS = 3000)
{
return this.FindAll<Element>(by, timeoutMS);
}
/// <summary>
/// Finds all elements by selector.
/// Shortcut for this.FindAll<Element>(By.Name(name), timeoutMS)
/// </summary>
/// <param name="name">The name to find the elements.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
/// <returns>A read-only collection of the found elements.</returns>
public ReadOnlyCollection<Element> FindAll(string name, int timeoutMS = 3000)
{
return this.FindAll<Element>(By.Name(name), timeoutMS);
}
/// <summary>
/// Keyboard Action key.
/// </summary>
/// <param name="key1">The Keys1 to click.</param>
/// <param name="key2">The Keys2 to click.</param>
/// <param name="key3">The Keys3 to click.</param>
/// <param name="key4">The Keys4 to click.</param>
public void KeyboardAction(string key1, string key2 = "", string key3 = "", string key4 = "")
{
PerformAction((actions, windowElement) =>
{
if (string.IsNullOrEmpty(key2))
{
actions.SendKeys(key1);
}
else if (string.IsNullOrEmpty(key3))
{
actions.SendKeys(key1).SendKeys(key2);
}
else if (string.IsNullOrEmpty(key4))
{
actions.SendKeys(key1).SendKeys(key2).SendKeys(key3);
}
else
{
actions.SendKeys(key1).SendKeys(key2).SendKeys(key3).SendKeys(key4);
}
actions.Release();
actions.Build().Perform();
});
}
/// <summary>
@@ -110,6 +215,7 @@ namespace Microsoft.PowerToys.UITest
SetForegroundWindow(windowHandle);
var hexWindowHandle = windowHandle.ToString("x");
var appCapabilities = new AppiumOptions();
appCapabilities.AddAdditionalCapability("appTopLevelWindow", hexWindowHandle);
appCapabilities.AddAdditionalCapability("deviceName", "WindowsPC");
this.WindowsDriver = new WindowsDriver<WindowsElement>(new Uri(ModuleConfigData.Instance.GetWindowsApplicationDriverUrl()), appCapabilities);
@@ -125,5 +231,28 @@ namespace Microsoft.PowerToys.UITest
return this;
}
/// <summary>
/// Simulates a manual operation on the element.
/// </summary>
/// <param name="action">The action to perform on the element.</param>
/// <param name="msPreAction">The number of milliseconds to wait before the action. Default value is 500 ms</param>
/// <param name="msPostAction">The number of milliseconds to wait after the action. Default value is 500 ms</param>
protected void PerformAction(Action<Actions, WindowsDriver<WindowsElement>> action, int msPreAction = 500, int msPostAction = 500)
{
if (msPreAction > 0)
{
Task.Delay(msPreAction).Wait();
}
var windowsDriver = this.WindowsDriver;
Actions actions = new Actions(this.WindowsDriver);
action(actions, windowsDriver);
if (msPostAction > 0)
{
Task.Delay(msPostAction).Wait();
}
}
}
}

View File

@@ -0,0 +1,149 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Windows;
namespace Microsoft.PowerToys.UITest
{
/// <summary>
/// Nested class for test initialization.
/// </summary>
internal class SessionHelper
{
// Default session path is PowerToys settings dashboard
private readonly string sessionPath = ModuleConfigData.Instance.GetModulePath(PowerToysModule.PowerToysSettings);
private string? locationPath;
private WindowsDriver<WindowsElement> Root { get; set; }
private WindowsDriver<WindowsElement>? Driver { get; set; }
private Process? appDriver;
[UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification = "<Pending>")]
public SessionHelper(PowerToysModule scope)
{
this.sessionPath = ModuleConfigData.Instance.GetModulePath(scope);
this.locationPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var winAppDriverProcessInfo = new ProcessStartInfo
{
FileName = "C:\\Program Files (x86)\\Windows Application Driver\\WinAppDriver.exe",
Verb = "runas",
};
this.appDriver = Process.Start(winAppDriverProcessInfo);
var desktopCapabilities = new AppiumOptions();
desktopCapabilities.AddAdditionalCapability("app", "Root");
this.Root = new WindowsDriver<WindowsElement>(new Uri(ModuleConfigData.Instance.GetWindowsApplicationDriverUrl()), desktopCapabilities);
// Set default timeout to 5 seconds
this.Root.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5);
}
/// <summary>
/// Initializes the test environment.
/// </summary>
/// <param name="scope">The PowerToys module to start.</param>
public SessionHelper Init()
{
this.StartExe(locationPath + this.sessionPath);
Assert.IsNotNull(this.Driver, $"Failed to initialize the test environment. Driver is null.");
return this;
}
/// <summary>
/// Cleans up the test environment.
/// </summary>
public void Cleanup()
{
ExitScopeExe();
try
{
appDriver?.Kill();
appDriver?.WaitForExit(); // Optional: Wait for the process to exit
}
catch (Exception ex)
{
// Handle exceptions if needed
Debug.WriteLine($"Exception during Cleanup: {ex.Message}");
}
}
/// <summary>
/// Starts a new exe and takes control of it.
/// </summary>
/// <param name="appPath">The path to the application executable.</param>
public void StartExe(string appPath)
{
var opts = new AppiumOptions();
opts.AddAdditionalCapability("app", appPath);
Console.WriteLine($"appPath: {appPath}");
this.Driver = new WindowsDriver<WindowsElement>(new Uri(ModuleConfigData.Instance.GetWindowsApplicationDriverUrl()), opts);
// Set default timeout to 5 seconds
this.Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5);
}
/// <summary>
/// Exit a exe.
/// </summary>
/// <param name="path">The path to the application executable.</param>
public void ExitExe(string path)
{
// Exit Exe
string exeName = Path.GetFileNameWithoutExtension(path);
// PowerToys.FancyZonesEditor
Process[] processes = Process.GetProcessesByName(exeName);
foreach (Process process in processes)
{
try
{
process.Kill();
process.WaitForExit(); // Optional: Wait for the process to exit
}
catch (Exception ex)
{
Assert.Fail($"Failed to terminate process {process.ProcessName} (ID: {process.Id}): {ex.Message}");
}
}
}
/// <summary>
/// Exit now exe.
/// </summary>
public void ExitScopeExe()
{
ExitExe(sessionPath);
}
/// <summary>
/// Restarts now exe and takes control of it.
/// </summary>
public void RestartScopeExe()
{
ExitExe(sessionPath);
StartExe(locationPath + sessionPath);
}
public WindowsDriver<WindowsElement> GetRoot() => this.Root;
public WindowsDriver<WindowsElement> GetDriver()
{
Assert.IsNotNull(this.Driver, $"Failed to get driver. Driver is null.");
return this.Driver;
}
}
}

View File

@@ -1,8 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\Common.Dotnet.CsWinRT.props" />
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
@@ -15,7 +16,4 @@
<PackageReference Include="System.IO.Abstractions" />
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
</Project>

View File

@@ -2,129 +2,180 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Interactions;
namespace Microsoft.PowerToys.UITest
{
/// <summary>
/// Base class that should be inherited by all Test Classes.
/// </summary>
[TestClass]
public class UITestBase
{
public Session Session { get; set; }
private readonly TestInit testInit = new TestInit();
private readonly SessionHelper sessionHelper;
private readonly PowerToysModule scope;
public UITestBase(PowerToysModule scope = PowerToysModule.PowerToysSettings)
{
this.testInit.SetScope(scope);
this.testInit.Init();
this.Session = new Session(this.testInit.GetRoot(), this.testInit.GetDriver());
}
~UITestBase()
{
this.testInit.Cleanup();
this.scope = scope;
this.sessionHelper = new SessionHelper(scope).Init();
this.Session = new Session(this.sessionHelper.GetRoot(), this.sessionHelper.GetDriver());
}
/// <summary>
/// Nested class for test initialization.
/// Initializes the test.
/// </summary>
private sealed class TestInit
[TestInitialize]
public void TestInit()
{
private WindowsDriver<WindowsElement> Root { get; set; }
private WindowsDriver<WindowsElement>? Driver { get; set; }
private static Process? appDriver;
// Default session path is PowerToys settings dashboard
private static string sessionPath = ModuleConfigData.Instance.GetModulePath(PowerToysModule.PowerToysSettings);
public TestInit()
if (this.scope == PowerToysModule.PowerToysSettings)
{
appDriver = Process.Start(new ProcessStartInfo
// close Debug warning dialog if any
// Such debug warning dialog seems only appear in PowerToys Settings
if (this.FindAll("DEBUG").Count > 0)
{
FileName = "C:\\Program Files (x86)\\Windows Application Driver\\WinAppDriver.exe",
Verb = "runas",
});
var desktopCapabilities = new AppiumOptions();
desktopCapabilities.AddAdditionalCapability("app", "Root");
this.Root = new WindowsDriver<WindowsElement>(new Uri(ModuleConfigData.Instance.GetWindowsApplicationDriverUrl()), desktopCapabilities);
// Set default timeout to 5 seconds
this.Root.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5);
}
/// <summary>
/// Initializes the test environment.
/// </summary>
[UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification = "<Pending>")]
public void Init()
{
string? path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
this.StartExe(path + sessionPath);
Assert.IsNotNull(this.Driver, $"Failed to initialize the test environment. Driver is null.");
// Set default timeout to 5 seconds
this.Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5);
}
/// <summary>
/// Cleans up the test environment.
/// </summary>
public void Cleanup()
{
try
{
appDriver?.Kill();
}
catch (Exception ex)
{
// Handle exceptions if needed
Debug.WriteLine($"Exception during Cleanup: {ex.Message}");
this.Find("DEBUG").Find<Button>("Close").Click();
}
}
}
/// <summary>
/// Starts a new exe and takes control of it.
/// </summary>
/// <param name="appPath">The path to the application executable.</param>
public void StartExe(string appPath)
{
var opts = new AppiumOptions();
opts.AddAdditionalCapability("app", appPath);
this.Driver = new WindowsDriver<WindowsElement>(new Uri(ModuleConfigData.Instance.GetWindowsApplicationDriverUrl()), opts);
}
/// <summary>
/// UnInitializes the test.
/// </summary>
[TestCleanup]
public void TestClean()
{
this.sessionHelper.Cleanup();
}
/// <summary>
/// Sets scope to the Test Class.
/// </summary>
/// <param name="scope">The PowerToys module to start.</param>
public void SetScope(PowerToysModule scope)
{
sessionPath = ModuleConfigData.Instance.GetModulePath(scope);
}
/// <summary>
/// Finds an element by selector.
/// Shortcut for this.Session.Find<T>(by, timeoutMS)
/// </summary>
/// <typeparam name="T">The class of the element, should be Element or its derived class.</typeparam>
/// <param name="by">The selector to find the element.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
/// <returns>The found element.</returns>
protected T Find<T>(By by, int timeoutMS = 3000)
where T : Element, new()
{
return this.Session.Find<T>(by, timeoutMS);
}
public WindowsDriver<WindowsElement> GetRoot() => this.Root;
/// <summary>
/// Shortcut for this.Session.Find<Element>(By.Name(name), timeoutMS)
/// </summary>
/// <typeparam name="T">The class of the element, should be Element or its derived class.</typeparam>
/// <param name="name">The name of the element.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
/// <returns>The found element.</returns>
protected T Find<T>(string name, int timeoutMS = 3000)
where T : Element, new()
{
return this.Session.Find<T>(By.Name(name), timeoutMS);
}
public WindowsDriver<WindowsElement> GetDriver()
{
Assert.IsNotNull(this.Driver, $"Failed to get driver. Driver is null.");
return this.Driver;
}
/// <summary>
/// Shortcut for this.Session.Find<Element>(by, timeoutMS)
/// </summary>
/// <param name="by">The selector to find the element.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
/// <returns>The found element.</returns>
protected Element Find(By by, int timeoutMS = 3000)
{
return this.Session.Find(by, timeoutMS);
}
/// <summary>
/// Shortcut for this.Session.Find<Element>(By.Name(name), timeoutMS)
/// </summary>
/// <param name="name">The name of the element.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
/// <returns>The found element.</returns>
protected Element Find(string name, int timeoutMS = 3000)
{
return this.Session.Find(name, timeoutMS);
}
/// <summary>
/// Finds all elements by selector.
/// Shortcut for this.Session.FindAll<T>(by, timeoutMS)
/// </summary>
/// <typeparam name="T">The class of the elements, should be Element or its derived class.</typeparam>
/// <param name="by">The selector to find the elements.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
/// <returns>A read-only collection of the found elements.</returns>
protected ReadOnlyCollection<T> FindAll<T>(By by, int timeoutMS = 3000)
where T : Element, new()
{
return this.Session.FindAll<T>(by, timeoutMS);
}
/// <summary>
/// Finds all elements by selector.
/// Shortcut for this.Session.FindAll<Element>(By.Name(name), timeoutMS)
/// </summary>
/// <typeparam name="T">The class of the elements, should be Element or its derived class.</typeparam>
/// <param name="name">The name of the elements.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
/// <returns>A read-only collection of the found elements.</returns>
protected ReadOnlyCollection<T> FindAll<T>(string name, int timeoutMS = 3000)
where T : Element, new()
{
return this.Session.FindAll<T>(By.Name(name), timeoutMS);
}
/// <summary>
/// Finds all elements by selector.
/// Shortcut for this.Session.FindAll<Element>(by, timeoutMS)
/// </summary>
/// <param name="by">The selector to find the elements.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
/// <returns>A read-only collection of the found elements.</returns>
protected ReadOnlyCollection<Element> FindAll(By by, int timeoutMS = 3000)
{
return this.Session.FindAll<Element>(by, timeoutMS);
}
/// <summary>
/// Finds all elements by selector.
/// Shortcut for this.Session.FindAll<Element>(By.Name(name), timeoutMS)
/// </summary>
/// <param name="name">The name of the elements.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
/// <returns>A read-only collection of the found elements.</returns>
protected ReadOnlyCollection<Element> FindAll(string name, int timeoutMS = 3000)
{
return this.Session.FindAll<Element>(By.Name(name), timeoutMS);
}
/// <summary>
/// Restart scope exe.
/// </summary>
public void RestartScopeExe()
{
this.sessionHelper.RestartScopeExe();
this.Session = new Session(this.sessionHelper.GetRoot(), this.sessionHelper.GetDriver());
return;
}
/// <summary>
/// Restart scope exe.
/// </summary>
public void ExitScopeExe()
{
this.sessionHelper.ExitScopeExe();
return;
}
}
}

View File

@@ -187,4 +187,8 @@ namespace winrt::PowerToys::Interop::implementation
{
return CommonSharedConstants::TERMINATE_SETTINGS_SHARED_EVENT;
}
hstring Constants::ShowCmdPalEvent()
{
return CommonSharedConstants::CMDPAL_SHOW_EVENT;
}
}

View File

@@ -50,6 +50,7 @@ namespace winrt::PowerToys::Interop::implementation
static hstring WorkspacesLaunchEditorEvent();
static hstring WorkspacesHotkeyEvent();
static hstring PowerToysRunnerTerminateSettingsEvent();
static hstring ShowCmdPalEvent();
};
}

View File

@@ -47,6 +47,7 @@ namespace PowerToys
static String WorkspacesLaunchEditorEvent();
static String WorkspacesHotkeyEvent();
static String PowerToysRunnerTerminateSettingsEvent();
static String ShowCmdPalEvent();
}
}
}

View File

@@ -128,6 +128,10 @@ namespace CommonSharedConstants
const wchar_t ZOOMIT_REFRESH_SETTINGS_EVENT[] = L"Local\\PowerToysZoomIt-RefreshSettingsEvent-f053a563-d519-4b0d-8152-a54489c13324";
const wchar_t ZOOMIT_EXIT_EVENT[] = L"Local\\PowerToysZoomIt-ExitEvent-36641ce6-df02-4eac-abea-a3fbf9138220";
// used from quick access window
const wchar_t CMDPAL_SHOW_EVENT[] = L"Local\\PowerToysCmdPal-ShowEvent-62336fcd-8611-4023-9b30-091a6af4cc5a";
const wchar_t CMDPAL_EXIT_EVENT[] = L"Local\\PowerToysCmdPal-ExitEvent-eb73f6be-3f22-4b36-aee3-62924ba40bfd";
// Max DWORD for key code to disable keys.
const DWORD VK_DISABLED = 0x100;
}

View File

@@ -4,8 +4,10 @@
#include <optional>
#include <vector>
namespace powertoys_gpo {
enum gpo_rule_configured_t {
namespace powertoys_gpo
{
enum gpo_rule_configured_t
{
gpo_rule_configured_wrong_value = -3, // The policy is set to an unrecognized value
gpo_rule_configured_unavailable = -2, // Couldn't access registry
gpo_rule_configured_not_configured = -1, // Policy is not configured
@@ -53,6 +55,7 @@ namespace powertoys_gpo {
const std::wstring POLICY_CONFIGURE_ENABLED_SHORTCUT_GUIDE = L"ConfigureEnabledUtilityShortcutGuide";
const std::wstring POLICY_CONFIGURE_ENABLED_TEXT_EXTRACTOR = L"ConfigureEnabledUtilityTextExtractor";
const std::wstring POLICY_CONFIGURE_ENABLED_ADVANCED_PASTE = L"ConfigureEnabledUtilityAdvancedPaste";
const std::wstring POLICY_CONFIGURE_ENABLED_CMD_PAL = L"ConfigureEnabledUtilityCmdPal";
const std::wstring POLICY_CONFIGURE_ENABLED_ZOOM_IT = L"ConfigureEnabledUtilityZoomIt";
const std::wstring POLICY_CONFIGURE_ENABLED_REGISTRY_PREVIEW = L"ConfigureEnabledUtilityRegistryPreview";
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_WITHOUT_BORDERS = L"ConfigureEnabledUtilityMouseWithoutBorders";
@@ -86,6 +89,7 @@ namespace powertoys_gpo {
const std::wstring POLICY_MWB_DISABLE_USER_DEFINED_IP_MAPPING_RULES = L"MwbDisableUserDefinedIpMappingRules";
const std::wstring POLICY_MWB_POLICY_DEFINED_IP_MAPPING_RULES = L"MwbPolicyDefinedIpMappingRules";
const std::wstring POLICY_NEW_PLUS_HIDE_TEMPLATE_FILENAME_EXTENSION = L"NewPlusHideTemplateFilenameExtension";
const std::wstring POLICY_NEW_PLUS_REPLACE_VARIABLES = L"NewPlusReplaceVariablesInTemplateFilenames";
// Methods used for reading the registry
#pragma region ReadRegistryMethods
@@ -156,16 +160,17 @@ namespace powertoys_gpo {
machine_key_found = false;
}
if(machine_key_found)
if (machine_key_found)
{
// If the path was found in the machine, we need to check if the value for the policy exists.
auto res = RegQueryValueExW(key, registry_value_name.c_str(), nullptr, nullptr, reinterpret_cast<LPBYTE>(&value), &valueSize);
RegCloseKey(key);
if (res != ERROR_SUCCESS) {
if (res != ERROR_SUCCESS)
{
// Value not found on the path.
machine_key_found=false;
machine_key_found = false;
}
}
@@ -174,7 +179,8 @@ namespace powertoys_gpo {
// If there's no value found on the machine scope, try to get it from the user scope.
if (auto res = RegOpenKeyExW(POLICIES_SCOPE_USER, POLICIES_PATH.c_str(), 0, KEY_READ, &key); res != ERROR_SUCCESS)
{
if (res == ERROR_FILE_NOT_FOUND) {
if (res == ERROR_FILE_NOT_FOUND)
{
return gpo_rule_configured_not_configured;
}
return gpo_rule_configured_unavailable;
@@ -182,7 +188,8 @@ namespace powertoys_gpo {
auto res = RegQueryValueExW(key, registry_value_name.c_str(), nullptr, nullptr, reinterpret_cast<LPBYTE>(&value), &valueSize);
RegCloseKey(key);
if (res != ERROR_SUCCESS) {
if (res != ERROR_SUCCESS)
{
return gpo_rule_configured_not_configured;
}
}
@@ -411,6 +418,11 @@ namespace powertoys_gpo {
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_ADVANCED_PASTE);
}
inline gpo_rule_configured_t getConfiguredCmdPalEnabledValue()
{
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_CMD_PAL);
}
inline gpo_rule_configured_t getConfiguredWorkspacesEnabledValue()
{
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_WORKSPACES);
@@ -501,7 +513,7 @@ namespace powertoys_gpo {
}
inline gpo_rule_configured_t getRunPluginEnabledValue(std::string pluginID)
{
{
if (pluginID == "" || pluginID == " ")
{
// this plugin id can't exist in the registry
@@ -510,7 +522,7 @@ namespace powertoys_gpo {
std::wstring plugin_id(pluginID.begin(), pluginID.end());
auto individual_plugin_setting = getPolicyListValue(POWER_LAUNCHER_INDIVIDUAL_PLUGIN_ENABLED_LIST_PATH, plugin_id);
if (individual_plugin_setting.has_value())
{
if (*individual_plugin_setting == L"0")
@@ -537,7 +549,7 @@ namespace powertoys_gpo {
{
// If no individual plugin policy exists, we check the policy with the setting for all plugins.
return getConfiguredValue(POLICY_CONFIGURE_ENABLED_POWER_LAUNCHER_ALL_PLUGINS);
}
}
}
inline gpo_rule_configured_t getAllowedAdvancedPasteOnlineAIModelsValue()
@@ -601,7 +613,7 @@ namespace powertoys_gpo {
}
else
{
return std::wstring ();
return std::wstring();
}
}
@@ -609,5 +621,11 @@ namespace powertoys_gpo {
{
return getConfiguredValue(POLICY_NEW_PLUS_HIDE_TEMPLATE_FILENAME_EXTENSION);
}
inline gpo_rule_configured_t getConfiguredNewPlusReplaceVariablesValue()
{
return getConfiguredValue(POLICY_NEW_PLUS_REPLACE_VARIABLES);
}
#pragma endregion IndividualModuleSettingPolicies
}

View File

@@ -3,7 +3,10 @@
#include <Windows.h>
#include <exception>
#include <filesystem>
#include <regex>
#include <string>
#include <optional>
#include <winrt/Windows.ApplicationModel.h>
#include <winrt/Windows.Foundation.h>
@@ -13,6 +16,11 @@
#include "../version/version.h"
namespace package {
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::ApplicationModel;
using namespace winrt::Windows::Management::Deployment;
inline BOOL IsWin11OrGreater()
{
OSVERSIONINFOEX osvi{};
@@ -38,35 +46,35 @@ namespace package {
dwlConditionMask);
}
inline bool IsPackageRegistered(std::wstring packageDisplayName)
inline std::optional<Package> GetRegisteredPackage(std::wstring packageDisplayName, bool checkVersion)
{
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Management::Deployment;
PackageManager packageManager;
for (auto const& package : packageManager.FindPackagesForUser({}))
for (const auto& package : packageManager.FindPackagesForUser({}))
{
const auto& packageFullName = std::wstring{ package.Id().FullName() };
const auto& packageVersion = package.Id().Version();
if (packageFullName.contains(packageDisplayName))
{
if (packageVersion.Major == VERSION_MAJOR && packageVersion.Minor == VERSION_MINOR && packageVersion.Revision == VERSION_REVISION)
// If checkVersion is true, verify if the package has the same version as PowerToys.
if ((!checkVersion) || (packageVersion.Major == VERSION_MAJOR && packageVersion.Minor == VERSION_MINOR && packageVersion.Revision == VERSION_REVISION))
{
return true;
return { package };
}
}
}
return false;
return {};
}
inline bool RegisterSparsePackage(std::wstring externalLocation, std::wstring sparsePkgPath)
inline bool IsPackageRegisteredWithPowerToysVersion(std::wstring packageDisplayName)
{
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Management::Deployment;
return GetRegisteredPackage(packageDisplayName, true).has_value();
}
inline bool RegisterSparsePackage(const std::wstring& externalLocation, const std::wstring& sparsePkgPath)
{
try
{
Uri externalUri{ externalLocation };
@@ -115,4 +123,174 @@ namespace package {
return false;
}
}
inline bool UnRegisterPackage(const std::wstring& pkgDisplayName)
{
try
{
PackageManager packageManager;
const static auto packages = packageManager.FindPackagesForUser({});
for (auto const& package : packages)
{
const auto& packageFullName = std::wstring{ package.Id().FullName() };
if (packageFullName.contains(pkgDisplayName))
{
auto deploymentOperation{ packageManager.RemovePackageAsync(packageFullName) };
deploymentOperation.get();
// Check the status of the operation
if (deploymentOperation.Status() == AsyncStatus::Error)
{
auto deploymentResult{ deploymentOperation.GetResults() };
auto errorCode = deploymentOperation.ErrorCode();
auto errorText = deploymentResult.ErrorText();
Logger::error(L"Unregister {} package failed. ErrorCode: {}, ErrorText: {}", packageFullName, std::to_wstring(errorCode), errorText);
}
else if (deploymentOperation.Status() == AsyncStatus::Canceled)
{
Logger::error(L"Unregister {} package canceled.", packageFullName);
}
else if (deploymentOperation.Status() == AsyncStatus::Completed)
{
Logger::info(L"Unregister {} package completed.", packageFullName);
}
else
{
Logger::debug(L"Unregister {} package started.", packageFullName);
}
break;
}
}
}
catch (std::exception& e)
{
Logger::error("Exception thrown while trying to unregister package: {}", e.what());
return false;
}
return true;
}
inline std::vector<std::wstring> FindMsixFile(const std::wstring& directoryPath, bool recursive)
{
if (directoryPath.empty())
{
return {};
}
if (!std::filesystem::exists(directoryPath))
{
Logger::error(L"The directory '" + directoryPath + L"' does not exist.");
}
const std::regex pattern(R"(^.+\.(appx|msix|msixbundle)$)", std::regex_constants::icase);
std::vector<std::wstring> matchedFiles;
try
{
if (recursive)
{
for (const auto& entry : std::filesystem::recursive_directory_iterator(directoryPath))
{
if (entry.is_regular_file())
{
const auto& fileName = entry.path().filename().string();
if (std::regex_match(fileName, pattern))
{
matchedFiles.push_back(entry.path());
}
}
}
}
else
{
for (const auto& entry : std::filesystem::directory_iterator(directoryPath))
{
if (entry.is_regular_file())
{
const auto& fileName = entry.path().filename().string();
if (std::regex_match(fileName, pattern))
{
matchedFiles.push_back(entry.path());
}
}
}
}
}
catch (const std::exception& ex)
{
Logger::error("An error occurred while searching for MSIX files: " + std::string(ex.what()));
}
return matchedFiles;
}
inline bool RegisterPackage(std::wstring pkgPath, std::vector<std::wstring> dependencies)
{
try
{
Uri packageUri{ pkgPath };
PackageManager packageManager;
// Declare use of an external location
DeploymentOptions options = DeploymentOptions::ForceApplicationShutdown;
Collections::IVector<Uri> uris = winrt::single_threaded_vector<Uri>();
if (!dependencies.empty())
{
for (const auto& dependency : dependencies)
{
try
{
uris.Append(Uri(dependency));
}
catch (const winrt::hresult_error& ex)
{
Logger::error(L"Error creating Uri for dependency: %s", ex.message().c_str());
}
}
}
IAsyncOperationWithProgress<DeploymentResult, DeploymentProgress> deploymentOperation = packageManager.AddPackageAsync(packageUri, uris, options);
deploymentOperation.get();
// Check the status of the operation
if (deploymentOperation.Status() == AsyncStatus::Error)
{
auto deploymentResult{ deploymentOperation.GetResults() };
auto errorCode = deploymentOperation.ErrorCode();
auto errorText = deploymentResult.ErrorText();
Logger::error(L"Register {} package failed. ErrorCode: {}, ErrorText: {}", pkgPath, std::to_wstring(errorCode), errorText);
return false;
}
else if (deploymentOperation.Status() == AsyncStatus::Canceled)
{
Logger::error(L"Register {} package canceled.", pkgPath);
return false;
}
else if (deploymentOperation.Status() == AsyncStatus::Completed)
{
Logger::info(L"Register {} package completed.", pkgPath);
}
else
{
Logger::debug(L"Register {} package started.", pkgPath);
}
}
catch (std::exception& e)
{
Logger::error("Exception thrown while trying to register package: {}", e.what());
return false;
}
return true;
}
}

View File

@@ -5,22 +5,22 @@ This folder contains samples of DSC files that can be used to configure PowerToy
> [!NOTE]
> PowerToys DSC user documentation can be found on [Learn Microsoft PowerToys documentation](https://aka.ms/powertoys-docs-dsc-configure).
### [configuration.dsc.yaml](./configuration.dsc.yaml)
### [configuration.winget](./configuration.winget)
Sample configuration file that changes the enabled state of some modules, changes an integer setting and a hotkey setting.
### [installAndConfiguration.dsc.yaml](./installAndConfiguration.dsc.yaml)
### [installAndConfiguration.winget](./installAndConfiguration.winget)
Installs PowerToys and applies configuration.dsc.yaml to it.
Installs PowerToys and applies configuration.winget to it.
### [enableAllModules.dsc.yaml](./enableAllModules.dsc.yaml)
### [enableAllModules.winget](./enableAllModules.winget)
Enables all PowerToys utilities.
### [disableAllModules.dsc.yaml](./disableAllModules.dsc.yaml)
### [disableAllModules.winget](./disableAllModules.winget)
Disables all PowerToys utilities.
### [configureLauncherPlugins.dsc.yaml](./configureLauncherPlugins.dsc.yaml)
### [configureLauncherPlugins.winget](./configureLauncherPlugins.winget)
Enables PowerToys Run and all its plugins and changes action keyword and global state for the Program plugin.

View File

@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft Corporation.
Licensed under the MIT License. -->
<policyDefinitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.16" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<policyDefinitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.17" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<policyNamespaces>
<target prefix="powertoys" namespace="Microsoft.Policies.PowerToys" />
</policyNamespaces>
<resources minRequiredRevision="1.16"/><!-- Last changed with PowerToys v0.89.0 -->
<resources minRequiredRevision="1.17"/><!-- Last changed with PowerToys v0.90.0 -->
<supportedOn>
<definitions>
<definition name="SUPPORTED_POWERTOYS_0_64_0" displayName="$(string.SUPPORTED_POWERTOYS_0_64_0)"/>
@@ -25,6 +25,7 @@
<definition name="SUPPORTED_POWERTOYS_0_86_0" displayName="$(string.SUPPORTED_POWERTOYS_0_86_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_88_0" displayName="$(string.SUPPORTED_POWERTOYS_0_88_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_89_0" displayName="$(string.SUPPORTED_POWERTOYS_0_89_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_90_0" displayName="$(string.SUPPORTED_POWERTOYS_0_90_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_64_0_TO_0_87_1" displayName="$(string.SUPPORTED_POWERTOYS_0_64_0_TO_0_87_1)"/>
</definitions>
</supportedOn>
@@ -106,6 +107,16 @@
<decimal value="0" />
</disabledValue>
</policy>
<policy name="ConfigureEnabledUtilityCmdPal" class="Both" displayName="$(string.ConfigureEnabledUtilityCmdPal)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityCmdPal">
<parentCategory ref="PowerToys" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_90_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="ConfigureEnabledUtilityColorPicker" class="Both" displayName="$(string.ConfigureEnabledUtilityColorPicker)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityColorPicker">
<parentCategory ref="PowerToys" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_64_0" />
@@ -671,5 +682,15 @@
<decimal value="0" />
</disabledValue>
</policy>
<policy name="NewPlusReplaceVariablesInTemplateFilenames" class="Both" displayName="$(string.NewPlusReplaceVariablesInTemplateFilenames)" explainText="$(string.NewPlusReplaceVariablesInTemplateFilenamesDescription)" key="Software\Policies\PowerToys" valueName="NewPlusReplaceVariablesInTemplateFilenames">
<parentCategory ref="NewPlus" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_90_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
</policies>
</policyDefinitions>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft Corporation.
Licensed under the MIT License. -->
<policyDefinitionResources xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.16" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<policyDefinitionResources xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.17" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<displayName>PowerToys</displayName>
<description>PowerToys</description>
<resources>
@@ -32,6 +32,7 @@
<string id="SUPPORTED_POWERTOYS_0_86_0">PowerToys version 0.86.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_88_0">PowerToys version 0.88.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_89_0">PowerToys version 0.89.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_90_0">PowerToys version 0.90.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_64_0_TO_0_87_1">From PowerToys version 0.64.0 until PowerToys version 0.87.1</string>
<string id="ConfigureAllUtilityGlobalEnabledStateDescription">This policy configures the enabled state for all PowerToys utilities.
@@ -226,6 +227,14 @@ If you enable this policy, the setting is enabled and the extension is hidden.
If you disable this policy, the setting is disabled and the extension is shown.
If you don't configure this policy, the user takes control over the setting and can enable or disable it.
</string>
<string id="NewPlusReplaceVariablesInTemplateFilenamesDescription">This policy configures if supported variables will get replaced in template filenames.
If you enable this policy, the setting is enabled and supported variables in filenames will get replaced.
If you disable this policy, the setting is disabled and variables in filenames will not get replaced.
If you don't configure this policy, the user will be able to control the setting and can enable or disable it.
</string>
<string id="ConfigureAllUtilityGlobalEnabledState">Configure global utility enabled state</string>
@@ -234,6 +243,7 @@ If you don't configure this policy, the user takes control over the setting and
<string id="ConfigureEnabledUtilityAwake">Awake: Configure enabled state</string>
<string id="ConfigureEnabledUtilityColorPicker">Color Picker: Configure enabled state</string>
<string id="ConfigureEnabledUtilityCmdNotFound">Command Not Found: Configure enabled state</string>
<string id="ConfigureEnabledUtilityCmdPal">CmdPal: Configure enabled state</string>
<string id="ConfigureEnabledUtilityCropAndLock">Crop And Lock: Configure enabled state</string>
<string id="ConfigureEnabledUtilityEnvironmentVariables">Environment Variables: Configure enabled state</string>
<string id="ConfigureEnabledUtilityFancyZones">FancyZones: Configure enabled state</string>
@@ -290,6 +300,7 @@ If you don't configure this policy, the user takes control over the setting and
<string id="NewPlusHideTemplateFilenameExtension">Hide template filename extension</string>
<string id="AllowDiagnosticData">Allow sending diagnostic data</string>
<string id="ConfigureRunAtStartup">Configure the run at startup setting</string>
<string id="NewPlusReplaceVariablesInTemplateFilenames">Replace variables in template filenames</string>
</stringTable>
<presentationTable>

View File

@@ -2,6 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Threading.Tasks;
using AdvancedPaste.Models.KernelQueryCache;

View File

@@ -0,0 +1,14 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace AdvancedPaste.UnitTests.Mocks;
internal sealed class NoOpProgress : IProgress<double>
{
public void Report(double value)
{
}
}

View File

@@ -8,6 +8,7 @@ using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using AdvancedPaste.Helpers;
@@ -131,17 +132,18 @@ public sealed class AIServiceBatchIntegrationTests
{
VaultCredentialsProvider credentialsProvider = new();
PromptModerationService promptModerationService = new(credentialsProvider);
NoOpProgress progress = new();
CustomTextTransformService customTextTransformService = new(credentialsProvider, promptModerationService);
switch (format)
{
case PasteFormats.CustomTextTransformation:
return DataPackageHelpers.CreateFromText(await customTextTransformService.TransformTextAsync(batchTestInput.Prompt, batchTestInput.Clipboard));
return DataPackageHelpers.CreateFromText(await customTextTransformService.TransformTextAsync(batchTestInput.Prompt, batchTestInput.Clipboard, CancellationToken.None, progress));
case PasteFormats.KernelQuery:
var clipboardData = DataPackageHelpers.CreateFromText(batchTestInput.Clipboard).GetView();
KernelService kernelService = new(new NoOpKernelQueryCacheService(), credentialsProvider, promptModerationService, customTextTransformService);
return await kernelService.TransformClipboardAsync(batchTestInput.Prompt, clipboardData, isSavedQuery: false);
return await kernelService.TransformClipboardAsync(batchTestInput.Prompt, clipboardData, isSavedQuery: false, CancellationToken.None, progress);
default:
throw new InvalidOperationException($"Unexpected format {format}");

View File

@@ -6,6 +6,7 @@ using System;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using AdvancedPaste.Helpers;
@@ -130,7 +131,7 @@ public sealed class KernelServiceIntegrationTests : IDisposable
private async Task<DataPackageView> GetKernelOutputAsync(string prompt, DataPackage input)
{
var output = await _kernelService.TransformClipboardAsync(prompt, input.GetView(), isSavedQuery: false);
var output = await _kernelService.TransformClipboardAsync(prompt, input.GetView(), isSavedQuery: false, CancellationToken.None, new NoOpProgress());
Assert.AreEqual(1, _eventListener.SemanticKernelEvents.Count);
Assert.IsTrue(_eventListener.SemanticKernelTokens > 0);

View File

@@ -0,0 +1,109 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AdvancedPaste.Helpers;
using AdvancedPaste.Models;
using AdvancedPaste.UnitTests.Mocks;
using ManagedCommon;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Windows.Storage;
using Windows.Storage.FileProperties;
namespace AdvancedPaste.UnitTests.ServicesTests;
[TestClass]
public sealed class TranscodeHelperIntegrationTests
{
private sealed record class MediaProperties(BasicProperties Basic, MusicProperties Music, VideoProperties Video);
private const string InputRootFolder = @"%USERPROFILE%\AdvancedPasteTranscodeMediaTestData";
/// <summary> Tests transforming a folder of media files.
/// - Verifies that the output file has the same basic properties (e.g. duration) as the input file.
/// - Copies the output file to a subfolder of the input folder for manual inspection.
/// </summary>
[TestMethod]
[DataRow(@"audio", PasteFormats.TranscodeToMp3)]
[DataRow(@"video", PasteFormats.TranscodeToMp4)]
public async Task TestTransformFolder(string inputSubfolder, PasteFormats format)
{
var inputFolder = Environment.ExpandEnvironmentVariables(Path.Combine(InputRootFolder, inputSubfolder));
if (!Directory.Exists(inputFolder))
{
Assert.Inconclusive($"Skipping tests for {inputFolder} as it does not exist");
}
var outputPath = Path.Combine(inputFolder, $"test_output_{format}");
foreach (var inputPath in Directory.EnumerateFiles(inputFolder))
{
await RunTestTransformFileAsync(inputPath, outputPath, format);
}
}
private async Task RunTestTransformFileAsync(string inputPath, string finalOutputPath, PasteFormats format)
{
Logger.LogDebug($"Running {nameof(RunTestTransformFileAsync)} for {inputPath}/{format}");
Directory.CreateDirectory(finalOutputPath);
var inputPackage = await DataPackageHelpers.CreateFromFileAsync(inputPath);
var inputProperties = await GetPropertiesAsync(await StorageFile.GetFileFromPathAsync(inputPath));
var outputPackage = await TransformHelpers.TransformAsync(format, inputPackage.GetView(), CancellationToken.None, new NoOpProgress());
var outputItems = await outputPackage.GetView().GetStorageItemsAsync();
Assert.AreEqual(1, outputItems.Count);
var outputFile = outputItems.Single() as StorageFile;
Assert.IsNotNull(outputFile);
var outputProperties = await GetPropertiesAsync(outputFile);
AssertPropertiesMatch(format, inputProperties, outputProperties);
await outputFile.CopyAsync(await StorageFolder.GetFolderFromPathAsync(finalOutputPath), outputFile.Name, NameCollisionOption.ReplaceExisting);
await outputPackage.GetView().TryCleanupAfterDelayAsync(TimeSpan.Zero);
}
private static void AssertPropertiesMatch(PasteFormats format, MediaProperties inputProperties, MediaProperties outputProperties)
{
Assert.IsTrue(outputProperties.Basic.Size > 0);
Assert.AreEqual(inputProperties.Music.Title, outputProperties.Music.Title);
Assert.AreEqual(inputProperties.Music.Album, outputProperties.Music.Album);
Assert.AreEqual(inputProperties.Music.Artist, outputProperties.Music.Artist);
AssertDurationsApproxEqual(inputProperties.Music.Duration, outputProperties.Music.Duration);
if (format == PasteFormats.TranscodeToMp4)
{
Assert.AreEqual(inputProperties.Video.Title, outputProperties.Video.Title);
AssertDurationsApproxEqual(inputProperties.Video.Duration, outputProperties.Video.Duration);
var inputVideoDimensions = GetNormalizedDimensions(inputProperties.Video);
if (inputVideoDimensions != null)
{
Assert.AreEqual(inputVideoDimensions, GetNormalizedDimensions(outputProperties.Video));
}
}
}
private static async Task<MediaProperties> GetPropertiesAsync(StorageFile file) =>
new(await file.GetBasicPropertiesAsync(), await file.Properties.GetMusicPropertiesAsync(), await file.Properties.GetVideoPropertiesAsync());
private static void AssertDurationsApproxEqual(TimeSpan expected, TimeSpan actual) =>
Assert.AreEqual(expected.Ticks, actual.Ticks, delta: TimeSpan.FromSeconds(1).Ticks);
/// <summary>
/// Gets the dimensions of a video, if available. Accounts for the fact that the dimensions may sometimes be swapped.
/// </summary>
private static (uint Width, uint Height)? GetNormalizedDimensions(VideoProperties properties) =>
properties.Width == 0 || properties.Height == 0
? null
: (Math.Max(properties.Width, properties.Height), Math.Min(properties.Width, properties.Height));
}

View File

@@ -69,6 +69,10 @@
<PackageReference Include="WinUIEx" />
<!-- HACK: To make sure the version pulled in by Microsoft.Extensions.Hosting is current. -->
<PackageReference Include="System.Text.Json" />
<!-- This line forces the WebView2 version used by Windows App SDK to be the one we expect from Directory.Packages.props . -->
<PackageReference Include="Microsoft.Web.WebView2" />
<!-- HACK: CmdPal uses CommunityToolkit.Common directly. Align the version. -->
<PackageReference Include="CommunityToolkit.Common" />
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>

View File

@@ -28,6 +28,7 @@
Background="Transparent"
BorderThickness="4"
CornerRadius="{TemplateBinding CornerRadius}"
IsHitTestVisible="False"
Visibility="Collapsed">
<!-- CornerRadius needs to be > 0 -->
<Grid.BorderBrush>

View File

@@ -178,17 +178,36 @@
Padding="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Image
x:Name="AIGlyphImage"
AutomationProperties.AccessibilityView="Raw"
Source="/Assets/AdvancedPaste/SemanticKernel.svg"
Visibility="{Binding DataContext.IsAdvancedAIEnabled, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BoolToVisibilityConverter}}" />
<PathIcon
x:Name="AIGlyph"
AutomationProperties.AccessibilityView="Raw"
Data="M128 766q0-42 24-77t65-48l178-57q32-11 61-30t52-42q50-50 71-114l58-179q13-40 48-65t78-26q42 0 77 24t50 65l58 177q21 66 72 117 49 50 117 72l176 58q43 14 69 48t26 80q0 41-25 76t-64 49l-178 58q-66 21-117 72-32 32-51 73t-33 84-26 83-30 73-45 51-71 20q-42 0-77-24t-49-65l-58-178q-8-25-19-47t-28-43q-34-43-77-68t-89-41-89-27-78-29-55-45-21-75zm1149 7q-76-29-145-53t-129-60-104-88-73-138l-57-176-67 176q-18 48-42 89t-60 78q-34 34-76 61t-89 43l-177 57q75 29 144 53t127 60 103 89 73 137l57 176 67-176q37-97 103-168t168-103l177-57zm-125 759q0-31 20-57t49-36l99-32q34-11 53-34t30-51 20-59 20-54 33-41 58-16q32 0 59 19t38 50q6 20 11 40t13 40 17 38 25 34q16 17 39 26t48 18 49 16 44 20 31 32 12 50q0 33-18 60t-51 38q-19 6-39 11t-41 13-39 17-34 25q-24 25-35 62t-24 73-35 61-68 25q-32 0-59-19t-38-50q-6-18-11-39t-13-41-17-40-24-33q-18-17-41-27t-47-17-49-15-43-20-30-33-12-54zm583 4q-43-13-74-30t-55-41-40-55-32-74q-12 41-29 72t-42 55-55 42-71 31q81 23 128 71t71 129q15-43 31-74t40-54 53-40 75-32z"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Visibility="{Binding DataContext.IsAdvancedAIEnabled, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BoolToInvertedVisibilityConverter}}" />
<ProgressRing
Width="30"
Height="30"
HorizontalAlignment="Right"
VerticalAlignment="Center"
IsActive="{Binding DataContext.IsBusy, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}"
IsIndeterminate="{Binding DataContext.HasIndeterminateTransformProgress, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Maximum="100"
Minimum="0"
Visibility="{Binding DataContext.IsBusy, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BoolToVisibilityConverter}}"
Value="{Binding DataContext.TransformProgress, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
<StackPanel
Margin="0"
Padding="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Visibility="{Binding DataContext.IsBusy, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BoolToInvertedVisibilityConverter}}">
<Image
x:Name="AIGlyphImage"
AutomationProperties.AccessibilityView="Raw"
Source="/Assets/AdvancedPaste/SemanticKernel.svg"
Visibility="{Binding DataContext.IsAdvancedAIEnabled, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BoolToVisibilityConverter}}" />
<PathIcon
x:Name="AIGlyph"
AutomationProperties.AccessibilityView="Raw"
Data="M128 766q0-42 24-77t65-48l178-57q32-11 61-30t52-42q50-50 71-114l58-179q13-40 48-65t78-26q42 0 77 24t50 65l58 177q21 66 72 117 49 50 117 72l176 58q43 14 69 48t26 80q0 41-25 76t-64 49l-178 58q-66 21-117 72-32 32-51 73t-33 84-26 83-30 73-45 51-71 20q-42 0-77-24t-49-65l-58-178q-8-25-19-47t-28-43q-34-43-77-68t-89-41-89-27-78-29-55-45-21-75zm1149 7q-76-29-145-53t-129-60-104-88-73-138l-57-176-67 176q-18 48-42 89t-60 78q-34 34-76 61t-89 43l-177 57q75 29 144 53t127 60 103 89 73 137l57 176 67-176q37-97 103-168t168-103l177-57zm-125 759q0-31 20-57t49-36l99-32q34-11 53-34t30-51 20-59 20-54 33-41 58-16q32 0 59 19t38 50q6 20 11 40t13 40 17 38 25 34q16 17 39 26t48 18 49 16 44 20 31 32 12 50q0 33-18 60t-51 38q-19 6-39 11t-41 13-39 17-34 25q-24 25-35 62t-24 73-35 61-68 25q-32 0-59-19t-38-50q-6-18-11-39t-13-41-17-40-24-33q-18-17-41-27t-47-17-49-15-43-20-30-33-12-54zm583 4q-43-13-74-30t-55-41-40-55-32-74q-12 41-29 72t-42 55-55 42-71 31q81 23 128 71t71 129q15-43 31-74t40-54 53-40 75-32z"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Visibility="{Binding DataContext.IsAdvancedAIEnabled, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BoolToInvertedVisibilityConverter}}" />
</StackPanel>
</StackPanel>
</Viewbox>
<ScrollViewer
@@ -572,6 +591,24 @@
Duration="0:0:0.167" />
</animations:Implicit.HideAnimations>
</Button>
<Button
x:Name="CancelBtn"
x:Uid="CancelBtnAutomation"
Padding="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ui:VisualExtensions.NormalizedCenterPoint="0.5,0.5"
Command="{x:Bind CancelPasteActionCommand}"
Content="{ui:FontIcon Glyph=&#xE711;,
FontSize=16}"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
IsEnabled="False"
Style="{StaticResource SubtleButtonStyle}"
Visibility="Collapsed">
<ToolTipService.ToolTip>
<TextBlock x:Uid="CancelBtnToolTip" TextWrapping="WrapWholeWords" />
</ToolTipService.ToolTip>
</Button>
<!-- Transparent overlay to show tooltip -->
<Grid
x:Name="SendBtnOverlay"
@@ -679,6 +716,10 @@
<Setter Target="Loader.IsLoading" Value="True" />
<Setter Target="InputTxtBox.IsEnabled" Value="False" />
<Setter Target="SendBtn.IsEnabled" Value="False" />
<Setter Target="SendBtn.Visibility" Value="Collapsed" />
<Setter Target="SendBtnOverlay.Visibility" Value="Collapsed" />
<Setter Target="CancelBtn.IsEnabled" Value="True" />
<Setter Target="CancelBtn.Visibility" Value="Visible" />
<Setter Target="DisclaimerPresenter.Visibility" Value="Collapsed" />
<Setter Target="LoadingText.Visibility" Value="Visible" />
</VisualState.Setters>

View File

@@ -55,9 +55,9 @@ namespace AdvancedPaste.Controls
private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(ViewModel.Busy) || e.PropertyName == nameof(ViewModel.PasteActionError))
if (e.PropertyName is nameof(ViewModel.IsBusy) or nameof(ViewModel.PasteActionError))
{
var state = ViewModel.Busy ? "LoadingState" : ViewModel.PasteActionError.HasText ? "ErrorState" : "DefaultState";
var state = ViewModel.IsBusy ? "LoadingState" : ViewModel.PasteActionError.HasText ? "ErrorState" : "DefaultState";
VisualStateManager.GoToState(this, state, true);
}
}
@@ -78,6 +78,9 @@ namespace AdvancedPaste.Controls
[RelayCommand]
private async Task GenerateCustomAIAsync() => await ViewModel.ExecuteCustomAIFormatFromCurrentQueryAsync(PasteActionSource.PromptBox);
[RelayCommand]
private async Task CancelPasteActionAsync() => await ViewModel.CancelPasteActionAsync();
private async void InputTxtBox_KeyDown(object sender, Microsoft.UI.Xaml.Input.KeyRoutedEventArgs e)
{
if (e.Key == Windows.System.VirtualKey.Enter && InputTxtBox.Text.Length > 0 && ViewModel.IsCustomAIAvailable)

View File

@@ -24,6 +24,7 @@ namespace AdvancedPaste
{
private readonly WindowMessageMonitor _msgMonitor;
private readonly IUserSettings _userSettings;
private readonly OptionsViewModel _optionsViewModel;
private bool _disposedValue;
@@ -32,8 +33,7 @@ namespace AdvancedPaste
InitializeComponent();
_userSettings = App.GetService<IUserSettings>();
var optionsViewModel = App.GetService<OptionsViewModel>();
_optionsViewModel = App.GetService<OptionsViewModel>();
var baseHeight = MinHeight;
var coreActionCount = PasteFormat.MetadataDict.Values.Count(metadata => metadata.IsCoreAction);
@@ -43,7 +43,7 @@ namespace AdvancedPaste
double GetHeight(int maxCustomActionCount) =>
baseHeight +
new PasteFormatsToHeightConverter().GetHeight(coreActionCount + _userSettings.AdditionalActions.Count) +
new PasteFormatsToHeightConverter() { MaxItems = maxCustomActionCount }.GetHeight(optionsViewModel.IsCustomAIServiceEnabled ? _userSettings.CustomActions.Count : 0);
new PasteFormatsToHeightConverter() { MaxItems = maxCustomActionCount }.GetHeight(_optionsViewModel.IsCustomAIServiceEnabled ? _userSettings.CustomActions.Count : 0);
MinHeight = GetHeight(1);
Height = GetHeight(5);
@@ -52,9 +52,9 @@ namespace AdvancedPaste
UpdateHeight();
_userSettings.Changed += (_, _) => UpdateHeight();
optionsViewModel.PropertyChanged += (_, e) =>
_optionsViewModel.PropertyChanged += (_, e) =>
{
if (e.PropertyName == nameof(optionsViewModel.IsCustomAIServiceEnabled))
if (e.PropertyName == nameof(_optionsViewModel.IsCustomAIServiceEnabled))
{
UpdateHeight();
}
@@ -111,8 +111,9 @@ namespace AdvancedPaste
GC.SuppressFinalize(this);
}
private void WindowEx_Closed(object sender, Microsoft.UI.Xaml.WindowEventArgs args)
private async void WindowEx_Closed(object sender, Microsoft.UI.Xaml.WindowEventArgs args)
{
await _optionsViewModel.CancelPasteActionAsync();
Hide();
args.Handled = true;
}

View File

@@ -4,10 +4,14 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AdvancedPaste.Models;
using ManagedCommon;
using Microsoft.Win32;
using Windows.ApplicationModel.DataTransfer;
using Windows.Data.Html;
using Windows.Graphics.Imaging;
@@ -18,8 +22,6 @@ namespace AdvancedPaste.Helpers;
internal static class DataPackageHelpers
{
private static readonly Lazy<HashSet<string>> ImageFileTypes = new(GetImageFileTypes());
private static readonly (string DataFormat, ClipboardFormat ClipboardFormat)[] DataFormats =
[
(StandardDataFormats.Text, ClipboardFormat.Text),
@@ -27,6 +29,14 @@ internal static class DataPackageHelpers
(StandardDataFormats.Bitmap, ClipboardFormat.Image),
];
private static readonly Lazy<(ClipboardFormat Format, HashSet<string> FileTypes)[]> SupportedFileTypes =
new(() =>
[
(ClipboardFormat.Image, GetImageFileTypes()),
(ClipboardFormat.Audio, GetMediaFileTypes("audio")),
(ClipboardFormat.Video, GetMediaFileTypes("video")),
]);
internal static DataPackage CreateFromText(string text)
{
DataPackage dataPackage = new();
@@ -57,9 +67,12 @@ internal static class DataPackageHelpers
{
availableFormats |= ClipboardFormat.File;
if (ImageFileTypes.Value.Contains(file.FileType))
foreach (var (format, fileTypes) in SupportedFileTypes.Value)
{
availableFormats |= ClipboardFormat.Image;
if (fileTypes.Contains(file.FileType))
{
availableFormats |= format;
}
}
}
}
@@ -93,6 +106,60 @@ internal static class DataPackageHelpers
return availableFormats == ClipboardFormat.Text ? !string.IsNullOrEmpty(await dataPackageView.GetTextAsync()) : availableFormats != ClipboardFormat.None;
}
internal static async Task TryCleanupAfterDelayAsync(this DataPackageView dataPackageView, TimeSpan delay)
{
try
{
var tempFile = await GetSingleTempFileOrNullAsync(dataPackageView);
if (tempFile != null)
{
await Task.Delay(delay);
Logger.LogDebug($"Cleaning up temporary file with extension [{tempFile.Extension}] from data package after delay");
tempFile.Delete();
if (NormalizeDirectoryPath(tempFile.Directory?.Parent?.FullName) == NormalizeDirectoryPath(Path.GetTempPath()))
{
tempFile.Directory?.Delete();
}
}
}
catch (Exception ex)
{
Logger.LogError("Failed to clean up temporary files", ex);
}
}
private static async Task<FileInfo> GetSingleTempFileOrNullAsync(this DataPackageView dataPackageView)
{
if (!dataPackageView.Contains(StandardDataFormats.StorageItems))
{
return null;
}
var storageItems = await dataPackageView.GetStorageItemsAsync();
if (storageItems.Count != 1 || storageItems.Single() is not StorageFile file)
{
return null;
}
FileInfo fileInfo = new(file.Path);
var tempPathDirectory = NormalizeDirectoryPath(Path.GetTempPath());
var directoryPaths = new[] { fileInfo.Directory, fileInfo.Directory?.Parent }
.Where(directory => directory != null)
.Select(directory => NormalizeDirectoryPath(directory.FullName));
return directoryPaths.Contains(NormalizeDirectoryPath(Path.GetTempPath())) ? fileInfo : null;
}
private static string NormalizeDirectoryPath(string path) =>
Path.GetFullPath(new Uri(path).LocalPath)
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
.ToUpperInvariant();
internal static async Task<string> GetTextOrEmptyAsync(this DataPackageView dataPackageView) =>
dataPackageView.Contains(StandardDataFormats.Text) ? await dataPackageView.GetTextAsync() : string.Empty;
@@ -153,4 +220,27 @@ internal static class DataPackageHelpers
BitmapDecoder.GetDecoderInformationEnumerator()
.SelectMany(di => di.FileExtensions)
.ToHashSet(StringComparer.InvariantCultureIgnoreCase);
private static HashSet<string> GetMediaFileTypes(string mediaKind)
{
static string AssocQueryString(NativeMethods.AssocStr assocStr, string extension)
{
uint pcchOut = 0;
NativeMethods.AssocQueryString(NativeMethods.AssocF.None, assocStr, extension, null, null, ref pcchOut);
StringBuilder pszOut = new((int)pcchOut);
var hResult = NativeMethods.AssocQueryString(NativeMethods.AssocF.None, assocStr, extension, null, pszOut, ref pcchOut);
return hResult == NativeMethods.HResult.Ok ? pszOut.ToString() : string.Empty;
}
var comparison = StringComparison.OrdinalIgnoreCase;
var extensions = from extension in Registry.ClassesRoot.GetSubKeyNames()
where extension.StartsWith('.')
where AssocQueryString(NativeMethods.AssocStr.PerceivedType, extension).Equals(mediaKind, comparison) ||
AssocQueryString(NativeMethods.AssocStr.ContentType, extension).StartsWith($"{mediaKind}/", comparison)
select extension;
return extensions.ToHashSet(StringComparer.InvariantCultureIgnoreCase);
}
}

View File

@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AdvancedPaste.Models;
@@ -17,6 +18,8 @@ internal static class KernelExtensions
private const string DataPackageKey = "DataPackage";
private const string LastErrorKey = "LastError";
private const string ActionChainKey = "ActionChain";
private const string CancellationTokenKey = "CancellationToken";
private const string ProgressKey = "Progress";
internal static DataPackageView GetDataPackageView(this Kernel kernel)
{
@@ -40,6 +43,14 @@ internal static class KernelExtensions
internal static void SetDataPackageView(this Kernel kernel, DataPackageView dataPackageView) => kernel.Data[DataPackageKey] = dataPackageView;
internal static CancellationToken GetCancellationToken(this Kernel kernel) => kernel.Data.TryGetValue(CancellationTokenKey, out object value) ? (CancellationToken)value : CancellationToken.None;
internal static void SetCancellationToken(this Kernel kernel, CancellationToken cancellationToken) => kernel.Data[CancellationTokenKey] = cancellationToken;
internal static IProgress<double> GetProgress(this Kernel kernel) => kernel.Data.TryGetValue(ProgressKey, out object obj) ? obj as IProgress<double> : null;
internal static void SetProgress(this Kernel kernel, IProgress<double> progress) => kernel.Data[ProgressKey] = progress;
internal static Exception GetLastError(this Kernel kernel) => kernel.Data.TryGetValue(LastErrorKey, out object obj) ? obj as Exception : null;
internal static void SetLastError(this Kernel kernel, Exception error) => kernel.Data[LastErrorKey] = error;

View File

@@ -4,6 +4,7 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace AdvancedPaste.Helpers
{
@@ -83,6 +84,68 @@ namespace AdvancedPaste.Helpers
Scancode = 0x0008,
}
public enum HResult
{
Ok = 0x0000,
False = 0x0001,
InvalidArguments = unchecked((int)0x80070057),
OutOfMemory = unchecked((int)0x8007000E),
NoInterface = unchecked((int)0x80004002),
Fail = unchecked((int)0x80004005),
ExtractionFailed = unchecked((int)0x8004B200),
ElementNotFound = unchecked((int)0x80070490),
TypeElementNotFound = unchecked((int)0x8002802B),
NoObject = unchecked((int)0x800401E5),
Win32ErrorCanceled = 1223,
Canceled = unchecked((int)0x800704C7),
ResourceInUse = unchecked((int)0x800700AA),
AccessDenied = unchecked((int)0x80030005),
}
[Flags]
public enum AssocF
{
None = 0,
Init_NoRemapCLSID = 0x1,
Init_ByExeName = 0x2,
Open_ByExeName = 0x3,
Init_DefaultToStar = 0x4,
Init_DefaultToFolder = 0x8,
NoUserSettings = 0x10,
NoTruncate = 0x20,
Verify = 0x40,
RemapRunDll = 0x80,
NoFixUps = 0x100,
IgnoreBaseClass = 0x200,
}
public enum AssocStr
{
Command = 1,
Executable,
FriendlyDocName,
FriendlyAppName,
NoOpen,
ShellNewValue,
DDECommand,
DDEIfExec,
DDEApplication,
DDETopic,
InfoTip,
QuickTip,
TileInfo,
ContentType,
DefaultIcon,
ShellExtension,
PerceivedType,
DelegateExecute,
SupportedUriProtocols,
ProgId,
AppId,
AppPublisher,
AppIconReference,
}
[DllImport("user32.dll")]
internal static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
@@ -100,5 +163,8 @@ namespace AdvancedPaste.Helpers
[DllImport("user32.dll")]
internal static extern bool GetCursorPos(out PointInter lpPoint);
[DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern HResult AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string pszExtra, [Out] StringBuilder pszOut, [In][Out] ref uint pcchOut);
}
}

View File

@@ -4,6 +4,7 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Windows.Globalization;
@@ -15,11 +16,14 @@ namespace AdvancedPaste.Helpers;
public static class OcrHelpers
{
public static async Task<string> ExtractTextAsync(SoftwareBitmap bitmap)
public static async Task<string> ExtractTextAsync(SoftwareBitmap bitmap, CancellationToken cancellationToken)
{
var ocrLanguage = GetOCRLanguage() ?? throw new InvalidOperationException("Unable to determine OCR language");
cancellationToken.ThrowIfCancellationRequested();
var ocrEngine = OcrEngine.TryCreateFromLanguage(ocrLanguage) ?? throw new InvalidOperationException("Unable to create OCR engine");
cancellationToken.ThrowIfCancellationRequested();
var ocrResult = await ocrEngine.RecognizeAsync(bitmap);
return string.IsNullOrWhiteSpace(ocrResult.Text)

Some files were not shown because too many files have changed in this diff Show More