Compare commits

..

2 Commits

Author SHA1 Message Date
vanzue
2b568e93dc dev 2025-10-31 10:42:28 +08:00
vanzue
4b1e0f6220 cli 2025-10-30 22:49:16 +08:00
152 changed files with 6333 additions and 7389 deletions

View File

@@ -47,7 +47,6 @@ resw
resx
srt
Stereolithography
taskmgr
terabyte
UYVY
xbf
@@ -320,9 +319,5 @@ MRUCMPPROC
MRUINFO
REGSTR
#Xaml
NVI
Storyboards
# Misc Win32 APIs and PInvokes
INVOKEIDLIST

View File

@@ -97,7 +97,6 @@ atl
ATX
ATRIOX
aumid
authenticode
Authenticode
AUTOBUDDY
AUTOCHECKBOX
@@ -143,7 +142,6 @@ bmi
BNumber
BODGY
BOklab
Bootstrappers
BOOTSTRAPPERINSTALLFOLDER
BOTTOMALIGN
boxmodel
@@ -806,8 +804,6 @@ jpnime
Jsons
jsonval
jxr
KBSC
kdc
keybd
KEYBDDATA
KEYBDINPUT
@@ -1034,7 +1030,6 @@ msiexec
MSIFASTINSTALL
MSIHANDLE
MSIRESTARTMANAGERCONTROL
MSIs
msixbundle
MSIXCA
MSLLHOOKSTRUCT
@@ -1201,7 +1196,6 @@ OUTOFCONTEXT
Outptr
outputtype
outsettings
outsourced
OVERLAPPEDWINDOW
Oversampling
OVERWRITEPROMPT
@@ -1265,7 +1259,6 @@ phwnd
pici
pidl
PIDLIST
pinboard
pinfo
pinvoke
pipename
@@ -1344,7 +1337,6 @@ projectname
PROPERTYKEY
Propset
PROPVARIANT
Prt
PRTL
prvpane
psapi
@@ -1997,7 +1989,6 @@ WNDCLASSW
WNDPROC
wnode
wom
workerw
WORKSPACESEDITOR
WORKSPACESLAUNCHER
WORKSPACESSNAPSHOTTOOL

View File

@@ -220,12 +220,8 @@
"WinUI3Apps\\PowerToys.RegistryPreview.dll",
"WinUI3Apps\\PowerToys.RegistryPreview.exe",
"WinUI3Apps\\PowerToys.ShortcutGuide.exe",
"WinUI3Apps\\PowerToys.ShortcutGuide.dll",
"WinUI3Apps\\PowerToys.ShortcutGuideModuleInterface.dll",
"WinUI3Apps\\PowerToys.ShortcutGuide.IndexYmlGenerator.dll",
"WinUI3Apps\\PowerToys.ShortcutGuide.IndexYmlGenerator.exe",
"WinUI3Apps\\ShortcutGuide.CPPProject.dll",
"PowerToys.ShortcutGuide.exe",
"PowerToys.ShortcutGuideModuleInterface.dll",
"PowerToys.ZoomIt.exe",
"PowerToys.ZoomItModuleInterface.dll",

View File

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

View File

@@ -512,6 +512,14 @@ jobs:
versionNumber: ${{ parameters.versionNumber }}
additionalBuildOptions: ${{ parameters.additionalBuildOptions }}
- template: steps-build-installer-vnext.yml
parameters:
codeSign: ${{ parameters.codeSign }}
signingIdentity: ${{ parameters.signingIdentity }}
versionNumber: ${{ parameters.versionNumber }}
additionalBuildOptions: ${{ parameters.additionalBuildOptions }}
buildUserInstaller: true # NOTE: This is the distinction between the above and below rules
# This saves ~1GiB per architecture. We won't need these later.
# Removes:
# - All .pdb files from any static libs .libs (which were only used during linking)

View File

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

View File

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

View File

@@ -113,7 +113,6 @@
<PackageVersion Include="WinUIEx" Version="2.8.0" />
<PackageVersion Include="WPF-UI" Version="3.0.5" />
<PackageVersion Include="WyHash" Version="1.0.5" />
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
<PackageVersion Include="WixToolset.Heat" Version="5.0.2" />
<PackageVersion Include="WixToolset.Firewall.wixext" Version="5.0.2" />
<PackageVersion Include="WixToolset.Util.wixext" Version="5.0.2" />

View File

@@ -1537,5 +1537,4 @@ SOFTWARE.
- UTF.Unknown
- WinUIEx
- WPF-UI
- WyHash
- YamlDotNet
- WyHash

View File

