Compare commits
2 Commits
tools/Rele
...
leilzh/fan
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17074f7e51 | ||
|
|
0eff4c2eb4 |
3
.github/actions/spell-check/allow/code.txt
vendored
@@ -94,7 +94,6 @@ onefuzzingestionpreparationtool
|
||||
OTP
|
||||
Yubi
|
||||
Yubico
|
||||
Perplexity
|
||||
svgl
|
||||
|
||||
# KEYS
|
||||
@@ -320,4 +319,4 @@ MRUINFO
|
||||
REGSTR
|
||||
|
||||
# Misc Win32 APIs and PInvokes
|
||||
INVOKEIDLIST
|
||||
INVOKEIDLIST
|
||||
2
.github/actions/spell-check/allow/names.txt
vendored
@@ -29,8 +29,6 @@ shortcutguide
|
||||
|
||||
# 8LWXpg is user name but user folder causes a flag
|
||||
LWXpg
|
||||
# 0x6f677548 is user name but user folder causes a flag
|
||||
x6f677548
|
||||
Adoumie
|
||||
Advaith
|
||||
alekhyareddy
|
||||
|
||||
1
.github/actions/spell-check/excludes.txt
vendored
@@ -131,4 +131,3 @@
|
||||
ignore$
|
||||
^src/modules/registrypreview/RegistryPreviewUILib/Controls/HexBox/.*$
|
||||
^src/common/CalculatorEngineCommon/exprtk\.hpp$
|
||||
src/modules/cmdpal/ext/SamplePagesExtension/Pages/SampleMarkdownImagesPage.cs
|
||||
|
||||
32
.github/actions/spell-check/expect.txt
vendored
@@ -27,7 +27,6 @@ admx
|
||||
advancedpaste
|
||||
advancedpasteui
|
||||
advancedpasteuishortcut
|
||||
advapi
|
||||
advfirewall
|
||||
AFeature
|
||||
affordances
|
||||
@@ -71,7 +70,6 @@ APPMODEL
|
||||
APPNAME
|
||||
appref
|
||||
appsettings
|
||||
appsfeatures
|
||||
appwindow
|
||||
appwiz
|
||||
appxpackage
|
||||
@@ -160,7 +158,6 @@ BUILDARCH
|
||||
BUILDNUMBER
|
||||
buildtransitive
|
||||
builttoroam
|
||||
BUNDLEINFO
|
||||
BVal
|
||||
BValue
|
||||
byapp
|
||||
@@ -249,7 +246,6 @@ CONFIGW
|
||||
CONFLICTINGMODIFIERKEY
|
||||
CONFLICTINGMODIFIERSHORTCUT
|
||||
CONOUT
|
||||
coreclr
|
||||
constexpr
|
||||
contentdialog
|
||||
contentfiles
|
||||
@@ -271,8 +267,6 @@ cpcontrols
|
||||
cph
|
||||
cplusplus
|
||||
CPower
|
||||
cpptools
|
||||
cppvsdbg
|
||||
cppwinrt
|
||||
createdump
|
||||
CREATEPROCESS
|
||||
@@ -284,7 +278,6 @@ CRH
|
||||
critsec
|
||||
cropandlock
|
||||
Crossdevice
|
||||
csdevkit
|
||||
CSearch
|
||||
CSettings
|
||||
cso
|
||||
@@ -312,7 +305,6 @@ CXVIRTUALSCREEN
|
||||
CYSCREEN
|
||||
CYSMICON
|
||||
CYVIRTUALSCREEN
|
||||
Czechia
|
||||
cziplib
|
||||
Dac
|
||||
dacl
|
||||
@@ -337,7 +329,6 @@ Deact
|
||||
debugbreak
|
||||
decryptor
|
||||
Dedup
|
||||
Deduplicator
|
||||
Deeplink
|
||||
DEFAULTBOOTSTRAPPERINSTALLFOLDER
|
||||
DEFAULTCOLOR
|
||||
@@ -394,7 +385,6 @@ DNLEN
|
||||
DONOTROUND
|
||||
DONTVALIDATEPATH
|
||||
dotnet
|
||||
downscale
|
||||
DPICHANGED
|
||||
DPIs
|
||||
DPSAPI
|
||||
@@ -444,7 +434,6 @@ EDITSHORTCUTS
|
||||
EDITTEXT
|
||||
EFile
|
||||
ekus
|
||||
emojis
|
||||
ENABLEDELAYEDEXPANSION
|
||||
ENABLEDPOPUP
|
||||
ENABLETAB
|
||||
@@ -484,7 +473,6 @@ examplehandler
|
||||
examplepowertoy
|
||||
EXAND
|
||||
EXCLUDEFROMCAPTURE
|
||||
EXECUTEDEFAULT
|
||||
executionpolicy
|
||||
exename
|
||||
exf
|
||||
@@ -810,7 +798,6 @@ KEYBOARDMANAGEREDITORLIBRARYWRAPPER
|
||||
keyboardmanagerstate
|
||||
keyboardmanagerui
|
||||
keyboardtester
|
||||
keycap
|
||||
KEYEVENTF
|
||||
KEYIMAGE
|
||||
keynum
|
||||
@@ -864,7 +851,6 @@ LOCKTYPE
|
||||
LOGFONT
|
||||
LOGFONTW
|
||||
logon
|
||||
LOGMSG
|
||||
LOGPIXELSX
|
||||
LOGPIXELSY
|
||||
LOn
|
||||
@@ -922,7 +908,6 @@ LWA
|
||||
lwin
|
||||
LZero
|
||||
MAGTRANSFORM
|
||||
MAJORMINOR
|
||||
MAKEINTRESOURCE
|
||||
MAKEINTRESOURCEA
|
||||
MAKEINTRESOURCEW
|
||||
@@ -1001,9 +986,6 @@ mousepointercrosshairs
|
||||
mouseutils
|
||||
MOVESIZEEND
|
||||
MOVESIZESTART
|
||||
muxx
|
||||
muxxc
|
||||
muxxh
|
||||
MRM
|
||||
MRT
|
||||
mru
|
||||
@@ -1042,7 +1024,6 @@ MWBEx
|
||||
MYICON
|
||||
NAMECHANGE
|
||||
namespaceanddescendants
|
||||
Namotion
|
||||
nao
|
||||
NCACTIVATE
|
||||
ncc
|
||||
@@ -1080,7 +1061,6 @@ NEWPLUSSHELLEXTENSIONWIN
|
||||
newrow
|
||||
nicksnettravels
|
||||
NIF
|
||||
NJson
|
||||
NLog
|
||||
NLSTEXT
|
||||
NMAKE
|
||||
@@ -1335,7 +1315,6 @@ PRODUCTVERSION
|
||||
Progman
|
||||
programdata
|
||||
projectname
|
||||
projitems
|
||||
PROPERTYKEY
|
||||
Propset
|
||||
PROPVARIANT
|
||||
@@ -1384,7 +1363,7 @@ QUNS
|
||||
RAII
|
||||
RAlt
|
||||
randi
|
||||
rasterization
|
||||
Rasterization
|
||||
Rasterize
|
||||
RAWINPUTDEVICE
|
||||
RAWINPUTHEADER
|
||||
@@ -1415,7 +1394,6 @@ regkey
|
||||
regroot
|
||||
regsvr
|
||||
REINSTALLMODE
|
||||
releaseblog
|
||||
reloadable
|
||||
Relogger
|
||||
remappings
|
||||
@@ -1466,6 +1444,7 @@ rstringalnum
|
||||
rstringalpha
|
||||
rstringdigit
|
||||
rtb
|
||||
RTB
|
||||
RTLREADING
|
||||
rtm
|
||||
runas
|
||||
@@ -1798,13 +1777,10 @@ UACUI
|
||||
UAL
|
||||
uap
|
||||
UBR
|
||||
UBreak
|
||||
ubrk
|
||||
UCallback
|
||||
ucrt
|
||||
ucrtd
|
||||
uefi
|
||||
UError
|
||||
uesc
|
||||
UFlags
|
||||
UHash
|
||||
@@ -1812,12 +1788,10 @@ UIA
|
||||
UIEx
|
||||
uild
|
||||
uitests
|
||||
UITo
|
||||
ULONGLONG
|
||||
ums
|
||||
uncompilable
|
||||
UNCPRIORITY
|
||||
undefining
|
||||
UNDNAME
|
||||
UNICODETEXT
|
||||
unins
|
||||
@@ -1876,7 +1850,6 @@ VFT
|
||||
vget
|
||||
vgetq
|
||||
viewmodels
|
||||
virama
|
||||
VIRTKEY
|
||||
VIRTUALDESK
|
||||
VISEGRADRELAY
|
||||
@@ -2028,7 +2001,6 @@ XButton
|
||||
xclip
|
||||
xcopy
|
||||
XDeployment
|
||||
xdf
|
||||
XDocument
|
||||
XElement
|
||||
xfd
|
||||
|
||||
43
.github/copilot-instructions.md
vendored
@@ -1,43 +0,0 @@
|
||||
# PowerToys – Copilot guide (concise)
|
||||
|
||||
This is the top-level guide for AI changes. Keep edits small, follow existing patterns, and cite exact paths in PRs.
|
||||
|
||||
Repo map (1‑line per area)
|
||||
- Core apps: `src/runner/**` (tray/loader), `src/settings-ui/**` (Settings app)
|
||||
- Shared libs: `src/common/**`
|
||||
- Modules: `src/modules/*` (one per utility; Command Palette in `src/modules/cmdpal/**`)
|
||||
- Build tools/docs: `tools/**`, `doc/devdocs/**`
|
||||
|
||||
Build and test (defaults)
|
||||
- Prerequisites: Visual Studio 2022 17.4+, minimal Windows 10 1803+.
|
||||
- Build discipline:
|
||||
- One terminal per operation (build → test). Don’t switch/open new ones mid-flow.
|
||||
- After making changes, `cd` to the project folder that changed (`.csproj`/`.vcxproj`).
|
||||
- Use script(s) to build, synchronously block and wait in foreground for it to finish: `tools/build/build.ps1|.cmd` (current folder), `build-essentials.*` (once per brand new build for missing nuget packages)
|
||||
- Treat build **exit code 0** as success; any non-zero exit code is a failure, have Copilot read the errors log in the build folder (e.g., `build.*.*.errors.log`) and surface problems.
|
||||
- Don’t start tests or launch Runner until the previous step succeeded.
|
||||
- Tests (fast + targeted):
|
||||
- Find the test project by product code prefix (e.g., FancyZones, AdvancedPaste). Look for a sibling folder or 1–2 levels up named like `<Product>*UnitTests` or `<Product>*UITests`.
|
||||
- Build the test project, wait for **exit**, then run only those tests via VS Test Explorer or `vstest.console.exe` with filters. Avoid `dotnet test` in this repo.
|
||||
- Add/adjust tests when changing behavior; if skipped, state why (e.g., comment-only, string rename).
|
||||
|
||||
Pull requests (expectations)
|
||||
- Atomic: one logical change; no drive‑by refactors.
|
||||
- Describe: problem / approach / risk / test evidence.
|
||||
- List: touched paths if not obvious.
|
||||
|
||||
When to ask for clarification
|
||||
- Ambiguous spec after scanning relevant docs (see below).
|
||||
- Cross-module impact (shared enum/struct) not clear.
|
||||
- Security / elevation / installer changes.
|
||||
|
||||
Logging (use existing stacks)
|
||||
- C++: `src/common/logger/**` (`Logger::info|warn|error|debug`). Keep hot paths quiet (hooks, tight loops).
|
||||
- C#: `ManagedCommon.Logger` (`LogInfo|LogWarning|LogError|LogDebug|LogTrace`). Some UIs use injected `ILogger` via `LoggerInstance.Logger`.
|
||||
|
||||
Docs to consult
|
||||
- `tools/build/BUILD-GUIDELINES.md`
|
||||
- `doc/devdocs/core/architecture.md`, `doc/devdocs/core/runner.md`, `doc/devdocs/core/settings/readme.md`, `doc/devdocs/modules/readme.md`
|
||||
|
||||
Done checklist (self review before finishing)
|
||||
- Build clean? Tests updated/passed? No unintended formatting? Any new dependency? Documented skips?
|
||||
@@ -1,19 +0,0 @@
|
||||
name: Automatic New Issue Deduplication
|
||||
on:
|
||||
issues:
|
||||
types: [opened, reopened]
|
||||
permissions:
|
||||
models: read
|
||||
issues: write
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.issue.number }}
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
deduplicate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run Deduplicate Action
|
||||
uses: pelikhan/action-genai-issue-dedup@v0
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
label_as_duplicate: true
|
||||
@@ -1,38 +0,0 @@
|
||||
name: Manual Batch Issue Deduplication
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
issue_numbers:
|
||||
description: "JSON array of issue numbers to deduplicate (e.g. [101,102,103])"
|
||||
required: true
|
||||
since:
|
||||
description: "Only compare against issues created after this date (ISO 8601, e.g. 2019-05-05T00:00:00Z)"
|
||||
required: false
|
||||
default: "2019-05-05T00:00:00Z"
|
||||
label_as_duplicate:
|
||||
description: "Apply duplicate label if duplicates are found (true/false)"
|
||||
required: false
|
||||
default: "true"
|
||||
|
||||
permissions:
|
||||
models: read
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
deduplicate:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
issue: ${{ fromJson(github.event.inputs.issue_numbers) }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Run GenAI Issue Deduplicator
|
||||
uses: pelikhan/action-genai-issue-dedup@v0
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
github_issue: ${{ matrix.issue }}
|
||||
label_as_duplicate: ${{ github.event.inputs.label_as_duplicate }}
|
||||
|
||||
2
.gitignore
vendored
@@ -350,9 +350,7 @@ src/common/Telemetry/*.etl
|
||||
|
||||
# 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/
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
"PowerToys.Awake.exe",
|
||||
"PowerToys.Awake.dll",
|
||||
|
||||
|
||||
"PowerToys.FancyZonesEditor.exe",
|
||||
"PowerToys.FancyZonesEditor.dll",
|
||||
"PowerToys.FancyZonesEditorCommon.dll",
|
||||
@@ -229,10 +230,7 @@
|
||||
|
||||
"PowerToys.CmdPalModuleInterface.dll",
|
||||
"CmdPalKeyboardService.dll",
|
||||
"*Microsoft.CmdPal.UI_*.msix",
|
||||
|
||||
"PowerToys.DSC.dll",
|
||||
"PowerToys.DSC.exe"
|
||||
"*Microsoft.CmdPal.UI_*.msix"
|
||||
],
|
||||
"SigningInfo": {
|
||||
"Operations": [
|
||||
@@ -299,9 +297,6 @@
|
||||
"msvcp140_1_app.dll",
|
||||
"msvcp140_2_app.dll",
|
||||
"msvcp140_app.dll",
|
||||
"Namotion.Reflection.dll",
|
||||
"NJsonSchema.Annotations.dll",
|
||||
"NJsonSchema.dll",
|
||||
"vcamp140_app.dll",
|
||||
"vccorlib140_app.dll",
|
||||
"vcomp140_app.dll",
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$BuildPlatform,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$BuildConfiguration,
|
||||
|
||||
[Parameter()]
|
||||
[string]$RepoRoot = (Get-Location).Path
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Resolve-PlatformDirectory {
|
||||
param(
|
||||
[string]$Root,
|
||||
[string]$Platform
|
||||
)
|
||||
|
||||
$normalized = $Platform.Trim()
|
||||
$candidates = @()
|
||||
$candidates += Join-Path $Root $normalized
|
||||
$candidates += Join-Path $Root ($normalized.ToUpperInvariant())
|
||||
$candidates += Join-Path $Root ($normalized.ToLowerInvariant())
|
||||
$candidates = $candidates | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -Unique
|
||||
|
||||
foreach ($candidate in $candidates) {
|
||||
if (Test-Path $candidate) {
|
||||
return $candidate
|
||||
}
|
||||
}
|
||||
|
||||
return $candidates[0]
|
||||
}
|
||||
|
||||
Write-Host "Repo root: $RepoRoot"
|
||||
Write-Host "Requested build platform: $BuildPlatform"
|
||||
Write-Host "Requested configuration: $BuildConfiguration"
|
||||
|
||||
# Always use x64 PowerToys.DSC.exe since CI/CD machines are x64
|
||||
$exePlatform = 'x64'
|
||||
$exeRoot = Resolve-PlatformDirectory -Root $RepoRoot -Platform $exePlatform
|
||||
$exeOutputDir = Join-Path $exeRoot $BuildConfiguration
|
||||
$exePath = Join-Path $exeOutputDir 'PowerToys.DSC.exe'
|
||||
|
||||
Write-Host "Using x64 PowerToys.DSC.exe to generate DSC manifests for $BuildPlatform build"
|
||||
|
||||
if (-not (Test-Path $exePath)) {
|
||||
throw "PowerToys.DSC.exe not found at '$exePath'. Make sure it has been built first."
|
||||
}
|
||||
|
||||
Write-Host "Using PowerToys.DSC.exe at '$exePath'."
|
||||
|
||||
# Output DSC manifests to the target build platform directory (x64, ARM64, etc.)
|
||||
$outputRoot = Resolve-PlatformDirectory -Root $RepoRoot -Platform $BuildPlatform
|
||||
if (-not (Test-Path $outputRoot)) {
|
||||
Write-Host "Creating missing platform output root at '$outputRoot'."
|
||||
New-Item -Path $outputRoot -ItemType Directory -Force | Out-Null
|
||||
}
|
||||
|
||||
$outputDir = Join-Path $outputRoot $BuildConfiguration
|
||||
if (-not (Test-Path $outputDir)) {
|
||||
Write-Host "Creating missing configuration output directory at '$outputDir'."
|
||||
New-Item -Path $outputDir -ItemType Directory -Force | Out-Null
|
||||
}
|
||||
|
||||
Write-Host "DSC manifests will be generated to: '$outputDir'"
|
||||
|
||||
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
|
||||
|
||||
$arguments = @('manifest', '--resource', 'settings', '--outputDir', $outputDir)
|
||||
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
|
||||
if ($generatedFiles.Count -eq 0) {
|
||||
throw "No DSC manifest files were generated in '$outputDir'."
|
||||
}
|
||||
|
||||
Write-Host "Generated $($generatedFiles.Count) DSC manifest file(s):"
|
||||
foreach ($file in $generatedFiles) {
|
||||
Write-Host " - $($file.FullName)"
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
# .pipelines/v2/nightly-prewarm.yml
|
||||
# Nightly pre-warm that reuses your existing ci.yml as-is
|
||||
|
||||
trigger: none
|
||||
pr: none
|
||||
|
||||
# (18:00 UTC) — adjust as you like
|
||||
schedules:
|
||||
- cron: "0 18 * * *" # UTC
|
||||
displayName: Nightly pre-warm (main)
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
always: true
|
||||
|
||||
name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
|
||||
|
||||
parameters:
|
||||
- name: buildPlatforms
|
||||
type: object
|
||||
default:
|
||||
- x64
|
||||
- arm64
|
||||
- name: enableMsBuildCaching
|
||||
type: boolean
|
||||
displayName: "Enable MSBuild Caching"
|
||||
default: true
|
||||
- name: msBuildCacheIsReadOnly
|
||||
type: boolean
|
||||
displayName: "MSBuild Cache Read Only"
|
||||
default: false
|
||||
|
||||
extends:
|
||||
template: templates/pipeline-ci-build.yml
|
||||
parameters:
|
||||
buildPlatforms: ${{ parameters.buildPlatforms }}
|
||||
enableMsBuildCaching: ${{ parameters.enableMsBuildCaching }}
|
||||
msBuildCacheIsReadOnly: ${{ parameters.msBuildCacheIsReadOnly }}
|
||||
@@ -32,7 +32,7 @@ parameters:
|
||||
- name: enableMsBuildCaching
|
||||
type: boolean
|
||||
displayName: "Enable MSBuild Caching"
|
||||
default: false
|
||||
default: true
|
||||
- name: runTests
|
||||
type: boolean
|
||||
displayName: "Run Tests"
|
||||
|
||||
@@ -43,6 +43,11 @@ parameters:
|
||||
displayName: "Build Using Visual Studio Preview"
|
||||
default: false
|
||||
|
||||
- name: enableAOT
|
||||
type: boolean
|
||||
displayName: "Enable AOT (Ahead-of-Time) Compilation for CmdPal"
|
||||
default: true
|
||||
|
||||
name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
|
||||
|
||||
variables:
|
||||
@@ -104,8 +109,8 @@ extends:
|
||||
useManagedIdentity: $(SigningUseManagedIdentity)
|
||||
clientId: $(SigningOriginalClientId)
|
||||
# Have msbuild use the release nuget config profile
|
||||
additionalBuildOptions: /p:RestoreConfigFile="$(Build.SourcesDirectory)\.pipelines\release-nuget.config" /p:EnableCmdPalAOT=${{ parameters.enableAOT }} /p:InstallerSuffix=${{ parameters.installerSuffix }}
|
||||
installerSuffix: ${{ parameters.installerSuffix }}
|
||||
additionalBuildOptions: /p:RestoreConfigFile="$(Build.SourcesDirectory)\.pipelines\release-nuget.config" /p:InstallerSuffix=${{ parameters.installerSuffix }} /p:EnableCmdPalAOT=true
|
||||
beforeBuildSteps:
|
||||
# Sets versions for all PowerToy created DLLs
|
||||
- pwsh: |-
|
||||
|
||||
@@ -50,9 +50,6 @@ parameters:
|
||||
- name: enableMsBuildCaching
|
||||
type: boolean
|
||||
default: false
|
||||
- name: msBuildCacheIsReadOnly
|
||||
type: boolean
|
||||
default: true
|
||||
- name: runTests
|
||||
type: boolean
|
||||
default: true
|
||||
@@ -157,11 +154,6 @@ jobs:
|
||||
$MSBuildCacheParameters += " -reportfileaccesses"
|
||||
$MSBuildCacheParameters += " -p:MSBuildCacheEnabled=true"
|
||||
$MSBuildCacheParameters += " -p:MSBuildCacheLogDirectory=$(LogOutputDirectory)\MSBuildCacheLogs"
|
||||
# Cache read-only policy controlled by parameter
|
||||
$cacheIsReadOnly = "${{ parameters.msBuildCacheIsReadOnly }}"
|
||||
if ($cacheIsReadOnly -eq "True") {
|
||||
$MSBuildCacheParameters += " /p:MSBuildCacheRemoteCacheIsReadOnly=true"
|
||||
}
|
||||
Write-Host "MSBuildCacheParameters: $MSBuildCacheParameters"
|
||||
Write-Host "##vso[task.setvariable variable=MSBuildCacheParameters]$MSBuildCacheParameters"
|
||||
displayName: Prepare MSBuildCache variables
|
||||
@@ -271,23 +263,6 @@ jobs:
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
|
||||
# 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)
|
||||
condition: ne(variables['BuildPlatform'], 'x64')
|
||||
inputs:
|
||||
solution: src/dsc/v3/PowerToys.DSC/PowerToys.DSC.csproj
|
||||
msbuildArgs: /t:Build /m /restore
|
||||
platform: x64
|
||||
configuration: $(BuildConfiguration)
|
||||
msbuildArchitecture: x64
|
||||
maximumCpuCount: true
|
||||
|
||||
# Generate DSC manifests using PowerToys.DSC.exe
|
||||
- pwsh: |-
|
||||
& '.pipelines/generateDscManifests.ps1' -BuildPlatform '$(BuildPlatform)' -BuildConfiguration '$(BuildConfiguration)' -RepoRoot '$(Build.SourcesDirectory)'
|
||||
displayName: Generate DSC manifests
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: Stage SDK/build
|
||||
inputs:
|
||||
@@ -436,28 +411,9 @@ jobs:
|
||||
!**\obj\**
|
||||
|
||||
- pwsh: |-
|
||||
$Packages = Get-ChildItem -Recurse -Filter "Microsoft.CmdPal.UI_*.msix"
|
||||
Write-Host "Found $($Packages.Count) CmdPal MSIX package(s):"
|
||||
foreach ($pkg in $Packages) {
|
||||
Write-Host " - $($pkg.FullName)"
|
||||
}
|
||||
|
||||
if ($Packages.Count -gt 0) {
|
||||
# Priority: Look for platform-specific MSIX (x64/arm64) first, then fall back to any
|
||||
$PlatformPackage = $Packages | Where-Object { $_.Name -match "Microsoft\.CmdPal\.UI_.*_(x64|arm64)\.msix$" } | Select-Object -First 1
|
||||
if ($PlatformPackage) {
|
||||
$Package = $PlatformPackage
|
||||
Write-Host "Using platform-specific package: $($Package.FullName)"
|
||||
} else {
|
||||
$Package = $Packages | Select-Object -First 1
|
||||
Write-Host "Using first available package: $($Package.FullName)"
|
||||
}
|
||||
|
||||
$PackageFilename = $Package.FullName
|
||||
Write-Host "##vso[task.setvariable variable=CmdPalPackagePath]${PackageFilename}"
|
||||
} else {
|
||||
Write-Warning "No CmdPal MSIX packages found!"
|
||||
}
|
||||
$Package = (Get-ChildItem -Recurse -Filter "Microsoft.CmdPal.UI_*.msix" | Select -First 1)
|
||||
$PackageFilename = $Package.FullName
|
||||
Write-Host "##vso[task.setvariable variable=CmdPalPackagePath]${PackageFilename}"
|
||||
displayName: Locate the CmdPal MSIX
|
||||
|
||||
- ${{ if eq(parameters.codeSign, true) }}:
|
||||
|
||||
@@ -13,9 +13,6 @@ parameters:
|
||||
- name: enableMsBuildCaching
|
||||
type: boolean
|
||||
default: false
|
||||
- name: msBuildCacheIsReadOnly
|
||||
type: boolean
|
||||
default: true
|
||||
- name: runTests
|
||||
type: boolean
|
||||
default: true
|
||||
@@ -55,7 +52,6 @@ stages:
|
||||
buildConfigurations: [Release]
|
||||
enablePackageCaching: true
|
||||
enableMsBuildCaching: ${{ parameters.enableMsBuildCaching }}
|
||||
msBuildCacheIsReadOnly: ${{ parameters.msBuildCacheIsReadOnly }}
|
||||
runTests: ${{ parameters.runTests }}
|
||||
useVSPreview: ${{ parameters.useVSPreview }}
|
||||
useLatestWinAppSDK: ${{ parameters.useLatestWinAppSDK }}
|
||||
|
||||
@@ -132,39 +132,6 @@ steps:
|
||||
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
|
||||
|
||||
#### 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
|
||||
/p:InstallerSuffix=${{ parameters.installerSuffix }}
|
||||
-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
|
||||
- task: VSBuild@1
|
||||
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Build VNext Bootstrapper
|
||||
@@ -181,7 +148,7 @@ steps:
|
||||
${{ parameters.additionalBuildOptions }}
|
||||
platform: $(BuildPlatform)
|
||||
configuration: $(BuildConfiguration)
|
||||
clean: false # don't undo our hard work above by deleting the MSI nor SilentFilesInUseBAFunction
|
||||
clean: false # don't undo our hard work above by deleting the MSI
|
||||
msbuildArchitecture: x64
|
||||
maximumCpuCount: true
|
||||
|
||||
|
||||
@@ -39,11 +39,6 @@ foreach ($csprojFile in $csprojFilesArray) {
|
||||
if ($csprojFile -like '*TemplateCmdPalExtension.csproj') {
|
||||
continue
|
||||
}
|
||||
|
||||
# The CmdPal.Core projects use a common shared props file, so skip them
|
||||
if ($csprojFile -like '*Microsoft.CmdPal.Core.*.csproj') {
|
||||
continue
|
||||
}
|
||||
|
||||
$importExists = Test-ImportSharedCsWinRTProps -filePath $csprojFile
|
||||
if (!$importExists) {
|
||||
|
||||
43
.vscode/launch.json
vendored
@@ -1,43 +0,0 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"inputs": [
|
||||
{
|
||||
"id": "arch",
|
||||
"type": "pickString",
|
||||
"description": "Select target architecture",
|
||||
"options": ["x64", "arm64"],
|
||||
"default": "x64"
|
||||
}
|
||||
],
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Run native executable (no build)",
|
||||
"type": "cppvsdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}\\${input:arch}\\Debug\\PowerToys.exe",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "C/C++ Attach to PowerToys Process (native)",
|
||||
"type": "cppvsdbg",
|
||||
"request": "attach",
|
||||
"processId": "${command:pickProcess}",
|
||||
"symbolSearchPath": "${workspaceFolder}\\${input:arch}\\Debug;${workspaceFolder}\\Debug;${workspaceFolder}\\symbols"
|
||||
},
|
||||
{
|
||||
"name": "Run managed code (managed, no build, ARCH configurable)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}\\${input:arch}\\Debug\\WinUI3Apps\\PowerToys.Settings.exe",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"env": {},
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -30,6 +30,7 @@
|
||||
<_PropertySheetDisplayName>PowerToys.Root.Props</_PropertySheetDisplayName>
|
||||
<ForceImportBeforeCppProps>$(MsbuildThisFileDirectory)\Cpp.Build.props</ForceImportBeforeCppProps>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(MSBuildProjectExtension)' == '.csproj'">
|
||||
<PackageReference Include="StyleCop.Analyzers">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
||||
@@ -3,9 +3,4 @@
|
||||
|
||||
<Import Project="$(MSBuildCachePackageRoot)\build\$(MSBuildCachePackageName).targets" Condition="'$(MSBuildCacheEnabled)' == 'true'" />
|
||||
<Import Project="$(MSBuildCacheSharedCompilationPackageRoot)\build\Microsoft.MSBuildCache.SharedCompilation.targets" Condition="'$(MSBuildCacheEnabled)' == 'true'" />
|
||||
|
||||
<!-- Override ManifestTool to the x64 host tool under WindowsSdkDir for all projects once the SDK path is known. -->
|
||||
<PropertyGroup Label="ManifestToolOverride">
|
||||
<ManifestTool Condition="Exists('$(WindowsSdkDir)bin\x64\mt.exe')">$(WindowsSdkDir)bin\x64\mt.exe</ManifestTool>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,7 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="AdaptiveCards.ObjectModel.WinUI3" Version="2.0.0-beta" />
|
||||
@@ -22,11 +21,11 @@
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.Converters" Version="8.2.250402" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.Extensions" Version="8.2.250402" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.UI.Controls.DataGrid" Version="7.1.2" />
|
||||
<PackageVersion Include="CommunityToolkit.Labs.WinUI.Controls.MarkdownTextBlock" Version="0.1.250910-build.2249" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.UI.Controls.Markdown" Version="7.1.2" />
|
||||
<PackageVersion Include="CommunityToolkit.Labs.WinUI.Controls.MarkdownTextBlock" Version="0.1.250703-build.2173" />
|
||||
<PackageVersion Include="ControlzEx" Version="6.0.0" />
|
||||
<PackageVersion Include="HelixToolkit" Version="2.24.0" />
|
||||
<PackageVersion Include="HelixToolkit.Core.Wpf" Version="2.24.0" />
|
||||
<PackageVersion Include="HtmlAgilityPack" Version="1.12.3" />
|
||||
<PackageVersion Include="hyjiacan.pinyin4net" Version="4.1.1" />
|
||||
<PackageVersion Include="Interop.Microsoft.Office.Interop.OneNote" Version="1.1.0.2" />
|
||||
<PackageVersion Include="LazyCache" Version="2.4.0" />
|
||||
@@ -38,7 +37,6 @@
|
||||
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.8" />
|
||||
<!-- 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.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" />
|
||||
@@ -47,7 +45,7 @@
|
||||
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.SemanticKernel" Version="1.15.0" />
|
||||
<PackageVersion Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
|
||||
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.3179.45" />
|
||||
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.2903.40" />
|
||||
<!-- Package Microsoft.Win32.SystemEvents added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Drawing.Common but the 8.0.1 version wasn't published to nuget. -->
|
||||
<PackageVersion Include="Microsoft.Win32.SystemEvents" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.WindowsPackageManager.ComInterop" Version="1.10.340" />
|
||||
@@ -59,15 +57,14 @@
|
||||
This is present due to a bug in CsWinRT where WPF projects cause the analyzer to fail.
|
||||
-->
|
||||
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
|
||||
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4948" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.8.250907003" />
|
||||
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4188" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.7.250513003" />
|
||||
<PackageVersion Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
|
||||
<PackageVersion Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
|
||||
<PackageVersion Include="ModernWpfUI" Version="0.9.4" />
|
||||
<!-- Moq to stay below v4.20 due to behavior change. need to be sure fixed -->
|
||||
<PackageVersion Include="Moq" Version="4.18.4" />
|
||||
<PackageVersion Include="MSTest" Version="3.8.3" />
|
||||
<PackageVersion Include="NJsonSchema" Version="11.4.0" />
|
||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageVersion Include="NLog" Version="5.2.8" />
|
||||
<PackageVersion Include="NLog.Extensions.Logging" Version="5.3.8" />
|
||||
|
||||
@@ -1509,6 +1509,7 @@ SOFTWARE.
|
||||
- CommunityToolkit.WinUI.Converters
|
||||
- CommunityToolkit.WinUI.Extensions
|
||||
- CommunityToolkit.WinUI.UI.Controls.DataGrid
|
||||
- CommunityToolkit.WinUI.UI.Controls.Markdown
|
||||
- ControlzEx
|
||||
- HelixToolkit
|
||||
- HelixToolkit.Core.Wpf
|
||||
@@ -1521,7 +1522,6 @@ SOFTWARE.
|
||||
- ModernWpfUI
|
||||
- Moq
|
||||
- MSTest
|
||||
- NJsonSchema
|
||||
- NLog
|
||||
- NLog.Extensions.Logging
|
||||
- NLog.Schema
|
||||
|
||||
@@ -262,6 +262,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "utils", "utils", "{B39DC643
|
||||
src\common\utils\EventLocker.h = src\common\utils\EventLocker.h
|
||||
src\common\utils\EventWaiter.h = src\common\utils\EventWaiter.h
|
||||
src\common\utils\excluded_apps.h = src\common\utils\excluded_apps.h
|
||||
src\common\utils\shell_ext_registration.h = src\common\utils\shell_ext_registration.h
|
||||
src\common\utils\exec.h = src\common\utils\exec.h
|
||||
src\common\utils\game_mode.h = src\common\utils\game_mode.h
|
||||
src\common\utils\gpo.h = src\common\utils\gpo.h
|
||||
@@ -281,7 +282,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "utils", "utils", "{B39DC643
|
||||
src\common\utils\registry.h = src\common\utils\registry.h
|
||||
src\common\utils\resources.h = src\common\utils\resources.h
|
||||
src\common\utils\serialized.h = src\common\utils\serialized.h
|
||||
src\common\utils\shell_ext_registration.h = src\common\utils\shell_ext_registration.h
|
||||
src\common\utils\string_utils.h = src\common\utils\string_utils.h
|
||||
src\common\utils\timeutil.h = src\common\utils\timeutil.h
|
||||
src\common\utils\UnhandledExceptionHandler.h = src\common\utils\UnhandledExceptionHandler.h
|
||||
@@ -638,7 +638,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.CommandPalette.Ex
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CommandPalette.Extensions.Toolkit", "src\modules\cmdpal\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj", "{CA4D810F-C8F4-4B61-9DA9-71807E0B9F24}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Core.Common", "src\modules\cmdpal\Core\Microsoft.CmdPal.Core.Common\Microsoft.CmdPal.Core.Common.csproj", "{14E62033-58D0-4A7D-8990-52F50A08BBBD}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Common", "src\modules\cmdpal\Microsoft.CmdPal.Common\Microsoft.CmdPal.Common.csproj", "{14E62033-58D0-4A7D-8990-52F50A08BBBD}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.UI", "src\modules\cmdpal\Microsoft.Terminal.UI\Microsoft.Terminal.UI.vcxproj", "{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}"
|
||||
EndProject
|
||||
@@ -728,7 +728,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerRename.UITests", "src\
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Core.ViewModels", "src\modules\cmdpal\Core\Microsoft.CmdPal.Core.ViewModels\Microsoft.CmdPal.Core.ViewModels.csproj", "{24133F7F-C1D1-DE04-EFA8-F5D5467FE027}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Core.ViewModels", "src\modules\cmdpal\Microsoft.CmdPal.Core.ViewModels\Microsoft.CmdPal.Core.ViewModels.csproj", "{24133F7F-C1D1-DE04-EFA8-F5D5467FE027}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{0E556541-6A45-42CB-AE49-EE5A9BE05E7C}"
|
||||
EndProject
|
||||
@@ -793,16 +793,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Window
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.UnitTestBase", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.UnitTestsBase\Microsoft.CmdPal.Ext.UnitTestBase.csproj", "{00D8659C-2068-40B6-8B86-759CD6284BBB}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{E11826E1-76DF-42AC-985C-164CC2EE57A1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScreenRuler.UITests", "src\modules\MeasureTool\Tests\ScreenRuler.UITests\ScreenRuler.UITests.csproj", "{66C069F8-C548-4CA6-8CDE-239104D68E88}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "v3", "v3", "{9605B84E-FAC4-477B-B9EC-0753177EE6A8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerToys.DSC", "src\dsc\v3\PowerToys.DSC\PowerToys.DSC.csproj", "{94CDC147-6137-45E9-AEDE-17FF809607C0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerToys.DSC.UnitTests", "src\dsc\v3\PowerToys.DSC.UnitTests\PowerToys.DSC.UnitTests.csproj", "{A24BF1AF-79AA-4896-BAE3-CCBBE0380A78}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Apps.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.Apps.UnitTests\Microsoft.CmdPal.Ext.Apps.UnitTests.csproj", "{E816D7B1-4688-4ECB-97CC-3D8E798F3830}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Bookmarks.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.Bookmarks.UnitTests\Microsoft.CmdPal.Ext.Bookmarks.UnitTests.csproj", "{E816D7B3-4688-4ECB-97CC-3D8E798F3832}"
|
||||
@@ -2705,22 +2695,6 @@ Global
|
||||
{61CBF221-9452-4934-B685-146285E080D7}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{61CBF221-9452-4934-B685-146285E080D7}.Release|x64.ActiveCfg = Release|x64
|
||||
{61CBF221-9452-4934-B685-146285E080D7}.Release|x64.Build.0 = Release|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|x64.Build.0 = Debug|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|x64.ActiveCfg = Release|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|x64.Build.0 = Release|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|x64.Build.0 = Debug|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|x64.ActiveCfg = Release|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|x64.Build.0 = Release|x64
|
||||
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A1}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A1}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
@@ -2737,6 +2711,30 @@ Global
|
||||
{43E779F3-D83C-48B1-BA8D-1912DBD76FC9}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{43E779F3-D83C-48B1-BA8D-1912DBD76FC9}.Release|x64.ActiveCfg = Release|x64
|
||||
{43E779F3-D83C-48B1-BA8D-1912DBD76FC9}.Release|x64.Build.0 = Release|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|x64.Build.0 = Debug|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|x64.ActiveCfg = Release|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|x64.Build.0 = Release|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|x64.Build.0 = Debug|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|x64.ActiveCfg = Release|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|x64.Build.0 = Release|x64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|x64.Build.0 = Debug|x64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|x64.ActiveCfg = Release|x64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|x64.Build.0 = Release|x64
|
||||
{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
@@ -2889,30 +2887,6 @@ Global
|
||||
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|x64.ActiveCfg = Release|x64
|
||||
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|x64.Build.0 = Release|x64
|
||||
{66C069F8-C548-4CA6-8CDE-239104D68E88}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{66C069F8-C548-4CA6-8CDE-239104D68E88}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{66C069F8-C548-4CA6-8CDE-239104D68E88}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{66C069F8-C548-4CA6-8CDE-239104D68E88}.Debug|x64.Build.0 = Debug|x64
|
||||
{66C069F8-C548-4CA6-8CDE-239104D68E88}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{66C069F8-C548-4CA6-8CDE-239104D68E88}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{66C069F8-C548-4CA6-8CDE-239104D68E88}.Release|x64.ActiveCfg = Release|x64
|
||||
{66C069F8-C548-4CA6-8CDE-239104D68E88}.Release|x64.Build.0 = Release|x64
|
||||
{94CDC147-6137-45E9-AEDE-17FF809607C0}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{94CDC147-6137-45E9-AEDE-17FF809607C0}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{94CDC147-6137-45E9-AEDE-17FF809607C0}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{94CDC147-6137-45E9-AEDE-17FF809607C0}.Debug|x64.Build.0 = Debug|x64
|
||||
{94CDC147-6137-45E9-AEDE-17FF809607C0}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{94CDC147-6137-45E9-AEDE-17FF809607C0}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{94CDC147-6137-45E9-AEDE-17FF809607C0}.Release|x64.ActiveCfg = Release|x64
|
||||
{94CDC147-6137-45E9-AEDE-17FF809607C0}.Release|x64.Build.0 = Release|x64
|
||||
{A24BF1AF-79AA-4896-BAE3-CCBBE0380A78}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{A24BF1AF-79AA-4896-BAE3-CCBBE0380A78}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{A24BF1AF-79AA-4896-BAE3-CCBBE0380A78}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A24BF1AF-79AA-4896-BAE3-CCBBE0380A78}.Debug|x64.Build.0 = Debug|x64
|
||||
{A24BF1AF-79AA-4896-BAE3-CCBBE0380A78}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{A24BF1AF-79AA-4896-BAE3-CCBBE0380A78}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{A24BF1AF-79AA-4896-BAE3-CCBBE0380A78}.Release|x64.ActiveCfg = Release|x64
|
||||
{A24BF1AF-79AA-4896-BAE3-CCBBE0380A78}.Release|x64.Build.0 = Release|x64
|
||||
{E816D7B1-4688-4ECB-97CC-3D8E798F3830}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{E816D7B1-4688-4ECB-97CC-3D8E798F3830}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{E816D7B1-4688-4ECB-97CC-3D8E798F3830}.Debug|x64.ActiveCfg = Debug|x64
|
||||
@@ -2954,6 +2928,7 @@ Global
|
||||
{D1D6BC88-09AE-4FB4-AD24-5DED46A791DD} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9} = {264B412F-DB8B-4CF8-A74B-96998B183045}
|
||||
{1AFB6476-670D-4E80-A464-657E01DFF482} = {557C4636-D7E1-4838-A504-7D19B725EE95}
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
@@ -3182,7 +3157,7 @@ Global
|
||||
{F3D09629-59A2-4924-A4B9-D6BFAA2C1B49} = {3846508C-77EB-4034-A702-F8BB263C4F79}
|
||||
{305DD37E-C85D-4B08-AAFE-7381FA890463} = {F3D09629-59A2-4924-A4B9-D6BFAA2C1B49}
|
||||
{CA4D810F-C8F4-4B61-9DA9-71807E0B9F24} = {F3D09629-59A2-4924-A4B9-D6BFAA2C1B49}
|
||||
{14E62033-58D0-4A7D-8990-52F50A08BBBD} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||
{14E62033-58D0-4A7D-8990-52F50A08BBBD} = {7520A2FE-00A2-49B8-83ED-DB216E874C04}
|
||||
{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F} = {7520A2FE-00A2-49B8-83ED-DB216E874C04}
|
||||
{071E18A4-A530-46B8-AB7D-B862EE55E24E} = {3846508C-77EB-4034-A702-F8BB263C4F79}
|
||||
{C846F7A7-792A-47D9-B0CB-417C900EE03D} = {071E18A4-A530-46B8-AB7D-B862EE55E24E}
|
||||
@@ -3219,10 +3194,10 @@ Global
|
||||
{9BC1C986-1E97-4D07-A7B1-CE226C239EFA} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{99CA1509-FB73-456E-AFAF-AB89C017BD72} = {6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}
|
||||
{61CBF221-9452-4934-B685-146285E080D7} = {6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE} = {C3081D9A-1586-441A-B5F4-ED815B3719C1}
|
||||
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A1} = {2C318EC3-BA86-4372-B1BC-DB0F33C208B2}
|
||||
{43E779F3-D83C-48B1-BA8D-1912DBD76FC9} = {68328142-5B31-4715-BCBB-7B6345EE0971}
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE} = {C3081D9A-1586-441A-B5F4-ED815B3719C1}
|
||||
{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{14AFD976-B4D2-49D0-9E6C-AA93CC061B8A} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{9D3F3793-EFE3-4525-8782-238015DABA62} = {66E1534A-1587-42B2-912F-45C994D32904}
|
||||
@@ -3258,11 +3233,6 @@ Global
|
||||
{E816D7AF-4688-4ECB-97CC-3D8E798F3828} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{E816D7B0-4688-4ECB-97CC-3D8E798F3829} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{00D8659C-2068-40B6-8B86-759CD6284BBB} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{E11826E1-76DF-42AC-985C-164CC2EE57A1} = {7AC943C9-52E8-44CF-9083-744D8049667B}
|
||||
{66C069F8-C548-4CA6-8CDE-239104D68E88} = {E11826E1-76DF-42AC-985C-164CC2EE57A1}
|
||||
{9605B84E-FAC4-477B-B9EC-0753177EE6A8} = {557C4636-D7E1-4838-A504-7D19B725EE95}
|
||||
{94CDC147-6137-45E9-AEDE-17FF809607C0} = {9605B84E-FAC4-477B-B9EC-0753177EE6A8}
|
||||
{A24BF1AF-79AA-4896-BAE3-CCBBE0380A78} = {9605B84E-FAC4-477B-B9EC-0753177EE6A8}
|
||||
{E816D7B1-4688-4ECB-97CC-3D8E798F3830} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{E816D7B3-4688-4ECB-97CC-3D8E798F3832} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{E816D7B2-4688-4ECB-97CC-3D8E798F3831} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
|
||||
387
README.md
@@ -1,253 +1,81 @@
|
||||
<p align="center">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: light)" srcset="./doc/images/readme/pt-hero.light.png" />
|
||||
<img src="./doc/images/readme/pt-hero.dark.png" />
|
||||
</picture>
|
||||
</p>
|
||||
<h1 align="center">
|
||||
<span>Microsoft PowerToys</span>
|
||||
</h1>
|
||||
# Microsoft PowerToys
|
||||
|
||||
<h3 align="center">
|
||||
<a href="#-installation">Installation</a>
|
||||
<span> · </span>
|
||||
<a href="https://aka.ms/powertoys-docs">Documentation</a>
|
||||
<span> · </span>
|
||||
<a href="https://aka.ms/powertoys-releaseblog">Blog</a>
|
||||
<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/>
|
||||

|
||||
|
||||
| | | |
|
||||
|---|---|---|
|
||||
| [<img src="doc/images/icons/AdvancedPaste.png" alt="Advanced Paste icon" height="16"> Advanced Paste](https://aka.ms/PowerToysOverview_AdvancedPaste) | [<img src="doc/images/icons/Always%20On%20Top.png" alt="Always on Top icon" height="16"> Always on Top](https://aka.ms/PowerToysOverview_AoT) | [<img src="doc/images/icons/Awake.png" alt="Awake icon" height="16"> Awake](https://aka.ms/PowerToysOverview_Awake) |
|
||||
| [<img src="doc/images/icons/Color%20Picker.png" alt="Color Picker icon" height="16"> Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) | [<img src="doc/images/icons/Command%20Not%20Found.png" alt="Command Not Found icon" height="16"> Command Not Found](https://aka.ms/PowerToysOverview_CmdNotFound) | [<img src="doc/images/icons/Command Palette.png" alt="Command Palette icon" height="16"> Command Palette](https://aka.ms/PowerToysOverview_CmdPal) |
|
||||
| [<img src="doc/images/icons/Crop%20And%20Lock.png" alt="Crop and Lock icon" height="16"> Crop And Lock](https://aka.ms/PowerToysOverview_CropAndLock) | [<img src="doc/images/icons/Environment%20Manager.png" alt="Environment Variables icon" height="16"> Environment Variables](https://aka.ms/PowerToysOverview_EnvironmentVariables) | [<img src="doc/images/icons/FancyZones.png" alt="FancyZones icon" height="16"> FancyZones](https://aka.ms/PowerToysOverview_FancyZones) |
|
||||
| [<img src="doc/images/icons/File%20Explorer%20Preview.png" alt="File Explorer Add-ons icon" height="16"> File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) | [<img src="doc/images/icons/File%20Locksmith.png" alt="File Locksmith icon" height="16"> File Locksmith](https://aka.ms/PowerToysOverview_FileLocksmith) | [<img src="doc/images/icons/Host%20File%20Editor.png" alt="Hosts File Editor icon" height="16"> Hosts File Editor](https://aka.ms/PowerToysOverview_HostsFileEditor) |
|
||||
| [<img src="doc/images/icons/Image%20Resizer.png" alt="Image Resizer icon" height="16"> Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [<img src="doc/images/icons/Keyboard%20Manager.png" alt="Keyboard Manager icon" height="16"> Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) | [<img src="doc/images/icons/Find My Mouse.png" alt="Mouse Utilities icon" height="16"> Mouse Utilities](https://aka.ms/PowerToysOverview_MouseUtilities) |
|
||||
| [<img src="doc/images/icons/MouseWithoutBorders.png" alt="Mouse Without Borders icon" height="16"> Mouse Without Borders](https://aka.ms/PowerToysOverview_MouseWithoutBorders) | [<img src="doc/images/icons/NewPlus.png" alt="New+ icon" height="16"> New+](https://aka.ms/PowerToysOverview_NewPlus) | [<img src="doc/images/icons/Peek.png" alt="Peek icon" height="16"> Peek](https://aka.ms/PowerToysOverview_Peek) |
|
||||
| [<img src="doc/images/icons/PowerRename.png" alt="PowerRename icon" height="16"> PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [<img src="doc/images/icons/PowerToys%20Run.png" alt="PowerToys Run icon" height="16"> PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) | [<img src="doc/images/icons/PowerAccent.png" alt="Quick Accent icon" height="16"> Quick Accent](https://aka.ms/PowerToysOverview_QuickAccent) |
|
||||
| [<img src="doc/images/icons/Registry%20Preview.png" alt="Registry Preview icon" height="16"> Registry Preview](https://aka.ms/PowerToysOverview_RegistryPreview) | [<img src="doc/images/icons/MeasureTool.png" alt="Screen Ruler icon" height="16"> Screen Ruler](https://aka.ms/PowerToysOverview_ScreenRuler) | [<img src="doc/images/icons/Shortcut%20Guide.png" alt="Shortcut Guide icon" height="16"> Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) |
|
||||
| [<img src="doc/images/icons/PowerOCR.png" alt="Text Extractor icon" height="16"> Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [<img src="doc/images/icons/Workspaces.png" alt="Workspaces icon" height="16"> Workspaces](https://aka.ms/PowerToysOverview_Workspaces) | [<img src="doc/images/icons/ZoomIt.png" alt="ZoomIt icon" height="16"> ZoomIt](https://aka.ms/PowerToysOverview_ZoomIt) |
|
||||
[How to use PowerToys][usingPowerToys-docs-link] | [Downloads & Release notes][github-release-link] | [Contributing to PowerToys](#contributing) | [What's Happening](#whats-happening) | [Roadmap](#powertoys-roadmap)
|
||||
|
||||
## About
|
||||
|
||||
## 📋 Installation
|
||||
Microsoft PowerToys is a set of utilities for power users to tune and streamline their Windows experience for greater productivity. For more info on [PowerToys overviews and how to use the utilities][usingPowerToys-docs-link], or any other tools and resources for [Windows development environments](https://learn.microsoft.com/windows/dev-environment/overview), head over to [learn.microsoft.com][usingPowerToys-docs-link]!
|
||||
|
||||
For detailed installation instructions, visit the [installation docs](https://learn.microsoft.com/windows/powertoys/install).
|
||||
| | Current utilities: | |
|
||||
|--------------|--------------------|--------------|
|
||||
| [Advanced Paste](https://aka.ms/PowerToysOverview_AdvancedPaste) | [Always on Top](https://aka.ms/PowerToysOverview_AoT) | [PowerToys Awake](https://aka.ms/PowerToysOverview_Awake) |
|
||||
| [Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) | [Command Not Found](https://aka.ms/PowerToysOverview_CmdNotFound) | [Command Palette](https://aka.ms/PowerToysOverview_CmdPal) |
|
||||
| [Crop And Lock](https://aka.ms/PowerToysOverview_CropAndLock) | [Environment Variables](https://aka.ms/PowerToysOverview_EnvironmentVariables) | [FancyZones](https://aka.ms/PowerToysOverview_FancyZones) |
|
||||
| [File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) | [File Locksmith](https://aka.ms/PowerToysOverview_FileLocksmith) | [Hosts File Editor](https://aka.ms/PowerToysOverview_HostsFileEditor) |
|
||||
| [Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) | [Mouse Utilities](https://aka.ms/PowerToysOverview_MouseUtilities) |
|
||||
| [Mouse Without Borders](https://aka.ms/PowerToysOverview_MouseWithoutBorders) | [New+](https://aka.ms/PowerToysOverview_NewPlus) | [Paste as Plain Text](https://aka.ms/PowerToysOverview_PastePlain) |
|
||||
| [Peek](https://aka.ms/PowerToysOverview_Peek) | [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) |
|
||||
| [Quick Accent](https://aka.ms/PowerToysOverview_QuickAccent) | [Registry Preview](https://aka.ms/PowerToysOverview_RegistryPreview) | [Screen Ruler](https://aka.ms/PowerToysOverview_ScreenRuler) |
|
||||
| [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) | [Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [Workspaces](https://aka.ms/PowerToysOverview_Workspaces) |
|
||||
| [ZoomIt](https://aka.ms/PowerToysOverview_ZoomIt) |
|
||||
|
||||
Before you begin, make sure your device meets the system requirements:
|
||||
## Installing and running Microsoft PowerToys
|
||||
|
||||
> [!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
|
||||
### Requirements
|
||||
|
||||
Choose one of the installation methods below:
|
||||
- Windows 11 or Windows 10 version 2004 (code name 20H1 / build number 19041) or newer.
|
||||
- x64 or ARM64 processor
|
||||
- Our installer will install the following items:
|
||||
- [Microsoft Edge WebView2 Runtime](https://go.microsoft.com/fwlink/p/?LinkId=2124703) bootstrapper. This will install the latest version.
|
||||
|
||||
<details>
|
||||
<summary>Download .exe from GitHub</summary>
|
||||
### Via GitHub with EXE [Recommended]
|
||||
|
||||
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.
|
||||
Go to the [Microsoft PowerToys GitHub releases page][github-release-link] and click on `Assets` at the bottom to show the files available in the release. Please use the appropriate PowerToys installer that matches your machine's architecture and install scope. For most, it is `x64` and per-user.
|
||||
|
||||
<!-- items that need to be updated release to release -->
|
||||
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.95%22
|
||||
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.94%22
|
||||
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.94.0/PowerToysUserSetup-0.94.0-x64.exe
|
||||
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.94.0/PowerToysUserSetup-0.94.0-arm64.exe
|
||||
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.94.0/PowerToysSetup-0.94.0-x64.exe
|
||||
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.94.0/PowerToysSetup-0.94.0-arm64.exe
|
||||
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.94%22
|
||||
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.93%22
|
||||
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.93.0/PowerToysUserSetup-0.93.0-x64.exe
|
||||
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.93.0/PowerToysUserSetup-0.93.0-arm64.exe
|
||||
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.93.0/PowerToysSetup-0.93.0-x64.exe
|
||||
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.93.0/PowerToysSetup-0.93.0-arm64.exe
|
||||
|
||||
| Description | Filename |
|
||||
|----------------|----------|
|
||||
| Per user - x64 | [PowerToysUserSetup-0.94.0-x64.exe][ptUserX64] |
|
||||
| Per user - ARM64 | [PowerToysUserSetup-0.94.0-arm64.exe][ptUserArm64] |
|
||||
| Machine wide - x64 | [PowerToysSetup-0.94.0-x64.exe][ptMachineX64] |
|
||||
| Machine wide - ARM64 | [PowerToysSetup-0.94.0-arm64.exe][ptMachineArm64] |
|
||||
| Per user - x64 | [PowerToysUserSetup-0.93.0-x64.exe][ptUserX64] |
|
||||
| Per user - ARM64 | [PowerToysUserSetup-0.93.0-arm64.exe][ptUserArm64] |
|
||||
| Machine wide - x64 | [PowerToysSetup-0.93.0-x64.exe][ptMachineX64] |
|
||||
| Machine wide - ARM64 | [PowerToysSetup-0.93.0-arm64.exe][ptMachineArm64] |
|
||||
|
||||
</details>
|
||||
This is our preferred method.
|
||||
|
||||
<details>
|
||||
<summary>Microsoft Store</summary>
|
||||
You can easily install PowerToys from the Microsoft Store:
|
||||
<p>
|
||||
<a style="text-decoration:none" href="https://aka.ms/getPowertoys">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: light)" srcset="doc/images/readme/StoreBadge-dark.png" width="148" />
|
||||
<img src="doc/images/readme/StoreBadge-light.png" width="148" />
|
||||
</picture></a>
|
||||
</p>
|
||||
</details>
|
||||
### Via Microsoft Store
|
||||
|
||||
Install from the [Microsoft Store's PowerToys page][microsoft-store-link]. You must be using the [new Microsoft Store](https://blogs.windows.com/windowsExperience/2021/06/24/building-a-new-open-microsoft-store-on-windows-11/), which is available for both Windows 11 and Windows 10.
|
||||
|
||||
<details>
|
||||
<summary>WinGet</summary>
|
||||
|
||||
### Via WinGet
|
||||
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]*
|
||||
#### User scope installer [default]
|
||||
```powershell
|
||||
winget install Microsoft.PowerToys -s winget
|
||||
```
|
||||
|
||||
*Machine-wide scope installer*
|
||||
#### Machine-wide scope installer
|
||||
|
||||
```powershell
|
||||
winget install --scope machine Microsoft.PowerToys -s winget
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Other methods</summary>
|
||||
### Other install methods
|
||||
|
||||
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>
|
||||
|
||||
## ✨ What's new
|
||||
**Version 0.94 (September 2025)**
|
||||
## Third-Party Run Plugins
|
||||
|
||||
For an in-depth look at the latest changes, visit the [Windows Command Line blog](https://aka.ms/powertoys-releaseblog).
|
||||
|
||||
**✨ Highlights**
|
||||
|
||||
- PowerToys Settings added a Settings search with fuzzy matching, suggestions, a results page, and UX polish to make finding options faster.
|
||||
- A comprehensive hotkey conflict detection system was introduced in Settings to surface and help resolve conflicting shortcuts. Note that the default hotkey settings (Win+Ctrl+Shift+T, Win+Ctrl+V, Win+Ctrl+T, Win+Shift+T) may overlap with existing Windows system shortcuts. This is expected. You can resolve the conflict by assigning different hotkeys.
|
||||
- Mouse Utilities added a “Gliding cursor” accessibility feature to Mouse Pointer Crosshairs for single‑button cursor movement and clicking. Thanks [@mikehall-ms](https://github.com/mikehall-ms)!
|
||||
- The installer was upgraded to WiX 5 after WiX 3 reached end-of-life; this move improved installer security, reliability, and community support.
|
||||
- Tons of bug fixes and improvements for Command Palette, including visual updates and new support for filters on ListPages (handy for extension developers).
|
||||
- Hosts Editor now has a “No leading spaces” option so active host entries can start at column 0 even if others are disabled. Thanks [@mohammed-saalim](https://github.com/mohammed-saalim)!
|
||||
- Context menu registration was moved from the installer to runtime to avoid loading disabled modules (runtime registrations).
|
||||
- Quick Accent now supports Maltese, and frequently used accents appear first (and are remembered across sessions). Thanks [@rovercoder](https://github.com/rovercoder)! [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
|
||||
### Always On Top
|
||||
|
||||
- Fixed the border hover cursor so it shows the arrow instead of the wait cursor. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
|
||||
### Command Palette
|
||||
|
||||
- Applied single-click activation only to pointer input; keyboard always activates immediately. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Let context menus open at the cursor by removing window-bound constraints. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Made error messages clearer with timestamps, HRESULTs, and full details for easier diagnosis. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Prevented crashes and improved robustness when updating providers without commands. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Ensured the Settings window reliably comes to the front when opened. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Replaced the Clipboard History icon with a colorful Fluent icon. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Hardened ContentIcon to avoid duplicate parenting and improve diagnostics. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Standardized null checks using C# pattern matching for safer behavior.
|
||||
- Improved accessibility by focusing the activation shortcut dialog and making text reachable. Thanks [@chatasweetie](https://github.com/chatasweetie)!
|
||||
- Moved the extension SDK to a stable Windows SDK and cleaned up message namespaces.
|
||||
- Added path shortcuts: ~ to home, and / or \\ to system root, plus UNC support. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Fixed a race in cancellation handling to avoid InvalidOperationException. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Aligned separator styling with WinUI 3 for consistent visuals. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Added ARM64 PDBs to the Extensions SDK NuGet for better debugging.
|
||||
- Added single-select filters to DynamicListPage and updated Windows Services sample.
|
||||
- Updated main page placeholder text to better describe what can be searched. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Removed explicit WinAppSDK/WebView2 dependencies from toolkit and API. Thanks [@rluengen](https://github.com/rluengen)!
|
||||
- Added a local keyboard hook to handle the GoBack key reliably. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Propagated alias changes safely and resolved conflicts across view models.
|
||||
- Allowed providers to override Dispose with a virtual method.
|
||||
- Fixed memory leaks by cleaning up removed or cancelled list items.
|
||||
- Sorted DateTime extension results by relevance for better usability.
|
||||
- Reduced search text "jiggling" by avoiding redundant change notifications.
|
||||
- Centralized automation notifications in a UIHelper for better accessibility. Thanks [@chatasweetie](https://github.com/chatasweetie)!
|
||||
- Preserved Adaptive Card action types during trimming via DynamicDependency.
|
||||
- Added an acrylic backdrop and refined styling to the context menu. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Prevented disposed pages and Settings windows from handling stale messages. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Made the extension API easier to evolve without breaking clients.
|
||||
- Added "evil" sample pages to help reproduce tricky bugs.
|
||||
- Fixed WinGet trim-safety issues by replacing LINQ with manual iteration.
|
||||
- Cancelled stale list fetches to avoid older results overwriting newer ones in CmdPal.
|
||||
|
||||
### Command Palette extensions
|
||||
|
||||
- Improved empty states and ranking logic for multiple extensions. Thanks [@htcfreek](https://github.com/htcfreek)!
|
||||
- Added app icons to the All Apps "Run" context command when available.
|
||||
- Restored missing builtin icons by standardizing extension dependencies.
|
||||
- Unblocked local deployment by adding WinAppSDK to two sample extensions.
|
||||
|
||||
### Hosts File Editor
|
||||
|
||||
- Added a "No leading spaces" option so active hosts entries can start at column 0 even when others are disabled. Thanks [@mohammed-saalim](https://github.com/mohammed-saalim)!
|
||||
|
||||
### Image Resizer
|
||||
|
||||
- Fixed Image Resizer localization by installing satellite resources under the WinUI 3 apps culture path.
|
||||
|
||||
### Mouse Utilities
|
||||
|
||||
- Introduced "Gliding cursor" to control the pointer and click with a single hotkey for better accessibility. Thanks [@mikehall-ms](https://github.com/mikehall-ms)!
|
||||
|
||||
### Mouse Without Borders
|
||||
|
||||
- Blocked Easy Mouse from switching machines during fullscreen apps, with an allow-list for exceptions. Thanks [@dot-tb](https://github.com/dot-tb)!
|
||||
|
||||
### Peek
|
||||
|
||||
- Added Visual Studio shared project file types to XML preview and fixed bgcode handler registration. Thanks [@rezanid](https://github.com/rezanid)!
|
||||
- Fixes bgcode preview handler registration and events for reliable previews. Thanks [@pedrolamas](https://github.com/pedrolamas)!
|
||||
|
||||
### PowerRename
|
||||
|
||||
- Changed the Explorer accelerator key to PowErRename to avoid clashing with the New menu. Thanks [@aaron-ni](https://github.com/aaron-ni)!
|
||||
|
||||
### Quick Accent
|
||||
|
||||
- Remembered character usage across sessions so frequently used accents appear first. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Added Maltese language support with specific characters and the Euro symbol. Thanks [@rovercoder](https://github.com/rovercoder)!
|
||||
- Reduced GPU usage issues by making the window Topmost only when the picker is visible. Thanks [@daverayment](https://github.com/daverayment)!
|
||||
|
||||
### Settings
|
||||
|
||||
- Added telemetry to track usage of the new shortcut conflict detection workflow.
|
||||
- Moved the shutdown action from the title bar to a footer menu item with confirmation. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Implemented comprehensive hotkey conflict detection with a dedicated resolution dialog.
|
||||
- Added branded visuals for Office and Copilot keys in the KeyVisual control.
|
||||
- Introduced Settings search with fuzzy matching and navigation to specific controls.
|
||||
- Corrected Spanish localization so product names like Awake remain in English across Settings and OOBE.
|
||||
- Simplified the Advanced Paste description in Settings for quicker reading and consistent capitalization. Thanks [@OldUser101](https://github.com/OldUser101)!
|
||||
- Localized conflict messages in the conflict window and dialog.
|
||||
|
||||
### Installer
|
||||
|
||||
- Upgraded the installer to WiX 5 with silent "Files in Use" handling for smoother winget installs.
|
||||
- Switched Win10 context menu modules to runtime registration and added cleanup on uninstall to avoid stale entries.
|
||||
|
||||
### Documentation
|
||||
|
||||
- Adds docs for building the installer locally and testing winget installs.
|
||||
- Fixed a broken style guide link in developer documentation. Thanks [@denizmaral](https://github.com/denizmaral)!
|
||||
|
||||
### Development
|
||||
|
||||
- Excluded test and coverage DLLs from BinSkim scans to cut false positives and speed up security analysis.
|
||||
- Simplified NOTICE maintenance by removing version numbers and filtering out Microsoft/System packages.
|
||||
- Improved NuGet dependency validation to prevent package downgrades and catch issues during restore.
|
||||
- Updated UTF.Unknown to a modern version to improve compatibility without breaking changes. Thanks [@304NotModified](https://github.com/304NotModified)!
|
||||
- Refreshed package catalog in CI before installing dependencies to prevent Linux workflow failures.
|
||||
- Refactored CmdPal tests with dependency injection and added coverage for queries and settings.
|
||||
- Added unit tests to verify Close on Enter swaps Copy/Save as expected. Thanks [@mohammed-saalim](https://github.com/mohammed-saalim)!
|
||||
- Added accessibility IDs to CmdPal UI for stable UI tests.
|
||||
- Rewrote system command tests with a new test base and cleaner patterns.
|
||||
- Added unit tests for WebSearch and Shell extensions with mockable settings.
|
||||
- Added unit tests and abstractions for Apps and Bookmarks extensions.
|
||||
- Cleans up AI-generated tests; adds meaningful query tests across extensions.
|
||||
- Removed the obsolete debug dialog from Settings for a smoother developer loop.
|
||||
|
||||
## 🛣️ Roadmap
|
||||
|
||||
For [v0.95][github-next-release-work], we'll work on the items below:
|
||||
|
||||
- Continued Command Palette polish
|
||||
- Working on Shortcut Guide v2 (Thanks [@noraa-junker](https://github.com/noraa-junker)!)
|
||||
- Upgrading Keyboard Manager's editor UI
|
||||
- UI tweaking utility with day/night theme switcher
|
||||
- DSC v3 support for top utilities
|
||||
- New UI automation tests
|
||||
- Stability, bug fixes
|
||||
|
||||
## ❤️ PowerToys Community
|
||||
|
||||
The PowerToys team is extremely grateful to have the [support of an amazing active community][community-link]. The work you do is incredibly important. PowerToys wouldn't be nearly what it is today without your help filing bugs, updating documentation, guiding the design, or writing features. We want to say thank you and take time to recognize your work. Your contributions and feedback improve PowerToys month after month!
|
||||
There is a collection of [third-party plugins](./doc/thirdPartyRunPlugins.md) created by the community that aren't distributed with PowerToys.
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -259,6 +87,131 @@ Most contributions require you to agree to a [Contributor License Agreement (CLA
|
||||
|
||||
For guidance on developing for PowerToys, please read the [developer docs](./doc/devdocs) for a detailed breakdown. This includes how to setup your computer to compile.
|
||||
|
||||
## What's Happening
|
||||
|
||||
### PowerToys Roadmap
|
||||
|
||||
Our [prioritized roadmap][roadmap] of features and utilities that the core team is focusing on.
|
||||
|
||||
### 0.93 - Aug 2025 Update
|
||||
|
||||
In this release, we focused on new features, stability, optimization improvements, and automation.
|
||||
|
||||
**✨Highlights**
|
||||
|
||||
- PowerToys settings debuts a modern, card-based dashboard with clearer descriptions and faster navigation for a streamlined user experience.
|
||||
- Command Palette had over 99 issues resolved, including bringing back Clipboard History, adding context menu shortcuts, pinning favorite apps, and supporting history in Run.
|
||||
- Command Palette reduced its startup memory usage by ~15%, load time by ~40%, built-in extensions loading time by ~70%, and installation size by ~55%—all due to using the full Ahead-of-Time (AOT) compilation mode in Windows App SDK.
|
||||
- Peek now supports instant previews and embedded thumbnails for Binary G-code (.bgcode) 3D printing files, making it easy to inspect models at a glance. Thanks [@pedrolamas](https://github.com/pedrolamas)!
|
||||
- Mouse Utilities introduces a new spotlight highlighting mode that dims the screen and draws attention to your cursor, perfect for presentations.
|
||||
- Test coverage improvements for multiple PowerToys modules including Command Palette, Advanced Paste, Peek, Text Extractor, and PowerRename — ensuring better reliability and quality, with over 600 new unit tests (mostly for Command Palette) and doubled UI automation coverage.
|
||||
|
||||
### Command Palette
|
||||
|
||||
- Ensured screen readers are notified when the selected item in the list changes for better accessibility.
|
||||
- Fixed command title changes not being properly notified to screen readers. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Made icon controls excluded from keyboard navigation by default for better accessibility. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Improved UI design with better text sizing and alignment.
|
||||
- Fixed keyboard shortcuts to work better in text boxes and context menus.
|
||||
- Added right-click context menus with critical command styling and separators.
|
||||
- Improved various context menu issues, improving item selection, handling of long titles, search bar text scaling, initial item behavior, and primary button functionality.
|
||||
- Fixed context menu crashes with better type handling.
|
||||
- Fixed "Reload" command to work with both uppercase and lowercase letters.
|
||||
- Added mouse back button support for easier navigation. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Fixed Alt+Left Arrow navigation not working when search box contains text. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Updated back button tooltip to show keyboard shortcut information. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Fixed Command Palette window not appearing properly when activated. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Fixed Command Palette window staying hidden from taskbar after File Explorer restarts. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Fixed window focus not returning to previous app properly.
|
||||
- Fixed Command Palette window to always appear on top when shown and move to bottom when hidden. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Fixed window hiding to properly work on UI thread. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Fixed crashes and improved stability with better synchronization of Command list updates. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Improved extension disposal with better error handling to prevent crashes. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Improved stability by fixing a UI threading issue when loading more results, preventing possible crashes and ensuring the loading state resets if loading fails. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Enhanced icon loading stability with better exception handling. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Added thread safety to recent commands to prevent crashes. Thanks [@MaoShengelia](https://github.com/MaoShengelia)!
|
||||
- Fixed acrylic (frosted glass) system backdrop display issues by ensuring proper UI thread handling. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
|
||||
### Command Palette extensions
|
||||
|
||||
- Added settings to each provider to control which fallback commands are enabled. Thanks [@jiripolasek](https://github.com/jiripolasek)! for fixing a regression in this feature.
|
||||
- Added sample code showing how Command Palette extensions can track when their pages are loaded or unloaded. [Check it out here](./src/modules/cmdpal/ext/SamplePagesExtension/OnLoadPage.cs).
|
||||
- Fixed *Calculator* to accept regular spaces in numbers that use space separators. Thanks [@PesBandi](https://github.com/PesBandi)!
|
||||
- Added a new setting to *Calculator* to make "Copy" the primary button (replacing “Save”) and enable "Close on Enter", streamlining the workflow. Thanks [@PesBandi](https://github.com/PesBandi)!
|
||||
- Improved *Apps* indexing error handling and removed obsolete code. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Prevented apps from showing in search when the *Apps* extension is disabled. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Added ability to pin/unpin *Apps* using Ctrl+P shortcut.
|
||||
- Added keyboard shortcuts to the *Apps* context menu items for faster access.
|
||||
- Added all file context menu options to the *Apps* items context menu, making all file actions available there for better functionality.
|
||||
- Streamlined All *Apps* extension settings by removing redundant descriptions, making the UI clearer.
|
||||
- Added command history to the *Run* page for easier access to previous commands.
|
||||
- Fixed directory path handling in *Run* fallback for better file navigation.
|
||||
- Fixed URL fallback item hiding properly in *Web Search* extension when search query becomes invalid. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Added proper empty state message for *Web Search* extension when no results found. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Added fallback command to *Windows Settings* extension for better search results.
|
||||
- Re-enabled *Clipboard History* feature with proper window handling.
|
||||
- Improved *Add Bookmark* extension to automatically detect file, folder, or URL types without manual input.
|
||||
- Updated terminology from "Kill process" to "End task" in *Window Walker* for consistency with Windows.
|
||||
- Fixed minor grammar error in SamplePagesExtension code comments. Thanks [@purofle](https://github.com/purofle)!
|
||||
|
||||
### Mouse Utilities
|
||||
|
||||
- Added a new spotlight highlighting mode that creates a large transparent circle around your cursor with a backdrop effect, providing an alternative to the traditional circle highlight. Perfect for presentations where you want to focus attention on a specific area while dimming the rest of the screen.
|
||||
|
||||
### Peek
|
||||
|
||||
- Added preview and thumbnail support for Binary G-code (.bgcode) files used in 3D printing. You can now see embedded thumbnails and preview these compressed 3D printing files directly in Peek and File Explorer. Thanks [@pedrolamas](https://github.com/pedrolamas)!
|
||||
|
||||
### Quick Accent
|
||||
|
||||
- Added Vietnamese language support to Quick Accent, mappings for Vietnamese vowels (a, e, i, o, u, y) and the letter d. Thanks [@octastylos-pseudodipteros](https://github.com/octastylos-pseudodipteros)!
|
||||
|
||||
### Settings
|
||||
|
||||
- Completely redesigned the Settings dashboard with a modern card-based layout featuring organized sections for quick actions and shortcuts overview, replacing the old module list.
|
||||
- Rewrote setting descriptions to be more concise and follow Windows writing style guidelines, making them easier to understand.
|
||||
- Improved formatting and readability of release notes in the "What's New" section with better typography and spacing.
|
||||
- Added missing deep link support for various settings pages (Peek, Quick Accent, PowerToys Run, etc.) so you can jump directly to specific settings.
|
||||
- Resolved an issue where the settings page header would drift away from its position when resizing the settings window.
|
||||
- Resolved a settings crash related to incompatible property names in ZoomIt configuration.
|
||||
|
||||
### Documentation
|
||||
|
||||
- Added detailed step-by-step instructions for first-time developers building the Command Palette module, including prerequisites and Visual Studio setup guidance. Thanks [@chatasweetie](https://github.com/chatasweetie)!
|
||||
- **Fixed Broken SDK Link**: Corrected a broken markdown link in the Command Palette SDK README that was pointing to an incorrect directory path. Thanks [@ChrisGuzak](https://github.com/ChrisGuzak)!
|
||||
- Added documentation for the "Open With Cursor" plugin that enables opening Visual Studio and VS Code recent files using Cursor AI. Thanks [@VictorNoxx](https://github.com/VictorNoxx)!
|
||||
- Added documentation for two new community plugins - Hotkeys plugin for creating custom keyboard shortcuts, and RandomGen plugin for generating random data like passwords, colors, and placeholder text. Thanks [@ruslanlap](https://github.com/ruslanlap)!
|
||||
|
||||
### Development
|
||||
|
||||
- Updated .NET libraries to 9.0.8 for performance and security. Thanks [@snickler](https://github.com/snickler)!
|
||||
- Updated the spell check system to version 0.0.25 with better GitHub integration and SARIF reporting, plus fixed numerous spelling errors throughout the codebase including property names and documentation. Thanks [@jsoref](https://github.com/jsoref)!
|
||||
- Cleaned up spelling check configuration to eliminate false positives and excessive noise that was appearing in every pull request, making the development process smoother.
|
||||
- Replaced NuGet feed with Azure Artifacts for better package management.
|
||||
- Implemented configurable UI test pipeline that can use pre-built official releases instead of building everything from scratch, reducing test execution time from 2+ hours.
|
||||
- Replaced brittle pixel-by-pixel image comparison with perceptual hash (pHash) technology that's more robust to minor rendering differences - no more test failures due to anti-aliasing or compression artifacts.
|
||||
- Reduced CI/fuzzing/UI test timeouts from 4 hours to 90 minutes, dramatically improving developer feedback loops and preventing long waits when builds get stuck.
|
||||
- Standardized test project naming across the entire codebase and improved pipeline result identification by adding platform/install mode context to test run titles. Thanks [@khmyznikov](https://github.com/khmyznikov)!
|
||||
- Added comprehensive UI test suites for multiple PowerToys modules including Command Palette, Advanced Paste, Peek, Text Extractor, and PowerRename - ensuring better reliability and quality.
|
||||
- Enhanced UI test automation with command-line argument support, better session management, and improved element location methods using pattern matching to avoid failures from minor differences in exact matches.
|
||||
|
||||
### What is being planned over the next few releases
|
||||
|
||||
For [v0.94][github-next-release-work], we'll work on the items below:
|
||||
|
||||
- Continued Command Palette polish
|
||||
- Working on Shortcut Guide v2 (Thanks [@noraa-junker](https://github.com/noraa-junker)!)
|
||||
- Working on upgrading the installer to WiX 5
|
||||
- Working on shortcut conflict detection
|
||||
- Working on setting search
|
||||
- Upgrading Keyboard Manager's editor UI
|
||||
- New UI automation tests
|
||||
- Stability, bug fixes
|
||||
|
||||
## PowerToys Community
|
||||
|
||||
The PowerToys team is extremely grateful to have the [support of an amazing active community][community-link]. The work you do is incredibly important. PowerToys wouldn’t be nearly what it is today without your help filing bugs, updating documentation, guiding the design, or writing features. We want to say thank you and take time to recognize your work. Month by month, you directly help make PowerToys a better piece of software.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct][oss-conduct-code].
|
||||
|
||||
@@ -18,8 +18,8 @@ You can build the entire solution from the command line, which is sometimes fast
|
||||
1. Open Developer Command Prompt for VS 2022
|
||||
2. Navigate to the repository root directory
|
||||
3. Run the following command(don't forget to set the correct platform):
|
||||
```pwsh
|
||||
msbuild -restore -p:RestorePackagesConfig=true -p:Platform=ARM64 -m PowerToys.sln /tl /p:NuGetInteractive="true"
|
||||
```
|
||||
msbuild -restore -p:RestorePackagesConfig=true -p:Platform=ARM64 -m PowerToys.sln
|
||||
```
|
||||
4. This process should complete in approximately 13-14 minutes for a full build
|
||||
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
## Developing PowerToys with Visual Studio Code
|
||||
|
||||
This guide shows how to build, debug, and contribute to PowerToys using VS Code instead of (or alongside) full Visual Studio. It focuses on common inner‑loop tasks for C++, .NET, and mixed scenarios present in the solution.
|
||||
|
||||
> PowerToys is a large mixed C++ / C# / WinAppSDK solution. VS Code works well for incremental development and quick module iterations, but occasionally you may still prefer full Visual Studio for designer tooling or specialized diagnostics.
|
||||
|
||||
---
|
||||
VS Code extensions Needed:
|
||||
|
||||
| Area | Extension | Notes |
|
||||
|------|-----------|-------|
|
||||
| C++ | ms-vscode.cpptools | IntelliSense, debugging (cppvsdbg) |
|
||||
| C# | ms-dotnettools.csdevkit (or C#) | Language service / test explorer |
|
||||
|
||||
---
|
||||
|
||||
## Building in VS Code
|
||||
### Configure developer powershell for vs2022 for more convenient dev in vscode.
|
||||
1. Configure profile in in settings, entry: "terminal.integrated.profiles.windows"
|
||||
2. Add below config as entry:
|
||||
```json
|
||||
"Developer PowerShell for VS 2022": {
|
||||
// Configure based on your preference
|
||||
"path": "C:\\Program Files\\WindowsApps\\Microsoft.PowerShell_7.5.2.0_arm64__8wekyb3d8bbwe\\pwsh.exe",
|
||||
"args": [
|
||||
"-NoExit",
|
||||
"-Command",
|
||||
"& {",
|
||||
"$orig = Get-Location;",
|
||||
// Configure based on your environment
|
||||
"& 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Common7\\Tools\\Launch-VsDevShell.ps1';",
|
||||
"Set-Location $orig",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
```
|
||||
3. [Optional] Set Developer PowerShell for VS 2022 as your default profile, so that you can get a deep integration with vscode coding agent.
|
||||
|
||||
4. Now You can build with plain `msbuild` or configure tasks.json in below section
|
||||
Or reach out to "tools\build\BUILD-GUIDELINES.md"
|
||||
|
||||
### Sample plain msbuild command
|
||||
```powershell
|
||||
# Restore:
|
||||
msbuild powertoys.sln -t:restore -p:configuration=debug -p:platform=x64 -m
|
||||
|
||||
# Build powertoys sln
|
||||
msbuild powertoys.sln -p:configuration=debug -p:platform=x64 -m
|
||||
|
||||
# dotnet project
|
||||
msbuild src\settings-ui\Settings.UI\PowerToys.Settings.csproj -p:Platform=x64 -p:Configuration=Debug -m
|
||||
|
||||
# native project
|
||||
msbuild "src\modules\MouseUtils\FindMyMouse\FindMyMouse.vcxproj" -p:Configuration=Debug -p:Platform=x64 -m
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Debugging
|
||||
|
||||
### Existing launch configuration
|
||||
|
||||
The repo provides `.vscode/launch.json` with:
|
||||
|
||||
- `Run PowerToys.exe (no build)`: Launches the already-built executable at `x64/Debug/PowerToys.exe` using `cppvsdbg`.
|
||||
|
||||
Build first, then press F5. To switch configuration (Release / ARM64) either edit the path or create additional launch entries.
|
||||
|
||||
### Attaching to a running instance
|
||||
|
||||
If PowerToys is already running, you can attach to that process:
|
||||
|
||||
2. VS Code command palette: “C/C++: (Windows) Attach to Process”.
|
||||
3. Filter for `PowerToys.exe` / module-specific processes.
|
||||
|
||||
### Debugging managed components
|
||||
|
||||
Many modules have a managed component loaded into the PowerToys process. `cppvsdbg` can debug mixed mode, but if you need richer .NET inspection you can create a second configuration using `type: coreclr` and `processId` attachment after the native launch, or just attach separately:
|
||||
|
||||
Similar for attach to managed code.
|
||||
> Note: In arm64 machine, can only debug arm64 code.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Run native executable (no build)",
|
||||
"type": "cppvsdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}\\x64\\Debug\\PowerToys.exe",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "C/C++ Attach to PowerToys Process (native)",
|
||||
"type": "cppvsdbg",
|
||||
"request": "attach",
|
||||
"processId": "${command:pickProcess}",
|
||||
"symbolSearchPath": "${workspaceFolder}\\x64\\Debug;${workspaceFolder}\\Debug;${workspaceFolder}\\symbols"
|
||||
},
|
||||
{
|
||||
"name": "Run managed code (managed, no build)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}\\arm64\\Debug\\WinUI3Apps\\PowerToys.Settings.exe",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"env": {},
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
---
|
||||
|
||||
## 6. Common tasks & tips
|
||||
|
||||
| Task | Command / Action | Notes |
|
||||
|------|------------------|-------|
|
||||
| Clean | `git clean -xdf` (careful) or `msbuild /t:Clean PowerToys.sln` | Deep clean removes packages & build outputs |
|
||||
| Rebuild single project | `msbuild path\to\proj.vcxproj /t:Rebuild -p:Platform=x64 -p:Configuration=Debug` | Faster than whole solution |
|
||||
| Generate installer (rare in inner loop) | See `tools\build\build-installer.ps1` | Usually not needed for local debug |
|
||||
| Resource conversion errors | Re-run restore + build | Triggers custom PowerShell targets |
|
||||
@@ -76,7 +76,6 @@ Once you've discussed your proposed feature/fix/etc. with a team member, and an
|
||||
1. Windows 10 April 2018 Update (version 1803) or newer
|
||||
1. Visual Studio Community/Professional/Enterprise 2022 17.4 or newer
|
||||
1. A local clone of the PowerToys repository
|
||||
1. Enable long paths in Windows (see [Enable Long Paths](https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation#enabling-long-paths-in-windows-10-version-1607-and-later) for details)
|
||||
|
||||
### Install Visual Studio dependencies
|
||||
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
# Settings resource
|
||||
Manage the settings for PowerToys modules
|
||||
|
||||
## Commands
|
||||
|
||||
### ✨ Modules
|
||||
List all the modules supported by the settings resource.
|
||||
```shell
|
||||
PS C:\> PowerToys.DSC.exe modules --resource 'settings'
|
||||
AdvancedPaste
|
||||
AlwaysOnTop
|
||||
App
|
||||
Awake
|
||||
ColorPicker
|
||||
CropAndLock
|
||||
EnvironmentVariables
|
||||
FancyZones
|
||||
FileLocksmith
|
||||
FindMyMouse
|
||||
Hosts
|
||||
ImageResizer
|
||||
KeyboardManager
|
||||
MeasureTool
|
||||
MouseHighlighter
|
||||
MouseJump
|
||||
MousePointerCrosshairs
|
||||
Peek
|
||||
PowerAccent
|
||||
PowerOCR
|
||||
PowerRename
|
||||
RegistryPreview
|
||||
ShortcutGuide
|
||||
Workspaces
|
||||
ZoomIt
|
||||
```
|
||||
|
||||
### 📄 Get
|
||||
Get the settings for a specific module.
|
||||
```shell
|
||||
PS C:\> PowerToys.DSC.exe get --resource 'settings' --module EnvironmentVariables
|
||||
{"settings":{"properties":{"LaunchAdministrator":{"value":true}},"name":"EnvironmentVariables","version":"1.0"}}
|
||||
```
|
||||
|
||||
### 🖨️ Export
|
||||
Export the settings for a specific module.
|
||||
|
||||
ℹ️ Settings resource Get and Export operation output states are identical.
|
||||
```shell
|
||||
PS C:\> PowerToys.DSC.exe get --resource 'settings' --module EnvironmentVariables
|
||||
{"settings":{"properties":{"LaunchAdministrator":{"value":true}},"name":"EnvironmentVariables","version":"1.0"}}
|
||||
```
|
||||
|
||||
### 📝 Set
|
||||
Set the settings for a specific module. This command will update the settings to the specified values.
|
||||
```shell
|
||||
PS C:\> PowerToys.DSC.exe set --resource 'settings' --module Awake --input '{"settings":{"properties":{"keepDisplayOn":false,"mode":0,"intervalHours":0,"intervalMinutes":1,"expirationDateTime":"2025-08-13T10:10:00.000001-07:00","customTrayTimes":{}},"name":"Awake","version":"0.0.1"}}'
|
||||
{"settings":{"properties":{"keepDisplayOn":false,"mode":0,"intervalHours":0,"intervalMinutes":1,"expirationDateTime":"2025-08-13T10:10:00.000001-07:00","customTrayTimes":{}},"name":"Awake","version":"0.0.1"}}
|
||||
["settings"]
|
||||
```
|
||||
|
||||
### 🧪 Test
|
||||
Test the settings for a specific module. This command will check if the current settings match the desired state.
|
||||
```shell
|
||||
PS C:\> PowerToys.DSC.exe test --resource 'settings' --module Awake --input '{"settings":{"properties":{"keepDisplayOn":false,"mode":0,"intervalHours":0,"intervalMinutes":1,"expirationDateTime":"2025-08-13T10:10:00.000002-07:00","customTrayTimes":{}},"name":"Awake","version":"0.0.1"}}'
|
||||
{"settings":{"properties":{"keepDisplayOn":false,"mode":0,"intervalHours":0,"intervalMinutes":1,"expirationDateTime":"2025-08-13T10:10:00.000001-07:00","customTrayTimes":{}},"name":"Awake","version":"0.0.1"},"_inDesiredState":false}
|
||||
["settings"]
|
||||
```
|
||||
|
||||
### 🛠️ Schema
|
||||
Generates the JSON schema for the settings resource of a specific module.
|
||||
```shell
|
||||
PS C:\> PowerToys.DSC.exe schema --resource 'settings' --module Awake
|
||||
{"$schema":"http://json-schema.org/draft-04/schema#","title":"SettingsResourceObjectOfAwakeSettings","type":"object","additionalProperties":false,"required":["settings"],"properties":{"_inDesiredState":{"type":["boolean","null"],"description":"Indicates whether an instance is in the desired state"},"settings":{"description":"The settings content for the module."}}}
|
||||
PS E:\src\powertoys> PowerToys.DSC.exe schema --resource 'settings' --module Awake | Format-Json
|
||||
```
|
||||
|
||||
### 📦 Manifest
|
||||
Generates a manifest dsc resource JSON file for the specified module.
|
||||
- If the module is not specified, it will generate a manifest for all modules.
|
||||
- If the output directory is not specified, it will print the manifest to the console.
|
||||
```shell
|
||||
PS C:\> PowerToys.DSC.exe manifest --resource settings --module 'Awake' --outputDir "C:\manifests"
|
||||
```
|
||||
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 13 KiB |
BIN
doc/images/overview/PT_hero_image.png
Normal file
|
After Width: | Height: | Size: 394 KiB |
BIN
doc/images/overview/PT_large.png
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
doc/images/overview/PT_small.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 464 KiB |
|
Before Width: | Height: | Size: 502 KiB |
@@ -73,5 +73,4 @@ Below are community created plugins that target a website or software. They are
|
||||
| [YubicoOauthOTP](https://github.com/dlnilsson/Community.PowerToys.Run.Plugin.YubicoOauthOTP) | [dlnilsson](https://github.com/dlnilsson) | Display generated codes from OATH accounts stored on the YubiKey in powerToys Run |
|
||||
| [Firefox Bookmark](https://github.com/8LWXpg/PowerToysRun-FirefoxBookmark) | [8LWXpg](https://github.com/8LWXpg) | Open bookmarks in Firefox based browser |
|
||||
| [Linear](https://github.com/vednig/powertoys-linear) | [vednig](https://github.com/vednig) | Create Linear Issues directly from Powertoys Run |
|
||||
| [PerplexitySearchShortcut](https://github.com/0x6f677548/PowerToys-Run-PerplexitySearchShortcut) | [0x6f677548](https://github.com/0x6f677548) | Search Perplexity |
|
||||
| [SpeedTest](https://github.com/ruslanlap/PowerToysRun-SpeedTest) | [ruslanlap](https://github.com/ruslanlap) | One-command internet speed tests with real-time results, modern UI, and shareable links. |
|
||||
|
||||
@@ -9,6 +9,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>
|
||||
|
||||
@@ -26,14 +33,41 @@
|
||||
</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" Win64="yes" Guid="C2790FC4-0665-4462-947A-D942A2AABFF0">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="Module_CmdPal_Deps" Value="" KeyPath="yes"/>
|
||||
</RegistryKey>
|
||||
<File Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_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" Win64="yes" Guid="C2790FC4-0665-4462-947A-D942A2AABFF0">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="Module_CmdPal_Deps" Value="" KeyPath="yes"/>
|
||||
</RegistryKey>
|
||||
<File Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_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>
|
||||
|
||||
@@ -16,7 +16,6 @@ SET PTRoot=$(SolutionDir)\..
|
||||
call "..\..\..\publish.cmd" x64
|
||||
)
|
||||
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateMonacoWxs.ps1 -monacoWxsFile "$(MSBuildThisFileDirectory)\MonacoSRC.wxs"
|
||||
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateDscResourcesWxs.ps1 -dscWxsFile "$(MSBuildThisFileDirectory)\DscResources.wxs" -Platform "$(Platform)" -Configuration "$(Configuration)"
|
||||
</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Platform)' != 'x64'">
|
||||
@@ -27,7 +26,6 @@ SET PTRoot=$(SolutionDir)\..
|
||||
call "..\..\..\publish.cmd" arm64
|
||||
)
|
||||
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateMonacoWxs.ps1 -monacoWxsFile "$(MSBuildThisFileDirectory)\MonacoSRC.wxs"
|
||||
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateDscResourcesWxs.ps1 -dscWxsFile "$(MSBuildThisFileDirectory)\DscResources.wxs" -Platform "$(Platform)" -Configuration "$(Configuration)"
|
||||
</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
@@ -123,7 +121,6 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
|
||||
<Compile Include="Hosts.wxs" />
|
||||
<Compile Include="ImageResizer.wxs" />
|
||||
<Compile Include="KeyboardManager.wxs" />
|
||||
<Compile Include="DscResources.wxs" />
|
||||
<Compile Include="Peek.wxs" />
|
||||
<Compile Include="PowerRename.wxs" />
|
||||
<Compile Include="RegistryPreview.wxs" />
|
||||
|
||||
@@ -75,7 +75,6 @@
|
||||
<ComponentGroupRef Id="NewPlusComponentGroup" />
|
||||
<ComponentGroupRef Id="NewPlusTemplatesComponentGroup" />
|
||||
<ComponentGroupRef Id="ResourcesComponentGroup" />
|
||||
<ComponentGroupRef Id="DscResourcesComponentGroup" />
|
||||
<ComponentGroupRef Id="WindowsAppSDKComponentGroup" />
|
||||
<ComponentGroupRef Id="ToolComponentGroup" />
|
||||
<ComponentGroupRef Id="MonacoSRCHeatGenerated" />
|
||||
@@ -325,6 +324,7 @@
|
||||
BinaryKey="PTCustomActions"
|
||||
DllEntry="UninstallDSCModuleCA"
|
||||
/>
|
||||
|
||||
<CustomAction Id="UninstallServicesTask"
|
||||
Return="ignore"
|
||||
Impersonate="yes"
|
||||
|
||||
@@ -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'"
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "RcResource.h"
|
||||
#include <ProjectTelemetry.h>
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <filesystem>
|
||||
|
||||
#include "../../src/common/logger/logger.h"
|
||||
#include "../../src/common/utils/gpo.h"
|
||||
@@ -233,9 +232,7 @@ UINT __stdcall LaunchPowerToysCA(MSIHANDLE hInstall)
|
||||
|
||||
auto action = [&commandLine](HANDLE userToken)
|
||||
{
|
||||
STARTUPINFO startupInfo = { 0 };
|
||||
startupInfo.cb = sizeof(STARTUPINFO);
|
||||
startupInfo.wShowWindow = SW_SHOWNORMAL;
|
||||
STARTUPINFO startupInfo{.cb = sizeof(STARTUPINFO), .wShowWindow = SW_SHOWNORMAL};
|
||||
PROCESS_INFORMATION processInformation;
|
||||
|
||||
PVOID lpEnvironment = NULL;
|
||||
@@ -274,9 +271,7 @@ UINT __stdcall LaunchPowerToysCA(MSIHANDLE hInstall)
|
||||
}
|
||||
else
|
||||
{
|
||||
STARTUPINFO startupInfo = { 0 };
|
||||
startupInfo.cb = sizeof(STARTUPINFO);
|
||||
startupInfo.wShowWindow = SW_SHOWNORMAL;
|
||||
STARTUPINFO startupInfo{.cb = sizeof(STARTUPINFO), .wShowWindow = SW_SHOWNORMAL};
|
||||
|
||||
PROCESS_INFORMATION processInformation;
|
||||
|
||||
@@ -429,7 +424,7 @@ UINT __stdcall InstallDSCModuleCA(MSIHANDLE hInstall)
|
||||
const auto modulesPath = baseModulesPath / L"Microsoft.PowerToys.Configure" / (get_product_version(false) + L".0");
|
||||
|
||||
std::error_code errorCode;
|
||||
std::filesystem::create_directories(modulesPath, errorCode);
|
||||
fs::create_directories(modulesPath, errorCode);
|
||||
if (errorCode)
|
||||
{
|
||||
hr = E_FAIL;
|
||||
@@ -438,7 +433,7 @@ UINT __stdcall InstallDSCModuleCA(MSIHANDLE hInstall)
|
||||
|
||||
for (const auto *filename : {DSC_CONFIGURE_PSD1_NAME, DSC_CONFIGURE_PSM1_NAME})
|
||||
{
|
||||
std::filesystem::copy_file(std::filesystem::path(installationFolder) / "DSCModules" / filename, modulesPath / filename, std::filesystem::copy_options::overwrite_existing, errorCode);
|
||||
fs::copy_file(fs::path(installationFolder) / "DSCModules" / filename, modulesPath / filename, fs::copy_options::overwrite_existing, errorCode);
|
||||
|
||||
if (errorCode)
|
||||
{
|
||||
@@ -486,7 +481,7 @@ UINT __stdcall UninstallDSCModuleCA(MSIHANDLE hInstall)
|
||||
|
||||
for (const auto *filename : {DSC_CONFIGURE_PSD1_NAME, DSC_CONFIGURE_PSM1_NAME})
|
||||
{
|
||||
std::filesystem::remove(versionedModulePath / filename, errorCode);
|
||||
fs::remove(versionedModulePath / filename, errorCode);
|
||||
|
||||
if (errorCode)
|
||||
{
|
||||
@@ -497,7 +492,7 @@ UINT __stdcall UninstallDSCModuleCA(MSIHANDLE hInstall)
|
||||
|
||||
for (const auto *modulePath : {&versionedModulePath, &powerToysModulePath})
|
||||
{
|
||||
std::filesystem::remove(*modulePath, errorCode);
|
||||
fs::remove(*modulePath, errorCode);
|
||||
|
||||
if (errorCode)
|
||||
{
|
||||
@@ -1380,120 +1375,6 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall SetBundleInstallLocationCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
|
||||
// Declare all variables at the beginning to avoid goto issues
|
||||
std::wstring customActionData;
|
||||
std::wstring installationFolder;
|
||||
std::wstring bundleUpgradeCode;
|
||||
std::wstring installScope;
|
||||
bool isPerUser = false;
|
||||
size_t pos1 = std::wstring::npos;
|
||||
size_t pos2 = std::wstring::npos;
|
||||
std::vector<HKEY> keysToTry;
|
||||
|
||||
hr = WcaInitialize(hInstall, "SetBundleInstallLocationCA");
|
||||
ExitOnFailure(hr, "Failed to initialize");
|
||||
|
||||
// Parse CustomActionData: "installFolder;upgradeCode;installScope"
|
||||
hr = getInstallFolder(hInstall, customActionData);
|
||||
ExitOnFailure(hr, "Failed to get CustomActionData.");
|
||||
|
||||
pos1 = customActionData.find(L';');
|
||||
if (pos1 == std::wstring::npos)
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
ExitOnFailure(hr, "Invalid CustomActionData format - missing first semicolon");
|
||||
}
|
||||
|
||||
pos2 = customActionData.find(L';', pos1 + 1);
|
||||
if (pos2 == std::wstring::npos)
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
ExitOnFailure(hr, "Invalid CustomActionData format - missing second semicolon");
|
||||
}
|
||||
|
||||
installationFolder = customActionData.substr(0, pos1);
|
||||
bundleUpgradeCode = customActionData.substr(pos1 + 1, pos2 - pos1 - 1);
|
||||
installScope = customActionData.substr(pos2 + 1);
|
||||
|
||||
isPerUser = (installScope == L"perUser");
|
||||
|
||||
// Use the appropriate registry based on install scope
|
||||
HKEY targetKey = isPerUser ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
|
||||
const wchar_t* keyName = isPerUser ? L"HKCU" : L"HKLM";
|
||||
|
||||
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: Searching for Bundle in %ls registry", keyName);
|
||||
|
||||
HKEY uninstallKey;
|
||||
LONG openResult = RegOpenKeyExW(targetKey, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall", 0, KEY_READ | KEY_ENUMERATE_SUB_KEYS, &uninstallKey);
|
||||
if (openResult != ERROR_SUCCESS)
|
||||
{
|
||||
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: Failed to open uninstall key, error: %ld", openResult);
|
||||
goto LExit;
|
||||
}
|
||||
|
||||
DWORD index = 0;
|
||||
wchar_t subKeyName[256];
|
||||
DWORD subKeyNameSize = sizeof(subKeyName) / sizeof(wchar_t);
|
||||
|
||||
while (RegEnumKeyExW(uninstallKey, index, subKeyName, &subKeyNameSize, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS)
|
||||
{
|
||||
HKEY productKey;
|
||||
if (RegOpenKeyExW(uninstallKey, subKeyName, 0, KEY_READ | KEY_WRITE, &productKey) == ERROR_SUCCESS)
|
||||
{
|
||||
wchar_t upgradeCode[256];
|
||||
DWORD upgradeCodeSize = sizeof(upgradeCode);
|
||||
DWORD valueType;
|
||||
|
||||
if (RegQueryValueExW(productKey, L"BundleUpgradeCode", nullptr, &valueType,
|
||||
reinterpret_cast<LPBYTE>(upgradeCode), &upgradeCodeSize) == ERROR_SUCCESS)
|
||||
{
|
||||
// Remove brackets from registry upgradeCode for comparison (bundleUpgradeCode doesn't have brackets)
|
||||
std::wstring regUpgradeCode = upgradeCode;
|
||||
if (!regUpgradeCode.empty() && regUpgradeCode.front() == L'{' && regUpgradeCode.back() == L'}')
|
||||
{
|
||||
regUpgradeCode = regUpgradeCode.substr(1, regUpgradeCode.length() - 2);
|
||||
}
|
||||
|
||||
if (_wcsicmp(regUpgradeCode.c_str(), bundleUpgradeCode.c_str()) == 0)
|
||||
{
|
||||
// Found matching Bundle, set InstallLocation
|
||||
LONG setResult = RegSetValueExW(productKey, L"InstallLocation", 0, REG_SZ,
|
||||
reinterpret_cast<const BYTE*>(installationFolder.c_str()),
|
||||
static_cast<DWORD>((installationFolder.length() + 1) * sizeof(wchar_t)));
|
||||
|
||||
if (setResult == ERROR_SUCCESS)
|
||||
{
|
||||
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: InstallLocation set successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: Failed to set InstallLocation, error: %ld", setResult);
|
||||
}
|
||||
|
||||
RegCloseKey(productKey);
|
||||
RegCloseKey(uninstallKey);
|
||||
goto LExit;
|
||||
}
|
||||
}
|
||||
RegCloseKey(productKey);
|
||||
}
|
||||
|
||||
index++;
|
||||
subKeyNameSize = sizeof(subKeyName) / sizeof(wchar_t);
|
||||
}
|
||||
|
||||
RegCloseKey(uninstallKey);
|
||||
|
||||
LExit:
|
||||
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
void initSystemLogger()
|
||||
{
|
||||
static std::once_flag initLoggerFlag;
|
||||
|
||||
@@ -32,4 +32,4 @@ EXPORTS
|
||||
CleanFileLocksmithRuntimeRegistryCA
|
||||
CleanPowerRenameRuntimeRegistryCA
|
||||
CleanNewPlusRuntimeRegistryCA
|
||||
SetBundleInstallLocationCA
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -9,25 +9,6 @@
|
||||
<RegistryValue Type="string" Name="InstallScope" Value="$(var.InstallScope)" />
|
||||
</RegistryKey>
|
||||
</Component>
|
||||
<?if $(var.PerUser) = "true" ?>
|
||||
<Component Id="powertoys_env_path_user" Bitness="always64">
|
||||
<!-- Anchor registry for component key path -->
|
||||
<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]" />
|
||||
</Component>
|
||||
<?else?>
|
||||
<Component Id="powertoys_env_path_machine" Bitness="always64">
|
||||
<!-- Anchor registry for component key path -->
|
||||
<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]" />
|
||||
</Component>
|
||||
<?endif?>
|
||||
<Component Id="powertoys_toast_clsid" Bitness="always64">
|
||||
<RemoveFolder Id="Remove_powertoys_toast_clsid" On="uninstall" />
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\CLSID\{DD5CACDA-7C2E-4997-A62A-04A597B58F76}">
|
||||
@@ -128,11 +109,6 @@
|
||||
<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" />
|
||||
|
||||
@@ -28,9 +28,6 @@
|
||||
|
||||
<Log Disable="no" Prefix="powertoys-bootstrapper-msi-$(var.Version)" Extension=".log" />
|
||||
|
||||
<!-- Store Bundle UpgradeCode for CustomAction -->
|
||||
<Variable Name="BundleUpgradeCode" Type="string" Value="$(var.UpgradeCode)" />
|
||||
|
||||
<!-- Only install/upgrade if the version is greater or equal than the currently installed version of PowerToys, to handle the case in which PowerToys was installed from old MSI (before WiX bootstrapper was used) -->
|
||||
<!-- If the previous installation is a bundle installation, just let WiX run its logic. -->
|
||||
<Variable Name="MinimumVersion" Type="version" Value="0.0.0.0" />
|
||||
@@ -61,7 +58,6 @@
|
||||
<MsiPackage DisplayName="PowerToys MSI" SourceFile="$(var.PowerToysPlatform)\Release\$(var.MSIPath)\$(var.MSIName)" Compressed="yes" bal:DisplayInternalUICondition="false">
|
||||
<MsiProperty Name="BOOTSTRAPPERINSTALLFOLDER" Value="[InstallFolder]" />
|
||||
<MsiProperty Name="MSIRESTARTMANAGERCONTROL" Value="Disable" />
|
||||
<MsiProperty Name="BUNDLEINFO" Value="[BundleUpgradeCode]" />
|
||||
</MsiPackage>
|
||||
</Chain>
|
||||
</Bundle>
|
||||
|
||||
@@ -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>
|
||||
@@ -117,7 +115,6 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
|
||||
<Compile Include="KeyboardManager.wxs" />
|
||||
<Compile Include="Peek.wxs" />
|
||||
<Compile Include="PowerRename.wxs" />
|
||||
<Compile Include="DscResources.wxs" />
|
||||
<Compile Include="RegistryPreview.wxs" />
|
||||
<Compile Include="Run.wxs" />
|
||||
<Compile Include="Settings.wxs" />
|
||||
|
||||
@@ -62,7 +62,6 @@
|
||||
<ComponentGroupRef Id="NewPlusComponentGroup" />
|
||||
<ComponentGroupRef Id="NewPlusTemplatesComponentGroup" />
|
||||
<ComponentGroupRef Id="ResourcesComponentGroup" />
|
||||
<ComponentGroupRef Id="DscResourcesComponentGroup" />
|
||||
<ComponentGroupRef Id="WindowsAppSDKComponentGroup" />
|
||||
<ComponentGroupRef Id="ToolComponentGroup" />
|
||||
<ComponentGroupRef Id="MonacoSRCHeatGenerated" />
|
||||
@@ -70,8 +69,8 @@
|
||||
<ComponentGroupRef Id="CmdPalComponentGroup" />
|
||||
</Feature>
|
||||
|
||||
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLFOLDER]" After="CostFinalize" Sequence="execute" />
|
||||
|
||||
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLFOLDER]" After="CostFinalize" />
|
||||
|
||||
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" />
|
||||
|
||||
<UI>
|
||||
@@ -118,8 +117,6 @@
|
||||
|
||||
<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="ApplyModulesRegistryChangeSets" After="InstallFiles" Condition="NOT Installed" />
|
||||
<Custom Action="InstallCmdPalPackage" After="InstallFiles" Condition="NOT Installed" />
|
||||
<Custom Action="override Wix4CloseApplications_$(sys.BUILDARCHSHORT)" Before="RemoveFiles" />
|
||||
@@ -163,9 +160,6 @@
|
||||
|
||||
<CustomAction Id="SetInstallCmdPalPackageParam" Property="InstallCmdPalPackage" Value="[INSTALLFOLDER]" />
|
||||
|
||||
<!-- Set InstallLocation for Bundle entry as well -->
|
||||
<CustomAction Id="SetBundleInstallLocationData" Property="SetBundleInstallLocation" Value="[INSTALLFOLDER];[BUNDLEINFO];[InstallScope]" />
|
||||
|
||||
<CustomAction Id="LaunchPowerToys" Return="ignore" Impersonate="yes" Execute="deferred" DllEntry="LaunchPowerToysCA" BinaryRef="PTCustomActions" />
|
||||
|
||||
<CustomAction Id="TerminateProcesses" Return="ignore" Execute="immediate" DllEntry="TerminateProcessesCA" BinaryRef="PTCustomActions" />
|
||||
@@ -250,8 +244,6 @@
|
||||
|
||||
<CustomAction Id="InstallCmdPalPackage" Return="ignore" Impersonate="yes" Execute="deferred" DllEntry="InstallCmdPalPackageCA" BinaryRef="PTCustomActions" />
|
||||
|
||||
<CustomAction Id="SetBundleInstallLocation" Return="ignore" Impersonate="no" Execute="deferred" DllEntry="SetBundleInstallLocationCA" BinaryRef="PTCustomActions" />
|
||||
|
||||
<!-- Close 'PowerToys.exe' before uninstall-->
|
||||
<Property Id="MSIRESTARTMANAGERCONTROL" Value="DisableShutdown" />
|
||||
<Property Id="MSIFASTINSTALL" Value="DisableShutdown" />
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<TargetName>SilentFilesInUseBAFunction</TargetName>
|
||||
<ProjectName>PowerToysSetupCustomActionsVNext</ProjectName>
|
||||
<ProjectModuleDefinitionFile>bafunctions.def</ProjectModuleDefinitionFile>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
@@ -92,31 +91,5 @@
|
||||
</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>
|
||||
|
||||
@@ -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'"
|
||||
@@ -9,4 +9,4 @@
|
||||
<package pattern="*" />
|
||||
</packageSource>
|
||||
</packageSourceMapping>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
||||
@@ -19,9 +19,7 @@ namespace ManagedCommon
|
||||
private static readonly string Error = "Error";
|
||||
private static readonly string Warning = "Warning";
|
||||
private static readonly string Info = "Info";
|
||||
#if DEBUG
|
||||
private static readonly string Debug = "Debug";
|
||||
#endif
|
||||
private static readonly string TraceFlag = "Trace";
|
||||
|
||||
private static readonly string Version = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyFileVersionAttribute>()?.Version ?? "Unknown";
|
||||
@@ -124,13 +122,13 @@ namespace ManagedCommon
|
||||
{
|
||||
var exMessage =
|
||||
message + Environment.NewLine +
|
||||
ex.GetType() + " (" + ex.HResult + "): " + ex.Message + Environment.NewLine;
|
||||
ex.GetType() + ": " + ex.Message + Environment.NewLine;
|
||||
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
exMessage +=
|
||||
"Inner exception: " + Environment.NewLine +
|
||||
ex.InnerException.GetType() + " (" + ex.HResult + "): " + ex.InnerException.Message + Environment.NewLine;
|
||||
ex.InnerException.GetType() + ": " + ex.InnerException.Message + Environment.NewLine;
|
||||
}
|
||||
|
||||
exMessage +=
|
||||
@@ -153,9 +151,7 @@ namespace ManagedCommon
|
||||
|
||||
public static void LogDebug(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
|
||||
{
|
||||
#if DEBUG
|
||||
Log(message, Debug, memberName, sourceFilePath, sourceLineNumber);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void LogTrace([System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
|
||||
|
||||
@@ -33,7 +33,6 @@ namespace Microsoft.PowerToys.UITest
|
||||
Workspaces,
|
||||
PowerRename,
|
||||
CommandPalette,
|
||||
ScreenRuler,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -105,7 +104,6 @@ namespace Microsoft.PowerToys.UITest
|
||||
[PowerToysModule.Workspaces] = new ModuleInfo("PowerToys.WorkspacesEditor.exe", "Workspaces Editor"),
|
||||
[PowerToysModule.PowerRename] = new ModuleInfo("PowerToys.PowerRename.exe", "PowerRename", "WinUI3Apps"),
|
||||
[PowerToysModule.CommandPalette] = new ModuleInfo("Microsoft.CmdPal.UI.exe", "PowerToys Command Palette", "WinUI3Apps\\CmdPal"),
|
||||
[PowerToysModule.ScreenRuler] = new ModuleInfo("PowerToys.MeasureToolUI.exe", "PowerToys.ScreenRuler", "WinUI3Apps"),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
<PackageReference Include="Appium.WebDriver" />
|
||||
<PackageReference Include="MSTest" />
|
||||
<PackageReference Include="System.IO.Abstractions" />
|
||||
<PackageReference Include="System.Net.Http" />
|
||||
<PackageReference Include="System.Private.Uri" />
|
||||
<PackageReference Include="System.Text.RegularExpressions" />
|
||||
<PackageReference Include="CoenM.ImageSharp.ImageHash" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
@@ -95,7 +94,6 @@ namespace Microsoft.PowerToys.UITest
|
||||
{
|
||||
Task.Delay(1000).Wait();
|
||||
AddScreenShotsToTestResultsDirectory();
|
||||
AddLogFilesToTestResultsDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -600,92 +598,6 @@ namespace Microsoft.PowerToys.UITest
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies PowerToys log files to test results directory when test fails.
|
||||
/// Renames files to include the directory structure after \PowerToys.
|
||||
/// </summary>
|
||||
protected void AddLogFilesToTestResultsDirectory()
|
||||
{
|
||||
try
|
||||
{
|
||||
var localAppDataLow = Path.Combine(
|
||||
Environment.GetEnvironmentVariable("USERPROFILE") ?? string.Empty,
|
||||
"AppData",
|
||||
"LocalLow",
|
||||
"Microsoft",
|
||||
"PowerToys");
|
||||
|
||||
if (Directory.Exists(localAppDataLow))
|
||||
{
|
||||
CopyLogFilesFromDirectory(localAppDataLow, string.Empty);
|
||||
}
|
||||
|
||||
var localAppData = Path.Combine(
|
||||
Environment.GetEnvironmentVariable("LOCALAPPDATA") ?? string.Empty,
|
||||
"Microsoft",
|
||||
"PowerToys");
|
||||
|
||||
if (Directory.Exists(localAppData))
|
||||
{
|
||||
CopyLogFilesFromDirectory(localAppData, string.Empty);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Don't fail the test if log file copying fails
|
||||
Console.WriteLine($"Failed to copy log files: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recursively copies log files from a directory and renames them with directory structure.
|
||||
/// </summary>
|
||||
/// <param name="sourceDir">Source directory to copy from</param>
|
||||
/// <param name="relativePath">Relative path from PowerToys folder</param>
|
||||
private void CopyLogFilesFromDirectory(string sourceDir, string relativePath)
|
||||
{
|
||||
if (!Directory.Exists(sourceDir))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Process log files in current directory
|
||||
var logFiles = Directory.GetFiles(sourceDir, "*.log");
|
||||
foreach (var logFile in logFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
var fileName = Path.GetFileName(logFile);
|
||||
var fileNameWithoutExt = Path.GetFileNameWithoutExtension(fileName);
|
||||
var extension = Path.GetExtension(fileName);
|
||||
|
||||
// Create new filename with directory structure
|
||||
var directoryPart = string.IsNullOrEmpty(relativePath) ? string.Empty : relativePath.Replace("\\", "-") + "-";
|
||||
var newFileName = $"{directoryPart}{fileNameWithoutExt}{extension}";
|
||||
|
||||
// Copy file to test results directory with new name
|
||||
var testResultsDir = TestContext.TestResultsDirectory ?? Path.GetTempPath();
|
||||
var destinationPath = Path.Combine(testResultsDir, newFileName);
|
||||
|
||||
File.Copy(logFile, destinationPath, true);
|
||||
TestContext.AddResultFile(destinationPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to copy log file {logFile}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively process subdirectories
|
||||
var subdirectories = Directory.GetDirectories(sourceDir);
|
||||
foreach (var subdir in subdirectories)
|
||||
{
|
||||
var dirName = Path.GetFileName(subdir);
|
||||
var newRelativePath = string.IsNullOrEmpty(relativePath) ? dirName : Path.Combine(relativePath, dirName);
|
||||
CopyLogFilesFromDirectory(subdir, newRelativePath);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restart scope exe.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
---
|
||||
applyTo: "**/*.cs,**/*.cpp,**/*.c,**/*.h,**/*.hpp"
|
||||
---
|
||||
# Common – shared libraries guidance (concise)
|
||||
|
||||
Scope
|
||||
- Logging, IPC, settings, DPI, telemetry, utilities consumed by multiple modules.
|
||||
|
||||
Guidelines
|
||||
- Avoid breaking public headers/APIs; if changed, search & update all callers.
|
||||
- Coordinate ABI-impacting struct/class layout changes; keep binary compatibility.
|
||||
- Watch perf in hot paths (hooks, timers, serialization); avoid avoidable allocations.
|
||||
- Ask before adding third‑party deps or changing serialization formats.
|
||||
|
||||
Acceptance
|
||||
- No unintended ABI breaks, no noisy logs, new non-obvious symbols briefly commented.
|
||||
@@ -31,11 +31,11 @@
|
||||
<!-- The following sections assume that the machine we're building on is always x64. That means we won't be able to run/inspect arm64 executables, therefore we must always execute x64 generator. -->
|
||||
|
||||
<Target Name="PostBuildAction" AfterTargets="Build" Outputs="$(GeneratedDSCModule)" Condition="'$(Platform)'!='ARM64'">
|
||||
<Exec Command=""$(OutDir)$(AssemblyName).exe" "..\..\..\x64\$(Configuration)\WinUI3Apps\PowerToys.Settings.UI.Lib.dll" $(GeneratedDSCModule) $(GeneratedDSCManifest)" />
|
||||
<Exec Command=""$(OutDir)$(AssemblyName).exe" "$(SolutionDir)x64\$(Configuration)\WinUI3Apps\PowerToys.Settings.UI.Lib.dll" $(GeneratedDSCModule) $(GeneratedDSCManifest)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PreBuild" BeforeTargets="PreBuildEvent" Condition="'$(Platform)'=='ARM64'">
|
||||
<Exec Command=""$(MSBuildToolsPath)\msbuild.exe" PowerToys.sln -p:Configuration="$(Configuration)" -p:Platform="x64" -verbosity:m -t:DSC\PowerToys_Settings_DSC_Schema_Generator" WorkingDirectory="..\..\..\" />
|
||||
<Exec Command=""$(MSBuildToolsPath)\msbuild.exe" PowerToys.sln -p:Configuration="$(Configuration)" -p:Platform="x64" -verbosity:m -t:DSC\PowerToys_Settings_DSC_Schema_Generator" WorkingDirectory="$(SolutionDir)" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
// 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.CommandLine;
|
||||
using System.CommandLine.Parsing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Resources;
|
||||
using PowerToys.DSC.UnitTests.Models;
|
||||
|
||||
namespace PowerToys.DSC.UnitTests;
|
||||
|
||||
public class BaseDscTest
|
||||
{
|
||||
private readonly ResourceManager _resourceManager;
|
||||
|
||||
public BaseDscTest()
|
||||
{
|
||||
_resourceManager = new ResourceManager("PowerToys.DSC.Properties.Resources", typeof(PowerToys.DSC.Program).Assembly);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the string resource for the given name, formatted with the provided arguments.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the resource string.</param>
|
||||
/// <param name="args">The arguments to format the resource string with.</param>
|
||||
/// <returns></returns>
|
||||
public string GetResourceString(string name, params string[] args)
|
||||
{
|
||||
return string.Format(CultureInfo.InvariantCulture, _resourceManager.GetString(name, CultureInfo.InvariantCulture), args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute a dsc command with the provided arguments.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
protected DscExecuteResult ExecuteDscCommand<T>(params string[] args)
|
||||
where T : Command, new()
|
||||
{
|
||||
var originalOut = Console.Out;
|
||||
var originalErr = Console.Error;
|
||||
|
||||
var outSw = new StringWriter();
|
||||
var errSw = new StringWriter();
|
||||
|
||||
try
|
||||
{
|
||||
Console.SetOut(outSw);
|
||||
Console.SetError(errSw);
|
||||
|
||||
var executeResult = new T().Invoke(args);
|
||||
var output = outSw.ToString();
|
||||
var errorOutput = errSw.ToString();
|
||||
return new(executeResult == 0, output, errorOutput);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.SetOut(originalOut);
|
||||
Console.SetError(originalErr);
|
||||
outSw.Dispose();
|
||||
errSw.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
// 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.VisualStudio.TestTools.UnitTesting;
|
||||
using PowerToys.DSC.Commands;
|
||||
using PowerToys.DSC.DSCResources;
|
||||
|
||||
namespace PowerToys.DSC.UnitTests;
|
||||
|
||||
[TestClass]
|
||||
public sealed class CommandTest : BaseDscTest
|
||||
{
|
||||
[TestMethod]
|
||||
public void GetResource_Found_Success()
|
||||
{
|
||||
// Act
|
||||
var result = ExecuteDscCommand<GetCommand>("--resource", SettingsResource.ResourceName);
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(result.Success);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetResource_NotFound_Fail()
|
||||
{
|
||||
// Arrange
|
||||
var availableResources = string.Join(", ", BaseCommand.AvailableResources);
|
||||
|
||||
// Act
|
||||
var result = ExecuteDscCommand<GetCommand>("--resource", "ResourceNotFound");
|
||||
|
||||
// Assert
|
||||
Assert.IsFalse(result.Success);
|
||||
Assert.Contains(GetResourceString("InvalidResourceNameError", availableResources), result.Error);
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
// 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.Linq;
|
||||
using System.Text.Json;
|
||||
using PowerToys.DSC.Models;
|
||||
|
||||
namespace PowerToys.DSC.UnitTests.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Result of executing a DSC command.
|
||||
/// </summary>
|
||||
public class DscExecuteResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DscExecuteResult"/> class.
|
||||
/// </summary>
|
||||
/// <param name="success">Value indicating whether the command execution was successful.</param>
|
||||
/// <param name="output">Output stream content.</param>
|
||||
/// <param name="error">Error stream content.</param>
|
||||
public DscExecuteResult(bool success, string output, string error)
|
||||
{
|
||||
Success = success;
|
||||
Output = output;
|
||||
Error = error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the command execution was successful.
|
||||
/// </summary>
|
||||
public bool Success { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the output stream content of the operation.
|
||||
/// </summary>
|
||||
public string Output { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the error stream content of the operation.
|
||||
/// </summary>
|
||||
public string Error { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the messages from the error stream.
|
||||
/// </summary>
|
||||
/// <returns>List of messages with their levels.</returns>
|
||||
public List<(DscMessageLevel Level, string Message)> Messages()
|
||||
{
|
||||
var lines = Error.Split([Environment.NewLine], StringSplitOptions.RemoveEmptyEntries);
|
||||
return lines.SelectMany(line =>
|
||||
{
|
||||
var map = JsonSerializer.Deserialize<Dictionary<string, string>>(line);
|
||||
return map.Select(v => (GetMessageLevel(v.Key), v.Value)).ToList();
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the output as state.
|
||||
/// </summary>
|
||||
/// <returns>State.</returns>
|
||||
public T OutputState<T>()
|
||||
{
|
||||
var lines = Output.Split([Environment.NewLine], StringSplitOptions.RemoveEmptyEntries);
|
||||
Debug.Assert(lines.Length == 1, "Output should contain exactly one line.");
|
||||
return JsonSerializer.Deserialize<T>(lines[0]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the output as state and diff.
|
||||
/// </summary>
|
||||
/// <returns>State and diff.</returns>
|
||||
public (T State, List<string> Diff) OutputStateAndDiff<T>()
|
||||
{
|
||||
var lines = Output.Split([Environment.NewLine], StringSplitOptions.RemoveEmptyEntries);
|
||||
Debug.Assert(lines.Length == 2, "Output should contain exactly two lines.");
|
||||
var obj = JsonSerializer.Deserialize<T>(lines[0]);
|
||||
var diff = JsonSerializer.Deserialize<List<string>>(lines[1]);
|
||||
return (obj, diff);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the message level from a string representation.
|
||||
/// </summary>
|
||||
/// <param name="level">The string representation of the message level.</param>
|
||||
/// <returns>The level as <see cref="DscMessageLevel"/>.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when the level is unknown.</exception>
|
||||
private DscMessageLevel GetMessageLevel(string level)
|
||||
{
|
||||
return level switch
|
||||
{
|
||||
"error" => DscMessageLevel.Error,
|
||||
"warn" => DscMessageLevel.Warning,
|
||||
"info" => DscMessageLevel.Info,
|
||||
"debug" => DscMessageLevel.Debug,
|
||||
"trace" => DscMessageLevel.Trace,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(level), level, "Unknown message level"),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<!-- Look at Directory.Build.props in root for common stuff as well -->
|
||||
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<IsPackable>false</IsPackable>
|
||||
<OutputPath>..\..\..\..\$(Configuration)\$(Platform)\tests\PowerToys.DSC.Tests\</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MSTest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PowerToys.DSC\PowerToys.DSC.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,34 +0,0 @@
|
||||
// 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.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace PowerToys.DSC.UnitTests.SettingsResourceTests;
|
||||
|
||||
[TestClass]
|
||||
public sealed class SettingsResourceAdvancedPasteModuleTest : SettingsResourceModuleTest<AdvancedPasteSettings>
|
||||
{
|
||||
public SettingsResourceAdvancedPasteModuleTest()
|
||||
: base(nameof(ModuleType.AdvancedPaste))
|
||||
{
|
||||
}
|
||||
|
||||
protected override Action<AdvancedPasteSettings> GetSettingsModifier()
|
||||
{
|
||||
return s =>
|
||||
{
|
||||
s.Properties.ShowCustomPreview = !s.Properties.ShowCustomPreview;
|
||||
s.Properties.CloseAfterLosingFocus = !s.Properties.CloseAfterLosingFocus;
|
||||
s.Properties.IsAdvancedAIEnabled = !s.Properties.IsAdvancedAIEnabled;
|
||||
s.Properties.AdvancedPasteUIShortcut = new HotkeySettings
|
||||
{
|
||||
Key = "mock",
|
||||
Alt = true,
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
// 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.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace PowerToys.DSC.UnitTests.SettingsResourceTests;
|
||||
|
||||
[TestClass]
|
||||
public sealed class SettingsResourceAlwaysOnTopModuleTest : SettingsResourceModuleTest<AlwaysOnTopSettings>
|
||||
{
|
||||
public SettingsResourceAlwaysOnTopModuleTest()
|
||||
: base(nameof(ModuleType.AlwaysOnTop))
|
||||
{
|
||||
}
|
||||
|
||||
protected override Action<AlwaysOnTopSettings> GetSettingsModifier()
|
||||
{
|
||||
return s =>
|
||||
{
|
||||
s.Properties.RoundCornersEnabled.Value = !s.Properties.RoundCornersEnabled.Value;
|
||||
s.Properties.FrameEnabled.Value = !s.Properties.FrameEnabled.Value;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// 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 Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using PowerToys.DSC.DSCResources;
|
||||
|
||||
namespace PowerToys.DSC.UnitTests.SettingsResourceTests;
|
||||
|
||||
[TestClass]
|
||||
public sealed class SettingsResourceAppModuleTest : SettingsResourceModuleTest<GeneralSettings>
|
||||
{
|
||||
public SettingsResourceAppModuleTest()
|
||||
: base(SettingsResource.AppModule)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Action<GeneralSettings> GetSettingsModifier()
|
||||
{
|
||||
return s =>
|
||||
{
|
||||
s.Startup = !s.Startup;
|
||||
s.ShowSysTrayIcon = !s.ShowSysTrayIcon;
|
||||
s.Enabled.Awake = !s.Enabled.Awake;
|
||||
s.Enabled.ColorPicker = !s.Enabled.ColorPicker;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
// 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 ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace PowerToys.DSC.UnitTests.SettingsResourceTests;
|
||||
|
||||
[TestClass]
|
||||
public sealed class SettingsResourceAwakeModuleTest : SettingsResourceModuleTest<AwakeSettings>
|
||||
{
|
||||
public SettingsResourceAwakeModuleTest()
|
||||
: base(nameof(ModuleType.Awake))
|
||||
{
|
||||
}
|
||||
|
||||
protected override Action<AwakeSettings> GetSettingsModifier()
|
||||
{
|
||||
return s =>
|
||||
{
|
||||
s.Properties.ExpirationDateTime = DateTimeOffset.MinValue;
|
||||
s.Properties.IntervalHours = DefaultSettings.Properties.IntervalHours + 1;
|
||||
s.Properties.IntervalMinutes = DefaultSettings.Properties.IntervalMinutes + 1;
|
||||
s.Properties.Mode = s.Properties.Mode == AwakeMode.PASSIVE ? AwakeMode.TIMED : AwakeMode.PASSIVE;
|
||||
s.Properties.KeepDisplayOn = !s.Properties.KeepDisplayOn;
|
||||
s.Properties.CustomTrayTimes = new Dictionary<string, uint>
|
||||
{
|
||||
{ "08:00", 1 },
|
||||
{ "12:00", 2 },
|
||||
{ "16:00", 3 },
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
// 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.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace PowerToys.DSC.UnitTests.SettingsResourceTests;
|
||||
|
||||
[TestClass]
|
||||
public sealed class SettingsResourceColorPickerModuleTest : SettingsResourceModuleTest<ColorPickerSettings>
|
||||
{
|
||||
public SettingsResourceColorPickerModuleTest()
|
||||
: base(nameof(ModuleType.ColorPicker))
|
||||
{
|
||||
}
|
||||
|
||||
protected override Action<ColorPickerSettings> GetSettingsModifier()
|
||||
{
|
||||
return s =>
|
||||
{
|
||||
s.Properties.ShowColorName = !s.Properties.ShowColorName;
|
||||
s.Properties.ColorHistoryLimit = s.Properties.ColorHistoryLimit == 0 ? 10 : 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
// 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.Linq;
|
||||
using ManagedCommon;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using PowerToys.DSC.Commands;
|
||||
using PowerToys.DSC.DSCResources;
|
||||
using PowerToys.DSC.Models;
|
||||
|
||||
namespace PowerToys.DSC.UnitTests.SettingsResourceTests;
|
||||
|
||||
[TestClass]
|
||||
public sealed class SettingsResourceCommandTest : BaseDscTest
|
||||
{
|
||||
[TestMethod]
|
||||
public void Modules_ListAllSupportedModules()
|
||||
{
|
||||
// Arrange
|
||||
var expectedModules = new List<string>()
|
||||
{
|
||||
SettingsResource.AppModule,
|
||||
nameof(ModuleType.AdvancedPaste),
|
||||
nameof(ModuleType.AlwaysOnTop),
|
||||
nameof(ModuleType.Awake),
|
||||
nameof(ModuleType.ColorPicker),
|
||||
nameof(ModuleType.CropAndLock),
|
||||
nameof(ModuleType.EnvironmentVariables),
|
||||
nameof(ModuleType.FancyZones),
|
||||
nameof(ModuleType.FileLocksmith),
|
||||
nameof(ModuleType.FindMyMouse),
|
||||
nameof(ModuleType.Hosts),
|
||||
nameof(ModuleType.ImageResizer),
|
||||
nameof(ModuleType.KeyboardManager),
|
||||
nameof(ModuleType.MouseHighlighter),
|
||||
nameof(ModuleType.MouseJump),
|
||||
nameof(ModuleType.MousePointerCrosshairs),
|
||||
nameof(ModuleType.Peek),
|
||||
nameof(ModuleType.PowerRename),
|
||||
nameof(ModuleType.PowerAccent),
|
||||
nameof(ModuleType.RegistryPreview),
|
||||
nameof(ModuleType.MeasureTool),
|
||||
nameof(ModuleType.ShortcutGuide),
|
||||
nameof(ModuleType.PowerOCR),
|
||||
nameof(ModuleType.Workspaces),
|
||||
nameof(ModuleType.ZoomIt),
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = ExecuteDscCommand<ModulesCommand>("--resource", SettingsResource.ResourceName);
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(string.Join(Environment.NewLine, expectedModules.Order()), result.Output.Trim());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Set_EmptyInput_Fail()
|
||||
{
|
||||
// Act
|
||||
var result = ExecuteDscCommand<SetCommand>("--resource", SettingsResource.ResourceName, "--module", "Awake");
|
||||
var messages = result.Messages();
|
||||
|
||||
// Assert
|
||||
Assert.IsFalse(result.Success);
|
||||
Assert.AreEqual(1, messages.Count);
|
||||
Assert.AreEqual(DscMessageLevel.Error, messages[0].Level);
|
||||
Assert.AreEqual(GetResourceString("InputEmptyOrNullError"), messages[0].Message);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Test_EmptyInput_Fail()
|
||||
{
|
||||
// Act
|
||||
var result = ExecuteDscCommand<TestCommand>("--resource", SettingsResource.ResourceName, "--module", "Awake");
|
||||
var messages = result.Messages();
|
||||
|
||||
// Assert
|
||||
Assert.IsFalse(result.Success);
|
||||
Assert.AreEqual(1, messages.Count);
|
||||
Assert.AreEqual(DscMessageLevel.Error, messages[0].Level);
|
||||
Assert.AreEqual(GetResourceString("InputEmptyOrNullError"), messages[0].Message);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// 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.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace PowerToys.DSC.UnitTests.SettingsResourceTests;
|
||||
|
||||
[TestClass]
|
||||
public sealed class SettingsResourceCropAndLockModuleTest : SettingsResourceModuleTest<CropAndLockSettings>
|
||||
{
|
||||
public SettingsResourceCropAndLockModuleTest()
|
||||
: base(nameof(ModuleType.CropAndLock))
|
||||
{
|
||||
}
|
||||
|
||||
protected override Action<CropAndLockSettings> GetSettingsModifier()
|
||||
{
|
||||
return s =>
|
||||
{
|
||||
s.Properties.ThumbnailHotkey = new KeyboardKeysProperty()
|
||||
{
|
||||
Value = new HotkeySettings
|
||||
{
|
||||
Key = "mock",
|
||||
Alt = true,
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
// 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.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using PowerToys.DSC.Commands;
|
||||
using PowerToys.DSC.DSCResources;
|
||||
using PowerToys.DSC.Models.ResourceObjects;
|
||||
|
||||
namespace PowerToys.DSC.UnitTests.SettingsResourceTests;
|
||||
|
||||
public abstract class SettingsResourceModuleTest<TSettingsConfig> : BaseDscTest
|
||||
where TSettingsConfig : ISettingsConfig, new()
|
||||
{
|
||||
private readonly SettingsUtils _settingsUtils = new();
|
||||
private TSettingsConfig _originalSettings;
|
||||
|
||||
protected TSettingsConfig DefaultSettings => new();
|
||||
|
||||
protected string Module { get; }
|
||||
|
||||
protected List<string> DiffSettings { get; } = [SettingsResourceObject<AwakeSettings>.SettingsJsonPropertyName];
|
||||
|
||||
protected List<string> DiffEmpty { get; } = [];
|
||||
|
||||
public SettingsResourceModuleTest(string module)
|
||||
{
|
||||
Module = module;
|
||||
}
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
_originalSettings = GetSettings();
|
||||
ResetSettingsToDefaultValues();
|
||||
}
|
||||
|
||||
[TestCleanup]
|
||||
public void TestCleanup()
|
||||
{
|
||||
SaveSettings(_originalSettings);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Get_Success()
|
||||
{
|
||||
// Arrange
|
||||
var settingsBeforeExecute = GetSettings();
|
||||
|
||||
// Act
|
||||
var result = ExecuteDscCommand<GetCommand>("--resource", SettingsResource.ResourceName, "--module", Module);
|
||||
var state = result.OutputState<SettingsResourceObject<TSettingsConfig>>();
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(result.Success);
|
||||
AssertSettingsAreEqual(settingsBeforeExecute, GetSettings());
|
||||
AssertStateAndSettingsAreEqual(settingsBeforeExecute, state);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Export_Success()
|
||||
{
|
||||
// Arrange
|
||||
var settingsBeforeExecute = GetSettings();
|
||||
|
||||
// Act
|
||||
var result = ExecuteDscCommand<ExportCommand>("--resource", SettingsResource.ResourceName, "--module", Module);
|
||||
var state = result.OutputState<SettingsResourceObject<TSettingsConfig>>();
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(result.Success);
|
||||
AssertSettingsAreEqual(settingsBeforeExecute, GetSettings());
|
||||
AssertStateAndSettingsAreEqual(settingsBeforeExecute, state);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SetWithDiff_Success()
|
||||
{
|
||||
// Arrange
|
||||
var settingsModifier = GetSettingsModifier();
|
||||
var input = CreateInputResourceObject(settingsModifier);
|
||||
|
||||
// Act
|
||||
var result = ExecuteDscCommand<SetCommand>("--resource", SettingsResource.ResourceName, "--module", Module, "--input", input);
|
||||
var (state, diff) = result.OutputStateAndDiff<SettingsResourceObject<TSettingsConfig>>();
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(result.Success);
|
||||
AssertSettingsHasChanged(settingsModifier);
|
||||
AssertStateAndSettingsAreEqual(GetSettings(), state);
|
||||
CollectionAssert.AreEqual(DiffSettings, diff);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SetWithoutDiff_Success()
|
||||
{
|
||||
// Arrange
|
||||
var settingsModifier = GetSettingsModifier();
|
||||
UpdateSettings(settingsModifier);
|
||||
var settingsBeforeExecute = GetSettings();
|
||||
var input = CreateInputResourceObject(settingsModifier);
|
||||
|
||||
// Act
|
||||
var result = ExecuteDscCommand<SetCommand>("--resource", SettingsResource.ResourceName, "--module", Module, "--input", input);
|
||||
var (state, diff) = result.OutputStateAndDiff<SettingsResourceObject<TSettingsConfig>>();
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(result.Success);
|
||||
AssertSettingsAreEqual(settingsBeforeExecute, GetSettings());
|
||||
AssertStateAndSettingsAreEqual(settingsBeforeExecute, state);
|
||||
CollectionAssert.AreEqual(DiffEmpty, diff);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestWithDiff_Success()
|
||||
{
|
||||
// Arrange
|
||||
var settingsModifier = GetSettingsModifier();
|
||||
var settingsBeforeExecute = GetSettings();
|
||||
var input = CreateInputResourceObject(settingsModifier);
|
||||
|
||||
// Act
|
||||
var result = ExecuteDscCommand<TestCommand>("--resource", SettingsResource.ResourceName, "--module", Module, "--input", input);
|
||||
var (state, diff) = result.OutputStateAndDiff<SettingsResourceObject<TSettingsConfig>>();
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(result.Success);
|
||||
AssertSettingsAreEqual(settingsBeforeExecute, GetSettings());
|
||||
AssertStateAndSettingsAreEqual(settingsBeforeExecute, state);
|
||||
CollectionAssert.AreEqual(DiffSettings, diff);
|
||||
Assert.IsFalse(state.InDesiredState);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestWithoutDiff_Success()
|
||||
{
|
||||
// Arrange
|
||||
var settingsModifier = GetSettingsModifier();
|
||||
UpdateSettings(settingsModifier);
|
||||
var settingsBeforeExecute = GetSettings();
|
||||
var input = CreateInputResourceObject(settingsModifier);
|
||||
|
||||
// Act
|
||||
var result = ExecuteDscCommand<TestCommand>("--resource", SettingsResource.ResourceName, "--module", Module, "--input", input);
|
||||
var (state, diff) = result.OutputStateAndDiff<SettingsResourceObject<TSettingsConfig>>();
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(result.Success);
|
||||
AssertSettingsAreEqual(settingsBeforeExecute, GetSettings());
|
||||
AssertStateAndSettingsAreEqual(settingsBeforeExecute, state);
|
||||
CollectionAssert.AreEqual(DiffEmpty, diff);
|
||||
Assert.IsTrue(state.InDesiredState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the settings modifier action for the specific settings configuration.
|
||||
/// </summary>
|
||||
/// <returns>An action that modifies the settings configuration.</returns>
|
||||
protected abstract Action<TSettingsConfig> GetSettingsModifier();
|
||||
|
||||
/// <summary>
|
||||
/// Resets the settings to default values.
|
||||
/// </summary>
|
||||
private void ResetSettingsToDefaultValues()
|
||||
{
|
||||
SaveSettings(DefaultSettings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the settings for the specified module.
|
||||
/// </summary>
|
||||
/// <returns>An instance of the settings type with the current configuration.</returns>
|
||||
private TSettingsConfig GetSettings()
|
||||
{
|
||||
return _settingsUtils.GetSettingsOrDefault<TSettingsConfig>(DefaultSettings.GetModuleName());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the settings for the specified module.
|
||||
/// </summary>
|
||||
/// <param name="settings">Settings to save.</param>
|
||||
private void SaveSettings(TSettingsConfig settings)
|
||||
{
|
||||
_settingsUtils.SaveSettings(JsonSerializer.Serialize(settings), DefaultSettings.GetModuleName());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the resource object for the operation.
|
||||
/// </summary>
|
||||
/// <param name="settings">Settings to include in the resource object.</param>
|
||||
/// <returns>A JSON string representing the resource object.</returns>
|
||||
private string CreateResourceObject(TSettingsConfig settings)
|
||||
{
|
||||
var resourceObject = new SettingsResourceObject<TSettingsConfig>
|
||||
{
|
||||
Settings = settings,
|
||||
};
|
||||
return JsonSerializer.Serialize(resourceObject);
|
||||
}
|
||||
|
||||
private string CreateInputResourceObject(Action<TSettingsConfig> settingsModifier)
|
||||
{
|
||||
var settings = DefaultSettings;
|
||||
settingsModifier(settings);
|
||||
return CreateResourceObject(settings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the response for the Get operation.
|
||||
/// </summary>
|
||||
/// <returns>A JSON string representing the response.</returns>
|
||||
private string CreateGetResponse()
|
||||
{
|
||||
return CreateResourceObject(GetSettings());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asserts that the state and settings are equal.
|
||||
/// </summary>
|
||||
/// <param name="settings">Settings manifest to compare against.</param>
|
||||
/// <param name="state">Output state to compare.</param>
|
||||
private void AssertStateAndSettingsAreEqual(TSettingsConfig settings, SettingsResourceObject<TSettingsConfig> state)
|
||||
{
|
||||
AssertSettingsAreEqual(settings, state.Settings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asserts that two settings manifests are equal.
|
||||
/// </summary>
|
||||
/// <param name="expected">Expected settings.</param>
|
||||
/// <param name="actual">Actual settings.</param>
|
||||
private void AssertSettingsAreEqual(TSettingsConfig expected, TSettingsConfig actual)
|
||||
{
|
||||
var expectedJson = JsonSerializer.SerializeToNode(expected) as JsonObject;
|
||||
var actualJson = JsonSerializer.SerializeToNode(actual) as JsonObject;
|
||||
Assert.IsTrue(JsonNode.DeepEquals(expectedJson, actualJson));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asserts that the current settings have changed.
|
||||
/// </summary>
|
||||
/// <param name="action">Action to prepare the default settings.</param>
|
||||
private void AssertSettingsHasChanged(Action<TSettingsConfig> action)
|
||||
{
|
||||
var currentSettings = GetSettings();
|
||||
var defaultSettings = DefaultSettings;
|
||||
action(defaultSettings);
|
||||
AssertSettingsAreEqual(defaultSettings, currentSettings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the settings.
|
||||
/// </summary>
|
||||
/// <param name="action">Action to modify the settings.</param>
|
||||
private void UpdateSettings(Action<TSettingsConfig> action)
|
||||
{
|
||||
var settings = GetSettings();
|
||||
action(settings);
|
||||
SaveSettings(settings);
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
// 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.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.CommandLine.IO;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using PowerToys.DSC.DSCResources;
|
||||
using PowerToys.DSC.Options;
|
||||
using PowerToys.DSC.Properties;
|
||||
|
||||
namespace PowerToys.DSC.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for all DSC commands.
|
||||
/// </summary>
|
||||
public abstract class BaseCommand : Command
|
||||
{
|
||||
private static readonly CompositeFormat ModuleNotSupportedByResource = CompositeFormat.Parse(Resources.ModuleNotSupportedByResource);
|
||||
|
||||
// Shared options for all commands
|
||||
private readonly ModuleOption _moduleOption;
|
||||
private readonly ResourceOption _resourceOption;
|
||||
private readonly InputOption _inputOption;
|
||||
|
||||
// The dictionary of available resources and their factories.
|
||||
private static readonly Dictionary<string, Func<string?, BaseResource>> _resourceFactories = new()
|
||||
{
|
||||
{ SettingsResource.ResourceName, module => new SettingsResource(module) },
|
||||
|
||||
// Add other resources here
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of available DSC resources that can be used with the command.
|
||||
/// </summary>
|
||||
public static List<string> AvailableResources => [.._resourceFactories.Keys];
|
||||
|
||||
/// <summary>
|
||||
/// Gets the DSC resource to be used by the command.
|
||||
/// </summary>
|
||||
protected BaseResource? Resource { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the input JSON provided by the user.
|
||||
/// </summary>
|
||||
protected string? Input { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the PowerToys module to be used by the command.
|
||||
/// </summary>
|
||||
protected string? Module { get; private set; }
|
||||
|
||||
public BaseCommand(string name, string description)
|
||||
: base(name, description)
|
||||
{
|
||||
// Register the common options for all commands
|
||||
_moduleOption = new ModuleOption();
|
||||
AddOption(_moduleOption);
|
||||
|
||||
_resourceOption = new ResourceOption(AvailableResources);
|
||||
AddOption(_resourceOption);
|
||||
|
||||
_inputOption = new InputOption();
|
||||
AddOption(_inputOption);
|
||||
|
||||
// Register the command handler
|
||||
this.SetHandler(CommandHandler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the command invocation.
|
||||
/// </summary>
|
||||
/// <param name="context">The invocation context containing the parsed command options.</param>
|
||||
public void CommandHandler(InvocationContext context)
|
||||
{
|
||||
Input = context.ParseResult.GetValueForOption(_inputOption);
|
||||
Module = context.ParseResult.GetValueForOption(_moduleOption);
|
||||
Resource = ResolvedResource(context);
|
||||
|
||||
// Validate the module against the resource's supported modules
|
||||
var supportedModules = Resource.GetSupportedModules();
|
||||
if (!string.IsNullOrEmpty(Module) && !supportedModules.Contains(Module))
|
||||
{
|
||||
var errorMessage = string.Format(CultureInfo.InvariantCulture, ModuleNotSupportedByResource, Module, Resource.Name);
|
||||
context.Console.Error.WriteLine(errorMessage);
|
||||
context.ExitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Continue with the command handler logic
|
||||
CommandHandlerInternal(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the command logic internally.
|
||||
/// </summary>
|
||||
/// <param name="context">Invocation context containing the parsed command options.</param>
|
||||
public abstract void CommandHandlerInternal(InvocationContext context);
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the resource from the provided resource name in the context.
|
||||
/// </summary>
|
||||
/// <param name="context">Invocation context containing the parsed command options.</param>
|
||||
/// <returns>The resolved <see cref="BaseResource"/> instance.</returns>
|
||||
private BaseResource ResolvedResource(InvocationContext context)
|
||||
{
|
||||
// Resource option has already been validated before the command
|
||||
// handler is invoked.
|
||||
var resourceName = context.ParseResult.GetValueForOption(_resourceOption);
|
||||
Debug.Assert(!string.IsNullOrEmpty(resourceName), "Resource name must not be null or empty.");
|
||||
Debug.Assert(_resourceFactories.ContainsKey(resourceName), $"Resource '{resourceName}' is not registered.");
|
||||
return _resourceFactories[resourceName](Module);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// 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.CommandLine.Invocation;
|
||||
using PowerToys.DSC.Properties;
|
||||
|
||||
namespace PowerToys.DSC.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Command to export all state instances.
|
||||
/// </summary>
|
||||
public sealed class ExportCommand : BaseCommand
|
||||
{
|
||||
public ExportCommand()
|
||||
: base("export", Resources.ExportCommandDescription)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void CommandHandlerInternal(InvocationContext context)
|
||||
{
|
||||
context.ExitCode = Resource!.ExportState(Input) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// 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.CommandLine.Invocation;
|
||||
using PowerToys.DSC.Properties;
|
||||
|
||||
namespace PowerToys.DSC.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Command to get the resource state.
|
||||
/// </summary>
|
||||
public sealed class GetCommand : BaseCommand
|
||||
{
|
||||
public GetCommand()
|
||||
: base("get", Resources.GetCommandDescription)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void CommandHandlerInternal(InvocationContext context)
|
||||
{
|
||||
context.ExitCode = Resource!.GetState(Input) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// 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.CommandLine.Invocation;
|
||||
using PowerToys.DSC.Options;
|
||||
using PowerToys.DSC.Properties;
|
||||
|
||||
namespace PowerToys.DSC.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Command to get the manifest of the DSC resource.
|
||||
/// </summary>
|
||||
public sealed class ManifestCommand : BaseCommand
|
||||
{
|
||||
/// <summary>
|
||||
/// Option to specify the output directory for the manifest.
|
||||
/// </summary>
|
||||
private readonly OutputDirectoryOption _outputDirectoryOption;
|
||||
|
||||
public ManifestCommand()
|
||||
: base("manifest", Resources.ManifestCommandDescription)
|
||||
{
|
||||
_outputDirectoryOption = new OutputDirectoryOption();
|
||||
AddOption(_outputDirectoryOption);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void CommandHandlerInternal(InvocationContext context)
|
||||
{
|
||||
var outputDir = context.ParseResult.GetValueForOption(_outputDirectoryOption);
|
||||
context.ExitCode = Resource!.Manifest(outputDir) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
// 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.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.Diagnostics;
|
||||
using PowerToys.DSC.Properties;
|
||||
|
||||
namespace PowerToys.DSC.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Command to get all supported modules for a specific resource.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is primarily used for debugging purposes and for build scripts.
|
||||
/// </remarks>
|
||||
public sealed class ModulesCommand : BaseCommand
|
||||
{
|
||||
public ModulesCommand()
|
||||
: base("modules", Resources.ModulesCommandDescription)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void CommandHandlerInternal(InvocationContext context)
|
||||
{
|
||||
// Module is optional, if not provided, all supported modules for the
|
||||
// resource will be printed. If provided, it must be one of the
|
||||
// supported modules since it has been validated before this command is
|
||||
// executed.
|
||||
if (!string.IsNullOrEmpty(Module))
|
||||
{
|
||||
Debug.Assert(Resource!.GetSupportedModules().Contains(Module), "Module must be present in the list of supported modules.");
|
||||
context.Console.WriteLine(Module);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print the supported modules for the specified resource
|
||||
foreach (var module in Resource!.GetSupportedModules())
|
||||
{
|
||||
context.Console.WriteLine(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// 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.CommandLine.Invocation;
|
||||
using PowerToys.DSC.Properties;
|
||||
|
||||
namespace PowerToys.DSC.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Command to output the schema of the resource.
|
||||
/// </summary>
|
||||
public sealed class SchemaCommand : BaseCommand
|
||||
{
|
||||
public SchemaCommand()
|
||||
: base("schema", Resources.SchemaCommandDescription)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void CommandHandlerInternal(InvocationContext context)
|
||||
{
|
||||
context.ExitCode = Resource!.Schema() ? 0 : 1;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// 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.CommandLine.Invocation;
|
||||
using PowerToys.DSC.Properties;
|
||||
|
||||
namespace PowerToys.DSC.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Command to set the resource state.
|
||||
/// </summary>
|
||||
public sealed class SetCommand : BaseCommand
|
||||
{
|
||||
public SetCommand()
|
||||
: base("set", Resources.SetCommandDescription)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void CommandHandlerInternal(InvocationContext context)
|
||||
{
|
||||
context.ExitCode = Resource!.SetState(Input) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// 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.CommandLine.Invocation;
|
||||
using PowerToys.DSC.Properties;
|
||||
|
||||
namespace PowerToys.DSC.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Command to test the resource state.
|
||||
/// </summary>
|
||||
public sealed class TestCommand : BaseCommand
|
||||
{
|
||||
public TestCommand()
|
||||
: base("test", Resources.TestCommandDescription)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void CommandHandlerInternal(InvocationContext context)
|
||||
{
|
||||
context.ExitCode = Resource!.TestState(Input) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
// 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.Text.Json.Nodes;
|
||||
using PowerToys.DSC.Models;
|
||||
|
||||
namespace PowerToys.DSC.DSCResources;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for all DSC resources.
|
||||
/// </summary>
|
||||
public abstract class BaseResource
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name of the resource.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the module being used by the resource, if provided.
|
||||
/// </summary>
|
||||
public string? Module { get; }
|
||||
|
||||
public BaseResource(string name, string? module)
|
||||
{
|
||||
Name = name;
|
||||
Module = module;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls the get method on the resource.
|
||||
/// </summary>
|
||||
/// <param name="input">The input string, if any.</param>
|
||||
/// <returns>True if the operation was successful; otherwise false.</returns>
|
||||
public abstract bool GetState(string? input);
|
||||
|
||||
/// <summary>
|
||||
/// Calls the set method on the resource.
|
||||
/// </summary>
|
||||
/// <param name="input">The input string, if any.</param>
|
||||
/// <returns>True if the operation was successful; otherwise false.</returns>
|
||||
public abstract bool SetState(string? input);
|
||||
|
||||
/// <summary>
|
||||
/// Calls the test method on the resource.
|
||||
/// </summary>
|
||||
/// <param name="input">The input string, if any.</param>
|
||||
/// <returns>True if the operation was successful; otherwise false.</returns>
|
||||
public abstract bool TestState(string? input);
|
||||
|
||||
/// <summary>
|
||||
/// Calls the export method on the resource.
|
||||
/// </summary>
|
||||
/// <param name="input"> The input string, if any.</param>
|
||||
/// <returns>True if the operation was successful; otherwise false.</returns>
|
||||
public abstract bool ExportState(string? input);
|
||||
|
||||
/// <summary>
|
||||
/// Calls the schema method on the resource.
|
||||
/// </summary>
|
||||
/// <returns>True if the operation was successful; otherwise false.</returns>
|
||||
public abstract bool Schema();
|
||||
|
||||
/// <summary>
|
||||
/// Generates a DSC resource JSON manifest for the resource. If the
|
||||
/// outputDir is not provided, the manifest will be printed to the console.
|
||||
/// </summary>
|
||||
/// <param name="outputDir"> The directory where the manifest should be
|
||||
/// saved. If null, the manifest will be printed to the console.</param>
|
||||
/// <returns>True if the manifest was successfully generated and saved,otherwise false.</returns>
|
||||
public abstract bool Manifest(string? outputDir);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of supported modules for the resource.
|
||||
/// </summary>
|
||||
/// <returns>Gets a list of supported modules.</returns>
|
||||
public abstract IList<string> GetSupportedModules();
|
||||
|
||||
/// <summary>
|
||||
/// Writes a JSON output line to the console.
|
||||
/// </summary>
|
||||
/// <param name="output">The JSON output to write.</param>
|
||||
protected void WriteJsonOutputLine(JsonNode output)
|
||||
{
|
||||
var json = output.ToJsonString(new() { WriteIndented = false });
|
||||
WriteJsonOutputLine(json);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a JSON output line to the console.
|
||||
/// </summary>
|
||||
/// <param name="output">The JSON output to write.</param>
|
||||
protected void WriteJsonOutputLine(string output)
|
||||
{
|
||||
Console.WriteLine(output);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a message output line to the console with the specified message level.
|
||||
/// </summary>
|
||||
/// <param name="level">The level of the message.</param>
|
||||
/// <param name="message">The message to write.</param>
|
||||
protected void WriteMessageOutputLine(DscMessageLevel level, string message)
|
||||
{
|
||||
var messageObj = new Dictionary<string, string>
|
||||
{
|
||||
[GetMessageLevel(level)] = message,
|
||||
};
|
||||
var messageJson = System.Text.Json.JsonSerializer.Serialize(messageObj);
|
||||
Console.Error.WriteLine(messageJson);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the message level as a string based on the provided dsc message level enum value.
|
||||
/// </summary>
|
||||
/// <param name="level">The dsc message level.</param>
|
||||
/// <returns>A string representation of the message level.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when the provided message level is not recognized.</exception>
|
||||
private static string GetMessageLevel(DscMessageLevel level)
|
||||
{
|
||||
return level switch
|
||||
{
|
||||
DscMessageLevel.Error => "error",
|
||||
DscMessageLevel.Warning => "warn",
|
||||
DscMessageLevel.Info => "info",
|
||||
DscMessageLevel.Debug => "debug",
|
||||
DscMessageLevel.Trace => "trace",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,248 +0,0 @@
|
||||
// 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.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
using PowerToys.DSC.Models;
|
||||
using PowerToys.DSC.Models.FunctionData;
|
||||
using PowerToys.DSC.Properties;
|
||||
|
||||
namespace PowerToys.DSC.DSCResources;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the DSC resource for managing PowerToys settings.
|
||||
/// </summary>
|
||||
public sealed class SettingsResource : BaseResource
|
||||
{
|
||||
private static readonly CompositeFormat FailedToWriteManifests = CompositeFormat.Parse(Resources.FailedToWriteManifests);
|
||||
|
||||
public const string AppModule = "App";
|
||||
public const string ResourceName = "settings";
|
||||
|
||||
private readonly Dictionary<string, Func<string?, ISettingsFunctionData>> _moduleFunctionData;
|
||||
|
||||
public string ModuleOrDefault => string.IsNullOrEmpty(Module) ? AppModule : Module;
|
||||
|
||||
public SettingsResource(string? module)
|
||||
: base(ResourceName, module)
|
||||
{
|
||||
_moduleFunctionData = new()
|
||||
{
|
||||
{ AppModule, CreateModuleFunctionData<GeneralSettings> },
|
||||
{ nameof(ModuleType.AdvancedPaste), CreateModuleFunctionData<AdvancedPasteSettings> },
|
||||
{ nameof(ModuleType.AlwaysOnTop), CreateModuleFunctionData<AlwaysOnTopSettings> },
|
||||
{ nameof(ModuleType.Awake), CreateModuleFunctionData<AwakeSettings> },
|
||||
{ nameof(ModuleType.ColorPicker), CreateModuleFunctionData<ColorPickerSettings> },
|
||||
{ nameof(ModuleType.CropAndLock), CreateModuleFunctionData<CropAndLockSettings> },
|
||||
{ nameof(ModuleType.EnvironmentVariables), CreateModuleFunctionData<EnvironmentVariablesSettings> },
|
||||
{ nameof(ModuleType.FancyZones), CreateModuleFunctionData<FancyZonesSettings> },
|
||||
{ nameof(ModuleType.FileLocksmith), CreateModuleFunctionData<FileLocksmithSettings> },
|
||||
{ nameof(ModuleType.FindMyMouse), CreateModuleFunctionData<FindMyMouseSettings> },
|
||||
{ nameof(ModuleType.Hosts), CreateModuleFunctionData<HostsSettings> },
|
||||
{ nameof(ModuleType.ImageResizer), CreateModuleFunctionData<ImageResizerSettings> },
|
||||
{ nameof(ModuleType.KeyboardManager), CreateModuleFunctionData<KeyboardManagerSettings> },
|
||||
{ nameof(ModuleType.MouseHighlighter), CreateModuleFunctionData<MouseHighlighterSettings> },
|
||||
{ nameof(ModuleType.MouseJump), CreateModuleFunctionData<MouseJumpSettings> },
|
||||
{ nameof(ModuleType.MousePointerCrosshairs), CreateModuleFunctionData<MousePointerCrosshairsSettings> },
|
||||
{ nameof(ModuleType.Peek), CreateModuleFunctionData<PeekSettings> },
|
||||
{ nameof(ModuleType.PowerRename), CreateModuleFunctionData<PowerRenameSettings> },
|
||||
{ nameof(ModuleType.PowerAccent), CreateModuleFunctionData<PowerAccentSettings> },
|
||||
{ nameof(ModuleType.RegistryPreview), CreateModuleFunctionData<RegistryPreviewSettings> },
|
||||
{ nameof(ModuleType.MeasureTool), CreateModuleFunctionData<MeasureToolSettings> },
|
||||
{ nameof(ModuleType.ShortcutGuide), CreateModuleFunctionData<ShortcutGuideSettings> },
|
||||
{ nameof(ModuleType.PowerOCR), CreateModuleFunctionData<PowerOcrSettings> },
|
||||
{ nameof(ModuleType.Workspaces), CreateModuleFunctionData<WorkspacesSettings> },
|
||||
{ nameof(ModuleType.ZoomIt), CreateModuleFunctionData<ZoomItSettings> },
|
||||
|
||||
// The following modules are not currently supported:
|
||||
// - MouseWithoutBorders Contains sensitive configuration values, making export/import potentially insecure.
|
||||
// - PowerLauncher Uses absolute file paths in its settings, which are not portable across systems.
|
||||
// - NewPlus Uses absolute file paths in its settings, which are not portable across systems.
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool ExportState(string? input)
|
||||
{
|
||||
var data = CreateFunctionData();
|
||||
data.GetState();
|
||||
WriteJsonOutputLine(data.Output.ToJson());
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool GetState(string? input)
|
||||
{
|
||||
return ExportState(input);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool SetState(string? input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
WriteMessageOutputLine(DscMessageLevel.Error, Resources.InputEmptyOrNullError);
|
||||
return false;
|
||||
}
|
||||
|
||||
var data = CreateFunctionData(input);
|
||||
data.GetState();
|
||||
|
||||
// Capture the diff before updating the output
|
||||
var diff = data.GetDiffJson();
|
||||
|
||||
// Only call Set if the desired state is different from the current state
|
||||
if (!data.TestState())
|
||||
{
|
||||
var inputSettings = data.Input.SettingsInternal;
|
||||
data.Output.SettingsInternal = inputSettings;
|
||||
data.SetState();
|
||||
}
|
||||
|
||||
WriteJsonOutputLine(data.Output.ToJson());
|
||||
WriteJsonOutputLine(diff);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool TestState(string? input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
WriteMessageOutputLine(DscMessageLevel.Error, Resources.InputEmptyOrNullError);
|
||||
return false;
|
||||
}
|
||||
|
||||
var data = CreateFunctionData(input);
|
||||
data.GetState();
|
||||
data.Output.InDesiredState = data.TestState();
|
||||
|
||||
WriteJsonOutputLine(data.Output.ToJson());
|
||||
WriteJsonOutputLine(data.GetDiffJson());
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Schema()
|
||||
{
|
||||
var data = CreateFunctionData();
|
||||
WriteJsonOutputLine(data.Schema());
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <remarks>
|
||||
/// If an output directory is specified, write the manifests to files,
|
||||
/// otherwise output them to the console.
|
||||
/// </remarks>
|
||||
public override bool Manifest(string? outputDir)
|
||||
{
|
||||
var manifests = GenerateManifests();
|
||||
|
||||
if (!string.IsNullOrEmpty(outputDir))
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var (name, manifest) in manifests)
|
||||
{
|
||||
File.WriteAllText(Path.Combine(outputDir, $"microsoft.powertoys.{name}.settings.dsc.resource.json"), manifest);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorMessage = string.Format(CultureInfo.InvariantCulture, FailedToWriteManifests, outputDir, ex.Message);
|
||||
WriteMessageOutputLine(DscMessageLevel.Error, errorMessage);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var (_, manifest) in manifests)
|
||||
{
|
||||
WriteJsonOutputLine(manifest);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates manifests for the specified module or all supported modules
|
||||
/// if no module is specified.
|
||||
/// </summary>
|
||||
/// <returns>A list of tuples containing the module name and its corresponding manifest JSON.</returns>
|
||||
private List<(string Name, string Manifest)> GenerateManifests()
|
||||
{
|
||||
List<(string Name, string Manifest)> manifests = [];
|
||||
if (!string.IsNullOrEmpty(Module))
|
||||
{
|
||||
manifests.Add((Module, GenerateManifest(Module)));
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var module in GetSupportedModules())
|
||||
{
|
||||
manifests.Add((module, GenerateManifest(module)));
|
||||
}
|
||||
}
|
||||
|
||||
return manifests;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a DSC resource JSON manifest for the specified module.
|
||||
/// </summary>
|
||||
/// <param name="module">The name of the module for which to generate the manifest.</param>
|
||||
/// <returns>A JSON string representing the DSC resource manifest.</returns>
|
||||
private string GenerateManifest(string module)
|
||||
{
|
||||
// Note: The description is not localized because the generated
|
||||
// manifest file will be part of the package
|
||||
return new DscManifest($"{module}Settings", "0.1.0")
|
||||
.AddDescription($"Allows management of {module} settings state via the DSC v3 command line interface protocol.")
|
||||
.AddStdinMethod("export", ["export", "--module", module, "--resource", "settings"])
|
||||
.AddStdinMethod("get", ["get", "--module", module, "--resource", "settings"])
|
||||
.AddJsonInputMethod("set", "--input", ["set", "--module", module, "--resource", "settings"], implementsPretest: true, stateAndDiff: true)
|
||||
.AddJsonInputMethod("test", "--input", ["test", "--module", module, "--resource", "settings"], stateAndDiff: true)
|
||||
.AddCommandMethod("schema", ["schema", "--module", module, "--resource", "settings"])
|
||||
.ToJson();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IList<string> GetSupportedModules()
|
||||
{
|
||||
return [.. _moduleFunctionData.Keys.Order()];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the function data for the specified module or the default module if none is specified.
|
||||
/// </summary>
|
||||
/// <param name="input">The input string, if any.</param>
|
||||
/// <returns>An instance of <see cref="ISettingsFunctionData"/> for the specified module.</returns>
|
||||
public ISettingsFunctionData CreateFunctionData(string? input = null)
|
||||
{
|
||||
Debug.Assert(_moduleFunctionData.ContainsKey(ModuleOrDefault), "Module should be supported by the resource.");
|
||||
return _moduleFunctionData[ModuleOrDefault](input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the function data for a specific settings configuration type.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettingsConfig">The type of settings configuration to create function data for.</typeparam>
|
||||
/// <param name="input">The input string, if any.</param>
|
||||
/// <returns>An instance of <see cref="ISettingsFunctionData"/> for the specified settings configuration type.</returns>
|
||||
private ISettingsFunctionData CreateModuleFunctionData<TSettingsConfig>(string? input)
|
||||
where TSettingsConfig : ISettingsConfig, new()
|
||||
{
|
||||
return new SettingsFunctionData<TSettingsConfig>(input);
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
// 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.Nodes;
|
||||
|
||||
namespace PowerToys.DSC.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Class for building a DSC manifest for PowerToys resources.
|
||||
/// </summary>
|
||||
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 readonly string _type;
|
||||
private readonly string _version;
|
||||
private readonly JsonObject _manifest;
|
||||
|
||||
public DscManifest(string type, string version)
|
||||
{
|
||||
_type = type;
|
||||
_version = version;
|
||||
_manifest = new JsonObject
|
||||
{
|
||||
["$schema"] = Schema,
|
||||
["type"] = $"Microsoft.PowerToys/{_type}",
|
||||
["version"] = _version,
|
||||
["tags"] = new JsonArray("PowerToys"),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a description to the manifest.
|
||||
/// </summary>
|
||||
/// <param name="description">The description to add.</param>
|
||||
/// <returns>Returns the current instance of <see cref="DscManifest"/>.</returns>
|
||||
public DscManifest AddDescription(string description)
|
||||
{
|
||||
_manifest["description"] = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a method to the manifest with the specified executable and arguments.
|
||||
/// </summary>
|
||||
/// <param name="method">The name of the method to add.</param>
|
||||
/// <param name="inputArg">The input argument for the method</param>
|
||||
/// <param name="args">The list of arguments for the method.</param>
|
||||
/// <param name="implementsPretest">Whether the method implements a pretest.</param>
|
||||
/// <param name="stateAndDiff">Whether the method returns state and diff.</param>
|
||||
/// <returns>Returns the current instance of <see cref="DscManifest"/>.</returns>
|
||||
public DscManifest AddJsonInputMethod(string method, string inputArg, List<string> args, bool? implementsPretest = null, bool? stateAndDiff = null)
|
||||
{
|
||||
var argsJson = CreateJsonArray(args);
|
||||
argsJson.Add(new JsonObject
|
||||
{
|
||||
["jsonInputArg"] = inputArg,
|
||||
["mandatory"] = true,
|
||||
});
|
||||
var methodObject = AddMethod(argsJson, implementsPretest, stateAndDiff);
|
||||
_manifest[method] = methodObject;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a method to the manifest that reads from standard input (stdin).
|
||||
/// </summary>
|
||||
/// <param name="method">The name of the method to add.</param>
|
||||
/// <param name="args">The list of arguments for the method.</param>
|
||||
/// <param name="implementsPretest">Whether the method implements a pretest.</param>
|
||||
/// <param name="stateAndDiff">Whether the method returns state and diff.</param>
|
||||
/// <returns>Returns the current instance of <see cref="DscManifest"/>.</returns>
|
||||
public DscManifest AddStdinMethod(string method, List<string> args, bool? implementsPretest = null, bool? stateAndDiff = null)
|
||||
{
|
||||
var argsJson = CreateJsonArray(args);
|
||||
var methodObject = AddMethod(argsJson, implementsPretest, stateAndDiff);
|
||||
methodObject["input"] = "stdin";
|
||||
_manifest[method] = methodObject;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a command method to the manifest.
|
||||
/// </summary>
|
||||
/// <param name="method">The name of the method to add.</param>
|
||||
/// <param name="args">The list of arguments for the method.</param>
|
||||
/// <returns>Returns the current instance of <see cref="DscManifest"/>.</returns>
|
||||
public DscManifest AddCommandMethod(string method, List<string> args)
|
||||
{
|
||||
_manifest[method] = new JsonObject
|
||||
{
|
||||
["command"] = AddMethod(CreateJsonArray(args)),
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the JSON representation of the manifest.
|
||||
/// </summary>
|
||||
/// <returns>Returns the JSON string of the manifest.</returns>
|
||||
public string ToJson()
|
||||
{
|
||||
return _manifest.ToJsonString(new() { WriteIndented = true });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a method to the manifest with the specified arguments.
|
||||
/// </summary>
|
||||
/// <param name="args">The list of arguments for the method.</param>
|
||||
/// <param name="implementsPretest">Whether the method implements a pretest.</param>
|
||||
/// <param name="stateAndDiff">Whether the method returns state and diff.</param>
|
||||
/// <returns>Returns the method object.</returns>
|
||||
private JsonObject AddMethod(JsonArray args, bool? implementsPretest = null, bool? stateAndDiff = null)
|
||||
{
|
||||
var methodObject = new JsonObject
|
||||
{
|
||||
["executable"] = Executable,
|
||||
["args"] = args,
|
||||
};
|
||||
|
||||
if (implementsPretest.HasValue)
|
||||
{
|
||||
methodObject["implementsPretest"] = implementsPretest.Value;
|
||||
}
|
||||
|
||||
if (stateAndDiff.HasValue)
|
||||
{
|
||||
methodObject["return"] = stateAndDiff.Value ? "stateAndDiff" : "state";
|
||||
}
|
||||
|
||||
return methodObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a JSON array from a list of strings.
|
||||
/// </summary>
|
||||
/// <param name="args">The list of strings to convert.</param>
|
||||
/// <returns>Returns the JSON array.</returns>
|
||||
private JsonArray CreateJsonArray(List<string> args)
|
||||
{
|
||||
var jsonArray = new JsonArray();
|
||||
foreach (var arg in args)
|
||||
{
|
||||
jsonArray.Add(arg);
|
||||
}
|
||||
|
||||
return jsonArray;
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
// 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 PowerToys.DSC.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the severity level of a message.
|
||||
/// </summary>
|
||||
public enum DscMessageLevel
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an error message.
|
||||
/// </summary>
|
||||
Error,
|
||||
|
||||
/// <summary>
|
||||
/// Represents a warning message.
|
||||
/// </summary>
|
||||
Warning,
|
||||
|
||||
/// <summary>
|
||||
/// Represents an informational message.
|
||||
/// </summary>
|
||||
Info,
|
||||
|
||||
/// <summary>
|
||||
/// Represents a debug message.
|
||||
/// </summary>
|
||||
Debug,
|
||||
|
||||
/// <summary>
|
||||
/// Represents a trace message.
|
||||
/// </summary>
|
||||
Trace,
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using NJsonSchema.Generation;
|
||||
using PowerToys.DSC.Models.ResourceObjects;
|
||||
|
||||
namespace PowerToys.DSC.Models.FunctionData;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for function data objects.
|
||||
/// </summary>
|
||||
public class BaseFunctionData
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates a JSON schema for the specified resource object type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the resource object.</typeparam>
|
||||
/// <returns>A JSON schema string.</returns>
|
||||
protected static string GenerateSchema<T>()
|
||||
where T : BaseResourceObject
|
||||
{
|
||||
var settings = new SystemTextJsonSchemaGeneratorSettings()
|
||||
{
|
||||
FlattenInheritanceHierarchy = true,
|
||||
SerializerOptions =
|
||||
{
|
||||
IgnoreReadOnlyFields = true,
|
||||
},
|
||||
};
|
||||
var generator = new JsonSchemaGenerator(settings);
|
||||
var schema = generator.Generate(typeof(T));
|
||||
return schema.ToJson(Formatting.None);
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
// 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.Nodes;
|
||||
using PowerToys.DSC.Models.ResourceObjects;
|
||||
|
||||
namespace PowerToys.DSC.Models.FunctionData;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for function data related to settings.
|
||||
/// </summary>
|
||||
public interface ISettingsFunctionData
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the input settings resource object.
|
||||
/// </summary>
|
||||
public ISettingsResourceObject Input { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the output settings resource object.
|
||||
/// </summary>
|
||||
public ISettingsResourceObject Output { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current settings.
|
||||
/// </summary>
|
||||
public void GetState();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current settings.
|
||||
/// </summary>
|
||||
public void SetState();
|
||||
|
||||
/// <summary>
|
||||
/// Tests if the current settings and the desired state are valid.
|
||||
/// </summary>
|
||||
/// <returns>True if the current settings match the desired state; otherwise false.</returns>
|
||||
public bool TestState();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the difference between the current settings and the desired state in JSON format.
|
||||
/// </summary>
|
||||
/// <returns>A JSON array representing the differences.</returns>
|
||||
public JsonArray GetDiffJson();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the schema for the settings resource object.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string Schema();
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
// 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.Diagnostics;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
using PowerToys.DSC.Models.ResourceObjects;
|
||||
|
||||
namespace PowerToys.DSC.Models.FunctionData;
|
||||
|
||||
/// <summary>
|
||||
/// Represents function data for the settings DSC resource.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettingsConfig">The module settings configuration type.</typeparam>
|
||||
public sealed class SettingsFunctionData<TSettingsConfig> : BaseFunctionData, ISettingsFunctionData
|
||||
where TSettingsConfig : ISettingsConfig, new()
|
||||
{
|
||||
private static readonly SettingsUtils _settingsUtils = new();
|
||||
private static readonly TSettingsConfig _settingsConfig = new();
|
||||
|
||||
private readonly SettingsResourceObject<TSettingsConfig> _input;
|
||||
private readonly SettingsResourceObject<TSettingsConfig> _output;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ISettingsResourceObject Input => _input;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ISettingsResourceObject Output => _output;
|
||||
|
||||
public SettingsFunctionData(string? input = null)
|
||||
{
|
||||
_output = new();
|
||||
_input = string.IsNullOrEmpty(input) ? new() : JsonSerializer.Deserialize<SettingsResourceObject<TSettingsConfig>>(input) ?? new();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void GetState()
|
||||
{
|
||||
_output.Settings = GetSettings();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SetState()
|
||||
{
|
||||
Debug.Assert(_output.Settings != null, "Output settings should not be null");
|
||||
SaveSettings(_output.Settings);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TestState()
|
||||
{
|
||||
var input = JsonSerializer.SerializeToNode(_input.Settings);
|
||||
var output = JsonSerializer.SerializeToNode(_output.Settings);
|
||||
return JsonNode.DeepEquals(input, output);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public JsonArray GetDiffJson()
|
||||
{
|
||||
var diff = new JsonArray();
|
||||
if (!TestState())
|
||||
{
|
||||
diff.Add(SettingsResourceObject<TSettingsConfig>.SettingsJsonPropertyName);
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Schema()
|
||||
{
|
||||
return GenerateSchema<SettingsResourceObject<TSettingsConfig>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the settings configuration from the settings utils for a specific module.
|
||||
/// </summary>
|
||||
/// <returns>The settings configuration for the module.</returns>
|
||||
private static TSettingsConfig GetSettings()
|
||||
{
|
||||
return _settingsUtils.GetSettingsOrDefault<TSettingsConfig>(_settingsConfig.GetModuleName());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the settings configuration to the settings utils for a specific module.
|
||||
/// </summary>
|
||||
/// <param name="settings">Settings of a specific module</param>
|
||||
private static void SaveSettings(TSettingsConfig settings)
|
||||
{
|
||||
var inputJson = JsonSerializer.Serialize(settings);
|
||||
_settingsUtils.SaveSettings(inputJson, _settingsConfig.GetModuleName());
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
// 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.ComponentModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
|
||||
namespace PowerToys.DSC.Models.ResourceObjects;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for all resource objects.
|
||||
/// </summary>
|
||||
public class BaseResourceObject
|
||||
{
|
||||
private readonly JsonSerializerOptions _options;
|
||||
|
||||
public BaseResourceObject()
|
||||
{
|
||||
_options = new()
|
||||
{
|
||||
WriteIndented = false,
|
||||
TypeInfoResolver = new DefaultJsonTypeInfoResolver(),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether an instance is in the desired state.
|
||||
/// </summary>
|
||||
[JsonPropertyName("_inDesiredState")]
|
||||
[Description("Indicates whether an instance is in the desired state")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public bool? InDesiredState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Generates a JSON representation of the resource object.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public JsonNode ToJson()
|
||||
{
|
||||
return JsonSerializer.SerializeToNode(this, GetType(), _options) ?? new JsonObject();
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// 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.Nodes;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
|
||||
namespace PowerToys.DSC.Models.ResourceObjects;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for settings resource objects.
|
||||
/// </summary>
|
||||
public interface ISettingsResourceObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the settings configuration.
|
||||
/// </summary>
|
||||
public ISettingsConfig SettingsInternal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether an instance is in the desired state.
|
||||
/// </summary>
|
||||
public bool? InDesiredState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Generates a JSON representation of the resource object.
|
||||
/// </summary>
|
||||
/// <returns>String representation of the resource object in JSON format.</returns>
|
||||
public JsonNode ToJson();
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// 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.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
using NJsonSchema.Annotations;
|
||||
|
||||
namespace PowerToys.DSC.Models.ResourceObjects;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a settings resource object for a module's settings configuration.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettingsConfig">The type of the settings configuration.</typeparam>
|
||||
public sealed class SettingsResourceObject<TSettingsConfig> : BaseResourceObject, ISettingsResourceObject
|
||||
where TSettingsConfig : ISettingsConfig, new()
|
||||
{
|
||||
public const string SettingsJsonPropertyName = "settings";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the settings content for the module.
|
||||
/// </summary>
|
||||
[JsonPropertyName(SettingsJsonPropertyName)]
|
||||
[Required]
|
||||
[Description("The settings content for the module.")]
|
||||
[JsonSchemaType(typeof(object))]
|
||||
public TSettingsConfig Settings { get; set; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
[JsonIgnore]
|
||||
public ISettingsConfig SettingsInternal { get => Settings; set => Settings = (TSettingsConfig)value; }
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
// 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.CommandLine;
|
||||
using System.CommandLine.Parsing;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using PowerToys.DSC.Properties;
|
||||
|
||||
namespace PowerToys.DSC.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an option for specifying JSON input for the dsc command.
|
||||
/// </summary>
|
||||
public sealed class InputOption : Option<string>
|
||||
{
|
||||
private static readonly CompositeFormat InvalidJsonInputError = CompositeFormat.Parse(Resources.InvalidJsonInputError);
|
||||
|
||||
public InputOption()
|
||||
: base("--input", Resources.InputOptionDescription)
|
||||
{
|
||||
AddValidator(OptionValidator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the JSON input provided to the option.
|
||||
/// </summary>
|
||||
/// <param name="result">The option result to validate.</param>
|
||||
private void OptionValidator(OptionResult result)
|
||||
{
|
||||
var value = result.GetValueOrDefault<string>() ?? string.Empty;
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
result.ErrorMessage = Resources.InputEmptyOrNullError;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
JsonDocument.Parse(value);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
result.ErrorMessage = string.Format(CultureInfo.InvariantCulture, InvalidJsonInputError, e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// 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.CommandLine;
|
||||
using PowerToys.DSC.Properties;
|
||||
|
||||
namespace PowerToys.DSC.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an option for specifying the module name for the dsc command.
|
||||
/// </summary>
|
||||
public sealed class ModuleOption : Option<string?>
|
||||
{
|
||||
public ModuleOption()
|
||||
: base("--module", Resources.ModuleOptionDescription)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// 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.CommandLine;
|
||||
using System.CommandLine.Parsing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using PowerToys.DSC.Properties;
|
||||
|
||||
namespace PowerToys.DSC.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an option for specifying the output directory for the dsc command.
|
||||
/// </summary>
|
||||
public sealed class OutputDirectoryOption : Option<string>
|
||||
{
|
||||
private static readonly CompositeFormat InvalidOutputDirectoryError = CompositeFormat.Parse(Resources.InvalidOutputDirectoryError);
|
||||
|
||||
public OutputDirectoryOption()
|
||||
: base("--outputDir", Resources.OutputDirectoryOptionDescription)
|
||||
{
|
||||
AddValidator(OptionValidator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the output directory option.
|
||||
/// </summary>
|
||||
/// <param name="result">The option result to validate.</param>
|
||||
private void OptionValidator(OptionResult result)
|
||||
{
|
||||
var value = result.GetValueOrDefault<string>() ?? string.Empty;
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
result.ErrorMessage = Resources.OutputDirectoryEmptyOrNullError;
|
||||
}
|
||||
else if (!Directory.Exists(value))
|
||||
{
|
||||
result.ErrorMessage = string.Format(CultureInfo.InvariantCulture, InvalidOutputDirectoryError, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// 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.CommandLine;
|
||||
using System.CommandLine.Parsing;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using PowerToys.DSC.Properties;
|
||||
|
||||
namespace PowerToys.DSC.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an option for specifying the resource name for the dsc command.
|
||||
/// </summary>
|
||||
public sealed class ResourceOption : Option<string>
|
||||
{
|
||||
private static readonly CompositeFormat InvalidResourceNameError = CompositeFormat.Parse(Resources.InvalidResourceNameError);
|
||||
|
||||
private readonly IList<string> _resources = [];
|
||||
|
||||
public ResourceOption(IList<string> resources)
|
||||
: base("--resource", Resources.ResourceOptionDescription)
|
||||
{
|
||||
_resources = resources;
|
||||
IsRequired = true;
|
||||
AddValidator(OptionValidator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the resource option to ensure that the specified resource name is valid.
|
||||
/// </summary>
|
||||
/// <param name="result">The option result to validate.</param>
|
||||
private void OptionValidator(OptionResult result)
|
||||
{
|
||||
var value = result.GetValueOrDefault<string>() ?? string.Empty;
|
||||
if (!_resources.Contains(value))
|
||||
{
|
||||
result.ErrorMessage = string.Format(CultureInfo.InvariantCulture, InvalidResourceNameError, string.Join(", ", _resources));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<!-- Look at Directory.Build.props in root for common stuff as well -->
|
||||
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\Common.SelfContained.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<AssemblyName>PowerToys.DSC</AssemblyName>
|
||||
<AssemblyDescription>PowerToys DSC</AssemblyDescription>
|
||||
<RootNamespace>PowerToys.DSC</RootNamespace>
|
||||
<Nullable>enable</Nullable>
|
||||
<!-- Ensure WindowsDesktop runtime pack is included for consistent WindowsBase.dll version -->
|
||||
<UseWPF>true</UseWPF>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NJsonSchema" />
|
||||
<PackageReference Include="System.CommandLine" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</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 "$(TargetPath)" manifest --resource settings --outputDir "$(TargetDir)\"" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -1,29 +0,0 @@
|
||||
// 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.CommandLine;
|
||||
using System.CommandLine.Parsing;
|
||||
using System.Threading.Tasks;
|
||||
using PowerToys.DSC.Commands;
|
||||
|
||||
namespace PowerToys.DSC;
|
||||
|
||||
/// <summary>
|
||||
/// Main entry point for the PowerToys Desired State Configuration CLI application.
|
||||
/// </summary>
|
||||
public class Program
|
||||
{
|
||||
public static async Task<int> Main(string[] args)
|
||||
{
|
||||
var rootCommand = new RootCommand(Properties.Resources.PowerToysDSC);
|
||||
rootCommand.AddCommand(new GetCommand());
|
||||
rootCommand.AddCommand(new SetCommand());
|
||||
rootCommand.AddCommand(new ExportCommand());
|
||||
rootCommand.AddCommand(new TestCommand());
|
||||
rootCommand.AddCommand(new SchemaCommand());
|
||||
rootCommand.AddCommand(new ManifestCommand());
|
||||
rootCommand.AddCommand(new ModulesCommand());
|
||||
return await rootCommand.InvokeAsync(args);
|
||||
}
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace PowerToys.DSC.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PowerToys.DSC.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Get all state instances.
|
||||
/// </summary>
|
||||
internal static string ExportCommandDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("ExportCommandDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Failed to write manifests to directory '{0}': {1}.
|
||||
/// </summary>
|
||||
internal static string FailedToWriteManifests {
|
||||
get {
|
||||
return ResourceManager.GetString("FailedToWriteManifests", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Get the resource state.
|
||||
/// </summary>
|
||||
internal static string GetCommandDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("GetCommandDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Input cannot be empty or null.
|
||||
/// </summary>
|
||||
internal static string InputEmptyOrNullError {
|
||||
get {
|
||||
return ResourceManager.GetString("InputEmptyOrNullError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The JSON input.
|
||||
/// </summary>
|
||||
internal static string InputOptionDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("InputOptionDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Invalid JSON input: {0}.
|
||||
/// </summary>
|
||||
internal static string InvalidJsonInputError {
|
||||
get {
|
||||
return ResourceManager.GetString("InvalidJsonInputError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Invalid output directory: {0}.
|
||||
/// </summary>
|
||||
internal static string InvalidOutputDirectoryError {
|
||||
get {
|
||||
return ResourceManager.GetString("InvalidOutputDirectoryError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Invalid resource name. Valid resource names are: {0}.
|
||||
/// </summary>
|
||||
internal static string InvalidResourceNameError {
|
||||
get {
|
||||
return ResourceManager.GetString("InvalidResourceNameError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Get the manifest of the dsc resource.
|
||||
/// </summary>
|
||||
internal static string ManifestCommandDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("ManifestCommandDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Module '{0}' is not supported for the resource {1}. Use the 'module' command to list available modules..
|
||||
/// </summary>
|
||||
internal static string ModuleNotSupportedByResource {
|
||||
get {
|
||||
return ResourceManager.GetString("ModuleNotSupportedByResource", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The module name.
|
||||
/// </summary>
|
||||
internal static string ModuleOptionDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("ModuleOptionDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Get all supported modules for a specific resource.
|
||||
/// </summary>
|
||||
internal static string ModulesCommandDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("ModulesCommandDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Output directory cannot be empty or null.
|
||||
/// </summary>
|
||||
internal static string OutputDirectoryEmptyOrNullError {
|
||||
get {
|
||||
return ResourceManager.GetString("OutputDirectoryEmptyOrNullError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The output directory.
|
||||
/// </summary>
|
||||
internal static string OutputDirectoryOptionDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("OutputDirectoryOptionDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to PowerToys Desired State Configuration commands.
|
||||
/// </summary>
|
||||
internal static string PowerToysDSC {
|
||||
get {
|
||||
return ResourceManager.GetString("PowerToysDSC", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The resource name.
|
||||
/// </summary>
|
||||
internal static string ResourceOptionDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("ResourceOptionDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Outputs schema of the resource.
|
||||
/// </summary>
|
||||
internal static string SchemaCommandDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("SchemaCommandDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Set the resource state.
|
||||
/// </summary>
|
||||
internal static string SetCommandDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("SetCommandDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Test the resource state.
|
||||
/// </summary>
|
||||
internal static string TestCommandDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("TestCommandDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,156 @@
|
||||
<!-- Other merged dictionaries here -->
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<!-- Other app resources here -->
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Default">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SystemColorHighlightTextColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SystemColorHighlightColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SystemColorHighlightColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SystemColorGrayTextColor" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="SystemColorButtonTextColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<Style x:Key="SubtleButtonStyle" TargetType="Button">
|
||||
<Setter Property="Background" Value="{ThemeResource SubtleButtonBackground}" />
|
||||
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
|
||||
<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="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<ContentPresenter
|
||||
x:Name="ContentPresenter"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
AnimatedIcon.State="Normal"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Background="{TemplateBinding Background}"
|
||||
BackgroundSizing="{TemplateBinding BackgroundSizing}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
ContentTransitions="{TemplateBinding ContentTransitions}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}"
|
||||
Foreground="{TemplateBinding Foreground}">
|
||||
<ContentPresenter.BackgroundTransition>
|
||||
<BrushTransition Duration="0:0:0.083" />
|
||||
</ContentPresenter.BackgroundTransition>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="PointerOver">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="PointerOver" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Pressed">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Pressed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Disabled">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" 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="ContentPresenter.(AnimatedIcon.State)" Value="Normal" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</ContentPresenter>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
||||
@@ -20,14 +20,27 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<TitleBar x:Name="titleBar">
|
||||
<!-- This is a workaround for https://github.com/microsoft/microsoft-ui-xaml/issues/10374, once fixed we should just be using IconSource -->
|
||||
<TitleBar.LeftHeader>
|
||||
<ImageIcon
|
||||
Height="16"
|
||||
Margin="16,0,0,0"
|
||||
Source="/Assets/EnvironmentVariables/EnvironmentVariables.ico" />
|
||||
</TitleBar.LeftHeader>
|
||||
</TitleBar>
|
||||
<Grid
|
||||
x:Name="titleBar"
|
||||
Height="32"
|
||||
ColumnSpacing="16">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition x:Name="LeftPaddingColumn" Width="0" />
|
||||
<ColumnDefinition x:Name="IconColumn" Width="Auto" />
|
||||
<ColumnDefinition x:Name="TitleColumn" Width="Auto" />
|
||||
<ColumnDefinition x:Name="RightPaddingColumn" Width="0" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image
|
||||
Grid.Column="1"
|
||||
Width="16"
|
||||
Height="16"
|
||||
VerticalAlignment="Center"
|
||||
Source="../Assets/EnvironmentVariables/EnvironmentVariables.ico" />
|
||||
<TextBlock
|
||||
x:Name="AppTitleTextBlock"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</winuiex:WindowEx>
|
||||
|
||||
@@ -4,19 +4,22 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using EnvironmentVariables.Win32;
|
||||
using EnvironmentVariablesUILib;
|
||||
using EnvironmentVariablesUILib.Helpers;
|
||||
using EnvironmentVariablesUILib.ViewModels;
|
||||
using ManagedCommon;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using WinUIEx;
|
||||
|
||||
namespace EnvironmentVariables
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty window that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class MainWindow : WindowEx
|
||||
{
|
||||
private EnvironmentVariablesMainPage MainPage { get; }
|
||||
@@ -31,9 +34,8 @@ namespace EnvironmentVariables
|
||||
AppWindow.SetIcon("Assets/EnvironmentVariables/EnvironmentVariables.ico");
|
||||
var loader = ResourceLoaderInstance.ResourceLoader;
|
||||
var title = App.GetService<IElevationHelper>().IsElevated ? loader.GetString("WindowAdminTitle") : loader.GetString("WindowTitle");
|
||||
|
||||
Title = title;
|
||||
titleBar.Title = title;
|
||||
AppTitleTextBlock.Text = title;
|
||||
|
||||
var handle = this.GetWindowHandle();
|
||||
RegisterWindow(handle);
|
||||
|
||||
@@ -21,6 +21,157 @@
|
||||
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.SettingsControls/SettingsExpander/SettingsExpander.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Default">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SystemColorHighlightTextColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SystemColorHighlightColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SystemColorHighlightColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SystemColorGrayTextColor" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="SystemColorButtonTextColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
|
||||
</ResourceDictionary>
|
||||
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<Style x:Key="SubtleButtonStyle" TargetType="Button">
|
||||
<Setter Property="Background" Value="{ThemeResource SubtleButtonBackground}" />
|
||||
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
|
||||
<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="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<ContentPresenter
|
||||
x:Name="ContentPresenter"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
AnimatedIcon.State="Normal"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Background="{TemplateBinding Background}"
|
||||
BackgroundSizing="{TemplateBinding BackgroundSizing}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
ContentTransitions="{TemplateBinding ContentTransitions}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}"
|
||||
Foreground="{TemplateBinding Foreground}">
|
||||
<ContentPresenter.BackgroundTransition>
|
||||
<BrushTransition Duration="0:0:0.083" />
|
||||
</ContentPresenter.BackgroundTransition>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="PointerOver">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="PointerOver" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Pressed">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Pressed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Disabled">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" 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="ContentPresenter.(AnimatedIcon.State)" Value="Normal" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</ContentPresenter>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<x:Double x:Key="SecondaryTextFontSize">12</x:Double>
|
||||
<Style x:Key="SecondaryTextStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontSize" Value="{StaticResource SecondaryTextFontSize}" />
|
||||
|
||||
@@ -9,6 +9,157 @@
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
<!-- Other merged dictionaries here -->
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Default">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SystemColorHighlightTextColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SystemColorHighlightColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SystemColorHighlightColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SystemColorGrayTextColor" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="SystemColorButtonTextColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
|
||||
</ResourceDictionary>
|
||||
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<Style x:Key="SubtleButtonStyle" TargetType="Button">
|
||||
<Setter Property="Background" Value="{ThemeResource SubtleButtonBackground}" />
|
||||
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
|
||||
<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="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<ContentPresenter
|
||||
x:Name="ContentPresenter"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
AnimatedIcon.State="Normal"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Background="{TemplateBinding Background}"
|
||||
BackgroundSizing="{TemplateBinding BackgroundSizing}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
ContentTransitions="{TemplateBinding ContentTransitions}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}"
|
||||
Foreground="{TemplateBinding Foreground}">
|
||||
<ContentPresenter.BackgroundTransition>
|
||||
<BrushTransition Duration="0:0:0.083" />
|
||||
</ContentPresenter.BackgroundTransition>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="PointerOver">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="PointerOver" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Pressed">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Pressed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Disabled">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" 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="ContentPresenter.(AnimatedIcon.State)" Value="Normal" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</ContentPresenter>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
||||