Compare commits

...

97 Commits

Author SHA1 Message Date
leileizhang
b62f642184 [Hot Fix] Fix Image Resizer not working on Win10 (#43763)
<!-- 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
Windows 10 can’t launch the app using the Sparse Package. Remove the app
manifest so that Image Resizer can start properly on Windows 10.

We will figure out how to support Sparse Packages on Windows 10 in the
next release.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #43747 #43734 #43722 #43759
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-24 11:04:30 +08:00
leileizhang
5367e77a9c [Hotfix] Remove the properties in Prompt Execution Settings for OpenAI (#43766)
<!-- 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
Remove the properties in Prompt Execution Settings for OpenAI, as the
new models may not support them.

Will try to expose them in the UI so users can add them on their own in
the next release.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-24 11:04:21 +08:00
Kai Tao
1c3a6ffe63 Advanced Paste: Adjust model parameter to make the result longer (#43768)
<!-- 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
Adjust model parameter to make the result longer
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-24 11:04:11 +08:00
Dave Rayment
3d63d499da [Awake] Fix issue with timed mode not expiring correctly (#43785)
<!-- 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
Resolves an issue with the timed mode's expiry not completing correctly.

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

- [x] Closes: #43775
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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
This was because of my recent change to the timed mode. The `Subscribe`
method on the `Observable` interval accidentally wired the completion
logic to the **Error** handler instead of the **Completion** handler
because of the use of a discard `_` instead of an empty parameter list
`()`. As a result of the incorrect overload being called, Awake stayed
in the Timed state despite the timer reaching zero.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Confirmed that the timed mode times out and exits upon expiry.
2025-11-24 11:03:54 +08:00
Kai Tao
bd2967806f Advanced Paste: No cache for foundry local model list (#43716)
<!-- 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
Cache of the downloaded model will make the newly added model only work
after running of powertoys, this disable the cache, so just downloaded
model will take effect immediately

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

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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
Validated locally
2025-11-24 11:03:29 +08:00
Niels Laute
068cccc22b Loc bug (#43685)
<!-- 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

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

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-19 10:34:08 +08:00
Niels Laute
1f0603fb2b Logo change 2025-11-19 10:27:14 +08:00
Niels Laute
374dccc475 Update FoundryLocal.svg (#43682)
<!-- 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

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

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-19 08:22:20 +08:00
Leilei Zhang
64113a1ca9 fix oobe 2025-11-18 13:21:54 +08:00
Kai Tao
d858dcc1bb Advanced Paste: Refresh environment if foundry is not present (#43662)
<!-- 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
As title
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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

[12:55:29.6763496] [Info] FoundryClient.cs::CreateAsync::23
    [FoundryClient] First attempt failed, refreshing PATH and retrying
[12:55:29.6766491] [Info] FoundryClient.cs::RefreshEnvironmentPath::225
    [FoundryClient] Refreshing PATH environment variable from system
[12:55:29.6768710] [Info] FoundryClient.cs::RefreshEnvironmentPath::266
    [FoundryClient] Updating process PATH with latest system values
[12:55:29.6769080] [Info] FoundryClient.cs::TryCreateClientAsync::33
    [FoundryClient] Creating Foundry Local client
[12:55:29.6769312] [Info] FoundryClient.cs::TryCreateClientAsync::45
[FoundryClient] Starting Foundry service using
manager.StartServiceAsync()
[12:55:29.9807668] [Info] FoundryClient.cs::TryCreateClientAsync::48
    [FoundryClient] Foundry service started successfully


Verified, fist launch successfully
2025-11-18 13:01:13 +08:00
Niels Laute
3539041b72 [AP] Adding a single scrollviewer and fixing hidden tabstop (#43660)
<!-- 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

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

- [x] Closes: #43655
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-18 10:32:10 +08:00
Jiří Polášek
d9b1ca0fd8 Setup: Hide apps in PowerToys.SpareApps package from Start Menu (#43650)
<!-- 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

This PR updates the Appx manifest for PowerToys.SpareApps to hide the
apps from the Start Menu, as they lack proper visual elements like icons
and text.

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

- [x] Closes: #43647
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-18 10:32:04 +08:00
Jiří Polášek
883ec9c815 Settings: Add ScrollViewer to Command Palette page in PowerToys Settings (#43649) 2025-11-18 10:31:56 +08:00
Dave Rayment
4b1f54fff9 Fix module list glitches and Sort Status checkmark issue. 2025-11-18 09:11:15 +08:00
Kai Tao
d130f3596d cmdpal: Fix launch by button in settings not work (#43634)
<!-- 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
Shell does not know it's a protocol, so add protocol to it.


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

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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
Locally verified
2025-11-17 12:59:52 +08:00
vanzue
fdd0832eb2 Sign added dll 2025-11-17 08:51:12 +08:00
Niels Laute
fcff4bc056 [AP] Loc fix (#43617)
<!-- 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

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

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-16 22:14:29 +08:00
Niels Laute
cb542079ff [CmdPal] Settings page refresh (#43487)
- Refreshed the CmdPal page.
- CmdPal can now also be activated from this page by clicking a button
- Added a Preview InfoBar for FL in AP

<img width="1384" height="1067" alt="image"
src="https://github.com/user-attachments/assets/f670e13b-5b4a-4f6a-bcb0-e1dc357afb1e"
/>

## Summary of the Pull Request

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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

---------

Co-authored-by: vanzue <vanzue@outlook.com>
2025-11-16 22:14:21 +08:00
Kai Tao
ea94bcdd6e Advanced paste: Add more error handle for foundry local (#43600)
<!-- 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
Foundry local sdk will not run models that is not in catalog, when
catalog removes some, the old ones will fail executing,
so add error hint for users to re-configure the models in settings.

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

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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
<img width="864" height="216" alt="image"
src="https://github.com/user-attachments/assets/654207b3-ff50-4888-a638-82136216de7b"
/>
2025-11-16 22:14:14 +08:00
Michael Jolley
cd467785f2 CmdPal: Adding page Id to OpenPage telemetry event (#43584)
@niels9001 requested this.

As the name says
2025-11-15 21:11:18 +08:00
Jaylyn Barbee
b79b7f7bf6 [Light Switch] Removed logs from every tick, only logging key events. (#43572)
Title
2025-11-15 21:11:11 +08:00
Mario Hewardt
6ab7e878eb Fixes regressions introduced with GIF support (#43589)
<!-- 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)?
-->
## Fixes regressions introduced with GIF support:
- Switches default recording format back to MP4
- Fixes framerate issues between the two formats
- Fixes file path names

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

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x ] **Communication:** I've discussed this with core contributors
already. If the 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
- Switches default recording format back to MP4
- Fixes framerate issues between the two formats
- Fixes file path names
- 
<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Manual testing
2025-11-15 09:38:36 +08:00
Shawn Yuan
064484c77c Remove unused properties in AP (#43564)
<!-- 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
This pull request removes legacy provider configuration migration logic
and associated data structures from the Advanced Paste AI provider
settings. The changes simplify the codebase by eliminating support for
legacy provider configuration snapshots and related migration methods,
focusing configuration management on the current provider model.

## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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

---------

Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2025-11-14 17:02:08 +08:00
leileizhang
60c886f817 Remove all AdvancedPaste stored keys during uninstall (#43563)
<!-- 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
Remove all AdvancedPaste stored keys during uninstall
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-14 16:19:32 +08:00
Kai Tao
db41c5a65c Hide cursor wrap (#43562)
<!-- 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

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

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-14 15:51:19 +08:00
Niels Laute
8f87058508 [CursorWRap] Revert the shortcut removal (#43537)
See title
2025-11-13 22:40:08 +08:00
Niels Laute
755c138723 [Advanced Paste] Localization (#43536)
More strings to loc, and re-ordering a few settings.
2025-11-13 22:39:56 +08:00
Kai Tao
8b066cea2e Advanced paste: Tweak Foundry Local Displayed Model and start server if server is turned on when using AP (#43529)
<!-- 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
1. Foundry local model name should not prefixed by fl://
2. If foundry service is shutdown, we should not just fail it, we should
start it then call FL to make availability better.

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

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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
Verified locally:
1. Manually disable foundry local service, then run AP with foundry
local, it can return result instead of direct failure.
2. 
<img width="659" height="294" alt="image"
src="https://github.com/user-attachments/assets/113da451-7131-4ce7-ae82-0ccf772ad8aa"
/>
<img width="988" height="192" alt="image"
src="https://github.com/user-attachments/assets/aa3650ba-668a-40c4-ad8a-303e09000dd4"
/>
![Uploading image.png…]()
2025-11-13 20:06:48 +08:00
Shawn Yuan
2d92ccdf3b Fix advanced paste migration issue (#43524)
<!-- 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
This pull request refactors how legacy AI enablement settings are
migrated and simplifies the handling of legacy properties in the
settings UI. The main improvements are in the migration logic and the
removal of legacy extension data handling.


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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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

Signed-off-by: Shawn Yuan <shuai.yuan.zju@gmail.com>
2025-11-13 20:06:36 +08:00
leileizhang
83ea0c2f28 Refine AdvancedPaste Terms UI and add default system prompt for Advanced AI (#43526)
<!-- 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
1. when no terms and Privacy links don't show the infobar
<img width="349" height="127" alt="image"
src="https://github.com/user-attachments/assets/b7eeeabf-365f-45f6-adb4-56335c14e8ad"
/>
<img width="410" height="217" alt="image"
src="https://github.com/user-attachments/assets/15e053c4-738d-4bb4-9544-24bdf8a5a584"
/>


2. add add default system prompt for Advanced AI

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-13 20:06:25 +08:00
Jiří Polášek
cb81a99c5f CmdPal: Change captitalization of "Last position" item (#43518)
## Summary of the Pull Request

This PR updates the capitalization of the drop-down item from "Last
Position" to "Last position" to align with the guidelines.

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-13 20:06:05 +08:00
vanzue
48a3f4fa87 Merge remote-tracking branch 'origin/main' into stable 2025-11-13 12:52:38 +08:00
Dave Rayment
9f95d9b477 [ZoomIt] Fix screenshot save accuracy issue and GDI object leak (#43375)
<!-- 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
This fixes two issues with the ZoomIt screenshot save function:

- The "actual size" saved bitmap was recomputed from the zoomed-in
viewport, leading to artefacts and a non-1:1 pixel accurate output if
smooth mode was active.
- Two bitmap objects were not deleted after being selected, leading to a
leak of 1 or 2 GDI objects per screenshot save operation.

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

- [x] Closes: #43323
- [x] Closes: #43352
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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
### GDI object leak
In the prior code, bitmap objects were created:

```cpp
            // Capture the screen before displaying the save dialog
            hInterimSaveDc = CreateCompatibleDC( hdcScreen );
            hInterimSaveBitmap = CreateCompatibleBitmap( hdcScreen, copyWidth, copyHeight );
            SelectObject( hInterimSaveDc, hInterimSaveBitmap );
...
                    hSaveBitmap = CreateCompatibleBitmap( hdcScreen, saveWidth, saveHeight );
                    SelectObject( hSaveDc, hSaveBitmap );
```

but were not deleted in the clean-up:

```cpp
            DeleteDC( hInterimSaveDc );
            DeleteDC( hSaveDc );
```

Deleting their associated device contexts orphans the bitmaps and the
GDI objects will not be recovered until ZoomIt is closed.

### Fix
The code now uses RAII for handles to DCs and Bitmaps, e.g.:

```cpp
                    wil::unique_hdc hdcZoomed( CreateCompatibleDC(hdcScreen) );
                    wil::unique_hbitmap hbmZoomed(
                        CreateCompatibleBitmap( hdcScreen, copyWidth, copyHeight ) );
                    SelectObject( hdcZoomed.get(), hbmZoomed.get() );
```

The handles are automatically cleaned up when the variables go out of
scope.

The existing `DeleteDC` code has been removed.

### Screenshot Actual Size save issue

ZoomIt's save screenshot routine operated on the currently-displayed
view, i.e. the zoomed-in viewport, executing a copy of the full monitor
resolution image to begin:

```cpp
            StretchBlt( hInterimSaveDc,
                        0, 0,
                        copyWidth, copyHeight,
                        hdcScreen,
                        monInfo.rcMonitor.left + copyX,
                        monInfo.rcMonitor.top + copyY,
                        copyWidth, copyHeight,
                        SRCCOPY|CAPTUREBLT );
```
(Here hdcScreen represents the zoomed-in image.)

When "Actual size" was selected by the user, this bitmap was scaled back
down to attempt to reproduce the 1:1 pixel source:

```cpp
                    StretchBlt( hSaveDc,
                                0, 0,
                                saveWidth, saveHeight,
                                hInterimSaveDc,
                                0,
                                0,
                                copyWidth, copyHeight,
                                SRCCOPY | CAPTUREBLT );
				
                    SavePng( targetFilePath, hSaveBitmap );
```

This mostly works if the smooth mode is not applied because the zoom
levels tend to produce integer zoomed pixel sizes, although it still
produces inexact results at times.

The main issue is that the new smooth mode produces a halftone-smoothed
output on the display. Attempting to scale this back down to a
pixel-accurate source removes high frequency detail and does not reflect
the underlying bitmap:

Original source:
<img width="523" height="186" alt="image"
src="https://github.com/user-attachments/assets/7a6dca02-8608-44ed-917f-c6fd1a7b112c"
/>

"Actual size" save result before fix:
<img width="524" height="211" alt="image"
src="https://github.com/user-attachments/assets/29c63018-1e8d-4e74-a572-3615686aaa61"
/>

### Fix

This fix reverses the prior logic. Instead of using the zoomed-in
viewport as the screenshot source, we start by blitting a copy of the
source bitmap itself, from `hdcScreenCompat`. If a zoomed screenshot is
required, this is used as the source of the resize, i.e. we replicate
the zoom the user sees in their viewport.

This approach:

- Is faster and saves memory. It removes the need for an initial
`StretchBlt` operation, and the working bitmap itself is significantly
smaller if the user is zoomed in.
- Saves on the second resize operation if "Actual size" is chosen. We
can simply save the copy as-is.
- Removes the need to care about monitor coords. All calculations are
relative to the top-left of the source bitmap copy.
- Simplifies the code. In addition to being able to remove some code,
locality is improved - the creation of the zoomed image (and the
application of smoothing, if required) is now immediately next to where
it is saved.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

(Manual validation on standalone ZoomIt build.)

- Confirmed that "Actual size" screenshots are now 1:1 copies of the
underlying bitmap, not scaled copies of the screen display.
- Confirmed that screenshots no longer leak GDI objects in either
"Zoomed" or "Actual size" modes.
- Tested cropped and non-cropped saves, i.e. using
<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>S</kbd> versus
<kbd>Ctrl</kbd>+<kbd>S</kbd>.
- Tested that user-added drawing/text was preserved in screenshots.
- Tested that both smooth and non-smooth zoom modes operate as they did
previously.
- Tested on multiple monitors, including a high-DPI external monitor
running at 175% scaling.

---------

Co-authored-by: Leilei Zhang <leilzh@microsoft.com>
2025-11-13 12:51:54 +08:00
Kai Tao
6c05e44680 Merge remote-tracking branch 'origin/main' into stable 2025-11-13 10:39:32 +08:00
Niels Laute
8fc43e1a22 [CursorWrap] Simplifying settings (#43496)
Removed the shortcut settings based on feedback

<img width="1028" height="249" alt="image"
src="https://github.com/user-attachments/assets/6ffdca64-9c2d-4398-aa77-7116be41f0ca"
/>

---------

Co-authored-by: Leilei Zhang <leilzh@microsoft.com>
2025-11-13 10:33:29 +08:00
Shawn Yuan
42ebf8d992 Fix AP system prompt textbox display issue (#43486)
<!-- 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
This pull request refactors how the system prompt is managed and
displayed in the Advanced Paste settings UI. The main improvements
center around normalizing the system prompt value, ensuring placeholder
prompts are handled consistently, and updating the logic for switching
between advanced and simple AI modes. These changes help prevent
placeholder text from being mistakenly saved as a custom system prompt
and improve maintainability.

**System prompt normalization and placeholder handling:**

* Added static normalization for both `AdvancedAISystemPrompt` and
`SimpleAISystemPrompt`, and introduced logic to clear the system prompt
if it matches a placeholder value. This prevents default placeholder
text from being persisted as a custom prompt.
[[1]](diffhunk://#diff-14126907329c7fcd49dd33bab32283296c7dd68ddc3902163a482a3b3ce58d36R39-R40)
[[2]](diffhunk://#diff-14126907329c7fcd49dd33bab32283296c7dd68ddc3902163a482a3b3ce58d36R942-R982)
* Refactored event handlers to use the new normalization logic and
updated the placeholder switching mechanism when toggling between
advanced and simple AI modes.
* Ensured system prompt normalization is applied when saving provider
configuration, further enforcing consistent prompt handling.

**UI improvements:**

* Removed hard-coded placeholder text from the XAML, ensuring that the
placeholder is now dynamically set based on the current mode and
normalized prompt value.
* Updated the logic for setting the system prompt textbox placeholder to
use the new normalization and mode detection methods, improving clarity
and reducing potential user confusion.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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

Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2025-11-13 10:19:43 +08:00
Kai Tao
76b6a25ac4 New info badge for cursor wrap and Advanced paste Tweak (#43490)
<!-- 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
1. New info badge for cursor wrap
2. Advanced paste UI string localization
3. Add ShowPreviewPane Setting to determine whether show the advanced
paste preview

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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
<img width="451" height="247" alt="image"
src="https://github.com/user-attachments/assets/920b4b8a-f1f9-4848-b140-3295ff347fdc"
/>

<img width="470" height="383" alt="image"
src="https://github.com/user-attachments/assets/3978ebec-e695-4036-99a8-abf1561d9a28"
/>

<img width="1136" height="392" alt="image"
src="https://github.com/user-attachments/assets/0d474fcf-49a4-4cc7-b849-0231a95d9ea7"
/>
2025-11-13 10:18:13 +08:00
leileizhang
1c646ecb2a Add more detailed telemetry for AdvancedPaste (#43498)
<!-- 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
Added telemetry to capture the following:

- PasteAI: endpoint, model name, and processing time
- PasteAI Errors
- Advanced AI: endpoint, model name, and token usage
- Advanced AI Errors

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-13 10:09:50 +08:00
Jaylyn Barbee
a51b2647d9 [Light Switch] Fixed issue where number boxes in select location dialog were sometimes not updating (#43514)
<!-- 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
Ensure that even if the user enters the same values the correct buttons
are enabled and the dialog shows the correct info.

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

- [x] Closes: #43511
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Localization:** All end-user-facing strings can be localized
2025-11-13 09:51:34 +08:00
Niels Laute
b41ed2feb1 Minor styling tweaks in README (#43494)
Added a section for utilities and updated installation instructions.

<!-- 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

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-13 09:36:49 +08:00
Niels Laute
1b742ef817 [AP] Settings UI improvements (#43488)
## Summary of the Pull Request

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-13 09:32:25 +08:00
Leon Zandman
2a40e1ce4d Minor ZoomIt fixes (#43495)
## Summary of the Pull Request
Regarding #43265 / #43266, I noticed some minor spelling mistakes. I
also refactored some literal strings to string constants.

I didn't discuss this with core contributors or @MarioHewardt. Just a
quick shot-from-the-hip PR ;-) I hope that isn't a problem...

_Note: this is a new Pull Request for this change. I had to close the
previous one (#43443), because I had made a commit using a wrong Github
account._

## PR Checklist

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-13 09:32:05 +08:00
Trevor
b015d6a778 Update onenote png icons to new core10 design (#43506)
<!-- 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 the oneNote pngs to October Core 10 icon design 

MSNews article:
https://www.msn.com/en-us/technology/software/microsoft-s-new-office-icons-are-more-curvy-and-colorful/ar-AA1NFYYI

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

- [x] Closes: #43507
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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
- [x] **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-11-12 20:28:31 +01:00
Mike Hall
3bfa0a0cf8 Update CursorWrap settings (#43492)
## Summary of the Pull Request
Modify CursorWrap settings so that 'Activate on Startup' is enabled when
CursorWrap is enabled. Disabling CursorWrap doesn't change the 'Activate
on Startup' toggle, this will need to be manually disabled, CursorWrap
is active when enabled, the hotkey can be used to temporarily disable
the CursorWrap functionality.

## PR Checklist

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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

## Validation Steps Performed
Manual validation performed on desktop PC and Surface Laptop.
2025-11-12 18:52:34 +08:00
Shawn Yuan
5884375e9d Fix advanced paste settings migration issue (#43459)
<!-- 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
This pull request introduces a robust migration system for legacy
Advanced Paste AI provider settings and credentials, refactoring both
the migration logic and credential handling to be more maintainable and
reliable. It also standardizes the default model names for AI providers
and updates related UI placeholders to reflect these changes. The
migration logic is now centralized in a new helper class, and legacy
credential migration is handled more cleanly in both the settings and
view model layers.

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

- [x] Closes: #43456
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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

---------

Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
Signed-off-by: Shawn Yuan <shuai.yuan.zju@gmail.com>
2025-11-12 16:24:21 +08:00
Shawn Yuan
a0a2f493c5 remove debug launching (#43485)
<!-- 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
This pull request simplifies the application launch logic in
`App.xaml.cs` by removing debug-specific code paths and asynchronous
window initialization. The main change is to standardize the launch
process for both debug and release builds.

**Launch logic simplification:**

* Removed the `#if DEBUG` conditional compilation around the
`OnLaunched` method, so the method signature is now consistent in all
build configurations.
* Eliminated the asynchronous call to `ShowWindow()` that was previously
executed only in debug mode, streamlining the launch behavior and
removing direct window access during debugging.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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

---------

Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2025-11-12 15:21:00 +08:00
Kai Tao
5e3e0660e7 Revert hybrid crt to make powertoys quit safely (#43484)
<!-- 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
After enabling Hybrid CRT, the PowerToys process failed to properly
unload some module interface DLLs when quit application. The root cause
is still unclear, but this change reverts the behavior to ensure safe
unloading.

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

- [ ] Closes: #43413
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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
Can unload dll safely when quit powertoys
2025-11-12 10:39:21 +08:00
Kai Tao
6505cd7a63 Revert "Hybrid CRT for powertys (#42073)"
This reverts commit c71fdca277.
2025-11-12 10:09:52 +08:00
Jaylyn Barbee
29688cea0e [Light Switch] Enter latitude and longitude manually in Sunrise to sunset mode (#43276)
<!-- 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
This PR introduces new UI to allow the users to manually enter their
lat/long.

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

- [x] Closes: #42429
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Localization:** All end-user-facing strings can be localized
- [x] **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:
#[5979](https://github.com/MicrosoftDocs/windows-dev-docs-pr/pull/5979)

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
2025-11-11 16:18:18 -05:00
Alex Mihaiuc
a0f33c8af1 Make zooming animation smooth for ZoomIt on mouse move (#42339)
This change coalesces the `WM_MOUSEMOVE` events with the `WM_TIMER`
events in the cases 1, 2 (telescope animation for zoom in, respectively,
out). I factored into a new lambda the `WM_TIMER` code and I made it
save the "now" amount of ticks into the new `g_TelescopingZoomLastTick`.

During `WM_MOUSEMOVE` processing, if the current tick count (rather
imprecise, but good enough) is larger than the animation step,
`ZOOM_LEVEL_STEP_TIME`, then I call that lambda. It's convenient that
the code in there already handles the "end of telescope zooming
animation" case.

## Validation Steps Performed

The choppy zooming animation was evident while moving the mouse during a
telescope zoom. It was also [reported on the Sysinternals
blog](https://techcommunity.microsoft.com/blog/sysinternals-blog/zoomit-v9-10-procdump-3-5-for-linux-and-jcd-1-0-1/4461244/replies/4461281).
2025-11-11 09:42:59 -06:00
leileizhang
e1edcc13b7 Fix the issue where the InstallLocation is missing after upgrading (#43462)
<!-- 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
**Root Cause**

The issue occurs because the Installed property in MSI indicates whether
the current product code has been installed on the machine.
During a Major Upgrade (where the old and new versions have different
ProductCode values), the installation sequence is:
1. Burn schedules uninstall of the old MSI (the old version might not
have this custom action).
2. Then installs the new MSI.
> - At this point, the current product has not yet been installed, so
the Installed property is empty.
> - The condition NOT Installed evaluates to true, and
SetBundleInstallLocationData / SetBundleInstallLocation executes
normally, writing the InstallLocation registry key.

This means upgrading from an older version without this function to a
newer version with it works correctly.
However, issues appear in subsequent upgrades (from “newer” → “newer”)
because both versions include the same custom action.
The previous condition restricted the action to run only on first
install, preventing it from running during upgrades.

**Fix**

Added `OR WIX_UPGRADE_DETECTED` to the condition of
SetBundleInstallLocationData / SetBundleInstallLocation custom actions,
so they also execute during upgrade scenarios, ensuring the
InstallLocation registry value is correctly updated after version
upgrades.

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

- [x] Closes: #43451
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-11 20:07:58 +08:00
leileizhang
756feb9f8c Clean up unused providers for AdvancedPaste (#43433)
<!-- 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
Clean up unused providers for AdvancedPaste

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

- [x] Closes: #43429
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-11 20:07:41 +08:00
leileizhang
2fff688c6f [CI] Fix Win10 New+ build: add local Generated Files include path (#43461)
<!-- 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
This PR (#43361) tries to fix the CI failure, and the root cause is
correct. However, using ;$(MSBuildThisFileDirectory)Generated Files
causes the include path to become \Generated Files\Generated
Files\resource.h. Removing Generated Files fixes the issue so that cl
can find the correct file.

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-11 20:07:26 +08:00
Kai Tao
24d7ae54ce Find my mouse: Fix the issue find my mouse xaml island could not be run in x64 environment (#43420)
<!-- 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
This pull request introduces a configuration update to the
`src/runner/runner.vcxproj` project file. The change enables undocked,
registration-free WinRT initialization for the Windows App SDK, which
can improve compatibility and reduce dependency issues in certain
deployment scenarios.

Windows App SDK configuration:

* Enabled `WindowsAppSdkUndockedRegFreeWinRTInitialize` to allow
registration-free WinRT initialization in the project file
`runner.vcxproj`.

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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
Validate in x64 environment, and it can be run without problem, no
errors any more
2025-11-11 09:34:50 +08:00
Mario Hewardt
a271a2f8af Enable GIF support for ZoomIt (#43266)
Closes #43265
2025-11-10 13:57:13 -06:00
Michael Jolley
a33c484c93 CmdPal: Removing app tag from apps (#43439)
The "App" tag is pretty redundant and is adding a lot of visual noise.
Closes #38968

New:

![image](https://github.com/user-attachments/assets/5eff195c-5aaf-477a-b988-4b3b14583569)
2025-11-10 20:03:36 +01:00
Niels Laute
f20c3b832b Asset updates (#43431)
title
2025-11-10 19:04:16 +01:00
Mike Griese
9c2884ab41 CmdPal: Bump version to 0.7 (#43428)
title
2025-11-10 10:38:55 -06:00
Jiří Polášek
076828f592 CmdPal: Remove duplicate HideWindow call in MainWindow .ctor (#43360)
## Summary of the Pull Request

Refer to the title. Calling this here will just log an error. Another
HideWindow is at the end of the constructor, so the behavior remains
unchanged.

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-10 10:38:22 -06:00
Niels Laute
301d504db1 • instead of . in README (#43353)
<!-- 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

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-10 06:18:27 -06:00
moooyo
e4a8488a2a [PowerRename] Fix FuzzTest project configuration issue (#43299)
<!-- 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
This PR add the missing configuration for FuzzTest to avoid build issue
in local env.

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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

Co-authored-by: Yu Leng <yuleng@microsoft.com>
2025-11-10 11:40:39 +08:00
leileizhang
93bf653f9c [CI] Fix Win10 New+ build: add local Generated Files include path (#43361)
<!-- 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
**The CI frequently fails due to this issue**
<img width="1094" height="139" alt="image"
src="https://github.com/user-attachments/assets/b69aa417-b25c-4396-a863-32e8a31415e9"
/>
<img width="1249" height="183" alt="image"
src="https://github.com/user-attachments/assets/14f57ada-4b3c-4a70-9e6b-17d7162cece4"
/>

**Fix**
make NewPlus.ShellExtension.win10.vcxproj include its own Generated
Files folder so autogenerated resource.h is always found
prevents CI failures when the Win10 module builds before the shared
NewPlus project has produced headers

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-08 01:06:48 +08:00
Jiří Polášek
b7eed480ba Spellchecking: Update spell-checking dictionary (#42294)
## Summary of the Pull Request

This PR updates the spell-checking dictionaries to fix outstanding
errors, and also clears up accumulated warnings.

- Cleans up duplicate or ignored entries in expect.txt:
    - `Authenticode` (favoring existing `authenticode`)
    - `DTo` (favoring existing `dto`)
    - `ekus` (favoring existing `eku`)
    - `nullrefs` (favoring existing `nullref`)
- Removes `CursorWrap` (invalid entry since camel case is treated as
separate words and is not allowed)
- Updates the pattern for `amazon.com` URLs to allow them within C#
strings
- Explicitly excludes the CmdPal sample page for images in Markdown with
Base64 encoded data from spell-checking (was previously auto-excluded)
- Suppresses spell-checking on lines with URLs containing encoded data

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-07 13:55:51 +01:00
Leon Zandman
dce61bcb9d Fix Awake's popup context menu positioning (#41009)
<!-- 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
Fix for issue #37457. The Awake popup context menu would show at the
wrong position, especially after adding additional displays. The reason
this happened was that the mouse cursor position was unnecessarily
converted from screen to to client-area coordinates.

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

- [x] Closes: #37457
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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
Ran Awake and its context menu seemed to display properly and at the
correct position.

---------

Co-authored-by: Leon Zandman <lzandman@rdw.nl>
2025-11-07 12:50:45 +08:00
Dustin L. Howett
056328823f build: remove SHINE pool image override (to enable Server 2022) (#43287)
I am changing the default build pool image from Windows Server 2019 to
Server 2022, as the 2019 images are deprecated and their use will become
a permanent error soon.

However, I cannot do that while PowerToys contains build image
overrides. These overrides prevent it from choosing the Server 2022
images.

As a drive-by, I fixed the following issues:

- `NUGET_PACKAGES` was being read from the ambient environment. It was
used in the package cache _and_ in the WIX projects directly (!). To
make the build more predictable, we now set it during build time.
- We _still_ had build step conditions that resulted in extra work being
done during build failure.
- The release builds now produce numbered failure log artifacts just
like the CI builds do.
- I have adjusted the default disk configuration to give enough space to
`C:\`, so we no longer need the work directory override or custom data
disk.

The screenshot below is from a test run where I overrode the pool image
to be `SHINE-VS17-Latest-2022`. We do not want to do that in the final
configuration, so I had to revert that change.

<img width="1205" height="452" alt="image"
src="https://github.com/user-attachments/assets/fcf03e8c-d2a1-47af-9240-64c183c43644"
/>
2025-11-07 09:05:24 +08:00
Niels Laute
73f789b062 Settings fix (#43348)
<!-- 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

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-06 12:48:27 -05:00
Jiří Polášek
57f0b4b342 CmdPal: Improve crash error message (#43340)
## Summary of the Pull Request

This PR localizes the message displayed when an unhandled exception
causes CmdPal to crash. It also resolves a regression from commit
a991a118dc, which disabled storing to the desktop but failed to
update the corresponding message.

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

- [x] Related to: #41392
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-06 11:32:56 -06:00
Dave Rayment
0e922a4dcb [ImageResizer] Fix issue where settings could be changed during a batch resize (#42163)
<!-- 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
This fixes an issue where the Image Resizer settings were reloaded for
every resize operation in a multi-file batch. This could result in
inconsistent resize results if the Settings application or the user
interacted with the settings and the properties were changed, even
temporarily.

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

- [x] Closes: #42116, #35114
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **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
Corrects an issue in `ResizeBatch.Execute()` where `Settings.Default`
was used:

```csharp
    protected virtual void Execute(string file)
        => new ResizeOperation(file, DestinationDirectory, Settings.Default).Execute();
```

Unfortunately, `Settings.Default` is poorly named, and is not a constant
property. Instead it actually calls `Reload()`, which loads the settings
JSON file and re-processes it fully:

```csharp
        [JsonIgnore]
        public static Settings Default
        {
            get
            {
                defaultInstance.Reload();
                return defaultInstance;
            }
        }
```

If the settings are changed part-way through a resize batch operation
(even scrolling through the presets will set `selectedIndex` and save it
back to disk), the batch resize operation may switch to a different
resize behaviour, giving inconsistent results. The chances of this
occurring increase with the length of the batch operation.

### Solution
The solution is to set the `Settings` outside of the main loop and use
that for every resize operation, which is what this PR does.

`Process` is altered to load the `Settings` at the start and pass that
to `Execute` on each iteration of the batch loop:

```csharp
        public IEnumerable<ResizeError> Process(Action<int, double> reportProgress, CancellationToken cancellationToken)
        {
            double total = Files.Count;
            int completed = 0;
            var errors = new ConcurrentBag<ResizeError>();
            var settings = Settings.Default;

            ...

                        Execute(file, settings);
```

`Execute` is updated to accept a `Settings` object instead of using
`Settings.Default`:

```csharp
    protected virtual void Execute(string file, Settings settings)
        => new ResizeOperation(file, DestinationDirectory, settings).Execute();
```

### Additional changes
The batch-related unit tests failed after the above change. I updated
the Mock `Execute` to reflect the use of the `Settings` parameter. Also,
the `Settings` class was unfortunately bound to the WPF UI, and could
not be instantiated during unit testing. I've refactored this so it can
be instantiated with or without an `App.Current.Dispatcher`. Ther's a
new `ReloadCore()` method which just contains the extracted property
setting code.

None of the unit tests currently use the settings themselves, but at
least the capability is now there.

I also removed the setting of the `MaxDegreeOfParallelism` option in the
`Parallel.For()`. When left at its default, the runtime will use the
appropriate number of threads, and the heuristic it uses may not
necessarily equal the number of processor cores in the system.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
- Ensured all existing unit tests passed.
- Tested with multiple runs of resizing 200 image files while browsing
and changing the settings. This was no longer able to alter the ongoing
resize operations.
- Checked that the settings could still be amended via the Settings app.

---------

Co-authored-by: Gordon Lam (SH) <yeelam@microsoft.com>
2025-11-06 19:55:47 +08:00
Juju Anselum J
d7785977d8 feat(quick-accent): add diameter ⌀ symbol for Shift+O #41954 (#42963)
## Summary of the Pull Request
- Adds support for the diameter symbol (⌀, U+2300) in Quick Accent. 
- When holding Shift+O with the Special Characters language enabled.

## Implementation
- Updated GetDefaultLetterKeySPECIAL(LetterKey.VK_O) to include ⌀.
- No impact on other existing functionalities.

## Issue
Closes  #41954
2025-11-06 19:55:30 +08:00
Copilot
bb604d87ca Fix accessibility: Associate controls with labels for screen readers (#42439)
## Problem

Input controls (ComboBoxes, ToggleSwitches, NumberBoxes) within
SettingsCards throughout the PowerToys Settings UI were not
programmatically associated with their visible labels. This caused
screen readers to announce only the control type (e.g., "combo box",
"toggle switch") without any context about the control's purpose, making
the settings inaccessible to screen reader users.

This violates WCAG 2.2 Success Criterion 1.3.1 (Info and Relationships)
- Level A requirement.

**User Impact**: Screen reader users navigating PowerToys settings would
hear only "edit text" or "combo box" with no description, making it
difficult or impossible to configure settings independently.

## Solution

Added `AutomationProperties.Name` bindings to controls, linking them to
their parent SettingsCard's `Header` property. This establishes the
programmatic relationship between labels and controls required by
assistive technologies.

### Pattern Applied

For controls inside SettingsCards with a `Name` attribute:

```xaml
<tkcontrols:SettingsCard Name="LanguageHeader" x:Uid="LanguageHeader">
    <ComboBox
        MinWidth="{StaticResource SettingActionControlMinWidth}"
        AutomationProperties.Name="{Binding ElementName=LanguageHeader, Path=Header}"
        DisplayMemberPath="Language"
        ItemsSource="{Binding Languages, Mode=TwoWay}"
        SelectedIndex="{Binding LanguagesIndex, Mode=TwoWay}" />
</tkcontrols:SettingsCard>
```

For data templates where headers are data-bound:

```xaml
<DataTemplate x:Key="ComboBoxTemplate" x:DataType="viewModels:PluginAdditionalOptionViewModel">
    <tkcontrols:SettingsCard Header="{x:Bind Path=DisplayLabel}">
        <ComboBox
            AutomationProperties.Name="{x:Bind Path=DisplayLabel}"
            ItemsSource="{x:Bind Path=ComboBoxItems}" />
    </tkcontrols:SettingsCard>
</DataTemplate>
```

## Changes Made

### GeneralPage.xaml (7 controls)
- Language selection ComboBox
- Color mode/theme ComboBox
- Run at startup ToggleSwitch
- Show system tray icon ToggleSwitch
- Enable experimentation ToggleSwitch
- Enable data diagnostics ToggleSwitch
- Enable view diagnostic data ToggleSwitch

### PowerLauncherPage.xaml (4 data templates)
- ComboBoxTemplate - for plugin settings
- NumberBoxTemplate - for plugin numeric settings
- CheckBoxComboBoxTemplate - for conditional ComboBox settings
- CheckBoxNumberBoxTemplate - for conditional NumberBox settings

### PowerRenamePage.xaml (6 controls)
- Enable PowerRename ToggleSwitch
- Context menu mode ComboBox
- Enable auto-complete ToggleSwitch
- Max display list number NumberBox
- Restore flags on launch ToggleSwitch
- Use Boost library ToggleSwitch

### NewPlusPage.xaml (4 controls)
- Enable New+ ToggleSwitch
- Hide file extension ToggleSwitch
- Hide starting digits ToggleSwitch
- Replace variables ToggleSwitch

## Testing

Screen readers (Windows Narrator) now properly announce controls with
context:
- **Before**: "Combo box"
- **After**: "Language, Combo box"

No functional changes to application behavior. The fix only affects how
controls are announced to assistive technologies.

## Notes

This fix follows the existing pattern already used in
ColorPickerPage.xaml. Similar issues exist in approximately 23 other
Settings pages which can be addressed in future PRs using this
established pattern. The pages fixed in this PR represent
commonly-accessed settings and demonstrate the solution approach for
comprehensive coverage.

Closes #<issue_number>

## References
- WCAG 2.2 SC 1.3.1:
https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships
- UIA Name Property:
https://learn.microsoft.com/en-us/windows/apps/design/accessibility/accessible-text-requirements#name_property_alternative_and_description

<!-- START COPILOT CODING AGENT SUFFIX -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>Controls Inside Sections Are Not Associated with Their
Labels.</issue_title>
> <issue_description>### Microsoft PowerToys version
> 
> v0.94.2
> 
> ### Installation method
> 
> PowerToys auto-update
> 
> ### Area(s) with issue?
> 
> New+
> 
> ### Steps to reproduce
> 
> **Repro Steps:**
> 
> 1. Open the Power Toys.
> 2. Now navigate to the home present in the left navigation pane.
> 3. Now turn on the narrator using CTRL + Win + Enter.
> 4. Now navigate to the controls present inside the different sections.
> 5. Observe the issue.
> 
> ### ✔️ Expected Behavior
> 
> Each control should be programmatically associated with its
corresponding label so screen readers can accurately convey the purpose
of the control to users.
> 
> ###  Actual Behavior
> 
> Input controls (e.g., checkboxes, text fields, dropdowns) located
within different sections of the UI are not programmatically associated
with their visible labels.
> 
> ### Additional Information
> 
> **User Impact:**
> Screen reader users may hear only the control type (e.g., “edit text”)
with no context or description of what it is for. This makes it
difficult or impossible for them to fill out forms or interact with the
UI correctly, leading to confusion and frustration.
> 
> **WCAG Reference:**
> https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships
> 
> **Attachments:**
> 
>
https://github.com/user-attachments/assets/d25b9237-bee7-41d5-b564-df15df19b0d4
> 
> ### Other Software
> 
> _No response_</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>

Fixes microsoft/PowerToys#42419

<!-- START COPILOT CODING AGENT TIPS -->
---

 Let Copilot coding agent [set things up for
you](https://github.com/microsoft/PowerToys/issues/new?title=+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
Co-authored-by: Gordon Lam (SH) <yeelam@microsoft.com>
2025-11-06 19:50:49 +08:00
Gleb Khmyznikov
ccaa876af2 [UI Tests] Peek - fix UI tests via setting hotkeys back to Ctrl+Space combo for tests only (#43168)
This pull request introduces a static initialization step to the
`PeekFilePreviewTests` class to ensure the correct test settings are
present before tests run. The main change is the addition of a static
constructor that creates or updates the `settings.json` file with
predefined settings, including setting the activation shortcut to
Ctrl+Space.

Test setup improvements:

* Added a static constructor to `PeekFilePreviewTests` that calls a new
`FixSettingsFileBeforeTests` method, ensuring the necessary settings
file exists and is properly configured before any tests execute.
* Implemented `FixSettingsFileBeforeTests` to create the required
directory and write a `settings.json` file with specific test
configuration, including setting the activation shortcut to Ctrl+Space
and other test-relevant properties.
2025-11-06 19:32:28 +08:00
Copilot
4a5e476a4e Fix: Add accessible name to Shortcut Conflicts button for screen readers (#42441)
## Summary
Fixes the accessibility issue where the "Shortcut Conflicts" button in
the Dashboard page has no accessible name defined, causing screen
readers to announce it as just "button" instead of providing context
about its purpose.

## Problem
The button in `ShortcutConflictControl.xaml` lacked an
`AutomationProperties.Name` attribute, violating WCAG 2.2 guidelines
(4.1.2 - Name, Role, Value). This prevented users who rely on screen
readers from determining the function of the button, making it
impossible to resolve or view shortcut conflicts.

**Before fix:**
- Screen reader announces: "button" 

**After fix:**
- Screen reader announces: "Shortcut conflicts, No conflicts found,
button" 
- Or: "Shortcut conflicts, 1 conflict found, button" 
- Or: "Shortcut conflicts, 3 conflicts found, button" 

## Solution
Added a new `AccessibleName` property to
`ShortcutConflictControl.xaml.cs` that combines:
- The static localized title: "Shortcut conflicts"
- The dynamic status text: "No conflicts found", "1 conflict found", or
"X conflicts found"

The button's `AutomationProperties.Name` is now bound to this property
using `{x:Bind AccessibleName, Mode=OneWay}`, ensuring it updates
dynamically as conflict data changes.

## Changes
- **ShortcutConflictControl.xaml**: Added `AutomationProperties.Name`
binding to the button
- **ShortcutConflictControl.xaml.cs**: Added `AccessibleName` property
and property change notification

## Impact
- Provides full context to assistive technology users about the button's
purpose and current state
- Complies with WCAG 2.2 accessibility standards
- Follows existing patterns in the codebase for accessible controls
- Minimal changes (2 files, 14 lines added)

## Related Issue
Closes #issue_number

## Testing
- [x] Code review completed with no issues
- [x] Follows existing accessibility patterns used in DashboardPage.xaml
- [x] Uses existing localized resource strings
- [x] Property updates dynamically via INotifyPropertyChanged

<!-- START COPILOT CODING AGENT SUFFIX -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>No Accessible Name Defined for "Shortcut Conflicts"
Button.</issue_title>
> <issue_description>### Microsoft PowerToys version
> 
> v0.94.2
> 
> ### Installation method
> 
> PowerToys auto-update
> 
> ### Area(s) with issue?
> 
> New+
> 
> ### Steps to reproduce
> 
> **Repro Steps:**
> 
> 1. Open power toys.
> 2. Now navigate to the home section and select.
> 3. Now turn on narrator using CTRL + Win + Enter.
> 4. Now navigate to the Shortcut conflicts button.
> 5. Observe the narrator's announcement.
> 
> ### ✔️ Expected Behavior
> 
> The button should have an accessible name — either via a visible
label, aria-label, or aria-labelledby — so that assistive technology
users understand its purpose.
> 
> ###  Actual Behavior
> 
> The "Shortcut Conflicts" button has no accessible name defined. Screen
readers announce it as “button”.
> 
> ### Additional Information
> 
> **User Impact:**
> Users who rely on screen readers cannot determine the function of the
button, making it inaccessible. This prevents users from resolving or
viewing shortcut conflicts, which could impact usability and task
completion.
> 
> **WCAG Reference:**
> https://www.w3.org/WAI/WCAG22/Understanding/name-role-value
> 
> **Attachments:**
> 
>
https://github.com/user-attachments/assets/ca0f51d3-f736-4eb9-b355-e55f2cfd5bbd
> 
> ### Other Software
> 
> _No response_</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>

Fixes microsoft/PowerToys#42418

<!-- START COPILOT CODING AGENT TIPS -->
---

 Let Copilot coding agent [set things up for
you](https://github.com/microsoft/PowerToys/issues/new?title=+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
2025-11-06 18:07:48 +08:00
Dave Rayment
5c96cea31f [Peek] Fix media sources remaining locked when Peek window is closed (#42055)
<!-- 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

Fixes an issue where audio and video files would remain locked by Peek
after the user closed the preview window. This could prevent the
ejecting of removable storage.

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

- [x] Closes: #41883
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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

When the Peek window is closed, it is hiden rather than destroyed,
allowing for quick reactivation. The cleanup process is triggered by
`MainWindowViewModel.Uninitialize()`, which eventually causes the active
`Previewer` instance in `FilePreviewer.xaml.cs` to be disposed of (via
`OnItemPropertyChanged()`).

The root cause of the bug is that neither `VideoPreviewer` nor
`AudioPreviewer` implemented `IDisposable` sufficiently to cover clean
up of the media file. The result was that the `MediaSource` object,
which holds the handle to the open media file, was not disposed
deterministically. This left the file locked until the GC eventually
finalised it.

### Solution
To fix this, I've implemented `IDisposable` on `AudioPreviewer` where it
was absent, and expanded `Dispose()` on `VideoPreviewer` to clean up the
media object. A new `Unload()` method on each previewer handles explicit
clean up of the media sources. The `Dispose()` method calls `Unload()`
to ensure the resources are released reliably when the previewer is
destroyed.

`Unload()` is deliberately public, as I'd like to expand upon its use in
a future refactoring of the previewer switching logic, allowing for
reusing an active previewer instead of creating a new one every time the
user navigates to a new file.

### AudioPreviewer refinements
I made a few updates to `AudioPreviewer` to make the lifecycle of the
media source more predictable and improve the error handling:
- The `Preview` observable property is now a nullable
`AudioPreviewData?`. This more accurately represents the state (data is
either present or not), and allows for the removal of the creation of an
empty object in the constructor.
- `thumbnailTask`'s success is no longer regarded as an error condition
in `LoadPreviewAsync`. It is reasonable to let the user play their audio
file even if the thumbnail cannot be shown.
- An error when loading the source data or metadata results in the new
`Unload()` method being called, correctly releasing the file, protecting
against the file lock issue even if the media file was corrupt and could
only be partially constructed.
- Null checks for `Preview`, obvs.

### Scope
I could repro the original issue on audio and video files, so this PR is
focused on improvements to `AudioPreviewer` and `VideoPreviewer`. I
wasn't able to reproduce the file locking problem with the
`WebBrowserPreviewer` for its built-in supported types (HTML, Markdown
and PDF). I found some additional issues with the previewer, however,
but they will be covered in a future PR.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Tests were performed with the following steps:

1. Place the audio/video file to test on a USB stick.
2. Open the file with Peek and play some of the media.
3. While previewing the media, close the Peek window.
4. Attempt to eject the USB stick via the systray.
- Before: the eject fails and Windows pops up the "File in use" dialog.
    - After: the drive is successfully removed.

I tested an MP4 video file and an MP3 audio track to confirm the fix.

I confirmed that other previewers were unaffected by previewing: JPEG
image files, a PDF, a TXT file, a Markdown file, an HTML file and a
folder. All items were successfully previewed.
2025-11-06 17:31:48 +08:00
Copilot
e7de5c7b8d Make update notification InfoBar clickable in Flyout (#42064)
## Summary

Resolves #38854 by making the "Update available" InfoBar in the tray
icon flyout clickable, providing direct navigation to the General
settings page where users can manage updates.

## Problem

When PowerToys has an available update, users experience unnecessary
navigation friction:

1. Click PowerToys tray icon → flyout opens with "Update available"
InfoBar
2. InfoBar is not clickable, only the settings wheel is interactive
3. Click settings wheel → opens Dashboard page (not where updates are
managed)
4. Navigate to General page → finally access update controls

Users requested making the "Update available" text itself a hyperlink
for direct access to update functionality.

## Solution

Made the InfoBar interactive by adding a `Tapped` event handler that:
- Hides the flyout (consistent with other flyout actions)
- Opens Settings window directly to the General page using
`App.OpenSettingsWindow(typeof(GeneralPage))`

## Changes

**Files Modified:**
- `src/settings-ui/Settings.UI/SettingsXAML/Flyout/LaunchPage.xaml`:
Added `Tapped="UpdateInfoBar_Tapped"` event
- `src/settings-ui/Settings.UI/SettingsXAML/Flyout/LaunchPage.xaml.cs`:
Added event handler and navigation logic

## User Experience

**Before:** Tray Icon → Flyout → Settings Wheel → Dashboard → Navigate
to General → Update Controls
**After:** Tray Icon → Flyout → **Click "Update available"** → General
Page → Update Controls

The InfoBar now behaves as a clickable hyperlink as requested, while
preserving all existing functionality. Users can still use the settings
wheel if preferred, but now have a more direct path to update
management.

## Testing

The implementation follows existing patterns in the codebase and uses
established APIs. The InfoBar only appears when updates are in
`ReadyToInstall` or `ReadyToDownload` states, ensuring the navigation is
contextually appropriate.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `i1qvsblobprodcus353.vsblob.vsassets.io`
>   - Triggering command: `dotnet build` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/microsoft/PowerToys/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT CODING AGENT SUFFIX -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>Taskbar icon should provide link directly to update
page</issue_title>
> <issue_description>### Description of the new feature / enhancement
> 
> Right now when there is an update the following message appears when
you click on the PT icon in the taskbar:
> 
>
![Image](https://github.com/user-attachments/assets/18641e1c-d80b-4f7e-b206-8c9a36f2de36)
> 
> When you click on the settings wheel you go to the dashboard page:
> 
>
![Image](https://github.com/user-attachments/assets/e951b988-79ab-48b3-8714-a26999223153)
> 
> Then you need to click on the Learn more button before you finally get
to the page where you can install the update:
> 
>
![Image](https://github.com/user-attachments/assets/914c9c00-a642-40da-bfb5-439c1fd930c0)
> 
> Can't you make the **_Update available_** a hyperlink or add another
button that would link directly to the General page (or wherever the
update button is) so we can quickly install the update instead of going
a roundabout way every time?
> 
>
![Image](https://github.com/user-attachments/assets/5c065eed-84ad-47be-9432-607155065a17)
> 
> ### Scenario when this would be used?
> 
> When there is an update. It's a usability annoyance more than
anything.
> 
> ### Supporting information
> 
> _No response_</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>
Fixes microsoft/PowerToys#38854

<!-- START COPILOT CODING AGENT TIPS -->
---

 Let Copilot coding agent [set things up for
you](https://github.com/microsoft/PowerToys/issues/new?title=+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
2025-11-06 16:53:32 +08:00
Shawn Yuan
d737e22d16 fixed terms & privacy link issue (#43327)
<!-- 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
This pull request updates the way legal links (Terms of Use and Privacy
Policy) are displayed for different AI providers in the AdvancedPaste
module, making them dynamic based on the currently selected provider. It
also updates the URLs for several providers to ensure accuracy and
relevance.

## PR Checklist

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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

---------

Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2025-11-06 15:04:16 +08:00
leileizhang
fabf60d18f Add DSC v3 resource discovery support in PowerToys with subfolder structure and PATH configuration (#43253)
<!-- 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

- Use DSCModules subfolder for JSON manifest files
- Use relative path "..\PowerToys.DSC.exe" in JSON manifests
- Configure PATH environment variable to point to DSCModules subfolder

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-06 12:08:41 +08:00
Jeremy Sinclair
1604b7b555 [Deps] Update .NET packages from 9.0.8 to 9.0.10 (#43295)
<!-- 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
Updates .NET 9 Runtime / Library packages to the latest 9.0.10 servicing
release for security fixes.

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-06 11:33:48 +08:00
leileizhang
7fb1cdd1ea Remove PowerToys installer path from PATH to prevent some other apps crashe (#43157)
<!-- 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
To support DSCv3, we previously added the PowerToys installer path to
the environment PATH. However, this change may cause some other
applications to crash.

This PR removes the installer path temporarily until we find a better
way to support DSCv3.

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

- [x] Closes: #42919
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-06 10:14:23 +08:00
leileizhang
05ae163eea Add back NuGet config file accidentally deleted by AdvancedPaste PR (#43312)
<!-- 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
Deleted by this https://github.com/microsoft/PowerToys/pull/42374
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-06 10:13:23 +08:00
Niels Laute
e19520e675 [CmdPal] Extension string updates (#43269)
<!-- 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

Feedback from the design team:
- Reduce any redundant or long text strings for better readability and
localization
- `Verb + noun` for most extensions
- Sentence casing according to the Windows Writing Guidelines


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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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

---------

Co-authored-by: Michael Jolley <mike@baldbeardedbuilder.com>
Co-authored-by: Jiří Polášek <me@jiripolasek.com>
2025-11-05 19:29:04 -06:00
Jiří Polášek
e2591250be CmdPal: Treat System command provider as special (#43321)
## Summary of the Pull Request

This change marks the System command provider as special, ensuring
fallback items are surfaced at the top of the list.

Additionally, the SystemCommandExtensionProvider ID has been updated to
comply with the new naming convention.

As a small cleanup, SystemCommandExtensionProvider is now sealed.

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

- [x] Related to: #42524
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-05 18:34:16 -06:00
Jaylyn Barbee
e448d731f8 [Light Switch] Refactor + cleaner behavior (#43159)
<!-- 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
This PR also includes a refactor to the light switch service. The
refactor will help me make cleaner updates in the future and makes the
"state" easier to track through the service.

## Validation
Completed the following steps as testing for normal behavior and edge
cases:

1. Start up
- Check defaults (delete settings.json files)
- Ensure PowerToys properly starts/does not start the module
- Ensure turning the module on and off starts/terminates the service
- Ensure the settings in the settings file are reflected in the front
end
2. Manual Override Activation
- Ensure that pressing the shortcut key triggers an update
- Ensure that pressing the shortcut key triggers a block in the schedule
(Should see logs Skipping schedule due to manual override)
- Ensure that changing windows settings triggers a manual override (at
the next minute)
- Ensure in both scenarios that the schedule is ignored until a boundary
is met
- Ensure that the schedule resumes following the boundary clearance.
4. New Day Detection / Sun Time Recalculation
- Keep service running past midnight (or simulate date change)
- Verify the last updated day is updated
- Verify new sun times are accurate and set in settings.
5. Coordinates / Mode Change
- Ensure that updates occur when the coordinates or mode changes. These
updates should reflect the new settings.
6. Schedule Mode OFF
- Turn the schedule off, check logs for notice
- Ensure the shortcut still works
- Ensure the schedule resumes as expected once turned back on.
8. Sleep / Hibernate Resume
- Set your schedule to change themes in the next 2 minutes.
- Send your machine to hibernate shutdown /h 
- Wake your machine after your theme should have changed and ensure
Light Switch catches itself up
- Repeat steps above but with a manual override triggered prior to the
theme change.Ensure manual override is flushed and schedule resumes.
9. Stop and Restart behavior
- Stop and restart the module. Ensure it behaves as expected. No reset
settings, etc.
2025-11-05 13:34:26 -05:00
Jiří Polášek
47c779e0a0 Run: handle DWM issues more gracefully (#42588)
## Summary of the Pull Request

This PR expands the scenarios where Run handles exceptions silently,
reducing the number of exception dialogs displayed to users and creating
a smoother experience. The premise remains unchanged: most exceptions
occur when Run is in the background, and the app can recover as the DWM
recovers.

This should cover most of the reports commonly encountered in the wild.

- Extended silent handling of DWM exceptions to include
`DWM_E_COMPOSITIONDISABLED` (0x80263001).
- Added silent handling for `STATUS_MESSAGE_LOST` error (NTSTATUS
0xC0000701, HR 0xD0000701).
- Implemented exception handling and retry logic for failures during
manual app theme changes (triggered by
`PowerLauncher.Helper.ThemeManager`).

I can't reproduce the error on its own; it only occurs alongside a fatal
render thread failure (`UCEERR_RENDERTHREADFAILURE`), which is
unrecoverable. Even if caught, the UI stops rendering, leaving the
end-user unable to proceed.

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

- [x] Related to: #31226
- [x] Related to: #30769
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-05 18:51:58 +01:00
Niels Laute
b7b6ae6485 Tweaking the focus state for AP (#43306)
Adding the AI underline to the inputbox

<img width="656" height="583" alt="image"
src="https://github.com/user-attachments/assets/998a4203-61d7-4228-a682-391c6d78b3a5"
/>
2025-11-05 21:23:17 +08:00
Dave Rayment
b5b7361855 [General] Include high-volume bugs in Issue Template header (#43134)
<!-- 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
Adds references to 3 bugs which are logged by those who are unfamiliar
with the issue search function. It is hoped that this will help ease the
amount of triaging.

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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
- Checked the YML preview on my own fork.
2025-11-05 13:26:55 +01:00
Mike Hall
cd988b798b Add Cursor Wrap functionality to Powertoys Mouse Utils (#41826)
## Summary of the Pull Request

Cursor Wrap makes it simple to move the mouse from one edge of a display
(or set of displays) to the opposite edge of the display stack - on a
single display Cursor Wrap will wrap top/bottom and left/right edges.


https://github.com/user-attachments/assets/3feb606c-142b-4dab-9824-7597833d3ba4


## PR Checklist

- [x] Closes: CursorWrap #41759
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [x] **New binaries:** Added on the required places
- [x] [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

## Detailed Description of the Pull Request / Additional comments
PR adds a new mouse utils module, this is 'Cursor Wrap' - Cursor Wrap
works with 1-9 monitors based on the logical monitor layout of the PC -
for a single monitor device the cursor is wrapped for the top/bottom and
left/right edges of the display - for a multi-monitor setup the cursor
is wrapped on the top/bottom left/right of the displays in the logical
display layout.

## Validation Steps Performed
Validation has been performed on a Surface Laptop 7 Pro (Intel) with a
single display and with an HDMI USB-C second display configured to be a
second monitor in top/left/right/bottom configuration - there are also
tests that run as part of the build to validate logical monitor layout
and cursor positioning.

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Kai Tao (from Dev Box) <kaitao@microsoft.com>
Co-authored-by: Gordon Lam (SH) <yeelam@microsoft.com>
2025-11-05 19:28:25 +08:00
Niels Laute
1ad468641b [UX] Dashboard utilities sorting (#42065)
## Summary of the Pull Request

This PR adds a sorting button to the module list so it can be sorted
alphabetically (default) or by status.

Fixes: #41837

<img width="760" height="933" alt="image"
src="https://github.com/user-attachments/assets/69c831a9-ae9e-4849-b630-772d03e4a4b1"
/>


@yeelam-gordon When running the runner, I do see the settings value is
being updated. But when running the runner again the setting doesn't
seem to be saved? Is that because of a bug in my implementation, or am I
testing it wrong :)?

<img width="286" height="86" alt="image"
src="https://github.com/user-attachments/assets/3a90997f-c40c-4f50-8361-b1ae3aa02052"
/>



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

- [x] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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

---------

Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
Co-authored-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2025-11-05 17:42:24 +08:00
Davide Giacometti
3176eb94a9 [Hosts] Backup Settings (#37778)
<!-- 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

Add backup settings for the Hosts File Editor to allow users to
customize the existing hardcoded logic.

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

- [x] **Closes:** #37666
- [ ] **Communication:** I've discussed this with core contributors
already. If work hasn't been agreed, this work might be rejected
- [x] **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)
- [x] **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:
https://github.com/MicrosoftDocs/windows-dev-docs/pull/5342

<!-- 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

<img width="707" alt="image"
src="https://github.com/user-attachments/assets/e114431e-60e0-4b8c-bba7-df23f7af0182"
/>

<img width="707" alt="image"
src="https://github.com/user-attachments/assets/a02b591e-eb46-4964-bee7-548ec175b3aa"
/>

<img width="707" alt="image"
src="https://github.com/user-attachments/assets/6eb0ff21-74fa-4229-8832-df2df877b5cd"
/>

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

- Backup on: verified that backup isn't executed
- Backups off: Verified that only one backup is executed
- Verified that backup is located in the expected path
- Auto delete is set to "never": verified that no backups are deleted
- Auto delete is set to "based on count": verified that backups are
deleted according to count value
- Auto delete is set to "based on age and count": verified that backups
are deleted according to days and count values
- Verified that files without the backup pattern aren't deleted
- There is also adequate test coverage for these scenarios 🚀

---------

Co-authored-by: Gordon Lam (SH) <yeelam@microsoft.com>
2025-11-05 16:42:31 +08:00
Antonín Procházka
31a0deee35 Peek a file using command line and named pipe. (#26422) (#38754)
This is a PoC. It adds the ability to peek a file using a named pipe and
a command line.

Usage/testing before this gets merged and released:

1. Build release configuration of Peek.UI and Peek.CLI.
2. Terminate PowerToys.Peek.UI.exe if running.
3. Back up and replace PowerToys.Peek.UI[.dll;.exe;.pdb;.pri]. Use
[Everything](https://www.voidtools.com/downloads/) to find the source
and destination folders.
4. Call `PowerToys.Peek.CLI.exe <path>` or send the path to peek to the
`PeekPipe` named pipe.

If this solution is OK, documentation and installer need to be updated
and a follow-up issue needs to be filed to support navigation.

---------

Co-authored-by: Clint Rutkas <clint@rutkas.com>
Co-authored-by: Leilei Zhang <leilzh@microsoft.com>
Co-authored-by: Gordon Lam (SH) <yeelam@microsoft.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-05 16:38:07 +08:00
Kai Tao
20b5ca79a3 light switch: Remove newinfobadge for light switch (#43300)
<!-- 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
Remove new tag for light switch

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

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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

<img width="773" height="332" alt="image"
src="https://github.com/user-attachments/assets/79f89994-8b6e-431e-a5f1-30909940e996"
/>
2025-11-05 16:36:46 +08:00
Shawn Yuan
a3b8dc6cb8 Advanced Paste: AI pasting enhancement (#42374)
<!-- 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
* Add multiple endpoint support for paste with AI
* Add Local AI support for paste AI
* Advanced AI implementation

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

- [x] Closes: #32960
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [x] **Dev docs:** Added/updated
- [x] **New binaries:** Added on the required places
- [x] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [x] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [x] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [x] [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

### GPO
- [x] Paste with AI should not be available if the original GPO for
paste AI is set to false
   - [x] Paste with AI should be controlled within endpoint granularity
- [x] Advanced Paste UI should disable AI ability if GPO is set to
disable for any llm
### Paste AI
   - [x] Every AI endpoint should work as expected
   - [x] Default prompt should be able to give a reasonable result
   - [x] Local AI should work as expected
### Advanced AI
- [x] Open AI and Azure OPENAI should be able to configure as advanced
AI endpoint
- [x] Advanced AI should be able to pick up functions correctly to do
the transformation and give reasonable result

---------

Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
Signed-off-by: Shuai Yuan <shuai.yuan.zju@gmail.com>
Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
Co-authored-by: Leilei Zhang <leilzh@microsoft.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Kai Tao <kaitao@microsoft.com>
Co-authored-by: Kai Tao <69313318+vanzue@users.noreply.github.com>
Co-authored-by: vanzue <vanzue@outlook.com>
Co-authored-by: Gordon Lam (SH) <yeelam@microsoft.com>
2025-11-05 16:13:55 +08:00
Kai Tao
c364aa7c70 Cmdpal: Bring vcruntime in cmdpal (#43255)
<!-- 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
Cmdpal has dependency on vcruntime appx package due to adaptive card,
bring that dependency in

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

- [x] Closes: #42497
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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
<img width="1873" height="1183" alt="image"
src="https://github.com/user-attachments/assets/d416d09f-f4d6-456c-a625-ca724a69b5ee"
/>

---------

Co-authored-by: Jiří Polášek <me@jiripolasek.com>
2025-11-05 09:51:25 +08:00
leileizhang
229bedd09f [UI Tests] Add complete OCR UI test coverage (#41947)
<!-- 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
* Enable Text Extractor. Then:
   - [x] Press the activation shortcut and verify the overlay appears.
   - [x] Press Escape and verify the overlay disappears.
   - [x] Press the activation shortcut and verify the overlay appears.
   - [x] Right-click and select Cancel. Verify the overlay disappears.
- [x] Disable Text Extractor and verify that the activation shortuct no
longer activates the utility.
 * With Text Extractor enabled and activated:
   - [x] Try to select text and verify it is copied to the clipboard.
- [x] Try to select a different OCR language by right-clicking and
verify the change is applied.
 * Test the different settings and verify they are applied:
   - [x] Activation shortcut
   - [x] OCR Language
 
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-11-04 11:59:10 +08:00
moooyo
70e1177a6a [PowerRename] Support using photo metadata to replace in the PowerRename (#41728)
<!-- 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
1. Introduce WIC for power rename and add new class WICMetadataExtractor
to use WIC to extract metadata.
2. Add some patterns for metadata extract.
3. Support XMP and EXIF metadata extract.
4. Add test data for xmp and exif extractor
5. Add attribution for the test data uploader.

UI:
<img width="2052" height="1415" alt="image"
src="https://github.com/user-attachments/assets/9051b12e-4e66-4fdc-a4d4-3bada661c235"
/>
<img width="284" height="170" alt="image"
src="https://github.com/user-attachments/assets/2fd67193-77a7-48f0-a5ac-08a69fe64e55"
/>
<img width="715" height="1160" alt="image"
src="https://github.com/user-attachments/assets/5fa68a8c-d129-44dd-b747-099dfbcded12"
/>

demo:


https://github.com/user-attachments/assets/e90bc206-62e5-4101-ada2-3187ee7e2039



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

- [x] Closes: #5612
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [x] **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

---------

Co-authored-by: Yu Leng <yuleng@microsoft.com>
2025-11-04 09:27:16 +08:00
Jiří Polášek
957b653210 CmdPal: Add a micro global error handler (#41392)
## Summary of the Pull Request

This PR introduces a scaled-down version of the global error handler
from #41061.

- Catches and logs virtually all unhandled exceptions.
- For UI thread exceptions, generates an additional error report:
    - One copy is saved in app's log folder for the Bug Report Tool.
- Another copy can be placed to the user’s desktop to increase
visibility and encourage report submission (disabled for now).
- Displays a message box that tells the user where to find the saved
report.

This PR is intentionally minimal and focused. The complete, more
polished solution is still planned in #41061, which should replace this
implementation in a follow-up.

<details><summary>Report example</summary>
<pre>

This is an error report generated by Windows Command Palette.
If you are seeing this message, it means the application has encountered
an unexpected issue.
You can help us fix it by filing a report at
https://aka.ms/powerToysReportBug.
============================================================
😢 An unexpected error occurred in the application.

Summary:
  Message:    NamedResource Not Found.

NamedResource Not Found.

  Type:       System.Runtime.InteropServices.COMException
  Source:     WinRT.Runtime
  Time:       2025-08-26 20:22:53.5752505
  HRESULT:    0x80073B17 (-2147009769)

Stack Trace:
at WinRT.ExceptionHelpers.<ThrowExceptionForHR>g__Throw|38_0(Int32 hr)
at
ABI.Microsoft.Windows.ApplicationModel.Resources.IResourceLoaderMethods.GetString(IObjectReference
_obj, String resourceId)
at
Microsoft.Windows.ApplicationModel.Resources.ResourceLoader.GetString(String
resourceId)
at Microsoft.CmdPal.UI.Helpers.ResourceLoaderInstance.GetString(String
resourceId)
at
Microsoft.CmdPal.UI.Settings.SettingsWindow.AnnounceNavigationPaneStateChanged(DependencyObject
sender, DependencyProperty dp)
at
ABI.Microsoft.UI.Xaml.DependencyPropertyChangedCallback.Do_Abi_Invoke(IntPtr
thisPtr, IntPtr sender, IntPtr dp)

------------------ Full Exception Details ------------------
System.Runtime.InteropServices.COMException (0x80073B17): NamedResource
Not Found.

NamedResource Not Found.

at WinRT.ExceptionHelpers.<ThrowExceptionForHR>g__Throw|38_0(Int32 hr)
at
ABI.Microsoft.Windows.ApplicationModel.Resources.IResourceLoaderMethods.GetString(IObjectReference
_obj, String resourceId)
at
Microsoft.Windows.ApplicationModel.Resources.ResourceLoader.GetString(String
resourceId)
at Microsoft.CmdPal.UI.Helpers.ResourceLoaderInstance.GetString(String
resourceId)
at
Microsoft.CmdPal.UI.Settings.SettingsWindow.AnnounceNavigationPaneStateChanged(DependencyObject
sender, DependencyProperty dp)
at
ABI.Microsoft.UI.Xaml.DependencyPropertyChangedCallback.Do_Abi_Invoke(IntPtr
thisPtr, IntPtr sender, IntPtr dp)

ℹ️ If you need further assistance, please include this information in
your support request.
ℹ️ Before sending, take a quick look to make sure it doesn't contain any
personal or sensitive information.
============================================================


</pre>
</details> 

Message:
<img width="2309" height="1341" alt="image"
src="https://github.com/user-attachments/assets/3ec20054-402f-421d-bebd-bf848a8eb504"
/>

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

- [x] Partially handles: #41606
- [ ] **Communication:** I've discussed this with core contributors
already. If the 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-10-31 12:35:37 -05:00
Dustin L. Howett
0b0ad68b60 build: build the Machine and User installers at the same time (#42888) 2025-10-31 00:28:12 -05:00
Dustin L. Howett
b87be7263d Tests: do not use *relative drive letter* (#43135)
Since we switched to running the build on C:\, this test started
failing. C: means "current directory on the C drive"!
2025-10-31 11:33:44 +08:00
396 changed files with 21533 additions and 3370 deletions

View File

@@ -7,6 +7,13 @@ body:
- type: markdown
attributes:
value: Please make sure to [search for existing issues](https://github.com/microsoft/PowerToys/issues) before filing a new one!
- type: markdown
attributes:
value: |
We are aware of the following high-volume issues and are actively working on them. Please check if your issue is one of these before filing a new bug report:
* **PowerToys Run crash related to "Desktop composition is disabled"**: This may appear as `COMException: 0x80263001`. For more details, see issue [#31226](https://github.com/microsoft/PowerToys/issues/31226).
* **PowerToys Run crash with `COMException (0xD0000701)`**: For more details, see issue [#30769](https://github.com/microsoft/PowerToys/issues/30769).
* **PowerToys Run crash with a "Cyclic reference" error**: This `System.InvalidOperationException` is detailed in issue [#36451](https://github.com/microsoft/PowerToys/issues/36451).
- id: version
type: input
attributes:

View File

@@ -321,3 +321,10 @@ REGSTR
# Misc Win32 APIs and PInvokes
INVOKEIDLIST
# PowerRename metadata pattern abbreviations (used in tests and regex patterns)
DDDD
FFF
HHH
riday
YYY

View File

@@ -105,6 +105,7 @@
^src/common/notifications/BackgroundActivatorDLL/cpp\.hint$
^src/common/sysinternals/Eula/
^src/modules/cmdpal/doc/initial-sdk-spec/list-elements-mock-002\.pdn$
^src/modules/cmdpal/ext/SamplePagesExtension/Pages/SampleMarkdownImagesPage\.cs$
^src/modules/colorPicker/ColorPickerUI/Shaders/GridShader\.cso$
^src/modules/launcher/Plugins/Microsoft\.PowerToys\.Run\.Plugin\.TimeDate/Properties/
^src/modules/MouseUtils/MouseJumpUI/MainForm\.resx$

View File

@@ -22,6 +22,7 @@ ADate
ADDSTRING
ADDUNDORECORD
ADifferent
adjacents
ADMINS
adml
admx
@@ -34,6 +35,7 @@ AFX
AGGREGATABLE
AHK
AHybrid
AIUI
akv
ALarger
ALIGNRIGHT
@@ -63,6 +65,7 @@ APIIs
Apm
APPBARDATA
APPEXECLINK
appext
APPLICATIONFRAMEHOST
appmanifest
APPMODEL
@@ -97,7 +100,7 @@ atl
ATX
ATRIOX
aumid
Authenticode
authenticode
AUTOBUDDY
AUTOCHECKBOX
AUTOHIDE
@@ -111,6 +114,9 @@ AValid
AWAYMODE
azcliversion
azman
azureaiinference
azureinference
azureopenai
bbwe
BCIE
bck
@@ -135,13 +141,14 @@ bla
BLACKFRAME
BLENDFUNCTION
Blockquotes
Blt
blt
BLURBEHIND
BLURREGION
bmi
BNumber
BODGY
BOklab
Bootstrappers
BOOTSTRAPPERINSTALLFOLDER
BOTTOMALIGN
boxmodel
@@ -169,14 +176,18 @@ BYPOSITION
CALCRECT
CALG
callbackptr
cabstr
calpwstr
caub
Cangjie
CANRENAME
Carlseibert
Canvascustomlayout
CAPTUREBLT
CAPTURECHANGED
CARETBLINKING
CAtl
CBN
cch
CCHDEVICENAME
CCHFORMNAME
@@ -199,6 +210,7 @@ CIBUILD
cidl
CIELCh
cim
claude
CImage
cla
CLASSDC
@@ -231,6 +243,7 @@ CODENAME
codereview
Codespaces
Coen
cognitiveservices
COINIT
colid
colorconv
@@ -245,6 +258,7 @@ cominterop
commandnotfound
commandpalette
compmgmt
COMPOSITIONDISABLED
COMPOSITIONFULL
CONFIGW
CONFLICTINGMODIFIERKEY
@@ -277,6 +291,7 @@ cpptools
cppvsdbg
cppwinrt
createdump
creativecommons
CREATEPROCESS
CREATESCHEDULEDTASK
CREATESTRUCT
@@ -300,6 +315,7 @@ CURRENTDIR
CURSORINFO
cursorpos
CURSORSHOWING
CURSORWRAP
customaction
CUSTOMACTIONTEST
CUSTOMFORMATPLACEHOLDER
@@ -339,6 +355,7 @@ Deact
debugbreak
decryptor
Dedup
dfx
Deduplicator
Deeplink
DEFAULTBOOTSTRAPPERINSTALLFOLDER
@@ -398,6 +415,9 @@ DNLEN
DONOTROUND
DONTVALIDATEPATH
dotnet
downsampled
downsampling
Downsampled
downscale
DPICHANGED
DPIs
@@ -413,7 +433,7 @@ DROPFILES
DSTINVERT
DString
DSVG
DTo
dto
DUMMYUNIONNAME
dutil
DVASPECT
@@ -447,7 +467,6 @@ EDITKEYBOARD
EDITSHORTCUTS
EDITTEXT
EFile
ekus
eku
emojis
ENABLEDELAYEDEXPANSION
@@ -512,6 +531,7 @@ EXTRINSICPROPERTIES
eyetracker
FANCYZONESDRAWLAYOUTTEST
FANCYZONESEDITOR
FNumber
FARPROC
fdx
fesf
@@ -543,6 +563,7 @@ FIXEDSYS
flac
flyouts
FMask
foundrylocal
fmtid
FOF
FOFX
@@ -581,6 +602,7 @@ getfilesiginforedist
geolocator
GETHOTKEY
GETICON
GETLBTEXT
GETMINMAXINFO
GETNONCLIENTMETRICS
GETPROPERTYSTOREFLAGS
@@ -588,6 +610,7 @@ GETSCREENSAVERRUNNING
GETSECKEY
GETSTICKYKEYS
GETTEXTLENGTH
GIFs
gitmodules
GHND
GMEM
@@ -598,6 +621,7 @@ GPOCA
gpp
gpu
gradians
grctlext
Gridcustomlayout
GSM
gtm
@@ -607,6 +631,8 @@ GValue
gwl
GWLP
GWLSTYLE
googleai
googlegemini
hangeul
Hanzi
Hardlines
@@ -695,6 +721,7 @@ HTCLIENT
hthumbnail
HTOUCHINPUT
HTTRANSPARENT
hutchinsoniana
HVal
HValue
Hvci
@@ -716,7 +743,9 @@ IDCANCEL
IDD
idk
idl
IIM
idlist
ifd
IDOK
IDOn
IDR
@@ -733,6 +762,7 @@ Ijwhost
ILD
IMAGEHLP
IMAGERESIZERCONTEXTMENU
IPTC
IMAGERESIZEREXT
imageresizerinput
imageresizersettings
@@ -872,6 +902,7 @@ LOCKTYPE
LOGFONT
LOGFONTW
logon
lon
LOGMSG
LOGPIXELSX
LOGPIXELSY
@@ -963,6 +994,7 @@ MENUITEMINFOW
MERGECOPY
MERGEPAINT
Metadatas
metadatamatters
metafile
mfc
Mgmt
@@ -1030,6 +1062,7 @@ msiexec
MSIFASTINSTALL
MSIHANDLE
MSIRESTARTMANAGERCONTROL
MSIs
msixbundle
MSIXCA
MSLLHOOKSTRUCT
@@ -1124,6 +1157,7 @@ nonstd
NOOWNERZORDER
NOPARENTNOTIFY
NOPREFIX
NPU
NOREDIRECTIONBITMAP
NOREDRAW
NOREMOVE
@@ -1159,8 +1193,8 @@ ntfs
NTSTATUS
NTSYSAPI
NULLCURSOR
nullref
nullonfailure
nullref
numberbox
nwc
ocr
@@ -1183,6 +1217,9 @@ opencode
OPENFILENAME
opensource
openxmlformats
ollama
Olllama
onnx
OPTIMIZEFORINVOKE
ORPHANEDDIALOGTITLE
ORSCANS
@@ -1277,6 +1314,7 @@ pnid
PNMLINK
Poc
Podcasts
Photoshop
POINTERID
POINTERUPDATE
Pokedex
@@ -1371,6 +1409,8 @@ pwsz
pwtd
QDC
qit
QNN
Qualcomm
QITAB
QITABENT
qoi
@@ -1479,6 +1519,7 @@ sacl
safeprojectname
SAMEKEYPREVIOUSLYMAPPED
SAMESHORTCUTPREVIOUSLYMAPPED
samsung
sancov
SAVEFAILED
scanled
@@ -1832,6 +1873,7 @@ UPDATENOW
UPDATEREGISTRY
updown
UPGRADINGPRODUCTCODE
upscaling
Uptool
urld
Usb
@@ -1841,6 +1883,7 @@ USEINSTALLERFORTEST
USESHOWWINDOW
USESTDHANDLES
USRDLL
utm
UType
uuidv
uwp
@@ -1917,6 +1960,7 @@ wcsicmp
wcsncpy
wcsnicmp
WCT
WCRAPI
WDA
wdm
wdp
@@ -1930,6 +1974,7 @@ wgpocpl
WHEREID
wic
wifi
wikimedia
wikipedia
WIL
winapi
@@ -1959,6 +2004,8 @@ WINL
winlogon
winmd
WINNT
windowsml
winml
winres
winrt
winsdk
@@ -2024,7 +2071,9 @@ XAxis
XButton
xclip
xcopy
xap
XDeployment
XDimension
xdf
XDocument
XElement
@@ -2042,6 +2091,7 @@ xsi
XSpeed
XStr
xstyler
xmp
XTimer
XUP
XVIRTUALSCREEN
@@ -2049,6 +2099,7 @@ xxxxxx
YAxis
ycombinator
YIncrement
YDimension
yinle
yinyue
YPels

View File

@@ -253,7 +253,7 @@ _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING
# hit-count: 1 file-count: 1
# Amazon
\bamazon\.com/[-\w]+/(?:dp/[0-9A-Z]+|)[^"'\s]+
\bamazon\.com/[-\w]+/(?:dp/[0-9A-Z]+|)
# hit-count: 3 file-count: 3
# imgur

3
.gitignore vendored
View File

@@ -349,10 +349,7 @@ src/common/Telemetry/*.etl
/src/modules/powerrename/ui/RCb24464
# Generated installer file for Monaco source files.
/installer/PowerToysSetup/MonacoSRC.wxs
/installer/PowerToysSetup/DscResources.wxs
/installer/PowerToysSetupVNext/MonacoSRC.wxs
/installer/PowerToysSetupVNext/DscResources.wxs
# MSBuildCache
/MSBuildCacheLogs/

View File

@@ -5,7 +5,6 @@
{
"MatchedPath": [
"*.resources.dll",
"WinUI3Apps\\Assets\\Settings\\Scripts\\*.ps1",
"PowerToys.ActionRunner.exe",
@@ -27,6 +26,7 @@
"PowerToys.GPOWrapper.dll",
"PowerToys.GPOWrapperProjection.dll",
"PowerToys.AllExperiments.dll",
"LanguageModelProvider.dll",
"Common.Search.dll",
@@ -181,6 +181,7 @@
"PowerToys.MousePointerCrosshairs.dll",
"PowerToys.MouseJumpUI.dll",
"PowerToys.MouseJumpUI.exe",
"PowerToys.CursorWrap.dll",
"PowerToys.MouseWithoutBorders.dll",
"PowerToys.MouseWithoutBorders.exe",
@@ -290,6 +291,7 @@
"Mono.Cecil.Rocks.dll",
"Newtonsoft.Json.dll",
"CommunityToolkit.WinUI.Controls.TitleBar.dll",
"CommunityToolkit.WinUI.Controls.OpacityMaskView.dll",
"NLog.dll",
"HtmlAgilityPack.dll",
@@ -346,6 +348,8 @@
"Testably.Abstractions.FileSystem.Interface.dll",
"WinUI3Apps\\Testably.Abstractions.FileSystem.Interface.dll",
"ColorCode.Core.dll",
"Microsoft.SemanticKernel.Connectors.Ollama.dll",
"OllamaSharp.dll",
"UnitsNet.dll",
"UtfUnknown.dll",

View File

@@ -1,53 +0,0 @@
{
"Version": "1.0.0",
"UseMinimatch": false,
"SignBatches": [
{
"MatchedPath": [
"PowerToysSetupCustomActionsVNext.dll",
"SilentFilesInUseBAFunction.dll",
"PowerToys*Setup-*.exe",
"PowerToys*Setup-*.msi"
],
"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

@@ -65,21 +65,28 @@ if (-not (Test-Path $outputDir)) {
New-Item -Path $outputDir -ItemType Directory -Force | Out-Null
}
Write-Host "DSC manifests will be generated to: '$outputDir'"
# DSC v3 manifests go to DSCModules subfolder
$dscOutputDir = Join-Path $outputDir 'DSCModules'
if (-not (Test-Path $dscOutputDir)) {
Write-Host "Creating DSCModules subfolder at '$dscOutputDir'."
New-Item -Path $dscOutputDir -ItemType Directory -Force | Out-Null
}
Write-Host "Cleaning previously generated DSC manifest files from '$outputDir'."
Get-ChildItem -Path $outputDir -Filter 'microsoft.powertoys.*.settings.dsc.resource.json' -ErrorAction SilentlyContinue | Remove-Item -Force
Write-Host "DSC manifests will be generated to: '$dscOutputDir'"
$arguments = @('manifest', '--resource', 'settings', '--outputDir', $outputDir)
Write-Host "Cleaning previously generated DSC manifest files from '$dscOutputDir'."
Get-ChildItem -Path $dscOutputDir -Filter 'microsoft.powertoys.*.settings.dsc.resource.json' -ErrorAction SilentlyContinue | Remove-Item -Force
$arguments = @('manifest', '--resource', 'settings', '--outputDir', $dscOutputDir)
Write-Host "Invoking DSC manifest generator: '$exePath' $($arguments -join ' ')"
& $exePath @arguments
if ($LASTEXITCODE -ne 0) {
throw "PowerToys.DSC.exe exited with code $LASTEXITCODE"
}
$generatedFiles = Get-ChildItem -Path $outputDir -Filter 'microsoft.powertoys.*.settings.dsc.resource.json' -ErrorAction Stop
$generatedFiles = Get-ChildItem -Path $dscOutputDir -Filter 'microsoft.powertoys.*.settings.dsc.resource.json' -ErrorAction Stop
if ($generatedFiles.Count -eq 0) {
throw "No DSC manifest files were generated in '$outputDir'."
throw "No DSC manifest files were generated in '$dscOutputDir'."
}
Write-Host "Generated $($generatedFiles.Count) DSC manifest file(s):"

View File

@@ -32,7 +32,7 @@ parameters:
- name: enableMsBuildCaching
type: boolean
displayName: "Enable MSBuild Caching"
default: true
default: false
- name: runTests
type: boolean
displayName: "Run Tests"

View File

@@ -52,8 +52,6 @@ extends:
name: SHINE-INT-S
${{ if eq(parameters.useVSPreview, true) }}:
demands: ImageOverride -equals SHINE-VS17-Preview
${{ else }}:
image: SHINE-VS17-Latest
os: windows
sdl:
tsa:
@@ -75,7 +73,6 @@ extends:
name: SHINE-INT-L
demands:
# Our INT agents have a large disk mounted at P:\
- WorkFolder -equals P:\_work
- ${{ if eq(parameters.useVSPreview, true) }}:
- ImageOverride -equals SHINE-VS17-Preview
os: windows
@@ -126,7 +123,6 @@ extends:
parameters:
pool:
name: SHINE-INT-L
image: SHINE-VS17-Latest
os: windows
official: true
codeSign: true

View File

@@ -111,6 +111,7 @@ jobs:
${{ else }}:
OutputBuildPlatform: ${{ platform }}
variables:
NUGET_PACKAGES: 'C:\NuGetPackages' # Some of our build steps cache these here... and it was apparently part of the global environment
MakeAppxPath: 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.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*
@@ -139,6 +140,10 @@ jobs:
- output: pipelineArtifact
artifactName: $(JobOutputArtifactName)
targetPath: $(Build.ArtifactStagingDirectory)
- output: pipelineArtifact
artifactName: $(JobOutputArtifactName)-failure-$(System.JobAttempt)
targetPath: $(LogOutputDirectory)
condition: or(failed(), canceled())
steps:
- checkout: self
clean: true
@@ -266,6 +271,26 @@ jobs:
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
- task: VSBuild@1
displayName: Generate DSC artifacts for ARM64
condition: and(succeeded(), eq(variables['BuildPlatform'], 'arm64'))
inputs:
solution: PowerToys.sln
vsVersion: 17.0
msbuildArgs: >-
-restore
/p:Configuration=$(BuildConfiguration)
/p:Platform=x64
/t:DSC\PowerToys_Settings_DSC_Schema_Generator
/bl:$(LogOutputDirectory)\build-dsc-generator.binlog
${{ parameters.additionalBuildOptions }}
$(MSBuildCacheParameters)
$(RestoreAdditionalProjectSourcesArg)
platform: x64
configuration: $(BuildConfiguration)
msbuildArchitecture: x64
maximumCpuCount: true
# Build PowerToys.DSC.exe for ARM64 (x64 uses existing binary from previous build)
- task: VSBuild@1
displayName: Build PowerToys.DSC.exe (x64 for generating manifests)
@@ -375,7 +400,7 @@ jobs:
### HACK: On ARM64 builds, building an app with Windows App SDK copies the x64 WebView2 dll instead of the ARM64 one. This task makes sure the right dll is used.
- task: CopyFiles@2
displayName: HACK Copy core WebView2 ARM64 dll to output directory
condition: eq(variables['BuildPlatform'],'arm64')
condition: and(succeeded(), eq(variables['BuildPlatform'], 'arm64'))
inputs:
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/
@@ -414,11 +439,11 @@ jobs:
inputs:
testResultsFormat: VSTest
testResultsFiles: '**/*.trx'
condition: ne(variables['BuildPlatform'],'arm64')
condition: and(succeeded(), ne(variables['BuildPlatform'], 'arm64'))
# Native dlls
- task: VSTest@2
condition: ne(variables['BuildPlatform'],'arm64') # No arm64 agents to run the tests.
condition: and(succeeded(), ne(variables['BuildPlatform'], 'arm64')) # No arm64 agents to run the tests.
displayName: 'Native Tests'
inputs:
platform: '$(BuildPlatform)'
@@ -512,14 +537,6 @@ jobs:
versionNumber: ${{ parameters.versionNumber }}
additionalBuildOptions: ${{ parameters.additionalBuildOptions }}
- template: steps-build-installer-vnext.yml
parameters:
codeSign: ${{ parameters.codeSign }}
signingIdentity: ${{ parameters.signingIdentity }}
versionNumber: ${{ parameters.versionNumber }}
additionalBuildOptions: ${{ parameters.additionalBuildOptions }}
buildUserInstaller: true # NOTE: This is the distinction between the above and below rules
# This saves ~1GiB per architecture. We won't need these later.
# Removes:
# - All .pdb files from any static libs .libs (which were only used during linking)

View File

@@ -2,9 +2,6 @@ parameters:
- name: versionNumber
type: string
default: "0.0.1"
- name: buildUserInstaller
type: boolean
default: false
- name: codeSign
type: boolean
default: false
@@ -25,43 +22,26 @@ steps:
arguments: 'install --global wix --version 5.0.2'
- pwsh: |-
& git clean -xfd -e *exe -- .\installer\
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Clean installer to reduce cross-contamination
- pwsh: |-
# Determine whether this is a per-user build
$IsPerUser = $${{ parameters.buildUserInstaller }}
# Build slug used to locate the artifacts
$InstallerBuildSlug = if ($IsPerUser) { 'UserSetup' } else { 'MachineSetup' }
# VNext bundle folder; base name intentionally omits the VNext suffix
$InstallerFolder = 'PowerToysSetupVNext'
if ($IsPerUser) {
$InstallerBasename = "PowerToysUserSetup-${{ parameters.versionNumber }}-$(BuildPlatform)"
}
else {
$InstallerBasename = "PowerToysSetup-${{ parameters.versionNumber }}-$(BuildPlatform)"
}
# Export variables for downstream steps
Write-Host "##vso[task.setvariable variable=InstallerBuildSlug]$InstallerBuildSlug"
Write-Host "##vso[task.setvariable variable=InstallerRelativePath]$(BuildPlatform)\$(BuildConfiguration)\$InstallerBuildSlug"
Write-Host "##vso[task.setvariable variable=InstallerBasename]$InstallerBasename"
Write-Host "##vso[task.setvariable variable=InstallerFolder]$InstallerFolder"
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Prepare Installer variables
Write-Host "##vso[task.setvariable variable=InstallerMachineRoot]installer\PowerToysSetupVNext\$(BuildPlatform)\$(BuildConfiguration)\MachineSetup"
Write-Host "##vso[task.setvariable variable=InstallerUserRoot]installer\PowerToysSetupVNext\$(BuildPlatform)\$(BuildConfiguration)\UserSetup"
Write-Host "##vso[task.setvariable variable=InstallerMachineBasename]PowerToysSetup-${{ parameters.versionNumber }}-$(BuildPlatform)"
Write-Host "##vso[task.setvariable variable=InstallerUserBasename]PowerToysUserSetup-${{ parameters.versionNumber }}-$(BuildPlatform)"
displayName: Prepare Installer variables
# This dll needs to be built and signed before building the MSI.
# The Custom Actions project contains a pre-build event that prepares the .wxs files
# by filling them out with all our components. We pass RunBuildEvents=true to force
# that logic to run.
- task: VSBuild@1
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Build PowerToysSetupCustomActionsVNext
displayName: Build Shared Support DLLs
inputs:
solution: "**/installer/PowerToysSetup.sln"
vsVersion: 17.0
msbuildArgs: >-
/t:PowerToysSetupCustomActionsVNext
/p:RunBuildEvents=true;PerUser=${{parameters.buildUserInstaller}};RestorePackagesConfig=true;CIBuild=true
/t:PowerToysSetupCustomActionsVNext;SilentFilesInUseBAFunction
/p:RunBuildEvents=true;RestorePackagesConfig=true;CIBuild=true
-restore -graph
/bl:$(LogOutputDirectory)\installer-$(InstallerBuildSlug)-actions.binlog
/bl:$(LogOutputDirectory)\installer-actions.binlog
${{ parameters.additionalBuildOptions }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
@@ -70,28 +50,53 @@ steps:
maximumCpuCount: true
- ${{ if eq(parameters.codeSign, true) }}:
- template: steps-esrp-signing.yml
- template: steps-esrp-sign-files-authenticode.yml
parameters:
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign PowerToysSetupCustomActionsVNext
displayName: Sign Shared Support DLLs
signingIdentity: ${{ parameters.signingIdentity }}
inputs:
FolderPath: 'installer/PowerToysSetupCustomActionsVNext/$(InstallerRelativePath)'
signType: batchSigning
batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_installer.json'
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
folder: 'installer'
pattern: |-
**/PowerToysSetupCustomActionsVNext.dll
**/SilentFilesInUseBAFunction.dll
## INSTALLER START
#### MSI BUILDING AND SIGNING
#
# The MSI build contains code that reverts the .wxs files to their in-tree versions.
# This is only supposed to happen during local builds. Since this build system is
# supposed to run side by side--machine and then user--we do NOT want to destroy
# the .wxs files. Therefore, we pass RunBuildEvents=false to suppress all of that
# logic.
#
# We pass BuildProjectReferences=false so that it does not recompile the DLLs we just built.
# We only pass -restore on the first one because the second run should already have all
# of the dependencies.
- task: VSBuild@1
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Build VNext MSI
displayName: 💻 Build VNext MSI
inputs:
solution: "**/installer/PowerToysSetup.sln"
vsVersion: 17.0
msbuildArgs: >-
-restore
/t:PowerToysInstallerVNext
/p:RunBuildEvents=false;PerUser=${{parameters.buildUserInstaller}};BuildProjectReferences=false;CIBuild=true
/bl:$(LogOutputDirectory)\installer-$(InstallerBuildSlug)-msi.binlog
/p:RunBuildEvents=false;PerUser=false;BuildProjectReferences=false;CIBuild=true
/bl:$(LogOutputDirectory)\installer-machine-msi.binlog
${{ parameters.additionalBuildOptions }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
clean: false # don't undo our hard work above by deleting the CustomActions dll
msbuildArchitecture: x64
maximumCpuCount: true
- task: VSBuild@1
displayName: 👤 Build VNext MSI
inputs:
solution: "**/installer/PowerToysSetup.sln"
vsVersion: 17.0
msbuildArgs: >-
/t:PowerToysInstallerVNext
/p:RunBuildEvents=false;PerUser=true;BuildProjectReferences=false;CIBuild=true
/bl:$(LogOutputDirectory)\installer-user-msi.binlog
${{ parameters.additionalBuildOptions }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
@@ -100,77 +105,66 @@ steps:
maximumCpuCount: true
- script: |-
wix msi decompile installer\$(InstallerFolder)\$(InstallerRelativePath)\$(InstallerBasename).msi -x $(build.sourcesdirectory)\extractedMsi
dir $(build.sourcesdirectory)\extractedMsi
displayName: "${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} WiX5: Extract and verify MSI"
wix msi decompile $(InstallerMachineRoot)\$(InstallerMachineBasename).msi -x $(build.sourcesdirectory)\extractedMachineMsi
wix msi decompile $(InstallerUserRoot)\$(InstallerUserBasename).msi -x $(build.sourcesdirectory)\extractedUserMsi
dir $(build.sourcesdirectory)\extractedMachineMsi
dir $(build.sourcesdirectory)\extractedUserMsi
displayName: "WiX5: Extract and verify MSIs"
# Check if deps.json files don't reference different dll versions.
- pwsh: |-
& '.pipelines/verifyDepsJsonLibraryVersions.ps1' -targetDir '$(build.sourcesdirectory)\extractedMsi\File'
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Audit deps.json in MSI extracted files
& '.pipelines/verifyDepsJsonLibraryVersions.ps1' -targetDir '$(build.sourcesdirectory)\extractedMachineMsi\File'
& '.pipelines/verifyDepsJsonLibraryVersions.ps1' -targetDir '$(build.sourcesdirectory)\extractedUserMsi\File'
displayName: Audit deps.json in MSI extracted files
- ${{ if eq(parameters.codeSign, true) }}:
- pwsh: |-
& .pipelines/versionAndSignCheck.ps1 -targetDir '$(build.sourcesdirectory)\extractedMsi\File'
& .pipelines/versionAndSignCheck.ps1 -targetDir '$(build.sourcesdirectory)\extractedMsi\Binary'
git clean -xfd ./extractedMsi
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Verify all binaries are signed and versioned
& .pipelines/versionAndSignCheck.ps1 -targetDir '$(build.sourcesdirectory)\extractedMachineMsi\File'
& .pipelines/versionAndSignCheck.ps1 -targetDir '$(build.sourcesdirectory)\extractedMachineMsi\Binary'
& .pipelines/versionAndSignCheck.ps1 -targetDir '$(build.sourcesdirectory)\extractedUserMsi\File'
& .pipelines/versionAndSignCheck.ps1 -targetDir '$(build.sourcesdirectory)\extractedUserMsi\Binary'
git clean -xfd ./extractedMachineMsi ./extractedUserMsi
displayName: Verify all binaries are signed and versioned
- template: steps-esrp-signing.yml
- template: steps-esrp-sign-files-authenticode.yml
parameters:
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign VNext MSI
displayName: Sign VNext MSIs
signingIdentity: ${{ parameters.signingIdentity }}
inputs:
FolderPath: 'installer/$(InstallerFolder)/$(InstallerRelativePath)'
signType: batchSigning
batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_installer.json'
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
folder: 'installer'
pattern: '**/PowerToys*Setup-*.msi'
#### END MSI
#### BUILDING AND SIGNING SilentFilesInUseBAFunction DLL
- task: VSBuild@1
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Build SilentFilesInUseBAFunction
inputs:
solution: "**/installer/PowerToysSetup.sln"
vsVersion: 17.0
msbuildArgs: >-
/t:SilentFilesInUseBAFunction
/p:RunBuildEvents=true;PerUser=${{parameters.buildUserInstaller}};RestorePackagesConfig=true;CIBuild=true
-restore -graph
/bl:$(LogOutputDirectory)\installer-$(InstallerBuildSlug)-SilentFilesInUseBAFunction.binlog
${{ parameters.additionalBuildOptions }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
clean: false # don't undo our hard work above by deleting the msi
msbuildArchitecture: x64
maximumCpuCount: true
- ${{ if eq(parameters.codeSign, true) }}:
- template: steps-esrp-signing.yml
parameters:
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign SilentFilesInUseBAFunction
signingIdentity: ${{ parameters.signingIdentity }}
inputs:
FolderPath: 'installer/$(BuildPlatform)/$(BuildConfiguration)'
signType: batchSigning
batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_installer.json'
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
#### END BUILDING AND SIGNING SilentFilesInUseBAFunction DLL
#### BOOTSTRAP BUILDING AND SIGNING
# We pass BuildProjectReferences=false so that it does not recompile the DLLs we just built.
# We only pass -restore on the first one because the second run should already have all
# of the dependencies.
- task: VSBuild@1
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Build VNext Bootstrapper
displayName: 💻 Build VNext Bootstrapper
inputs:
solution: "**/installer/PowerToysSetup.sln"
vsVersion: 17.0
msbuildArgs: >-
-restore
/t:PowerToysBootstrapperVNext
/p:PerUser=${{parameters.buildUserInstaller}};CIBuild=true
/bl:$(LogOutputDirectory)\installer-$(InstallerBuildSlug)-bootstrapper.binlog
-restore -graph
/p:PerUser=false;BuildProjectReferences=false;CIBuild=true
/bl:$(LogOutputDirectory)\installer-machine-bootstrapper.binlog
${{ parameters.additionalBuildOptions }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
clean: false # don't undo our hard work above by deleting the MSI nor SilentFilesInUseBAFunction
msbuildArchitecture: x64
maximumCpuCount: true
- task: VSBuild@1
displayName: 👤 Build VNext Bootstrapper
inputs:
solution: "**/installer/PowerToysSetup.sln"
vsVersion: 17.0
msbuildArgs: >-
/t:PowerToysBootstrapperVNext
/p:PerUser=true;BuildProjectReferences=false;CIBuild=true
/bl:$(LogOutputDirectory)\installer-user-bootstrapper.binlog
${{ parameters.additionalBuildOptions }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
@@ -181,54 +175,41 @@ steps:
# The entirety of bundle unpacking/re-packing is unnecessary if we are not code signing it.
- ${{ if eq(parameters.codeSign, true) }}:
- script: |-
wix burn detach installer\$(InstallerFolder)\$(InstallerRelativePath)\$(InstallerBasename).exe -engine installer\engine.exe
displayName: "${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} WiX5: Extract Engine from Bundle"
wix burn detach $(InstallerMachineRoot)\$(InstallerMachineBasename).exe -engine installer\machine-engine.exe
wix burn detach $(InstallerUserRoot)\$(InstallerUserBasename).exe -engine installer\user-engine.exe
displayName: "WiX5: Extract Engines from Bundles"
- template: steps-esrp-signing.yml
- template: steps-esrp-sign-files-authenticode.yml
parameters:
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign WiX Engine
displayName: Sign WiX Engines
signingIdentity: ${{ parameters.signingIdentity }}
inputs:
FolderPath: "installer"
Pattern: engine.exe
signConfigType: inlineSignParams
inlineOperation: |
[
{
"KeyCode": "CP-230012",
"OperationCode": "SigntoolSign",
"Parameters": {
"OpusName": "Microsoft",
"OpusInfo": "http://www.microsoft.com",
"FileDigest": "/fd \"SHA256\"",
"PageHash": "/NPH",
"TimeStamp": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
},
"ToolName": "sign",
"ToolVersion": "1.0"
},
{
"KeyCode": "CP-230012",
"OperationCode": "SigntoolVerify",
"Parameters": {},
"ToolName": "sign",
"ToolVersion": "1.0"
}
]
folder: "installer"
pattern: '*-engine.exe'
- script: |-
wix burn reattach installer\$(InstallerFolder)\$(InstallerRelativePath)\$(InstallerBasename).exe -engine installer\engine.exe -o installer\$(InstallerFolder)\$(InstallerRelativePath)\$(InstallerBasename).exe
displayName: "${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} WiX5: Reattach Engine to Bundle"
wix burn reattach $(InstallerMachineRoot)\$(InstallerMachineBasename).exe -engine installer\machine-engine.exe -o $(InstallerMachineRoot)\$(InstallerMachineBasename).exe
wix burn reattach $(InstallerUserRoot)\$(InstallerUserBasename).exe -engine installer\user-engine.exe -o $(InstallerUserRoot)\$(InstallerUserBasename).exe
displayName: "WiX5: Reattach Engines to Bundles"
- template: steps-esrp-signing.yml
- pwsh: |-
& wix burn extract -oba installer\ba\m "$(InstallerMachineRoot)\$(InstallerMachineBasename).exe"
& wix burn extract -oba installer\ba\u "$(InstallerUserRoot)\$(InstallerUserBasename).exe"
Get-ChildItem installer\ba -Recurse -Include *.exe,*.dll | Get-AuthenticodeSignature | ForEach-Object {
If ($_.Status -Ne "Valid") {
Write-Error $_.StatusMessage
} Else {
Write-Host $_.StatusMessage
}
}
& git clean -fdx installer\ba
displayName: "WiX5: Verify Bootstrapper content is signed"
- template: steps-esrp-sign-files-authenticode.yml
parameters:
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign Final Bootstrapper
displayName: Sign Final Bootstrappers
signingIdentity: ${{ parameters.signingIdentity }}
inputs:
FolderPath: 'installer/$(InstallerFolder)/$(InstallerRelativePath)'
signType: batchSigning
batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_installer.json'
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
folder: 'installer'
pattern: '**/PowerToys*Setup-*.exe'
#### END BOOTSTRAP
## END INSTALLER

View File

@@ -0,0 +1,45 @@
parameters:
- name: displayName
type: string
default: Sign Specific Files
- name: folder
type: string
- name: pattern
type: string
- name: signingIdentity
type: object
default: {}
steps:
- template: steps-esrp-signing.yml
parameters:
displayName: ${{ parameters.displayName }}
signingIdentity: ${{ parameters.signingIdentity }}
inputs:
FolderPath: ${{ parameters.folder }}
Pattern: ${{ parameters.pattern }}
UseMinimatch: true
signConfigType: inlineSignParams
inlineOperation: |-
[
{
"KeyCode": "CP-230012",
"OperationCode": "SigntoolSign",
"Parameters": {
"OpusName": "Microsoft",
"OpusInfo": "http://www.microsoft.com",
"FileDigest": "/fd \"SHA256\"",
"PageHash": "/NPH",
"TimeStamp": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
},
"ToolName": "sign",
"ToolVersion": "1.0"
},
{
"KeyCode": "CP-230012",
"OperationCode": "SigntoolVerify",
"Parameters": {},
"ToolName": "sign",
"ToolVersion": "1.0"
}
]

13
.vscode/launch.json vendored
View File

@@ -38,6 +38,17 @@
"env": {},
"console": "internalConsole",
"stopAtEntry": false
}
},
{
"name": "Run AdvancedPaste (managed, no build, ARCH configurable)",
"type": "coreclr",
"request": "launch",
"program": "${workspaceFolder}\\${input:arch}\\Debug\\WinUI3Apps\\PowerToys.AdvancedPaste.exe",
"args": [],
"cwd": "${workspaceFolder}",
"env": {},
"console": "internalConsole",
"stopAtEntry": false
},
]
}

View File

@@ -1,56 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Hybrid CRT configuration -->
<PropertyGroup Condition="'$(HybridCrtConfiguration)'==''">
<HybridCrtConfiguration>$(Configuration)</HybridCrtConfiguration>
</PropertyGroup>
<!-- Skip Hybrid CRT for AppContainer/UWP projects as they require MultiThreadedDLL -->
<PropertyGroup Condition="'$(AppContainerApplication)'=='true' and '$(_VC_Target_Library_Platform)'!='Desktop'">
<HybridCrtConfiguration></HybridCrtConfiguration>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(HybridCrtConfiguration)'=='Debug'">
<ClCompile>
<!-- We use MultiThreadedDebug, rather than MultiThreadedDebugDLL, to avoid DLL dependencies on VCRUNTIME140d.dll and MSVCP140d.dll. -->
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrtd.lib</IgnoreSpecificDefaultLibraries>
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrtd.lib</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(HybridCrtConfiguration)'=='Release'">
<ClCompile>
<!-- We use MultiThreaded, rather than MultiThreadedDLL, to avoid DLL dependencies on VCRUNTIME140.dll and MSVCP140.dll. -->
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrt.lib</IgnoreSpecificDefaultLibraries>
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrt.lib</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<!-- AppContainer/UWP projects must use MultiThreadedDLL -->
<ItemDefinitionGroup Condition="'$(AppContainerApplication)'=='true' and '$(_VC_Target_Library_Platform)'!='Desktop' And '$(Configuration)'=='Debug'">
<ClCompile>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(AppContainerApplication)'=='true' and '$(_VC_Target_Library_Platform)'!='Desktop' And '$(Configuration)'=='Release'">
<ClCompile>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
</ItemDefinitionGroup>
<!-- Project configurations -->
<ItemGroup Label="ProjectConfigurations">
@@ -123,6 +73,7 @@
<ClCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@@ -132,6 +83,7 @@
<ClCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Optimization>MaxSpeed</Optimization>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
</ClCompile>

View File

@@ -147,6 +147,18 @@ _If you want to find diagnostic data events in the source code, these two links
<td>Microsoft.PowerToys.AdvancedPasteSemanticKernelFormatEvent</td>
<td>Triggered when Advanced Paste leverages the Semantic Kernel.</td>
</tr>
<tr>
<td>Microsoft.PowerToys.AdvancedPasteSemanticKernelErrorEvent</td>
<td>Occurs when the Semantic Kernel workflow encounters an error.</td>
</tr>
<tr>
<td>Microsoft.PowerToys.AdvancedPasteEndpointUsageEvent</td>
<td>Logs the AI provider, model, and processing duration for each endpoint call.</td>
</tr>
<tr>
<td>Microsoft.PowerToys.AdvancedPasteCustomActionErrorEvent</td>
<td>Records provider, model, and status details when a custom action fails.</td>
</tr>
</table>
### Always on Top

View File

@@ -1,4 +1,4 @@
<Project>
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
@@ -7,9 +7,9 @@
<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.5" />
<PackageVersion Include="CommunityToolkit.Labs.WinUI.Controls.OpacityMaskView" Version="0.1.251101-build.2372" />
<PackageVersion Include="Microsoft.Bot.AdaptiveExpressions.Core" Version="4.23.0" />
<PackageVersion Include="Appium.WebDriver" Version="4.4.5" />
<PackageVersion Include="Azure.AI.OpenAI" Version="1.0.0-beta.17" />
<PackageVersion Include="CoenM.ImageSharp.ImageHash" Version="1.3.6" />
<PackageVersion Include="CommunityToolkit.Common" Version="8.4.0" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
@@ -35,23 +35,33 @@
<!-- 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="3.1.3" />
<PackageVersion Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="9.0.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.8" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.10" />
<!-- Including Microsoft.Bcl.AsyncInterfaces to force version, since it's used by Microsoft.SemanticKernel. -->
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.8" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.10" />
<PackageVersion Include="Microsoft.Windows.CppWinRT" Version="2.0.240111.5" />
<PackageVersion Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="3.1.16" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.8" />
<PackageVersion Include="Microsoft.SemanticKernel" Version="1.15.0" />
<PackageVersion Include="Microsoft.Extensions.AI" Version="9.9.1" />
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="9.9.1-preview.1.25474.6" />
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.10" />
<PackageVersion Include="Microsoft.AI.Foundry.Local" Version="0.3.0" />
<PackageVersion Include="Microsoft.SemanticKernel" Version="1.66.0" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.OpenAI" Version="1.66.0" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.AzureAIInference" Version="1.66.0-beta" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.Google" Version="1.66.0-alpha" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.MistralAI" Version="1.66.0-alpha" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.Ollama" Version="1.66.0-alpha" />
<PackageVersion Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.3179.45" />
<!-- 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.8" />
<PackageVersion Include="Microsoft.Win32.SystemEvents" Version="9.0.10" />
<PackageVersion Include="Microsoft.WindowsPackageManager.ComInterop" Version="1.10.340" />
<PackageVersion Include="Microsoft.Windows.Compatibility" Version="9.0.8" />
<PackageVersion Include="Microsoft.Windows.Compatibility" Version="9.0.10" />
<PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.3.183" />
<!-- 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. -->
<!--
@@ -74,7 +84,7 @@
<PackageVersion Include="NLog" Version="5.2.8" />
<PackageVersion Include="NLog.Extensions.Logging" Version="5.3.8" />
<PackageVersion Include="NLog.Schema" Version="5.2.8" />
<PackageVersion Include="OpenAI" Version="2.0.0" />
<PackageVersion Include="OpenAI" Version="2.5.0" />
<PackageVersion Include="ReverseMarkdown" Version="4.1.0" />
<PackageVersion Include="RtfPipe" Version="2.0.7677.4303" />
<PackageVersion Include="ScipBe.Common.Office.OneNote" Version="3.0.1" />
@@ -84,28 +94,29 @@
<PackageVersion Include="StreamJsonRpc" Version="2.21.69" />
<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.8" />
<PackageVersion Include="System.CodeDom" Version="9.0.10" />
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<PackageVersion Include="System.ComponentModel.Composition" Version="9.0.8" />
<PackageVersion Include="System.Configuration.ConfigurationManager" Version="9.0.8" />
<PackageVersion Include="System.Data.OleDb" Version="9.0.8" />
<PackageVersion Include="System.ComponentModel.Composition" Version="9.0.10" />
<PackageVersion Include="System.Configuration.ConfigurationManager" Version="9.0.10" />
<PackageVersion Include="System.Data.OleDb" Version="9.0.10" />
<!-- 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.9.0" />
<!-- 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.8" />
<PackageVersion Include="System.Diagnostics.EventLog" Version="9.0.10" />
<!-- 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.8" />
<PackageVersion Include="System.Drawing.Common" Version="9.0.8" />
<PackageVersion Include="System.Diagnostics.PerformanceCounter" Version="9.0.10" />
<PackageVersion Include="System.ClientModel" Version="1.7.0" />
<PackageVersion Include="System.Drawing.Common" Version="9.0.10" />
<PackageVersion Include="System.IO.Abstractions" Version="22.0.13" />
<PackageVersion Include="System.IO.Abstractions.TestingHelpers" Version="22.0.13" />
<PackageVersion Include="System.Management" Version="9.0.8" />
<PackageVersion Include="System.Management" Version="9.0.10" />
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
<PackageVersion Include="System.Reactive" Version="6.0.1" />
<PackageVersion Include="System.Runtime.Caching" Version="9.0.8" />
<PackageVersion Include="System.ServiceProcess.ServiceController" Version="9.0.8" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.8" />
<PackageVersion Include="System.Text.Json" Version="9.0.8" />
<PackageVersion Include="System.Runtime.Caching" Version="9.0.10" />
<PackageVersion Include="System.ServiceProcess.ServiceController" Version="9.0.10" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.10" />
<PackageVersion Include="System.Text.Json" Version="9.0.10" />
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageVersion Include="UnicodeInformation" Version="2.6.0" />
<PackageVersion Include="UnitsNet" Version="5.56.0" />
@@ -127,4 +138,4 @@
<PackageVersion Include="Microsoft.VariantAssignment.Client" Version="2.4.17140001" />
<PackageVersion Include="Microsoft.VariantAssignment.Contract" Version="3.0.16990001" />
</ItemGroup>
</Project>
</Project>

View File

@@ -1495,10 +1495,10 @@ SOFTWARE.
- AdaptiveCards.Rendering.WinUI3
- AdaptiveCards.Templating
- Appium.WebDriver
- Azure.AI.OpenAI
- CoenM.ImageSharp.ImageHash
- CommunityToolkit.Common
- CommunityToolkit.Labs.WinUI.Controls.MarkdownTextBlock
- CommunityToolkit.Labs.WinUI.Controls.OpacityMaskView
- CommunityToolkit.Mvvm
- CommunityToolkit.WinUI.Animations
- CommunityToolkit.WinUI.Collections

View File

@@ -822,12 +822,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.WebSea
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Shell.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.Shell.UnitTests\Microsoft.CmdPal.Ext.Shell.UnitTests.csproj", "{E816D7B4-4688-4ECB-97CC-3D8E798F3833}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CursorWrap", "src\modules\MouseUtils\CursorWrap\CursorWrap.vcxproj", "{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{3DCCD936-D085-4869-A1DE-CA6A64152C94}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightSwitch.UITests", "src\modules\LightSwitch\Tests\LightSwitch.UITests\LightSwitch.UITests.csproj", "{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.ClipboardHistory.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.ClipboardHistory.UnitTests\Microsoft.CmdPal.Ext.ClipboardHistory.UnitTests.csproj", "{4E0FCF69-B06B-D272-76BF-ED3A559B4EDA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LanguageModelProvider", "src\common\LanguageModelProvider\LanguageModelProvider.csproj", "{45354F4F-1414-45CE-B600-51CD1209FD19}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.UI.ViewModels.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.UI.ViewModels.UnitTests\Microsoft.CmdPal.UI.ViewModels.UnitTests.csproj", "{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}"
EndProject
Global
@@ -2988,6 +2992,14 @@ Global
{E816D7B4-4688-4ECB-97CC-3D8E798F3833}.Release|ARM64.Build.0 = Release|ARM64
{E816D7B4-4688-4ECB-97CC-3D8E798F3833}.Release|x64.ActiveCfg = Release|x64
{E816D7B4-4688-4ECB-97CC-3D8E798F3833}.Release|x64.Build.0 = Release|x64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|ARM64.ActiveCfg = Debug|ARM64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|ARM64.Build.0 = Debug|ARM64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|x64.ActiveCfg = Debug|x64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|x64.Build.0 = Debug|x64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|ARM64.ActiveCfg = Release|ARM64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|ARM64.Build.0 = Release|ARM64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|x64.ActiveCfg = Release|x64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|x64.Build.0 = Release|x64
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}.Debug|ARM64.ActiveCfg = Debug|ARM64
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}.Debug|ARM64.Build.0 = Debug|ARM64
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}.Debug|ARM64.Deploy.0 = Debug|ARM64
@@ -3008,6 +3020,14 @@ Global
{4E0FCF69-B06B-D272-76BF-ED3A559B4EDA}.Release|ARM64.Build.0 = Release|ARM64
{4E0FCF69-B06B-D272-76BF-ED3A559B4EDA}.Release|x64.ActiveCfg = Release|x64
{4E0FCF69-B06B-D272-76BF-ED3A559B4EDA}.Release|x64.Build.0 = Release|x64
{45354F4F-1414-45CE-B600-51CD1209FD19}.Debug|ARM64.ActiveCfg = Debug|ARM64
{45354F4F-1414-45CE-B600-51CD1209FD19}.Debug|ARM64.Build.0 = Debug|ARM64
{45354F4F-1414-45CE-B600-51CD1209FD19}.Debug|x64.ActiveCfg = Debug|x64
{45354F4F-1414-45CE-B600-51CD1209FD19}.Debug|x64.Build.0 = Debug|x64
{45354F4F-1414-45CE-B600-51CD1209FD19}.Release|ARM64.ActiveCfg = Release|ARM64
{45354F4F-1414-45CE-B600-51CD1209FD19}.Release|ARM64.Build.0 = Release|ARM64
{45354F4F-1414-45CE-B600-51CD1209FD19}.Release|x64.ActiveCfg = Release|x64
{45354F4F-1414-45CE-B600-51CD1209FD19}.Release|x64.Build.0 = Release|x64
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}.Debug|ARM64.ActiveCfg = Debug|ARM64
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}.Debug|ARM64.Build.0 = Debug|ARM64
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}.Debug|x64.ActiveCfg = Debug|x64
@@ -3341,9 +3361,11 @@ Global
{E816D7B3-4688-4ECB-97CC-3D8E798F3832} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{E816D7B2-4688-4ECB-97CC-3D8E798F3831} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{E816D7B4-4688-4ECB-97CC-3D8E798F3833} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5} = {322566EF-20DC-43A6-B9F8-616AF942579A}
{3DCCD936-D085-4869-A1DE-CA6A64152C94} = {5B201255-53C8-490B-A34F-01F05D48A477}
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F} = {3DCCD936-D085-4869-A1DE-CA6A64152C94}
{4E0FCF69-B06B-D272-76BF-ED3A559B4EDA} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{45354F4F-1414-45CE-B600-51CD1209FD19} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution

View File

@@ -7,19 +7,23 @@
<h1 align="center">
<span>Microsoft PowerToys</span>
</h1>
<p align="center">
<span align="center">Microsoft PowerToys is a collection of utilities that help you customize Windows and streamline everyday tasks.</span>
</p>
<h3 align="center">
<a href="#-installation">Installation</a>
<span> . </span>
<span> · </span>
<a href="https://aka.ms/powertoys-docs">Documentation</a>
<span> . </span>
<span> · </span>
<a href="https://aka.ms/powertoys-releaseblog">Blog</a>
<span> . </span>
<span> · </span>
<a href="#-whats-new">Release notes</a>
</h3>
<br/><br/>
Microsoft PowerToys is a collection of utilities that help you customize Windows and streamline everyday tasks.
<br/><br/>
## 🔨 Utilities
PowerToys includes over 25 utilities to help you customize and optimize your Windows experience:
| | | |
|---|---|---|
@@ -37,20 +41,13 @@ Microsoft PowerToys is a collection of utilities that help you customize Windows
## 📋 Installation
For detailed installation instructions, visit the [installation docs](https://learn.microsoft.com/windows/powertoys/install).
Before you begin, make sure your device meets the system requirements:
> [!NOTE]
> - Windows 11 or Windows 10 version 2004 (20H1 / build 19041) or newer
> - 64-bit processor: x64 or ARM64
> - Latest stable version of [Microsoft Edge WebView2 Runtime](https://go.microsoft.com/fwlink/p/?LinkId=2124703) is installed via the bootstrapper during setup
Choose one of the installation methods below:
For detailed installation instructions and system requirements, visit the [installation docs](https://learn.microsoft.com/windows/powertoys/install).
But to get started quickly, choose one of the installation methods below:
<br/><br/>
<details open>
<summary>Download .exe from GitHub</summary>
<summary><strong>Download .exe from GitHub</strong></summary>
<br/>
Go to the [PowerToys GitHub releases][github-release-link], click Assets to reveal the downloads, and choose the installer that matches your architecture and install scope. For most devices, that's the x64 per-user installer.
<!-- items that need to be updated release to release -->
@@ -67,11 +64,11 @@ Go to the [PowerToys GitHub releases][github-release-link], click Assets to reve
| Per user - ARM64 | [PowerToysUserSetup-0.95.1-arm64.exe][ptUserArm64] |
| Machine wide - x64 | [PowerToysSetup-0.95.1-x64.exe][ptMachineX64] |
| Machine wide - ARM64 | [PowerToysSetup-0.95.1-arm64.exe][ptMachineArm64] |
</details>
<details>
<summary>Microsoft Store</summary>
<summary><strong>Microsoft Store</strong></summary>
<br/>
You can easily install PowerToys from the Microsoft Store:
<p>
<a style="text-decoration:none" href="https://aka.ms/getPowertoys">
@@ -82,10 +79,9 @@ You can easily install PowerToys from the Microsoft Store:
</p>
</details>
<details>
<summary>WinGet</summary>
<summary><strong>WinGet</strong></summary>
<br/>
Download PowerToys from [WinGet][winget-link]. Updating PowerToys via winget will respect the current PowerToys installation scope. To install PowerToys, run the following command from the command line / PowerShell:
*User scope installer [default]*
@@ -100,8 +96,8 @@ winget install --scope machine Microsoft.PowerToys -s winget
</details>
<details>
<summary>Other methods</summary>
<summary><strong>Other methods</strong></summary>
<br/>
There are [community driven install methods](./doc/unofficialInstallMethods.md) such as Chocolatey and Scoop. If these are your preferred install solutions, you can find the install instructions there.
</details>

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -1,87 +0,0 @@
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True)]
[string]$dscWxsFile,
[Parameter(Mandatory = $True)]
[string]$Platform,
[Parameter(Mandatory = $True)]
[string]$Configuration
)
$ErrorActionPreference = 'Stop'
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$buildOutputDir = Join-Path $scriptDir "..\..\$Platform\$Configuration"
if (-not (Test-Path $buildOutputDir)) {
Write-Error "Build output directory not found: '$buildOutputDir'"
exit 1
}
$dscFiles = Get-ChildItem -Path $buildOutputDir -Filter "microsoft.powertoys.*.settings.dsc.resource.json" -File
if (-not $dscFiles) {
Write-Warning "No DSC manifest files found in '$buildOutputDir'"
$wxsContent = @"
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?include `$(sys.CURRENTDIR)\Common.wxi?>
<Fragment>
<ComponentGroup Id="DscResourcesComponentGroup">
</ComponentGroup>
</Fragment>
</Wix>
"@
Set-Content -Path $dscWxsFile -Value $wxsContent
exit 0
}
Write-Host "Found $($dscFiles.Count) DSC manifest file(s)"
$wxsContent = @"
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?include `$(sys.CURRENTDIR)\Common.wxi?>
<Fragment>
<DirectoryRef Id="DSCModulesReferenceFolder">
"@
$componentRefs = @()
foreach ($file in $dscFiles) {
$componentId = "DscResource_" + ($file.BaseName -replace '[^A-Za-z0-9_]', '_')
$fileId = $componentId + "_File"
$guid = [System.Guid]::NewGuid().ToString().ToUpper()
$componentRefs += $componentId
$wxsContent += @"
<Component Id="$componentId" Guid="{$guid}">
<RegistryKey Root="`$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="$componentId" Value="" KeyPath="yes"/>
</RegistryKey>
<File Id="$fileId" Source="`$(var.BinDir)$($file.Name)" Vital="no"/>
</Component>
"@
}
$wxsContent += @"
</DirectoryRef>
</Fragment>
<Fragment>
<ComponentGroup Id="DscResourcesComponentGroup">
"@
foreach ($componentId in $componentRefs) {
$wxsContent += @"
<ComponentRef Id="$componentId"/>
"@
}
$wxsContent += @"
</ComponentGroup>
</Fragment>
</Wix>
"@
Set-Content -Path $dscWxsFile -Value $wxsContent
Write-Host "Generated DSC resources WiX fragment: '$dscWxsFile'"

View File

@@ -4,6 +4,7 @@
#include <ProjectTelemetry.h>
#include <spdlog/sinks/base_sink.h>
#include <filesystem>
#include <string_view>
#include "../../src/common/logger/logger.h"
#include "../../src/common/utils/gpo.h"
@@ -856,14 +857,69 @@ UINT __stdcall UnsetAdvancedPasteAPIKeyCA(MSIHANDLE hInstall)
try
{
winrt::Windows::Security::Credentials::PasswordVault vault;
winrt::Windows::Security::Credentials::PasswordCredential cred;
hr = WcaInitialize(hInstall, "UnsetAdvancedPasteAPIKey");
ExitOnFailure(hr, "Failed to initialize");
cred = vault.Retrieve(L"https://platform.openai.com/api-keys", L"PowerToys_AdvancedPaste_OpenAIKey");
vault.Remove(cred);
winrt::Windows::Security::Credentials::PasswordVault vault;
auto hasPrefix = [](std::wstring_view value, wchar_t const* prefix) {
std::wstring_view prefixView{ prefix };
return value.compare(0, prefixView.size(), prefixView) == 0;
};
const wchar_t* resourcePrefixes[] = {
L"https://platform.openai.com/api-keys",
L"https://azure.microsoft.com/products/ai-services/openai-service",
L"https://azure.microsoft.com/products/ai-services/ai-inference",
L"https://console.mistral.ai/account/api-keys",
L"https://ai.google.dev/",
};
const wchar_t* usernamePrefixes[] = {
L"PowerToys_AdvancedPaste_",
};
auto credentials = vault.RetrieveAll();
for (auto const& credential : credentials)
{
bool shouldRemove = false;
std::wstring resource{ credential.Resource() };
for (auto const prefix : resourcePrefixes)
{
if (hasPrefix(resource, prefix))
{
shouldRemove = true;
break;
}
}
if (!shouldRemove)
{
std::wstring username{ credential.UserName() };
for (auto const prefix : usernamePrefixes)
{
if (hasPrefix(username, prefix))
{
shouldRemove = true;
break;
}
}
}
if (!shouldRemove)
{
continue;
}
try
{
vault.Remove(credential);
}
catch (...)
{
}
}
}
catch (...)
{

View File

@@ -34,12 +34,8 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir Condition=" '$(PerUser)' != 'true' ">$(Platform)\$(Configuration)\MachineSetup\</OutDir>
<OutDir Condition=" '$(PerUser)' == 'true' ">$(Platform)\$(Configuration)\UserSetup\</OutDir>
<IntDir Condition=" '$(PerUser)' != 'true' ">$(SolutionDir)$(ProjectName)\$(Platform)\$(Configuration)\MachineSetup\obj\</IntDir>
<IntDir Condition=" '$(PerUser)' == 'true' ">$(SolutionDir)$(ProjectName)\$(Platform)\$(Configuration)\UserSetup\obj\</IntDir>
<NormalizedPerUserValue>false</NormalizedPerUserValue>
<NormalizedPerUserValue Condition=" '$(PerUser)' == 'true' ">true</NormalizedPerUserValue>
<OutDir>$(Platform)\$(Configuration)\SetupShared\</OutDir>
<IntDir>$(SolutionDir)$(ProjectName)\$(Platform)\$(Configuration)\SetupShared\obj\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<LinkIncremental>true</LinkIncremental>
@@ -58,6 +54,7 @@
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\CmdPal.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\CmdPal.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\ColorPicker.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\ColorPicker.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\Core.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\Core.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\DscResources.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\DscResources.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\EnvironmentVariables.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\EnvironmentVariables.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\FileExplorerPreview.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\FileExplorerPreview.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\FileLocksmith.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\FileLocksmith.wxs.bk""""
@@ -79,8 +76,7 @@
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\WinAppSDK.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\WinAppSDK.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\WinUI3Applications.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\WinUI3Applications.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\Workspaces.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\Workspaces.wxs.bk""""
if not "$(NormalizedPerUserValue)" == "true" call powershell.exe -NonInteractive -executionpolicy Unrestricted -File ..\PowerToysSetupVNext\generateAllFileComponents.ps1 -platform $(Platform)
if "$(NormalizedPerUserValue)" == "true" call powershell.exe -NonInteractive -executionpolicy Unrestricted -File ..\PowerToysSetupVNext\generateAllFileComponents.ps1 -platform $(Platform) -installscopeperuser $(NormalizedPerUserValue)
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File ..\PowerToysSetupVNext\generateAllFileComponents.ps1 -platform $(Platform)
</Command>
<Message>Backing up original files and populating .NET and WPF Runtime dependencies for WiX3 based installer</Message>
</PreBuildEvent>
@@ -114,6 +110,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;CUSTOMACTIONTEST_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@@ -126,6 +123,7 @@
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;CUSTOMACTIONTEST_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
</ClCompile>
<Link>
@@ -178,4 +176,4 @@
<Error Condition="!Exists('..\packages\WixToolset.DUtil.5.0.2\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WixToolset.DUtil.5.0.2\build\WixToolset.DUtil.props'))" />
<Error Condition="!Exists('..\packages\WixToolset.WcaUtil.5.0.2\build\WixToolset.WcaUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WixToolset.WcaUtil.5.0.2\build\WixToolset.WcaUtil.props'))" />
</Target>
</Project>
</Project>

View File

@@ -4,6 +4,13 @@
<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)_Test">
@@ -18,14 +25,40 @@
<?endif?>
</Component>
</DirectoryRef>
<?if $(sys.BUILDARCH) = x64 ?>
<DirectoryRef Id="CmdPalDepsX64InstallFolder" FileSource="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\x64">
<Component Id="Module_CmdPal_Deps" Guid="C2790FC4-0665-4462-947A-D942A2AABFF0" Bitness="always64">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="Module_CmdPal_Deps" Value="" KeyPath="yes" />
</RegistryKey>
<File Id="Microsoft.VCLibs.x64.14.00.Desktop.appx" Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\x64\Microsoft.VCLibs.x64.14.00.Desktop.appx" />
</Component>
</DirectoryRef>
<?else?>
<DirectoryRef Id="CmdPalDepsArm64InstallFolder" FileSource="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\arm64">
<Component Id="Module_CmdPal_Deps" Guid="C2790FC4-0665-4462-947A-D942A2AABFF0" Bitness="always64">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="Module_CmdPal_Deps" Value="" KeyPath="yes" />
</RegistryKey>
<File Id="Microsoft.VCLibs.ARM64.14.00.Desktop.appx" Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\arm64\Microsoft.VCLibs.ARM64.14.00.Desktop.appx" />
</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

@@ -15,8 +15,8 @@
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="powertoys_env_path_user" Value="" KeyPath="yes" />
</RegistryKey>
<!-- Append install folder to current user's PATH -->
<Environment Id="AddPowerToysToUserPath" Name="PATH" Action="set" Part="last" System="no" Value="[INSTALLFOLDER]" />
<!-- Append DSCModules folder to current user's PATH for DSC v3 usage -->
<Environment Id="AddPowerToysToUserPath" Name="PATH" Action="set" Part="last" System="no" Value="[DSCModulesReferenceFolder]" />
</Component>
<?else?>
<Component Id="powertoys_env_path_machine" Bitness="always64">
@@ -24,8 +24,8 @@
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="powertoys_env_path_machine" Value="" KeyPath="yes" />
</RegistryKey>
<!-- Append install folder to machine PATH -->
<Environment Id="AddPowerToysToMachinePath" Name="PATH" Action="set" Part="last" System="yes" Value="[INSTALLFOLDER]" />
<!-- Append DSCModules folder to machine PATH for DSC v3 usage -->
<Environment Id="AddPowerToysToMachinePath" Name="PATH" Action="set" Part="last" System="yes" Value="[DSCModulesReferenceFolder]" />
</Component>
<?endif?>
<Component Id="powertoys_toast_clsid" Bitness="always64">
@@ -63,16 +63,6 @@
</Component>
</DirectoryRef>
<DirectoryRef Id="DSCModulesReferenceFolder">
<Component Id="PowerToysDSCReference" Guid="40869ACB-0BEB-4911-AE41-5E73BC1586A9" Bitness="always64">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="DSCModulesReference" Value="" KeyPath="yes" />
</RegistryKey>
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version).0\Microsoft.PowerToys.Configure.psd1" Id="PTConfReference.psd1" />
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version).0\Microsoft.PowerToys.Configure.psm1" Id="PTConfReference.psm1" />
</Component>
</DirectoryRef>
<?if $(var.PerUser) = "true" ?>
<!-- DSC module files for PerUser handled in InstallDSCModule custom action. -->
<?else?>
@@ -120,7 +110,6 @@
<RegistryValue Type="string" Name="RemoveCoreFolder" Value="" KeyPath="yes" />
</RegistryKey>
<RemoveFolder Id="RemoveBaseApplicationsAssetsFolder" Directory="BaseApplicationsAssetsFolder" On="uninstall" />
<RemoveFolder Id="RemoveDSCModulesReferenceFolder" Directory="DSCModulesReferenceFolder" On="uninstall" />
<RemoveFolder Id="RemoveWinUI3AppsInstallFolder" Directory="WinUI3AppsInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveWinUI3AppsAssetsFolder" Directory="WinUI3AppsAssetsFolder" On="uninstall" />
<RemoveFolder Id="RemoveINSTALLFOLDER" Directory="INSTALLFOLDER" On="uninstall" />
@@ -128,16 +117,15 @@
<ComponentRef Id="powertoys_exe" />
<ComponentRef Id="PowerToysStartMenuShortcut" />
<ComponentRef Id="powertoys_per_machine_comp" />
<?if $(var.PerUser) = "true" ?>
<ComponentRef Id="powertoys_env_path_user" />
<?else?>
<ComponentRef Id="powertoys_env_path_machine" />
<?endif?>
<ComponentRef Id="powertoys_toast_clsid" />
<ComponentRef Id="License_rtf" />
<ComponentRef Id="Notice_md" />
<ComponentRef Id="DesktopShortcut" />
<ComponentRef Id="PowerToysDSCReference" />
<?if $(var.PerUser) = "true" ?>
<ComponentRef Id="powertoys_env_path_user" />
<?else?>
<ComponentRef Id="powertoys_env_path_machine" />
<?endif?>
<?if $(var.PerUser) = "false" ?>
<ComponentRef Id="PowerToysDSC" />
<?endif?>

View File

@@ -1,5 +1,4 @@
<Project>
<Import Project="..\..\Directory.Build.props" Condition="Exists('..\..\Directory.Build.props')" />
<Import Project="..\..\src\Version.props" Condition="Exists('..\..\src\Version.props')" />
<PropertyGroup>
<!-- Set BaseIntermediateOutputPath for each project to avoid conflicts -->
@@ -9,4 +8,4 @@
<!-- Set MSBuildProjectExtensionsPath to use the BaseIntermediateOutputPath -->
<MSBuildProjectExtensionsPath Condition="'$(BaseIntermediateOutputPath)' != ''">$(BaseIntermediateOutputPath)</MSBuildProjectExtensionsPath>
</PropertyGroup>
</Project>
</Project>

View File

@@ -0,0 +1,33 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<?include $(sys.CURRENTDIR)\Common.wxi?>
<?define DscJsonFiles=?>
<?define DscJsonFilesPath=$(var.BinDir)\DSCModules?>
<Fragment>
<DirectoryRef Id="DSCModulesReferenceFolder" FileSource="$(var.DscJsonFilesPath)">
<!-- DSC v2 PowerShell module files -->
<Component Id="PowerToysDSCReference" Guid="40869ACB-0BEB-4911-AE41-5E73BC1586A9" Bitness="always64">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="DSCModulesReference" Value="" KeyPath="yes" />
</RegistryKey>
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version).0\Microsoft.PowerToys.Configure.psd1" Id="PTConfReference.psd1" />
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version).0\Microsoft.PowerToys.Configure.psm1" Id="PTConfReference.psm1" />
</Component>
<!-- DSC v3 JSON manifest files - Generated by generateAllFileComponents.ps1 -->
<!--DscJsonFiles_Component_Def-->
</DirectoryRef>
<ComponentGroup Id="DscResourcesComponentGroup">
<ComponentRef Id="PowerToysDSCReference" />
<Component Id="RemoveDSCModulesFolder" Guid="A3C77D92-4E97-4C1A-9F2E-8B3C5D6E7F80" Directory="DSCModulesReferenceFolder">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="RemoveDSCModulesFolder" Value="" KeyPath="yes" />
</RegistryKey>
<RemoveFolder Id="RemoveDSCModulesReferenceFolder" Directory="DSCModulesReferenceFolder" On="uninstall" />
</Component>
</ComponentGroup>
</Fragment>
</Wix>

View File

@@ -14,7 +14,6 @@ SET PTRoot=$(SolutionDir)\..
call "..\..\..\publish.cmd" x64
)
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateMonacoWxs.ps1 -monacoWxsFile "$(MSBuildThisFileDirectory)\MonacoSRC.wxs" -Platform "$(Platform)" -nugetHeatPath "$(NUGET_PACKAGES)\wixtoolset.heat\5.0.2"
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateDscResourcesWxs.ps1 -dscWxsFile "$(MSBuildThisFileDirectory)\DscResources.wxs" -Platform "$(Platform)" -Configuration "$(Configuration)"
</PreBuildEvent>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)' != 'x64'">
@@ -25,7 +24,6 @@ SET PTRoot=$(SolutionDir)\..
call "..\..\..\publish.cmd" arm64
)
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateMonacoWxs.ps1 -monacoWxsFile "$(MSBuildThisFileDirectory)\MonacoSRC.wxs" -Platform "$(Platform)" -nugetHeatPath "$(NUGET_PACKAGES)\wixtoolset.heat\5.0.2"
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateDscResourcesWxs.ps1 -dscWxsFile "$(MSBuildThisFileDirectory)\DscResources.wxs" -Platform "$(Platform)" -Configuration "$(Configuration)"
</PreBuildEvent>
</PropertyGroup>
<PropertyGroup>
@@ -37,6 +35,7 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
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 ..\..\..\DscResources.wxs.bk ..\..\..\DscResources.wxs
call move /Y ..\..\..\EnvironmentVariables.wxs.bk ..\..\..\EnvironmentVariables.wxs
call move /Y ..\..\..\FileExplorerPreview.wxs.bk ..\..\..\FileExplorerPreview.wxs
call move /Y ..\..\..\FileLocksmith.wxs.bk ..\..\..\FileLocksmith.wxs
@@ -60,6 +59,12 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
call move /Y ..\..\..\Workspaces.wxs.bk ..\..\..\Workspaces.wxs
</PostBuildEvent>
</PropertyGroup>
<PropertyGroup Condition="'$(RunBuildEvents)'=='false'">
<PostBuildEvent></PostBuildEvent>
<RunPostBuildEvent></RunPostBuildEvent>
<PreBuildEventUseInBuild>false</PreBuildEventUseInBuild>
<PostBuildEventUseInBuild>false</PostBuildEventUseInBuild>
</PropertyGroup>
<PropertyGroup Label="UserMacros" Condition=" '$(PerUser)' == 'true' ">
<DefineConstants>$(DefineConstants);PerUser=true</DefineConstants>
</PropertyGroup>

View File

@@ -120,8 +120,8 @@
<Custom Action="SetUnApplyModulesRegistryChangeSetsParam" Before="UnApplyModulesRegistryChangeSets" />
<Custom Action="CheckGPO" After="InstallInitialize" Condition="NOT Installed" />
<Custom Action="SetBundleInstallLocationData" Before="SetBundleInstallLocation" Condition="NOT Installed" />
<Custom Action="SetBundleInstallLocation" After="InstallFiles" Condition="NOT Installed" />
<Custom Action="SetBundleInstallLocationData" Before="SetBundleInstallLocation" Condition="NOT Installed OR WIX_UPGRADE_DETECTED" />
<Custom Action="SetBundleInstallLocation" After="InstallFiles" Condition="NOT Installed OR WIX_UPGRADE_DETECTED" />
<Custom Action="ApplyModulesRegistryChangeSets" After="InstallFiles" Condition="NOT Installed" />
<Custom Action="InstallCmdPalPackage" After="InstallFiles" Condition="NOT Installed" />
<Custom Action="InstallPackageIdentityMSIX" After="InstallFiles" Condition="NOT Installed" />

View File

@@ -14,11 +14,16 @@
<?define SettingsV2OOBEAssetsFluentIconsFiles=?>
<?define SettingsV2OOBEAssetsFluentIconsFilesPath=$(var.BinDir)WinUI3Apps\Assets\Settings\Icons\?>
<?define SettingsV2IconsModelsFiles=?>
<?define SettingsV2IconsModelsFilesPath=$(var.BinDir)WinUI3Apps\Assets\Settings\Icons\Models\?>
<Fragment>
<DirectoryRef Id="WinUI3AppsAssetsFolder">
<Directory Id="SettingsV2AssetsInstallFolder" Name="Settings">
<Directory Id="SettingsAppAssetsScriptsFolder" Name="Scripts" />
<Directory Id="SettingsV2OOBEAssetsFluentIconsInstallFolder" Name="Icons" />
<Directory Id="SettingsV2OOBEAssetsFluentIconsInstallFolder" Name="Icons">
<Directory Id="SettingsV2IconsModelsInstallFolder" Name="Models" />
</Directory>
<Directory Id="SettingsV2AssetsModulesInstallFolder" Name="Modules">
<Directory Id="SettingsV2OOBEAssetsModulesInstallFolder" Name="OOBE" />
</Directory>
@@ -45,6 +50,11 @@
<!--SettingsV2OOBEAssetsFluentIconsFiles_Component_Def-->
</DirectoryRef>
<DirectoryRef Id="SettingsV2IconsModelsInstallFolder" FileSource="$(var.SettingsV2IconsModelsFilesPath)">
<!-- Generated by generateFileComponents.ps1 -->
<!--SettingsV2IconsModelsFiles_Component_Def-->
</DirectoryRef>
<DirectoryRef Id="SettingsAppAssetsScriptsFolder" FileSource="$(var.SettingsV2AssetsFilesPath)\Scripts\">
<Component Id="CommandNotFound_Scripts" Guid="898EFA1E-EDD3-4F4B-8C7F-4A14B0D05B02" Bitness="always64">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
@@ -67,6 +77,7 @@
</RegistryKey>
<RemoveFolder Id="RemoveFolderSettingsV2AssetsInstallFolder" Directory="SettingsV2AssetsInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveFolderSettingsV2OOBEAssetsFluentIconsInstallFolder" Directory="SettingsV2OOBEAssetsFluentIconsInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveFolderSettingsV2IconsModelsInstallFolder" Directory="SettingsV2IconsModelsInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveFolderSettingsV2AssetsModulesInstallFolder" Directory="SettingsV2AssetsModulesInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveFolderSettingsV2OOBEAssetsModulesInstallFolder" Directory="SettingsV2OOBEAssetsModulesInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveFolderSettingsAppAssetsScriptsFolder" Directory="SettingsAppAssetsScriptsFolder" On="uninstall" />

View File

@@ -1,7 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{F8B9F842-F5C3-4A2D-8C85-7F8B9E2B4F1D}</ProjectGuid>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<TargetName>SilentFilesInUseBAFunction</TargetName>
<ProjectName>PowerToysSetupCustomActionsVNext</ProjectName>
<ProjectModuleDefinitionFile>bafunctions.def</ProjectModuleDefinitionFile>
@@ -10,6 +33,7 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<!-- Configuration-specific property groups -->
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
@@ -41,10 +65,7 @@
</PropertyGroup>
<ItemGroup>
<ClCompile Include="SilentFilesInUseBAFunctions.cpp">
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="SilentFilesInUseBAFunctions.cpp" />
<ClCompile Include="bafunctions.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
<PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
@@ -71,5 +92,31 @@
</Link>
</ItemDefinitionGroup>
<!-- C++ source compile-specific things for Debug/Release configurations -->
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Optimization>MaxSpeed</Optimization>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@@ -18,6 +18,7 @@ public: // IBootstrapperApplication
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "*** CUSTOM BA FUNCTION SYSTEM ACTIVE *** Running detect begin BA function. fCached=%d, registrationType=%d, cPackages=%u, fCancel=%d", fCached, registrationType, cPackages, *pfCancel);
LExit:
return hr;
}
@@ -31,6 +32,12 @@ public: // IBAFunctions
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "*** CUSTOM BA FUNCTION SYSTEM ACTIVE *** Running plan begin BA function. cPackages=%u, fCancel=%d", cPackages, *pfCancel);
//-------------------------------------------------------------------------------------------------
// YOUR CODE GOES HERE
// BalExitOnFailure(hr, "Change this message to represent real error handling.");
//-------------------------------------------------------------------------------------------------
LExit:
return hr;
}
@@ -56,7 +63,6 @@ public: // IBAFunctions
)
{
HRESULT hr = S_OK;
UNREFERENCED_PARAMETER(source);
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "*** CUSTOM BA FUNCTION CALLED *** Running OnExecuteFilesInUse BA function. packageId=%ls, cFiles=%u, recommendation=%d", wzPackageId, cFiles, nRecommendation);

View File

@@ -1,9 +1,7 @@
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True, Position = 1)]
[string]$platform,
[Parameter(Mandatory = $False, Position = 2)]
[string]$installscopeperuser = "false"
[string]$platform
)
Function Generate-FileList() {
@@ -77,9 +75,7 @@ Function Generate-FileComponents() {
[Parameter(Mandatory = $True, Position = 1)]
[string]$fileListName,
[Parameter(Mandatory = $True, Position = 2)]
[string]$wxsFilePath,
[Parameter(Mandatory = $True, Position = 3)]
[string]$regroot
[string]$wxsFilePath
)
$wxsFile = Get-Content $wxsFilePath;
@@ -100,7 +96,7 @@ Function Generate-FileComponents() {
$componentDefs +=
@"
<Component Id="$($componentId)" Guid="$((New-Guid).ToString().ToUpper())">
<RegistryKey Root="$($regroot)" Key="Software\Classes\powertoys\components">
<RegistryKey Root="`$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="$($componentId)" Value="" KeyPath="yes"/>
</RegistryKey>`r`n
"@
@@ -134,194 +130,194 @@ if ($platform -ceq "arm64") {
$platform = "ARM64"
}
if ($installscopeperuser -eq "true") {
$registryroot = "HKCU"
} else {
$registryroot = "HKLM"
}
#BaseApplications
Generate-FileList -fileDepsJson "" -fileListName BaseApplicationsFiles -wxsFilePath $PSScriptRoot\BaseApplications.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release"
Generate-FileComponents -fileListName "BaseApplicationsFiles" -wxsFilePath $PSScriptRoot\BaseApplications.wxs -regroot $registryroot
Generate-FileComponents -fileListName "BaseApplicationsFiles" -wxsFilePath $PSScriptRoot\BaseApplications.wxs
#WinUI3Applications
Generate-FileList -fileDepsJson "" -fileListName WinUI3ApplicationsFiles -wxsFilePath $PSScriptRoot\WinUI3Applications.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps"
Generate-FileComponents -fileListName "WinUI3ApplicationsFiles" -wxsFilePath $PSScriptRoot\WinUI3Applications.wxs -regroot $registryroot
Generate-FileComponents -fileListName "WinUI3ApplicationsFiles" -wxsFilePath $PSScriptRoot\WinUI3Applications.wxs
#AdvancedPaste
Generate-FileList -fileDepsJson "" -fileListName AdvancedPasteAssetsFiles -wxsFilePath $PSScriptRoot\AdvancedPaste.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\AdvancedPaste"
Generate-FileComponents -fileListName "AdvancedPasteAssetsFiles" -wxsFilePath $PSScriptRoot\AdvancedPaste.wxs -regroot $registryroot
Generate-FileComponents -fileListName "AdvancedPasteAssetsFiles" -wxsFilePath $PSScriptRoot\AdvancedPaste.wxs
#AwakeFiles
Generate-FileList -fileDepsJson "" -fileListName AwakeImagesFiles -wxsFilePath $PSScriptRoot\Awake.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\Awake"
Generate-FileComponents -fileListName "AwakeImagesFiles" -wxsFilePath $PSScriptRoot\Awake.wxs -regroot $registryroot
Generate-FileComponents -fileListName "AwakeImagesFiles" -wxsFilePath $PSScriptRoot\Awake.wxs
#ColorPicker
Generate-FileList -fileDepsJson "" -fileListName ColorPickerAssetsFiles -wxsFilePath $PSScriptRoot\ColorPicker.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\ColorPicker"
Generate-FileComponents -fileListName "ColorPickerAssetsFiles" -wxsFilePath $PSScriptRoot\ColorPicker.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ColorPickerAssetsFiles" -wxsFilePath $PSScriptRoot\ColorPicker.wxs
#Environment Variables
Generate-FileList -fileDepsJson "" -fileListName EnvironmentVariablesAssetsFiles -wxsFilePath $PSScriptRoot\EnvironmentVariables.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\EnvironmentVariables"
Generate-FileComponents -fileListName "EnvironmentVariablesAssetsFiles" -wxsFilePath $PSScriptRoot\EnvironmentVariables.wxs -regroot $registryroot
Generate-FileComponents -fileListName "EnvironmentVariablesAssetsFiles" -wxsFilePath $PSScriptRoot\EnvironmentVariables.wxs
#FileExplorerAdd-ons
Generate-FileList -fileDepsJson "" -fileListName MonacoPreviewHandlerMonacoAssetsFiles -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\Monaco"
Generate-FileList -fileDepsJson "" -fileListName MonacoPreviewHandlerCustomLanguagesFiles -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\Monaco\customLanguages"
Generate-FileComponents -fileListName "MonacoPreviewHandlerMonacoAssetsFiles" -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs -regroot $registryroot
Generate-FileComponents -fileListName "MonacoPreviewHandlerCustomLanguagesFiles" -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs -regroot $registryroot
Generate-FileComponents -fileListName "MonacoPreviewHandlerMonacoAssetsFiles" -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs
Generate-FileComponents -fileListName "MonacoPreviewHandlerCustomLanguagesFiles" -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs
#FileLocksmith
Generate-FileList -fileDepsJson "" -fileListName FileLocksmithAssetsFiles -wxsFilePath $PSScriptRoot\FileLocksmith.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\FileLocksmith"
Generate-FileComponents -fileListName "FileLocksmithAssetsFiles" -wxsFilePath $PSScriptRoot\FileLocksmith.wxs -regroot $registryroot
Generate-FileComponents -fileListName "FileLocksmithAssetsFiles" -wxsFilePath $PSScriptRoot\FileLocksmith.wxs
#Hosts
Generate-FileList -fileDepsJson "" -fileListName HostsAssetsFiles -wxsFilePath $PSScriptRoot\Hosts.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Hosts"
Generate-FileComponents -fileListName "HostsAssetsFiles" -wxsFilePath $PSScriptRoot\Hosts.wxs -regroot $registryroot
Generate-FileComponents -fileListName "HostsAssetsFiles" -wxsFilePath $PSScriptRoot\Hosts.wxs
#ImageResizer
Generate-FileList -fileDepsJson "" -fileListName ImageResizerAssetsFiles -wxsFilePath $PSScriptRoot\ImageResizer.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\ImageResizer"
Generate-FileComponents -fileListName "ImageResizerAssetsFiles" -wxsFilePath $PSScriptRoot\ImageResizer.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ImageResizerAssetsFiles" -wxsFilePath $PSScriptRoot\ImageResizer.wxs
# Light Switch Service
Generate-FileList -fileDepsJson "" -fileListName LightSwitchFiles -wxsFilePath $PSScriptRoot\LightSwitch.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\LightSwitchService"
Generate-FileComponents -fileListName "LightSwitchFiles" -wxsFilePath $PSScriptRoot\LightSwitch.wxs -regroot $registryroot
Generate-FileComponents -fileListName "LightSwitchFiles" -wxsFilePath $PSScriptRoot\LightSwitch.wxs
#New+
Generate-FileList -fileDepsJson "" -fileListName NewPlusAssetsFiles -wxsFilePath $PSScriptRoot\NewPlus.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\NewPlus"
Generate-FileComponents -fileListName "NewPlusAssetsFiles" -wxsFilePath $PSScriptRoot\NewPlus.wxs -regroot $registryroot
Generate-FileComponents -fileListName "NewPlusAssetsFiles" -wxsFilePath $PSScriptRoot\NewPlus.wxs
#Peek
Generate-FileList -fileDepsJson "" -fileListName PeekAssetsFiles -wxsFilePath $PSScriptRoot\Peek.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Peek\"
Generate-FileComponents -fileListName "PeekAssetsFiles" -wxsFilePath $PSScriptRoot\Peek.wxs -regroot $registryroot
Generate-FileComponents -fileListName "PeekAssetsFiles" -wxsFilePath $PSScriptRoot\Peek.wxs
#PowerRename
Generate-FileList -fileDepsJson "" -fileListName PowerRenameAssetsFiles -wxsFilePath $PSScriptRoot\PowerRename.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\PowerRename\"
Generate-FileComponents -fileListName "PowerRenameAssetsFiles" -wxsFilePath $PSScriptRoot\PowerRename.wxs -regroot $registryroot
Generate-FileComponents -fileListName "PowerRenameAssetsFiles" -wxsFilePath $PSScriptRoot\PowerRename.wxs
#RegistryPreview
Generate-FileList -fileDepsJson "" -fileListName RegistryPreviewAssetsFiles -wxsFilePath $PSScriptRoot\RegistryPreview.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\RegistryPreview\"
Generate-FileComponents -fileListName "RegistryPreviewAssetsFiles" -wxsFilePath $PSScriptRoot\RegistryPreview.wxs -regroot $registryroot
Generate-FileComponents -fileListName "RegistryPreviewAssetsFiles" -wxsFilePath $PSScriptRoot\RegistryPreview.wxs
#Run
Generate-FileList -fileDepsJson "" -fileListName launcherImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\PowerLauncher"
Generate-FileComponents -fileListName "launcherImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "launcherImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
## Plugins
###Calculator
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Calculator\Microsoft.PowerToys.Run.Plugin.Calculator.deps.json" -fileListName calcComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName calcImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Calculator\Images"
Generate-FileComponents -fileListName "calcComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "calcImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "calcComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "calcImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###Folder
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Folder\Microsoft.Plugin.Folder.deps.json" -fileListName FolderComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName FolderImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Folder\Images"
Generate-FileComponents -fileListName "FolderComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "FolderImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "FolderComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "FolderImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###Program
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Program\Microsoft.Plugin.Program.deps.json" -fileListName ProgramComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName ProgramImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Program\Images"
Generate-FileComponents -fileListName "ProgramComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ProgramImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ProgramComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ProgramImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###Shell
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Shell\Microsoft.Plugin.Shell.deps.json" -fileListName ShellComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName ShellImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Shell\Images"
Generate-FileComponents -fileListName "ShellComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ShellImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ShellComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ShellImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###Indexer
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Indexer\Microsoft.Plugin.Indexer.deps.json" -fileListName IndexerComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName IndexerImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Indexer\Images"
Generate-FileComponents -fileListName "IndexerComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "IndexerImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "IndexerComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "IndexerImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###UnitConverter
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\UnitConverter\Community.PowerToys.Run.Plugin.UnitConverter.deps.json" -fileListName UnitConvCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName UnitConvImagesCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\UnitConverter\Images"
Generate-FileComponents -fileListName "UnitConvCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "UnitConvImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "UnitConvCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "UnitConvImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###WebSearch
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WebSearch\Community.PowerToys.Run.Plugin.WebSearch.deps.json" -fileListName WebSrchCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName WebSrchImagesCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WebSearch\Images"
Generate-FileComponents -fileListName "WebSrchCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "WebSrchImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "WebSrchCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WebSrchImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###History
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\History\Microsoft.PowerToys.Run.Plugin.History.deps.json" -fileListName HistoryPluginComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName HistoryPluginImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\History\Images"
Generate-FileComponents -fileListName "HistoryPluginComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "HistoryPluginImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "HistoryPluginComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "HistoryPluginImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###Uri
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Uri\Microsoft.Plugin.Uri.deps.json" -fileListName UriComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName UriImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Uri\Images"
Generate-FileComponents -fileListName "UriComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "UriImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "UriComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "UriImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###VSCodeWorkspaces
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\VSCodeWorkspaces\Community.PowerToys.Run.Plugin.VSCodeWorkspaces.deps.json" -fileListName VSCWrkCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName VSCWrkImagesCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\VSCodeWorkspaces\Images"
Generate-FileComponents -fileListName "VSCWrkCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "VSCWrkImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "VSCWrkCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "VSCWrkImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###WindowWalker
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WindowWalker\Microsoft.Plugin.WindowWalker.deps.json" -fileListName WindowWlkrCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName WindowWlkrImagesCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WindowWalker\Images"
Generate-FileComponents -fileListName "WindowWlkrCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "WindowWlkrImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "WindowWlkrCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WindowWlkrImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###OneNote
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\OneNote\Microsoft.PowerToys.Run.Plugin.OneNote.deps.json" -fileListName OneNoteComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName OneNoteImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\OneNote\Images"
Generate-FileComponents -fileListName "OneNoteComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "OneNoteImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "OneNoteComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "OneNoteImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###Registry
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Registry\Microsoft.PowerToys.Run.Plugin.Registry.deps.json" -fileListName RegistryComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName RegistryImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Registry\Images"
Generate-FileComponents -fileListName "RegistryComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "RegistryImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "RegistryComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "RegistryImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###Service
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Service\Microsoft.PowerToys.Run.Plugin.Service.deps.json" -fileListName ServiceComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName ServiceImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Service\Images"
Generate-FileComponents -fileListName "ServiceComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ServiceImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ServiceComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ServiceImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###System
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\System\Microsoft.PowerToys.Run.Plugin.System.deps.json" -fileListName SystemComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName SystemImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\System\Images"
Generate-FileComponents -fileListName "SystemComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "SystemImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "SystemComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "SystemImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###TimeDate
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\TimeDate\Microsoft.PowerToys.Run.Plugin.TimeDate.deps.json" -fileListName TimeDateComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName TimeDateImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\TimeDate\Images"
Generate-FileComponents -fileListName "TimeDateComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "TimeDateImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "TimeDateComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "TimeDateImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###WindowsSettings
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WindowsSettings\Microsoft.PowerToys.Run.Plugin.WindowsSettings.deps.json" -fileListName WinSetCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName WinSetImagesCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WindowsSettings\Images"
Generate-FileComponents -fileListName "WinSetCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "WinSetImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "WinSetCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WinSetImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###WindowsTerminal
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WindowsTerminal\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.deps.json" -fileListName WinTermCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName WinTermImagesCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WindowsTerminal\Images"
Generate-FileComponents -fileListName "WinTermCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "WinTermImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "WinTermCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WinTermImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###PowerToys
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\PowerToys\Microsoft.PowerToys.Run.Plugin.PowerToys.deps.json" -fileListName PowerToysCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName PowerToysImagesCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\PowerToys\Images"
Generate-FileComponents -fileListName "PowerToysCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "PowerToysImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "PowerToysCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "PowerToysImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
###ValueGenerator
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\ValueGenerator\Community.PowerToys.Run.Plugin.ValueGenerator.deps.json" -fileListName ValueGeneratorCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName ValueGeneratorImagesCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\ValueGenerator\Images"
Generate-FileComponents -fileListName "ValueGeneratorCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ValueGeneratorImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ValueGeneratorCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ValueGeneratorImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
## Plugins
#ShortcutGuide
Generate-FileList -fileDepsJson "" -fileListName ShortcutGuideSvgFiles -wxsFilePath $PSScriptRoot\ShortcutGuide.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\ShortcutGuide\"
Generate-FileComponents -fileListName "ShortcutGuideSvgFiles" -wxsFilePath $PSScriptRoot\ShortcutGuide.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ShortcutGuideSvgFiles" -wxsFilePath $PSScriptRoot\ShortcutGuide.wxs
#Settings
Generate-FileList -fileDepsJson "" -fileListName SettingsV2AssetsFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\"
Generate-FileList -fileDepsJson "" -fileListName SettingsV2AssetsModulesFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\Modules\"
Generate-FileList -fileDepsJson "" -fileListName SettingsV2OOBEAssetsModulesFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\Modules\OOBE\"
Generate-FileList -fileDepsJson "" -fileListName SettingsV2OOBEAssetsFluentIconsFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\Icons\"
Generate-FileComponents -fileListName "SettingsV2AssetsFiles" -wxsFilePath $PSScriptRoot\Settings.wxs -regroot $registryroot
Generate-FileComponents -fileListName "SettingsV2AssetsModulesFiles" -wxsFilePath $PSScriptRoot\Settings.wxs -regroot $registryroot
Generate-FileComponents -fileListName "SettingsV2OOBEAssetsModulesFiles" -wxsFilePath $PSScriptRoot\Settings.wxs -regroot $registryroot
Generate-FileComponents -fileListName "SettingsV2OOBEAssetsFluentIconsFiles" -wxsFilePath $PSScriptRoot\Settings.wxs -regroot $registryroot
Generate-FileList -fileDepsJson "" -fileListName SettingsV2IconsModelsFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\Icons\Models\"
Generate-FileComponents -fileListName "SettingsV2AssetsFiles" -wxsFilePath $PSScriptRoot\Settings.wxs
Generate-FileComponents -fileListName "SettingsV2AssetsModulesFiles" -wxsFilePath $PSScriptRoot\Settings.wxs
Generate-FileComponents -fileListName "SettingsV2OOBEAssetsModulesFiles" -wxsFilePath $PSScriptRoot\Settings.wxs
Generate-FileComponents -fileListName "SettingsV2OOBEAssetsFluentIconsFiles" -wxsFilePath $PSScriptRoot\Settings.wxs
Generate-FileComponents -fileListName "SettingsV2IconsModelsFiles" -wxsFilePath $PSScriptRoot\Settings.wxs
#Workspaces
Generate-FileList -fileDepsJson "" -fileListName WorkspacesImagesComponentFiles -wxsFilePath $PSScriptRoot\Workspaces.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\Workspaces\"
Generate-FileComponents -fileListName "WorkspacesImagesComponentFiles" -wxsFilePath $PSScriptRoot\Workspaces.wxs -regroot $registryroot
Generate-FileComponents -fileListName "WorkspacesImagesComponentFiles" -wxsFilePath $PSScriptRoot\Workspaces.wxs
#DSC Resources - JSON manifest files in DSCModules subfolder
Generate-FileList -fileDepsJson "" -fileListName DscJsonFiles -wxsFilePath $PSScriptRoot\DscResources.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\DSCModules\"
Generate-FileComponents -fileListName "DscJsonFiles" -wxsFilePath $PSScriptRoot\DscResources.wxs

View File

@@ -1,102 +0,0 @@
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True)]
[string]$dscWxsFile,
[Parameter(Mandatory = $True)]
[string]$Platform,
[Parameter(Mandatory = $True)]
[string]$Configuration
)
$ErrorActionPreference = 'Stop'
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
# Find build output directory
$buildOutputDir = Join-Path $scriptDir "..\..\$Platform\$Configuration"
if (-not (Test-Path $buildOutputDir)) {
Write-Error "Build output directory not found: '$buildOutputDir'"
exit 1
}
# Find all DSC manifest JSON files
$dscFiles = Get-ChildItem -Path $buildOutputDir -Filter "microsoft.powertoys.*.settings.dsc.resource.json" -File
if (-not $dscFiles) {
Write-Warning "No DSC manifest files found in '$buildOutputDir'"
# Create empty component group
$wxsContent = @"
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<?include `$(sys.CURRENTDIR)\Common.wxi?>
<Fragment>
<ComponentGroup Id="DscResourcesComponentGroup">
</ComponentGroup>
</Fragment>
</Wix>
"@
Set-Content -Path $dscWxsFile -Value $wxsContent
exit 0
}
Write-Host "Found $($dscFiles.Count) DSC manifest file(s)"
# Generate WiX fragment
$wxsContent = @"
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<?include `$(sys.CURRENTDIR)\Common.wxi?>
<Fragment>
<DirectoryRef Id="DSCModulesReferenceFolder">
"@
$componentRefs = @()
foreach ($file in $dscFiles) {
$componentId = "DscResource_" + ($file.BaseName -replace '[^A-Za-z0-9_]', '_')
$fileId = $componentId + "_File"
$guid = [System.Guid]::NewGuid().ToString().ToUpper()
$componentRefs += $componentId
$wxsContent += @"
<Component Id="$componentId" Guid="{$guid}" Directory="DSCModulesReferenceFolder">
<RegistryKey Root="`$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="$componentId" Value="" KeyPath="yes"/>
</RegistryKey>
<File Id="$fileId" Source="`$(var.BinDir)$($file.Name)" Vital="no"/>
</Component>
"@
}
$wxsContent += @"
</DirectoryRef>
</Fragment>
<Fragment>
<ComponentGroup Id="DscResourcesComponentGroup">
"@
foreach ($componentId in $componentRefs) {
$wxsContent += @"
<ComponentRef Id="$componentId"/>
"@
}
$wxsContent += @"
</ComponentGroup>
</Fragment>
</Wix>
"@
# Write the WiX file
Set-Content -Path $dscWxsFile -Value $wxsContent
Write-Host "Generated DSC resources WiX fragment: '$dscWxsFile'"

View File

@@ -42,7 +42,8 @@
Description="PowerToys OCR Module"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">
Square44x44Logo="Images\Square44x44Logo.png"
AppListEntry="none">
</uap:VisualElements>
</Application>
<Application Id="PowerToys.SettingsUI" Executable="WinUI3Apps\PowerToys.Settings.exe" EntryPoint="Windows.FullTrustApplication">
@@ -51,7 +52,8 @@
Description="PowerToys Settings UI"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">
Square44x44Logo="Images\Square44x44Logo.png"
AppListEntry="none">
</uap:VisualElements>
</Application>
<Application Id="PowerToys.ImageResizerUI" Executable="WinUI3Apps\PowerToys.ImageResizer.exe" EntryPoint="Windows.FullTrustApplication">
@@ -60,7 +62,8 @@
Description="PowerToys Image Resizer UI"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">
Square44x44Logo="Images\Square44x44Logo.png"
AppListEntry="none">
</uap:VisualElements>
</Application>
</Applications>

View File

@@ -9,6 +9,12 @@
<RootNamespace>CalculatorEngineCommon</RootNamespace>
<AppxPackage>false</AppxPackage>
</PropertyGroup>
<!-- BEGIN common.build.pre.props -->
<PropertyGroup Label="Configuration">
<EnableHybridCRT>true</EnableHybridCRT>
<UseCrtSDKReferenceStaticWarning Condition="'$(EnableHybridCRT)'=='true'">false</UseCrtSDKReferenceStaticWarning>
</PropertyGroup>
<!-- END common.build.pre.props -->
<!-- BEGIN cppwinrt.build.pre.props -->
<PropertyGroup Label="Globals">
<CppWinRTEnabled>true</CppWinRTEnabled>
@@ -19,9 +25,11 @@
</PropertyGroup>
<PropertyGroup>
<MinimalCoreWin>true</MinimalCoreWin>
<AppContainerApplication>false</AppContainerApplication>
<AppContainerApplication>true</AppContainerApplication>
<WindowsStoreApp>true</WindowsStoreApp>
<ApplicationType>Windows Store</ApplicationType>
<UseCrtSDKReference Condition="'$(EnableHybridCRT)'=='true'">false</UseCrtSDKReference>
<!-- The SDK reference breaks the Hybrid CRT -->
</PropertyGroup>
<PropertyGroup>
<!-- We have to use the Desktop platform for Hybrid CRT to work. -->
@@ -140,5 +148,43 @@
</PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target> <!-- END common.build.post.props -->
</Target>
<!-- BEGIN common.build.post.props -->
<!--
The Hybrid CRT model statically links the runtime and STL and dynamically
links the UCRT instead of the VC++ CRT. The UCRT ships with Windows.
WinAppSDK asserts that this is "supported according to the CRT maintainer."
This must come before Microsoft.Cpp.targets because it manipulates ClCompile.RuntimeLibrary.
-->
<ItemDefinitionGroup Condition="'$(EnableHybridCRT)'=='true' and '$(Configuration)'=='Debug'">
<ClCompile>
<!-- We use MultiThreadedDebug, rather than MultiThreadedDebugDLL, to avoid DLL dependencies on VCRUNTIME140d.dll and MSVCP140d.dll. -->
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrtd.lib</IgnoreSpecificDefaultLibraries>
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrtd.lib</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(EnableHybridCRT)'=='true' and ('$(Configuration)'=='Release' or '$(Configuration)'=='AuditMode')">
<ClCompile>
<!-- We use MultiThreaded, rather than MultiThreadedDLL, to avoid DLL dependencies on VCRUNTIME140.dll and MSVCP140.dll. -->
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrt.lib</IgnoreSpecificDefaultLibraries>
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrt.lib</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<!-- END common.build.post.props -->
</Project>

View File

@@ -112,6 +112,10 @@ namespace winrt::PowerToys::GPOWrapper::implementation
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredMousePointerCrosshairsEnabledValue());
}
GpoRuleConfigured GPOWrapper::GetConfiguredCursorWrapEnabledValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredCursorWrapEnabledValue());
}
GpoRuleConfigured GPOWrapper::GetConfiguredPowerRenameEnabledValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredPowerRenameEnabledValue());
@@ -192,6 +196,34 @@ namespace winrt::PowerToys::GPOWrapper::implementation
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteOnlineAIModelsValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteOpenAIValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteOpenAIValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteAzureOpenAIValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteAzureOpenAIValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteAzureAIInferenceValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteAzureAIInferenceValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteMistralValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteMistralValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteGoogleValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteGoogleValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteOllamaValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteOllamaValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteFoundryLocalValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteFoundryLocalValue());
}
GpoRuleConfigured GPOWrapper::GetConfiguredNewPlusEnabledValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredNewPlusEnabledValue());

View File

@@ -35,6 +35,7 @@ namespace winrt::PowerToys::GPOWrapper::implementation
static GpoRuleConfigured GetConfiguredMouseHighlighterEnabledValue();
static GpoRuleConfigured GetConfiguredMouseJumpEnabledValue();
static GpoRuleConfigured GetConfiguredMousePointerCrosshairsEnabledValue();
static GpoRuleConfigured GetConfiguredCursorWrapEnabledValue();
static GpoRuleConfigured GetConfiguredPowerRenameEnabledValue();
static GpoRuleConfigured GetConfiguredPowerLauncherEnabledValue();
static GpoRuleConfigured GetConfiguredQuickAccentEnabledValue();
@@ -54,6 +55,13 @@ namespace winrt::PowerToys::GPOWrapper::implementation
static GpoRuleConfigured GetConfiguredQoiPreviewEnabledValue();
static GpoRuleConfigured GetConfiguredQoiThumbnailsEnabledValue();
static GpoRuleConfigured GetAllowedAdvancedPasteOnlineAIModelsValue();
static GpoRuleConfigured GetAllowedAdvancedPasteOpenAIValue();
static GpoRuleConfigured GetAllowedAdvancedPasteAzureOpenAIValue();
static GpoRuleConfigured GetAllowedAdvancedPasteAzureAIInferenceValue();
static GpoRuleConfigured GetAllowedAdvancedPasteMistralValue();
static GpoRuleConfigured GetAllowedAdvancedPasteGoogleValue();
static GpoRuleConfigured GetAllowedAdvancedPasteOllamaValue();
static GpoRuleConfigured GetAllowedAdvancedPasteFoundryLocalValue();
static GpoRuleConfigured GetConfiguredNewPlusEnabledValue();
static GpoRuleConfigured GetConfiguredWorkspacesEnabledValue();
static GpoRuleConfigured GetConfiguredMwbClipboardSharingEnabledValue();

View File

@@ -38,6 +38,7 @@ namespace PowerToys
static GpoRuleConfigured GetConfiguredMouseHighlighterEnabledValue();
static GpoRuleConfigured GetConfiguredMouseJumpEnabledValue();
static GpoRuleConfigured GetConfiguredMousePointerCrosshairsEnabledValue();
static GpoRuleConfigured GetConfiguredCursorWrapEnabledValue();
static GpoRuleConfigured GetConfiguredMouseWithoutBordersEnabledValue();
static GpoRuleConfigured GetConfiguredPowerRenameEnabledValue();
static GpoRuleConfigured GetConfiguredPowerLauncherEnabledValue();
@@ -58,6 +59,13 @@ namespace PowerToys
static GpoRuleConfigured GetConfiguredQoiPreviewEnabledValue();
static GpoRuleConfigured GetConfiguredQoiThumbnailsEnabledValue();
static GpoRuleConfigured GetAllowedAdvancedPasteOnlineAIModelsValue();
static GpoRuleConfigured GetAllowedAdvancedPasteOpenAIValue();
static GpoRuleConfigured GetAllowedAdvancedPasteAzureOpenAIValue();
static GpoRuleConfigured GetAllowedAdvancedPasteAzureAIInferenceValue();
static GpoRuleConfigured GetAllowedAdvancedPasteMistralValue();
static GpoRuleConfigured GetAllowedAdvancedPasteGoogleValue();
static GpoRuleConfigured GetAllowedAdvancedPasteOllamaValue();
static GpoRuleConfigured GetAllowedAdvancedPasteFoundryLocalValue();
static GpoRuleConfigured GetConfiguredNewPlusEnabledValue();
static GpoRuleConfigured GetConfiguredWorkspacesEnabledValue();
static GpoRuleConfigured GetConfiguredMwbClipboardSharingEnabledValue();

View File

@@ -0,0 +1,7 @@
// 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 LanguageModelProvider.FoundryLocal;
internal sealed record FoundryCachedModel(string Name, string? Id);

View File

@@ -0,0 +1,61 @@
// 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;
namespace LanguageModelProvider.FoundryLocal;
internal sealed record FoundryCatalogModel
{
[JsonPropertyName("name")]
public string Name { get; init; } = string.Empty;
[JsonPropertyName("displayName")]
public string DisplayName { get; init; } = string.Empty;
[JsonPropertyName("providerType")]
public string ProviderType { get; init; } = string.Empty;
[JsonPropertyName("uri")]
public string Uri { get; init; } = string.Empty;
[JsonPropertyName("version")]
public string Version { get; init; } = string.Empty;
[JsonPropertyName("modelType")]
public string ModelType { get; init; } = string.Empty;
[JsonPropertyName("promptTemplate")]
public PromptTemplate PromptTemplate { get; init; } = default!;
[JsonPropertyName("publisher")]
public string Publisher { get; init; } = string.Empty;
[JsonPropertyName("task")]
public string Task { get; init; } = string.Empty;
[JsonPropertyName("runtime")]
public Runtime Runtime { get; init; } = default!;
[JsonPropertyName("fileSizeMb")]
public long FileSizeMb { get; init; }
[JsonPropertyName("modelSettings")]
public ModelSettings ModelSettings { get; init; } = default!;
[JsonPropertyName("alias")]
public string Alias { get; init; } = string.Empty;
[JsonPropertyName("supportsToolCalling")]
public bool SupportsToolCalling { get; init; }
[JsonPropertyName("license")]
public string License { get; init; } = string.Empty;
[JsonPropertyName("licenseDescription")]
public string LicenseDescription { get; init; } = string.Empty;
[JsonPropertyName("parentModelUri")]
public string ParentModelUri { get; init; } = string.Empty;
}

View File

@@ -0,0 +1,279 @@
// 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 ManagedCommon;
using Microsoft.AI.Foundry.Local;
namespace LanguageModelProvider.FoundryLocal;
internal sealed class FoundryClient
{
public static async Task<FoundryClient?> CreateAsync()
{
// First attempt with current environment
var client = await TryCreateClientAsync().ConfigureAwait(false);
if (client != null)
{
return client;
}
// If failed, refresh PATH from registry and retry once
// This handles cases where PowerToys was launched by MSI installer.
Logger.LogInfo("[FoundryClient] First attempt failed, refreshing PATH and retrying");
RefreshEnvironmentPath();
return await TryCreateClientAsync().ConfigureAwait(false);
}
private static async Task<FoundryClient?> TryCreateClientAsync()
{
try
{
Logger.LogInfo("[FoundryClient] Creating Foundry Local client");
var manager = new FoundryLocalManager();
// Check if service is already running
if (manager.IsServiceRunning)
{
Logger.LogInfo("[FoundryClient] Foundry service is already running");
return new FoundryClient(manager);
}
// Start the service using SDK's method
Logger.LogInfo("[FoundryClient] Starting Foundry service using manager.StartServiceAsync()");
await manager.StartServiceAsync().ConfigureAwait(false);
Logger.LogInfo("[FoundryClient] Foundry service started successfully");
return new FoundryClient(manager);
}
catch (Exception ex)
{
Logger.LogError($"[FoundryClient] Error creating client: {ex.Message}");
if (ex.InnerException != null)
{
Logger.LogError($"[FoundryClient] Inner exception: {ex.InnerException.Message}");
}
return null;
}
}
private readonly FoundryLocalManager _foundryManager;
private readonly List<FoundryCatalogModel> _catalogModels = [];
private FoundryClient(FoundryLocalManager foundryManager)
{
_foundryManager = foundryManager;
}
public Task<string?> GetServiceUrl()
{
try
{
return Task.FromResult(_foundryManager.Endpoint?.ToString());
}
catch
{
return Task.FromResult<string?>(null);
}
}
public Uri? GetServiceUri()
{
try
{
return _foundryManager.ServiceUri;
}
catch
{
return null;
}
}
public async Task<List<FoundryCatalogModel>> ListCatalogModels()
{
if (_catalogModels.Count > 0)
{
return _catalogModels;
}
try
{
Logger.LogInfo("[FoundryClient] Listing catalog models");
var models = await _foundryManager.ListCatalogModelsAsync().ConfigureAwait(false);
if (models != null)
{
foreach (var model in models)
{
_catalogModels.Add(new FoundryCatalogModel
{
Name = model.ModelId ?? string.Empty,
DisplayName = model.DisplayName ?? string.Empty,
ProviderType = model.ProviderType ?? string.Empty,
Uri = model.Uri ?? string.Empty,
Version = model.Version ?? string.Empty,
ModelType = model.ModelType ?? string.Empty,
Publisher = model.Publisher ?? string.Empty,
Task = model.Task ?? string.Empty,
FileSizeMb = model.FileSizeMb,
Alias = model.Alias ?? string.Empty,
License = model.License ?? string.Empty,
LicenseDescription = model.LicenseDescription ?? string.Empty,
ParentModelUri = model.ParentModelUri ?? string.Empty,
SupportsToolCalling = model.SupportsToolCalling,
});
}
Logger.LogInfo($"[FoundryClient] Found {_catalogModels.Count} catalog models");
}
}
catch (Exception ex)
{
Logger.LogError($"[FoundryClient] Error listing catalog models: {ex.Message}");
// Surfacing errors here prevents listing other providers; swallow and return cached list instead.
}
return _catalogModels;
}
public async Task<List<FoundryCachedModel>> ListCachedModels()
{
try
{
Logger.LogInfo("[FoundryClient] Listing cached models");
var cachedModels = await _foundryManager.ListCachedModelsAsync().ConfigureAwait(false);
var catalogModels = await ListCatalogModels().ConfigureAwait(false);
List<FoundryCachedModel> models = [];
foreach (var model in cachedModels)
{
var catalogModel = catalogModels.FirstOrDefault(m => m.Name == model.ModelId);
var alias = catalogModel?.Alias ?? model.Alias;
models.Add(new FoundryCachedModel(model.ModelId ?? string.Empty, alias));
}
Logger.LogInfo($"[FoundryClient] Found {models.Count} cached models");
return models;
}
catch (Exception ex)
{
Logger.LogError($"[FoundryClient] Error listing cached models: {ex.Message}");
return [];
}
}
public async Task<bool> IsModelLoaded(string modelId)
{
try
{
var loadedModels = await _foundryManager.ListLoadedModelsAsync().ConfigureAwait(false);
var isLoaded = loadedModels.Any(m => m.ModelId == modelId);
Logger.LogInfo($"[FoundryClient] IsModelLoaded({modelId}): {isLoaded}");
Logger.LogInfo($"[FoundryClient] Loaded models: {string.Join(", ", loadedModels.Select(m => m.ModelId))}");
return isLoaded;
}
catch (Exception ex)
{
Logger.LogError($"[FoundryClient] IsModelLoaded exception: {ex.Message}");
return false;
}
}
public async Task<bool> EnsureModelLoaded(string modelId)
{
Logger.LogInfo($"[FoundryClient] EnsureModelLoaded called with: {modelId}");
// Check if already loaded
if (await IsModelLoaded(modelId).ConfigureAwait(false))
{
Logger.LogInfo($"[FoundryClient] Model already loaded: {modelId}");
return true;
}
// Load the model
Logger.LogInfo($"[FoundryClient] Loading model: {modelId}");
await _foundryManager.LoadModelAsync(modelId).ConfigureAwait(false);
// Verify it's loaded
var loaded = await IsModelLoaded(modelId).ConfigureAwait(false);
Logger.LogInfo($"[FoundryClient] Model load result: {loaded}");
return loaded;
}
public async Task EnsureRunning()
{
if (!_foundryManager.IsServiceRunning)
{
await _foundryManager.StartServiceAsync();
}
}
/// <summary>
/// Refreshes the PATH environment variable from the system registry.
/// This is necessary when tools are installed while PowerToys is running,
/// as the installer updates the system PATH but running processes don't see the change.
/// </summary>
private static void RefreshEnvironmentPath()
{
try
{
Logger.LogInfo("[FoundryClient] Refreshing PATH environment variable from system");
var currentPath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process) ?? string.Empty;
var machinePath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine) ?? string.Empty;
var userPath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.User) ?? string.Empty;
var pathsToAdd = new List<string>();
if (!string.IsNullOrWhiteSpace(currentPath))
{
pathsToAdd.AddRange(currentPath.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries));
}
if (!string.IsNullOrWhiteSpace(userPath))
{
var userPaths = userPath.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries);
foreach (var path in userPaths)
{
if (!pathsToAdd.Contains(path, StringComparer.OrdinalIgnoreCase))
{
pathsToAdd.Add(path);
}
}
}
if (!string.IsNullOrWhiteSpace(machinePath))
{
var machinePaths = machinePath.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries);
foreach (var path in machinePaths)
{
if (!pathsToAdd.Contains(path, StringComparer.OrdinalIgnoreCase))
{
pathsToAdd.Add(path);
}
}
}
var newPath = string.Join(Path.PathSeparator.ToString(), pathsToAdd);
if (currentPath != newPath)
{
Logger.LogInfo("[FoundryClient] Updating process PATH with latest system values");
Environment.SetEnvironmentVariable("PATH", newPath, EnvironmentVariableTarget.Process);
}
else
{
Logger.LogInfo("[FoundryClient] PATH is already up to date");
}
}
catch (Exception ex)
{
Logger.LogError($"[FoundryClient] Failed to refresh PATH: {ex.Message}");
}
}
}

View File

@@ -0,0 +1,17 @@
// 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.Collections.Generic;
using System.Text.Json.Serialization;
namespace LanguageModelProvider.FoundryLocal;
[JsonSourceGenerationOptions(
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
WriteIndented = false)]
[JsonSerializable(typeof(FoundryCatalogModel))]
[JsonSerializable(typeof(List<FoundryCatalogModel>))]
internal sealed partial class FoundryJsonContext : JsonSerializerContext
{
}

View File

@@ -0,0 +1,16 @@
// 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.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace LanguageModelProvider.FoundryLocal;
internal sealed record ModelSettings
{
// The sample shows an empty array; keep it open-ended.
[JsonPropertyName("parameters")]
public List<JsonElement> Parameters { get; init; } = [];
}

View File

@@ -0,0 +1,16 @@
// 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;
namespace LanguageModelProvider.FoundryLocal;
internal sealed record PromptTemplate
{
[JsonPropertyName("assistant")]
public string Assistant { get; init; } = string.Empty;
[JsonPropertyName("prompt")]
public string Prompt { get; init; } = string.Empty;
}

View File

@@ -0,0 +1,16 @@
// 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;
namespace LanguageModelProvider.FoundryLocal;
internal sealed record Runtime
{
[JsonPropertyName("deviceType")]
public string DeviceType { get; init; } = string.Empty;
[JsonPropertyName("executionProvider")]
public string ExecutionProvider { get; init; } = string.Empty;
}

View File

@@ -0,0 +1,156 @@
// 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.ClientModel;
using LanguageModelProvider.FoundryLocal;
using ManagedCommon;
using Microsoft.Extensions.AI;
using OpenAI;
namespace LanguageModelProvider;
public sealed class FoundryLocalModelProvider : ILanguageModelProvider
{
private FoundryClient? _foundryClient;
private IEnumerable<FoundryCatalogModel>? _catalogModels;
private string? _serviceUrl;
public static FoundryLocalModelProvider Instance { get; } = new();
public string Name => "FoundryLocal";
public string ProviderDescription => "The model will run locally via Foundry Local";
public IChatClient? GetIChatClient(string modelId)
{
Logger.LogInfo($"[FoundryLocal] GetIChatClient called with url: {modelId}");
InitializeAsync().GetAwaiter().GetResult();
if (string.IsNullOrWhiteSpace(modelId))
{
Logger.LogError("[FoundryLocal] Model ID is empty after extraction");
return null;
}
// Check if model is in catalog
var isInCatalog = _catalogModels?.Any(m => m.Name == modelId) ?? false;
if (!isInCatalog)
{
var errorMessage = $"{modelId} is not supported in Foundry Local. Please configure supported models in Settings.";
Logger.LogError($"[FoundryLocal] {errorMessage}");
throw new InvalidOperationException(errorMessage);
}
// Ensure the model is loaded before returning chat client
var isLoaded = _foundryClient!.EnsureModelLoaded(modelId).GetAwaiter().GetResult();
if (!isLoaded)
{
Logger.LogError($"[FoundryLocal] Failed to load model: {modelId}");
throw new InvalidOperationException($"Failed to load the model '{modelId}'.");
}
// Use ServiceUri instead of Endpoint since Endpoint already includes /v1
var baseUri = _foundryClient.GetServiceUri();
if (baseUri == null)
{
const string message = "Foundry Local service URL is not available. Please make sure Foundry Local is installed and running.";
Logger.LogError($"[FoundryLocal] {message}");
throw new InvalidOperationException(message);
}
var endpointUri = new Uri($"{baseUri.ToString().TrimEnd('/')}/v1");
Logger.LogInfo($"[FoundryLocal] Creating OpenAI client with endpoint: {endpointUri}");
return new OpenAIClient(
new ApiKeyCredential("none"),
new OpenAIClientOptions { Endpoint = endpointUri, NetworkTimeout = TimeSpan.FromMinutes(5) })
.GetChatClient(modelId)
.AsIChatClient();
}
public string GetIChatClientString(string url)
{
try
{
InitializeAsync().GetAwaiter().GetResult();
}
catch
{
return string.Empty;
}
var modelId = url.Split('/').LastOrDefault();
if (string.IsNullOrWhiteSpace(_serviceUrl) || string.IsNullOrWhiteSpace(modelId))
{
return string.Empty;
}
return $"new OpenAIClient(new ApiKeyCredential(\"none\"), new OpenAIClientOptions{{ Endpoint = new Uri(\"{_serviceUrl}/v1\") }}).GetChatClient(\"{modelId}\").AsIChatClient()";
}
public async Task<IEnumerable<ModelDetails>> GetModelsAsync(CancellationToken cancelationToken = default)
{
await InitializeAsync(cancelationToken);
if (_foundryClient == null)
{
return Array.Empty<ModelDetails>();
}
var cachedModels = await _foundryClient.ListCachedModels();
List<ModelDetails> downloadedModels = [];
foreach (var model in cachedModels)
{
Logger.LogInfo($"[FoundryLocal] Adding unmatched cached model: {model.Name}");
downloadedModels.Add(new ModelDetails
{
Id = $"fl-{model.Name}",
Name = model.Name,
Url = $"fl://{model.Name}",
Description = $"{model.Name} running locally with Foundry Local",
HardwareAccelerators = [HardwareAccelerator.FOUNDRYLOCAL],
ProviderModelDetails = model,
});
}
return downloadedModels;
}
private async Task InitializeAsync(CancellationToken cancelationToken = default)
{
if (_foundryClient != null && _catalogModels != null && _catalogModels.Any())
{
await _foundryClient.EnsureRunning().ConfigureAwait(false);
return;
}
Logger.LogInfo("[FoundryLocal] Initializing provider");
_foundryClient ??= await FoundryClient.CreateAsync();
if (_foundryClient == null)
{
const string message = "Foundry Local client could not be created. Please make sure Foundry Local is installed and running.";
Logger.LogError($"[FoundryLocal] {message}");
throw new InvalidOperationException(message);
}
_serviceUrl ??= await _foundryClient.GetServiceUrl();
Logger.LogInfo($"[FoundryLocal] Service URL: {_serviceUrl}");
var catalogModels = await _foundryClient.ListCatalogModels();
Logger.LogInfo($"[FoundryLocal] Found {catalogModels.Count} catalog models");
_catalogModels = catalogModels;
}
public async Task<bool> IsAvailable()
{
Logger.LogInfo("[FoundryLocal] Checking availability");
await InitializeAsync();
var available = _foundryClient != null;
Logger.LogInfo($"[FoundryLocal] Available: {available}");
return available;
}
}

View File

@@ -0,0 +1,22 @@
// 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 LanguageModelProvider;
public enum HardwareAccelerator
{
CPU,
DML,
QNN,
WCRAPI,
OLLAMA,
OPENAI,
FOUNDRYLOCAL,
LEMONADE,
NPU,
GPU,
VitisAI,
OpenVINO,
NvTensorRT,
}

View File

@@ -0,0 +1,20 @@
// 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 Microsoft.Extensions.AI;
namespace LanguageModelProvider;
public interface ILanguageModelProvider
{
string Name { get; }
string ProviderDescription { get; }
Task<IEnumerable<ModelDetails>> GetModelsAsync(CancellationToken cancelationToken = default);
IChatClient? GetIChatClient(string modelId);
string GetIChatClientString(string url);
}

View File

@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\Common.Dotnet.CsWinRT.props" />
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.AI" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" />
<PackageReference Include="Microsoft.AI.Foundry.Local" />
<PackageReference Include="OpenAI" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ManagedCommon\ManagedCommon.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,30 @@
// 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.Collections.Generic;
namespace LanguageModelProvider;
public class ModelDetails
{
public string Id { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string Url { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public long Size { get; set; }
public bool IsUserAdded { get; set; }
public string Icon { get; set; } = string.Empty;
public List<HardwareAccelerator> HardwareAccelerators { get; set; } = [];
public string License { get; set; } = string.Empty;
public object? ProviderModelDetails { get; set; }
}

View File

@@ -26,6 +26,16 @@ namespace ManagedCommon
private static readonly string Version = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyFileVersionAttribute>()?.Version ?? "Unknown";
/// <summary>
/// Gets the path to the log directory for the current version of the app.
/// </summary>
public static string CurrentVersionLogDirectoryPath { get; private set; }
/// <summary>
/// Gets the path to the log directory for the app.
/// </summary>
public static string AppLogDirectoryPath { get; private set; }
/// <summary>
/// Initializes the logger and sets the path for logging.
/// </summary>
@@ -42,6 +52,9 @@ namespace ManagedCommon
Directory.CreateDirectory(versionedPath);
}
AppLogDirectoryPath = basePath;
CurrentVersionLogDirectoryPath = versionedPath;
var logFilePath = Path.Combine(versionedPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".log");
Trace.Listeners.Add(new TextWriterTraceListener(logFilePath));

View File

@@ -12,6 +12,7 @@ namespace ManagedCommon
ColorPicker,
CmdPal,
CropAndLock,
CursorWrap,
EnvironmentVariables,
FancyZones,
FileLocksmith,

View File

@@ -0,0 +1,175 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text.Json;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
namespace Microsoft.PowerToys.UITest
{
/// <summary>
/// Helper class for configuring PowerToys settings for UI tests.
/// </summary>
public class SettingsConfigHelper
{
private static readonly JsonSerializerOptions IndentedJsonOptions = new() { WriteIndented = true };
private static readonly SettingsUtils SettingsUtils = new SettingsUtils();
/// <summary>
/// Configures global PowerToys settings to enable only specified modules and disable all others.
/// </summary>
/// <param name="modulesToEnable">Array of module names to enable (e.g., "Peek", "FancyZones"). All other modules will be disabled.</param>
/// <exception cref="ArgumentNullException">Thrown when modulesToEnable is null.</exception>
/// <exception cref="InvalidOperationException">Thrown when settings file operations fail.</exception>
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "This is test code and will not be trimmed")]
[UnconditionalSuppressMessage("AOT", "IL3050", Justification = "This is test code and will not be AOT compiled")]
public static void ConfigureGlobalModuleSettings(params string[] modulesToEnable)
{
ArgumentNullException.ThrowIfNull(modulesToEnable);
try
{
GeneralSettings settings;
try
{
settings = SettingsUtils.GetSettingsOrDefault<GeneralSettings>();
}
catch (Exception ex)
{
Debug.WriteLine($"Failed to load settings, creating defaults: {ex.Message}");
settings = new GeneralSettings();
}
string settingsJson = settings.ToJsonString();
using (JsonDocument doc = JsonDocument.Parse(settingsJson))
{
var options = new JsonSerializerOptions { WriteIndented = true };
var root = doc.RootElement.Clone();
if (root.TryGetProperty("enabled", out var enabledElement))
{
var enabledModules = new Dictionary<string, bool>();
foreach (var property in enabledElement.EnumerateObject())
{
string moduleName = property.Name;
bool shouldEnable = Array.Exists(modulesToEnable, m => string.Equals(m, moduleName, StringComparison.Ordinal));
enabledModules[moduleName] = shouldEnable;
}
var settingsDict = JsonSerializer.Deserialize<Dictionary<string, object>>(settingsJson);
if (settingsDict != null)
{
settingsDict["enabled"] = enabledModules;
settingsJson = JsonSerializer.Serialize(settingsDict, IndentedJsonOptions);
}
}
}
SettingsUtils.SaveSettings(settingsJson);
string enabledList = modulesToEnable.Length > 0 ? string.Join(", ", modulesToEnable) : "none";
Debug.WriteLine($"Successfully updated global settings");
Debug.WriteLine($"Enabled modules: {enabledList}");
}
catch (Exception ex)
{
Debug.WriteLine($"ERROR in ConfigureGlobalModuleSettings: {ex.Message}");
throw new InvalidOperationException($"Failed to configure global module settings: {ex.Message}", ex);
}
}
/// <summary>
/// Updates a module's settings file. If the file doesn't exist, creates it with default content.
/// If the file exists, reads it and applies the provided update function to modify the settings.
/// </summary>
/// <param name="moduleName">The name of the module (e.g., "Peek", "FancyZones").</param>
/// <param name="defaultSettingsContent">The default JSON content to use if the settings file doesn't exist.</param>
/// <param name="updateSettingsAction">
/// A callback function that modifies the settings dictionary. The function receives the deserialized settings
/// and should modify it in-place. The function should accept a Dictionary&lt;string, object&gt; and not return a value.
/// Example: (settings) => { ((Dictionary&lt;string, object&gt;)settings["properties"])["SomeSetting"] = newValue; }
/// </param>
/// <exception cref="ArgumentNullException">Thrown when moduleName or updateSettingsAction is null.</exception>
/// <exception cref="InvalidOperationException">Thrown when settings file operations fail.</exception>
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "This is test code and will not be trimmed")]
[UnconditionalSuppressMessage("AOT", "IL3050", Justification = "This is test code and will not be AOT compiled")]
public static void UpdateModuleSettings(
string moduleName,
string defaultSettingsContent,
Action<Dictionary<string, object>> updateSettingsAction)
{
ArgumentNullException.ThrowIfNull(moduleName);
ArgumentNullException.ThrowIfNull(updateSettingsAction);
try
{
// Build the path to the module settings file
string powerToysSettingsDirectory = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Microsoft",
"PowerToys");
string moduleDirectory = Path.Combine(powerToysSettingsDirectory, moduleName);
string settingsPath = Path.Combine(moduleDirectory, "settings.json");
// Ensure directory exists
Directory.CreateDirectory(moduleDirectory);
// Read existing settings or use default
string existingJson = string.Empty;
if (File.Exists(settingsPath))
{
existingJson = File.ReadAllText(settingsPath);
}
Dictionary<string, object>? settings;
// If file doesn't exist or is empty, create from defaults
if (string.IsNullOrWhiteSpace(existingJson))
{
if (string.IsNullOrWhiteSpace(defaultSettingsContent))
{
throw new ArgumentException("Default settings content must be provided when file doesn't exist.", nameof(defaultSettingsContent));
}
settings = JsonSerializer.Deserialize<Dictionary<string, object>>(defaultSettingsContent)
?? throw new InvalidOperationException($"Failed to deserialize default settings for {moduleName}");
Debug.WriteLine($"Created default settings for {moduleName} at {settingsPath}");
}
else
{
// Parse existing settings
settings = JsonSerializer.Deserialize<Dictionary<string, object>>(existingJson)
?? throw new InvalidOperationException($"Failed to deserialize existing settings for {moduleName}");
Debug.WriteLine($"Loaded existing settings for {moduleName} from {settingsPath}");
}
// Apply the update action to modify settings
updateSettingsAction(settings);
// Serialize and save the updated settings using SettingsUtils
string updatedJson = JsonSerializer.Serialize(settings, IndentedJsonOptions);
SettingsUtils.SaveSettings(updatedJson, moduleName);
Debug.WriteLine($"Successfully updated settings for {moduleName}");
}
catch (Exception ex)
{
Debug.WriteLine($"ERROR in UpdateModuleSettings for {moduleName}: {ex.Message}");
throw new InvalidOperationException($"Failed to update settings for {moduleName}: {ex.Message}", ex);
}
}
}
}

View File

@@ -8,7 +8,7 @@
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
<InvariantGlobalization>true</InvariantGlobalization>
<TargetFramework>net9.0-windows10.0.22621.0</TargetFramework>
<TargetFramework>net9.0-windows10.0.26100.0</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<PublishTrimmed>false</PublishTrimmed>
</PropertyGroup>
@@ -21,4 +21,8 @@
<PackageReference Include="CoenM.ImageSharp.ImageHash" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
</ItemGroup>
</Project>

View File

@@ -63,12 +63,14 @@
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<UseDebugLibraries>true</UseDebugLibraries>
<LinkIncremental>true</LinkIncremental>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LinkIncremental>false</LinkIncremental>

View File

@@ -59,6 +59,7 @@ struct LogSettings
inline const static std::string mouseHighlighterLoggerName = "mouse-highlighter";
inline const static std::string mouseJumpLoggerName = "mouse-jump";
inline const static std::string mousePointerCrosshairsLoggerName = "mouse-pointer-crosshairs";
inline const static std::string cursorWrapLoggerName = "cursor-wrap";
inline const static std::string imageResizerLoggerName = "imageresizer";
inline const static std::string powerRenameLoggerName = "powerrename";
inline const static std::string alwaysOnTopLoggerName = "always-on-top";

View File

@@ -46,6 +46,16 @@
<PropertyGroup>
<TargetName>notifications</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup>
<ClCompile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>

View File

@@ -3,6 +3,7 @@
#include <Windows.h>
#include <optional>
#include <vector>
#include <string>
namespace powertoys_gpo
{
@@ -51,6 +52,7 @@ namespace powertoys_gpo
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_HIGHLIGHTER = L"ConfigureEnabledUtilityMouseHighlighter";
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_JUMP = L"ConfigureEnabledUtilityMouseJump";
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_POINTER_CROSSHAIRS = L"ConfigureEnabledUtilityMousePointerCrosshairs";
const std::wstring POLICY_CONFIGURE_ENABLED_CURSOR_WRAP = L"ConfigureEnabledUtilityCursorWrap";
const std::wstring POLICY_CONFIGURE_ENABLED_POWER_RENAME = L"ConfigureEnabledUtilityPowerRename";
const std::wstring POLICY_CONFIGURE_ENABLED_POWER_LAUNCHER = L"ConfigureEnabledUtilityPowerLauncher";
const std::wstring POLICY_CONFIGURE_ENABLED_QUICK_ACCENT = L"ConfigureEnabledUtilityQuickAccent";
@@ -82,6 +84,13 @@ namespace powertoys_gpo
const std::wstring POLICY_CONFIGURE_RUN_AT_STARTUP = L"ConfigureRunAtStartup";
const std::wstring POLICY_CONFIGURE_ENABLED_POWER_LAUNCHER_ALL_PLUGINS = L"PowerLauncherAllPluginsEnabledState";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_ONLINE_AI_MODELS = L"AllowPowerToysAdvancedPasteOnlineAIModels";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_OPENAI = L"AllowAdvancedPasteOpenAI";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_AZURE_OPENAI = L"AllowAdvancedPasteAzureOpenAI";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_AZURE_AI_INFERENCE = L"AllowAdvancedPasteAzureAIInference";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_MISTRAL = L"AllowAdvancedPasteMistral";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_GOOGLE = L"AllowAdvancedPasteGoogle";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_OLLAMA = L"AllowAdvancedPasteOllama";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_FOUNDRY_LOCAL = L"AllowAdvancedPasteFoundryLocal";
const std::wstring POLICY_MWB_CLIPBOARD_SHARING_ENABLED = L"MwbClipboardSharingEnabled";
const std::wstring POLICY_MWB_FILE_TRANSFER_ENABLED = L"MwbFileTransferEnabled";
const std::wstring POLICY_MWB_USE_ORIGINAL_USER_INTERFACE = L"MwbUseOriginalUserInterface";
@@ -401,6 +410,11 @@ namespace powertoys_gpo
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_MOUSE_POINTER_CROSSHAIRS);
}
inline gpo_rule_configured_t getConfiguredCursorWrapEnabledValue()
{
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_CURSOR_WRAP);
}
inline gpo_rule_configured_t getConfiguredPowerRenameEnabledValue()
{
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_POWER_RENAME);
@@ -575,6 +589,41 @@ namespace powertoys_gpo
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_ONLINE_AI_MODELS);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteOpenAIValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_OPENAI);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteAzureOpenAIValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_AZURE_OPENAI);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteAzureAIInferenceValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_AZURE_AI_INFERENCE);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteMistralValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_MISTRAL);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteGoogleValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_GOOGLE);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteOllamaValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_OLLAMA);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteFoundryLocalValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_FOUNDRY_LOCAL);
}
inline gpo_rule_configured_t getConfiguredMwbClipboardSharingEnabledValue()
{
return getConfiguredValue(POLICY_MWB_CLIPBOARD_SHARING_ENABLED);

View File

@@ -33,9 +33,4 @@
<Target Name="PostBuildAction" AfterTargets="Build" Outputs="$(GeneratedDSCModule)" Condition="'$(Platform)'!='ARM64'">
<Exec Command="&quot;$(OutDir)$(AssemblyName).exe&quot; &quot;..\..\..\x64\$(Configuration)\WinUI3Apps\PowerToys.Settings.UI.Lib.dll&quot; $(GeneratedDSCModule) $(GeneratedDSCManifest)" />
</Target>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent" Condition="'$(Platform)'=='ARM64'">
<Exec Command="&quot;$(MSBuildToolsPath)\msbuild.exe&quot; PowerToys.sln -p:Configuration=&quot;$(Configuration)&quot; -p:Platform=&quot;x64&quot; -verbosity:m -t:DSC\PowerToys_Settings_DSC_Schema_Generator" WorkingDirectory="..\..\..\" />
</Target>
</Project>

View File

@@ -23,7 +23,8 @@ public sealed class SettingsResourceAdvancedPasteModuleTest : SettingsResourceMo
{
s.Properties.ShowCustomPreview = !s.Properties.ShowCustomPreview;
s.Properties.CloseAfterLosingFocus = !s.Properties.CloseAfterLosingFocus;
s.Properties.IsAdvancedAIEnabled = !s.Properties.IsAdvancedAIEnabled;
// s.Properties.IsAdvancedAIEnabled = !s.Properties.IsAdvancedAIEnabled;
s.Properties.AdvancedPasteUIShortcut = new HotkeySettings
{
Key = "mock",

View File

@@ -13,7 +13,7 @@ namespace PowerToys.DSC.Models;
public sealed class DscManifest
{
private const string Schema = "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.vscode.json";
private const string Executable = @"PowerToys.DSC.exe";
private const string Executable = @"..\PowerToys.DSC.exe";
private readonly string _type;
private readonly string _version;

View File

@@ -40,9 +40,11 @@
</EmbeddedResource>
</ItemGroup>
<!-- In debug mode, generate the DSC resource JSON files -->
<Target Name="GenerateDscResourceJsonFiles" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'">
<Message Text="Generating DSC resource JSON files inside ..." Importance="high" />
<Exec Command="dotnet &quot;$(TargetPath)&quot; manifest --resource settings --outputDir &quot;$(TargetDir)\&quot;" />
<!-- Generate the DSC resource JSON files to DSCModules subfolder -->
<!-- Skip generation in CI/CD builds (CIBuild=true) to avoid unnecessary work during pipeline -->
<Target Name="GenerateDscResourceJsonFiles" AfterTargets="Build" Condition="'$(CIBuild)' != 'true'">
<Message Text="Generating DSC resource JSON files to DSCModules subfolder..." Importance="high" />
<MakeDir Directories="$(TargetDir)DSCModules" />
<Exec Command="dotnet &quot;$(TargetPath)&quot; manifest --resource settings --outputDir &quot;$(TargetDir)DSCModules&quot;" />
</Target>
</Project>

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.17" 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.18" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<policyNamespaces>
<target prefix="powertoys" namespace="Microsoft.Policies.PowerToys" />
</policyNamespaces>
<resources minRequiredRevision="1.17"/><!-- Last changed with PowerToys v0.90.0 -->
<resources minRequiredRevision="1.18"/><!-- Last changed with PowerToys v0.96.0 -->
<supportedOn>
<definitions>
<definition name="SUPPORTED_POWERTOYS_0_64_0" displayName="$(string.SUPPORTED_POWERTOYS_0_64_0)"/>
@@ -26,6 +26,7 @@
<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_96_0" displayName="$(string.SUPPORTED_POWERTOYS_0_96_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>
@@ -614,6 +615,86 @@
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteOpenAI" class="Both" displayName="$(string.AllowAdvancedPasteOpenAI)" explainText="$(string.AllowAdvancedPasteOpenAIDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteOpenAI">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteAzureOpenAI" class="Both" displayName="$(string.AllowAdvancedPasteAzureOpenAI)" explainText="$(string.AllowAdvancedPasteAzureOpenAIDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteAzureOpenAI">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteAzureAIInference" class="Both" displayName="$(string.AllowAdvancedPasteAzureAIInference)" explainText="$(string.AllowAdvancedPasteAzureAIInferenceDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteAzureAIInference">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteMistral" class="Both" displayName="$(string.AllowAdvancedPasteMistral)" explainText="$(string.AllowAdvancedPasteMistralDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteMistral">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteGoogle" class="Both" displayName="$(string.AllowAdvancedPasteGoogle)" explainText="$(string.AllowAdvancedPasteGoogleDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteGoogle">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteAnthropic" class="Both" displayName="$(string.AllowAdvancedPasteAnthropic)" explainText="$(string.AllowAdvancedPasteAnthropicDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteAnthropic">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteOllama" class="Both" displayName="$(string.AllowAdvancedPasteOllama)" explainText="$(string.AllowAdvancedPasteOllamaDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteOllama">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteFoundryLocal" class="Both" displayName="$(string.AllowAdvancedPasteFoundryLocal)" explainText="$(string.AllowAdvancedPasteFoundryLocalDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteFoundryLocal">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="MwbClipboardSharingEnabled" class="Both" displayName="$(string.MwbClipboardSharingEnabled)" explainText="$(string.MwbClipboardSharingEnabledDescription)" key="Software\Policies\PowerToys" valueName="MwbClipboardSharingEnabled">
<parentCategory ref="MouseWithoutBorders" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_83_0" />

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.17" 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.18" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<displayName>PowerToys</displayName>
<description>PowerToys</description>
<resources>
@@ -33,6 +33,7 @@
<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_96_0">PowerToys version 0.96.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.
@@ -291,6 +292,54 @@ If you don't configure this policy, the user will be able to control the setting
<string id="ConfigureEnabledUtilityFileExplorerQOIPreview">QOI file preview: Configure enabled state</string>
<string id="ConfigureEnabledUtilityFileExplorerQOIThumbnails">QOI file thumbnail: Configure enabled state</string>
<string id="AllowPowerToysAdvancedPasteOnlineAIModels">Allow using online AI models</string>
<string id="AllowAdvancedPasteOpenAI">Advanced Paste: Allow OpenAI endpoint</string>
<string id="AllowAdvancedPasteOpenAIDescription">This policy controls whether users can use the OpenAI endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use OpenAI as their AI provider.
If you disable this policy, users will not be able to select or use OpenAI endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteAzureOpenAI">Advanced Paste: Allow Azure OpenAI endpoint</string>
<string id="AllowAdvancedPasteAzureOpenAIDescription">This policy controls whether users can use the Azure OpenAI endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Azure OpenAI as their AI provider.
If you disable this policy, users will not be able to select or use Azure OpenAI endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteAzureAIInference">Advanced Paste: Allow Azure AI Inference endpoint</string>
<string id="AllowAdvancedPasteAzureAIInferenceDescription">This policy controls whether users can use the Azure AI Inference endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Azure AI Inference as their AI provider.
If you disable this policy, users will not be able to select or use Azure AI Inference endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteMistral">Advanced Paste: Allow Mistral endpoint</string>
<string id="AllowAdvancedPasteMistralDescription">This policy controls whether users can use the Mistral AI endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Mistral as their AI provider.
If you disable this policy, users will not be able to select or use Mistral endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteGoogle">Advanced Paste: Allow Google endpoint</string>
<string id="AllowAdvancedPasteGoogleDescription">This policy controls whether users can use the Google (Gemini) endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Google as their AI provider.
If you disable this policy, users will not be able to select or use Google endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteAnthropic">Advanced Paste: Allow Anthropic endpoint</string>
<string id="AllowAdvancedPasteAnthropicDescription">This policy controls whether users can use the Anthropic (Claude) endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Anthropic as their AI provider.
If you disable this policy, users will not be able to select or use Anthropic endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteOllama">Advanced Paste: Allow Ollama endpoint</string>
<string id="AllowAdvancedPasteOllamaDescription">This policy controls whether users can use the Ollama local model endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Ollama as their AI provider.
If you disable this policy, users will not be able to select or use Ollama endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteFoundryLocal">Advanced Paste: Allow Foundry Local endpoint</string>
<string id="AllowAdvancedPasteFoundryLocalDescription">This policy controls whether users can use the Foundry Local model endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Foundry Local as their AI provider.
If you disable this policy, users will not be able to select or use Foundry Local endpoint in Advanced Paste settings.</string>
<string id="MwbClipboardSharingEnabled">Clipboard sharing enabled</string>
<string id="MwbFileTransferEnabled">File transfer enabled</string>
<string id="MwbUseOriginalUserInterface">Original user interface is available</string>

View File

@@ -0,0 +1,68 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using AdvancedPaste.Models;
using AdvancedPaste.Settings;
using Microsoft.PowerToys.Settings.UI.Library;
namespace AdvancedPaste.UnitTests.Mocks;
/// <summary>
/// Minimal <see cref="IUserSettings"/> implementation used by integration tests that
/// need to construct the runtime Advanced Paste services.
/// </summary>
internal sealed class IntegrationTestUserSettings : IUserSettings
{
private readonly PasteAIConfiguration _configuration;
private readonly IReadOnlyList<AdvancedPasteCustomAction> _customActions;
private readonly IReadOnlyList<PasteFormats> _additionalActions;
public IntegrationTestUserSettings()
{
var provider = new PasteAIProviderDefinition
{
Id = "integration-openai",
EnableAdvancedAI = true,
ServiceTypeKind = AIServiceType.OpenAI,
ModelName = "gpt-4o",
ModerationEnabled = true,
};
_configuration = new PasteAIConfiguration
{
ActiveProviderId = provider.Id,
Providers = new ObservableCollection<PasteAIProviderDefinition> { provider },
};
_customActions = Array.Empty<AdvancedPasteCustomAction>();
_additionalActions = Array.Empty<PasteFormats>();
}
public bool IsAIEnabled => true;
public bool ShowCustomPreview => false;
public bool CloseAfterLosingFocus => false;
public bool EnableClipboardPreview => true;
public IReadOnlyList<AdvancedPasteCustomAction> CustomActions => _customActions;
public IReadOnlyList<PasteFormats> AdditionalActions => _additionalActions;
public PasteAIConfiguration PasteAIConfiguration => _configuration;
public event EventHandler Changed;
public Task SetActiveAIProviderAsync(string providerId)
{
_configuration.ActiveProviderId = providerId ?? string.Empty;
Changed?.Invoke(this, EventArgs.Empty);
return Task.CompletedTask;
}
}

View File

@@ -13,6 +13,8 @@ using System.Threading.Tasks;
using AdvancedPaste.Helpers;
using AdvancedPaste.Models;
using AdvancedPaste.Services;
using AdvancedPaste.Services.CustomActions;
using AdvancedPaste.Services.OpenAI;
using AdvancedPaste.UnitTests.Mocks;
using ManagedCommon;
@@ -79,7 +81,9 @@ public sealed class AIServiceBatchIntegrationTests
Assert.IsTrue(results.Count <= inputs.Count);
CollectionAssert.AreEqual(results.Select(result => result.ToInput()).ToList(), inputs.Take(results.Count).ToList());
#pragma warning disable IL2026, IL3050 // The tests rely on runtime JSON serialization for ad-hoc data files.
async Task WriteResultsAsync() => await File.WriteAllTextAsync(resultsFile, JsonSerializer.Serialize(results, SerializerOptions));
#pragma warning restore IL2026, IL3050
Logger.LogInfo($"Starting {nameof(TestGenerateBatchResults)}; Count={inputs.Count}, InCache={results.Count}");
@@ -101,8 +105,12 @@ public sealed class AIServiceBatchIntegrationTests
await WriteResultsAsync();
}
private static async Task<List<T>> GetDataListAsync<T>(string filePath) =>
File.Exists(filePath) ? JsonSerializer.Deserialize<List<T>>(await File.ReadAllTextAsync(filePath)) : [];
private static async Task<List<T>> GetDataListAsync<T>(string filePath)
{
#pragma warning disable IL2026, IL3050 // Tests only run locally and can depend on runtime JSON serialization.
return File.Exists(filePath) ? JsonSerializer.Deserialize<List<T>>(await File.ReadAllTextAsync(filePath)) : [];
#pragma warning restore IL2026, IL3050
}
private static async Task<string> GetTextOutputAsync(BatchTestInput input, PasteFormats format)
{
@@ -130,23 +138,35 @@ public sealed class AIServiceBatchIntegrationTests
private static async Task<DataPackage> GetOutputDataPackageAsync(BatchTestInput batchTestInput, PasteFormats format)
{
VaultCredentialsProvider credentialsProvider = new();
PromptModerationService promptModerationService = new(credentialsProvider);
var services = CreateServices();
NoOpProgress progress = new();
CustomTextTransformService customTextTransformService = new(credentialsProvider, promptModerationService);
switch (format)
{
case PasteFormats.CustomTextTransformation:
return DataPackageHelpers.CreateFromText(await customTextTransformService.TransformTextAsync(batchTestInput.Prompt, batchTestInput.Clipboard, CancellationToken.None, progress));
var transformResult = await services.CustomActionTransformService.TransformTextAsync(batchTestInput.Prompt, batchTestInput.Clipboard, CancellationToken.None, progress);
return DataPackageHelpers.CreateFromText(transformResult.Content ?? string.Empty);
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, CancellationToken.None, progress);
return await services.KernelService.TransformClipboardAsync(batchTestInput.Prompt, clipboardData, isSavedQuery: false, CancellationToken.None, progress);
default:
throw new InvalidOperationException($"Unexpected format {format}");
}
}
private static IntegrationTestServices CreateServices()
{
IntegrationTestUserSettings userSettings = new();
EnhancedVaultCredentialsProvider credentialsProvider = new(userSettings);
PromptModerationService promptModerationService = new(credentialsProvider);
PasteAIProviderFactory providerFactory = new();
ICustomActionTransformService customActionTransformService = new CustomActionTransformService(promptModerationService, providerFactory, credentialsProvider, userSettings);
IKernelService kernelService = new AdvancedAIKernelService(credentialsProvider, new NoOpKernelQueryCacheService(), promptModerationService, userSettings, customActionTransformService);
return new IntegrationTestServices(customActionTransformService, kernelService);
}
private readonly record struct IntegrationTestServices(ICustomActionTransformService CustomActionTransformService, IKernelService KernelService);
}

View File

@@ -11,6 +11,8 @@ using System.Threading.Tasks;
using AdvancedPaste.Helpers;
using AdvancedPaste.Models;
using AdvancedPaste.Services;
using AdvancedPaste.Services.CustomActions;
using AdvancedPaste.Services.OpenAI;
using AdvancedPaste.Telemetry;
using AdvancedPaste.UnitTests.Mocks;
@@ -27,16 +29,19 @@ namespace AdvancedPaste.UnitTests.ServicesTests;
public sealed class KernelServiceIntegrationTests : IDisposable
{
private const string StandardImageFile = "image_with_text_example.png";
private KernelService _kernelService;
private IKernelService _kernelService;
private AdvancedPasteEventListener _eventListener;
[TestInitialize]
public void TestInitialize()
{
VaultCredentialsProvider credentialsProvider = new();
IntegrationTestUserSettings userSettings = new();
EnhancedVaultCredentialsProvider credentialsProvider = new(userSettings);
PromptModerationService promptModerationService = new(credentialsProvider);
PasteAIProviderFactory providerFactory = new();
CustomActionTransformService customActionTransformService = new(promptModerationService, providerFactory, credentialsProvider, userSettings);
_kernelService = new KernelService(new NoOpKernelQueryCacheService(), credentialsProvider, promptModerationService, new CustomTextTransformService(credentialsProvider, promptModerationService));
_kernelService = new AdvancedAIKernelService(credentialsProvider, new NoOpKernelQueryCacheService(), promptModerationService, userSettings, customActionTransformService);
_eventListener = new();
}

View File

@@ -33,11 +33,14 @@
</PropertyGroup>
<ItemGroup>
<None Remove="AdvancedPasteXAML\Controls\ClipboardHistoryItemPreviewControl.xaml" />
<None Remove="AdvancedPasteXAML\Controls\PromptBox.xaml" />
<None Remove="AdvancedPasteXAML\Styles\Button.xaml" />
<None Remove="Assets\AdvancedPaste\AIIcon.png" />
<None Remove="Assets\AdvancedPaste\Gradient.png" />
<None Remove="AdvancedPasteXAML\Controls\AnimatedContentControl\AnimatedBorderBrush.xaml" />
<None Remove="AdvancedPasteXAML\Views\MainPage.xaml" />
<None Remove="Assets\AdvancedPaste\SemanticKernel.svg" />
</ItemGroup>
<ItemGroup>
@@ -49,7 +52,6 @@
<ItemGroup>
<PackageReference Include="OpenAI" />
<PackageReference Include="Azure.AI.OpenAI" />
<PackageReference Include="CommunityToolkit.Mvvm" />
<PackageReference Include="CommunityToolkit.WinUI.Animations" />
<PackageReference Include="CommunityToolkit.WinUI.Converters" />
@@ -57,10 +59,15 @@
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" />
<!-- 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. -->
<PackageReference Include="MessagePack" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.AzureAIInference" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Google" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.MistralAI" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Ollama" />
<PackageReference Include="Microsoft.Extensions.Hosting" />
<PackageReference Include="Microsoft.SemanticKernel" />
<PackageReference Include="Microsoft.WindowsAppSDK" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
<PackageReference Include="System.ClientModel" />
<PackageReference Include="Microsoft.Windows.Compatibility" />
<PackageReference Include="Microsoft.Windows.CsWin32" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" />
@@ -102,6 +109,7 @@
<!-- HACK: Common.UI is referenced, even if it is not used, to force dll versions to be the same as in other projects that use it. It's still unclear why this is the case, but this is need for flattening the install directory. -->
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
<ProjectReference Include="..\..\..\common\LanguageModelProvider\LanguageModelProvider.csproj" />
<ProjectReference Include="..\..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
<ProjectReference Include="..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
</ItemGroup>
@@ -114,9 +122,38 @@
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
</PropertyGroup>
<ItemGroup>
<Page Update="AdvancedPasteXAML\Controls\ClipboardHistoryItemPreviewControl.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="AdvancedPasteXAML\Controls\PromptBox.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="AdvancedPasteXAML\Styles\Button.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<!-- Share AI Model Provider Icons from Settings.UI to avoid duplication -->
<!-- These icons are included from Settings.UI project -->
<Content Include="..\..\..\settings-ui\Settings.UI\Assets\Settings\Icons\Models\*.svg">
<Link>Assets\Settings\Icons\Models\%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<!-- AdvancedPaste specific assets -->
<Content Include="Assets\AdvancedPaste\*.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Assets\AdvancedPaste\*.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<!-- Keep SemanticKernel.svg as it's specific to AdvancedPaste -->
<Content Include="Assets\AdvancedPaste\SemanticKernel.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

View File

@@ -9,6 +9,7 @@
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<ResourceDictionary Source="ms-appx:///AdvancedPasteXAML/Controls/AnimatedContentControl/AnimatedContentControl.xaml" />
<ResourceDictionary Source="ms-appx:///AdvancedPasteXAML/Styles/Button.xaml" />
<!-- Other merged dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<!-- Other app resources here -->

View File

@@ -10,10 +10,10 @@ using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using AdvancedPaste.Helpers;
using AdvancedPaste.Models;
using AdvancedPaste.Services;
using AdvancedPaste.Services.CustomActions;
using AdvancedPaste.Settings;
using AdvancedPaste.ViewModels;
using ManagedCommon;
@@ -77,11 +77,12 @@ namespace AdvancedPaste
{
services.AddSingleton<IFileSystem, FileSystem>();
services.AddSingleton<IUserSettings, UserSettings>();
services.AddSingleton<IAICredentialsProvider, Services.OpenAI.VaultCredentialsProvider>();
services.AddSingleton<IAICredentialsProvider, EnhancedVaultCredentialsProvider>();
services.AddSingleton<IPromptModerationService, Services.OpenAI.PromptModerationService>();
services.AddSingleton<ICustomTextTransformService, Services.OpenAI.CustomTextTransformService>();
services.AddSingleton<IKernelQueryCacheService, CustomActionKernelQueryCacheService>();
services.AddSingleton<IKernelService, Services.OpenAI.KernelService>();
services.AddSingleton<IPasteAIProviderFactory, PasteAIProviderFactory>();
services.AddSingleton<ICustomActionTransformService, CustomActionTransformService>();
services.AddSingleton<IKernelService, AdvancedAIKernelService>();
services.AddSingleton<IPasteFormatExecutor, PasteFormatExecutor>();
services.AddSingleton<OptionsViewModel>();
}).Build();

View File

@@ -11,7 +11,7 @@
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="CornerRadius" Value="16" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:AnimatedContentControl">

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8" ?>
<UserControl
x:Class="AdvancedPaste.Controls.ClipboardHistoryItemPreviewControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:AdvancedPaste.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:AdvancedPaste.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters"
mc:Ignorable="d">
<UserControl.Resources>
<converters:DateTimeToFriendlyStringConverter x:Key="DateTimeToFriendlyStringConverter" />
<tkconverters:BoolToVisibilityConverter x:Name="BoolToVisibilityConverter" />
</UserControl.Resources>
<Grid ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Background="{ThemeResource SubtleFillColorSecondaryBrush}" CornerRadius="16,0,0,16">
<Grid>
<!-- Image preview -->
<Image
Source="{x:Bind ClipboardItem.Image, Mode=OneWay}"
Stretch="UniformToFill"
Visibility="{x:Bind HasImage, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
<!-- Text preview -->
<TextBlock
Margin="8,0,0,0"
VerticalAlignment="Center"
FontSize="10"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="{x:Bind ClipboardItem.Content, Mode=OneWay}"
TextWrapping="Wrap"
Visibility="{x:Bind HasText, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
<!-- Icon glyph fallback -->
<FontIcon
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="48"
Glyph="{x:Bind IconGlyph, Mode=OneWay}"
Visibility="{x:Bind HasGlyph, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
</Grid>
</Border>
<StackPanel
Grid.Column="1"
VerticalAlignment="Center"
Spacing="2">
<TextBlock
Style="{StaticResource BodyTextBlockStyle}"
Text="{x:Bind Header, Mode=OneWay}"
TextWrapping="NoWrap" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind Timestamp, Converter={StaticResource DateTimeToFriendlyStringConverter}, Mode=OneWay}" />
</StackPanel>
</Grid>
</UserControl>

View File

@@ -0,0 +1,127 @@
// 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 AdvancedPaste.Helpers;
using AdvancedPaste.Models;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
namespace AdvancedPaste.Controls
{
public sealed partial class ClipboardHistoryItemPreviewControl : UserControl
{
public static readonly DependencyProperty ClipboardItemProperty = DependencyProperty.Register(
nameof(ClipboardItem),
typeof(ClipboardItem),
typeof(ClipboardHistoryItemPreviewControl),
new PropertyMetadata(defaultValue: null, OnClipboardItemChanged));
public ClipboardItem ClipboardItem
{
get => (ClipboardItem)GetValue(ClipboardItemProperty);
set => SetValue(ClipboardItemProperty, value);
}
// Computed properties for display
public string Header => ClipboardItem != null ? GetHeaderFromFormat(ClipboardItem.Format) : string.Empty;
public string IconGlyph => ClipboardItem != null ? GetGlyphFromFormat(ClipboardItem.Format) : string.Empty;
public string ContentText => ClipboardItem?.Content ?? string.Empty;
public ImageSource ContentImage => ClipboardItem?.Image;
public DateTimeOffset? Timestamp => ClipboardItem?.Timestamp ?? ClipboardItem?.Item?.Timestamp;
public bool HasImage => ContentImage is not null;
public bool HasText => !string.IsNullOrEmpty(ContentText) && !HasImage;
public bool HasGlyph => !HasImage && !HasText && !string.IsNullOrEmpty(IconGlyph);
public ClipboardHistoryItemPreviewControl()
{
InitializeComponent();
}
private static void OnClipboardItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ClipboardHistoryItemPreviewControl control)
{
// Notify bindings that all computed properties may have changed
control.Bindings.Update();
}
}
private static string GetHeaderFromFormat(ClipboardFormat format)
{
// Check flags in priority order (most specific first)
if (format.HasFlag(ClipboardFormat.Image))
{
return GetStringOrFallback("ClipboardPreviewCategoryImage", "Image");
}
if (format.HasFlag(ClipboardFormat.Video))
{
return GetStringOrFallback("ClipboardPreviewCategoryVideo", "Video");
}
if (format.HasFlag(ClipboardFormat.Audio))
{
return GetStringOrFallback("ClipboardPreviewCategoryAudio", "Audio");
}
if (format.HasFlag(ClipboardFormat.File))
{
return GetStringOrFallback("ClipboardPreviewCategoryFile", "File");
}
if (format.HasFlag(ClipboardFormat.Text) || format.HasFlag(ClipboardFormat.Html))
{
return GetStringOrFallback("ClipboardPreviewCategoryText", "Text");
}
return GetStringOrFallback("ClipboardPreviewCategoryUnknown", "Clipboard");
}
private static string GetGlyphFromFormat(ClipboardFormat format)
{
// Check flags in priority order (most specific first)
if (format.HasFlag(ClipboardFormat.Image))
{
return "\uEB9F"; // Image icon
}
if (format.HasFlag(ClipboardFormat.Video))
{
return "\uE714"; // Video icon
}
if (format.HasFlag(ClipboardFormat.Audio))
{
return "\uE189"; // Audio icon
}
if (format.HasFlag(ClipboardFormat.File))
{
return "\uE8A5"; // File icon
}
if (format.HasFlag(ClipboardFormat.Text) || format.HasFlag(ClipboardFormat.Html))
{
return "\uE8D2"; // Text icon
}
return "\uE77B"; // Generic clipboard icon
}
private static string GetStringOrFallback(string resourceKey, string fallback)
{
var value = ResourceLoaderInstance.ResourceLoader.GetString(resourceKey);
return string.IsNullOrEmpty(value) ? fallback : value;
}
}
}

View File

@@ -7,34 +7,21 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:AdvancedPaste.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:settings="using:Microsoft.PowerToys.Settings.UI.Library"
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters"
xmlns:ui="using:CommunityToolkit.WinUI"
x:Name="PromptBoxControl"
mc:Ignorable="d">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<Color x:Key="AccentGradientColor">#65C8F2</Color>
<LinearGradientBrush x:Key="AccentGradientBrush" StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0.0" Color="#98EFFE" />
<GradientStop Offset="0.25" Color="#48B1E9" />
<GradientStop Offset="1.0" Color="{StaticResource AccentGradientColor}" />
</LinearGradientBrush>
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<Color x:Key="AccentGradientColor">#005FB8</Color>
<LinearGradientBrush x:Key="AccentGradientBrush" StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0.0" Color="#4992C7" />
<GradientStop Offset="0.25" Color="#1353A0" />
<GradientStop Offset="1.0" Color="{StaticResource AccentGradientColor}" />
</LinearGradientBrush>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<Color x:Key="AccentGradientColor">#48B1E9</Color>
<SolidColorBrush x:Key="AccentGradientBrush" Color="{StaticResource AccentGradientColor}" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<LinearGradientBrush x:Name="IntelligentUnderlineGradient" StartPoint="0,0.5" EndPoint="1,0.5">
<GradientStop Offset="0.0" Color="#FF0078D4" />
<GradientStop Offset="0.42" Color="#FF464FEB" />
<GradientStop Offset="0.87" Color="#FFD660FF" />
<GradientStop Offset="1.0" Color="#FFFEA874" />
</LinearGradientBrush>
<x:Double x:Key="ModelSelectorButtonWidth">44</x:Double>
<Style x:Key="CustomTextBoxStyle" TargetType="TextBox">
<Setter Property="Foreground" Value="{ThemeResource TextControlForeground}" />
<Setter Property="Background" Value="{ThemeResource TextControlBackground}" />
@@ -155,6 +142,7 @@
Foreground="{ThemeResource TextControlHeaderForeground}"
TextWrapping="Wrap"
Visibility="Collapsed" />
<Border
x:Name="BorderElement"
Grid.Row="1"
@@ -168,48 +156,32 @@
BorderThickness="{TemplateBinding BorderThickness}"
Control.IsTemplateFocusTarget="True"
CornerRadius="{TemplateBinding CornerRadius}" />
<Viewbox
<Rectangle
x:Name="FocusHighlighter"
Grid.Row="1"
Width="16"
Height="16"
Margin="8,0,0,0">
<StackPanel
Margin="0"
Padding="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<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>
Grid.RowSpan="1"
Grid.ColumnSpan="4"
Height="2"
Margin="12,0,12,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom"
Fill="{StaticResource IntelligentUnderlineGradient}"
RadiusX="1"
RadiusY="1"
Visibility="Collapsed" />
<Grid Grid.Row="1" Width="{StaticResource ModelSelectorButtonWidth}">
<ProgressRing
Width="20"
Height="20"
HorizontalAlignment="Center"
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}}" />
</Grid>
<ScrollViewer
x:Name="ContentElement"
Grid.Row="1"
@@ -279,12 +251,6 @@
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentElement" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="AIGlyph" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="AIGlyphImage" Storyboard.TargetProperty="Opacity">
<DiscreteObjectKeyFrame KeyTime="0" Value="0.4" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderTextContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{Binding PlaceholderForeground, RelativeSource={RelativeSource TemplatedParent}, TargetNullValue={ThemeResource TextControlPlaceholderForegroundDisabled}}" />
</ObjectAnimationUsingKeyFrames>
@@ -314,7 +280,10 @@
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBackgroundFocused}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush">
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="FocusHighlighter" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
</ObjectAnimationUsingKeyFrames>
<!--<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<LinearGradientBrush MappingMode="Absolute" StartPoint="0,0" EndPoint="0,2">
@@ -331,7 +300,7 @@
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderThickness">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBorderThemeThicknessFocused}" />
</ObjectAnimationUsingKeyFrames>
</ObjectAnimationUsingKeyFrames>-->
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentElement" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlForegroundFocused}" />
</ObjectAnimationUsingKeyFrames>
@@ -364,6 +333,8 @@
FalseValue="Visible"
TrueValue="Collapsed" />
<converters:CountToVisibilityConverter x:Key="CountToVisibilityConverter" />
<converters:CountToInvertedVisibilityConverter x:Key="CountToInvertedVisibilityConverter" />
<converters:ServiceTypeToIconConverter x:Key="ServiceTypeToIconConverter" />
</ResourceDictionary>
</UserControl.Resources>
<Grid x:Name="PromptBoxGrid" Loaded="Grid_Loaded">
@@ -374,18 +345,19 @@
<local:AnimatedContentControl
x:Name="Loader"
MinHeight="48"
CornerRadius="8">
CornerRadius="16">
<Grid>
<TextBox
x:Name="InputTxtBox"
HorizontalAlignment="Stretch"
x:FieldModifier="public"
CornerRadius="16"
DataContext="{x:Bind ViewModel}"
IsEnabled="{x:Bind ViewModel.ClipboardHasData, Mode=OneWay}"
KeyDown="InputTxtBox_KeyDown"
PlaceholderText="{x:Bind ViewModel.InputTxtBoxPlaceholderText, Mode=OneWay}"
Style="{StaticResource CustomTextBoxStyle}"
TabIndex="0"
TabIndex="1"
Text="{x:Bind ViewModel.Query, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ToolTipService.ToolTip>
<TextBlock x:Uid="InputTxtBoxTooltip" />
@@ -545,6 +517,139 @@
</Flyout>
</FlyoutBase.AttachedFlyout>
</TextBox>
<DropDownButton
x:Name="AIProviderButton"
x:Uid="AIProviderButton"
MinWidth="{StaticResource ModelSelectorButtonWidth}"
Margin="1,1,0,2"
Padding="0,0,4,0"
VerticalAlignment="Stretch"
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
BorderThickness="0,0,1,0"
CornerRadius="16,0,0,16"
Style="{StaticResource SubtleDropDownButtonStyle}"
TabIndex="0"
Visibility="{x:Bind ViewModel.IsBusy, Mode=OneWay, Converter={StaticResource BoolToInvertedVisibilityConverter}}">
<ToolTipService.ToolTip>
<TextBlock Text="{x:Bind ViewModel.ActiveAIProviderTooltip, Mode=OneWay}" TextWrapping="WrapWholeWords" />
</ToolTipService.ToolTip>
<DropDownButton.Content>
<Image
x:Name="AIProviderIcon"
Width="16"
Height="16"
AutomationProperties.AccessibilityView="Raw"
Source="{x:Bind ViewModel.ActiveAIProvider?.ServiceType, Mode=OneWay, Converter={StaticResource ServiceTypeToIconConverter}}" />
</DropDownButton.Content>
<DropDownButton.Flyout>
<Flyout
Opened="AIProviderFlyout_Opened"
Placement="Bottom"
ShouldConstrainToRootBounds="False">
<Grid
Width="386"
Margin="-4"
RowSpacing="12">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
x:Uid="AIProvidersFlyoutHeader"
Grid.Row="0"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
<ListView
x:Name="AIProviderListView"
Grid.Row="1"
MaxHeight="320"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="{StaticResource OverlayCornerRadius}"
ItemsSource="{x:Bind ViewModel.AIProviders, Mode=OneWay}"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollMode="Auto"
SelectedItem="{x:Bind ViewModel.ActiveAIProvider, Mode=OneWay}"
SelectionChanged="AIProviderListView_SelectionChanged"
SelectionMode="Single"
Visibility="{x:Bind ViewModel.AIProviders.Count, Mode=OneWay, Converter={StaticResource CountToVisibilityConverter}}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" Spacing="2" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate x:DataType="settings:PasteAIProviderDefinition">
<Grid Padding="0,8,0,8" ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image
Width="20"
Height="20"
AutomationProperties.AccessibilityView="Raw"
Source="{x:Bind ServiceType, Mode=OneWay, Converter={StaticResource ServiceTypeToIconConverter}}" />
<StackPanel
Grid.Column="1"
VerticalAlignment="Center"
Spacing="2">
<TextBlock Text="{x:Bind DisplayName, Mode=OneWay}" TextTrimming="CharacterEllipsis" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind ServiceType, Mode=OneWay}" />
</StackPanel>
<Border
Grid.Column="2"
Padding="2,0,2,0"
VerticalAlignment="Center"
BorderBrush="{ThemeResource ControlStrokeColorSecondary}"
BorderThickness="1"
CornerRadius="{StaticResource ControlCornerRadius}"
Visibility="{x:Bind IsLocalModel, Mode=OneWay}">
<TextBlock
x:Uid="LocalModelBadge"
AutomationProperties.AccessibilityView="Raw"
FontSize="10"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
</Border>
<!--<Border
Grid.Column="2"
Padding="2,0,2,0"
VerticalAlignment="Center"
BorderBrush="{ThemeResource TertiaryButtonBorderBrush}"
BorderThickness="1"
CornerRadius="{StaticResource ControlCornerRadius}"
Visibility="{x:Bind EnableAdvanceAI}">
<TextBlock
AutomationProperties.AccessibilityView="Raw"
FontSize="10"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="ADVANCED" />
</Border>-->
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<TextBlock
x:Uid="AIProvidersEmptyText"
Grid.Row="1"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
TextWrapping="WrapWholeWords"
Visibility="{x:Bind ViewModel.AIProviders.Count, Mode=OneWay, Converter={StaticResource CountToInvertedVisibilityConverter}}" />
<HyperlinkButton
x:Uid="AIProvidersManageButtonContent"
Grid.Row="2"
HorizontalAlignment="Right"
Command="{x:Bind ViewModel.OpenSettingsCommand, Mode=OneWay}" />
</Grid>
</Flyout>
</DropDownButton.Flyout>
</DropDownButton>
<Grid
Width="32"
Height="32"
@@ -562,10 +667,9 @@
Command="{x:Bind GenerateCustomAICommand}"
Content="{ui:FontIcon Glyph=&#xE724;,
FontSize=16}"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
IsEnabled="{x:Bind ViewModel.IsCustomAIAvailable, Mode=OneWay}"
Style="{StaticResource SubtleButtonStyle}"
TabIndex="1"
TabIndex="2"
Visibility="{x:Bind ViewModel.Query.Length, Mode=OneWay, Converter={StaticResource CountToVisibilityConverter}}">
<ToolTipService.ToolTip>
<TextBlock x:Uid="SendBtnToolTip" TextWrapping="WrapWholeWords" />
@@ -640,8 +744,8 @@
x:Name="LoadingText"
x:Uid="LoadingText"
Grid.Row="1"
FontWeight="SemiBold"
Foreground="{ThemeResource AccentGradientBrush}"
Margin="4,4,0,0"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Visibility="Collapsed">
<animations:Implicit.ShowAnimations>

View File

@@ -10,9 +10,11 @@ using AdvancedPaste.Models;
using AdvancedPaste.ViewModels;
using CommunityToolkit.Mvvm.Input;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Telemetry;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
namespace AdvancedPaste.Controls
{
@@ -20,6 +22,8 @@ namespace AdvancedPaste.Controls
{
public OptionsViewModel ViewModel { get; private set; }
private bool _syncingProviderSelection;
public static readonly DependencyProperty PlaceholderTextProperty = DependencyProperty.Register(
nameof(PlaceholderText),
typeof(string),
@@ -44,6 +48,18 @@ namespace AdvancedPaste.Controls
set => SetValue(FooterProperty, value);
}
public static readonly DependencyProperty ModelSelectorProperty = DependencyProperty.Register(
nameof(ModelSelector),
typeof(object),
typeof(PromptBox),
new PropertyMetadata(defaultValue: null));
public object ModelSelector
{
get => GetValue(ModelSelectorProperty);
set => SetValue(ModelSelectorProperty, value);
}
public PromptBox()
{
InitializeComponent();
@@ -60,6 +76,11 @@ namespace AdvancedPaste.Controls
var state = ViewModel.IsBusy ? "LoadingState" : ViewModel.PasteActionError.HasText ? "ErrorState" : "DefaultState";
VisualStateManager.GoToState(this, state, true);
}
if (e.PropertyName is nameof(ViewModel.ActiveAIProvider) or nameof(ViewModel.AIProviders))
{
SyncProviderSelection();
}
}
private void ViewModel_PreviewRequested(object sender, EventArgs e)
@@ -73,6 +94,7 @@ namespace AdvancedPaste.Controls
private void Grid_Loaded(object sender, RoutedEventArgs e)
{
InputTxtBox.Focus(FocusState.Programmatic);
SyncProviderSelection();
}
[RelayCommand]
@@ -111,5 +133,57 @@ namespace AdvancedPaste.Controls
{
Loader.IsLoading = loading;
}
private void SyncProviderSelection()
{
if (AIProviderListView is null)
{
return;
}
try
{
_syncingProviderSelection = true;
AIProviderListView.SelectedItem = ViewModel.ActiveAIProvider;
}
finally
{
_syncingProviderSelection = false;
}
}
private void AIProviderFlyout_Opened(object sender, object e)
{
SyncProviderSelection();
}
private async void AIProviderListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (_syncingProviderSelection)
{
return;
}
var flyout = FlyoutBase.GetAttachedFlyout(AIProviderButton);
if (AIProviderListView.SelectedItem is not PasteAIProviderDefinition provider)
{
return;
}
if (string.Equals(ViewModel.ActiveAIProvider?.Id, provider.Id, StringComparison.OrdinalIgnoreCase))
{
flyout?.Hide();
return;
}
if (ViewModel.SetActiveProviderCommand.CanExecute(provider))
{
await ViewModel.SetActiveProviderCommand.ExecuteAsync(provider);
SyncProviderSelection();
}
flyout?.Hide();
}
}
}

View File

@@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Data;
namespace AdvancedPaste.Converters;
public sealed partial class CountToInvertedVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
bool hasItems = ((value is int intValue) && intValue > 0) || (value is IEnumerable enumerable && enumerable.GetEnumerator().MoveNext());
return targetType == typeof(Visibility)
? (hasItems ? Visibility.Collapsed : Visibility.Visible)
: !hasItems;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
=> throw new NotSupportedException();
}

View File

@@ -0,0 +1,103 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.UI.Xaml.Data;
using Microsoft.Windows.ApplicationModel.Resources;
namespace AdvancedPaste.Converters
{
public sealed partial class DateTimeToFriendlyStringConverter : IValueConverter
{
private static readonly ResourceLoader _resources = new ResourceLoader();
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is not DateTimeOffset dto)
{
return string.Empty;
}
// Use local times to calculate relative values and formatting
var now = DateTimeOffset.Now;
var localValue = dto.ToLocalTime();
var culture = !string.IsNullOrEmpty(language)
? new CultureInfo(language)
: CultureInfo.CurrentCulture;
var delta = now - localValue;
// Future dates: fall back to date/time formatting
if (delta < TimeSpan.Zero)
{
return FormatDateAndTime(localValue, culture);
}
// < 1 minute
if (delta.TotalSeconds < 60)
{
return _resources.GetString("Relative_JustNow"); // "Just now"
}
// < 60 minutes
if (delta.TotalMinutes < 60)
{
var mins = (int)Math.Round(delta.TotalMinutes);
if (mins <= 1)
{
return _resources.GetString("Relative_MinuteAgo"); // "1 minute ago"
}
var fmt = _resources.GetString("Relative_MinutesAgo_Format"); // "{0} minutes ago"
return string.Format(culture, fmt, mins);
}
// Same calendar day → "Today, {time}"
var today = now.Date;
if (localValue.Date == today)
{
var time = localValue.ToString("t", culture); // localized short time
var fmt = _resources.GetString("Relative_Today_TimeFormat"); // "Today, {0}"
return string.Format(culture, fmt, time);
}
// Yesterday → "Yesterday, {time}"
if (localValue.Date == today.AddDays(-1))
{
var time = localValue.ToString("t", culture);
var fmt = _resources.GetString("Relative_Yesterday_TimeFormat"); // "Yesterday, {0}"
return string.Format(culture, fmt, time);
}
// Within last 7 days → "{Weekday}, {time}"
if (delta.TotalDays < 7)
{
var weekday = localValue.ToString("dddd", culture); // localized weekday
var time = localValue.ToString("t", culture);
var fmt = _resources.GetString("Relative_Weekday_TimeFormat"); // "{0}, {1}"
return string.Format(culture, fmt, weekday, time);
}
// Older → localized date + time
return FormatDateAndTime(localValue, culture);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
=> throw new NotSupportedException();
private static string FormatDateAndTime(DateTimeOffset localValue, CultureInfo culture)
{
// Use localized short date + short time
var date = localValue.ToString("d", culture);
var time = localValue.ToString("t", culture);
var fmt = _resources.GetString("Relative_Date_TimeFormat"); // "{0}, {1}"
return string.Format(culture, fmt, date, time);
}
}
}

View File

@@ -0,0 +1,42 @@
// 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 ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Media.Imaging;
namespace AdvancedPaste.Converters;
public sealed partial class ServiceTypeToIconConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
string iconPath = value switch
{
string service when !string.IsNullOrWhiteSpace(service) => AIServiceTypeRegistry.GetIconPath(service),
AIServiceType serviceType => AIServiceTypeRegistry.GetIconPath(serviceType),
_ => null,
};
if (string.IsNullOrEmpty(iconPath))
{
iconPath = AIServiceTypeRegistry.GetIconPath(AIServiceType.Unknown);
}
try
{
return new SvgImageSource(new Uri(iconPath));
}
catch (Exception ex)
{
Logger.LogDebug("Failed to create SvgImageSource for AI service icon", ex.Message);
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
=> throw new NotSupportedException();
}

View File

@@ -7,9 +7,9 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:pages="using:AdvancedPaste.Pages"
xmlns:winuiex="using:WinUIEx"
Width="420"
Width="486"
Height="188"
MinWidth="420"
MinWidth="486"
MinHeight="188"
Closed="WindowEx_Closed"
IsAlwaysOnTop="True"

View File

@@ -35,7 +35,7 @@
AutomationProperties.HelpText="{x:Bind Name, Mode=OneWay}"
AutomationProperties.Name="{x:Bind AccessibleName, Mode=OneWay}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="26" />
<ColumnDefinition Width="48" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
@@ -52,6 +52,7 @@
Grid.Column="1"
VerticalAlignment="Center"
x:Phase="1"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind Name, Mode=OneWay}" />
<TextBlock
Grid.Column="2"
@@ -74,7 +75,7 @@
AutomationProperties.AccessibilityView="Raw"
Opacity="0.5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="26" />
<ColumnDefinition Width="48" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
@@ -87,6 +88,7 @@
Grid.Column="1"
VerticalAlignment="Center"
x:Phase="1"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind Name, Mode=OneWay}" />
</Grid>
</DataTemplate>
@@ -142,221 +144,204 @@
</Page.KeyboardAccelerators>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<controls:PromptBox
x:Name="CustomFormatTextBox"
x:Uid="CustomFormatTextBox"
Margin="8,4,8,0"
x:FieldModifier="public"
TabIndex="0">
<controls:PromptBox.Footer>
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="0,0,2,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{StaticResource CaptionTextBlockStyle}">
<Run x:Uid="AIMistakeNote" Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
</TextBlock>
<TextBlock
Margin="4,0,2,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{StaticResource CaptionTextBlockStyle}">
<Hyperlink
x:Name="TermsHyperlink"
NavigateUri="https://openai.com/policies/terms-of-use"
TabIndex="3">
<Run x:Uid="TermsLink" />
</Hyperlink>
<ToolTipService.ToolTip>
<TextBlock Text="https://openai.com/policies/terms-of-use" />
</ToolTipService.ToolTip>
</TextBlock>
<TextBlock
Margin="0,0,2,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{StaticResource CaptionTextBlockStyle}"
ToolTipService.ToolTip="">
<Run x:Uid="AIFooterSeparator" Foreground="{ThemeResource TextFillColorSecondaryBrush}">|</Run>
</TextBlock>
<TextBlock
Margin="0,0,2,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{StaticResource CaptionTextBlockStyle}">
<Hyperlink NavigateUri="https://openai.com/policies/privacy-policy" TabIndex="3">
<Run x:Uid="PrivacyLink" />
</Hyperlink>
<ToolTipService.ToolTip>
<TextBlock Text="https://openai.com/policies/privacy-policy" />
</ToolTipService.ToolTip>
</TextBlock>
</StackPanel>
</controls:PromptBox.Footer>
</controls:PromptBox>
<Grid
Grid.Row="2"
Background="{ThemeResource LayerOnAcrylicFillColorDefaultBrush}"
Margin="8,0,8,16"
Padding="4"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="0,1,0,0"
RowSpacing="4">
<Grid.RowDefinitions>
<RowDefinition Height="{x:Bind ViewModel.StandardPasteFormats.Count, Mode=OneWay, Converter={StaticResource standardPasteFormatsToHeightConverter}}" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" MinHeight="{x:Bind ViewModel.CustomActionPasteFormats.Count, Mode=OneWay, Converter={StaticResource customActionsToMinHeightConverter}}" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListView
x:Name="PasteOptionsListView"
Grid.Row="0"
VerticalAlignment="Bottom"
IsItemClickEnabled="True"
ItemClick="PasteFormat_ItemClick"
ItemContainerTransitions="{x:Null}"
ItemTemplateSelector="{StaticResource PasteFormatTemplateSelector}"
ItemsSource="{x:Bind ViewModel.StandardPasteFormats, Mode=OneWay}"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollMode="Auto"
SelectionMode="None"
TabIndex="1" />
<Rectangle
Grid.Row="1"
Height="1"
HorizontalAlignment="Stretch"
Fill="{ThemeResource DividerStrokeColorDefaultBrush}"
Visibility="{x:Bind ViewModel.CustomActionPasteFormats.Count, Mode=OneWay, Converter={StaticResource countToVisibilityConverter}}" />
<ListView
x:Name="CustomActionsListView"
Grid.Row="2"
VerticalAlignment="Top"
IsItemClickEnabled="True"
ItemClick="PasteFormat_ItemClick"
ItemContainerTransitions="{x:Null}"
ItemTemplateSelector="{StaticResource PasteFormatTemplateSelector}"
ItemsSource="{x:Bind ViewModel.CustomActionPasteFormats, Mode=OneWay}"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollMode="Auto"
SelectionMode="None"
TabIndex="2" />
<Rectangle
Grid.Row="3"
Height="1"
HorizontalAlignment="Stretch"
Fill="{ThemeResource DividerStrokeColorDefaultBrush}" />
BorderThickness="1"
CornerRadius="20"
Visibility="{x:Bind ViewModel.ShowClipboardPreview, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<controls:ClipboardHistoryItemPreviewControl Height="48" ClipboardItem="{x:Bind ViewModel.CurrentClipboardItem, Mode=OneWay}" />
<Button
Grid.Row="4"
Height="32"
Margin="4,0,4,4"
Padding="{StaticResource ButtonPadding}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
AutomationProperties.LabeledBy="{x:Bind ClipboardHistoryButton}"
x:Uid="ClipboardHistoryButton"
Grid.Column="1"
Margin="0,0,4,0"
VerticalAlignment="Center"
IsEnabled="{x:Bind ViewModel.ClipboardHistoryEnabled, Mode=TwoWay}"
Style="{StaticResource SubtleButtonStyle}">
<Grid
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ColumnSpacing="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<FontIcon
Margin="0,0,0,0"
VerticalAlignment="Center"
AutomationProperties.AccessibilityView="Raw"
FontSize="16"
Glyph="&#xE81C;" />
<TextBlock
x:Name="ClipboardHistoryButton"
x:Uid="ClipboardHistoryButton"
Grid.Column="1"
VerticalAlignment="Center" />
<FontIcon
Grid.Column="2"
AutomationProperties.AccessibilityView="Raw"
FontSize="12"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Glyph="&#xE974;" />
</Grid>
Style="{StaticResource SubtleButtonStyle}"
Visibility="{x:Bind ViewModel.ShowClipboardHistoryButton, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}">
<ToolTipService.ToolTip>
<TextBlock x:Uid="ClipboardHistoryButtonToolTip" />
</ToolTipService.ToolTip>
<FontIcon
Margin="0,0,0,0"
VerticalAlignment="Center"
AutomationProperties.AccessibilityView="Raw"
FontSize="16"
Glyph="&#xE81C;" />
<Button.Flyout>
<Flyout
FlyoutPresenterStyle="{StaticResource PaddingLessFlyoutPresenterStyle}"
Placement="Right"
ShouldConstrainToRootBounds="False">
<ListView
<ItemsView
Width="320"
IsItemClickEnabled="True"
ItemClick="ClipboardHistory_ItemClick"
Margin="8,8,8,0"
IsItemInvokedEnabled="True"
ItemInvoked="ClipboardHistory_ItemInvoked"
ItemsSource="{x:Bind clipboardHistory, Mode=OneWay}"
SelectionMode="None">
<ListView.Transitions />
<ListView.ItemTemplate>
<ItemsView.Layout>
<StackLayout Orientation="Vertical" Spacing="8" />
</ItemsView.Layout>
<ItemsView.Transitions />
<ItemsView.ItemTemplate>
<DataTemplate x:DataType="local:ClipboardItem">
<Grid
Height="40"
HorizontalAlignment="Stretch"
<ItemContainer
AutomationProperties.Name="{x:Bind Description, Mode=OneWay}"
ColumnSpacing="8"
CornerRadius="16"
ToolTipService.ToolTip="{x:Bind Content}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MaxWidth="240" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image
Grid.Column="0"
HorizontalAlignment="Left"
x:Phase="2"
Source="{x:Bind Image}"
Visibility="Visible" />
<TextBlock
Grid.Column="0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
x:Phase="1"
Text="{x:Bind Content}"
TextTrimming="CharacterEllipsis"
Visibility="Visible" />
<Button
x:Name="ClipboardHistoryItemMoreOptionsButton"
x:Uid="ClipboardHistoryItemMoreOptionsButton"
Grid.Column="1"
VerticalAlignment="Center"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource SubtleButtonStyle}">
<Button.Content>
<FontIcon FontSize="16" Glyph="&#xe712;" />
</Button.Content>
<Button.Flyout>
<MenuFlyout>
<MenuFlyoutItem
x:Uid="ClipboardHistoryItemDeleteButton"
Click="ClipboardHistoryItemDeleteButton_Click"
CommandParameter="{x:Bind (local:ClipboardItem)}"
Icon="Delete" />
</MenuFlyout>
</Button.Flyout>
</Button>
</Grid>
<Grid
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="1"
ColumnSpacing="8"
CornerRadius="16">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MaxWidth="240" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<controls:ClipboardHistoryItemPreviewControl
Height="64"
x:Phase="0"
ClipboardItem="{x:Bind}" />
<Button
x:Name="ClipboardHistoryItemMoreOptionsButton"
x:Uid="ClipboardHistoryItemMoreOptionsButton"
Grid.Column="1"
VerticalAlignment="Center"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource SubtleButtonStyle}">
<Button.Content>
<FontIcon FontSize="16" Glyph="&#xe712;" />
</Button.Content>
<Button.Flyout>
<MenuFlyout>
<MenuFlyoutItem
x:Uid="ClipboardHistoryItemDeleteButton"
Click="ClipboardHistoryItemDeleteButton_Click"
CommandParameter="{x:Bind (local:ClipboardItem)}"
Icon="Delete" />
</MenuFlyout>
</Button.Flyout>
</Button>
</Grid>
</ItemContainer>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ItemsView.ItemTemplate>
</ItemsView>
</Flyout>
</Button.Flyout>
</Button>
</Grid>
<controls:PromptBox
x:Name="CustomFormatTextBox"
x:Uid="CustomFormatTextBox"
Grid.Row="1"
Margin="20,0,20,0"
x:FieldModifier="public"
IsEnabled="{x:Bind ViewModel.IsCustomAIServiceEnabled, Mode=OneWay}"
TabIndex="0">
<controls:PromptBox.Footer>
<StackPanel Orientation="Horizontal">
<TextBlock
x:Uid="AIMistakeNote"
Margin="0,0,2,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="10"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
<Button
Padding="0"
VerticalAlignment="Center"
Style="{StaticResource SubtleButtonStyle}"
Visibility="{x:Bind ViewModel.HasLegalLinks, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
<FontIcon FontSize="12" Glyph="&#xE946;" />
<Button.Flyout>
<Flyout>
<StackPanel Spacing="8">
<TextBlock TextWrapping="Wrap">
<Run x:Uid="AIMistakeNote" /><LineBreak /><Run
x:Uid="CustomEndpointWarning"
FontSize="12"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
</TextBlock>
<StackPanel Orientation="Horizontal" Spacing="8">
<HyperlinkButton
x:Name="TermsHyperlink"
x:Uid="TermsLink"
Padding="0"
FontSize="12"
NavigateUri="{x:Bind ViewModel.TermsLinkUri, Mode=OneWay}"
Visibility="{x:Bind ViewModel.HasTermsLink, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
<HyperlinkButton
x:Name="PrivacyHyperLink"
x:Uid="PrivacyLink"
Padding="0"
FontSize="12"
NavigateUri="{x:Bind ViewModel.PrivacyLinkUri, Mode=OneWay}"
Visibility="{x:Bind ViewModel.HasPrivacyLink, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
</StackPanel>
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</StackPanel>
</controls:PromptBox.Footer>
</controls:PromptBox>
<ScrollViewer Grid.Row="2">
<Grid RowSpacing="4">
<Grid.RowDefinitions>
<RowDefinition Height="{x:Bind ViewModel.StandardPasteFormats.Count, Mode=OneWay, Converter={StaticResource standardPasteFormatsToHeightConverter}}" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" MinHeight="{x:Bind ViewModel.CustomActionPasteFormats.Count, Mode=OneWay, Converter={StaticResource customActionsToMinHeightConverter}}" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListView
x:Name="PasteOptionsListView"
Grid.Row="0"
VerticalAlignment="Bottom"
IsItemClickEnabled="True"
ItemClick="PasteFormat_ItemClick"
ItemContainerTransitions="{x:Null}"
ItemTemplateSelector="{StaticResource PasteFormatTemplateSelector}"
ItemsSource="{x:Bind ViewModel.StandardPasteFormats, Mode=OneWay}"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollMode="Disabled"
SelectionMode="None"
TabIndex="1" />
<Rectangle
Grid.Row="1"
Height="1"
HorizontalAlignment="Stretch"
Fill="{ThemeResource DividerStrokeColorDefaultBrush}"
Visibility="{x:Bind ViewModel.CustomActionPasteFormats.Count, Mode=OneWay, Converter={StaticResource countToVisibilityConverter}}" />
<ListView
x:Name="CustomActionsListView"
Grid.Row="2"
VerticalAlignment="Top"
IsItemClickEnabled="True"
ItemClick="PasteFormat_ItemClick"
ItemContainerTransitions="{x:Null}"
ItemTemplateSelector="{StaticResource PasteFormatTemplateSelector}"
ItemsSource="{x:Bind ViewModel.CustomActionPasteFormats, Mode=OneWay}"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollMode="Disabled"
SelectionMode="None"
TabIndex="2" />
</Grid>
</ScrollViewer>
</Grid>
</Page>

View File

@@ -68,11 +68,22 @@ namespace AdvancedPaste.Pages
if (item.Content.Contains(StandardDataFormats.Text))
{
string text = await item.Content.GetTextAsync();
items.Add(new ClipboardItem { Content = text, Item = item });
items.Add(new ClipboardItem
{
Content = text,
Format = ClipboardFormat.Text,
Timestamp = item.Timestamp,
Item = item,
});
}
else if (item.Content.Contains(StandardDataFormats.Bitmap))
{
items.Add(new ClipboardItem { Item = item });
items.Add(new ClipboardItem
{
Format = ClipboardFormat.Image,
Timestamp = item.Timestamp,
Item = item,
});
}
}
}
@@ -187,10 +198,9 @@ namespace AdvancedPaste.Pages
}
}
private async void ClipboardHistory_ItemClick(object sender, ItemClickEventArgs e)
private async void ClipboardHistory_ItemInvoked(ItemsView sender, ItemsViewItemInvokedEventArgs args)
{
var item = e.ClickedItem as ClipboardItem;
if (item is not null)
if (args.InvokedItem is ClipboardItem item)
{
PowerToysTelemetry.Log.WriteEvent(new Telemetry.AdvancedPasteClipboardItemClicked());
if (!string.IsNullOrEmpty(item.Content))

View File

@@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:animatedvisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals">
<Style x:Key="SubtleDropDownButtonStyle" TargetType="DropDownButton">
<Setter Property="Background" Value="{ThemeResource SubtleButtonBackground}" />
<Setter Property="Foreground" Value="{ThemeResource SubtleButtonForeground}" />
<Setter Property="BorderBrush" Value="{ThemeResource SubtleButtonBorderBrush}" />
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
<Setter Property="Padding" Value="{StaticResource ButtonPadding}" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
<Setter Property="FocusVisualMargin" Value="-3" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid
x:Name="RootGrid"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BackgroundSizing="{TemplateBinding BackgroundSizing}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Grid.BackgroundTransition>
<BrushTransition Duration="0:0:0.083" />
</Grid.BackgroundTransition>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter
x:Name="ContentPresenter"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
AutomationProperties.AccessibilityView="Raw"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}" />
<AnimatedIcon
xmlns:local="using:Microsoft.UI.Xaml.Controls"
x:Name="ChevronIcon"
Grid.Column="1"
Width="12"
Height="12"
Margin="-4,0,0,0"
local:AnimatedIcon.State="Normal"
AutomationProperties.AccessibilityView="Raw"
Foreground="{ThemeResource DropDownButtonForegroundSecondary}">
<animatedvisuals:AnimatedChevronDownSmallVisualSource />
<AnimatedIcon.FallbackIconSource>
<FontIconSource
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="8"
Glyph="&#xE96E;"
IsTextScaleFactorEnabled="False" />
</AnimatedIcon.FallbackIconSource>
</AnimatedIcon>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ChevronIcon" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource DropDownButtonForegroundSecondaryPointerOver}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<Setter Target="ChevronIcon.(AnimatedIcon.State)" Value="PointerOver" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ChevronIcon" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource DropDownButtonForegroundSecondaryPressed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<Setter Target="ChevronIcon.(AnimatedIcon.State)" Value="Pressed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ChevronIcon" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<!-- DisabledVisual Should be handled by the control, not the animated icon. -->
<Setter Target="ChevronIcon.(AnimatedIcon.State)" Value="Normal" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -18,6 +18,7 @@ namespace AdvancedPaste.Helpers
PromptTokens = semanticKernelFormatEvent.PromptTokens;
CompletionTokens = semanticKernelFormatEvent.CompletionTokens;
ModelName = semanticKernelFormatEvent.ModelName;
ProviderType = semanticKernelFormatEvent.ProviderType;
ActionChain = semanticKernelFormatEvent.ActionChain;
}
@@ -38,6 +39,8 @@ namespace AdvancedPaste.Helpers
public string ModelName { get; set; }
public string ProviderType { get; set; }
public string ActionChain { get; set; }
public string ToJsonString() => JsonSerializer.Serialize(this, SourceGenerationContext.Default.AIServiceFormatEvent);

View File

@@ -0,0 +1,54 @@
// 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 AdvancedPaste.Models;
using Microsoft.SemanticKernel;
namespace AdvancedPaste.Helpers;
/// <summary>
/// Helper class for extracting AI service usage information from chat messages.
/// </summary>
public static class AIServiceUsageHelper
{
/// <summary>
/// Extracts AI service usage information from OpenAI chat message metadata.
/// </summary>
/// <param name="chatMessage">The chat message containing usage metadata.</param>
/// <returns>AI service usage information or AIServiceUsage.None if extraction fails.</returns>
public static AIServiceUsage GetOpenAIServiceUsage(ChatMessageContent chatMessage)
{
// Try to get usage information from metadata
if (chatMessage.Metadata?.TryGetValue("Usage", out var usageObj) == true)
{
// Handle different possible usage types through reflection to be version-agnostic
var usageType = usageObj.GetType();
try
{
// Try common property names for prompt tokens
var promptTokensProp = usageType.GetProperty("PromptTokens") ??
usageType.GetProperty("InputTokens") ??
usageType.GetProperty("InputTokenCount");
var completionTokensProp = usageType.GetProperty("CompletionTokens") ??
usageType.GetProperty("OutputTokens") ??
usageType.GetProperty("OutputTokenCount");
if (promptTokensProp != null && completionTokensProp != null)
{
var promptTokens = (int)(promptTokensProp.GetValue(usageObj) ?? 0);
var completionTokens = (int)(completionTokensProp.GetValue(usageObj) ?? 0);
return new AIServiceUsage(promptTokens, completionTokens);
}
}
catch
{
// If reflection fails, fall back to no usage
}
}
return AIServiceUsage.None;
}
}

View File

@@ -0,0 +1,84 @@
// 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.Threading.Tasks;
using AdvancedPaste.Models;
using Microsoft.UI.Xaml.Media.Imaging;
using Windows.ApplicationModel.DataTransfer;
namespace AdvancedPaste.Helpers
{
internal static class ClipboardItemHelper
{
/// <summary>
/// Creates a ClipboardItem from current clipboard data.
/// </summary>
public static async Task<ClipboardItem> CreateFromCurrentClipboardAsync(
DataPackageView clipboardData,
ClipboardFormat availableFormats,
DateTimeOffset? timestamp = null,
BitmapImage existingImage = null)
{
if (clipboardData == null || availableFormats == ClipboardFormat.None)
{
return null;
}
var clipboardItem = new ClipboardItem
{
Format = availableFormats,
Timestamp = timestamp,
};
// Text or HTML content
if (availableFormats.HasFlag(ClipboardFormat.Text) || availableFormats.HasFlag(ClipboardFormat.Html))
{
clipboardItem.Content = await clipboardData.GetTextOrEmptyAsync();
}
// Image content
else if (availableFormats.HasFlag(ClipboardFormat.Image))
{
// Reuse existing image if provided
if (existingImage != null)
{
clipboardItem.Image = existingImage;
}
else
{
clipboardItem.Image = await TryCreateBitmapImageAsync(clipboardData);
}
}
return clipboardItem;
}
/// <summary>
/// Creates a BitmapImage from clipboard data.
/// </summary>
private static async Task<BitmapImage> TryCreateBitmapImageAsync(DataPackageView clipboardData)
{
try
{
var imageReference = await clipboardData.GetBitmapAsync();
if (imageReference != null)
{
using (var imageStream = await imageReference.OpenReadAsync())
{
var bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(imageStream);
return bitmapImage;
}
}
}
catch
{
// Silently fail - caller can check for null
}
return null;
}
}
}

View File

@@ -6,11 +6,13 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using AdvancedPaste.Models;
using ManagedCommon;
using Microsoft.UI.Xaml.Media.Imaging;
using Microsoft.Win32;
using Windows.ApplicationModel.DataTransfer;
using Windows.Data.Html;
@@ -180,6 +182,46 @@ internal static class DataPackageHelpers
}
}
internal static async Task<string> GetClipboardTextOrThrowAsync(this DataPackageView dataPackageView, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(dataPackageView);
try
{
if (dataPackageView.Contains(StandardDataFormats.Text))
{
return await dataPackageView.GetTextAsync();
}
if (dataPackageView.Contains(StandardDataFormats.Html))
{
var html = await dataPackageView.GetHtmlFormatAsync();
return HtmlUtilities.ConvertToText(html);
}
if (dataPackageView.Contains(StandardDataFormats.Bitmap))
{
var bitmap = await dataPackageView.GetImageContentAsync();
if (bitmap != null)
{
return await OcrHelpers.ExtractTextAsync(bitmap, cancellationToken);
}
}
}
catch (Exception ex) when (ex is COMException or InvalidOperationException)
{
throw CreateClipboardTextMissingException(ex);
}
throw CreateClipboardTextMissingException();
}
private static PasteActionException CreateClipboardTextMissingException(Exception innerException = null)
{
var message = ResourceLoaderInstance.ResourceLoader.GetString("ClipboardEmptyWarning");
return new PasteActionException(message, innerException ?? new InvalidOperationException("Clipboard does not contain text content."));
}
internal static async Task<string> GetHtmlContentAsync(this DataPackageView dataPackageView) =>
dataPackageView.Contains(StandardDataFormats.Html) ? await dataPackageView.GetHtmlFormatAsync() : string.Empty;
@@ -195,6 +237,22 @@ internal static class DataPackageHelpers
return null;
}
internal static async Task<BitmapImage> GetPreviewBitmapAsync(this DataPackageView dataPackageView)
{
var stream = await dataPackageView.GetImageStreamAsync();
if (stream == null)
{
return null;
}
using (stream)
{
var bitmapImage = new BitmapImage();
bitmapImage.SetSource(stream);
return bitmapImage;
}
}
private static async Task<IRandomAccessStream> GetImageStreamAsync(this DataPackageView dataPackageView)
{
if (dataPackageView.Contains(StandardDataFormats.StorageItems))

View File

@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using AdvancedPaste.Models;
using Microsoft.PowerToys.Settings.UI.Library;
@@ -12,16 +13,22 @@ namespace AdvancedPaste.Settings
{
public interface IUserSettings
{
public bool IsAdvancedAIEnabled { get; }
public bool IsAIEnabled { get; }
public bool ShowCustomPreview { get; }
public bool CloseAfterLosingFocus { get; }
public bool EnableClipboardPreview { get; }
public IReadOnlyList<AdvancedPasteCustomAction> CustomActions { get; }
public IReadOnlyList<PasteFormats> AdditionalActions { get; }
public PasteAIConfiguration PasteAIConfiguration { get; }
public event EventHandler Changed;
Task SetActiveAIProviderAsync(string providerId);
}
}

View File

@@ -13,6 +13,7 @@ using AdvancedPaste.Models;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
using Windows.Security.Credentials;
namespace AdvancedPaste.Settings
{
@@ -33,23 +34,29 @@ namespace AdvancedPaste.Settings
public event EventHandler Changed;
public bool IsAdvancedAIEnabled { get; private set; }
public bool IsAIEnabled { get; private set; }
public bool ShowCustomPreview { get; private set; }
public bool CloseAfterLosingFocus { get; private set; }
public bool EnableClipboardPreview { get; private set; }
public IReadOnlyList<PasteFormats> AdditionalActions => _additionalActions;
public IReadOnlyList<AdvancedPasteCustomAction> CustomActions => _customActions;
public PasteAIConfiguration PasteAIConfiguration { get; private set; }
public UserSettings(IFileSystem fileSystem)
{
_settingsUtils = new SettingsUtils(fileSystem);
IsAdvancedAIEnabled = false;
IsAIEnabled = false;
ShowCustomPreview = true;
CloseAfterLosingFocus = false;
EnableClipboardPreview = true;
PasteAIConfiguration = new PasteAIConfiguration();
_additionalActions = [];
_customActions = [];
_taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
@@ -94,13 +101,17 @@ namespace AdvancedPaste.Settings
var settings = _settingsUtils.GetSettingsOrDefault<AdvancedPasteSettings>(AdvancedPasteModuleName);
if (settings != null)
{
bool migratedLegacyEnablement = TryMigrateLegacyAIEnablement(settings);
void UpdateSettings()
{
var properties = settings.Properties;
IsAdvancedAIEnabled = properties.IsAdvancedAIEnabled;
IsAIEnabled = properties.IsAIEnabled;
ShowCustomPreview = properties.ShowCustomPreview;
CloseAfterLosingFocus = properties.CloseAfterLosingFocus;
EnableClipboardPreview = properties.EnableClipboardPreview;
PasteAIConfiguration = properties.PasteAIConfiguration ?? new PasteAIConfiguration();
var sourceAdditionalActions = properties.AdditionalActions;
(PasteFormats Format, IAdvancedPasteAction[] Actions)[] additionalActionFormats =
@@ -126,6 +137,11 @@ namespace AdvancedPaste.Settings
Task.Factory
.StartNew(UpdateSettings, CancellationToken.None, TaskCreationOptions.None, _taskScheduler)
.Wait();
if (migratedLegacyEnablement)
{
settings.Save(_settingsUtils);
}
}
retry = false;
@@ -144,6 +160,220 @@ namespace AdvancedPaste.Settings
}
}
private static bool TryMigrateLegacyAIEnablement(AdvancedPasteSettings settings)
{
if (settings?.Properties is null)
{
return false;
}
var properties = settings.Properties;
bool legacyAdvancedAIConsumed = properties.TryConsumeLegacyAdvancedAIEnabled(out var advancedFlag);
bool legacyAdvancedAIEnabled = legacyAdvancedAIConsumed && advancedFlag;
PasswordCredential legacyCredential = TryGetLegacyOpenAICredential();
if (legacyCredential is null)
{
return legacyAdvancedAIConsumed;
}
var configuration = properties.PasteAIConfiguration;
if (configuration is null)
{
configuration = new PasteAIConfiguration();
properties.PasteAIConfiguration = configuration;
}
bool configurationUpdated = false;
var ensureResult = AdvancedPasteMigrationHelper.EnsureOpenAIProvider(configuration);
PasteAIProviderDefinition openAIProvider = ensureResult.Provider;
configurationUpdated |= ensureResult.Updated;
if (legacyAdvancedAIConsumed && openAIProvider is not null && openAIProvider.EnableAdvancedAI != legacyAdvancedAIEnabled)
{
openAIProvider.EnableAdvancedAI = legacyAdvancedAIEnabled;
configurationUpdated = true;
}
if (openAIProvider is not null)
{
StoreMigratedOpenAICredential(openAIProvider.Id, openAIProvider.ServiceType, legacyCredential.Password);
RemoveLegacyOpenAICredential();
}
const bool shouldEnableAI = true;
bool enabledUpdated = false;
if (properties.IsAIEnabled != shouldEnableAI)
{
properties.IsAIEnabled = shouldEnableAI;
enabledUpdated = true;
}
return configurationUpdated || enabledUpdated || legacyAdvancedAIConsumed;
}
private static PasswordCredential TryGetLegacyOpenAICredential()
{
try
{
PasswordVault vault = new();
var credential = vault.Retrieve("https://platform.openai.com/api-keys", "PowerToys_AdvancedPaste_OpenAIKey");
credential?.RetrievePassword();
return credential;
}
catch (Exception)
{
return null;
}
}
private static void RemoveLegacyOpenAICredential()
{
try
{
PasswordVault vault = new();
TryRemoveCredential(vault, "https://platform.openai.com/api-keys", "PowerToys_AdvancedPaste_OpenAIKey");
}
catch (Exception)
{
}
}
private static void StoreMigratedOpenAICredential(string providerId, string serviceType, string password)
{
if (string.IsNullOrWhiteSpace(password))
{
return;
}
try
{
var serviceKind = serviceType.ToAIServiceType();
if (serviceKind != AIServiceType.OpenAI)
{
return;
}
string resource = "https://platform.openai.com/api-keys";
string username = $"PowerToys_AdvancedPaste_PasteAI_openai_{NormalizeProviderIdentifier(providerId)}";
PasswordVault vault = new();
TryRemoveCredential(vault, resource, username);
PasswordCredential credential = new(resource, username, password);
vault.Add(credential);
}
catch (Exception ex)
{
Logger.LogError("Failed to migrate legacy OpenAI credential", ex);
}
}
private static void TryRemoveCredential(PasswordVault vault, string credentialResource, string credentialUserName)
{
try
{
PasswordCredential existingCred = vault.Retrieve(credentialResource, credentialUserName);
vault.Remove(existingCred);
}
catch (Exception)
{
// Credential doesn't exist, which is fine
}
}
private static string NormalizeProviderIdentifier(string providerId)
{
if (string.IsNullOrWhiteSpace(providerId))
{
return "default";
}
var filtered = new string(providerId.Where(char.IsLetterOrDigit).ToArray());
return string.IsNullOrWhiteSpace(filtered) ? "default" : filtered.ToLowerInvariant();
}
public async Task SetActiveAIProviderAsync(string providerId)
{
if (string.IsNullOrWhiteSpace(providerId))
{
return;
}
await Task.Run(() =>
{
lock (_loadingSettingsLock)
{
var settings = _settingsUtils.GetSettingsOrDefault<AdvancedPasteSettings>(AdvancedPasteModuleName);
var configuration = settings?.Properties?.PasteAIConfiguration;
var providers = configuration?.Providers;
if (configuration == null || providers == null || providers.Count == 0)
{
return;
}
var target = providers.FirstOrDefault(provider => string.Equals(provider.Id, providerId, StringComparison.OrdinalIgnoreCase));
if (target == null)
{
return;
}
if (string.Equals(configuration.ActiveProvider?.Id, providerId, StringComparison.OrdinalIgnoreCase))
{
return;
}
configuration.ActiveProviderId = providerId;
foreach (var provider in providers)
{
provider.IsActive = string.Equals(provider.Id, providerId, StringComparison.OrdinalIgnoreCase);
}
try
{
settings.Save(_settingsUtils);
}
catch (Exception ex)
{
Logger.LogError("Failed to set active AI provider", ex);
return;
}
try
{
Task.Factory
.StartNew(
() =>
{
PasteAIConfiguration.ActiveProviderId = providerId;
if (PasteAIConfiguration.Providers is not null)
{
foreach (var provider in PasteAIConfiguration.Providers)
{
provider.IsActive = string.Equals(provider.Id, providerId, StringComparison.OrdinalIgnoreCase);
}
}
Changed?.Invoke(this, EventArgs.Empty);
},
CancellationToken.None,
TaskCreationOptions.None,
_taskScheduler)
.Wait();
}
catch (Exception ex)
{
Logger.LogError("Failed to dispatch active AI provider change", ex);
}
}
});
}
public void Dispose()
{
Dispose(true);

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 AdvancedPaste.Helpers;
using Microsoft.UI.Xaml.Media.Imaging;
using Windows.ApplicationModel.DataTransfer;
@@ -12,10 +13,15 @@ public class ClipboardItem
{
public string Content { get; set; }
public ClipboardHistoryItem Item { get; set; }
public BitmapImage Image { get; set; }
public ClipboardFormat Format { get; set; }
public DateTimeOffset? Timestamp { get; set; }
// Only used for clipboard history items that have a ClipboardHistoryItem
public ClipboardHistoryItem Item { get; set; }
public string Description => !string.IsNullOrEmpty(Content) ? Content :
Image is not null ? ResourceLoaderInstance.ResourceLoader.GetString("ClipboardHistoryImage") :
string.Empty;

View File

@@ -0,0 +1,220 @@
// 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.Linq;
using AdvancedPaste.Helpers;
using AdvancedPaste.Models;
using AdvancedPaste.Services.CustomActions;
using AdvancedPaste.Settings;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
namespace AdvancedPaste.Services;
public sealed class AdvancedAIKernelService : KernelServiceBase
{
private sealed record RuntimeConfiguration(
AIServiceType ServiceType,
string ModelName,
string Endpoint,
string DeploymentName,
string ModelPath,
string SystemPrompt,
bool ModerationEnabled) : IKernelRuntimeConfiguration;
private readonly IAICredentialsProvider credentialsProvider;
public AdvancedAIKernelService(
IAICredentialsProvider credentialsProvider,
IKernelQueryCacheService queryCacheService,
IPromptModerationService promptModerationService,
IUserSettings userSettings,
ICustomActionTransformService customActionTransformService)
: base(queryCacheService, promptModerationService, userSettings, customActionTransformService)
{
ArgumentNullException.ThrowIfNull(credentialsProvider);
this.credentialsProvider = credentialsProvider;
}
protected override string AdvancedAIModelName => GetRuntimeConfiguration().ModelName;
protected override PromptExecutionSettings PromptExecutionSettings => CreatePromptExecutionSettings();
protected override void AddChatCompletionService(IKernelBuilder kernelBuilder)
{
ArgumentNullException.ThrowIfNull(kernelBuilder);
var runtimeConfig = GetRuntimeConfiguration();
var serviceType = runtimeConfig.ServiceType;
var modelName = runtimeConfig.ModelName;
var requiresApiKey = RequiresApiKey(serviceType);
var apiKey = string.Empty;
if (requiresApiKey)
{
this.credentialsProvider.Refresh();
apiKey = (this.credentialsProvider.GetKey() ?? string.Empty).Trim();
if (string.IsNullOrWhiteSpace(apiKey))
{
throw new InvalidOperationException($"An API key is required for {serviceType} but none was found in the credential vault.");
}
}
var endpoint = string.IsNullOrWhiteSpace(runtimeConfig.Endpoint) ? null : runtimeConfig.Endpoint.Trim();
var deployment = string.IsNullOrWhiteSpace(runtimeConfig.DeploymentName) ? modelName : runtimeConfig.DeploymentName;
switch (serviceType)
{
case AIServiceType.OpenAI:
kernelBuilder.AddOpenAIChatCompletion(modelName, apiKey, serviceId: modelName);
break;
case AIServiceType.AzureOpenAI:
kernelBuilder.AddAzureOpenAIChatCompletion(deployment, RequireEndpoint(endpoint, serviceType), apiKey, serviceId: modelName);
break;
default:
throw new NotSupportedException($"Service type '{runtimeConfig.ServiceType}' is not supported");
}
}
protected override AIServiceUsage GetAIServiceUsage(ChatMessageContent chatMessage)
{
return AIServiceUsageHelper.GetOpenAIServiceUsage(chatMessage);
}
protected override bool ShouldModerateAdvancedAI()
{
if (!TryGetRuntimeConfiguration(out var runtimeConfig))
{
return false;
}
return runtimeConfig.ModerationEnabled && (runtimeConfig.ServiceType == AIServiceType.OpenAI || runtimeConfig.ServiceType == AIServiceType.AzureOpenAI);
}
private static string GetModelName(PasteAIProviderDefinition config)
{
if (!string.IsNullOrWhiteSpace(config?.ModelName))
{
return config.ModelName;
}
return "gpt-4o";
}
protected override IKernelRuntimeConfiguration GetRuntimeConfiguration()
{
if (TryGetRuntimeConfiguration(out var runtimeConfig))
{
return runtimeConfig;
}
throw new InvalidOperationException("No Advanced AI provider is configured.");
}
private bool TryGetRuntimeConfiguration(out IKernelRuntimeConfiguration runtimeConfig)
{
runtimeConfig = null;
if (!TryResolveAdvancedProvider(out var provider))
{
return false;
}
var serviceType = NormalizeServiceType(provider.ServiceTypeKind);
if (!IsServiceTypeSupported(serviceType))
{
return false;
}
runtimeConfig = new RuntimeConfiguration(
serviceType,
GetModelName(provider),
provider.EndpointUrl,
provider.DeploymentName,
provider.ModelPath,
provider.SystemPrompt,
provider.ModerationEnabled);
return true;
}
private bool TryResolveAdvancedProvider(out PasteAIProviderDefinition provider)
{
provider = null;
var configuration = this.UserSettings?.PasteAIConfiguration;
if (configuration is null)
{
return false;
}
var activeProvider = configuration.ActiveProvider;
if (IsAdvancedProvider(activeProvider))
{
provider = activeProvider;
return true;
}
if (activeProvider is not null)
{
return false;
}
var fallback = configuration.Providers?.FirstOrDefault(IsAdvancedProvider);
if (fallback is not null)
{
provider = fallback;
return true;
}
return false;
}
private static bool IsAdvancedProvider(PasteAIProviderDefinition provider)
{
if (provider is null || !provider.EnableAdvancedAI)
{
return false;
}
var serviceType = NormalizeServiceType(provider.ServiceTypeKind);
return IsServiceTypeSupported(serviceType);
}
private static bool IsServiceTypeSupported(AIServiceType serviceType)
{
return serviceType is AIServiceType.OpenAI or AIServiceType.AzureOpenAI;
}
private static AIServiceType NormalizeServiceType(AIServiceType serviceType)
{
return serviceType == AIServiceType.Unknown ? AIServiceType.OpenAI : serviceType;
}
private static bool RequiresApiKey(AIServiceType serviceType)
{
return true;
}
private static string RequireEndpoint(string endpoint, AIServiceType serviceType)
{
if (!string.IsNullOrWhiteSpace(endpoint))
{
return endpoint;
}
throw new InvalidOperationException($"Endpoint is required for {serviceType} configuration but was not provided.");
}
private PromptExecutionSettings CreatePromptExecutionSettings()
{
var serviceType = GetRuntimeConfiguration().ServiceType;
return new OpenAIPromptExecutionSettings
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(),
};
}
}

View File

@@ -0,0 +1,22 @@
// 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 AdvancedPaste.Models;
namespace AdvancedPaste.Services.CustomActions
{
public sealed class CustomActionTransformResult
{
public CustomActionTransformResult(string content, AIServiceUsage usage)
{
Content = content;
Usage = usage;
}
public string Content { get; }
public AIServiceUsage Usage { get; }
}
}

View File

@@ -0,0 +1,205 @@
// 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.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using AdvancedPaste.Helpers;
using AdvancedPaste.Models;
using AdvancedPaste.Settings;
using AdvancedPaste.Telemetry;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Telemetry;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.OpenAI;
namespace AdvancedPaste.Services.CustomActions
{
public sealed class CustomActionTransformService : ICustomActionTransformService
{
private const string DefaultSystemPrompt = """
You are tasked with reformatting user's clipboard data. Use the user's instructions, and the content of their clipboard below to edit their clipboard content as they have requested it.
Do not output anything else besides the reformatted clipboard content.
""";
private readonly IPromptModerationService promptModerationService;
private readonly IPasteAIProviderFactory providerFactory;
private readonly IAICredentialsProvider credentialsProvider;
private readonly IUserSettings userSettings;
public CustomActionTransformService(IPromptModerationService promptModerationService, IPasteAIProviderFactory providerFactory, IAICredentialsProvider credentialsProvider, IUserSettings userSettings)
{
this.promptModerationService = promptModerationService;
this.providerFactory = providerFactory;
this.credentialsProvider = credentialsProvider;
this.userSettings = userSettings;
}
public async Task<CustomActionTransformResult> TransformTextAsync(string prompt, string inputText, CancellationToken cancellationToken, IProgress<double> progress)
{
var pasteConfig = userSettings?.PasteAIConfiguration;
var providerConfig = BuildProviderConfig(pasteConfig);
return await TransformAsync(prompt, inputText, providerConfig, cancellationToken, progress);
}
private async Task<CustomActionTransformResult> TransformAsync(string prompt, string inputText, PasteAIConfig providerConfig, CancellationToken cancellationToken, IProgress<double> progress)
{
ArgumentNullException.ThrowIfNull(providerConfig);
if (string.IsNullOrWhiteSpace(prompt))
{
return new CustomActionTransformResult(string.Empty, AIServiceUsage.None);
}
if (string.IsNullOrWhiteSpace(inputText))
{
Logger.LogWarning("Clipboard has no usable text data");
return new CustomActionTransformResult(string.Empty, AIServiceUsage.None);
}
var systemPrompt = providerConfig.SystemPrompt ?? DefaultSystemPrompt;
var fullPrompt = (systemPrompt ?? string.Empty) + "\n\n" + (inputText ?? string.Empty);
if (ShouldModerate(providerConfig))
{
await promptModerationService.ValidateAsync(fullPrompt, cancellationToken);
}
try
{
var provider = providerFactory.CreateProvider(providerConfig);
var request = new PasteAIRequest
{
Prompt = prompt,
InputText = inputText,
SystemPrompt = systemPrompt,
};
var operationStart = DateTime.UtcNow;
var providerContent = await provider.ProcessPasteAsync(
request,
cancellationToken,
progress);
var durationMs = (int)Math.Round((DateTime.UtcNow - operationStart).TotalMilliseconds);
var usage = request.Usage;
var content = providerContent ?? string.Empty;
// Log endpoint usage (custom action pipeline is not the advanced SK flow)
var endpointEvent = new AdvancedPasteEndpointUsageEvent(providerConfig.ProviderType, providerConfig.Model ?? string.Empty, isAdvanced: false, durationMs: durationMs);
PowerToysTelemetry.Log.WriteEvent(endpointEvent);
Logger.LogDebug($"{nameof(CustomActionTransformService)}.{nameof(TransformAsync)} complete; ModelName={providerConfig.Model ?? string.Empty}, PromptTokens={usage.PromptTokens}, CompletionTokens={usage.CompletionTokens}, DurationMs={durationMs}");
return new CustomActionTransformResult(content, usage);
}
catch (Exception ex)
{
Logger.LogError($"{nameof(CustomActionTransformService)}.{nameof(TransformAsync)} failed", ex);
var statusCode = ExtractStatusCode(ex);
var modelName = providerConfig.Model ?? string.Empty;
AdvancedPasteCustomActionErrorEvent errorEvent = new(providerConfig.ProviderType, modelName, statusCode, ex is PasteActionModeratedException ? PasteActionModeratedException.ErrorDescription : ex.Message);
PowerToysTelemetry.Log.WriteEvent(errorEvent);
if (ex is PasteActionException or OperationCanceledException)
{
throw;
}
var failureMessage = providerConfig.ProviderType switch
{
AIServiceType.OpenAI or AIServiceType.AzureOpenAI => ErrorHelpers.TranslateErrorText(statusCode),
_ => ResourceLoaderInstance.ResourceLoader.GetString("PasteError"),
};
throw new PasteActionException(failureMessage, ex);
}
}
private static int ExtractStatusCode(Exception exception)
{
if (exception is HttpOperationException httpOperationException)
{
return (int?)httpOperationException.StatusCode ?? -1;
}
if (exception is HttpRequestException httpRequestException && httpRequestException.StatusCode is HttpStatusCode statusCode)
{
return (int)statusCode;
}
return -1;
}
private static AIServiceType NormalizeServiceType(AIServiceType serviceType)
{
return serviceType == AIServiceType.Unknown ? AIServiceType.OpenAI : serviceType;
}
private PasteAIConfig BuildProviderConfig(PasteAIConfiguration config)
{
config ??= new PasteAIConfiguration();
var provider = config.ActiveProvider ?? config.Providers?.FirstOrDefault() ?? new PasteAIProviderDefinition();
var serviceType = NormalizeServiceType(provider.ServiceTypeKind);
var systemPrompt = string.IsNullOrWhiteSpace(provider.SystemPrompt) ? DefaultSystemPrompt : provider.SystemPrompt;
var apiKey = AcquireApiKey(serviceType);
var modelName = provider.ModelName;
var providerConfig = new PasteAIConfig
{
ProviderType = serviceType,
ApiKey = apiKey,
Model = modelName,
Endpoint = provider.EndpointUrl,
DeploymentName = provider.DeploymentName,
LocalModelPath = provider.ModelPath,
ModelPath = provider.ModelPath,
SystemPrompt = systemPrompt,
ModerationEnabled = provider.ModerationEnabled,
};
return providerConfig;
}
private string AcquireApiKey(AIServiceType serviceType)
{
if (!RequiresApiKey(serviceType))
{
return string.Empty;
}
credentialsProvider.Refresh();
return credentialsProvider.GetKey() ?? string.Empty;
}
private static bool RequiresApiKey(AIServiceType serviceType)
{
return serviceType switch
{
AIServiceType.Onnx => false,
AIServiceType.Ollama => false,
_ => true,
};
}
private static bool ShouldModerate(PasteAIConfig providerConfig)
{
if (providerConfig is null || !providerConfig.ModerationEnabled)
{
return false;
}
return providerConfig.ProviderType == AIServiceType.OpenAI || providerConfig.ProviderType == AIServiceType.AzureOpenAI;
}
}
}

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