@@ -42,7 +42,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "fancyzones", "fancyzones",
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FancyZonesLib", "src\modules\fancyzones\FancyZonesLib\FancyZonesLib.vcxproj", "{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests", "src\modules\fancyzones\FancyZonesTests\UnitTests\UnitTests.vcxproj", "{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FancyZones.UnitTests", "src\modules\fancyzones\FancyZonesTests\UnitTests\UnitTests.vcxproj", "{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}"
ProjectSection(ProjectDependencies) = postProject
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99} = {F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}
EndProjectSection
@@ -66,7 +66,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameLib", "src\modul
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameTest", "src\modules\powerrename\testapp\PowerRenameTest.vcxproj", "{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameLibUnitTests", "src\modules\powerrename\unittests\PowerRenameLibUnitTests.vcxproj", "{2151F984-E006-4A9F-92EF-C6DDE3DC8413}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRename.UnitTests", "src\modules\powerrename\unittests\PowerRenameLibUnitTests.vcxproj", "{2151F984-E006-4A9F-92EF-C6DDE3DC8413}"
ProjectSection(ProjectDependencies) = postProject
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
{B25AC7A5-FB9F-4789-B392-D5C85E948670} = {B25AC7A5-FB9F-4789-B392-D5C85E948670}
@@ -74,6 +74,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameLibUnitTests", "
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ModuleTemplateCompileTest", "tools\project_template\ModuleTemplate\ModuleTemplateCompileTest.vcxproj", "{64A80062-4D8B-4229-8A38-DFA1D7497749}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ptcli", "tools\ptcli\ptcli.csproj", "{2589570C-B068-41CA-A554-BDCAE6FC4CAC}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManager", "src\modules\keyboardmanager\dll\KeyboardManager.vcxproj", "{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "imageresizer", "imageresizer", "{6C7F47CC-2151-44A3-A546-41C70025132C}"
@@ -316,13 +318,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEngine", "sr
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEngineLibrary", "src\modules\keyboardmanager\KeyboardManagerEngineLibrary\KeyboardManagerEngineLibrary.vcxproj", "{E496B7FC-1E99-4BAB-849B-0E8367040B02}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEngineTest", "src\modules\keyboardmanager\KeyboardManagerEngineTest\KeyboardManagerEngineTest.vcxproj", "{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManager.Engine.UnitTests", "src\modules\keyboardmanager\KeyboardManagerEngineTest\KeyboardManagerEngineTest.vcxproj", "{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEditor", "src\modules\keyboardmanager\KeyboardManagerEditor\KeyboardManagerEditor.vcxproj", "{8DF78B53-200E-451F-9328-01EB907193AE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEditorLibrary", "src\modules\keyboardmanager\KeyboardManagerEditorLibrary\KeyboardManagerEditorLibrary.vcxproj", "{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEditorTest", "src\modules\keyboardmanager\KeyboardManagerEditorTest\KeyboardManagerEditorTest.vcxproj", "{62173D9A-6724-4C00-A1C8-FB646480A9EC}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManager.Editor.UnitTests", "src\modules\keyboardmanager\KeyboardManagerEditorTest\KeyboardManagerEditorTest.vcxproj", "{62173D9A-6724-4C00-A1C8-FB646480A9EC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "awake", "awake", "{127F38E0-40AA-4594-B955-5616BF206882}"
EndProject
@@ -334,6 +336,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Community.PowerToys.Run.Plu
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Community.PowerToys.Run.Plugin.UnitConverter.UnitTest", "src\modules\launcher\Plugins\Community.PowerToys.Run.Plugin.UnitConverter.UnitTest\Community.PowerToys.Run.Plugin.UnitConverter.UnitTest.csproj", "{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shortcutguide", "shortcutguide", "{106CBECA-0701-4FC3-838C-9DF816A19AE2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShortcutGuideModuleInterface", "src\modules\ShortcutGuide\ShortcutGuideModuleInterface\ShortcutGuideModuleInterface.vcxproj", "{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShortcutGuide", "src\modules\ShortcutGuide\ShortcutGuide\ShortcutGuide.vcxproj", "{2EDB3EB4-FA92-4BFF-B2D8-566584837231}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FancyZonesModuleInterface", "src\modules\fancyzones\FancyZonesModuleInterface\FancyZonesModuleInterface.vcxproj", "{48804216-2A0E-4168-A6D8-9CD068D14227}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FancyZones", "src\modules\fancyzones\FancyZones\FancyZones.vcxproj", "{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}"
@@ -445,7 +453,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FileLocksmithExt", "src\mod
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileLocksmithUI", "src\modules\FileLocksmith\FileLocksmithUI\FileLocksmithUI.csproj", "{E69B044A-2F8A-45AA-AD0B-256C59421807}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FileLocksmithLibInterop", "src\modules\FileLocksmith\FileLocksmithLibInterop\FileLocksmithLibInterop.vcxproj", "{C604B37E-9D0E-4484-8778-E8B31B0E1B3A}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerToys.FileLocksmithLib.Interop", "src\modules\FileLocksmith\FileLocksmithLibInterop\FileLocksmithLibInterop.vcxproj", "{C604B37E-9D0E-4484-8778-E8B31B0E1B3A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GPOWrapper", "src\common\GPOWrapper\GPOWrapper.vcxproj", "{E599C30B-9DC8-4E5A-BF27-93D4CCEDE788}"
EndProject
@@ -453,7 +461,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GPOWrapperProjection", "src
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Peek", "Peek", "{17B4FA70-001E-4D33-BBBB-0D142DBC2E20}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "peek", "src\modules\peek\peek\peek.vcxproj", "{A1425B53-3D61-4679-8623-E64A0D3D0A48}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Peek", "src\modules\peek\peek\peek.vcxproj", "{A1425B53-3D61-4679-8623-E64A0D3D0A48}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Peek.UI", "src\modules\peek\Peek.UI\Peek.UI.csproj", "{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}"
EndProject
@@ -568,7 +576,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerToys.Settings.DSC.Sche
{020A7474-3601-4160-A159-D7B70B77B15F} = {020A7474-3601-4160-A159-D7B70B77B15F}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NewShellExtensionContextMenu", "src\modules\NewPlus\NewShellExtensionContextMenu\NewShellExtensionContextMenu.vcxproj", "{8ACB33D9-C95B-47D4-8363-9731EE0930A0}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NewPlus.ShellExtension", "src\modules\NewPlus\NewShellExtensionContextMenu\NewShellExtensionContextMenu.vcxproj", "{8ACB33D9-C95B-47D4-8363-9731EE0930A0}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "New+", "New+", "{CA716AE6-FE5C-40AC-BB8F-2C87912687AC}"
EndProject
@@ -697,7 +705,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.System
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdPalKeyboardService", "src\modules\cmdpal\CmdPalKeyboardService\CmdPalKeyboardService.vcxproj", "{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRename.FuzzingTest", "src\modules\powerrename\PowerRename.FuzzingTest\PowerRename.FuzzingTest.vcxproj", "{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRename.FuzzTests", "src\modules\powerrename\PowerRename.FuzzingTest\PowerRename.FuzzingTest.vcxproj", "{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BgcodePreviewHandler", "src\modules\previewpane\BgcodePreviewHandler\BgcodePreviewHandler.csproj", "{9E0CBC06-F29A-4810-B93C-97D53863B95E}"
EndProject
@@ -824,16 +832,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Clipbo
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.UI.ViewModels.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.UI.ViewModels.UnitTests\Microsoft.CmdPal.UI.ViewModels.UnitTests.csproj", "{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ShortcutGuide", "ShortcutGuide", "{17A43950-5FA1-47AC-A4E7-2E6E4A3C32D5}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShortcutGuide.CPPProject", "src\modules\ShortcutGuide\ShortcutGuide.CPPProject\ShortcutGuide.CPPProject.vcxproj", "{C992FD2C-83B8-4941-9FC1-09730068D8EC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShortcutGuide.IndexYmlGenerator", "src\modules\ShortcutGuide\ShortcutGuide.IndexYmlGenerator\ShortcutGuide.IndexYmlGenerator.csproj", "{30F57201-9B54-5253-8033-8A28ECD3F1CE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShortcutGuide.Ui", "src\modules\ShortcutGuide\ShortcutGuide.Ui\ShortcutGuide.Ui.csproj", "{D5BD72DD-B461-FDD4-FD7D-AF0B620AE75D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShortcutGuideModuleInterface", "src\modules\ShortcutGuide\ShortcutGuideModuleInterface\ShortcutGuideModuleInterface.vcxproj", "{E487304A-B1FB-4E6B-8E70-014051AF5B99}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
@@ -930,6 +928,14 @@ Global
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|ARM64.Build.0 = Release|ARM64
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|x64.ActiveCfg = Release|x64
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|x64.Build.0 = Release|x64
{2589570C-B068-41CA-A554-BDCAE6FC4CAC}.Debug|ARM64.ActiveCfg = Debug|ARM64
{2589570C-B068-41CA-A554-BDCAE6FC4CAC}.Debug|ARM64.Build.0 = Debug|ARM64
{2589570C-B068-41CA-A554-BDCAE6FC4CAC}.Debug|x64.ActiveCfg = Debug|x64
{2589570C-B068-41CA-A554-BDCAE6FC4CAC}.Debug|x64.Build.0 = Debug|x64
{2589570C-B068-41CA-A554-BDCAE6FC4CAC}.Release|ARM64.ActiveCfg = Release|ARM64
{2589570C-B068-41CA-A554-BDCAE6FC4CAC}.Release|ARM64.Build.0 = Release|ARM64
{2589570C-B068-41CA-A554-BDCAE6FC4CAC}.Release|x64.ActiveCfg = Release|x64
{2589570C-B068-41CA-A554-BDCAE6FC4CAC}.Release|x64.Build.0 = Release|x64
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Debug|ARM64.ActiveCfg = Debug|ARM64
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Debug|ARM64.Build.0 = Debug|ARM64
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Debug|x64.ActiveCfg = Debug|x64
@@ -1474,6 +1480,22 @@ Global
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|ARM64.Build.0 = Release|ARM64
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x64.ActiveCfg = Release|x64
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x64.Build.0 = Release|x64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|ARM64.ActiveCfg = Debug|ARM64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|ARM64.Build.0 = Debug|ARM64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|x64.ActiveCfg = Debug|x64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|x64.Build.0 = Debug|x64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Release|ARM64.ActiveCfg = Release|ARM64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Release|ARM64.Build.0 = Release|ARM64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Release|x64.ActiveCfg = Release|x64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Release|x64.Build.0 = Release|x64
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Debug|ARM64.ActiveCfg = Debug|ARM64
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Debug|ARM64.Build.0 = Debug|ARM64
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Debug|x64.ActiveCfg = Debug|x64
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Debug|x64.Build.0 = Debug|x64
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|ARM64.ActiveCfg = Release|ARM64
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|ARM64.Build.0 = Release|ARM64
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|x64.ActiveCfg = Release|x64
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|x64.Build.0 = Release|x64
{48804216-2A0E-4168-A6D8-9CD068D14227}.Debug|ARM64.ActiveCfg = Debug|ARM64
{48804216-2A0E-4168-A6D8-9CD068D14227}.Debug|ARM64.Build.0 = Debug|ARM64
{48804216-2A0E-4168-A6D8-9CD068D14227}.Debug|x64.ActiveCfg = Debug|x64
@@ -3004,38 +3026,6 @@ Global
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}.Release|ARM64.Build.0 = Release|ARM64
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}.Release|x64.ActiveCfg = Release|x64
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}.Release|x64.Build.0 = Release|x64
{C992FD2C-83B8-4941-9FC1-09730068D8EC}.Debug|ARM64.ActiveCfg = Debug|ARM64
{C992FD2C-83B8-4941-9FC1-09730068D8EC}.Debug|ARM64.Build.0 = Debug|ARM64
{C992FD2C-83B8-4941-9FC1-09730068D8EC}.Debug|x64.ActiveCfg = Debug|x64
{C992FD2C-83B8-4941-9FC1-09730068D8EC}.Debug|x64.Build.0 = Debug|x64
{C992FD2C-83B8-4941-9FC1-09730068D8EC}.Release|ARM64.ActiveCfg = Release|ARM64
{C992FD2C-83B8-4941-9FC1-09730068D8EC}.Release|ARM64.Build.0 = Release|ARM64
{C992FD2C-83B8-4941-9FC1-09730068D8EC}.Release|x64.ActiveCfg = Release|x64
{C992FD2C-83B8-4941-9FC1-09730068D8EC}.Release|x64.Build.0 = Release|x64
{30F57201-9B54-5253-8033-8A28ECD3F1CE}.Debug|ARM64.ActiveCfg = Debug|ARM64
{30F57201-9B54-5253-8033-8A28ECD3F1CE}.Debug|ARM64.Build.0 = Debug|ARM64
{30F57201-9B54-5253-8033-8A28ECD3F1CE}.Debug|x64.ActiveCfg = Debug|x64
{30F57201-9B54-5253-8033-8A28ECD3F1CE}.Debug|x64.Build.0 = Debug|x64
{30F57201-9B54-5253-8033-8A28ECD3F1CE}.Release|ARM64.ActiveCfg = Release|ARM64
{30F57201-9B54-5253-8033-8A28ECD3F1CE}.Release|ARM64.Build.0 = Release|ARM64
{30F57201-9B54-5253-8033-8A28ECD3F1CE}.Release|x64.ActiveCfg = Release|x64
{30F57201-9B54-5253-8033-8A28ECD3F1CE}.Release|x64.Build.0 = Release|x64
{D5BD72DD-B461-FDD4-FD7D-AF0B620AE75D}.Debug|ARM64.ActiveCfg = Debug|ARM64
{D5BD72DD-B461-FDD4-FD7D-AF0B620AE75D}.Debug|ARM64.Build.0 = Debug|ARM64
{D5BD72DD-B461-FDD4-FD7D-AF0B620AE75D}.Debug|x64.ActiveCfg = Debug|x64
{D5BD72DD-B461-FDD4-FD7D-AF0B620AE75D}.Debug|x64.Build.0 = Debug|x64
{D5BD72DD-B461-FDD4-FD7D-AF0B620AE75D}.Release|ARM64.ActiveCfg = Release|ARM64
{D5BD72DD-B461-FDD4-FD7D-AF0B620AE75D}.Release|ARM64.Build.0 = Release|ARM64
{D5BD72DD-B461-FDD4-FD7D-AF0B620AE75D}.Release|x64.ActiveCfg = Release|x64
{D5BD72DD-B461-FDD4-FD7D-AF0B620AE75D}.Release|x64.Build.0 = Release|x64
{E487304A-B1FB-4E6B-8E70-014051AF5B99}.Debug|ARM64.ActiveCfg = Debug|ARM64
{E487304A-B1FB-4E6B-8E70-014051AF5B99}.Debug|ARM64.Build.0 = Debug|ARM64
{E487304A-B1FB-4E6B-8E70-014051AF5B99}.Debug|x64.ActiveCfg = Debug|x64
{E487304A-B1FB-4E6B-8E70-014051AF5B99}.Debug|x64.Build.0 = Debug|x64
{E487304A-B1FB-4E6B-8E70-014051AF5B99}.Release|ARM64.ActiveCfg = Release|ARM64
{E487304A-B1FB-4E6B-8E70-014051AF5B99}.Release|ARM64.Build.0 = Release|ARM64
{E487304A-B1FB-4E6B-8E70-014051AF5B99}.Release|x64.ActiveCfg = Release|x64
{E487304A-B1FB-4E6B-8E70-014051AF5B99}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -3131,6 +3121,9 @@ Global
{D940E07F-532C-4FF3-883F-790DA014F19A} = {127F38E0-40AA-4594-B955-5616BF206882}
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1} = {B9617A31-0F0A-4397-851D-BF2FBEE32D7F}
{106CBECA-0701-4FC3-838C-9DF816A19AE2} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81} = {106CBECA-0701-4FC3-838C-9DF816A19AE2}
{2EDB3EB4-FA92-4BFF-B2D8-566584837231} = {106CBECA-0701-4FC3-838C-9DF816A19AE2}
{48804216-2A0E-4168-A6D8-9CD068D14227} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{5043CECE-E6A7-4867-9CBE-02D27D83747A} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
@@ -3362,11 +3355,6 @@ Global
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F} = {3DCCD936-D085-4869-A1DE-CA6A64152C94}
{4E0FCF69-B06B-D272-76BF-ED3A559B4EDA} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{17A43950-5FA1-47AC-A4E7-2E6E4A3C32D5} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{C992FD2C-83B8-4941-9FC1-09730068D8EC} = {17A43950-5FA1-47AC-A4E7-2E6E4A3C32D5}
{30F57201-9B54-5253-8033-8A28ECD3F1CE} = {17A43950-5FA1-47AC-A4E7-2E6E4A3C32D5}
{D5BD72DD-B461-FDD4-FD7D-AF0B620AE75D} = {17A43950-5FA1-47AC-A4E7-2E6E4A3C32D5}
{E487304A-B1FB-4E6B-8E70-014051AF5B99} = {17A43950-5FA1-47AC-A4E7-2E6E4A3C32D5}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}

2
deps/cziplib vendored

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -9,14 +9,12 @@
[Pull Requests](https://github.com/microsoft/PowerToys/pulls?q=is%3Apr+is%3Aopen+label%3A%22Product-Shortcut+Guide%22+)
## Overview
Shortcut Guide is a PowerToy that displays an overlay of available keyboard shortcuts when a user-set keyboard shortcut is pressed. It helps users discover and remember keyboard shortcuts for Windows and apps.
> [!NOTE]
> The spec for the manifest files is in development and will be linked here once available.
Shortcut Guide is a PowerToy that displays an overlay of available keyboard shortcuts when the Windows key is pressed and held. It provides a visual reference for Windows key combinations, helping users discover and utilize built-in Windows shortcuts.
## Usage
- Press the user-defined hotkey to display the overlay
- Press the hotkey again or press ESC to dismiss the overlay
- Press and hold the Windows key to display the overlay of available shortcuts
- Press the hotkey again to dismiss the overlay
- The overlay displays Windows shortcuts with their corresponding actions
## Build and Debug Instructions
@@ -27,83 +25,67 @@ Shortcut Guide is a PowerToy that displays an overlay of available keyboard shor
4. The executable is named PowerToys.ShortcutGuide.exe
### Debug
1. Right-click the ShortcutGuide.Ui project and select 'Set as Startup Project'
1. Right-click the ShortcutGuide project and select 'Set as Startup Project'
2. Right-click the project again and select 'Debug'
> [!NOTE]
> When run in debug mode, the window behaves differently than in release mode. It will not automatically close when loosing focus, it will be displayed on top of all other windows, and it is not hidden from the taskbar.
## Code Structure
## Project Structure
![Diagram](../images/shortcutguide/diagram.png)
The Shortcut Guide module consists of the following 4 projects:
### Core Files
### [`ShortcutGuide.Ui`](/src/modules/ShortcutGuide/ShortcutGuide.Ui/ShortcutGuide.Ui.csproj
#### [`dllmain.cpp`](/src/modules/shortcut_guide/dllmain.cpp)
Contains DLL boilerplate code. Implements the PowertoyModuleIface, including enable/disable functionality and GPO policy handling. Captures hotkey events and starts the PowerToys.ShortcutGuide.exe process to display the shortcut guide window.
This is the main UI project for the Shortcut Guide module. Upon startup it does the following tasks:
#### [`shortcut_guide.cpp`](/src/modules/shortcut_guide/shortcut_guide.cpp)
Contains the module interface code. It initializes the settings values and the keyboard event listener. Defines the OverlayWindow class, which manages the overall logic and event handling for the PowerToys Shortcut Guide.
1. Copies the built-in manifest files to the users manifest directory (overwriting existing files).
2. Generate the `index.yml` manifest file.
3. Populate the PowerToys shortcut manifest with the user-defined shortcuts.
4. Starts the UI.
#### [`overlay_window.cpp`](/src/modules/shortcut_guide/overlay_window.cpp)
Contains the code for loading the SVGs, creating and rendering of the overlay window. Manages and displays overlay windows with SVG graphics through two main classes:
- D2DOverlaySVG: Handles loading, resizing, and manipulation of SVG graphics
- D2DOverlayWindow: Manages the display and behavior of the overlay window
### [`ShortcutGuide.CPPProject`](/src/modules/ShortcutGuide/ShortcutGuide.CPPProject/ShortcutGuide.CPPProject.vcxproj)
#### [`keyboard_state.cpp`](/src/modules/shortcut_guide/keyboard_state.cpp)
Contains helper methods for checking the current state of the keyboard.
This project exports certain functions to be used by the Shortcut Guide module, that were not able to be implemented in C#.
#### [`target_state.cpp`](/src/modules/shortcut_guide/target_state.cpp)
State machine that handles the keyboard events. It's responsible for deciding when to show the overlay, when to suppress the Start menu (if the overlay is displayed long enough), etc. Handles state transitions and synchronization to ensure the overlay is shown or hidden appropriately based on user interactions.
#### [`excluded_app.cpp`](/src/modules/ShortcutGuide/ShortcutGuide.CPPProject/excluded_app.cpp)
#### [`trace.cpp`](/src/modules/shortcut_guide/trace.cpp)
Contains code for telemetry.
This file contains one function with the following signature:
### Supporting Files
```cpp
__declspec(dllexport) bool IsCurrentWindowExcludedFromShortcutGuide()
```
#### [`animation.cpp`](/src/modules/shortcut_guide/animation.cpp)
Handles the timing and interpolation of animations. Calculates the current value of an animation based on elapsed time and a specified easing function.
This function checks if the current window is excluded from the Shortcut Guide overlay. It returns `true` if the current window is excluded otherwise it returns `false`.
#### [`d2d_svg.cpp`](/src/modules/shortcut_guide/d2d_svg.cpp)
Provides functionality for loading, resizing, recoloring, rendering, and manipulating SVG images using Direct2D.
#### [`tasklist_positions.cpp`](/src/modules/ShortcutGuide/ShortcutGuide.CPPProject/tasklist_positions.cpp)
#### [`d2d_text.cpp`](/src/modules/shortcut_guide/d2d_text.cpp)
Handles creation, resizing, alignment, and rendering of text using Direct2D and DirectWrite.
This file contains helper functions to retrieve the positions of the taskbar buttons. It exports the following function:
#### [`d2d_window.cpp`](/src/modules/shortcut_guide/d2d_window.cpp)
Manages a window using Direct2D and Direct3D for rendering. Handles window creation, resizing, rendering, and destruction.
```cpp
__declspec(dllexport) TasklistButton* get_buttons(HMONITOR monitor, int* size)
```
#### [`native_event_waiter.cpp`](/src/modules/shortcut_guide/native_event_waiter.cpp)
Waits for a named event and executes a specified action when the event is triggered. Uses a separate thread to handle event waiting and action execution.
This function retrieves the positions of the taskbar buttons for a given monitor. It returns an array of `TasklistButton` structures (max 10), which contain the position and size of each button.
#### [`tasklist_positions.cpp`](/src/modules/shortcut_guide/tasklist_positions.cpp)
Handles retrieving and updating the positions and information of taskbar buttons in Windows.
`monitor` must be the monitor handle of the monitor containing the taskbar instance of which the buttons should be retrieved.
`size` will contain the resulting array size.
It determines the positions through Windows `FindWindowEx` function.
For the primary taskbar it searches for:
* A window called "Shell_TrayWnd"
* that contains a window called "ReBarWindow32"
* that contains a window called "MSTaskSwWClass"
* that contains a window called "MSTaskListWClass"
For any secondary taskbar it searches for:
* A window called "Shell_SecondaryTrayWnd"
* that contains a window called "WorkerW"
* that contains a window called "MSTaskListWClass"
It then enumerates all the button elements inside "MSTaskListWClass" while skipping such with a same name (which implies the user does not use combining taskbar buttons)
### [`ShortcutGuide.IndexYmlGenerator`](/src/modules/ShortcutGuide/ShortcutGuide.IndexYmlGenerator/)
This application generates the `index.yml` manifest file.
It is a separate project so that its code can be easier ported to WinGet in the future.
### [`ShortcutGuideModuleInterface`](/src/modules/ShortcutGuide/ShortcutGuideModuleInterface/ShortcutGuideModuleInterface.vcxproj)
The module interface that handles opening and closing the user interface.
#### [`main.cpp`](/src/modules/shortcut_guide/main.cpp)
The entry point for the PowerToys Shortcut Guide application. Handles initialization, ensures single instance execution, manages parent process termination, creates and displays the overlay window, and runs the main event loop.
## Features and Limitations
- Currently the displayed shortcuts (Except the ones from PowerToys) are not localized.
- The overlay displays Windows shortcuts (Windows key combinations)
- The module supports localization, but only for the Windows controls on the left side of the overlay
- It's currently rated as a P3 (lower priority) module
## Future Development
- Implementing with WinGet to get new shortcut manifest files
- Adding localization support for the built-in manifest files
A community-contributed version 2 is in development that will support:
- Application-specific shortcuts based on the active application
- Additional shortcuts beyond Windows key combinations
- PowerToys shortcuts

View File

@@ -1,318 +0,0 @@
# WinGet Manifest Keyboard Shortcuts schema
## 1 What this spec is about
This spec provides an extension to the existing [WinGet manifest schema](https://github.com/microsoft/winget-pkgs/blob/master/doc/manifest/README.md) in form of an additional yaml file, that describes keyboard shortcuts the application provides.
These yaml files are saved on a per-user base and so called manifest interpreters can then display these manifests in a human-friendly version.
### 1.1 What this spec is not about
This spec does not provide a way to back up or save user-defined keyboard shortcuts.
## 2 Save location of manifests
### 2.1 WinGet
These files are saved online along with the other manifest files in the [WinGet Package repository](https://github.com/microsoft/winget-pkgs).
### 2.2 Locally
All manifests and one index file are saved locally under `%LocalAppData%/Microsoft/WinGet/KeyboardShortcuts`. All apps are allowed to add their manifest files there. In addition Package Managers (like WinGet) and manifest interpreters (like PowerToys Shortcut Guide) can control and add other manifests themselves.
#### 2.2.1 Downloading manifests
When WinGet or other package managers download a package, they should also download the corresponding keyboard shortcuts manifest file and save it in the local directory, given such a file exists in the WinGet repository.
The downloader is also responsible for updating the local `index.yaml` file, which contains all the information about the different manifest files that are saved in the same directory.
#### 2.2.2 Updating manifests
When a manifest interpreter starts, it should download the latest version of the manifests from the WinGet repository and save them in the local directory. If a manifest interpreter is not able to download the manifests or they do not exist, it should use the locally saved manifests.
The updater is also responsible for updating the local `index.yaml` file, which contains all the information about the different manifest files that are saved in the same directory.
> Note: WinGet must provide a way to update the keyboard shortcuts manifests given a package id.
### 2.3 File names
The file name of a keyboard shortcuts file is the WinGet package identifier, plus the locale of the strings of the file and at last the `.KBSC.yaml` file extension.
For example the package "test.bar" saves its manifest with `en-US` strings in `test.bar.en-US.KBSC.yaml`.
#### 2.3.1 No winget package available
If an application has no corresponding WinGet package its name starts with a plus (`+`) symbol.
### 2.4 Reserved namespaces
Every name starting with `+WindowsNT` is reserved for the Windows OS and its components.
## 3 File syntax
All relevant files are written in [YAML](https://yaml.org/spec).
> Note: A JSON schema will be provided as soon as the spec reaches a further step
### 3.1 Manifest Schema vNext Keyboard Shortcuts File
```
PackageName: # The package unique identifier
WindowFilter: # The filter of window processes to which the shortcuts apply to
BackgroundProcess: # Optionally allows applying WindowFilter to background processes
Shortcuts: # List of sections with keyboard shortcuts
- SectionName: # Name of the category of shortcuts
Properties: # List of shortcuts in the category
- Name: # Name of the shortcut
Description: # Optional description of the shortcut
AdditionalInfo: # Optional additional information about the shortcut
Recommended: # Optionally determines if the shortcut is displayed in a designated recommended area
Shortcut: # An array of shortcuts that need to be pressed
- Win: # Determines if the Windows Key is part of the shortcut
Ctrl: # Determines if the Ctrl Key is part of the shortcut
Shift: # Determines if the Shift Key is part of the shortcut
Alt: # Determines if the Alt Key is part of the shortcut
Keys: # Array of keys that need to be pressed
```
Per Application/Package one or more Keyboard manifests can be declared. Every manifest must have a different locale and the same `PackageName`, `WindowFilter` and `BackgroundProcess` fields.
<details>
<summary><b>PackageName</b> - The package unique identifier</summary>
Package identifier (see 2.1 for more information on the package identifier).
</details>
<details>
<summary><b>WindowFilter</b> - The filter of window processes to which the shortcuts apply to</summary>
This field declares for which process name the shortcuts should be showed (To rephrase: For which processes the shortcut will have an effect if pressed). You can use an asterisk to leave out a certain part. For example `*.PowerToys.*.exe` targets all PowerToys processes and `*` apply to any process.
</details>
<details>
<summary><b>BackgroundProcess</b> - Optionally allows applying WindowFilter to background processes.</summary>
**Optional field**
Defaults to `False`. Determines if WindowFilter should apply to background processes as well (Rephrased: When the process is running, the shortcuts will apply).
</details>
<details>
<summary><b>Shortcuts</b> - List of sections with keyboard shortcuts</summary>
List of different section (also called categories) of shortcuts.
</details>
<details>
<summary><b>SectionName</b> - Name of the category of shortcuts</summary>
Name of the section of shortcuts.
**Special sections**:
Special sections start with an identifier enclosed between `<` and `>`. This declares the category as a special display. If the interpreter of the manifest file can't understand the content this section should be left out.
</details>
<details>
<summary><b>Properties</b> - List of shortcuts in the category</summary>
</details>
<details>
<summary><b>Name</b> - Name of the shortcut</summary>
Name of the shortcut. This is the name that will be displayed in the interpreter.
</details>
<details>
<summary><b>Description</b> - Optional description of the shortcut</summary>
Optional description of the shortcut. This is the description that will be displayed by the interpreter.
</details>
<details>
<summary><b>AdditionalInfo</b> - Optional additional information about the shortcut</summary>
Array of additional information about the shortcut. This is the additional information that will be displayed by the interpreter and are not part of this manifest.
**Example**:
For example, if the shortcut is only available on a certain Windows version, this information could be added here.
```yaml
AdditionalInfo:
- MinWindowsVersion: "10.0.19041.0"
```
</details>
<details>
<summary><b>Shortcut</b> - An array of shortcuts that need to be pressed</summary>
An array of shortcuts that need to be pressed. This allows defining sequential shortcuts that need to be pressed in order to trigger the action.
</details>
<details>
<summary><b>Win</b> - Determines if the Windows Key is part of the shortcut</summary>
Refers to the left Windows Key on the keyboard.
</details>
<details>
<summary><b>Ctrl</b> - Determines if the Ctrl Key is part of the shortcut</summary>
Refers to the left Ctrl Key on the keyboard.
</details>
<details>
<summary><b>Shift</b> - Determines if the Shift Key is part of the shortcut</summary>
Refers to the left Shift Key on the keyboard.
</details>
<details>
<summary><b>Alt</b> - Determines if the Alt Key is part of the shortcut</summary>
Refers to the left Alt Key on the keyboard.
</details>
<details>
<summary><b>Recommended</b> - Optionally determines if the shortcut is displayed in a designated recommended area</summary>
**Optional field**
Defaults to `False`. Determines if the shortcut should be displayed in a designated recommended area. This is a visual hint for the user that this shortcut is important.
</details>
<details>
<summary><b>Keys</b> - Array of keys that need to be pressed</summary>
A string array of all the keys that need to be pressed. If a number is supplied, it should be read as a [KeyCode](https://learn.microsoft.com/windows/win32/inputdev/virtual-key-codes) and displayed accordingly (based on the Keyboard Layout of the user).
**Special keys**:
Special keys are enclosed between `<` and `>` and correspond to a key that should be displayed in a certain way. If the interpreter of the manifest file can't understand the content, the brackets should be left out.
|Name|Description|
|----|-----------|
|`<Office>`| Corresponds to the Office key on some Windows keyboards |
|`<Copilot>`| Corresponds to the Copilot key on some Windows keyboards |
|`<Left>`| Corresponds to the left arrow key |
|`<Right>`| Corresponds to the right arrow key |
|`<Up>`| Corresponds to the up arrow key |
|`<Down>`| Corresponds to the down arrow key |
|`<Enter>`| Corresponds to the Enter key |
|`<Space>`| Corresponds to the Space key |
|`<Tab>`| Corresponds to the Tab key |
|`<Backspace>`| Corresponds to the Backspace key |
|`<Delete>`| Corresponds to the Delete key |
|`<Insert>`| Corresponds to the Insert key |
|`<Home>`| Corresponds to the Home key |
|`<End>`| Corresponds to the End key |
|`<PrtScr>`| Corresponds to the Print Screen key |
|`<Pause>`| Corresponds to the pause key |
|`<PageUp>`| Corresponds to the Page Up key |
|`<PageDown>`| Corresponds to the Page Down key |
|`<Escape>`| Corresponds to the Escape key |
|`<Arrow>`| Corresponds to either the left, right, up or down arrow key |
|`<ArrowLR>`| Corresponds to either the left or right arrow key |
|`<ArrowUD>`| Corresponds to either the up or down arrow key |
|`<Underlined letter>`| Corresponds to any letter that is _underlined_ in the UI |
</details>
#### 3.2.2 Example
```yaml
PackageName: Microsoft.PowerToys
WindowFilter: "*"
BackgroundProcess: True
Shortcuts:
- SectionName: General
Properties:
- Name: Advanced Paste
Shortcut:
- Win: True
Ctrl: False
Alt: False
Shift: False
Keys:
- 86
Description: Open Advanced Paste window
- Name: Advanced Paste
Shortcut:
- Win: True
Ctrl: True
Alt: True
Shift: False
Keys:
- 86
Description: Paste as plain text directly
```
### 3.2 `index.yaml` file
The `index.yaml` file is a file that contains all the information about the different manifest files that are saved in the same directory. This file is only available locally and is not saved in the WinGet repository as it is specific to the user.
```yaml
DefaultShellName: # The package identifier of the default shell used in Windows
Index: # List of all manifest files
- WindowFilter: # The filter of window processes to which the shortcuts apply to
BackgroundProcess: # Optionally allows applying WindowFilter to background processes
Apps: # List of all manifest files for the filter
```
<details>
<summary><b>DefaultShellName</b> - The package identifier of the default shell used in Windows</summary>
This declares the package identifier of the default shell used in Windows. Most commonly it is `+WindowsNT.Shell`. Although not enforced, only the shell declared in the registry key `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell` should be used here.
</details>
<details>
<summary><b>Index</b> - List of all manifest files</summary>
</details>
<details>
<summary><b>WindowFilter</b> - The filter of window processes to which the shortcuts apply to</summary>
See the `WindowFilter` field in the manifest file for more information.
</details>
<details>
<summary><b>BackgroundProcess</b> - Optionally allows applying WindowFilter to background processes</summary>
**Optional field**
See the `BackgroundProcess` field in the manifest file for more information.
</details>
<details>
<summary><b>Apps</b> - List of all the package identifiers applying for the filter</summary>
</details>
#### 3.2.1 Example
```yaml
DefaultShellName: "+WindowsNT.Shell"
Index:
- Filter: "*"
BackgroundProcess: True
Apps: ["+WindowsNT.Shell", "Microsoft.PowerToys"]
- Filter: "explorer.exe"
Apps: ["+WindowsNT.WindowsExplorer"]
- Filter: "taskmgr.exe"
Apps: ["+WindowsNT.TaskManager"]
- Filter: "msedge.exe"
Apps: ["+WindowsNT.Edge"]
```

View File

@@ -34,8 +34,12 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>$(Platform)\$(Configuration)\SetupShared\</OutDir>
<IntDir>$(SolutionDir)$(ProjectName)\$(Platform)\$(Configuration)\SetupShared\obj\</IntDir>
<OutDir Condition=" '$(PerUser)' != 'true' ">$(Platform)\$(Configuration)\MachineSetup\</OutDir>
<OutDir Condition=" '$(PerUser)' == 'true' ">$(Platform)\$(Configuration)\UserSetup\</OutDir>
<IntDir Condition=" '$(PerUser)' != 'true' ">$(SolutionDir)$(ProjectName)\$(Platform)\$(Configuration)\MachineSetup\obj\</IntDir>
<IntDir Condition=" '$(PerUser)' == 'true' ">$(SolutionDir)$(ProjectName)\$(Platform)\$(Configuration)\UserSetup\obj\</IntDir>
<NormalizedPerUserValue>false</NormalizedPerUserValue>
<NormalizedPerUserValue Condition=" '$(PerUser)' == 'true' ">true</NormalizedPerUserValue>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<LinkIncremental>true</LinkIncremental>
@@ -75,7 +79,8 @@
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\WinAppSDK.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\WinAppSDK.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\WinUI3Applications.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\WinUI3Applications.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\Workspaces.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\Workspaces.wxs.bk""""
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File ..\PowerToysSetupVNext\generateAllFileComponents.ps1 -platform $(Platform)
if not "$(NormalizedPerUserValue)" == "true" call powershell.exe -NonInteractive -executionpolicy Unrestricted -File ..\PowerToysSetupVNext\generateAllFileComponents.ps1 -platform $(Platform)
if "$(NormalizedPerUserValue)" == "true" call powershell.exe -NonInteractive -executionpolicy Unrestricted -File ..\PowerToysSetupVNext\generateAllFileComponents.ps1 -platform $(Platform) -installscopeperuser $(NormalizedPerUserValue)
</Command>
<Message>Backing up original files and populating .NET and WPF Runtime dependencies for WiX3 based installer</Message>
</PreBuildEvent>
@@ -173,4 +178,4 @@
<Error Condition="!Exists('..\packages\WixToolset.DUtil.5.0.2\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WixToolset.DUtil.5.0.2\build\WixToolset.DUtil.props'))" />
<Error Condition="!Exists('..\packages\WixToolset.WcaUtil.5.0.2\build\WixToolset.WcaUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WixToolset.WcaUtil.5.0.2\build\WixToolset.WcaUtil.props'))" />
</Target>
</Project>
</Project>

View File

@@ -60,12 +60,6 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
call move /Y ..\..\..\Workspaces.wxs.bk ..\..\..\Workspaces.wxs
</PostBuildEvent>
</PropertyGroup>
<PropertyGroup Condition="'$(RunBuildEvents)'=='false'">
<PostBuildEvent></PostBuildEvent>
<RunPostBuildEvent></RunPostBuildEvent>
<PreBuildEventUseInBuild>false</PreBuildEventUseInBuild>
<PostBuildEventUseInBuild>false</PostBuildEventUseInBuild>
</PropertyGroup>
<PropertyGroup Label="UserMacros" Condition=" '$(PerUser)' == 'true' ">
<DefineConstants>$(DefineConstants);PerUser=true</DefineConstants>
</PropertyGroup>

View File

@@ -2,25 +2,26 @@
<?include $(sys.CURRENTDIR)\Common.wxi?>
<?define ShortcutGuideAssetsFiles=?>
<?define ShortcutGuideAssetsFilesPath=$(var.BinDir)WinUI3Apps\Assets\ShortcutGuide\?>
<?define ShortcutGuideSvgFiles=?>
<?define ShortcutGuideSvgFilesPath=$(var.BinDir)\Assets\ShortcutGuide\?>
<Fragment>
<DirectoryRef Id="WinUI3AppsAssetsFolder">
<Directory Id="ShortcutGuideAssetsFolder" Name="ShortcutGuide" />
<!-- Shortcut guide files -->
<DirectoryRef Id="BaseApplicationsAssetsFolder">
<Directory Id="ShortcutGuideSvgsInstallFolder" Name="ShortcutGuide" />
</DirectoryRef>
<DirectoryRef Id="ShortcutGuideAssetsFolder" FileSource="$(var.ShortcutGuideAssetsFilesPath)">
<DirectoryRef Id="ShortcutGuideSvgsInstallFolder" FileSource="$(var.ShortcutGuideSvgFilesPath)">
<!-- Generated by generateFileComponents.ps1 -->
<!--ShortcutGuideAssetsFiles_Component_Def-->
<!--ShortcutGuideSvgFiles_Component_Def-->
</DirectoryRef>
<!-- Shortcut guide -->
<ComponentGroup Id="ShortcutGuideComponentGroup" >
<Component Id="RemoveShortcutGuideFolder" Guid="AD1ABC55-B593-4A60-A86A-BA8C0ED493A5" Directory="ShortcutGuideAssetsFolder" >
<ComponentGroup Id="ShortcutGuideComponentGroup">
<Component Id="RemoveShortcutGuideFolder" Guid="AD1ABC55-B593-4A60-A86A-BA8C0ED493A5" Directory="ShortcutGuideSvgsInstallFolder">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="RemoveShortcutGuideFolder" Value="" KeyPath="yes"/>
<RegistryValue Type="string" Name="RemoveShortcutGuideFolder" Value="" KeyPath="yes" />
</RegistryKey>
<RemoveFolder Id="RemoveFolderShortcutGuideAssetsInstallFolder" Directory="ShortcutGuideAssetsFolder" On="uninstall"/>
<RemoveFolder Id="RemoveFolderShortcutGuideSvgsInstallFolder" Directory="ShortcutGuideSvgsInstallFolder" On="uninstall" />
</Component>
</ComponentGroup>

View File

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

59
pt-cli-plan.md Normal file
View File

@@ -0,0 +1,59 @@
# PowerToys CLI Implementation Plan
## Goal
- Deliver the `ptcli` command-line experience described in `pt-cli.md`, with `Runner` acting as the single broker for module commands.
- Provide a maintainable architecture where modules self-describe commands, and CLI clients consume a uniform JSON/NamedPipe protocol.
## Workstreams
### 1. Broker Foundation (Runner)
- **Command Registry**: Implement `IModuleCommandProvider` registration on module load and persist `CommandDescriptor` metadata (schema, elevation flag, long-running hints, docs).
- **IPC Host**: Stand up the `\\.\pipe\PowerToys.Runner.CLI` NamedPipe server; define request/response DTOs with versioning (`v` field, correlation IDs).
- **Dispatch Pipeline**: Validate module/action, apply schema validation, enforce elevation policy, and invoke `ExecuteAsync`.
- **Response Envelope**: Normalize `status` (`ok|error|accepted`), payload, and error block (`code/message/details`). Emit diagnostic logging (caller, command, latency, result).
### 2. CLI Thin Client (`ptcli`)
- **Argument Parsing**: Support `ptcli -m <module> <action> [--arg value]`, plus `--list-modules`, `--list-commands`.
- **Transport**: Serialize requests to JSON, connect to the pipe with timeout handling, and deserialize responses.
- **Output UX**: Map standard errors to friendly text, show structured results, and support optional `--json` passthrough.
- **Async Jobs**: Handle `status=accepted` by printing job IDs, exposing `ptcli job status <id>` and `ptcli job cancel <id>` commands (polling via Runner endpoints).
### 3. Module Onboarding
- **Awake**: Implement `IModuleCommandProvider` returning `set/start/stop/list` commands. Adapt current APIs or legacy triggers inside `ExecuteAsync`.
- **Workspaces**: Provide `list/apply/delete` commands; wrap existing workspace manager calls. Ensure long-running operations flag `LongRunning=true`.
- **Legacy Adapters**: For modules still using raw events/pipes, add Runner-side shims that translate command invocations while longer-term refactors are scheduled.
### 4. Capability Discovery & Help
- **Describe APIs**: Expose Runner endpoints for `modules`, `commands`, parameter schemas, and elevation requirements.
- **CLI Help**: Use discovery data to render `ptcli help`, module-specific usage, and argument hints without duplicating metadata.
### 5. Reliability, Security, Observability
- **Security**: Configure pipe DACL to restrict access to the interactive user; enforce argument length/type limits.
- **Concurrency**: Process each request on a dedicated task; delegate concurrency limits to modules. Provide cancellation tokens from Runner.
- **Tracing**: Emit structured logs/ETW for requests, errors, and long-running progress notifications.
- **Error Catalog**: Implement standardized error codes (`E_MODULE_NOT_FOUND`, `E_ARGS_INVALID`, `E_NEEDS_ELEVATION`, `E_TIMEOUT`, etc.) and map module exceptions accordingly.
### 6. Elevation & Policies
- **Elevation Flow**: Detect when commands require elevation; if Runner is not elevated, return `E_NEEDS_ELEVATION` with actionable hints. Integrate with existing elevated Runner helper when available.
- **Policy Hooks**: Add optional checks for policy/experiment gates before command execution.
### 7. Progress & Notifications
- **Progress Channel**: Support incremental JSON progress messages over the same pipe or via job polling endpoints.
- **Timeouts/Retry**: Implement configurable `timeoutMs` handling and `E_BUSY_RETRY` responses for transient module lock scenarios.
### 8. Incremental Rollout Strategy
- **Phase 1**: Ship Runner pipe host + CLI client with two flagship commands (Awake.Set, Workspaces.List); document manual enablement.
- **Phase 2**: Migrate additional modules through adapters; add help/describe surfaces and job management.
- **Phase 3**: Enforce schema validation, finalize error catalog, and wire observability dashboards.
- **Phase 4**: Deprecate direct module NamedPipe/event entry points once CLI parity is achieved.
### 9. Documentation & Maintenance
- **User Docs**: Populate `pt-cli.md` with usage examples, elevation guidance, and troubleshooting mapped to error codes.
- **Developer Guide**: Add module author instructions for implementing `IModuleCommandProvider`, including schema examples and best practices.
- **Release Checklist**: Track new commands per release, update discovery metadata, and ensure CLI integration tests cover regression cases.
## Open Questions
- What tooling will maintain JSON schemas (hand-authored vs. source-generated)?
- Should progress streaming use duplex pipe messages or a per-job polling API?
- How will elevated Runner lifecycle be managed (reuse existing helper vs. new broker)?
- Which modules are in-scope for the first public preview, and what is the rollout schedule?

358
pt-cli.md Normal file
View File

@@ -0,0 +1,358 @@
选 Runner 作为唯一的 Server/Brokerptcli 只是瘦客户端。
模块通过各自的 ModuleInterface 向 Runner 注册“可被调用的命令/参数模式”。
ptcli → Runner 用 统一的 IPC建议 NamedPipe + JSON-RPC/自定义轻量 JSON 协议)。
Runner 再把请求转发到对应模块(可以是直接调用模块公开的接口,或转译为该模块现有的触发机制,如 Event/NamedPipe
对“历史遗留的 event handle/pipe 触发点”,短期由 Runner 做兼容层;长期逐步统一为“命令接口”。
这样你能得到:能力发现、参数校验、权限/提权、错误码一致、可观察性一致、向后兼容。
组件与职责
ptcli瘦客户端
解析命令行ptcli -m awake set --duration 1h / ptcli -m workspace list
将其映射为通用消息JSON发给 Runner。
处理同步/异步返回、展示统一错误码与人类可读信息。
最多内置“列出模块/命令的帮助”这类“离线功能”,但真正的能力发现来自 Runner。
Runner统一 Server/Broker
启动时建立 NamedPipe 服务端:\\.\pipe\PowerToys.Runner.CLI示例
维护 Command Registry每个模块在加载/初始化时注册自己的命令(名称、参数 schema、是否需要提权、是否长任务、超时时间建议、描述文案等
收到请求后:
校验模块是否存在、命令是否存在、参数是否通过 schema 验证。
如需提权且当前 Runner 权限不足按策略返回“需要提权”的标准错误或通过你们现有的提权助手启动“Elevated Runner”做代办。
转发给目标模块(优先调用模块公开的“命令接口方法”;若模块尚未改造,由 Runner 适配为该模块现有触发Event/NamedPipe
汇总返回值,统一封装标准响应(状态、数据、错误码、诊断信息)。
Module实现者
实现 IModuleCommandProvider示例命名
IEnumerable<CommandDescriptor> DescribeCommands() 暴露命令元数据;
Task<CommandResult> ExecuteAsync(CommandInvocation ctx) 执行命令;
可标注“需要前台 UI”、“需要管理员”、“可能长时间运行支持取消/进度)”等。
现有“事件/NamedPipe 触发路径”的模块:短期由 Runner 适配;长期建议模块直接实现上面的 ExecuteAsync统一语义与可观测性。
协议与数据结构(建议)
请求ptcli→Runner
{
"v": 1,
"correlationId": "uuid",
"command": {
"module": "awake",
"action": "set", // 例如 set/start/stop/list 等
"args": { "duration": "1h" } // 按模块定义的 schema
},
"options": {
"timeoutMs": 20000,
"wantProgress": false
}
}
响应Runner→ptcli
{
"v": 1,
"correlationId": "uuid",
"status": "ok", // ok | error | accepted (异步)
"result": { /* 模块返回的结构化数据 */ },
"error": { // 仅当 status=error
"code": "E_NEEDS_ELEVATION", // 标准化错误码
"message": "Awake requires elevation",
"details": { "hint": "rerun with --elevated" }
}
}
进度/异步(可选)
长任务时status="accepted" 并返回 jobIdptcli 可 ptcli job status <jobId> 轮询,或 Runner 通过同管道 增量推送 progressJSON lines
取消ptcli 发送 { action: "cancel", jobId: "..." }Runner 调用模块 CancellationToken。
命令发现与帮助
ptcli -m list列出模块Runner 直接返回 registry
ptcli -m awake -hDescribeCommands() 中的 Awake 条目返回所有 action、参数与示例。
参数 schema用简化 JSON Schema或手写约束即可让 ptcli 能本地提示,也让 Runner 能服务器端校验。
示例映射
Awake
ptcli -m awake set --duration 1h
→ Awake.Set(duration=1h)
→ Runner 调用 AwakeModule.ExecuteAsync("set", args)
→ 结果:{ "effectiveUntil": "2025-10-30T18:00:00+08:00" }
ptcli -m awake stop
→ Awake.Stop()(幂等)
Workspaces
ptcli -m workspace list
→ Workspaces.List() 返回 { "items": [{ "id": "...", "name": "...", "monitors": 2, "windows": 14 }] }
ptcli -m workspace apply --id 123 --strict
→ Workspaces.Apply(id=123, strict=true) 支持进度与失败报告(缺失进程、权限不足等)。
Runner vs 直接敲模块事件/NamedPipe
直接敲模块(如你举的 EventWaitHandle优点
省一跳,模块自己掌控。
对少数“拍一下就够”的快捷触发点,写起来快。
缺点(关键)
入口分散:每个模块各有各的触发名、参数约定、错误语义。
能力发现困难ptcli 无法统一列出“模块能干啥、参数是什么”。
权限与多实例问题:有的模块需要管理员/前台,有的在用户会话,有的在服务;直接对模块打洞容易踩坑。
审计/可观察性差:难以统一日志/遥测/超时/取消。
演进成本高:接口一旦铺散,很难回收。
走 Runner Proxy推荐
统一注册:模块只跟 Runner 说“我能做哪些命令、参数是什么”。
统一协议ptcli 只会说一种“通用 JSON 命令”。
统一安全/提权/会话Runner 最懂自己所在的权限/桌面会话,可决定是否需要跳 Elevation/切用户会话。
兼容旧触发Runner 内部去“Set 事件/写管道”,外部对 ptcli 完全透明。
可测试/可监控:所有调用都经由同一 Broker便于打点、限流、诊断。
结论:把直接事件/管道触发视为“模块侧 private API”只由 Runner 调用。ptcli 与普通用户两边都只看得到 Runner 的“公共命令接口”。
Runner 怎么“轻量 Server”
进程:沿用现有 Runner不另起新守护新增一个 CommandRouter 子系统即可。
IPCNamedPipeServerStream + StreamJsonRpc或你们已有的 JSON 框架);单管道多请求(长度前缀 + correlationId
并发:每请求一个 Task模块执行受自身并发控制。
安全:给管道设定 DACL仅允许同一交互式用户或受信 SID连接参数白名单与长度限制防注入。
错误码:统一枚举(像 HTTP 状态一样):
E_MODULE_NOT_FOUND / E_COMMAND_NOT_FOUND / E_ARGS_INVALID
E_NEEDS_ELEVATION / E_ACCESS_DENIED
E_BUSY_RETRY / E_TIMEOUT / E_INTERNAL
最小可行落地(增量实施顺序)
在 Runner 加一个 Pipe + CommandRouter硬编码两个演示命令
Awake.Set(duration)(直接调用 Awake 的现有 API
Workspaces.List()(调用 Workspace 管理器)
写 ptcli只做 JSON 打包、发管道、打印结果。
给两个模块各加 IModuleCommandProvider从 Runner 注册。
把 1~2 个“历史事件触发点”接入 RouterRunner 内部去 Set Event对外暴露为 Module.Action。
扩展help/describe、Job/进度、取消、提权路径、返回码规范化。
简短示例C#,仅示意;注释英文)
Runner 接口定义
public record CommandDescriptor(
string Module, string Action, string Description,
IReadOnlyDictionary<string, ParamSpec> Params,
bool RequiresElevation = false, bool LongRunning = false);
public interface IModuleCommandProvider
{
IEnumerable<CommandDescriptor> DescribeCommands();
Task<CommandResult> ExecuteAsync(CommandInvocation ctx, CancellationToken ct);
}
public record CommandInvocation(string Action, IReadOnlyDictionary<string, object?> Args);
public record CommandResult(bool Ok, object? Data = null, string? ErrorCode = null, string? ErrorMessage = null);
Runner 注册与路由(伪码)
// On module load:
registry.Register(provider.DescribeCommands(), provider);
// On request:
var cmd = request.Command; // module, action, args
var provider = registry.Resolve(cmd.Module, cmd.Action);
ValidateArgs(cmd.Args, provider.Schema);
if (provider.RequiresElevation && !IsElevated())
return Error("E_NEEDS_ELEVATION", "Elevation required.");
return await provider.ExecuteAsync(new CommandInvocation(cmd.Action, cmd.Args), ct);
ptcli 调用(伪码)
// Build request from CLI args
var req = new { v = 1, correlationId = Guid.NewGuid(), command = new { module, action, args } };
using var client = new NamedPipeClientStream(".", "PowerToys.Runner.CLI", PipeDirection.InOut);
await client.ConnectAsync(timeout);
await WriteJsonAsync(client, req);
var resp = await ReadJsonAsync(client);
Render(resp);
return resp.status == "ok" ? 0 : 1;
兼容性与演进策略
不强行改造所有模块Runner 先用“适配器”把旧事件/管道触发包起来CLI 立即可用;后续模块逐步实现 IModuleCommandProvider。
版本化:请求/响应带 v便于以后扩展字段。
可观测性Runner 统一日志:调用者、命令、耗时、结果码;必要时加 ETW/Trace。
权限Runner 决策提权路径ptcli 接到 E_NEEDS_ELEVATION 时,可提示 --elevated 或弹系统 UAC按你们策略
并行/队列:对长任务(如 workspace apply可按模块内队列执行避免竞态CLI 侧提供 job status/cancel。
你关心的具体问题直答
“由 moduleinterface 做统一入口管理是个好主意吗?”
好,但入口管理应驻留在 Runner。模块通过 ModuleInterface 报告命令与执行入口Runner 统一对外暴露。
“ptcli 直接找模块执行,还是让 Runner 派发?”
让 Runner 派发。这样获得统一发现、权限、错误、日志与演进空间。
“现在很多模块用 named pipe/event 触发,这算绕过 Runner 吗?”
目前你看到的例子确实是“模块直连触发”。建议以后仅 Runner 使用这些内部触发(做兼容/过渡),对外统一成命令。
“Runner 起一个 light-weight server 吗?”
对。就在 Runner 里加一个轻量 NamedPipe JSON-RPC 服务,不必单独再起一个服务进程。
要的话,我可以按上面的协议给你一版 ptcliC#)与 Runner 侧 CommandRouter 的“最小可用代码骨架”,再加上 Awake/Workspaces 的两个真实命令适配示例。

View File

@@ -1,161 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{2d604c07-51fc-46bb-9eb7-75aecc7f5e81}</ProjectGuid>
<RootNamespace>ShortcutGuide.CPPProject</RootNamespace>
<ProjectName>ShortcutGuide.CPPProject</ProjectName>
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>Spectre</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>Spectre</SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{c992fd2c-83b8-4941-9fc1-09730068d8ec}</ProjectGuid>
<RootNamespace>ShortcutGuideCPPProject</RootNamespace>
<WindowsTargetPlatformVersion>10.0.22621.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>..\..\..\common\utils;..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>..\..\..\common\utils;..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\..\common\utils;..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\..\common\utils;..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="excluded_app.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="tasklist_positions.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="excluded_app.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="tasklist_positions.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View File

@@ -1,42 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="tasklist_positions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="excluded_app.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="tasklist_positions.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="excluded_app.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

View File

@@ -1,39 +0,0 @@
#include "pch.h"
#include "excluded_app.h"
#include <string_utils.h>
extern "C"
{
__declspec(dllexport) bool IsCurrentWindowExcludedFromShortcutGuide()
{
PowerToysSettings::PowerToyValues settings = PowerToysSettings::PowerToyValues::load_from_settings_file(L"Shortcut Guide");
auto settingsObject = settings.get_raw_json();
std::wstring apps = settingsObject.GetNamedObject(L"properties").GetNamedObject(L"disabled_apps").GetNamedString(L"value").c_str();
auto excludedUppercase = apps;
CharUpperBuffW(excludedUppercase.data(), static_cast<DWORD>(excludedUppercase.length()));
std::wstring_view view(excludedUppercase);
view = left_trim<wchar_t>(trim<wchar_t>(view));
while (!view.empty())
{
auto pos = (std::min)(view.find_first_of(L"\r\n"), view.length());
m_excludedApps.emplace_back(view.substr(0, pos));
view.remove_prefix(pos);
view = left_trim<wchar_t>(trim<wchar_t>(view));
}
if (m_excludedApps.empty())
{
return false;
}
if (HWND foregroundApp{ GetForegroundWindow() })
{
auto processPath = get_process_path(foregroundApp);
CharUpperBuffW(processPath.data(), static_cast<DWORD>(processPath.length()));
return check_excluded_app(foregroundApp, processPath, m_excludedApps);
}
return false;
}
}

View File

@@ -1,7 +0,0 @@
#pragma once
extern "C"
{
std::vector<std::wstring> m_excludedApps;
__declspec(dllexport) bool IsCurrentWindowExcludedFromShortcutGuide();
}

View File

@@ -1,185 +0,0 @@
#include "pch.h"
#include "tasklist_positions.h"
// Tried my hardest adapting this to C#, but FindWindowW didn't work properly in C#. ~Noraa Junker
extern "C"
{
HWND GetTaskbarHwndForCursorMonitor(HMONITOR monitor)
{
POINT pt;
if (!GetCursorPos(&pt))
return nullptr;
// Find the primary taskbar
HWND primaryTaskbar = FindWindowW(L"Shell_TrayWnd", nullptr);
if (primaryTaskbar)
{
MONITORINFO mi = { sizeof(mi) };
if (GetWindowRect(primaryTaskbar, &mi.rcMonitor))
{
HMONITOR primaryMonitor = MonitorFromRect(&mi.rcMonitor, MONITOR_DEFAULTTONEAREST);
if (primaryMonitor == monitor)
return primaryTaskbar;
}
}
// Find the secondary taskbar(s)
HWND secondaryTaskbar = nullptr;
while ((secondaryTaskbar = FindWindowExW(nullptr, secondaryTaskbar, L"Shell_SecondaryTrayWnd", nullptr)) != nullptr)
{
MONITORINFO mi = { sizeof(mi) };
RECT rc;
if (GetWindowRect(secondaryTaskbar, &rc))
{
HMONITOR taskbarMonitor = MonitorFromRect(&rc, MONITOR_DEFAULTTONEAREST);
if (monitor == taskbarMonitor)
return secondaryTaskbar;
}
}
return nullptr;
}
void update(HMONITOR monitor)
{
// Get HWND of the tasklist for the monitor under the cursor
auto taskbar_hwnd = GetTaskbarHwndForCursorMonitor(monitor);
if (!taskbar_hwnd)
return;
wchar_t class_name[64] = {};
GetClassNameW(taskbar_hwnd, class_name, 64);
HWND tasklist_hwnd = nullptr;
if (wcscmp(class_name, L"Shell_TrayWnd") == 0)
{
// Primary taskbar structure
tasklist_hwnd = FindWindowExW(taskbar_hwnd, 0, L"ReBarWindow32", nullptr);
if (!tasklist_hwnd)
return;
tasklist_hwnd = FindWindowExW(tasklist_hwnd, 0, L"MSTaskSwWClass", nullptr);
if (!tasklist_hwnd)
return;
tasklist_hwnd = FindWindowExW(tasklist_hwnd, 0, L"MSTaskListWClass", nullptr);
if (!tasklist_hwnd)
return;
}
else if (wcscmp(class_name, L"Shell_SecondaryTrayWnd") == 0)
{
// Secondary taskbar structure
HWND worker_hwnd = FindWindowExW(taskbar_hwnd, 0, L"WorkerW", nullptr);
if (!worker_hwnd)
return;
tasklist_hwnd = FindWindowExW(worker_hwnd, 0, L"MSTaskListWClass", nullptr);
if (!tasklist_hwnd)
return;
}
else
{
// Unknown taskbar type
return;
}
if (!automation)
{
winrt::check_hresult(CoCreateInstance(CLSID_CUIAutomation,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IUIAutomation,
automation.put_void()));
winrt::check_hresult(automation->CreateTrueCondition(true_condition.put()));
}
element = nullptr;
winrt::check_hresult(automation->ElementFromHandle(tasklist_hwnd, element.put()));
}
bool update_buttons(std::vector<TasklistButton>& buttons)
{
if (!automation || !element)
{
return false;
}
winrt::com_ptr<IUIAutomationElementArray> elements;
if (element->FindAll(TreeScope_Children, true_condition.get(), elements.put()) < 0)
return false;
if (!elements)
return false;
int count;
if (elements->get_Length(&count) < 0)
return false;
winrt::com_ptr<IUIAutomationElement> child;
std::vector<TasklistButton> found_buttons;
found_buttons.reserve(count);
for (int i = 0; i < count; ++i)
{
child = nullptr;
if (elements->GetElement(i, child.put()) < 0)
return false;
TasklistButton button = {};
if (VARIANT var_rect; child->GetCurrentPropertyValue(UIA_BoundingRectanglePropertyId, &var_rect) >= 0)
{
if (var_rect.vt == (VT_R8 | VT_ARRAY))
{
LONG pos;
double value;
pos = 0;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.x = static_cast<long>(value);
pos = 1;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.y = static_cast<long>(value);
pos = 2;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.width = static_cast<long>(value);
pos = 3;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.height = static_cast<long>(value);
}
VariantClear(&var_rect);
}
else
{
return false;
}
if (BSTR automation_id; child->get_CurrentAutomationId(&automation_id) >= 0)
{
wcsncpy_s(button.name, automation_id, _countof(button.name));
SysFreeString(automation_id);
}
found_buttons.push_back(button);
}
// assign keynums
buttons.clear();
for (auto& button : found_buttons)
{
if (buttons.empty())
{
button.keynum = 1;
buttons.push_back(std::move(button));
}
else
{
if (button.x < buttons.back().x || button.y < buttons.back().y) // skip 2nd row
break;
if (wcsncmp(button.name, buttons.back().name, _countof(button.name)) == 0)
continue; // skip buttons from the same app
button.keynum = buttons.back().keynum + 1;
buttons.push_back(std::move(button));
if (buttons.back().keynum == 10)
break; // no more than 10 buttons
}
}
return true;
}
__declspec(dllexport) TasklistButton* get_buttons(HMONITOR monitor, int* size)
{
update(monitor);
static std::vector<TasklistButton> buttons;
update_buttons(buttons);
*size = static_cast<int>(buttons.size());
return buttons.data();
}
}

View File

@@ -1,23 +0,0 @@
#pragma once
struct TasklistButton
{
wchar_t name[256];
int x;
int y;
int width;
int height;
int keynum;
};
extern "C"
{
winrt::com_ptr<IUIAutomation> automation;
winrt::com_ptr<IUIAutomationElement> element;
winrt::com_ptr<IUIAutomationCondition> true_condition;
// Helper to get the taskbar HWND for the monitor under the cursor
HWND GetTaskbarHwndForCursorMonitor(HMONITOR monitor);
bool update_buttons(std::vector<TasklistButton>& buttons);
__declspec(dllexport) TasklistButton* get_buttons(HMONITOR monitor, int* size);
}

View File

@@ -1,76 +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.IO;
using ShortcutGuide.Helpers;
using ShortcutGuide.Models;
using YamlDotNet.Serialization;
// This class should be moved to WinGet in the future
namespace ShortcutGuide.IndexYmlGenerator
{
public class IndexYmlGenerator
{
public static void Main()
{
CreateIndexYmlFile();
}
// Todo: Exception handling
public static void CreateIndexYmlFile()
{
string path = ManifestInterpreter.PathOfManifestFiles;
if (File.Exists(Path.Combine(path, "index.yml")))
{
File.Delete(Path.Combine(path, "index.yml"));
}
IndexFile indexFile = new() { };
Dictionary<(string WindowFilter, bool BackgroundProcess), List<string>> processes = [];
foreach (string file in Directory.EnumerateFiles(path, "*.yml"))
{
string content = File.ReadAllText(file);
Deserializer deserializer = new();
ShortcutFile shortcutFile = deserializer.Deserialize<ShortcutFile>(content);
if (processes.TryGetValue((shortcutFile.WindowFilter, shortcutFile.BackgroundProcess), out List<string>? apps))
{
if (apps.Contains(shortcutFile.PackageName))
{
continue;
}
apps.Add(shortcutFile.PackageName);
continue;
}
processes[(shortcutFile.WindowFilter, shortcutFile.BackgroundProcess)] = [shortcutFile.PackageName];
}
indexFile.Index = [];
foreach (var item in processes)
{
indexFile.Index =
[
.. indexFile.Index,
new IndexFile.IndexItem
{
WindowFilter = item.Key.WindowFilter,
BackgroundProcess = item.Key.BackgroundProcess,
Apps = [.. item.Value],
},
];
}
// Todo: Take the default shell name from the settings or environment variable, default to "+WindowsNT.Shell"
indexFile.DefaultShellName = "+WindowsNT.Shell";
Serializer serializer = new();
string yamlContent = serializer.Serialize(indexFile);
File.WriteAllText(Path.Combine(path, "index.yml"), yamlContent);
}
}
}

View File

@@ -1,24 +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>WinExe</OutputType>
<RootNamespace>ShortcutGuide.IndexYmlGenerator</RootNamespace>
<Nullable>enable</Nullable>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps</OutputPath>
<AssemblyName>PowerToys.ShortcutGuide.IndexYmlGenerator</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="YamlDotNet" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ShortcutGuide.Ui\ShortcutGuide.Ui.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,247 +0,0 @@
PackageName: +WindowsNT.Notepad
Name: Notepad
WindowFilter: "Notepad.exe"
BackgroundProcess: false
Shortcuts:
- SectionName: File
Properties:
- Name: New tab
Recommended: true
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- N
- Name: New window
Shortcut:
- Win: false
Ctrl: true
Shift: true
Alt: false
Keys:
- N
- Name: Open
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- O
- Name: Save
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- S
- Name: Save As
Shortcut:
- Win: false
Ctrl: true
Shift: true
Alt: false
Keys:
- S
- Name: Save all
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: true
Keys:
- S
- Name: Print
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- P
- Name: Close tab
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- W
- Name: Close window
Shortcut:
- Win: false
Ctrl: true
Shift: true
Alt: false
Keys:
- W
- SectionName: Edit
Properties:
- Name: Undo
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- Z
- Name: Redo
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: true
Keys:
- Z
- Name: Cut
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- X
- Name: Copy
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- C
- Name: Paste
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- V
- Name: Search with Bing
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- E
- Name: Find
Recommended: true
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- F
- Name: Find next
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- F3
- Name: Find previous
Shortcut:
- Win: false
Ctrl: false
Shift: true
Alt: false
Keys:
- F3
- Name: Replace
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- H
- Name: Go to
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- G
- Name: Select all
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- A
- Name: Time/Date
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- F5
- SectionName: View
Properties:
- Name: Zoom in
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- Plus
- Name: Zoom out
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- Minus
- Name: Reset zoom
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- 0
- SectionName: Formatting
Properties:
- Name: Bold
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- B
- Name: Italic
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- I
- Name: Insert link
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- K
- Name: Clear formatting
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- Space

View File

@@ -1,773 +0,0 @@
PackageName: +WindowsNT.Shell
WindowFilter: "*"
BackgroundProcess: true
Shortcuts:
- SectionName: Desktop Shortcuts
Properties:
- Name: Close active window
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: true
Keys:
- F4
- Name: Open shutdown box
Description: When no windows are open
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: true
Keys:
- F4
- Name: Cycle through open Windows
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: true
Keys:
- Esc
- Name: Reveal typed password
Description: On sign-in screen
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: true
Keys:
- F8
- Name: Go back
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: true
Keys:
- "<Left>"
- Name: Go forward
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: true
Keys:
- "<Right>"
- Name: Move up one screen
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: true
Keys:
- "<Page Up>"
- Name: Move down one screen
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: true
Keys:
- "<Page Down>"
- Name: Window context menu
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: true
Keys:
- Space
- Name: Switch between open apps
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: true
Keys:
- Tab
Description: While pressing Tab multiple times
- Name: Run command
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: true
Keys:
- "<Underlined letter>"
Description: for the underlined letter in the app
- Name: View open apps
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: true
Keys:
- Tab
- Name: Change start menu size
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- "<Arrow>"
- Name: Move cursor
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- "<ArrowLR>"
Description: To the beginning or end of a word
- Name: Switch keyboard layout
Shortcut:
- Win: false
Ctrl: true
Shift: true
Alt: false
Keys:
- ""
- Name: Select block of text
Shortcut:
- Win: false
Ctrl: true
Shift: true
Alt: false
Keys:
- "<Arrow>"
- Name: Open Task Manager
Shortcut:
- Win: false
Ctrl: true
Shift: true
Alt: false
Keys:
- Esc
- Name: Enable/Disable Chinese IME
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- Space
- Name: Open context menu
Shortcut:
- Win: false
Ctrl: false
Shift: true
Alt: false
Keys:
- F10
Description: For the selected item
- SectionName: Virtual desktop
Properties:
- Name: Open task view
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- Tab
- Name: Add a virtual desktop
Shortcut:
- Win: true
Ctrl: true
Shift: false
Alt: false
Keys:
- D
- Name: Close current desktop
Shortcut:
- Win: true
Ctrl: true
Shift: false
Alt: false
Keys:
- F4
- Name: Switch desktop
Shortcut:
- Win: true
Ctrl: true
Shift: false
Alt: false
Keys:
- "<ArrowLR>"
Recommended: true
- SectionName: "Windows key"
Properties:
- Name: Open start menu
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- ""
- Name: Open Action Center
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "A"
- Name: Open Date and Time
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: true
Keys:
- "D"
- Name: Focus on the notification area
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "B"
- Name: Open narrator
Shortcut:
- Win: true
Ctrl: true
Shift: false
Alt: false
Keys:
- "Enter"
- Name: Open domain search
Shortcut:
- Win: true
Ctrl: true
Shift: false
Alt: false
Keys:
- "F"
- Name: Open Quick Assist
Shortcut:
- Win: true
Ctrl: true
Shift: false
Alt: false
Keys:
- "Q"
- Name: Wake up device
Shortcut:
- Win: true
Ctrl: true
Shift: true
Alt: false
Keys:
- "B"
Description: When black or a blank screen.
- Name: Change input option
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "Space"
Description: To next option
- Name: Change input option
Shortcut:
- Win: true
Ctrl: true
Shift: false
Alt: false
Keys:
- "Space"
Description: To previous option
- Name: Display/Hide desktop
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "D"
- Name: Minimize the active window
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "Down"
Recommended: true
- Name: Open file Explorer
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "E"
- Name: Close Magnifier
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "Esc"
- Name: Open Feedback Hub
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "F"
Recommended: true
- Name: Start IME reconversion
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "/"
- Name: Open Game Bar
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "G"
- Name: Open voice dictation
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "H"
- Name: Minimize or restore all other windows
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "<Home>"
- Name: Open Settings
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "I"
- Name: Set focus to a Windows tip
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "J"
- Name: Open Cast
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "K"
- Name: Lock the device
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "L"
- Name: Snap the window
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "<ArrowLR>"
- Name: Minimize all windows
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "M"
- Name: Zoom out Magnifier
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "-"
- Name: Zoom in Magnifier
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "="
- Name: Open notification center
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "N"
- Name: Lock the device orientation
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "O"
- Name: Open project Settings
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "P"
- Name: Open Settings about Page
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "<Pause>"
- Name: Open the emoji panel
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "."
- Name: Open the emoji panel
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- ";"
- Name: Capture a screenshot
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "<PrtScr>"
Description: Save to the pictures folder
- Name: Open search
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "Q"
- Name: Open search
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "S"
- Name: Open Run dialog
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "R"
- Name: Restore window
Description: If a window is snapped or maximized
Shortcut:
- Win: true
Ctrl: false
Shift: true
Alt: false
Keys:
- "<Down>"
- Name: Make UWP app full screen
Shortcut:
- Win: true
Ctrl: false
Shift: true
Alt: false
Keys:
- "<Up>"
- Name: Move window to monitor
Shortcut:
- Win: true
Ctrl: false
Shift: true
Alt: false
Keys:
- "<Arrow>"
- Name: Open Snipping Tool
Shortcut:
- Win: true
Ctrl: false
Shift: true
Alt: false
Keys:
- "S"
- Name: Stretch window
Description: To the top and bottom of the screen
Shortcut:
- Win: true
Ctrl: false
Shift: true
Alt: false
Keys:
- "<Up>"
- Name: Open task view
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "Tab"
- Name: Open Accessibility Settings
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "U"
- Name: Maximize the active window
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "<Up>"
- Name: Open the clipboard history
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "V"
- Name: Open widgets
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "W"
- Name: Open Quick Link menu
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "X"
- Name: Open snap layouts
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "Z"
- SectionName: Clipboard
Properties:
- Name: Copy
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- "C"
- Name: Cut
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- "X"
- Name: Paste
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- "V"
- Name: Paste
Shortcut:
- Win: false
Ctrl: false
Shift: true
Alt: false
Keys:
- "<Insert>"
Description: Paste as plain text
- SectionName: <TASKBAR1-9>Taskbar Shortcuts
Properties:
- Name: Open app in Taskbar
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "<TASKBAR1-9>"
- Name: Open jump list
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: true
Keys:
- "<TASKBAR1-9>"
- Name: Switch to last active window
Shortcut:
- Win: true
Ctrl: true
Shift: false
Alt: false
Keys:
- "<TASKBAR1-9>"
- Name: Open as administrator
Shortcut:
- Win: true
Ctrl: true
Shift: true
Alt: false
Keys:
- "<TASKBAR1-9>"
- SectionName: Copilot key
Properties:
- Name: Open Copilot
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- '<Copilot>'
Description: When copilot is available
- Name: Open Windows search
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- '<Copilot>'
Description: When copilot is not available
- SectionName: Office key
Properties:
- Name: Open Word
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- "<Office>"
- "W"
- Name: Open Excel
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- "<Office>"
- "X"
- Name: Open PowerPoint
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- "<Office>"
- "P"
- Name: Open Outlook
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- "<Office>"
- "O"
- Name: Open Microsoft Teams
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- "<Office>"
- "T"
- Name: Open OneNote
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- "<Office>"
- "N"
- Name: Open OneDrive
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- "<Office>"
- "D"
- Name: Open Yammer
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- "<Office>"
- "Y"
- Name: Open LinkedIn
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- "<Office>"
- "L"

View File

@@ -1,266 +0,0 @@
PackageName: +WindowsNT.WindowsExplorer
WindowFilter: "explorer.exe"
Name: File Explorer
Shortcuts:
- SectionName: General
Properties:
- Name: Open File Explorer
Shortcut:
- Win: true
Ctrl: false
Shift: false
Alt: false
Keys:
- "E"
Recommended: true
- Name: Select the address bar
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: true
Keys:
- "D"
- Name: Select the address bar
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- "L"
- Name: Select the address bar
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- "F4"
- Name: Select the search box
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- "E"
- Name: Select the search box
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- "F3"
- Name: Select the search box
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- "F"
- Name: Refresh the window
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- "F5"
- Name: Cycle through elements in the active window
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- "F6"
- Name: Maximize or restore the active window
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- "F11"
- SectionName: Navigation
Properties:
- Name: Navigate to the previous folder
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: true
Keys:
- "<Left>"
- Name: Navigate to the previous folder
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- "<Backspace>"
- Name: Navigate to the next folder
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: true
Keys:
- "<Right>"
- Name: Move up a level in the folder path
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: true
Keys:
- "<Up>"
- SectionName: "Window management"
Properties:
- Name: Open a new window
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- "N"
- Name: Open a new tab
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- "T"
Recommended: true
- Name: Close the current active tab
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- "W"
- Name: Move to the next tab
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- "Tab"
- Name: Move to the previous tab
Shortcut:
- Win: false
Ctrl: true
Shift: true
Alt: false
Keys:
- "Tab"
- Name: Move to that tab number
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- "Number (1-9)"
- Name: Show/Hide the preview pane
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: true
Keys:
- "P"
- Name: Show/Hide the details pane
Shortcut:
- Win: false
Ctrl: false
Shift: true
Alt: true
Keys:
- "P"
- Name: Resize all columns to fit text
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- "+"
- Name: Expand all folders
Description: In the navigation pane
Shortcut:
- Win: false
Ctrl: true
Shift: true
Alt: false
Keys:
- "E"
- SectionName: "File management"
Properties:
- Name: Display properties for the selected item
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: true
Keys:
- "Enter"
- Name: Delete the selected item
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- "<Delete>"
- Name: Delete the selected item
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- "D"
- Name: Delete the selected item permanently
Description: "This removes the item without sending it to the Recycle Bin"
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- "D"
- Name: Create a new folder
Shortcut:
- Win: false
Ctrl: true
Shift: true
Alt: false
Keys:
- "N"
Recommended: true
- Name: Rename the selected item
Shortcut:
- Win: false
Ctrl: false
Shift: false
Alt: false
Keys:
- "F2"
- Name: Select multiple items
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- "<Arrow>"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

View File

@@ -1,9 +0,0 @@
PackageName: Microsoft.PowerToys
Name: PowerToys
BackgroundProcess: True
WindowFilter: "powertoys.exe"
Shortcuts:
- SectionName: General
Properties:
# <Populate start>
# <Populate end>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -1,100 +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.Windows.Documents;
using ManagedCommon;
using Microsoft.UI.Xaml.Data;
using ShortcutGuide.Models;
using Windows.System;
namespace ShortcutGuide.Converters
{
public sealed partial class ShortcutDescriptionToKeysConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is ShortcutDescription description)
{
// Populate keysList with the keys from the ShortcutDescription
return GetKeysList(description);
}
else
{
List<object> keysList = [string.Empty];
return keysList;
}
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value;
}
public List<object> GetKeysList(ShortcutDescription description)
{
List<object> shortcutList = [];
if (description.Win)
{
shortcutList.Add(92); // The Windows key or button.
}
if (description.Ctrl)
{
shortcutList.Add("Ctrl");
}
if (description.Alt)
{
shortcutList.Add("Alt");
}
if (description.Shift)
{
shortcutList.Add(16); // The Shift key or button.
}
foreach (var key in description.Keys)
{
// Try to parse a string key number to a VirtualKey
if (int.TryParse(key, out int keyCode))
{
shortcutList.Add(keyCode);
}
else
{
switch (key)
{
// https://learn.microsoft.com/uwp/api/windows.system.virtualkey?view=winrt-20348
case "Up":
shortcutList.Add(38); // The Up Arrow key or button.
break;
case "Down":
shortcutList.Add(40); // The Down Arrow key or button.
break;
case "Left":
shortcutList.Add(37); // The Left Arrow key or button.
break;
case "Right":
shortcutList.Add(39); // The Right Arrow key or button.
break;
case "Back":
shortcutList.Add(8); // The Back key or button.
break;
case "<TASKBAR1-9>":
shortcutList.Add("Num");
break;
default:
shortcutList.Add(key); // Add other keys as strings.
break;
}
}
}
return shortcutList;
}
}
}

View File

@@ -1,50 +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 Windows.Foundation;
using WinUIEx;
namespace ShortcutGuide.Helpers
{
public static class DisplayHelper
{
/// <summary>
/// Returns the display work area for the monitor that contains the specified window.
/// </summary>
/// <param name="hwnd">The window handle</param>
/// <returns>A <see cref="Rect"/> element containing the display area</returns>
public static Rect GetWorkAreaForDisplayWithWindow(nint hwnd)
{
_foundMonitorIndex = -1;
_monitorIndex = 0;
var monitor = NativeMethods.MonitorFromWindow(hwnd, (int)NativeMethods.MonitorFromWindowDwFlags.MONITOR_DEFAULTTONEAREST);
NativeMethods.EnumDisplayMonitors(nint.Zero, nint.Zero, MonitorEnumProc, new NativeMethods.LPARAM(monitor));
return MonitorInfo.GetDisplayMonitors()[_foundMonitorIndex].RectWork;
}
/// <summary>
/// The index of the monitor that contains the specified window. -1 indicates that no monitor was found (yet).
/// </summary>
private static int _foundMonitorIndex = -1;
/// <summary>
/// The index of the monitor in the enumeration. This is used to find the correct monitor in the list of monitors.
/// </summary>
private static int _monitorIndex;
private static bool MonitorEnumProc(nint hMonitor, nint hdcMonitor, ref NativeMethods.RECT lprcMonitor, nint dwData)
{
nint targetMonitor = dwData;
if (hMonitor == targetMonitor)
{
_foundMonitorIndex = _monitorIndex;
return false;
}
_monitorIndex++;
return true;
}
}
}

View File

@@ -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.
namespace ShortcutGuide.Helpers
{
// This class is rewritten from C++ to C# from the measure tool project
internal static class DpiHelper
{
#pragma warning disable SA1310 // Field names should not contain underscore
private const int DEFAULT_DPI = 96;
private const int MONITOR_DEFAULTTONEAREST = 2;
private const int MDT_EFFECTIVE_DPI = 0;
#pragma warning restore SA1310 // Field names should not contain underscore
public static float GetDPIScaleForWindow(int hwnd)
{
int dpi = DEFAULT_DPI;
GetScreenDPIForWindow(hwnd, ref dpi);
return (float)dpi / DEFAULT_DPI;
}
private static long GetScreenDPIForWindow(int hwnd, ref int dpi)
{
var targetMonitor = NativeMethods.MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
return GetScreenDPIForMonitor(targetMonitor.ToInt32(), ref dpi);
}
private static long GetScreenDPIForMonitor(int targetMonitor, ref int dpi)
{
if (targetMonitor != 0)
{
int dummy = 0;
return NativeMethods.GetDpiForMonitor(targetMonitor, MDT_EFFECTIVE_DPI, ref dpi, ref dummy);
}
else
{
dpi = DEFAULT_DPI;
return 0x80004005L;
}
}
}
}

View File

@@ -1,150 +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.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using ShortcutGuide.Models;
using YamlDotNet.Serialization;
namespace ShortcutGuide.Helpers
{
/// <summary>
/// Helps to interpret the manifest files for the Shortcut Guide.
/// </summary>
public class ManifestInterpreter
{
// Todo: Get language from settings or environment variable, default to "en-US"
/// <summary>
/// Gets the language used for the manifest files.
/// </summary>
public static string Language => "en-US";
/// <summary>
/// Returns the shortcuts for a specific application.
/// </summary>
/// <remarks>
/// The method should only be called if the application is known to have a shortcuts file.
/// </remarks>
/// <param name="applicationName">The manifest id.</param>
/// <returns>The deserialized shortcuts file.</returns>
/// <exception cref="FileNotFoundException">The requested file was not found.</exception>
public static ShortcutFile GetShortcutsOfApplication(string applicationName)
{
string path = PathOfManifestFiles;
IEnumerable<string> files = Directory.EnumerateFiles(path, applicationName + ".*.yml") ??
throw new FileNotFoundException($"The file for the application '{applicationName}' was not found in '{path}'.");
IEnumerable<string> filesEnumerable = files as string[] ?? [.. files];
return filesEnumerable.Any(f => f.EndsWith($".{Language}.yml", StringComparison.InvariantCulture))
? YamlToShortcutList(File.ReadAllText(Path.Combine(path, applicationName + $".{Language}.yml")))
: filesEnumerable.Any(f => f.EndsWith(".en-US.yml", StringComparison.InvariantCulture))
? YamlToShortcutList(File.ReadAllText(filesEnumerable.First(f => f.EndsWith(".en-US.yml", StringComparison.InvariantCulture))))
: throw new FileNotFoundException($"The file for the application '{applicationName}' was not found in '{path}' with the language '{Language}' or 'en-US'.");
}
/// <summary>
/// Deserializes the content of a YAML file to a <see cref="ShortcutFile"/>.
/// </summary>
/// <param name="content">The content of the YAML file.</param>
/// <returns>A deserialized <see cref="ShortcutFile"/> object.</returns>
private static ShortcutFile YamlToShortcutList(string content)
{
Deserializer deserializer = new();
return deserializer.Deserialize<ShortcutFile>(content);
}
/// <summary>
/// Gets the path to the directory where the manifest files are stored.
/// </summary>
public static string PathOfManifestFiles => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Microsoft", "WinGet", "KeyboardShortcuts");
/// <summary>
/// Retrieves the index YAML file that contains the list of all applications and their shortcuts.
/// </summary>
/// <returns>A deserialized <see cref="IndexFile"/> object.</returns>
public static IndexFile GetIndexYamlFile()
{
string path = PathOfManifestFiles;
string content = File.ReadAllText(Path.Combine(path, "index.yml"));
Deserializer deserializer = new();
return deserializer.Deserialize<IndexFile>(content);
}
/// <summary>
/// Retrieves all application IDs that should be displayed, based on the foreground window and background processes.
/// </summary>
/// <returns>An array of all application IDs.</returns>
public static string[] GetAllCurrentApplicationIds()
{
nint handle = NativeMethods.GetForegroundWindow();
List<string> applicationIds = [];
Process[] processes = Process.GetProcesses();
if (NativeMethods.GetWindowThreadProcessId(handle, out uint processId) > 0)
{
string? name = Process.GetProcessById((int)processId).MainModule?.ModuleName;
if (name is not null)
{
try
{
foreach (var item in GetIndexYamlFile().Index.First((s) => !s.BackgroundProcess && IsMatch(name, s.WindowFilter)).Apps)
{
applicationIds.Add(item);
}
}
catch (InvalidOperationException)
{
}
}
}
foreach (var item in GetIndexYamlFile().Index.Where((s) => s.BackgroundProcess))
{
try
{
if (processes.Any((p) =>
{
try
{
return IsMatch(p.MainModule!.ModuleName, item.WindowFilter);
}
catch (Win32Exception)
{
return false;
}
}))
{
foreach (var app in item.Apps)
{
applicationIds.Add(app);
}
}
}
catch (InvalidOperationException)
{
}
}
return [.. applicationIds];
static bool IsMatch(string input, string filter)
{
input = input.ToLower(CultureInfo.InvariantCulture);
filter = filter.ToLower(CultureInfo.InvariantCulture);
string regexPattern = "^" + Regex.Escape(filter).Replace("\\*", ".*") + "$";
return Regex.IsMatch(input, regexPattern);
}
}
}
}

View File

@@ -1,85 +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.UI.Xaml;
namespace ShortcutGuide.Helpers;
internal static class NavItemIconHelper
{
public static object GetSelectedIcon(DependencyObject obj)
{
return obj.GetValue(SelectedIconProperty);
}
public static void SetSelectedIcon(DependencyObject obj, object value)
{
obj.SetValue(SelectedIconProperty, value);
}
public static readonly DependencyProperty SelectedIconProperty =
DependencyProperty.RegisterAttached("SelectedIcon", typeof(object), typeof(NavItemIconHelper), new PropertyMetadata(null));
/// <summary>
/// Gets the value of <see cref="ShowNotificationDotProperty" /> for a <see cref="DependencyObject" />
/// </summary>
/// <returns>Returns a boolean indicating whether the notification dot should be shown.</returns>
public static bool GetShowNotificationDot(DependencyObject obj)
{
return (bool)obj.GetValue(ShowNotificationDotProperty);
}
/// <summary>
/// Sets <see cref="ShowNotificationDotProperty" /> on a <see cref="DependencyObject" />
/// </summary>
public static void SetShowNotificationDot(DependencyObject obj, bool value)
{
obj.SetValue(ShowNotificationDotProperty, value);
}
/// <summary>
/// An attached property that sets whether or not a notification dot should be shown on an associated <see cref="Microsoft.UI.Xaml.Controls.NavigationViewItem" />
/// </summary>
public static readonly DependencyProperty ShowNotificationDotProperty =
DependencyProperty.RegisterAttached("ShowNotificationDot", typeof(bool), typeof(NavItemIconHelper), new PropertyMetadata(false));
/// <summary>
/// Gets the value of <see cref="UnselectedIconProperty"/> for a <see cref="DependencyObject"/>
/// </summary>
/// <returns>Returns the unselected icon as an object.</returns>
public static object GetUnselectedIcon(DependencyObject obj)
{
return (object)obj.GetValue(UnselectedIconProperty);
}
/// <summary>
/// Sets the value of <see cref="UnselectedIconProperty"/> for a <see cref="DependencyObject"/>
/// </summary>
public static void SetUnselectedIcon(DependencyObject obj, object value)
{
obj.SetValue(UnselectedIconProperty, value);
}
/// <summary>
/// An attached property that sets the unselected icon on an associated <see cref="Microsoft.UI.Xaml.Controls.NavigationViewItem" />
/// </summary>
public static readonly DependencyProperty UnselectedIconProperty =
DependencyProperty.RegisterAttached("UnselectedIcon", typeof(object), typeof(NavItemIconHelper), new PropertyMetadata(null));
public static Visibility GetStaticIconVisibility(DependencyObject obj)
{
return (Visibility)obj.GetValue(StaticIconVisibilityProperty);
}
public static void SetStaticIconVisibility(DependencyObject obj, Visibility value)
{
obj.SetValue(StaticIconVisibilityProperty, value);
}
/// <summary>
/// An attached property that sets the visibility of the static icon in the associated <see cref="Microsoft.UI.Xaml.Controls.NavigationViewItem"/>.
/// </summary>
public static readonly DependencyProperty StaticIconVisibilityProperty =
DependencyProperty.RegisterAttached("StaticIconVisibility", typeof(Visibility), typeof(NavItemIconHelper), new PropertyMetadata(Visibility.Collapsed));
}

View File

@@ -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 System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.PowerToys.Settings.UI.Library;
using ShortcutGuide.Models;
namespace ShortcutGuide.Helpers
{
public static class PinnedShortcutsHelper
{
public static void UpdatePinnedShortcuts(string appName, ShortcutEntry shortcutEntry)
{
if (!App.PinnedShortcuts[appName].Remove(shortcutEntry))
{
App.PinnedShortcuts[appName].Add(shortcutEntry);
}
Save();
}
public static void Save()
{
string serialized = JsonSerializer.Serialize(App.PinnedShortcuts);
SettingsUtils settingsUtils = new();
string pinnedPath = settingsUtils.GetSettingsFilePath(ShortcutGuideSettings.ModuleName, "Pinned.json");
File.WriteAllText(pinnedPath, serialized);
}
}
}

View File

@@ -1,187 +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.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.PowerToys.Settings.UI.Library;
using static ShortcutGuide.Helpers.ResourceLoaderInstance;
namespace ShortcutGuide.Helpers
{
/// <summary>
/// Populates the PowerToys shortcuts in the manifest files.
/// </summary>
internal sealed partial class PowerToysShortcutsPopulator
{
/// <summary>
/// Populates the PowerToys shortcuts in the manifest files.
/// </summary>
public static void Populate()
{
string path = Path.Combine(ManifestInterpreter.PathOfManifestFiles, $"Microsoft.PowerToys.{ManifestInterpreter.Language}.yml");
StringBuilder content = new(File.ReadAllText(path));
const string populateStartString = "# <Populate start>";
const string populateEndString = "# <Populate end>";
content = new(PopulateRegex().Replace(content.ToString(), populateStartString + Environment.NewLine));
ISettingsUtils settingsUtils = new SettingsUtils();
EnabledModules enabledModules = SettingsRepository<GeneralSettings>.GetInstance(settingsUtils).SettingsConfig.Enabled;
if (enabledModules.AdvancedPaste)
{
AdvancedPasteProperties advancedPasteProperties = SettingsRepository<AdvancedPasteSettings>.GetInstance(settingsUtils).SettingsConfig.Properties;
content.Append(HotkeySettingsToYaml(advancedPasteProperties.AdvancedPasteUIShortcut, SettingsResourceLoader.GetString("AdvancedPaste/ModuleTitle"), SettingsResourceLoader.GetString("AdvancedPasteUI_Shortcut/Header")));
content.Append(HotkeySettingsToYaml(advancedPasteProperties.PasteAsPlainTextShortcut, SettingsResourceLoader.GetString("AdvancedPaste/ModuleTitle"), SettingsResourceLoader.GetString("PasteAsPlainText_Shortcut/Header")));
content.Append(HotkeySettingsToYaml(advancedPasteProperties.PasteAsMarkdownShortcut, SettingsResourceLoader.GetString("AdvancedPaste/ModuleTitle"), SettingsResourceLoader.GetString("PasteAsMarkdown_Shortcut/Header")));
content.Append(HotkeySettingsToYaml(advancedPasteProperties.PasteAsJsonShortcut, SettingsResourceLoader.GetString("AdvancedPaste/ModuleTitle"), SettingsResourceLoader.GetString("PasteAsJson_Shortcut/Header")));
if (advancedPasteProperties.AdditionalActions.ImageToText.IsShown)
{
content.Append(HotkeySettingsToYaml(advancedPasteProperties.AdditionalActions.ImageToText.Shortcut, SettingsResourceLoader.GetString("AdvancedPaste/ModuleTitle"), SettingsResourceLoader.GetString("ImageToText/Header")));
}
if (advancedPasteProperties.AdditionalActions.PasteAsFile.IsShown)
{
content.Append(HotkeySettingsToYaml(advancedPasteProperties.AdditionalActions.PasteAsFile.PasteAsTxtFile.Shortcut, SettingsResourceLoader.GetString("AdvancedPaste/ModuleTitle"), SettingsResourceLoader.GetString("PasteAsTxtFile/Header")));
content.Append(HotkeySettingsToYaml(advancedPasteProperties.AdditionalActions.PasteAsFile.PasteAsPngFile.Shortcut, SettingsResourceLoader.GetString("AdvancedPaste/ModuleTitle"), SettingsResourceLoader.GetString("PasteAsPngFile/Header")));
content.Append(HotkeySettingsToYaml(advancedPasteProperties.AdditionalActions.PasteAsFile.PasteAsHtmlFile.Shortcut, SettingsResourceLoader.GetString("AdvancedPaste/ModuleTitle"), SettingsResourceLoader.GetString("PasteAsHtmlFile/Header")));
}
if (advancedPasteProperties.AdditionalActions.Transcode.IsShown)
{
content.Append(HotkeySettingsToYaml(advancedPasteProperties.AdditionalActions.Transcode.TranscodeToMp3.Shortcut, SettingsResourceLoader.GetString("AdvancedPaste/ModuleTitle"), SettingsResourceLoader.GetString("TranscodeToMp3/Header")));
content.Append(HotkeySettingsToYaml(advancedPasteProperties.AdditionalActions.Transcode.TranscodeToMp4.Shortcut, SettingsResourceLoader.GetString("AdvancedPaste/ModuleTitle"), SettingsResourceLoader.GetString("TranscodeToMp4/Header")));
}
}
if (enabledModules.AlwaysOnTop)
{
content.Append(HotkeySettingsToYaml(SettingsRepository<AlwaysOnTopSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.Hotkey, SettingsResourceLoader.GetString("AlwaysOnTop/ModuleTitle"), SettingsResourceLoader.GetString("AlwaysOnTop_ShortDescription")));
}
if (enabledModules.ColorPicker)
{
content.Append(HotkeySettingsToYaml(SettingsRepository<ColorPickerSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.ActivationShortcut, SettingsResourceLoader.GetString("ColorPicker/ModuleTitle"), SettingsResourceLoader.GetString("ColorPicker_ShortDescription")));
}
if (enabledModules.CmdPal)
{
content.Append(HotkeySettingsToYaml(new CmdPalProperties().Hotkey, SettingsResourceLoader.GetString("CmdPal/ModuleTitle")));
}
if (enabledModules.CropAndLock)
{
CropAndLockProperties cropAndLockProperties = SettingsRepository<CropAndLockSettings>.GetInstance(settingsUtils).SettingsConfig.Properties;
content.Append(HotkeySettingsToYaml(cropAndLockProperties.ThumbnailHotkey, SettingsResourceLoader.GetString("CropAndLock/ModuleTitle"), SettingsResourceLoader.GetString("CropAndLock_Thumbnail")));
content.Append(HotkeySettingsToYaml(cropAndLockProperties.ReparentHotkey, SettingsResourceLoader.GetString("CropAndLock/ModuleTitle"), SettingsResourceLoader.GetString("CropAndLock_Reparent")));
}
if (enabledModules.FancyZones)
{
content.Append(HotkeySettingsToYaml(SettingsRepository<FancyZonesSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.FancyzonesEditorHotkey, SettingsResourceLoader.GetString("FancyZones/ModuleTitle"), SettingsResourceLoader.GetString("FancyZones_OpenEditor")));
}
if (enabledModules.MouseHighlighter)
{
content.Append(HotkeySettingsToYaml(SettingsRepository<MouseHighlighterSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.ActivationShortcut, SettingsResourceLoader.GetString("MouseUtils_MouseHighlighter/Header"), SettingsResourceLoader.GetString("MouseHighlighter_ShortDescription")));
}
if (enabledModules.MouseJump)
{
content.Append(HotkeySettingsToYaml(SettingsRepository<MouseJumpSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.ActivationShortcut, SettingsResourceLoader.GetString("MouseUtils_MouseJump/Header"), SettingsResourceLoader.GetString("MouseJump_ShortDescription")));
}
if (enabledModules.MousePointerCrosshairs)
{
content.Append(HotkeySettingsToYaml(SettingsRepository<MousePointerCrosshairsSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.ActivationShortcut, SettingsResourceLoader.GetString("MouseUtils_MousePointerCrosshairs/Header"), SettingsResourceLoader.GetString("MouseCrosshairs_ShortDescription")));
}
if (enabledModules.Peek)
{
content.Append(HotkeySettingsToYaml(SettingsRepository<PeekSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.ActivationShortcut, SettingsResourceLoader.GetString("Peek/ModuleTitle")));
}
if (enabledModules.PowerLauncher)
{
content.Append(HotkeySettingsToYaml(SettingsRepository<PowerLauncherSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.OpenPowerLauncher, SettingsResourceLoader.GetString("PowerLauncher/ModuleTitle")));
}
if (enabledModules.MeasureTool)
{
content.Append(HotkeySettingsToYaml(SettingsRepository<MeasureToolSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.ActivationShortcut, SettingsResourceLoader.GetString("MeasureTool/ModuleTitle"), SettingsResourceLoader.GetString("ScreenRuler_ShortDescription")));
}
if (enabledModules.ShortcutGuide)
{
content.Append(HotkeySettingsToYaml(SettingsRepository<ShortcutGuideSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.DefaultOpenShortcutGuide, SettingsResourceLoader.GetString("ShortcutGuide/ModuleTitle"), SettingsResourceLoader.GetString("ShortcutGuide_ShortDescription")));
}
if (enabledModules.PowerOcr)
{
content.Append(HotkeySettingsToYaml(SettingsRepository<PowerOcrSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.ActivationShortcut, SettingsResourceLoader.GetString("TextExtractor/ModuleTitle"), SettingsResourceLoader.GetString("PowerOcr_ShortDescription")));
}
if (enabledModules.Workspaces)
{
content.Append(HotkeySettingsToYaml(SettingsRepository<WorkspacesSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.Hotkey, SettingsResourceLoader.GetString("Workspaces/ModuleTitle"), SettingsResourceLoader.GetString("Workspaces_ShortDescription")));
}
// Todo: ZoomIt hotkeys currently not supported, because ZoomIt does save their settings in the view model instead of the settings properties, which is weird.
/*
if (enabledModules.ZoomIt)
{
content.Append(HotkeySettingsToYaml(SettingsRepository<ZoomItSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.ToggleKey, SettingsResourceLoader.GetString("ZoomIt/ModuleTitle"), SettingsResourceLoader.GetString("ZoomIt_ZoomGroup/Header")));
content.Append(HotkeySettingsToYaml(SettingsRepository<ZoomItSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.LiveZoomToggleKey, SettingsResourceLoader.GetString("ZoomIt/ModuleTitle"), SettingsResourceLoader.GetString("ZoomIt_LiveZoomGroup/Header")));
content.Append(HotkeySettingsToYaml(SettingsRepository<ZoomItSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.DrawToggleKey, SettingsResourceLoader.GetString("ZoomIt/ModuleTitle"), SettingsResourceLoader.GetString("ZoomIt_DrawGroup/Header")));
content.Append(HotkeySettingsToYaml(SettingsRepository<ZoomItSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.DemoTypeToggleKey, SettingsResourceLoader.GetString("ZoomIt/ModuleTitle"), SettingsResourceLoader.GetString("ZoomIt_DemoTypeGroup/Header")));
content.Append(HotkeySettingsToYaml(SettingsRepository<ZoomItSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.BreakTimerKey, SettingsResourceLoader.GetString("ZoomIt/ModuleTitle"), SettingsResourceLoader.GetString("ZoomIt_BreakGroup/Header")));
content.Append(HotkeySettingsToYaml(SettingsRepository<ZoomItSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.RecordToggleKey, SettingsResourceLoader.GetString("ZoomIt/ModuleTitle"), SettingsResourceLoader.GetString("ZoomIt_RecordGroup/Header")));
content.Append(HotkeySettingsToYaml(SettingsRepository<ZoomItSettings>.GetInstance(settingsUtils).SettingsConfig.Properties.SnipToggleKey, SettingsResourceLoader.GetString("ZoomIt/ModuleTitle"), SettingsResourceLoader.GetString("ZoomIt_SnipGroup/Header")));
}*/
content.Append(populateEndString);
File.WriteAllText(path, content.ToString());
}
/// <summary>
/// Converts the hotkey settings to a YAML format string for the manifest file.
/// </summary>
/// <param name="hotkeySettings">Object containing a hotkey from the settings.</param>
/// <param name="moduleName">The name of the PowerToys module.</param>
/// <param name="description">Description of the action.</param>
/// <returns>Yaml code for the manifest file.</returns>
private static string HotkeySettingsToYaml(HotkeySettings hotkeySettings, string moduleName, string? description = null)
{
string content = string.Empty;
content += " - Name: " + moduleName + Environment.NewLine;
content += " Shortcut: " + Environment.NewLine;
content += " - Win: " + hotkeySettings.Win.ToString() + Environment.NewLine;
content += " Ctrl: " + hotkeySettings.Ctrl.ToString() + Environment.NewLine;
content += " Alt: " + hotkeySettings.Alt.ToString() + Environment.NewLine;
content += " Shift: " + hotkeySettings.Shift.ToString() + Environment.NewLine;
content += " Keys:" + Environment.NewLine;
content += " - " + hotkeySettings.Code.ToString(CultureInfo.InvariantCulture) + Environment.NewLine;
if (description != null)
{
content += " Description: " + description + Environment.NewLine;
}
return content;
}
/// <inheritdoc cref="HotkeySettingsToYaml(HotkeySettings, string, string?)"/>
private static string HotkeySettingsToYaml(KeyboardKeysProperty hotkeySettings, string moduleName, string? description = null)
{
return HotkeySettingsToYaml(hotkeySettings.Value, moduleName, description);
}
[GeneratedRegex(@"# <Populate start>[\s\S\n\r]*# <Populate end>")]
private static partial Regex PopulateRegex();
}
}

View File

@@ -1,27 +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.Windows.ApplicationModel.Resources;
namespace ShortcutGuide.Helpers
{
internal static class ResourceLoaderInstance
{
/// <summary>
/// Gets the resource loader for the Shortcut Guide module.
/// </summary>
internal static ResourceLoader ResourceLoader { get; private set; }
/// <summary>
/// Gets the resource loader for the Settings module.
/// </summary>
internal static ResourceLoader SettingsResourceLoader { get; private set; }
static ResourceLoaderInstance()
{
ResourceLoader = new ResourceLoader("PowerToys.ShortcutGuide.pri");
SettingsResourceLoader = new ResourceLoader("PowerToys.Settings.pri");
}
}
}

View File

@@ -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 Microsoft.UI.Xaml.Markup;
namespace ShortcutGuide.Helpers
{
[MarkupExtensionReturnType(ReturnType = typeof(string))]
public partial class StringResourceExtension : MarkupExtension
{
public enum SpecialTreatment
{
None,
FirstCharOnly,
EverythingExceptFirstChar,
}
public string Key { get; set; } = string.Empty;
public SpecialTreatment Treatment { get; set; } = SpecialTreatment.None;
protected override object ProvideValue() => Treatment switch
{
SpecialTreatment.FirstCharOnly => ResourceLoaderInstance.ResourceLoader.GetString(Key)[0].ToString(),
SpecialTreatment.EverythingExceptFirstChar => ResourceLoaderInstance.ResourceLoader.GetString(Key)[1..],
_ => ResourceLoaderInstance.ResourceLoader.GetString(Key),
};
}
}

View File

@@ -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.Runtime.InteropServices;
using WinRT.Interop;
using TasklistButton = ShortcutGuide.NativeMethods.TasklistButton;
namespace ShortcutGuide.Helpers
{
/// <summary>
/// Provides methods to retrieve the positions of taskbar buttons on the current monitor.
/// </summary>
internal static class TasklistPositions
{
/// <summary>
/// Retrieves the taskbar buttons for the current monitor.
/// </summary>
/// <returns>An array of the taskbar buttons.</returns>
public static TasklistButton[] GetButtons()
{
var monitor = NativeMethods.MonitorFromWindow(WindowNative.GetWindowHandle(App.MainWindow), 0);
nint ptr = NativeMethods.GetTasklistButtons(monitor, out int size);
if (ptr == nint.Zero)
{
return [];
}
if (size <= 0)
{
return [];
}
TasklistButton[] buttons = new TasklistButton[size];
nint currentPtr = ptr;
for (int i = 0; i < size; i++)
{
buttons[i] = Marshal.PtrToStructure<TasklistButton>(currentPtr);
currentPtr += Marshal.SizeOf<TasklistButton>();
}
return buttons;
}
}
}

View File

@@ -1,22 +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 ShortcutGuide.Models
{
public struct IndexFile
{
public struct IndexItem
{
public string WindowFilter { get; set; }
public bool BackgroundProcess { get; set; }
public string[] Apps { get; set; }
}
public string DefaultShellName { get; set; }
public IndexItem[] Index { get; set; }
}
}

View File

@@ -1,13 +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 ShortcutGuide.Models
{
public struct ShortcutCategory
{
public string SectionName { get; set; }
public ShortcutEntry[] Properties { get; set; }
}
}

View File

@@ -1,60 +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 System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace ShortcutGuide.Models
{
public class ShortcutDescription(bool ctrl, bool shift, bool alt, bool win, string[] keys)
{
public ShortcutDescription()
: this(false, false, false, false, [])
{
}
[JsonPropertyName(nameof(Ctrl))]
public bool Ctrl { get; set; } = ctrl;
[JsonPropertyName(nameof(Shift))]
public bool Shift { get; set; } = shift;
[JsonPropertyName(nameof(Alt))]
public bool Alt { get; set; } = alt;
[JsonPropertyName(nameof(Win))]
public bool Win { get; set; } = win;
[JsonPropertyName(nameof(Keys))]
public string[] Keys { get; set; } = keys;
public override bool Equals(object? obj)
{
return obj is ShortcutDescription other && Ctrl == other.Ctrl &&
Shift == other.Shift &&
Alt == other.Alt &&
Win == other.Win &&
Keys.SequenceEqual(other.Keys);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public static bool operator ==(ShortcutDescription? left, ShortcutDescription? right)
{
return (left is null && right is null) || (left is not null && right is not null && left.Equals(right));
}
public static bool operator !=(ShortcutDescription? left, ShortcutDescription? right)
{
return !(left == right);
}
}
}

View File

@@ -1,63 +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 System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Markup;
using Windows.UI.Text;
using static ShortcutGuide.Models.ShortcutEntry;
using Orientation = Microsoft.UI.Xaml.Controls.Orientation;
namespace ShortcutGuide.Models
{
public class ShortcutEntry(string name, string? description, bool recommended, ShortcutDescription[] shortcutDescriptions)
{
public override bool Equals(object? obj)
{
return obj is ShortcutEntry other && Name == other.Name &&
Description == other.Description &&
Shortcut.Length == other.Shortcut.Length &&
Shortcut.SequenceEqual(other.Shortcut);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public static bool operator ==(ShortcutEntry? left, ShortcutEntry? right)
{
return (left is null && right is null) || (left is not null && right is not null && left.Equals(right));
}
public static bool operator !=(ShortcutEntry? left, ShortcutEntry? right)
{
return !(left == right);
}
public ShortcutEntry()
: this(string.Empty, string.Empty, false, [])
{
}
[JsonPropertyName(nameof(Name))]
public string Name { get; set; } = name;
[JsonPropertyName(nameof(Description))]
public string? Description { get; set; } = description;
[JsonPropertyName(nameof(Recommended))]
public bool Recommended { get; set; } = recommended;
[JsonPropertyName(nameof(Shortcut))]
public ShortcutDescription[] Shortcut { get; set; } = shortcutDescriptions;
}
}

View File

@@ -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.
namespace ShortcutGuide.Models
{
public struct ShortcutFile
{
public string PackageName { get; set; }
public ShortcutCategory[] Shortcuts { get; set; }
public string WindowFilter { get; set; }
public bool BackgroundProcess { get; set; }
public string Name { get; set; }
}
}

View File

@@ -1,21 +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 System.Text;
using System.Threading.Tasks;
namespace ShortcutGuide.Models
{
internal sealed class ShortcutPageNavParam
{
public string AppName { get; set; } = string.Empty;
public ShortcutFile ShortcutFile { get; set; }
public int PageIndex { get; set; }
}
}

View File

@@ -1,127 +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.Runtime.InteropServices;
using Windows.Graphics;
namespace ShortcutGuide;
internal static partial class NativeMethods
{
internal const int GWL_STYLE = -16;
internal const int WS_CAPTION = 0x00C00000;
[LibraryImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
[LibraryImport("user32.dll", SetLastError = true)]
internal static partial int GetWindowLongW(IntPtr hWnd, int nIndex);
[LibraryImport("user32.dll")]
internal static partial int SetWindowLongW(IntPtr hWnd, int nIndex, int dwNewLong);
[LibraryImport("user32.dll", StringMarshalling = StringMarshalling.Utf16)]
internal static partial IntPtr FindWindowA(in string lpClassName, in string? lpWindowName);
[LibraryImport("User32.dll")]
internal static partial IntPtr MonitorFromWindow(IntPtr hwnd, int dwFlags);
[LibraryImport("Shcore.dll")]
internal static partial long GetDpiForMonitor(IntPtr hmonitor, int dpiType, ref int dpiX, ref int dpiY);
[LibraryImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool GetCursorPos(out POINT lpPoint);
[LibraryImport("user32.dll")]
internal static partial IntPtr GetForegroundWindow();
[LibraryImport("user32.dll", SetLastError = true)]
internal static partial uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
[LibraryImport("user32.dll")]
internal static partial short GetAsyncKeyState(int vKey);
[LibraryImport("ShortcutGuide.CPPProject.dll", EntryPoint = "get_buttons")]
internal static partial IntPtr GetTasklistButtons(IntPtr monitor, out int size);
[LibraryImport("ShortcutGuide.CPPProject.dll", EntryPoint = "IsCurrentWindowExcludedFromShortcutGuide")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool IsCurrentWindowExcludedFromShortcutGuide();
[LibraryImport("User32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumDelegate lpfnEnum, IntPtr dwData);
internal delegate bool MonitorEnumDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData);
internal struct LPARAM(IntPtr value)
{
internal IntPtr Value = value;
public static implicit operator IntPtr(LPARAM lParam)
{
return lParam.Value;
}
public static implicit operator LPARAM(IntPtr value)
{
return new LPARAM(value);
}
public static implicit operator LPARAM(int value)
{
return new LPARAM(new IntPtr(value));
}
public static implicit operator int(LPARAM lParam)
{
return lParam.Value.ToInt32();
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
internal struct POINT
{
internal int X;
internal int Y;
public static implicit operator PointInt32(POINT point)
{
return new PointInt32(point.X, point.Y);
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct TasklistButton
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Name;
public int X;
public int Y;
public int Width;
public int Height;
public int Keynum;
}
public enum MonitorFromWindowDwFlags
{
MONITOR_DEFAULTTONEAREST = 2,
}
}

View File

@@ -1,84 +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.Diagnostics;
using System.IO;
using System.Threading;
using System.Windows;
using ManagedCommon;
using Microsoft.UI.Dispatching;
using Microsoft.Windows.AppLifecycle;
using ShortcutGuide.Helpers;
using Application = Microsoft.UI.Xaml.Application;
namespace ShortcutGuide
{
public sealed class Program
{
private static readonly string[] InbuiltManifestFiles = [
"+WindowsNT.Shell.en-US.yml",
"+WindowsNT.WindowsExplorer.en-US.yml",
"+WindowsNT.Notepad.en-US.yml",
"Microsoft.PowerToys.en-US.yml",
];
[STAThread]
public static void Main()
{
if (PowerToys.GPOWrapper.GPOWrapper.GetConfiguredShortcutGuideEnabledValue() == PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
{
Logger.LogWarning("Tried to start with a GPO policy setting the utility to always be disabled. Please contact your systems administrator.");
return;
}
Directory.CreateDirectory(ManifestInterpreter.PathOfManifestFiles);
if (NativeMethods.IsCurrentWindowExcludedFromShortcutGuide())
{
return;
}
// Todo: Only copy files after an update.
// Todo: Handle error
foreach (var file in InbuiltManifestFiles)
{
File.Copy(Path.GetDirectoryName(Environment.ProcessPath) + "\\Assets\\ShortcutGuide\\" + file, ManifestInterpreter.PathOfManifestFiles + "\\" + file, true);
}
Process indexGeneration = Process.Start(Path.GetDirectoryName(Environment.ProcessPath) + "\\PowerToys.ShortcutGuide.IndexYmlGenerator.exe");
indexGeneration.WaitForExit();
if (indexGeneration.ExitCode != 0)
{
Logger.LogError("Index generation failed with exit code: " + indexGeneration.ExitCode);
MessageBox.Show($"Shortcut Guide encountered an error while generating the index file. There is likely a corrupt shortcuts file in \"{ManifestInterpreter.PathOfManifestFiles}\". Try deleting this directory.", "Error displaying shortcuts", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
PowerToysShortcutsPopulator.Populate();
Logger.InitializeLogger("\\ShortcutGuide\\Logs");
WinRT.ComWrappersSupport.InitializeComWrappers();
var instanceKey = AppInstance.FindOrRegisterForKey("PowerToys_ShortcutGuide_Instance");
if (instanceKey.IsCurrent)
{
Application.Start((p) =>
{
var context = new DispatcherQueueSynchronizationContext(DispatcherQueue.GetForCurrentThread());
SynchronizationContext.SetSynchronizationContext(context);
_ = new App();
});
}
else
{
Logger.LogWarning("Another instance of ShortcutGuide is running. Exiting ShortcutGuide");
}
// Something prevents the process from exiting, so we need to kill it manually.
Process.GetCurrentProcess().Kill();
}
}
}

View File

@@ -1,146 +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>WinExe</OutputType>
<RootNamespace>ShortcutGuide</RootNamespace>
<ApplicationManifest>app.manifest</ApplicationManifest>
<UseWinUI>true</UseWinUI>
<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
<WindowsPackageType>None</WindowsPackageType>
<Nullable>enable</Nullable>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps</OutputPath>
<AssemblyName>PowerToys.ShortcutGuide</AssemblyName>
<DefineConstants>DISABLE_XAML_GENERATED_MAIN,TRACE</DefineConstants>
<ApplicationIcon>Assets\ShortcutGuide\ShortcutGuide.ico</ApplicationIcon>
<!-- MRT from windows app sdk will search for a pri file with the same name of the module before defaulting to resources.pri -->
<ProjectPriFileName>PowerToys.ShortcutGuide.pri</ProjectPriFileName>
</PropertyGroup>
<ItemGroup>
<Content Remove="Assets\CopilotKey.png" />
<Content Remove="Assets\ShortcutGuide\+WindowsNT.Shell.en-US.yml" />
<Content Remove="Assets\ShortcutGuide\+WindowsNT.WindowsExplorer.en-US.yml" />
<Content Remove="Assets\ShortcutGuide\HeroImage.png" />
<Content Remove="Assets\ShortcutGuide\Microsoft.PowerToys.en-US.yml" />
<Content Remove="Assets\ShortcutGuide\OfficeKey.png" />
<Content Remove="Assets\ShortcutGuide\ShortcutGuide.ico" />
</ItemGroup>
<ItemGroup>
<None Remove="ShortcutGuideXAML\CustomNavigationViewStyle.xaml" />
<None Remove="ShortcutGuideXAML\Pages\ShortcutsPage.xaml" />
<None Remove="ShortcutGuideXAML\TaskbarIndicator.xaml" />
<None Remove="ShortcutGuideXAML\TaskbarWindow.xaml" />
<None Include="Assets\ShortcutGuide\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<Target Name="CopyPRIFileToOutputDir" AfterTargets="Build">
<Message Text="Executing CopyPRIFileToOutputDir task" Importance="High" />
<ItemGroup>
<PRIFile Include="$(OutDir)**\PowerToys.ShortcutGuide.pri" />
</ItemGroup>
<Copy SourceFiles="@(PRIFile)" DestinationFolder="$(OutDir)" />
<Message Text="Copied CopyPRIFileToOutputDir files" Importance="High" />
</Target>
<ItemGroup>
<Page Remove="ShortcutGuideXAML\App.xaml" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="ShortcutGuideXAML\App.xaml" />
</ItemGroup>
<ItemGroup>
<COMReference Include="UIAutomationClient">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>0</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>944de083-8fb8-45cf-bcb7-c477acb2f897</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<!-- See https://learn.microsoft.com/windows/apps/develop/platform/csharp-winrt/net-projection-from-cppwinrt-component for more info -->
<PropertyGroup>
<CsWinRTIncludes>PowerToys.GPOWrapper</CsWinRTIncludes>
<CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir>
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" />
<PackageReference Include="Microsoft.WindowsAppSDK" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" />
<PackageReference Include="CommunityToolkit.WinUI.Animations" />
<PackageReference Include="CommunityToolkit.WinUI.Converters" />
<PackageReference Include="WinUIEx" />
<!-- HACK: To make sure the version pulled in by Microsoft.Extensions.Hosting is current. -->
<PackageReference Include="System.Text.Json" />
<PackageReference Include="YamlDotNet" />
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>
<!--
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
Tools extension to be activated for this project even if the Windows App SDK Nuget
package has not yet been restored.
-->
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<ProjectCapability Include="Msix" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
<ProjectReference Include="..\..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
<ProjectReference Include="..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
<ProjectReference Include="..\ShortcutGuide.CPPProject\ShortcutGuide.CPPProject.vcxproj" />
</ItemGroup>
<ItemGroup>
<Page Update="ShortcutGuideXAML\Pages\OverviewPage.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="ShortcutGuideXAML\CustomNavigationViewStyle.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="ShortcutGuideXAML\TaskbarWindow.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="ShortcutGuideXAML\TaskbarIndicator.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="ShortcutGuideXAML\Pages\ShortcutsPage.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Folder Include="ShortcutGuideXAML\Styles\" />
</ItemGroup>
<!--
Defining the "HasPackageAndPublishMenuAddedByProject" property here allows the Solution
Explorer "Package and Publish" context menu entry to be enabled for this project even if
the Windows App SDK Nuget package has not yet been restored.
-->
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
</PropertyGroup>
</Project>

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<Application
x:Class="ShortcutGuide.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:ShortcutGuide.Converters"
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<ResourceDictionary Source="/ShortcutGuideXAML/Styles/CustomNavigationViewStyle.xaml" />
<ResourceDictionary Source="/ShortcutGuideXAML/Controls/KeyCharPresenter.xaml" />
<ResourceDictionary Source="/ShortcutGuideXAML/Controls/KeyVisual.xaml" />
<!-- Other merged dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<!-- Other app resources here -->
<tkconverters:DoubleToVisibilityConverter
x:Name="DoubleToVisibilityConverter"
FalseValue="Collapsed"
GreaterThan="0"
TrueValue="Visible" />
<tkconverters:DoubleToVisibilityConverter
x:Name="DoubleToInvertedVisibilityConverter"
FalseValue="Visible"
GreaterThan="0"
TrueValue="Collapsed" />
<tkconverters:StringVisibilityConverter x:Name="StringVisibilityConverter" />
<converters:ShortcutDescriptionToKeysConverter x:Name="ShortcutDescriptionToKeysConverter" />
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@@ -1,62 +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.IO;
using System.Text.Json;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.UI.Xaml;
using ShortcutGuide.Models;
using ShortcutGuide.ShortcutGuideXAML;
namespace ShortcutGuide
{
public partial class App
{
internal static Dictionary<string, List<ShortcutEntry>> PinnedShortcuts { get; private set; } = null!;
internal static ShortcutGuideSettings ShortcutGuideSettings { get; private set; } = null!;
internal static ShortcutGuideProperties ShortcutGuideProperties { get; private set; } = null!;
internal static MainWindow MainWindow { get; private set; } = null!;
internal static TaskbarWindow TaskBarWindow { get; private set; } = null!;
public App()
{
InitializeComponent();
}
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
LoadData();
MainWindow = new MainWindow();
TaskBarWindow = new TaskbarWindow();
MainWindow.Activate();
MainWindow.Closed += (_, _) =>
{
Current.Exit();
};
}
private void LoadData()
{
SettingsUtils settingsUtils = new();
if (settingsUtils.SettingsExists(ShortcutGuideSettings.ModuleName, "Pinned.json"))
{
string pinnedPath = settingsUtils.GetSettingsFilePath(ShortcutGuideSettings.ModuleName, "Pinned.json");
PinnedShortcuts = JsonSerializer.Deserialize<Dictionary<string, List<ShortcutEntry>>>(File.ReadAllText(pinnedPath))!;
}
ShortcutGuideSettings = SettingsRepository<ShortcutGuideSettings>.GetInstance(settingsUtils).SettingsConfig;
ShortcutGuideProperties = ShortcutGuideSettings.Properties;
#pragma warning disable CA1869 // Cache and reuse 'JsonSerializerOptions' instances
settingsUtils.SaveSettings(JsonSerializer.Serialize(App.ShortcutGuideSettings, new JsonSerializerOptions { WriteIndented = true }), "Shortcut Guide");
#pragma warning restore CA1869 // Cache and reuse 'JsonSerializerOptions' instances
}
}
}

View File

@@ -1,131 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:helpers="using:ShortcutGuide.Helpers"
xmlns:local="using:ShortcutGuide.Controls"
xmlns:ui="using:CommunityToolkit.WinUI">
<Style BasedOn="{StaticResource DefaultKeyCharPresenterStyle}" TargetType="local:KeyCharPresenter" />
<Style x:Key="DefaultKeyCharPresenterStyle" TargetType="local:KeyCharPresenter">
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="AutomationProperties.AccessibilityView" Value="Raw" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:KeyCharPresenter">
<Grid Height="{TemplateBinding FontSize}">
<TextBlock
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
Text="{TemplateBinding Content}"
TextLineBounds="Tight" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="UnderlinedLetterKeyCharPresenterStyle"
BasedOn="{StaticResource DefaultKeyCharPresenterStyle}"
TargetType="local:KeyCharPresenter">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:KeyCharPresenter">
<Grid Height="{TemplateBinding FontSize}">
<TextBlock
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
TextLineBounds="Tight">
<Run Text="{helpers:StringResourceExtension Key='UnderlinedKeyChar/Text', Treatment=FirstCharOnly}" TextDecorations="Underline" /><Run Text="{helpers:StringResourceExtension Key='UnderlinedKeyChar/Text', Treatment=EverythingExceptFirstChar}" />
</TextBlock>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="WindowsKeyCharPresenterStyle"
BasedOn="{StaticResource DefaultKeyCharPresenterStyle}"
TargetType="local:KeyCharPresenter">
<!-- Scale to visually align the height of the Windows logo and text -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:KeyCharPresenter">
<Grid Height="{TemplateBinding FontSize}">
<Viewbox>
<PathIcon Data="M9 20H0V11H9V20ZM20 20H11V11H20V20ZM9 9H0V0H9V9ZM20 9H11V0H20V9Z" />
</Viewbox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="OfficeKeyCharPresenterStyle"
BasedOn="{StaticResource DefaultKeyCharPresenterStyle}"
TargetType="local:KeyCharPresenter">
<!-- Scale to visually align the height of the Office logo and text -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:KeyCharPresenter">
<Grid Height="{TemplateBinding FontSize}">
<Viewbox>
<PathIcon Data="M1792 405v1238q0 33-10 62t-28 54-44 41-57 27l-555 159q-23 6-47 6-31 0-58-8t-53-24l-363-205q-20-11-31-29t-12-42q0-35 24-59t60-25h470V458L735 584q-43 15-69 53t-26 83v651q0 41-20 73t-55 53l-167 91q-23 12-46 12-40 0-68-28t-28-68V587q0-51 26-96t71-71L949 81q41-23 89-23 17 0 30 2t30 8l555 153q31 9 56 27t44 42 29 54 10 61zm-128 1238V405q0-22-13-38t-34-23l-273-75-64-18-64-18v1586l401-115q21-6 34-22t13-39z" />
</Viewbox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="CopilotKeyCharPresenterStyle"
BasedOn="{StaticResource DefaultKeyCharPresenterStyle}"
TargetType="local:KeyCharPresenter">
<!-- Scale to visually align the height of the Copilot logo and text -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:KeyCharPresenter">
<Grid Height="{TemplateBinding FontSize}">
<Viewbox>
<PathIcon Data="M0 1213q0-60 10-124t27-130 35-129 38-121q18-55 41-119t54-129 70-125 87-106 106-74 129-28h661q59 0 114 17t96 64q30 34 46 72t33 81l22 58q11 29 34 52 23 25 56 31t65 9h4q157 0 238 83t82 240q0 60-10 125t-27 130-35 128-38 121q-18 55-41 119t-54 129-70 125-87 106-106 74-129 28H790q-61 0-107-15t-82-44-61-72-46-98q-11-29-24-60t-35-55q-23-25-51-31t-60-9h-4q-157 0-238-83T0 1213zm598-957q-50 0-93 25t-79 68-67 94-54 108-42 106-31 91q-17 51-35 110t-33 119-26 121-10 114q0 102 43 149t147 47h163q39 0 74-12t64-35 50-53 34-67q19-58 35-115t35-117q35-117 70-232t72-233q23-73 47-147t63-141H598zm452 285q69-29 143-29h281q-18-29-29-59t-21-58-21-54-30-44-46-30-69-11q-32 0-60 9t-48 35q-17 23-31 53t-27 63-23 65-19 60zm-296 867h101q39 0 74-12t66-34 52-52 33-68l58-191 42-140q21-70 43-140 11-36 28-69t43-62h-101q-39 0-74 12t-66 34-52 52-33 68q-15 48-29 96t-29 96q-21 70-41 140t-44 140q-11 36-28 68t-43 62zm814-768q-39 0-74 12t-64 35-50 53-34 68q-56 174-107 347t-106 349q-23 74-47 147t-63 141h427q50 0 93-25t79-68 67-94 54-108 42-106 31-91q16-51 34-110t34-119 26-121 10-114q0-102-43-149t-147-47h-162zm-570 867q-69 29-143 29H564q17 28 29 58t22 58 24 54 32 45 48 30 71 11q31 0 60-8t49-35q15-19 29-50t28-65 24-69 18-58z" />
</Viewbox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="GlyphKeyCharPresenterStyle"
BasedOn="{StaticResource DefaultKeyCharPresenterStyle}"
TargetType="local:KeyCharPresenter">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:KeyCharPresenter">
<Grid>
<Viewbox>
<FontIcon
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
Glyph="{TemplateBinding Content}" />
</Viewbox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -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 System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Windows.Markup;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Documents;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using ShortcutGuide.Helpers;
namespace ShortcutGuide.Controls;
public sealed partial class KeyCharPresenter : Control
{
public KeyCharPresenter()
{
DefaultStyleKey = typeof(KeyCharPresenter);
}
public object Content
{
get => (object)GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(nameof(Content), typeof(object), typeof(KeyCharPresenter), new PropertyMetadata(default(string)));
}

View File

@@ -1,191 +0,0 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ShortcutGuide.Controls">
<Style BasedOn="{StaticResource DefaultKeyVisualStyle}" TargetType="local:KeyVisual" />
<Style x:Key="DefaultKeyVisualStyle" TargetType="local:KeyVisual">
<Setter Property="MinWidth" Value="16" />
<Setter Property="AutomationProperties.AccessibilityView" Value="Raw" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="MinHeight" Value="16" />
<Setter Property="Background" Value="{ThemeResource SubtleFillColorTransparentBrush}" />
<Setter Property="Foreground" Value="{ThemeResource TextFillColorPrimaryBrush}" />
<Setter Property="BorderBrush" Value="{ThemeResource ControlStrokeColorDefaultBrush}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Padding" Value="4,4,4,4" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="14" />
<Setter Property="CornerRadius" Value="2" />
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:KeyVisual">
<Grid
x:Name="KeyHolder"
MinWidth="{TemplateBinding MinWidth}"
MinHeight="{TemplateBinding MinHeight}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Grid.BackgroundTransition>
<BrushTransition Duration="0:0:0.083" />
</Grid.BackgroundTransition>
<local:KeyCharPresenter
x:Name="KeyPresenter"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
AutomationProperties.AccessibilityView="Raw"
Content="{TemplateBinding Content}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Target="KeyHolder.Background" Value="{ThemeResource SubtleFillColorTransparentBrush}" />
<Setter Target="KeyHolder.BorderBrush" Value="{ThemeResource CardStrokeColorDefaultSolidBrush}" />
<Setter Target="KeyPresenter.Foreground" Value="{ThemeResource ControlStrokeColorDefaultBrush}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Invalid">
<VisualState.Setters>
<Setter Target="KeyHolder.Background" Value="{ThemeResource SystemFillColorCriticalBackgroundBrush}" />
<Setter Target="KeyHolder.BorderBrush" Value="{ThemeResource SystemFillColorCriticalBrush}" />
<Setter Target="KeyHolder.BorderThickness" Value="2" />
<Setter Target="KeyPresenter.Foreground" Value="{ThemeResource SystemFillColorCriticalBrush}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="SubtleKeyVisualStyle"
BasedOn="{StaticResource DefaultKeyVisualStyle}"
TargetType="local:KeyVisual">
<Setter Property="Background" Value="{ThemeResource SubtleFillColorTransparentBrush}" />
<Setter Property="BorderBrush" Value="{ThemeResource SubtleFillColorTransparentBrush}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:KeyVisual">
<Grid
x:Name="KeyHolder"
MinWidth="{TemplateBinding MinWidth}"
MinHeight="{TemplateBinding MinHeight}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Grid.BackgroundTransition>
<BrushTransition Duration="0:0:0.083" />
</Grid.BackgroundTransition>
<local:KeyCharPresenter
x:Name="KeyPresenter"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
AutomationProperties.AccessibilityView="Raw"
Content="{TemplateBinding Content}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Target="KeyPresenter.Foreground" Value="{ThemeResource TextFillColorDisabledBrush}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Invalid">
<VisualState.Setters>
<Setter Target="KeyPresenter.Foreground" Value="{ThemeResource SystemFillColorCriticalBrush}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="AccentKeyVisualStyle"
BasedOn="{StaticResource DefaultKeyVisualStyle}"
TargetType="local:KeyVisual">
<Setter Property="Background" Value="{ThemeResource AccentFillColorDefaultBrush}" />
<Setter Property="Foreground" Value="{ThemeResource TextOnAccentFillColorPrimaryBrush}" />
<Setter Property="BorderBrush" Value="{ThemeResource AccentControlElevationBorderBrush}" />
<Setter Property="BackgroundSizing" Value="OuterBorderEdge" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:KeyVisual">
<Grid
x:Name="KeyHolder"
MinWidth="{TemplateBinding MinWidth}"
MinHeight="{TemplateBinding MinHeight}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
AutomationProperties.AccessibilityView="Raw"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Grid.BackgroundTransition>
<BrushTransition Duration="0:0:0.083" />
</Grid.BackgroundTransition>
<local:KeyCharPresenter
x:Name="KeyPresenter"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Target="KeyHolder.Background" Value="{ThemeResource AccentButtonBackgroundDisabled}" />
<Setter Target="KeyHolder.BorderBrush" Value="{ThemeResource AccentButtonBorderBrushDisabled}" />
<Setter Target="KeyPresenter.Foreground" Value="{ThemeResource AccentButtonForegroundDisabled}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Invalid">
<VisualState.Setters>
<Setter Target="KeyHolder.Background" Value="{ThemeResource SystemFillColorCriticalBackgroundBrush}" />
<Setter Target="KeyHolder.BorderBrush" Value="{ThemeResource SystemFillColorCriticalBrush}" />
<Setter Target="KeyHolder.BorderThickness" Value="2" />
<Setter Target="KeyPresenter.Foreground" Value="{ThemeResource SystemFillColorCriticalBrush}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -1,194 +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.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Windows.System;
namespace ShortcutGuide.Controls
{
[TemplatePart(Name = KeyPresenter, Type = typeof(KeyCharPresenter))]
[TemplateVisualState(Name = NormalState, GroupName = "CommonStates")]
[TemplateVisualState(Name = DisabledState, GroupName = "CommonStates")]
[TemplateVisualState(Name = InvalidState, GroupName = "CommonStates")]
public sealed partial class KeyVisual : Control
{
private const string KeyPresenter = "KeyPresenter";
private const string NormalState = "Normal";
private const string DisabledState = "Disabled";
private const string InvalidState = "Invalid";
private KeyCharPresenter _keyPresenter = null!;
public object Content
{
get => (object)GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(nameof(Content), typeof(object), typeof(KeyVisual), new PropertyMetadata(default(string), OnContentChanged));
public bool IsInvalid
{
get => (bool)GetValue(IsInvalidProperty);
set => SetValue(IsInvalidProperty, value);
}
public static readonly DependencyProperty IsInvalidProperty = DependencyProperty.Register(nameof(IsInvalid), typeof(bool), typeof(KeyVisual), new PropertyMetadata(false, OnIsInvalidChanged));
public bool RenderKeyAsGlyph
{
get => (bool)GetValue(RenderKeyAsGlyphProperty);
set => SetValue(RenderKeyAsGlyphProperty, value);
}
public static readonly DependencyProperty RenderKeyAsGlyphProperty = DependencyProperty.Register(nameof(RenderKeyAsGlyph), typeof(bool), typeof(KeyVisual), new PropertyMetadata(false, OnContentChanged));
public KeyVisual()
{
this.DefaultStyleKey = typeof(KeyVisual);
}
protected override void OnApplyTemplate()
{
IsEnabledChanged -= KeyVisual_IsEnabledChanged;
_keyPresenter = (KeyCharPresenter)this.GetTemplateChild(KeyPresenter);
Update();
SetVisualStates();
IsEnabledChanged += KeyVisual_IsEnabledChanged;
base.OnApplyTemplate();
}
private static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((KeyVisual)d).SetVisualStates();
}
private static void OnIsInvalidChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((KeyVisual)d).SetVisualStates();
}
private void SetVisualStates()
{
if (this != null)
{
if (IsInvalid)
{
VisualStateManager.GoToState(this, InvalidState, true);
}
else if (!IsEnabled)
{
VisualStateManager.GoToState(this, DisabledState, true);
}
else
{
VisualStateManager.GoToState(this, NormalState, true);
}
}
}
private void Update()
{
if (Content == null)
{
Visibility = Visibility.Collapsed;
return;
}
if (Content is string key)
{
SetGlyphOrText(key switch
{
"<TASKBAR1-9>" => "Num",
"<Left>" => "\uE0E2",
"<Right>" => "\uE0E3",
"<Up>" => "\uE0E4",
"<Down>" => "\uE0E5",
"<ArrowUD>" => "\uE0E4\uE0E5",
"<ArrowLR>" => "\uE0E2\uE0E3",
"<Arrow>" => "\uE0E2\uE0E3\uE0E4\uE0E5",
"<Enter>" => "\uE751",
"<Backspace>" => "\uE750",
"<Escape>" => "Esc",
string s when s.StartsWith('<') => s.Trim('<', '>'),
_ => key,
});
_keyPresenter.Style = key switch
{
"<Copilot>" => (Style)Application.Current.Resources["CopilotKeyCharPresenterStyle"],
"<Office>" => (Style)Application.Current.Resources["OfficeKeyCharPresenterStyle"],
"<Underlined letter>" => (Style)Application.Current.Resources["UnderlinedLetterKeyCharPresenterStyle"],
_ => _keyPresenter.Style,
};
return;
}
if (Content is int keyCode)
{
VirtualKey virtualKey = (VirtualKey)keyCode;
switch (virtualKey)
{
case VirtualKey.Enter:
SetGlyphOrText("\uE751");
break;
case VirtualKey.Back:
SetGlyphOrText("\uE750");
break;
case VirtualKey.Shift:
case (VirtualKey)160: // Left Shift
case (VirtualKey)161: // Right Shift
SetGlyphOrText("\uE752");
break;
case VirtualKey.Up:
SetGlyphOrText("\uE0E4");
break;
case VirtualKey.Down:
SetGlyphOrText("\uE0E5");
break;
case VirtualKey.Left:
SetGlyphOrText("\uE0E2");
break;
case VirtualKey.Right:
SetGlyphOrText("\uE0E3");
break;
case VirtualKey.LeftWindows:
case VirtualKey.RightWindows:
_keyPresenter.Style = (Style)Application.Current.Resources["WindowsKeyCharPresenterStyle"];
break;
default: // For all other keys, we will use the key name.
SetGlyphOrText(virtualKey.ToString());
break;
}
return;
}
Visibility = Visibility.Collapsed;
}
private void SetGlyphOrText(string glyphOrText)
{
RenderKeyAsGlyph = ((glyphOrText[0] >> 12) & 0xF) is 0xE or 0xF;
_keyPresenter.Content = glyphOrText;
_keyPresenter.Style = RenderKeyAsGlyph
? (Style)Application.Current.Resources["GlyphKeyCharPresenterStyle"]
: (Style)Application.Current.Resources["DefaultKeyCharPresenterStyle"];
}
private void KeyVisual_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
SetVisualStates();
}
}
}

View File

@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<UserControl
x:Class="ShortcutGuide.Controls.TaskbarIndicator"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:ShortcutGuide"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid HorizontalAlignment="Stretch">
<Border
x:Name="IndicatorRectangle"
Width="36"
Height="36"
Background="{ThemeResource AcrylicBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource ControlElevationBorderBrush}"
BorderThickness="1"
CornerRadius="{StaticResource ControlCornerRadius}">
<TextBlock
x:Name="IndicatorText"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="18"
Style="{ThemeResource BodyStrongTextBlockStyle}"
Text="{x:Bind Label, Mode=OneWay}"
TextAlignment="Center" />
</Border>
</Grid>
</UserControl>

View File

@@ -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.Globalization;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
namespace ShortcutGuide.Controls;
public sealed partial class TaskbarIndicator : UserControl
{
public string Label
{
get => (string)GetValue(LabelProperty);
set => SetValue(LabelProperty, value);
}
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register(nameof(Label), typeof(string), typeof(TaskbarIndicator), new PropertyMetadata(default(string)));
public TaskbarIndicator()
{
InitializeComponent();
}
}

View File

@@ -1,100 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<winuiex:WindowEx
x:Class="ShortcutGuide.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:models="using:ShortcutGuide.Models"
xmlns:winuiex="using:WinUIEx"
Width="586"
IsMaximizable="False"
IsMinimizable="False"
IsResizable="False"
IsShownInSwitchers="False"
mc:Ignorable="d">
<winuiex:WindowEx.SystemBackdrop>
<DesktopAcrylicBackdrop />
</winuiex:WindowEx.SystemBackdrop>
<Page x:Name="MainPage">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="48" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TitleBar x:Uid="TitleBar">
<!--<TitleBar.Content>
<AutoSuggestBox
x:Name="SearchBox"
x:Uid="SearchBox"
Width="300"
VerticalAlignment="Center"
QueryIcon="Find"
TextChanged="SearchBox_TextChanged">
<AutoSuggestBox.KeyboardAccelerators>
<KeyboardAccelerator
Key="F"
Invoked="SearchBox_KeyboardAcceleratorInvoked"
Modifiers="Control" />
</AutoSuggestBox.KeyboardAccelerators>
<AutoSuggestBox.ItemTemplate>
<DataTemplate x:DataType="models:ShortcutEntry">
<Grid>
<TextBlock Text="{x:Bind Name}" />
TO DO: Add shortcuts / description
</Grid>
</DataTemplate>
</AutoSuggestBox.ItemTemplate>
</AutoSuggestBox>
</TitleBar.Content>-->
</TitleBar>
<NavigationView
x:Name="WindowSelector"
Grid.Row="1"
IsBackButtonVisible="Collapsed"
IsPaneToggleButtonVisible="False"
IsSettingsVisible="False"
SelectionChanged="WindowSelector_SelectionChanged"
Style="{StaticResource RailNavigationViewStyle}">
<NavigationView.MenuItems />
<NavigationView.FooterMenuItems>
<!-- If footer only has one item, a visual bug can occur. This fake settings button will have set height to zero as soon as the content is loaded -->
<NavigationViewItem
x:Name="FakeSettingsButton"
Icon="Setting"
SelectsOnInvoked="False"
Tag="Settings"
Tapped="Settings_Tapped" />
<NavigationViewItem
x:Uid="SettingsButton"
Icon="Setting"
SelectsOnInvoked="False"
Tag="Settings"
Tapped="Settings_Tapped" />
</NavigationView.FooterMenuItems>
<NavigationView.Content>
<NavigationView
x:Name="SubNav"
IsBackButtonVisible="Collapsed"
IsSettingsVisible="False"
PaneDisplayMode="Top"
SelectionChanged="SubNav_SelectionChanged">
<Frame
x:Name="ContentFrame"
Margin="4,8,0,0"
Background="{ThemeResource AcrylicBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="8,0,0,0" />
</NavigationView>
</NavigationView.Content>
<NavigationView.Resources>
<SolidColorBrush x:Key="NavigationViewContentBackground" Color="Transparent" />
<SolidColorBrush x:Key="NavigationViewContentGridBorderBrush" Color="Transparent" />
</NavigationView.Resources>
</NavigationView>
</Grid>
</Page>
</winuiex:WindowEx>

View File

@@ -1,307 +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.IO;
using System.Linq;
using Common.UI;
using ManagedCommon;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
using ShortcutGuide.Helpers;
using ShortcutGuide.Models;
using ShortcutGuide.Pages;
using Windows.Foundation;
using Windows.Graphics;
using Windows.System;
using Windows.UI.WindowManagement;
using WinRT.Interop;
using WinUIEx;
using WinUIEx.Messaging;
namespace ShortcutGuide
{
public sealed partial class MainWindow : WindowEx
{
private readonly string[] _currentApplicationIds;
private ShortcutFile? _shortcutFile;
private string _selectedAppName = null!;
private bool _setPosition;
public MainWindow()
{
_currentApplicationIds = ManifestInterpreter.GetAllCurrentApplicationIds();
InitializeComponent();
Title = ResourceLoaderInstance.ResourceLoader.GetString("Title")!;
ExtendsContentIntoTitleBar = true;
#if !DEBUG
this.SetIsAlwaysOnTop(true);
this.SetIsShownInSwitchers(false);
#endif
WindowMessageMonitor msgMonitor = new(this);
msgMonitor.WindowMessageReceived += (_, e) =>
{
const int WM_NCLBUTTONDBLCLK = 0x00A3;
if (e.Message.MessageId == WM_NCLBUTTONDBLCLK)
{
// Disable double click on title bar to maximize window
e.Result = 0;
e.Handled = true;
}
};
Activated += Window_Activated;
Content.KeyUp += (_, e) =>
{
if (e.Key == VirtualKey.Escape)
{
Close();
}
};
switch (App.ShortcutGuideProperties.Theme.Value)
{
case "dark":
((FrameworkElement)Content).RequestedTheme = ElementTheme.Dark;
MainPage.RequestedTheme = ElementTheme.Dark;
break;
case "light":
((FrameworkElement)Content).RequestedTheme = ElementTheme.Light;
MainPage.RequestedTheme = ElementTheme.Light;
break;
case "system":
// Ignore, as the theme will be set by the system.
break;
default:
Logger.LogError("Invalid theme value in settings: " + App.ShortcutGuideProperties.Theme.Value);
break;
}
}
protected override void OnStateChanged(WindowState state)
{
if (state == WindowState.Maximized)
{
SetWindowPosition();
}
}
protected override void OnPositionChanged(PointInt32 position)
{
SetWindowPosition();
}
private void Window_Activated(object sender, WindowActivatedEventArgs e)
{
if (e.WindowActivationState == WindowActivationState.Deactivated && !_taskBarWindowActivated)
{
#if !DEBUG
Close();
#endif
}
if (_taskBarWindowActivated)
{
_taskBarWindowActivated = false;
this.BringToFront();
}
// The code below sets the position of the window to the center of the monitor, but only if it hasn't been set before.
if (!_setPosition)
{
Content.GettingFocus += (_, _) =>
{
FakeSettingsButton.Height = 10;
FakeSettingsButton.Height = 0;
};
SetWindowPosition();
_setPosition = true;
AppWindow.Changed += (_, a) =>
{
if (!a.DidPresenterChange)
{
return;
}
SetWindowPosition();
};
}
SetNavItems();
}
private void SetNavItems()
{
// Populate the window selector with the current application IDs if it is empty.
// TO DO: Check if Settings button is considered an item too.
if (WindowSelector.MenuItems.Count == 0)
{
foreach (var item in _currentApplicationIds)
{
if (item == ManifestInterpreter.GetIndexYamlFile().DefaultShellName)
{
WindowSelector.MenuItems.Add(new NavigationViewItem { Name = item, Content = "Windows", Icon = new FontIcon() { Glyph = "\xE770" } });
}
else
{
try
{
WindowSelector.MenuItems.Add(new NavigationViewItem { Name = item, Content = ManifestInterpreter.GetShortcutsOfApplication(item).Name, Icon = new FontIcon { Glyph = "\uEB91" } });
}
catch (IOException)
{
}
}
}
WindowSelector.SelectedItem = WindowSelector.MenuItems[0];
}
}
private bool _hasMovedToRightMonitor;
private void SetWindowPosition()
{
if (!_hasMovedToRightMonitor)
{
NativeMethods.GetCursorPos(out NativeMethods.POINT lpPoint);
AppWindow.Move(new NativeMethods.POINT { Y = lpPoint.Y - ((int)Height / 2), X = lpPoint.X - ((int)Width / 2) });
_hasMovedToRightMonitor = true;
}
var hwnd = WindowNative.GetWindowHandle(this);
float dpi = DpiHelper.GetDPIScaleForWindow(hwnd.ToInt32());
Rect monitorRect = DisplayHelper.GetWorkAreaForDisplayWithWindow(hwnd);
if (App.TaskBarWindow.AppWindow.IsVisible && App.TaskBarWindow.AppWindow.Position.X < AppWindow.Position.X + Width)
{
MaxHeight = (monitorRect.Height / dpi) - App.TaskBarWindow.AppWindow.Size.Height;
MinHeight = MaxHeight;
Height = MaxHeight;
}
else
{
MaxHeight = monitorRect.Height / DpiHelper.GetDPIScaleForWindow(hwnd.ToInt32());
MinHeight = MaxHeight;
Height = MaxHeight;
}
this.MoveAndResize((int)monitorRect.X, (int)monitorRect.Y, Width, Height);
}
/*private void SearchBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
// TO DO: should the results of this be shown on a separate results page? Or as part of the suggested items of the search box?
// The current UX is a bit weird as search is about the content that is selected on the page, vs. global search (which a search box in the title bar communicates).
// Also, the results indicate that they can be clicked - but they cannot, so this needs more UX thinking on having the right model.
if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput && !string.IsNullOrWhiteSpace(SearchBox.Text))
{
ObservableCollection<ShortcutEntry> searchResults = new ObservableCollection<ShortcutEntry>();
if (_shortcutFile is ShortcutFile file)
{
foreach (var shortcut in file.Shortcuts.SelectMany(list => list.Properties.Where(s => s.Name.Contains(SearchBox.Text, StringComparison.InvariantCultureIgnoreCase))))
{
searchResults.Add(shortcut);
}
SearchBox.ItemsSource = searchResults;
}
}
}
private void SearchBox_KeyboardAcceleratorInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)
{
SearchBox.Focus(FocusState.Programmatic);
}*/
private void WindowSelector_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
{
if (args.SelectedItem is NavigationViewItem selectedItem)
{
_selectedAppName = selectedItem.Name;
_shortcutFile = ManifestInterpreter.GetShortcutsOfApplication(_selectedAppName);
PopulateCategorySelector();
}
}
private void PopulateCategorySelector()
{
SubNav.MenuItems.Clear();
SubNav.MenuItems.Add(new NavigationViewItem()
{
Content = ResourceLoaderInstance.ResourceLoader.GetString("Overview"),
Tag = -1,
});
int i = 0;
if (_shortcutFile is ShortcutFile file)
{
foreach (var category in file.Shortcuts)
{
switch (category.SectionName)
{
case { } name when name.StartsWith("<TASKBAR1-9>", StringComparison.Ordinal):
break;
case { } name when name.StartsWith('<') && name.EndsWith('>'):
break;
default:
SubNav.MenuItems.Add(new NavigationViewItem() { Content = category.SectionName, Tag = i });
break;
}
i++;
}
if (SubNav.MenuItems.Count > 0)
{
SubNav.SelectedItem = SubNav.MenuItems[0];
}
}
}
/// <summary>
/// Tracks whether the taskbar window was activated. So that the main window does not close.
/// </summary>
private bool _taskBarWindowActivated;
private void SubNav_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
{
if (args.SelectedItem is NavigationViewItem selectedItem && selectedItem.Tag is int param && _shortcutFile is ShortcutFile file)
{
Type selectedPage = typeof(ShortcutsPage);
App.TaskBarWindow.Hide();
if (param == -1)
{
selectedPage = typeof(OverviewPage);
// We only show the taskbar button window when the overview page of Windows is selected.
if (_shortcutFile is not null && _shortcutFile.Value.Shortcuts.Any(c => c.SectionName.Contains("<TASKBAR1-9>")))
{
_taskBarWindowActivated = true;
App.TaskBarWindow.Activate();
}
}
// Set window position so that the taskbar window does not potentially clip into the main window
SetWindowPosition();
ContentFrame.Navigate(selectedPage, new ShortcutPageNavParam() { ShortcutFile = file, PageIndex = param, AppName = _selectedAppName });
}
}
private void Settings_Tapped(object sender, TappedRoutedEventArgs e)
{
SettingsDeepLink.OpenSettings(SettingsDeepLink.SettingsWindow.ShortcutGuide, true);
}
}
}

View File

@@ -1,143 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<Page
x:Class="ShortcutGuide.Pages.OverviewPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:ShortcutGuide.Controls"
xmlns:converters="using:CommunityToolkit.WinUI.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:ShortcutGuide"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:models="using:ShortcutGuide.Models"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:Key="ShortcutItemTemplate" x:DataType="models:ShortcutEntry">
<Grid
Padding="16,8,16,8"
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
BorderThickness="0,0,0,1"
Tag="{x:Bind}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.ContextFlyout>
<MenuFlyout Opening="PinFlyout_Opening">
<MenuFlyoutItem
Click="Pin_Click"
CommandParameter="{x:Bind}"
Text="Pin" />
</MenuFlyout>
</Grid.ContextFlyout>
<StackPanel
Grid.Column="1"
VerticalAlignment="Center"
Orientation="Vertical">
<TextBlock Text="{x:Bind Name}" TextWrapping="Wrap" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind Description}"
TextWrapping="Wrap"
Visibility="{x:Bind Description, Converter={StaticResource StringVisibilityConverter}}" />
</StackPanel>
<ItemsControl
Grid.Column="0"
VerticalAlignment="Center"
ItemsSource="{x:Bind Shortcut}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" Spacing="4" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="models:ShortcutDescription">
<Grid>
<ItemsControl Grid.Column="1" ItemsSource="{Binding Converter={StaticResource ShortcutDescriptionToKeysConverter}}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Spacing="4" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<controls:KeyVisual
Padding="4"
Background="{ThemeResource ControlFillColorInputActiveBrush}"
BorderBrush="{ThemeResource ControlElevationBorderBrush}"
Content="{Binding}"
CornerRadius="{StaticResource ControlCornerRadius}"
FontSize="12"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource DefaultKeyVisualStyle}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</DataTemplate>
</Page.Resources>
<Grid>
<ScrollViewer>
<StackPanel
Margin="0,16,0,0"
Orientation="Vertical"
Spacing="8">
<TextBlock
x:Name="RecommendedHeaderTxt"
x:Uid="RecommendedHeaderTxt"
Margin="16,0,16,8"
FontWeight="SemiBold" />
<ItemsRepeater
ItemTemplate="{StaticResource ShortcutItemTemplate}"
ItemsSource="{x:Bind _recommendedShortcuts, Mode=OneWay}"
Visibility="{x:Bind _recommendedShortcuts.Count, Mode=OneWay, Converter={StaticResource DoubleToVisibilityConverter}}" />
<TextBlock
x:Uid="NoRecommendedShortcuts"
Margin="16,0,16,0"
FontWeight="SemiBold"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Visibility="{x:Bind _recommendedShortcuts.Count, Mode=OneWay, Converter={StaticResource DoubleToInvertedVisibilityConverter}}" />
<TextBlock
x:Name="PinnedHeaderTxt"
x:Uid="PinnedHeaderTxt"
Margin="16,24,16,0"
FontWeight="SemiBold" />
<ItemsRepeater
x:Name="PinnedShortcutsListView"
ItemTemplate="{StaticResource ShortcutItemTemplate}"
ItemsSource="{x:Bind _pinnedShortcuts, Mode=OneWay}"
Visibility="{x:Bind PinnedShortcutsCount, Mode=OneWay, Converter={StaticResource DoubleToVisibilityConverter}}" />
<TextBlock
x:Uid="PinnedEmptyText"
Margin="16,0,16,8"
FontWeight="SemiBold"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Visibility="{x:Bind PinnedShortcutsCount, Mode=OneWay, Converter={StaticResource DoubleToInvertedVisibilityConverter}}" />
<StackPanel
x:Name="TaskbarShortcutsPanel"
Orientation="Vertical"
Visibility="Collapsed">
<TextBlock
x:Name="TaskbarHeaderTxt"
x:Uid="TaskbarHeaderTxt"
Margin="16,24,16,2"
FontWeight="SemiBold" />
<TextBlock x:Uid="TaskbarDescriptionTxt" Margin="16,2,16,12" />
<ItemsRepeater
x:Name="TaskbarShortcutsListView"
ItemTemplate="{StaticResource ShortcutItemTemplate}"
ItemsSource="{x:Bind _taskbarShortcuts, Mode=OneWay}" />
</StackPanel>
</StackPanel>
</ScrollViewer>
</Grid>
</Page>

View File

@@ -1,86 +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.ObjectModel;
using System.ComponentModel;
using System.Linq;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Navigation;
using ShortcutGuide.Helpers;
using ShortcutGuide.Models;
namespace ShortcutGuide.Pages
{
public sealed partial class OverviewPage : Page, INotifyPropertyChanged
{
private ObservableCollection<ShortcutEntry>? _recommendedShortcuts;
private ObservableCollection<ShortcutEntry>? _pinnedShortcuts;
private ObservableCollection<ShortcutEntry>? _taskbarShortcuts;
private int PinnedShortcutsCount => _pinnedShortcuts?.Count ?? 0;
private string _appName = string.Empty;
private ShortcutFile _shortcutFile;
public OverviewPage()
{
InitializeComponent();
}
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler? PropertyChanged;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.Parameter is ShortcutPageNavParam param)
{
_appName = param.AppName;
_shortcutFile = param.ShortcutFile;
_recommendedShortcuts = [.. _shortcutFile.Shortcuts.SelectMany(list => list.Properties.Where(s => s.Recommended))];
if (App.PinnedShortcuts.TryGetValue(_appName, out var shortcuts))
{
_pinnedShortcuts = [.. shortcuts];
}
if (_appName == ManifestInterpreter.GetIndexYamlFile().DefaultShellName)
{
TaskbarShortcutsPanel.Visibility = Visibility.Visible;
_taskbarShortcuts =
[
.. _shortcutFile.Shortcuts.First(x => x.SectionName.StartsWith("<TASKBAR1-9>", StringComparison.InvariantCulture)).Properties,
];
}
}
}
private void PinFlyout_Opening(object sender, object e)
{
if (sender is MenuFlyout fl && fl.Target is Grid g && g.Tag is ShortcutEntry dataObject && fl.Items[0] is MenuFlyoutItem pinItem)
{
bool isItemPinned = App.PinnedShortcuts[_appName].Any(x => x.Equals(dataObject));
pinItem.Text = isItemPinned ? ResourceLoaderInstance.ResourceLoader.GetString("UnpinShortcut") : ResourceLoaderInstance.ResourceLoader.GetString("PinShortcut");
pinItem.Icon = new SymbolIcon(isItemPinned ? Symbol.UnPin : Symbol.Pin);
}
}
private void Pin_Click(object sender, RoutedEventArgs e)
{
if (sender is MenuFlyoutItem { CommandParameter: ShortcutEntry shortcutEntry })
{
PinnedShortcutsHelper.UpdatePinnedShortcuts(_appName, shortcutEntry);
// Update ListView to reflect changes
_pinnedShortcuts = [.. App.PinnedShortcuts[_appName]];
PinnedShortcutsListView.ItemsSource = _pinnedShortcuts;
OnPropertyChanged(nameof(PinnedShortcutsCount));
}
}
}
}

View File

@@ -1,101 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<Page
x:Class="ShortcutGuide.Pages.ShortcutsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:ShortcutGuide.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:ShortcutGuide.Pages"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:models="using:ShortcutGuide.Models"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:Key="ShortcutItemTemplate" x:DataType="models:ShortcutEntry">
<Grid
Padding="16,8,16,8"
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
BorderThickness="0,0,0,1"
Tag="{x:Bind}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.ContextFlyout>
<MenuFlyout Opening="PinFlyout_Opening">
<MenuFlyoutItem
x:Uid="PinShortcut"
Click="Pin_Click"
CommandParameter="{x:Bind}" />
</MenuFlyout>
</Grid.ContextFlyout>
<StackPanel
Grid.Column="1"
VerticalAlignment="Center"
Orientation="Vertical">
<TextBlock Text="{x:Bind Name}" TextWrapping="Wrap" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind Description}"
TextWrapping="Wrap"
Visibility="{x:Bind Description, Converter={StaticResource StringVisibilityConverter}}" />
</StackPanel>
<ItemsControl
Grid.Column="0"
VerticalAlignment="Center"
ItemsSource="{x:Bind Shortcut}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" Spacing="4" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="models:ShortcutDescription">
<Grid>
<ItemsControl Grid.Column="1" ItemsSource="{Binding Converter={StaticResource ShortcutDescriptionToKeysConverter}}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Spacing="4" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<controls:KeyVisual
Padding="4"
Background="{ThemeResource ControlFillColorInputActiveBrush}"
BorderBrush="{ThemeResource ControlElevationBorderBrush}"
Content="{Binding}"
CornerRadius="{StaticResource ControlCornerRadius}"
FontSize="12"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource DefaultKeyVisualStyle}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</DataTemplate>
</Page.Resources>
<Grid>
<ScrollViewer>
<StackPanel
Margin="0,16,0,0"
Orientation="Vertical"
Spacing="8">
<ItemsRepeater
ItemTemplate="{StaticResource ShortcutItemTemplate}"
ItemsSource="{x:Bind _shortcuts, Mode=OneWay}"
Visibility="{x:Bind _shortcuts.Count, Mode=OneWay, Converter={StaticResource DoubleToVisibilityConverter}}" />
<TextBlock
x:Uid="NoShortcuts"
Margin="16,0,16,8"
FontWeight="SemiBold"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Visibility="{x:Bind _shortcuts.Count, Mode=OneWay, Converter={StaticResource DoubleToInvertedVisibilityConverter}}" />
</StackPanel>
</ScrollViewer>
</Grid>
</Page>

View File

@@ -1,61 +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.ObjectModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.Json;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Navigation;
using ShortcutGuide.Helpers;
using ShortcutGuide.Models;
using Windows.ApplicationModel.VoiceCommands;
namespace ShortcutGuide.Pages
{
public sealed partial class ShortcutsPage : Page
{
private ObservableCollection<ShortcutEntry>? _shortcuts;
private string _appName = string.Empty;
private ShortcutFile _shortcutFile;
private int _pageIndex;
public ShortcutsPage()
{
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.Parameter is ShortcutPageNavParam param)
{
_appName = param.AppName;
_shortcutFile = param.ShortcutFile;
_pageIndex = param.PageIndex;
_shortcuts = [.. _shortcutFile.Shortcuts[_pageIndex].Properties ?? Enumerable.Empty<ShortcutEntry>()];
}
}
private void PinFlyout_Opening(object sender, object e)
{
if (sender is MenuFlyout fl && fl.Target is Grid g && g.Tag is ShortcutEntry dataObject && fl.Items[0] is MenuFlyoutItem pinItem)
{
bool isItemPinned = App.PinnedShortcuts[_appName].Any(x => x.Equals(dataObject));
pinItem.Text = isItemPinned ? ResourceLoaderInstance.ResourceLoader.GetString("UnpinShortcut") : ResourceLoaderInstance.ResourceLoader.GetString("PinShortcut");
pinItem.Icon = new SymbolIcon(isItemPinned ? Symbol.UnPin : Symbol.Pin);
}
}
private void Pin_Click(object sender, RoutedEventArgs e)
{
if (sender is MenuFlyoutItem { CommandParameter: ShortcutEntry shortcutEntry })
{
PinnedShortcutsHelper.UpdatePinnedShortcuts(_appName, shortcutEntry);
}
}
}
}

View File

@@ -1,57 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<winuiex:WindowEx
x:Class="ShortcutGuide.ShortcutGuideXAML.TaskbarWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:ShortcutGuide"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:winuiex="using:WinUIEx"
Title="TaskbarWindow"
Width="600"
Height="200"
IsAlwaysOnTop="True"
IsMaximizable="False"
IsMinimizable="False"
IsResizable="False"
IsShownInSwitchers="False"
IsTitleBarVisible="False"
mc:Ignorable="d">
<Window.SystemBackdrop>
<DesktopAcrylicBackdrop />
</Window.SystemBackdrop>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="WindowsLogoColumnWidth" Width="68" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Canvas x:Name="KeyHolder" Grid.Column="1" />
<StackPanel
Margin="8"
VerticalAlignment="Top"
Orientation="Horizontal"
Spacing="8">
<Border
Width="34"
Height="34"
Padding="8"
BorderBrush="{ThemeResource ControlElevationBorderBrush}"
BorderThickness="0"
CornerRadius="{StaticResource ControlCornerRadius}">
<Viewbox>
<PathIcon Data="M9 20H0V11H9V20ZM20 20H11V11H20V20ZM9 9H0V0H9V9ZM20 9H11V0H20V9Z" />
</Viewbox>
</Border>
<TextBlock
Margin="0,-3,0,0"
VerticalAlignment="Center"
FontSize="18"
FontWeight="SemiBold"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="+" />
</StackPanel>
</Grid>
</winuiex:WindowEx>

View File

@@ -1,69 +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.Globalization;
using Microsoft.UI;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Shapes;
using ShortcutGuide.Controls;
using ShortcutGuide.Helpers;
using Windows.Foundation;
using WinRT.Interop;
using WinUIEx;
using static ShortcutGuide.NativeMethods;
namespace ShortcutGuide.ShortcutGuideXAML
{
public sealed partial class TaskbarWindow : WindowEx
{
private float DPI => DpiHelper.GetDPIScaleForWindow(WindowNative.GetWindowHandle(this).ToInt32());
private Rect WorkArea => DisplayHelper.GetWorkAreaForDisplayWithWindow(WindowNative.GetWindowHandle(this));
public TaskbarWindow()
{
InitializeComponent();
UpdateTasklistButtons();
this.Activated += (_, _) => UpdateTasklistButtons();
}
public void UpdateTasklistButtons()
{
// This move ensures the window spawns on the same monitor as the main window
AppWindow.MoveInZOrderAtBottom();
AppWindow.Move(App.MainWindow.AppWindow.Position);
TasklistButton[] buttons = TasklistPositions.GetButtons();
double windowsLogoColumnWidth = WindowsLogoColumnWidth.Width.Value;
double windowHeight = 58;
double windowMargin = 8 * DPI;
double windowWidth = windowsLogoColumnWidth;
double xPosition = buttons[0].X - (windowsLogoColumnWidth * DPI);
double yPosition = WorkArea.Bottom - (windowHeight * DPI);
KeyHolder.Children.Clear();
foreach (TasklistButton b in buttons)
{
TaskbarIndicator indicator = new()
{
Label = b.Keynum >= 10 ? "0" : b.Keynum.ToString(CultureInfo.InvariantCulture),
Height = b.Height / DPI,
Width = b.Width / DPI,
};
windowWidth += indicator.Width;
KeyHolder.Children.Add(indicator);
double indicatorPos = (b.X - xPosition) / DPI;
Canvas.SetLeft(indicator, indicatorPos - windowsLogoColumnWidth);
}
this.MoveAndResize(xPosition - windowMargin, yPosition, windowWidth + (2 * windowMargin), windowHeight);
AppWindow.MoveInZOrderAtTop();
}
}
}

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0"
xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="ShortcutGuide.app"/>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<!-- The combination of below two tags have the following effect:
1) Per-Monitor for >= Windows 10 Anniversary Update
2) System < Windows 10 Anniversary Update
-->
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
</windowsSettings>
</application>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="53px" height="52px" viewBox="0 0 53 52" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Artboard" clip-path="url(#clip-Artboard)">
<g id="_0" data-name="0">
<rect id="Rectangle" width="29" height="36" rx="4" transform="translate(13 8)" fill="#2582fb"/>
<g id="bottom">
<rect id="carat" width="14" height="14" transform="translate(18 39) rotate(-45)" fill="#2582fb"/>
</g>
<g id="left">
<rect id="carat-2" data-name="carat" width="14" height="14" transform="translate(7.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="right">
<rect id="carat-3" data-name="carat" width="14" height="14" transform="translate(26.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="top">
<rect id="carat-4" data-name="carat" width="14" height="14" transform="translate(18 13) rotate(-45)" fill="#2582fb"/>
</g>
<path id="A" d="M13.968,15.171a2.7,2.7,0,0,1-2.427-1.251,6.713,6.713,0,0,1-.813-3.644,7.215,7.215,0,0,1,.868-3.9,2.784,2.784,0,0,1,2.481-1.343,2.684,2.684,0,0,1,2.468,1.251,7.283,7.283,0,0,1,.772,3.76,6.981,6.981,0,0,1-.861,3.8A2.79,2.79,0,0,1,13.968,15.171ZM14.05,6.3a1.365,1.365,0,0,0-1.289.981,7.967,7.967,0,0,0-.414,2.943,7.039,7.039,0,0,0,.414,2.758,1.345,1.345,0,0,0,1.268.919,1.323,1.323,0,0,0,1.268-.94,7.716,7.716,0,0,0,.393-2.827A7.991,7.991,0,0,0,15.3,7.258,1.315,1.315,0,0,0,14.05,6.3Z" transform="translate(13.5 15.689)" fill="#fff"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="53px" height="52px" viewBox="0 0 53 52" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Artboard" clip-path="url(#clip-Artboard)">
<g id="_1" data-name="1">
<rect id="Rectangle" width="29" height="36" rx="4" transform="translate(13 8)" fill="#2582fb"/>
<g id="bottom">
<rect id="carat" width="14" height="14" transform="translate(18 39) rotate(-45)" fill="#2582fb"/>
</g>
<g id="left">
<rect id="carat-2" data-name="carat" width="14" height="14" transform="translate(7.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="right">
<rect id="carat-3" data-name="carat" width="14" height="14" transform="translate(26.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="top">
<rect id="carat-4" data-name="carat" width="14" height="14" transform="translate(18 13) rotate(-45)" fill="#2582fb"/>
</g>
<path id="A" d="M15.277,15H13.691V7.022a4.525,4.525,0,0,1-.868.482,8.428,8.428,0,0,1-1.08.4l-.437-1.319a8.886,8.886,0,0,0,1.716-.673,7.345,7.345,0,0,0,1.436-.933h.82Z" transform="translate(13.5 15.689)" fill="#fff"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="53px" height="52px" viewBox="0 0 53 52" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Artboard" clip-path="url(#clip-Artboard)">
<g id="_2" data-name="2">
<rect id="Rectangle" width="29" height="36" rx="4" transform="translate(13 8)" fill="#2582fb"/>
<g id="bottom">
<rect id="carat" width="14" height="14" transform="translate(18 39) rotate(-45)" fill="#2582fb"/>
</g>
<g id="left">
<rect id="carat-2" data-name="carat" width="14" height="14" transform="translate(7.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="right">
<rect id="carat-3" data-name="carat" width="14" height="14" transform="translate(26.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="top">
<rect id="carat-4" data-name="carat" width="14" height="14" transform="translate(18 13) rotate(-45)" fill="#2582fb"/>
</g>
<path id="A" d="M10.974,15v-.6a3.649,3.649,0,0,1,.188-1.217A3.508,3.508,0,0,1,11.7,12.2a5.092,5.092,0,0,1,.827-.851q.485-.4,1.073-.831a7.588,7.588,0,0,0,.824-.66,5.023,5.023,0,0,0,.571-.625,1.98,1.98,0,0,0,.328-.625,2.443,2.443,0,0,0,.109-.742,1.561,1.561,0,0,0-.4-1.1,1.448,1.448,0,0,0-1.121-.431,3.157,3.157,0,0,0-1.135.229,3.742,3.742,0,0,0-1.135.708L10.8,6.291A4.651,4.651,0,0,1,14.1,5.033a2.9,2.9,0,0,1,2.167.786,2.564,2.564,0,0,1,.772,1.859,3.645,3.645,0,0,1-.178,1.2,3.375,3.375,0,0,1-.479.913,4.918,4.918,0,0,1-.728.807,10.746,10.746,0,0,1-.94.745q-.526.369-.909.66a5.2,5.2,0,0,0-.629.55,1.988,1.988,0,0,0-.373.526,1.324,1.324,0,0,0-.12.561h4.553V15Z" transform="translate(13.5 15.689)" fill="#fff"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="53px" height="52px" viewBox="0 0 53 52" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Artboard" clip-path="url(#clip-Artboard)">
<g id="_3" data-name="3">
<rect id="Rectangle" width="29" height="36" rx="4" transform="translate(13 8)" fill="#2582fb"/>
<g id="bottom">
<rect id="carat" width="14" height="14" transform="translate(18 39) rotate(-45)" fill="#2582fb"/>
</g>
<g id="left">
<rect id="carat-2" data-name="carat" width="14" height="14" transform="translate(7.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="right">
<rect id="carat-3" data-name="carat" width="14" height="14" transform="translate(26.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="top">
<rect id="carat-4" data-name="carat" width="14" height="14" transform="translate(18 13) rotate(-45)" fill="#2582fb"/>
</g>
<path id="A" d="M10.857,14.344l.663-1.094a4.564,4.564,0,0,0,1.036.5,3.6,3.6,0,0,0,1.083.154,2,2,0,0,0,1.446-.461,1.516,1.516,0,0,0,.475-1.131,1.453,1.453,0,0,0-.636-1.3,3.3,3.3,0,0,0-1.832-.424h-.807V9.319h.752a2.827,2.827,0,0,0,1.644-.393,1.435,1.435,0,0,0,.55-1.254,1.3,1.3,0,0,0-.4-1.022A1.477,1.477,0,0,0,13.817,6.3a3.274,3.274,0,0,0-1.008.164,4.127,4.127,0,0,0-1.029.513l-.67-1.053A4.8,4.8,0,0,1,14,5.033a3.1,3.1,0,0,1,2.071.663,2.192,2.192,0,0,1,.786,1.764,2.46,2.46,0,0,1-.455,1.5,2.608,2.608,0,0,1-1.371.9v.027a2.585,2.585,0,0,1,1.555.762,2.2,2.2,0,0,1,.6,1.583,2.679,2.679,0,0,1-.926,2.129,3.629,3.629,0,0,1-2.464.8,5.294,5.294,0,0,1-2.933-.827Z" transform="translate(13.5 15.689)" fill="#fff"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="53px" height="52px" viewBox="0 0 53 52" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Artboard" clip-path="url(#clip-Artboard)">
<g id="_4" data-name="4">
<rect id="Rectangle" width="29" height="36" rx="4" transform="translate(13 8)" fill="#2582fb"/>
<g id="bottom">
<rect id="carat" width="14" height="14" transform="translate(18 39) rotate(-45)" fill="#2582fb"/>
</g>
<g id="left">
<rect id="carat-2" data-name="carat" width="14" height="14" transform="translate(7.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="right">
<rect id="carat-3" data-name="carat" width="14" height="14" transform="translate(26.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="top">
<rect id="carat-4" data-name="carat" width="14" height="14" transform="translate(18 13) rotate(-45)" fill="#2582fb"/>
</g>
<path id="A" d="M16.576,5.149v6.405h1.032V12.86H16.576v2.194H14.983V12.86H10.43V11.555q.629-.69,1.275-1.494t1.241-1.637q.595-.834,1.1-1.671a15.328,15.328,0,0,0,.858-1.6Zm-4.532,6.405h2.939v-4.2q-.41.7-.8,1.3t-.752,1.114q-.376.52-.721.957T12.043,11.555Z" transform="translate(13.5 15.689)" fill="#fff"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="53px" height="52px" viewBox="0 0 53 52" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Artboard" clip-path="url(#clip-Artboard)">
<g id="_5" data-name="5">
<rect id="Rectangle" width="29" height="36" rx="4" transform="translate(13 8)" fill="#2582fb"/>
<g id="bottom">
<rect id="carat" width="14" height="14" transform="translate(18 39) rotate(-45)" fill="#2582fb"/>
</g>
<g id="left">
<rect id="carat-2" data-name="carat" width="14" height="14" transform="translate(7.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="right">
<rect id="carat-3" data-name="carat" width="14" height="14" transform="translate(26.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="top">
<rect id="carat-4" data-name="carat" width="14" height="14" transform="translate(18 13) rotate(-45)" fill="#2582fb"/>
</g>
<path id="A" d="M10.816,14.18l.772-1.012a3.292,3.292,0,0,0,2.1.731,1.913,1.913,0,0,0,1.395-.513,1.753,1.753,0,0,0,.526-1.312,1.613,1.613,0,0,0-.588-1.35,2.748,2.748,0,0,0-1.723-.461q-.39,0-.841.027t-.861.075L11.944,5.2h4.826V6.551H13.223l-.171,2.461q.239-.014.475-.024t.427-.01a3.435,3.435,0,0,1,2.4.79,2.8,2.8,0,0,1,.868,2.177,3.054,3.054,0,0,1-.954,2.328,3.532,3.532,0,0,1-2.526.9,4.532,4.532,0,0,1-2.926-.991Z" transform="translate(13.5 15.689)" fill="#fff"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="53px" height="52px" viewBox="0 0 53 52" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Artboard" clip-path="url(#clip-Artboard)">
<g id="_6" data-name="6">
<rect id="Rectangle" width="29" height="36" rx="4" transform="translate(13 8)" fill="#2582fb"/>
<g id="bottom">
<rect id="carat" width="14" height="14" transform="translate(18 39) rotate(-45)" fill="#2582fb"/>
</g>
<g id="left">
<rect id="carat-2" data-name="carat" width="14" height="14" transform="translate(7.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="right">
<rect id="carat-3" data-name="carat" width="14" height="14" transform="translate(26.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="top">
<rect id="carat-4" data-name="carat" width="14" height="14" transform="translate(18 13) rotate(-45)" fill="#2582fb"/>
</g>
<path id="A" d="M17.249,11.849a3.289,3.289,0,0,1-.9,2.4,3.053,3.053,0,0,1-2.283.926A2.824,2.824,0,0,1,11.654,14a5.564,5.564,0,0,1-.865-3.346,10.182,10.182,0,0,1,.236-2.211,5.023,5.023,0,0,1,.837-1.89,3.714,3.714,0,0,1,1.292-1.142,3.851,3.851,0,0,1,1.777-.376,3.546,3.546,0,0,1,1.039.161,3.365,3.365,0,0,1,1.06.571l-.807,1a2.328,2.328,0,0,0-.636-.352,2.2,2.2,0,0,0-.731-.113,2.074,2.074,0,0,0-.995.232,2.535,2.535,0,0,0-.81.731,3.2,3.2,0,0,0-.513,1.094,5.618,5.618,0,0,0-.185,1.436h.034a2.468,2.468,0,0,1,.947-.749,2.885,2.885,0,0,1,1.193-.25,2.5,2.5,0,0,1,1.979.844A3.228,3.228,0,0,1,17.249,11.849Zm-1.545.082a2.094,2.094,0,0,0-.417-1.422,1.413,1.413,0,0,0-1.114-.472,1.652,1.652,0,0,0-1.289.516,1.818,1.818,0,0,0-.468,1.268,2.34,2.34,0,0,0,.461,1.49,1.461,1.461,0,0,0,1.207.588,1.477,1.477,0,0,0,1.179-.513A2.167,2.167,0,0,0,15.7,11.931Z" transform="translate(13.5 15.689)" fill="#fff"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="53px" height="52px" viewBox="0 0 53 52" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Artboard" clip-path="url(#clip-Artboard)">
<g id="_7" data-name="7">
<rect id="Rectangle" width="29" height="36" rx="4" transform="translate(13 8)" fill="#2582fb"/>
<g id="bottom">
<rect id="carat" width="14" height="14" transform="translate(18 39) rotate(-45)" fill="#2582fb"/>
</g>
<g id="left">
<rect id="carat-2" data-name="carat" width="14" height="14" transform="translate(7.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="right">
<rect id="carat-3" data-name="carat" width="14" height="14" transform="translate(26.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="top">
<rect id="carat-4" data-name="carat" width="14" height="14" transform="translate(18 13) rotate(-45)" fill="#2582fb"/>
</g>
<path id="A" d="M17.164,6.113A43.443,43.443,0,0,0,15.1,10.4,19.372,19.372,0,0,0,13.869,15h-1.62a18.538,18.538,0,0,1,1.285-4.539,37.232,37.232,0,0,1,1.935-3.91H10.875V5.2h6.289Z" transform="translate(13.5 15.689)" fill="#fff"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="53px" height="52px" viewBox="0 0 53 52" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Artboard" clip-path="url(#clip-Artboard)">
<g id="_8" data-name="8">
<rect id="Rectangle" width="29" height="36" rx="4" transform="translate(13 8)" fill="#2582fb"/>
<g id="bottom">
<rect id="carat" width="14" height="14" transform="translate(18 39) rotate(-45)" fill="#2582fb"/>
</g>
<g id="left">
<rect id="carat-2" data-name="carat" width="14" height="14" transform="translate(7.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="right">
<rect id="carat-3" data-name="carat" width="14" height="14" transform="translate(26.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="top">
<rect id="carat-4" data-name="carat" width="14" height="14" transform="translate(18 13) rotate(-45)" fill="#2582fb"/>
</g>
<path id="A" d="M10.728,12.307A2.72,2.72,0,0,1,12.5,9.764a2.918,2.918,0,0,1-1.019-.93,2.225,2.225,0,0,1-.369-1.251,2.323,2.323,0,0,1,.827-1.825,3.059,3.059,0,0,1,2.092-.725,3.069,3.069,0,0,1,2.1.725,2.309,2.309,0,0,1,.827,1.812,2.157,2.157,0,0,1-.383,1.244,3.029,3.029,0,0,1-1.039.93,2.666,2.666,0,0,1,1.319,1.046,2.742,2.742,0,0,1,.458,1.511,2.613,2.613,0,0,1-.909,2.061,3.479,3.479,0,0,1-2.379.8,3.518,3.518,0,0,1-2.382-.793A2.59,2.59,0,0,1,10.728,12.307Zm1.565-.137a1.693,1.693,0,0,0,.482,1.278,1.905,1.905,0,0,0,2.5-.007,1.672,1.672,0,0,0,.5-1.271,1.74,1.74,0,0,0-.479-1.23,1.64,1.64,0,0,0-1.258-.513,1.689,1.689,0,0,0-1.743,1.743Zm.321-4.457a1.415,1.415,0,0,0,.424,1.053,1.423,1.423,0,0,0,2.013,0,1.409,1.409,0,0,0,.427-1.053A1.414,1.414,0,0,0,14.043,6.25a1.362,1.362,0,0,0-1.029.417A1.451,1.451,0,0,0,12.614,7.713Z" transform="translate(13.5 15.689)" fill="#fff"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="53px" height="52px" viewBox="0 0 53 52" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Artboard" clip-path="url(#clip-Artboard)">
<g id="_9" data-name="9">
<rect id="Rectangle" width="29" height="36" rx="4" transform="translate(13 8)" fill="#2582fb"/>
<g id="bottom">
<rect id="carat" width="14" height="14" transform="translate(18 39) rotate(-45)" fill="#2582fb"/>
</g>
<g id="left">
<rect id="carat-2" data-name="carat" width="14" height="14" transform="translate(7.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="right">
<rect id="carat-3" data-name="carat" width="14" height="14" transform="translate(26.899 26) rotate(-45)" fill="#2582fb"/>
</g>
<g id="top">
<rect id="carat-4" data-name="carat" width="14" height="14" transform="translate(18 13) rotate(-45)" fill="#2582fb"/>
</g>
<path id="A" d="M17.27,9.565a7.426,7.426,0,0,1-.974,4.163,3.4,3.4,0,0,1-3.032,1.442,3.851,3.851,0,0,1-1.336-.222,3.755,3.755,0,0,1-1.159-.7l.827-.978a2.674,2.674,0,0,0,.779.465,2.74,2.74,0,0,0,.957.15,2.071,2.071,0,0,0,1.791-.865,4.586,4.586,0,0,0,.622-2.663l-.034-.007a2.05,2.05,0,0,1-.834.81,2.651,2.651,0,0,1-1.237.27,2.617,2.617,0,0,1-2.017-.854,3.1,3.1,0,0,1-.786-2.187,3.316,3.316,0,0,1,.913-2.427,3.13,3.13,0,0,1,2.334-.93,2.708,2.708,0,0,1,2.348,1.189A5.744,5.744,0,0,1,17.27,9.565Zm-1.6-1.073a2.551,2.551,0,0,0-.465-1.576,1.487,1.487,0,0,0-2.362-.068,2.071,2.071,0,0,0-.461,1.377,2.044,2.044,0,0,0,.461,1.429,1.572,1.572,0,0,0,1.22.506,1.513,1.513,0,0,0,1.148-.485A1.659,1.659,0,0,0,15.67,8.492Z" transform="translate(13.5 15.689)" fill="#fff"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 178 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 179 KiB

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<!--
To customize common C++/WinRT project properties:
* right-click the project node
* expand the Common Properties item
* select the C++/WinRT property page
For more advanced scenarios, and complete documentation, please see:
https://github.com/Microsoft/cppwinrt/tree/master/nuget
-->
<PropertyGroup />
<ItemDefinitionGroup />
</Project>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
@@ -117,94 +117,55 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="CloseButton.ToolTipService.ToolTip" xml:space="preserve">
<value>Close</value>
<data name="Setting_Description_Overlay_Opacity" xml:space="preserve">
<value>Opacity of the Shortcut Guide's overlay background (%)</value>
</data>
<data name="ErrorInAppParsing" xml:space="preserve">
<value>Error displaying the application's shortcuts</value>
<comment>Shortcuts refers to keyboard shortcuts; Application refers to a PC application</comment>
<data name="Setting_Description_Theme" xml:space="preserve">
<value>Choose Shortcut Guide overlay color</value>
</data>
<data name="ErrorInCategoryParsing" xml:space="preserve">
<value>There has been an error displaying this category</value>
<data name="Setting_Description_Theme_Light" xml:space="preserve">
<value>Light</value>
</data>
<data name="InformationButton.ToolTipService.ToolTip" xml:space="preserve">
<value>Open additional information</value>
<data name="Setting_Description_Theme_Dark" xml:space="preserve">
<value>Dark</value>
</data>
<data name="InformationTip.Title" xml:space="preserve">
<value>Additional information</value>
<data name="Setting_Description_Theme_System" xml:space="preserve">
<value>System default app mode</value>
</data>
<data name="InformationTip1.Text" xml:space="preserve">
<value>This app may display content provided by third-party sources. Microsoft does not endorse or assume responsibility for the accuracy, reliability, or legality of such content.</value>
<data name="Settings_Description" xml:space="preserve">
<value>Shows a help overlay with Windows shortcuts when the Windows key is pressed.</value>
</data>
<data name="InformationTip2.Text" xml:space="preserve">
<value>The content related to Windows is always based on the latest release build of Windows.</value>
</data>
<data name="Overview" xml:space="preserve">
<value>Overview</value>
<comment>Category title</comment>
</data>
<data name="PinnedHeaderTxt.Text" xml:space="preserve">
<value>Pinned Shortcuts</value>
<comment>Shortcuts refers to keyboard shortcuts</comment>
</data>
<data name="PinShortcut" xml:space="preserve">
<value>Pin</value>
<comment>Refers to the action of pinning something on a pin board</comment>
</data>
<data name="RecommendedHeaderText.Text" xml:space="preserve">
<value>Recommended Shortcuts</value>
<comment>Shortcuts refers to keyboard shortcuts</comment>
</data>
<data name="SearchBlank" xml:space="preserve">
<value>No results found</value>
<comment>Results refers to search results</comment>
</data>
<data name="SearchBox.PlaceholderText" xml:space="preserve">
<value>Search shortcuts</value>
</data>
<data name="SettingsButton.ToolTipService.ToolTip" xml:space="preserve">
<value>Open settings</value>
</data>
<data name="TaskbarLaunchShortcutsDescription.Text" xml:space="preserve">
<value>Use these keys together with a number displayed below</value>
<comment>keys refers to keyboard keys</comment>
</data>
<data name="TaskbarHeaderTxt.Text" xml:space="preserve">
<value>Taskbar Shortcuts</value>
<comment>Shortcuts refers to keyboard shortcuts</comment>
</data>
<data name="Title" xml:space="preserve">
<data name="Shortcut_Guide" xml:space="preserve">
<value>Shortcut Guide</value>
<comment>Shortcut refers to a keyboard shortcut</comment>
</data>
<data name="UnpinShortcut" xml:space="preserve">
<value>Unpin</value>
<comment>Refers to the action of unpinning something from a pin board</comment>
<data name="No_Action" xml:space="preserve">
<value>No action</value>
</data>
<data name="Welcome" xml:space="preserve">
<value>Welcome</value>
<data name="Restore" xml:space="preserve">
<value>Restore</value>
</data>
<data name="PinnedEmptyText.Text" xml:space="preserve">
<value>No pinned shortcuts</value>
<data name="Snap_Right" xml:space="preserve">
<value>Snap right</value>
</data>
<data name="NoShortcuts.Text" xml:space="preserve">
<value>No shortcuts available</value>
<data name="Snap_Left" xml:space="preserve">
<value>Snap left</value>
</data>
<data name="NoRecommendedShortcuts.Text" xml:space="preserve">
<value>No recommended shortcuts available</value>
<data name="Snap_Upper_Right" xml:space="preserve">
<value>Snap upper right</value>
</data>
<data name="Titlebar.Title" xml:space="preserve">
<value>Shortcut Guide</value>
<comment>Shortcut refers to a keyboard shortcut</comment>
<data name="Snap_Upper_Left" xml:space="preserve">
<value>Snap upper left</value>
</data>
<data name="TaskbarDescriptionTxt.Text" xml:space="preserve">
<value>In combination with the number shown above the taskbar</value>
<data name="Snap_Lower_Right" xml:space="preserve">
<value>Snap lower right</value>
</data>
<data name="UnderlinedKeyChar.Text" xml:space="preserve">
<value>Underlined character</value>
<comment>character meaning a letter</comment>
<data name="Snap_Lower_Left" xml:space="preserve">
<value>Snap lower left</value>
</data>
<data name="SettingsButton.Content" xml:space="preserve">
<value>Settings</value>
<data name="Minimize" xml:space="preserve">
<value>Minimize</value>
</data>
<data name="Maximize" xml:space="preserve">
<value>Maximize</value>
</data>
</root>

View File

@@ -0,0 +1,54 @@
#include <windows.h>
#include "Generated Files/resource.h"
#include "../../../../common/version/version.h"
#define APSTUDIO_READONLY_SYMBOLS
#include "winres.h"
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON "Shortcut-Guide.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION FILE_VERSION
PRODUCTVERSION PRODUCT_VERSION
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", COMPANY_NAME
VALUE "FileDescription", FILE_DESCRIPTION
VALUE "FileVersion", FILE_VERSION_STRING
VALUE "InternalName", INTERNAL_NAME
VALUE "LegalCopyright", COPYRIGHT_NOTE
VALUE "OriginalFilename", ORIGINAL_FILENAME
VALUE "ProductName", PRODUCT_NAME
VALUE "ProductVersion", PRODUCT_VERSION_STRING
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</windowsSettings>
</application>
</assembly>

View File

@@ -0,0 +1,193 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 $(MSBuildThisFileDirectory) resource.base.h resource.h ShortcutGuide.base.rc ShortcutGuide.rc" />
</Target>
<PropertyGroup Label="Globals">
<CppWinRTOptimized>true</CppWinRTOptimized>
<CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge>
<CppWinRTGenerateWindowsMetadata>true</CppWinRTGenerateWindowsMetadata>
<MinimalCoreWin>true</MinimalCoreWin>
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{2edb3eb4-fa92-4bff-b2d8-566584837231}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>ShortcutGuide</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="PropertySheet.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<TargetName>PowerToys.$(MSBuildProjectName)</TargetName>
</PropertyGroup>
<PropertyGroup>
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>;..\..\..\common\inc;..\..\..\common\Telemetry;..\..\..\;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>ole32.lib;Shell32.lib;OleAut32.lib;Dbghelp.lib;Dwmapi.lib;Dcomp.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="animation.h" />
<ClInclude Include="d2d_svg.h" />
<ClInclude Include="d2d_text.h" />
<ClInclude Include="d2d_window.h" />
<ClInclude Include="Generated Files\resource.h" />
<ClInclude Include="native_event_waiter.h" />
<ClInclude Include="overlay_window.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="resource.base.h" />
<ClInclude Include="ShortcutGuideSettings.h" />
<ClInclude Include="ShortcutGuideConstants.h" />
<ClInclude Include="shortcut_guide.h" />
<ClInclude Include="start_visible.h" />
<ClInclude Include="target_state.h" />
<ClInclude Include="tasklist_positions.h" />
<ClInclude Include="trace.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="animation.cpp" />
<ClCompile Include="d2d_svg.cpp" />
<ClCompile Include="d2d_text.cpp" />
<ClCompile Include="d2d_window.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="native_event_waiter.cpp" />
<ClCompile Include="overlay_window.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="shortcut_guide.cpp" />
<ClCompile Include="start_visible.cpp" />
<ClCompile Include="target_state.cpp" />
<ClCompile Include="tasklist_positions.cpp" />
<ClCompile Include="trace.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="PropertySheet.props" />
<CopyFileToFolders Include="Assets\ShortcutGuide\0.svg">
<FileType>Document</FileType>
<DestinationFolders>$(OutDir)\Assets\ShortcutGuide</DestinationFolders>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\1.svg">
<FileType>Document</FileType>
<DestinationFolders>$(OutDir)\Assets\ShortcutGuide</DestinationFolders>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\2.svg">
<FileType>Document</FileType>
<DestinationFolders>$(OutDir)\Assets\ShortcutGuide</DestinationFolders>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\3.svg">
<FileType>Document</FileType>
<DestinationFolders>$(OutDir)\Assets\ShortcutGuide</DestinationFolders>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\4.svg">
<FileType>Document</FileType>
<DestinationFolders>$(OutDir)\Assets\ShortcutGuide</DestinationFolders>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\5.svg">
<FileType>Document</FileType>
<DestinationFolders>$(OutDir)\Assets\ShortcutGuide</DestinationFolders>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\6.svg">
<FileType>Document</FileType>
<DestinationFolders>$(OutDir)\Assets\ShortcutGuide</DestinationFolders>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\7.svg">
<FileType>Document</FileType>
<DestinationFolders>$(OutDir)\Assets\ShortcutGuide</DestinationFolders>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\8.svg">
<FileType>Document</FileType>
<DestinationFolders>$(OutDir)\Assets\ShortcutGuide</DestinationFolders>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\9.svg">
<FileType>Document</FileType>
<DestinationFolders>$(OutDir)\Assets\ShortcutGuide</DestinationFolders>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\no_active_window.svg">
<FileType>Document</FileType>
<DestinationFolders>$(OutDir)\Assets\ShortcutGuide</DestinationFolders>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\overlay.svg">
<FileType>Document</FileType>
<DestinationFolders>$(OutDir)\Assets\ShortcutGuide</DestinationFolders>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\overlay_portrait.svg">
<FileType>Document</FileType>
<DestinationFolders>$(OutDir)\Assets\ShortcutGuide</DestinationFolders>
</CopyFileToFolders>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\Display\Display.vcxproj">
<Project>{caba8dfb-823b-4bf2-93ac-3f31984150d9}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\common\Telemetry\EtwTrace\EtwTrace.vcxproj">
<Project>{8f021b46-362b-485c-bfba-ccf83e820cbd}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\common\Themes\Themes.vcxproj">
<Project>{98537082-0fdb-40de-abd8-0dc5a4269bab}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources.resx" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Generated Files\ShortcutGuide.rc" />
<None Include="ShortcutGuide.base.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="Shortcut-Guide.ico" />
</ItemGroup>
<ItemGroup>
<Manifest Include="ShortcutGuide.exe.manifest" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="..\..\..\..\deps\spdlog.props" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View File

@@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;svg;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Generated Files">
<UniqueIdentifier>{cb917ac7-30da-494b-81f1-cbe4415e91f4}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="animation.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="d2d_svg.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="d2d_text.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="d2d_window.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="native_event_waiter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="overlay_window.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="shortcut_guide.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ShortcutGuideConstants.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="start_visible.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="target_state.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="tasklist_positions.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="trace.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.base.h">
<Filter>Resource Files</Filter>
</ClInclude>
<ClInclude Include="Generated Files\resource.h">
<Filter>Generated Files</Filter>
</ClInclude>
<ClInclude Include="ShortcutGuideSettings.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="animation.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="d2d_svg.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="d2d_text.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="d2d_window.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="native_event_waiter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="overlay_window.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="shortcut_guide.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="start_visible.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="target_state.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="tasklist_positions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="trace.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="PropertySheet.props" />
<None Include="ShortcutGuide.base.rc">
<Filter>Resource Files</Filter>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<CopyFileToFolders Include="Assets\ShortcutGuide\**">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources.resx">
<Filter>Resource Files</Filter>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Generated Files\ShortcutGuide.rc">
<Filter>Generated Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<Image Include="Shortcut-Guide.ico">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<Manifest Include="ShortcutGuide.exe.manifest" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,8 @@
#pragma once
#include <string>
namespace ShortcutGuideConstants
{
// Name of the powertoy module.
inline const std::wstring ModuleKey = L"Shortcut Guide";
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
struct ShortcutGuideSettings
{
std::wstring hotkey = L"shift+win+/";
int overlayOpacity = 90;
std::wstring theme = L"system";
std::wstring disabledApps = L"";
bool shouldReactToPressedWinKey = false;
int windowsKeyPressTimeForGlobalWindowsShortcuts = 900;
int windowsKeyPressTimeForTaskbarIconShortcuts = 900;
};

View File

@@ -0,0 +1,51 @@
#include "pch.h"
#include "animation.h"
Animation::Animation(double duration, double start, double stop) :
duration(duration), start_value(start), end_value(stop), start(std::chrono::high_resolution_clock::now()) {}
void Animation::reset()
{
start = std::chrono::high_resolution_clock::now();
}
void Animation::reset(double animation_duration)
{
duration = animation_duration;
reset();
}
void Animation::reset(double animation_duration, double animation_start, double animation_stop)
{
start_value = animation_start;
end_value = animation_stop;
reset(animation_duration);
}
static double ease_out_expo(double t)
{
return 1 - pow(2, -8 * t);
}
double Animation::apply_animation_function(double t, AnimFunctions apply_function)
{
switch (apply_function)
{
case EASE_OUT_EXPO:
return ease_out_expo(t);
case LINEAR:
default:
return t;
}
}
double Animation::value(AnimFunctions apply_function) const
{
auto anim_duration = std::chrono::high_resolution_clock::now() - start;
double t = std::chrono::duration<double>(anim_duration).count() / duration;
if (t >= 1)
return end_value;
return start_value + (end_value - start_value) * apply_animation_function(t, apply_function);
}
bool Animation::done() const
{
return std::chrono::high_resolution_clock::now() - start >= std::chrono::duration<double>(duration);
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include <chrono>
/*
Usage:
When creating animation constructor takes one parameter - how long
should the animation take in seconds.
Call reset() when starting animation.
When rendering, call value() to get value from 0 to 1 - depending on animation
progress.
*/
class Animation
{
public:
enum AnimFunctions
{
LINEAR = 0,
EASE_OUT_EXPO
};
Animation(double duration = 1, double start = 0, double stop = 1);
void reset();
void reset(double animation_duration);
void reset(double animation_duration, double animation_start, double animation_stop);
double value(AnimFunctions apply_function) const;
bool done() const;
private:
static double apply_animation_function(double t, AnimFunctions apply_function);
std::chrono::high_resolution_clock::time_point start;
double start_value, end_value, duration;
};

View File

@@ -0,0 +1,120 @@
#include "pch.h"
#include "d2d_svg.h"
D2DSVG& D2DSVG::load(const std::wstring& filename, ID2D1DeviceContext5* d2d_dc)
{
svg = nullptr;
winrt::com_ptr<IStream> svg_stream;
auto h = SHCreateStreamOnFileEx(filename.c_str(),
STGM_READ,
FILE_ATTRIBUTE_NORMAL,
FALSE,
nullptr,
svg_stream.put());
winrt::check_hresult(h);
auto h1 = d2d_dc->CreateSvgDocument(
svg_stream.get(),
D2D1::SizeF(1, 1),
svg.put());
winrt::check_hresult(h1);
winrt::com_ptr<ID2D1SvgElement> root;
svg->GetRoot(root.put());
float tmp;
winrt::check_hresult(root->GetAttributeValue(L"width", &tmp));
svg_width = static_cast<int>(tmp);
winrt::check_hresult(root->GetAttributeValue(L"height", &tmp));
svg_height = static_cast<int>(tmp);
return *this;
}
D2DSVG& D2DSVG::resize(int x, int y, int width, int height, float fill, float max_scale)
{
// Center
transform = D2D1::Matrix3x2F::Identity();
transform = transform * D2D1::Matrix3x2F::Translation((width - svg_width) / 2.0f, (height - svg_height) / 2.0f);
float h_scale = fill * height / svg_height;
float v_scale = fill * width / svg_width;
used_scale = std::min(h_scale, v_scale);
if (max_scale > 0)
{
used_scale = std::min(used_scale, max_scale);
}
transform = transform * D2D1::Matrix3x2F::Scale(used_scale, used_scale, D2D1::Point2F(width / 2.0f, height / 2.0f));
transform = transform * D2D1::Matrix3x2F::Translation(static_cast<float>(x), static_cast<float>(y));
return *this;
}
D2DSVG& D2DSVG::recolor(uint32_t oldcolor, uint32_t newcolor)
{
auto new_color = D2D1::ColorF(newcolor & 0xFFFFFF, 1);
auto old_color = D2D1::ColorF(oldcolor & 0xFFFFFF, 1);
std::function<void(ID2D1SvgElement * element)> recurse = [&](ID2D1SvgElement* element) {
if (!element)
return;
if (element->IsAttributeSpecified(L"fill"))
{
D2D1_COLOR_F elem_fill;
winrt::com_ptr<ID2D1SvgPaint> paint;
element->GetAttributeValue(L"fill", paint.put());
paint->GetColor(&elem_fill);
if (elem_fill.r == old_color.r && elem_fill.g == old_color.g && elem_fill.b == old_color.b)
{
winrt::check_hresult(element->SetAttributeValue(L"fill", new_color));
}
}
winrt::com_ptr<ID2D1SvgElement> sub;
element->GetFirstChild(sub.put());
while (sub)
{
recurse(sub.get());
winrt::com_ptr<ID2D1SvgElement> next;
element->GetNextChild(sub.get(), next.put());
sub = next;
}
};
winrt::com_ptr<ID2D1SvgElement> root;
svg->GetRoot(root.put());
recurse(root.get());
return *this;
}
D2DSVG& D2DSVG::render(ID2D1DeviceContext5* d2d_dc)
{
D2D1_MATRIX_3X2_F current;
d2d_dc->GetTransform(&current);
d2d_dc->SetTransform(transform * current);
d2d_dc->DrawSvgDocument(svg.get());
d2d_dc->SetTransform(current);
return *this;
}
D2DSVG& D2DSVG::toggle_element(const wchar_t* id, bool visible)
{
winrt::com_ptr<ID2D1SvgElement> element;
if (svg->FindElementById(id, element.put()) != S_OK)
return *this;
if (!element)
return *this;
element->SetAttributeValue(L"display", visible ? D2D1_SVG_DISPLAY::D2D1_SVG_DISPLAY_INLINE : D2D1_SVG_DISPLAY::D2D1_SVG_DISPLAY_NONE);
return *this;
}
winrt::com_ptr<ID2D1SvgElement> D2DSVG::find_element(const std::wstring& id)
{
winrt::com_ptr<ID2D1SvgElement> element;
winrt::check_hresult(svg->FindElementById(id.c_str(), element.put()));
return element;
}
D2D1_RECT_F D2DSVG::rescale(D2D1_RECT_F rect)
{
D2D1_RECT_F result;
auto src = reinterpret_cast<D2D1_POINT_2F*>(&rect);
auto dst = reinterpret_cast<D2D1_POINT_2F*>(&result);
dst[0] = src[0] * transform;
dst[1] = src[1] * transform;
return result;
}

View File

@@ -0,0 +1,26 @@
#pragma once
#include <d2d1_3.h>
#include <d2d1_3helper.h>
#include <winrt/base.h>
#include <string>
class D2DSVG
{
public:
D2DSVG& load(const std::wstring& filename, ID2D1DeviceContext5* d2d_dc);
D2DSVG& resize(int x, int y, int width, int height, float fill, float max_scale = -1.0f);
D2DSVG& render(ID2D1DeviceContext5* d2d_dc);
D2DSVG& recolor(uint32_t oldcolor, uint32_t newcolor);
float get_scale() const { return used_scale; }
int width() const { return svg_width; }
int height() const { return svg_height; }
D2DSVG& toggle_element(const wchar_t* id, bool visible);
winrt::com_ptr<ID2D1SvgElement> find_element(const std::wstring& id);
D2D1_RECT_F rescale(D2D1_RECT_F rect);
protected:
float used_scale = 1.0f;
winrt::com_ptr<ID2D1SvgDocument> svg;
int svg_width = -1, svg_height = -1;
D2D1::Matrix3x2F transform;
};

View File

@@ -0,0 +1,54 @@
#include "pch.h"
#include "d2d_text.h"
D2DText::D2DText(float text_size, float scale)
{
winrt::check_hresult(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(factory), reinterpret_cast<IUnknown**>(factory.put_void())));
resize(text_size, scale);
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
winrt::check_hresult(format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER));
}
D2DText& D2DText::resize(float text_size, float scale)
{
format = nullptr;
winrt::check_hresult(factory->CreateTextFormat(L"Segoe UI",
nullptr,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
text_size * scale,
L"en-us",
format.put()));
winrt::check_hresult(format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER));
return *this;
}
D2DText& D2DText::set_alignment_left()
{
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING));
return *this;
}
D2DText& D2DText::set_alignment_center()
{
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
return *this;
}
D2DText& D2DText::set_alignment_right()
{
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_TRAILING));
return *this;
}
void D2DText::write(ID2D1DeviceContext5* d2d_dc, D2D1_COLOR_F color, D2D1_RECT_F rect, std::wstring text)
{
winrt::com_ptr<ID2D1SolidColorBrush> brush;
d2d_dc->CreateSolidColorBrush(color, brush.put());
d2d_dc->DrawText(text.c_str(),
static_cast<UINT32>(text.length()),
format.get(),
rect,
brush.get());
}

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