mirror of
https://github.com/microsoft/PowerToys.git
synced 2024-12-24 09:07:59 +08:00
Merge remote-tracking branch 'origin/main' into dev/snickler/net8-upgrade
This commit is contained in:
commit
c05270aafd
1
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
1
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -50,6 +50,7 @@ body:
|
||||
- Always on Top
|
||||
- Awake
|
||||
- ColorPicker
|
||||
- Crop and Lock
|
||||
- FancyZones
|
||||
- FancyZones Editor
|
||||
- File Locksmith
|
||||
|
1
.github/ISSUE_TEMPLATE/translation_issue.yml
vendored
1
.github/ISSUE_TEMPLATE/translation_issue.yml
vendored
@ -24,6 +24,7 @@ body:
|
||||
- Always on Top
|
||||
- Awake
|
||||
- ColorPicker
|
||||
- Crop and Lock
|
||||
- FancyZones
|
||||
- FancyZones Editor
|
||||
- File Locksmith
|
||||
|
6
.github/actions/spell-check/allow/names.txt
vendored
6
.github/actions/spell-check/allow/names.txt
vendored
@ -15,6 +15,8 @@ edwinzap
|
||||
Essey
|
||||
Garside
|
||||
Gershaft
|
||||
Gokce
|
||||
Guo
|
||||
hallatore
|
||||
Harmath
|
||||
Hemmerlein
|
||||
@ -22,10 +24,13 @@ Huynh
|
||||
Jaswal
|
||||
jefflord
|
||||
Kamra
|
||||
Kantarci
|
||||
Karthick
|
||||
kevinguo
|
||||
Krigun
|
||||
Luecking
|
||||
Mahalingam
|
||||
Mikhayelyan
|
||||
mshtang
|
||||
Myrvold
|
||||
naveensrinivasan
|
||||
@ -33,6 +38,7 @@ nVidia
|
||||
Ponten
|
||||
Pooja
|
||||
robmen
|
||||
robmikh
|
||||
Schoen
|
||||
skycommand
|
||||
snickler
|
||||
|
8
.github/actions/spell-check/expect.txt
vendored
8
.github/actions/spell-check/expect.txt
vendored
@ -674,6 +674,7 @@ hcblack
|
||||
HCERTSTORE
|
||||
HCRYPTHASH
|
||||
HCRYPTPROV
|
||||
hcursor
|
||||
hcwhite
|
||||
hdc
|
||||
hdrop
|
||||
@ -742,7 +743,7 @@ hstring
|
||||
hsv
|
||||
htcfreek
|
||||
HTCLIENT
|
||||
HTHUMBNAIL
|
||||
hthumbnail
|
||||
HTOUCHINPUT
|
||||
HTTRANSPARENT
|
||||
HVal
|
||||
@ -1529,6 +1530,7 @@ RECTDESTINATION
|
||||
RECTL
|
||||
rectp
|
||||
rects
|
||||
RECTSOURCE
|
||||
redirectedfrom
|
||||
Redist
|
||||
redistributable
|
||||
@ -1566,6 +1568,9 @@ Removelnk
|
||||
renamable
|
||||
RENAMEONCOLLISION
|
||||
Renamer
|
||||
reparent
|
||||
reparented
|
||||
reparenting
|
||||
reparse
|
||||
reportbug
|
||||
requery
|
||||
@ -1998,6 +2003,7 @@ unregistering
|
||||
unremapped
|
||||
unsubscribe
|
||||
unvirtualized
|
||||
unwide
|
||||
UOffset
|
||||
UOI
|
||||
Updatelayout
|
||||
|
2
.github/actions/spell-check/patterns.txt
vendored
2
.github/actions/spell-check/patterns.txt
vendored
@ -115,12 +115,14 @@ TestCase\("[^"]+"
|
||||
\\Registry
|
||||
\\registry
|
||||
\\reinstall
|
||||
\\release
|
||||
\\Resize
|
||||
\\resource
|
||||
\\Resources
|
||||
\\restart
|
||||
\\restore
|
||||
\\result
|
||||
\\robmikh
|
||||
\\rotating
|
||||
\\runner
|
||||
\\runtimes
|
||||
|
@ -33,6 +33,9 @@
|
||||
"PowerToys.ColorPickerUI.dll",
|
||||
"PowerToys.ColorPickerUI.exe",
|
||||
|
||||
"PowerToys.CropAndLockModuleInterface.dll",
|
||||
"PowerToys.CropAndLock.exe",
|
||||
|
||||
"PowerToys.PowerOCRModuleInterface.dll",
|
||||
"PowerToys.PowerOCR.dll",
|
||||
"PowerToys.PowerOCR.exe",
|
||||
|
@ -1,7 +1,7 @@
|
||||
parameters:
|
||||
configuration: 'Release'
|
||||
platform: ''
|
||||
additionalBuildArguments: '-m'
|
||||
additionalBuildArguments: '/p:RestorePackagesConfig=true -m'
|
||||
|
||||
jobs:
|
||||
- job: Build${{ parameters.platform }}${{ parameters.configuration }}
|
||||
|
@ -1,7 +1,7 @@
|
||||
parameters:
|
||||
configuration: 'Release'
|
||||
platform: ''
|
||||
additionalBuildArguments: '-m'
|
||||
additionalBuildArguments: '/p:RestorePackagesConfig=true -m'
|
||||
|
||||
jobs:
|
||||
- job: Build${{ parameters.platform }}${{ parameters.configuration }}
|
||||
|
@ -55,21 +55,9 @@ steps:
|
||||
packageType: sdk
|
||||
version: '7.x'
|
||||
|
||||
- task: NuGetToolInstaller@1
|
||||
displayName: Ensure NuGet Installer
|
||||
|
||||
- task: VisualStudioTestPlatformInstaller@1
|
||||
displayName: Ensure VSTest Platform
|
||||
|
||||
- task: NuGetCommand@2
|
||||
displayName: Restore NuGet packages for PowerToys.sln
|
||||
inputs:
|
||||
command: restore
|
||||
feedsToUse: config
|
||||
configPath: NuGet.config
|
||||
restoreSolution: PowerToys.sln
|
||||
restoreDirectory: '$(Build.SourcesDirectory)\packages'
|
||||
|
||||
- task: VSBuild@1
|
||||
displayName: 'Build PowerToys.sln'
|
||||
inputs:
|
||||
@ -77,18 +65,9 @@ steps:
|
||||
vsVersion: 17.0
|
||||
platform: '$(BuildPlatform)'
|
||||
configuration: '$(BuildConfiguration)'
|
||||
msbuildArgs: ${{ parameters.additionalBuildArguments }}
|
||||
msbuildArgs: -restore ${{ parameters.additionalBuildArguments }}
|
||||
maximumCpuCount: true
|
||||
|
||||
- task: NuGetCommand@2
|
||||
displayName: Restore NuGet packages for BugReportTool.sln
|
||||
inputs:
|
||||
command: restore
|
||||
feedsToUse: config
|
||||
configPath: NuGet.config
|
||||
restoreSolution: tools\BugReportTool\BugReportTool.sln
|
||||
restoreDirectory: '$(Build.SourcesDirectory)\tools\BugReportTool\packages'
|
||||
|
||||
- task: VSBuild@1
|
||||
displayName: 'Build BugReportTool.sln'
|
||||
inputs:
|
||||
@ -96,18 +75,9 @@ steps:
|
||||
vsVersion: 17.0
|
||||
platform: '$(BuildPlatform)'
|
||||
configuration: '$(BuildConfiguration)'
|
||||
msbuildArgs: ${{ parameters.additionalBuildArguments }}
|
||||
msbuildArgs: -restore ${{ parameters.additionalBuildArguments }}
|
||||
maximumCpuCount: true
|
||||
|
||||
- task: NuGetCommand@2
|
||||
displayName: Restore NuGet packages for WebcamReportTool.sln
|
||||
inputs:
|
||||
command: restore
|
||||
feedsToUse: config
|
||||
configPath: NuGet.config
|
||||
restoreSolution: tools\WebcamReportTool\WebcamReportTool.sln
|
||||
restoreDirectory: '$(Build.SourcesDirectory)\tools\WebcamReportTool\packages'
|
||||
|
||||
- task: VSBuild@1
|
||||
displayName: 'Build WebcamReportTool.sln'
|
||||
inputs:
|
||||
@ -115,18 +85,9 @@ steps:
|
||||
vsVersion: 17.0
|
||||
platform: '$(BuildPlatform)'
|
||||
configuration: '$(BuildConfiguration)'
|
||||
msbuildArgs: ${{ parameters.additionalBuildArguments }}
|
||||
msbuildArgs: -restore ${{ parameters.additionalBuildArguments }}
|
||||
maximumCpuCount: true
|
||||
|
||||
- task: NuGetCommand@2
|
||||
displayName: Restore NuGet packages for StylesReportTool.sln
|
||||
inputs:
|
||||
command: restore
|
||||
feedsToUse: config
|
||||
configPath: NuGet.config
|
||||
restoreSolution: tools\StylesReportTool\StylesReportTool.sln
|
||||
restoreDirectory: '$(Build.SourcesDirectory)\tools\StylesReportTool\packages'
|
||||
|
||||
- task: VSBuild@1
|
||||
displayName: 'Build StylesReportTool.sln'
|
||||
inputs:
|
||||
@ -134,18 +95,9 @@ steps:
|
||||
vsVersion: 17.0
|
||||
platform: '$(BuildPlatform)'
|
||||
configuration: '$(BuildConfiguration)'
|
||||
msbuildArgs: ${{ parameters.additionalBuildArguments }}
|
||||
msbuildArgs: -restore ${{ parameters.additionalBuildArguments }}
|
||||
maximumCpuCount: true
|
||||
|
||||
- task: NuGetCommand@2
|
||||
displayName: Restore NuGet packages for PowerToysSetup.sln
|
||||
inputs:
|
||||
command: restore
|
||||
feedsToUse: config
|
||||
configPath: NuGet.config
|
||||
restoreSolution: installer\PowerToysSetup.sln
|
||||
restoreDirectory: '$(Build.SourcesDirectory)\installer\packages'
|
||||
|
||||
- task: PowerShell@2
|
||||
displayName: Download and install WiX 3.14 development build
|
||||
inputs:
|
||||
@ -159,7 +111,7 @@ steps:
|
||||
vsVersion: 17.0
|
||||
platform: '$(BuildPlatform)'
|
||||
configuration: '$(BuildConfiguration)'
|
||||
msbuildArgs: /t:PowerToysInstaller ${{ parameters.additionalBuildArguments }}
|
||||
msbuildArgs: /t:PowerToysInstaller -restore ${{ parameters.additionalBuildArguments }}
|
||||
maximumCpuCount: true
|
||||
|
||||
- task: VSBuild@1
|
||||
@ -180,15 +132,6 @@ steps:
|
||||
script: git clean -xfd -e *exe -- .\installer\
|
||||
pwsh: true
|
||||
|
||||
- task: NuGetCommand@2
|
||||
displayName: Restore NuGet packages for PowerToysSetup.sln
|
||||
inputs:
|
||||
command: restore
|
||||
feedsToUse: config
|
||||
configPath: NuGet.config
|
||||
restoreSolution: installer\PowerToysSetup.sln
|
||||
restoreDirectory: '$(Build.SourcesDirectory)\installer\packages'
|
||||
|
||||
- task: VSBuild@1
|
||||
displayName: 'Build PowerToys per-user MSI'
|
||||
inputs:
|
||||
@ -196,7 +139,7 @@ steps:
|
||||
vsVersion: 17.0
|
||||
platform: '$(BuildPlatform)'
|
||||
configuration: '$(BuildConfiguration)'
|
||||
msbuildArgs: /t:PowerToysInstaller ${{ parameters.additionalBuildArguments }} /p:PerUser=true
|
||||
msbuildArgs: /t:PowerToysInstaller -restore ${{ parameters.additionalBuildArguments }} /p:PerUser=true
|
||||
maximumCpuCount: true
|
||||
|
||||
- task: VSBuild@1
|
||||
|
@ -18,7 +18,7 @@ steps:
|
||||
inputs:
|
||||
solution: "**/installer/PowerToysSetup.sln"
|
||||
vsVersion: 17.0
|
||||
msbuildArgs: /p:CIBuild=true /bl:$(Build.SourcesDirectory)\msbuild.binlog /t:PowerToysSetupCustomActions /p:RunBuildEvents=true /p:PerUser=${{parameters.perUserArg}}
|
||||
msbuildArgs: -restore /p:RestorePackagesConfig=true /p:RestoreConfigFile="$(Build.SourcesDirectory)\.pipelines\release-nuget.config" /p:CIBuild=true /bl:$(Build.SourcesDirectory)\msbuild.binlog /t:PowerToysSetupCustomActions /p:RunBuildEvents=true /p:PerUser=${{parameters.perUserArg}}
|
||||
platform: $(BuildPlatform)
|
||||
configuration: $(BuildConfiguration)
|
||||
clean: true
|
||||
|
@ -71,7 +71,7 @@ jobs:
|
||||
packageType: sdk
|
||||
version: '7.x'
|
||||
|
||||
- task: NuGetAuthenticate@0
|
||||
- task: NuGetAuthenticate@1
|
||||
|
||||
- task: NuGetToolInstaller@1
|
||||
displayName: Use NuGet Installer latest
|
||||
@ -82,14 +82,6 @@ jobs:
|
||||
# - Webcam report tool
|
||||
# - Installer
|
||||
# - Bootstrapper Installer
|
||||
- task: NuGetCommand@2
|
||||
displayName: NuGet restore solutions dependencies
|
||||
inputs:
|
||||
command: restore
|
||||
restoreSolution: '**/*.sln'
|
||||
selectOrConfig: config
|
||||
nugetConfigPath: .pipelines/release-nuget.config
|
||||
|
||||
- task: PowerShell@2
|
||||
displayName: Download and install WiX 3.14 development build
|
||||
inputs:
|
||||
@ -136,7 +128,7 @@ jobs:
|
||||
inputs:
|
||||
solution: '**\PowerToys.sln'
|
||||
vsVersion: 17.0
|
||||
msbuildArgs: /p:CIBuild=true /bl:$(Build.SourcesDirectory)\msbuild.binlog
|
||||
msbuildArgs: -restore /p:RestorePackagesConfig=true /p:RestoreConfigFile="$(Build.SourcesDirectory)\.pipelines\release-nuget.config" /p:CIBuild=true /bl:$(Build.SourcesDirectory)\msbuild.binlog
|
||||
platform: $(BuildPlatform)
|
||||
configuration: $(BuildConfiguration)
|
||||
clean: true
|
||||
@ -147,7 +139,7 @@ jobs:
|
||||
inputs:
|
||||
solution: '**/tools/BugReportTool/BugReportTool.sln'
|
||||
vsVersion: 17.0
|
||||
msbuildArgs: /p:CIBuild=true /bl:$(Build.SourcesDirectory)\msbuild.binlog
|
||||
msbuildArgs: -restore /p:RestorePackagesConfig=true /p:RestoreConfigFile="$(Build.SourcesDirectory)\.pipelines\release-nuget.config" /p:CIBuild=true /bl:$(Build.SourcesDirectory)\msbuild.binlog
|
||||
platform: $(BuildPlatform)
|
||||
configuration: $(BuildConfiguration)
|
||||
clean: true
|
||||
@ -158,7 +150,7 @@ jobs:
|
||||
inputs:
|
||||
solution: '**/tools/WebcamReportTool/WebcamReportTool.sln'
|
||||
vsVersion: 17.0
|
||||
msbuildArgs: /p:CIBuild=true /bl:$(Build.SourcesDirectory)\msbuild.binlog
|
||||
msbuildArgs: -restore /p:RestorePackagesConfig=true /p:RestoreConfigFile="$(Build.SourcesDirectory)\.pipelines\release-nuget.config" /p:CIBuild=true /bl:$(Build.SourcesDirectory)\msbuild.binlog
|
||||
platform: $(BuildPlatform)
|
||||
configuration: $(BuildConfiguration)
|
||||
clean: true
|
||||
@ -169,7 +161,7 @@ jobs:
|
||||
inputs:
|
||||
solution: '**/tools/StylesReportTool/StylesReportTool.sln'
|
||||
vsVersion: 17.0
|
||||
msbuildArgs: /p:CIBuild=true /bl:$(Build.SourcesDirectory)\msbuild.binlog
|
||||
msbuildArgs: -restore /p:RestorePackagesConfig=true /p:RestoreConfigFile="$(Build.SourcesDirectory)\.pipelines\release-nuget.config" /p:CIBuild=true /bl:$(Build.SourcesDirectory)\msbuild.binlog
|
||||
platform: $(BuildPlatform)
|
||||
configuration: $(BuildConfiguration)
|
||||
clean: true
|
||||
@ -397,14 +389,6 @@ jobs:
|
||||
script: git clean -xfd -e *exe -- .\installer\
|
||||
pwsh: true
|
||||
|
||||
- task: NuGetCommand@2
|
||||
displayName: NuGet restore solutions dependencies
|
||||
inputs:
|
||||
command: restore
|
||||
restoreSolution: 'installer/*.sln'
|
||||
selectOrConfig: config
|
||||
nugetConfigPath: .pipelines/release-nuget.config
|
||||
|
||||
- template: installer-steps.yml
|
||||
parameters:
|
||||
versionNumber: ${{ parameters.versionNumber }}
|
||||
|
@ -107,6 +107,10 @@ Randy contributed Registry Preview and some very early conversations about keybo
|
||||
|
||||
Find My Mouse is based on Raymond Chen's SuperSonar.
|
||||
|
||||
### [@robmikh](https://github.com/robmikh) - Robert Mikhayelyan
|
||||
|
||||
Crop And Lock is based on the original work of Robert Mikhayelyan, with Program Manager support from [@kevinguo305](https://github.com/kevinguo305) - Kevin Guo.
|
||||
|
||||
### Microsoft InVEST team
|
||||
|
||||
This amazing team helped PowerToys develop PowerToys Run and Keyboard manager as well as update our Settings to v2. @alekhyareddy28, @arjunbalgovind, @jyuwono @laviusmotileng-ms, @ryanbodrug-microsoft, @saahmedm, @somil55, @traies, @udit3333
|
||||
@ -152,8 +156,7 @@ Other contributors:
|
||||
- [@cinnamon-msft](https://github.com/cinnamon-msft) - Kayla Cinnamon - Product Manager
|
||||
- [@jaimecbernardo](https://github.com/jaimecbernardo) - Jaime Bernardo - Dev lead
|
||||
- [@donlaci](https://github.com/donlaci) - Laszlo Nemeth - Dev
|
||||
- [@gokcekantarci](https://github.com/gokcekantarci) - Gokce Kantarci - Dev
|
||||
- [@SeraphimaZykova](https://github.com/SeraphimaZykova) - Seraphima Zykova - Dev
|
||||
- [@sosssego](https://github.com/sosssego) - Frederico Moron - Dev
|
||||
- [@stefansjfw](https://github.com/stefansjfw) - Stefan Markovic - Dev
|
||||
- [@taras-janea](https://github.com/taras-janea) - Taras Sich - Dev
|
||||
- [@yuyoyuppe](https://github.com/yuyoyuppe) - Andrey Nekrasov - Dev
|
||||
|
@ -530,6 +530,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Community.PowerToys.Run.Plu
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Community.PowerToys.Run.Plugin.ValueGenerator.UnitTests", "src\modules\launcher\Plugins\Community.PowerToys.Run.Plugin.ValueGenerator.UnitTests\Community.PowerToys.Run.Plugin.ValueGenerator.UnitTests.csproj", "{90F9FA90-2C20-4004-96E6-F3B78151F5A5}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CropAndLock", "CropAndLock", "{3B227528-4BA6-4CAF-B44A-A10C78A64849}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CropAndLock", "src\modules\CropAndLock\CropAndLock\CropAndLock.vcxproj", "{F5E1146E-B7B3-4E11-85FD-270A500BD78C}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CropAndLockModuleInterface", "src\modules\CropAndLock\CropAndLockModuleInterface\CropAndLockModuleInterface.vcxproj", "{3157FA75-86CF-4EE2-8F62-C43F776493C6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
@ -2276,6 +2282,30 @@ Global
|
||||
{90F9FA90-2C20-4004-96E6-F3B78151F5A5}.Release|x64.Build.0 = Release|x64
|
||||
{90F9FA90-2C20-4004-96E6-F3B78151F5A5}.Release|x86.ActiveCfg = Release|x64
|
||||
{90F9FA90-2C20-4004-96E6-F3B78151F5A5}.Release|x86.Build.0 = Release|x64
|
||||
{F5E1146E-B7B3-4E11-85FD-270A500BD78C}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{F5E1146E-B7B3-4E11-85FD-270A500BD78C}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{F5E1146E-B7B3-4E11-85FD-270A500BD78C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F5E1146E-B7B3-4E11-85FD-270A500BD78C}.Debug|x64.Build.0 = Debug|x64
|
||||
{F5E1146E-B7B3-4E11-85FD-270A500BD78C}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{F5E1146E-B7B3-4E11-85FD-270A500BD78C}.Debug|x86.Build.0 = Debug|x64
|
||||
{F5E1146E-B7B3-4E11-85FD-270A500BD78C}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{F5E1146E-B7B3-4E11-85FD-270A500BD78C}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{F5E1146E-B7B3-4E11-85FD-270A500BD78C}.Release|x64.ActiveCfg = Release|x64
|
||||
{F5E1146E-B7B3-4E11-85FD-270A500BD78C}.Release|x64.Build.0 = Release|x64
|
||||
{F5E1146E-B7B3-4E11-85FD-270A500BD78C}.Release|x86.ActiveCfg = Release|x64
|
||||
{F5E1146E-B7B3-4E11-85FD-270A500BD78C}.Release|x86.Build.0 = Release|x64
|
||||
{3157FA75-86CF-4EE2-8F62-C43F776493C6}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{3157FA75-86CF-4EE2-8F62-C43F776493C6}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{3157FA75-86CF-4EE2-8F62-C43F776493C6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3157FA75-86CF-4EE2-8F62-C43F776493C6}.Debug|x64.Build.0 = Debug|x64
|
||||
{3157FA75-86CF-4EE2-8F62-C43F776493C6}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{3157FA75-86CF-4EE2-8F62-C43F776493C6}.Debug|x86.Build.0 = Debug|x64
|
||||
{3157FA75-86CF-4EE2-8F62-C43F776493C6}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{3157FA75-86CF-4EE2-8F62-C43F776493C6}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{3157FA75-86CF-4EE2-8F62-C43F776493C6}.Release|x64.ActiveCfg = Release|x64
|
||||
{3157FA75-86CF-4EE2-8F62-C43F776493C6}.Release|x64.Build.0 = Release|x64
|
||||
{3157FA75-86CF-4EE2-8F62-C43F776493C6}.Release|x86.ActiveCfg = Release|x64
|
||||
{3157FA75-86CF-4EE2-8F62-C43F776493C6}.Release|x86.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -2467,6 +2497,9 @@ Global
|
||||
{500DED3E-CFB5-4ED5-ACC6-02B3D6DC336D} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{D095BE44-1F2E-463E-A494-121892A75EA2} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{90F9FA90-2C20-4004-96E6-F3B78151F5A5} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{3B227528-4BA6-4CAF-B44A-A10C78A64849} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{F5E1146E-B7B3-4E11-85FD-270A500BD78C} = {3B227528-4BA6-4CAF-B44A-A10C78A64849}
|
||||
{3157FA75-86CF-4EE2-8F62-C43F776493C6} = {3B227528-4BA6-4CAF-B44A-A10C78A64849}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
13
README.md
13
README.md
@ -18,12 +18,13 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
|
||||
| | Current utilities: | |
|
||||
|--------------|--------------------|--------------|
|
||||
| [Always on Top](https://aka.ms/PowerToysOverview_AoT) | [PowerToys Awake](https://aka.ms/PowerToysOverview_Awake) | [Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) |
|
||||
| [FancyZones](https://aka.ms/PowerToysOverview_FancyZones) | [File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) | [File Locksmith](https://aka.ms/PowerToysOverview_FileLocksmith) |
|
||||
| [Hosts File Editor](https://aka.ms/PowerToysOverview_HostsFileEditor) | [Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) |
|
||||
| [Mouse utilities](https://aka.ms/PowerToysOverview_MouseUtilities) | [Mouse Without Borders](https://aka.ms/PowerToysOverview_MouseWithoutBorders) | [Peek](https://aka.ms/PowerToysOverview_Peek) |
|
||||
| [Paste as Plain Text](https://aka.ms/PowerToysOverview_PastePlain) | [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) |
|
||||
| [Quick Accent](https://aka.ms/PowerToysOverview_QuickAccent) | [Registry Preview](https://aka.ms/PowerToysOverview_RegistryPreview) | [Screen Ruler](https://aka.ms/PowerToysOverview_ScreenRuler) |
|
||||
| [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) | [Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [Video Conference Mute](https://aka.ms/PowerToysOverview_VideoConference) |
|
||||
| [Crop And Lock](https://aka.ms/PowerToysOverview_CropAndLock) | [FancyZones](https://aka.ms/PowerToysOverview_FancyZones) | [File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) |
|
||||
| [File Locksmith](https://aka.ms/PowerToysOverview_FileLocksmith) | [Hosts File Editor](https://aka.ms/PowerToysOverview_HostsFileEditor) | [Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) |
|
||||
| [Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) | [Mouse utilities](https://aka.ms/PowerToysOverview_MouseUtilities) | [Mouse Without Borders](https://aka.ms/PowerToysOverview_MouseWithoutBorders) |
|
||||
| [Peek](https://aka.ms/PowerToysOverview_Peek) | [Paste as Plain Text](https://aka.ms/PowerToysOverview_PastePlain) | [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) |
|
||||
| [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) | [Quick Accent](https://aka.ms/PowerToysOverview_QuickAccent) | [Registry Preview](https://aka.ms/PowerToysOverview_RegistryPreview) |
|
||||
| [Screen Ruler](https://aka.ms/PowerToysOverview_ScreenRuler) | [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) | [Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) |
|
||||
| [Video Conference Mute](https://aka.ms/PowerToysOverview_VideoConference) |
|
||||
|
||||
## Installing and running Microsoft PowerToys
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
# Keyboard Manager UI
|
||||
|
||||
## Table of Contents:
|
||||
1. [C++ XAML Islands](#c---xaml-islands)
|
||||
1. [C++ XAML Islands](#c-xaml-islands)
|
||||
1. [Debugging exceptions in XAML Islands](#debugging-exceptions-in-xaml-islands)
|
||||
2. [Build times](#build-times)
|
||||
3. [Setting custom backgrounds for Xaml Controls using brushes](#setting-custom-backgrounds-for-xaml-controls-using-brushes)
|
||||
2. [UI Structure](#ui-structure)
|
||||
3. [EditKeyboardWindow/EditShortcutsWindow](#editkeyboardwindow-editshortcutswindow)
|
||||
3. [EditKeyboardWindow / EditShortcutsWindow](#editkeyboardwindow--editshortcutswindow)
|
||||
1. [OK and Cancel button](#ok-and-cancel-button)
|
||||
2. [Delete button](#delete-button)
|
||||
3. [Handling common modifiers in EditKeyboardWindow](#handling-common-modifiers-in-editkeyboardwindow)
|
||||
@ -51,7 +51,7 @@ Since ComboBoxes are added dynamically, handlers have been added which [update t
|
||||
|
||||
When the `EditKeyboardWindow`/`EditShortcutsWindow` is created, [we iterate through the remappings](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L254-L262) stored in `KeyboardManagerState` and add rows to the UI Grid. For both the windows we have `static` buffers [`singleKeyRemapBuffer`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/SingleKeyRemapControl.h#L39-L40) and [`shortcutRemapBuffer`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/ShortcutControl.h#L42-L43) which store the corresponding key/shortcuts as per the selections in the UI if they are valid with no warnings.
|
||||
|
||||
## EditKeyboardWindow/EditShortcutsWindow
|
||||
## EditKeyboardWindow / EditShortcutsWindow
|
||||
|
||||
### OK and Cancel button
|
||||
[On pressing the OK button](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L66-L89) in `EditKeyboardWindow`, first the [`CheckIfRemappingsAreValid` method](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/LoadingAndSavingRemappingHelper.cpp#L10-L44) is executed which performs basic validity checks on the current remappings in the remap buffer (`static SingleKeyRemapControl::singleKeyRemapBuffer`), such as if there are no NULL columns and none of the source keys are repeated. All other validity checks are assumed to happen while the user adds the remapping. If this is found to be invalid a ContentDialog is displayed which shows that some remappings are invalid and if the user proceeds only the valid ones will be applied. If it is valid [`GetOrphanedKeys`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/LoadingAndSavingRemappingHelper.cpp#L46-L75) is executed which checks if any keys are orphaned (i.e. the key has been remapped and no other key has been remapped to it, so there is no way to send that key code), and a dialog is shown for notifying the user with a list of orphaned keys. After this the settings are [applied by adding it to the `KeyboardManagerState.singleKeyReMap` member](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/LoadingAndSavingRemappingHelper.cpp#L102-L164) and they are saved to the JSON file. `EditShortcutsWindow` differs slightly from this, as there is no orphaned keys check, and [on pressing OK](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditShortcutsWindow.cpp#L32-L47) both the global and app-specific shortcuts are validated and [updated](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/LoadingAndSavingRemappingHelper.cpp#L166-L223).
|
||||
|
@ -1005,7 +1005,7 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
|
||||
}
|
||||
processes.resize(bytes / sizeof(processes[0]));
|
||||
|
||||
std::array<std::wstring_view, 27> processesToTerminate = {
|
||||
std::array<std::wstring_view, 28> processesToTerminate = {
|
||||
L"PowerToys.PowerLauncher.exe",
|
||||
L"PowerToys.Settings.exe",
|
||||
L"PowerToys.Awake.exe",
|
||||
@ -1032,6 +1032,7 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
|
||||
L"PowerToys.MouseWithoutBorders.exe",
|
||||
L"PowerToys.MouseWithoutBordersHelper.exe",
|
||||
L"PowerToys.MouseWithoutBordersService.exe",
|
||||
L"PowerToys.CropAndLock.exe",
|
||||
L"PowerToys.exe",
|
||||
};
|
||||
|
||||
|
@ -73,6 +73,9 @@ std::optional<fs::path> ObtainInstaller(bool& isUpToDate)
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Cleanup old updates before downloading the latest
|
||||
updating::cleanup_updates();
|
||||
|
||||
auto downloaded_installer = download_new_version(std::get<new_version_download_info>(*new_version_info)).get();
|
||||
if (!downloaded_installer)
|
||||
{
|
||||
|
@ -16,6 +16,10 @@ namespace winrt::PowerToys::GPOWrapper::implementation
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredColorPickerEnabledValue());
|
||||
}
|
||||
GpoRuleConfigured GPOWrapper::GetConfiguredCropAndLockEnabledValue()
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredCropAndLockEnabledValue());
|
||||
}
|
||||
GpoRuleConfigured GPOWrapper::GetConfiguredFancyZonesEnabledValue()
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredFancyZonesEnabledValue());
|
||||
|
@ -10,6 +10,7 @@ namespace winrt::PowerToys::GPOWrapper::implementation
|
||||
static GpoRuleConfigured GetConfiguredAlwaysOnTopEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredAwakeEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredColorPickerEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredCropAndLockEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredFancyZonesEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredFileLocksmithEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredSvgPreviewEnabledValue();
|
||||
|
@ -14,6 +14,7 @@ namespace PowerToys
|
||||
static GpoRuleConfigured GetConfiguredAlwaysOnTopEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredAwakeEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredColorPickerEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredCropAndLockEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredFancyZonesEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredFileLocksmithEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredSvgPreviewEnabledValue();
|
||||
|
@ -74,6 +74,11 @@ namespace CommonSharedConstants
|
||||
// Path to the event used to show Peek
|
||||
const wchar_t SHOW_PEEK_SHARED_EVENT[] = L"Local\\ShowPeekEvent";
|
||||
|
||||
// Path to the events used by CropAndLock
|
||||
const wchar_t CROP_AND_LOCK_REPARENT_EVENT[] = L"Local\\PowerToysCropAndLockReparentEvent-6060860a-76a1-44e8-8d0e-6355785e9c36";
|
||||
const wchar_t CROP_AND_LOCK_THUMBNAIL_EVENT[] = L"Local\\PowerToysCropAndLockThumbnailEvent-1637be50-da72-46b2-9220-b32b206b2434";
|
||||
const wchar_t CROP_AND_LOCK_EXIT_EVENT[] = L"Local\\PowerToysCropAndLockExitEvent-d995d409-7b70-482b-bad6-e7c8666f375a";
|
||||
|
||||
// Max DWORD for key code to disable keys.
|
||||
const DWORD VK_DISABLED = 0x100;
|
||||
}
|
||||
|
@ -59,7 +59,8 @@ struct LogSettings
|
||||
inline const static std::wstring alwaysOnTopLogPath = L"always-on-top-log.txt";
|
||||
inline const static std::string hostsLoggerName = "hosts";
|
||||
inline const static std::wstring hostsLogPath = L"Logs\\hosts-log.txt";
|
||||
inline const static std::string registryPreviewLoggerName = "registrypreview";
|
||||
inline const static std::string registryPreviewLoggerName = "registrypreview";
|
||||
inline const static std::string cropAndLockLoggerName = "crop-and-lock";
|
||||
inline const static std::wstring registryPreviewLogPath = L"Logs\\registryPreview-log.txt";
|
||||
inline const static int retention = 30;
|
||||
std::wstring logLevel;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include <common/utils/HttpClient.h>
|
||||
#include <common/utils/string_utils.h>
|
||||
#include <common/version/version.h>
|
||||
#include <common/version/helper.h>
|
||||
|
||||
@ -185,4 +186,48 @@ namespace updating
|
||||
co_return download_success ? installer_download_path : std::nullopt;
|
||||
}
|
||||
|
||||
void cleanup_updates()
|
||||
{
|
||||
auto update_dir = updating::get_pending_updates_path();
|
||||
if (std::filesystem::exists(update_dir))
|
||||
{
|
||||
// Msi and exe files
|
||||
for (const auto& entry : std::filesystem::directory_iterator(update_dir))
|
||||
{
|
||||
auto entryPath = entry.path().wstring();
|
||||
std::transform(entryPath.begin(), entryPath.end(), entryPath.begin(), ::towlower);
|
||||
|
||||
if (entryPath.ends_with(L".msi") || entryPath.ends_with(L".exe"))
|
||||
{
|
||||
std::error_code err;
|
||||
std::filesystem::remove(entry, err);
|
||||
if (err.value())
|
||||
{
|
||||
Logger::warn("Failed to delete installer file {}. {}", entry.path().string(), err.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Log files
|
||||
auto rootPath{ PTSettingsHelper::get_root_save_folder_location() };
|
||||
auto currentVersion = left_trim<wchar_t>(get_product_version(), L"v");
|
||||
if (std::filesystem::exists(rootPath))
|
||||
{
|
||||
for (const auto& entry : std::filesystem::directory_iterator(rootPath))
|
||||
{
|
||||
auto entryPath = entry.path().wstring();
|
||||
std::transform(entryPath.begin(), entryPath.end(), entryPath.begin(), ::towlower);
|
||||
if (entry.is_regular_file() && entryPath.ends_with(L".log") && entryPath.find(currentVersion) == std::string::npos)
|
||||
{
|
||||
std::error_code err;
|
||||
std::filesystem::remove(entry, err);
|
||||
if (err.value())
|
||||
{
|
||||
Logger::warn("Failed to delete log file {}. {}", entry.path().string(), err.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ namespace updating
|
||||
std::future<std::optional<std::filesystem::path>> download_new_version(const new_version_download_info& new_version);
|
||||
std::filesystem::path get_pending_updates_path();
|
||||
std::future<nonstd::expected<github_version_info, std::wstring>> get_github_version_info_async(const bool prerelease = false);
|
||||
void cleanup_updates();
|
||||
|
||||
// non-localized
|
||||
constexpr inline std::wstring_view INSTALLER_FILENAME_PATTERN = L"powertoyssetup";
|
||||
|
@ -22,6 +22,7 @@ namespace powertoys_gpo {
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_ALWAYS_ON_TOP = L"ConfigureEnabledUtilityAlwaysOnTop";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_AWAKE = L"ConfigureEnabledUtilityAwake";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_COLOR_PICKER = L"ConfigureEnabledUtilityColorPicker";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_CROP_AND_LOCK = L"ConfigureEnabledUtilityCropAndLock";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_FANCYZONES = L"ConfigureEnabledUtilityFancyZones";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_FILE_LOCKSMITH = L"ConfigureEnabledUtilityFileLocksmith";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_SVG_PREVIEW = L"ConfigureEnabledUtilityFileExplorerSVGPreview";
|
||||
@ -129,6 +130,11 @@ namespace powertoys_gpo {
|
||||
return getConfiguredValue(POLICY_CONFIGURE_ENABLED_COLOR_PICKER);
|
||||
}
|
||||
|
||||
inline gpo_rule_configured_t getConfiguredCropAndLockEnabledValue()
|
||||
{
|
||||
return getConfiguredValue(POLICY_CONFIGURE_ENABLED_CROP_AND_LOCK);
|
||||
}
|
||||
|
||||
inline gpo_rule_configured_t getConfiguredFancyZonesEnabledValue()
|
||||
{
|
||||
return getConfiguredValue(POLICY_CONFIGURE_ENABLED_FANCYZONES);
|
||||
|
@ -54,3 +54,12 @@ inline void replace_chars(std::basic_string<CharT>& s,
|
||||
std::replace(begin(s), end(s), c, replacement_char);
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string unwide(const std::wstring& wide)
|
||||
{
|
||||
std::string result(wide.length(), 0);
|
||||
std::transform(begin(wide), end(wide), result.begin(), [](const wchar_t c) {
|
||||
return static_cast<char>(c);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
@ -1,17 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (c) Microsoft Corporation.
|
||||
Licensed under the MIT License. -->
|
||||
<policyDefinitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.2" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
|
||||
<policyDefinitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.3" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
|
||||
<policyNamespaces>
|
||||
<target prefix="powertoys" namespace="Microsoft.Policies.PowerToys" />
|
||||
</policyNamespaces>
|
||||
<resources minRequiredRevision="1.2"/><!-- Last changed with PowerToys v0.70.0 -->
|
||||
<resources minRequiredRevision="1.3"/><!-- Last changed with PowerToys v0.73.0 -->
|
||||
<supportedOn>
|
||||
<definitions>
|
||||
<definition name="SUPPORTED_POWERTOYS_0_64_0" displayName="$(string.SUPPORTED_POWERTOYS_0_64_0)"/>
|
||||
<definition name="SUPPORTED_POWERTOYS_0_68_0" displayName="$(string.SUPPORTED_POWERTOYS_0_68_0)"/>
|
||||
<definition name="SUPPORTED_POWERTOYS_0_69_0" displayName="$(string.SUPPORTED_POWERTOYS_0_69_0)"/>
|
||||
<definition name="SUPPORTED_POWERTOYS_0_70_0" displayName="$(string.SUPPORTED_POWERTOYS_0_70_0)"/>
|
||||
<definition name="SUPPORTED_POWERTOYS_0_73_0" displayName="$(string.SUPPORTED_POWERTOYS_0_73_0)"/>
|
||||
</definitions>
|
||||
</supportedOn>
|
||||
<categories>
|
||||
@ -51,6 +52,16 @@
|
||||
<decimal value="0" />
|
||||
</disabledValue>
|
||||
</policy>
|
||||
<policy name="ConfigureEnabledUtilityCropAndLock" class="Both" displayName="$(string.ConfigureEnabledUtilityCropAndLock)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityCropAndLock">
|
||||
<parentCategory ref="PowerToys" />
|
||||
<supportedOn ref="SUPPORTED_POWERTOYS_0_73_0" />
|
||||
<enabledValue>
|
||||
<decimal value="1" />
|
||||
</enabledValue>
|
||||
<disabledValue>
|
||||
<decimal value="0" />
|
||||
</disabledValue>
|
||||
</policy>
|
||||
<policy name="ConfigureEnabledUtilityFancyZones" class="Both" displayName="$(string.ConfigureEnabledUtilityFancyZones)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityFancyZones">
|
||||
<parentCategory ref="PowerToys" />
|
||||
<supportedOn ref="SUPPORTED_POWERTOYS_0_64_0" />
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (c) Microsoft Corporation.
|
||||
Licensed under the MIT License. -->
|
||||
<policyDefinitionResources xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.2" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
|
||||
<policyDefinitionResources xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.3" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
|
||||
<displayName>PowerToys</displayName>
|
||||
<description>PowerToys</description>
|
||||
<resources>
|
||||
@ -13,6 +13,7 @@
|
||||
<string id="SUPPORTED_POWERTOYS_0_68_0">PowerToys version 0.68.0 or later</string>
|
||||
<string id="SUPPORTED_POWERTOYS_0_69_0">PowerToys version 0.69.0 or later</string>
|
||||
<string id="SUPPORTED_POWERTOYS_0_70_0">PowerToys version 0.70.0 or later</string>
|
||||
<string id="SUPPORTED_POWERTOYS_0_73_0">PowerToys version 0.73.0 or later</string>
|
||||
|
||||
<string id="ConfigureEnabledUtilityDescription">This policy configures the enabled state for a PowerToys utility.
|
||||
|
||||
@ -67,6 +68,7 @@ If this setting is disabled, experimentation is not allowed.
|
||||
<string id="ConfigureEnabledUtilityAlwaysOnTop">Always On Top: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityAwake">Awake: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityColorPicker">Color Picker: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityCropAndLock">Crop And Lock: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityFancyZones">FancyZones: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityFileLocksmith">File Locksmith: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityFileExplorerSVGPreview">SVG file preview: Configure enabled state</string>
|
||||
|
56
src/modules/CropAndLock/CropAndLock/ChildWindow.cpp
Normal file
56
src/modules/CropAndLock/CropAndLock/ChildWindow.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
#include "pch.h"
|
||||
#include "ChildWindow.h"
|
||||
|
||||
namespace util
|
||||
{
|
||||
using namespace robmikh::common::desktop;
|
||||
using namespace robmikh::common::desktop::controls;
|
||||
}
|
||||
|
||||
const std::wstring ChildWindow::ClassName = L"CropAndLock.ChildWindow";
|
||||
std::once_flag ChildWindowClassRegistration;
|
||||
|
||||
void ChildWindow::RegisterWindowClass()
|
||||
{
|
||||
auto instance = winrt::check_pointer(GetModuleHandleW(nullptr));
|
||||
WNDCLASSEXW wcex = {};
|
||||
wcex.cbSize = sizeof(wcex);
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcex.lpfnWndProc = WndProc;
|
||||
wcex.hInstance = instance;
|
||||
wcex.hIcon = LoadIconW(instance, IDI_APPLICATION);
|
||||
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
|
||||
wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
|
||||
wcex.lpszClassName = ClassName.c_str();
|
||||
wcex.hIconSm = LoadIconW(wcex.hInstance, IDI_APPLICATION);
|
||||
winrt::check_bool(RegisterClassExW(&wcex));
|
||||
}
|
||||
|
||||
ChildWindow::ChildWindow(int width, int height, HWND parent)
|
||||
{
|
||||
auto instance = winrt::check_pointer(GetModuleHandleW(nullptr));
|
||||
|
||||
std::call_once(ChildWindowClassRegistration, []() { RegisterWindowClass(); });
|
||||
|
||||
auto exStyle = 0;
|
||||
auto style = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
|
||||
|
||||
winrt::check_bool(CreateWindowExW(exStyle, ClassName.c_str(), L"", style,
|
||||
0, 0, width, height, parent, nullptr, instance, this));
|
||||
WINRT_ASSERT(m_window);
|
||||
|
||||
ShowWindow(m_window, SW_SHOW);
|
||||
UpdateWindow(m_window);
|
||||
}
|
||||
|
||||
LRESULT ChildWindow::MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_DESTROY:
|
||||
break;
|
||||
default:
|
||||
return base_type::MessageHandler(message, wparam, lparam);
|
||||
}
|
||||
return 0;
|
||||
}
|
11
src/modules/CropAndLock/CropAndLock/ChildWindow.h
Normal file
11
src/modules/CropAndLock/CropAndLock/ChildWindow.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include <robmikh.common/DesktopWindow.h>
|
||||
|
||||
struct ChildWindow : robmikh::common::desktop::DesktopWindow<ChildWindow>
|
||||
{
|
||||
static const std::wstring ClassName;
|
||||
ChildWindow(int width, int height, HWND parent);
|
||||
LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam);
|
||||
private:
|
||||
static void RegisterWindowClass();
|
||||
};
|
105
src/modules/CropAndLock/CropAndLock/CropAndLock.rc
Normal file
105
src/modules/CropAndLock/CropAndLock/CropAndLock.rc
Normal file
@ -0,0 +1,105 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
#include "../../../common/version/version.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
1 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" // US English (0x0409), Unicode (0x04B0) charset
|
||||
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 // US English (0x0409), Unicode (1200) charset
|
||||
END
|
||||
END
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United States) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_ICON1 ICON "icon1.ico"
|
||||
|
||||
#endif // English (United States) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
170
src/modules/CropAndLock/CropAndLock/CropAndLock.vcxproj
Normal file
170
src/modules/CropAndLock/CropAndLock/CropAndLock.vcxproj
Normal file
@ -0,0 +1,170 @@
|
||||
<?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.220929.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<CppWinRTOptimized>true</CppWinRTOptimized>
|
||||
<CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge>
|
||||
<CppWinRTGenerateWindowsMetadata>true</CppWinRTGenerateWindowsMetadata>
|
||||
<MinimalCoreWin>true</MinimalCoreWin>
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{f5e1146e-b7b3-4e11-85fd-270a500bd78c}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>CropAndLock</RootNamespace>
|
||||
<WindowsTargetPlatformVersion Condition=" '$(WindowsTargetPlatformVersion)' == '' ">10.0.20348.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformMinVersion>10.0.19041.0</WindowsTargetPlatformMinVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|ARM64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|ARM64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)' == '17.0'">v143</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)' == '18.0'">v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<SpectreMitigation>Spectre</SpectreMitigation>
|
||||
</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>
|
||||
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_CONSOLE;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)src\common\Telemetry;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<AdditionalDependencies>shell32.lib;dwmapi.lib;DbgHelp.lib;gdi32.lib;Shcore.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">MultiThreadedDebug</RuntimeLibrary>
|
||||
<RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">MultiThreaded</RuntimeLibrary>
|
||||
<RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<None Include="PropertySheet.props" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ChildWindow.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="ReparentCropAndLockWindow.cpp" />
|
||||
<ClCompile Include="ThumbnailCropAndLockWindow.cpp" />
|
||||
<ClCompile Include="OverlayWindow.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ChildWindow.h" />
|
||||
<ClInclude Include="CropAndLockWindow.h" />
|
||||
<ClInclude Include="DisplaysUtil.h" />
|
||||
<ClInclude Include="ModuleConstants.h" />
|
||||
<ClInclude Include="ReparentCropAndLockWindow.h" />
|
||||
<ClInclude Include="ThumbnailCropAndLockWindow.h" />
|
||||
<ClInclude Include="SettingsWindow.h" />
|
||||
<ClInclude Include="OverlayWindow.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="ThumbnailUtil.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="WindowRectUtil.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="CropAndLock.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="icon1.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="app.manifest" />
|
||||
</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>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
<Import Project="..\..\..\..\packages\robmikh.common.0.0.22-beta\build\native\robmikh.common.targets" Condition="Exists('..\..\..\..\packages\robmikh.common.0.0.22-beta\build\native\robmikh.common.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.220929.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\robmikh.common.0.0.22-beta\build\native\robmikh.common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\robmikh.common.0.0.22-beta\build\native\robmikh.common.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<None Include="PropertySheet.props" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="pch.cpp" />
|
||||
<ClCompile Include="ThumbnailCropAndLockWindow.cpp" />
|
||||
<ClCompile Include="OverlayWindow.cpp" />
|
||||
<ClCompile Include="ReparentCropAndLockWindow.cpp" />
|
||||
<ClCompile Include="ChildWindow.cpp" />
|
||||
<ClCompile Include="trace.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="ThumbnailCropAndLockWindow.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="SettingsWindow.h" />
|
||||
<ClInclude Include="OverlayWindow.h" />
|
||||
<ClInclude Include="DisplaysUtil.h" />
|
||||
<ClInclude Include="ThumbnailUtil.h" />
|
||||
<ClInclude Include="WindowRectUtil.h" />
|
||||
<ClInclude Include="CropAndLockWindow.h" />
|
||||
<ClInclude Include="ReparentCropAndLockWindow.h" />
|
||||
<ClInclude Include="ChildWindow.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="ModuleConstants.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="CropAndLock.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="icon1.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="app.manifest" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
|
||||
</ItemGroup>
|
||||
</Project>
|
10
src/modules/CropAndLock/CropAndLock/CropAndLockWindow.h
Normal file
10
src/modules/CropAndLock/CropAndLock/CropAndLockWindow.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
struct CropAndLockWindow
|
||||
{
|
||||
virtual ~CropAndLockWindow() {}
|
||||
|
||||
virtual HWND Handle() = 0;
|
||||
virtual void CropAndLock(HWND windowToCrop, RECT cropRect) = 0;
|
||||
virtual void OnClosed(std::function<void(HWND)> callback) = 0;
|
||||
};
|
25
src/modules/CropAndLock/CropAndLock/DisplaysUtil.h
Normal file
25
src/modules/CropAndLock/CropAndLock/DisplaysUtil.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
inline RECT ComputeAllDisplaysUnion(std::vector<robmikh::common::desktop::DisplayInfo> const& infos)
|
||||
{
|
||||
RECT result = {};
|
||||
result.left = LONG_MAX;
|
||||
result.top = LONG_MAX;
|
||||
result.right = LONG_MIN;
|
||||
result.bottom = LONG_MIN;
|
||||
for (auto&& info : infos)
|
||||
{
|
||||
auto rect = info.Rect();
|
||||
result.left = std::min(result.left, rect.left);
|
||||
result.top = std::min(result.top, rect.top);
|
||||
result.right = std::max(result.right, rect.right);
|
||||
result.bottom = std::max(result.bottom, rect.bottom);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline RECT ComputeAllDisplaysUnion()
|
||||
{
|
||||
auto infos = robmikh::common::desktop::DisplayInfo::GetAllDisplays();
|
||||
return ComputeAllDisplaysUnion(infos);
|
||||
}
|
6
src/modules/CropAndLock/CropAndLock/ModuleConstants.h
Normal file
6
src/modules/CropAndLock/CropAndLock/ModuleConstants.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace NonLocalizable
|
||||
{
|
||||
const inline wchar_t ModuleKey[] = L"CropAndLock";
|
||||
}
|
356
src/modules/CropAndLock/CropAndLock/OverlayWindow.cpp
Normal file
356
src/modules/CropAndLock/CropAndLock/OverlayWindow.cpp
Normal file
@ -0,0 +1,356 @@
|
||||
#include "pch.h"
|
||||
#include "OverlayWindow.h"
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
using namespace Windows::UI;
|
||||
using namespace Windows::UI::Composition;
|
||||
}
|
||||
|
||||
namespace util
|
||||
{
|
||||
using namespace robmikh::common::desktop;
|
||||
}
|
||||
|
||||
const std::wstring OverlayWindow::ClassName = L"CropAndLock.OverlayWindow";
|
||||
const float OverlayWindow::BorderThickness = 5;
|
||||
std::once_flag OverlayWindowClassRegistration;
|
||||
|
||||
bool IsPointWithinRect(POINT const& point, RECT const& rect)
|
||||
{
|
||||
return point.x >= rect.left && point.x <= rect.right && point.y >= rect.top && point.y <= rect.bottom;
|
||||
}
|
||||
|
||||
void OverlayWindow::RegisterWindowClass()
|
||||
{
|
||||
auto instance = winrt::check_pointer(GetModuleHandleW(nullptr));
|
||||
WNDCLASSEXW wcex = {};
|
||||
wcex.cbSize = sizeof(wcex);
|
||||
wcex.lpfnWndProc = WndProc;
|
||||
wcex.hInstance = instance;
|
||||
wcex.hIcon = LoadIconW(instance, IDI_APPLICATION);
|
||||
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
|
||||
wcex.lpszClassName = ClassName.c_str();
|
||||
wcex.hIconSm = LoadIconW(instance, IDI_APPLICATION);
|
||||
winrt::check_bool(RegisterClassExW(&wcex));
|
||||
}
|
||||
|
||||
OverlayWindow::OverlayWindow(
|
||||
winrt::Compositor const& compositor,
|
||||
HWND windowToCrop,
|
||||
std::function<void(HWND, RECT)> windowCropped)
|
||||
{
|
||||
auto instance = winrt::check_pointer(GetModuleHandleW(nullptr));
|
||||
|
||||
std::call_once(OverlayWindowClassRegistration, []() { RegisterWindowClass(); });
|
||||
|
||||
auto exStyle = WS_EX_NOREDIRECTIONBITMAP | WS_EX_TOOLWINDOW | WS_EX_LAYERED | WS_EX_TOPMOST;
|
||||
auto style = WS_POPUP;
|
||||
|
||||
// Get the union of all displays
|
||||
auto displaysRect = ComputeAllDisplaysUnion();
|
||||
|
||||
// Create our window
|
||||
winrt::check_bool(CreateWindowExW(exStyle, ClassName.c_str(), L"", style,
|
||||
displaysRect.left, displaysRect.top, displaysRect.right - displaysRect.left, displaysRect.bottom - displaysRect.top, nullptr, nullptr, instance, this));
|
||||
WINRT_ASSERT(m_window);
|
||||
|
||||
// Load cursors
|
||||
m_standardCursor.reset(winrt::check_pointer(LoadCursorW(nullptr, IDC_ARROW)));
|
||||
m_crosshairCursor.reset(winrt::check_pointer(LoadCursorW(nullptr, IDC_CROSS)));
|
||||
m_cursorType = CursorType::Standard;
|
||||
|
||||
// Setup the visual tree
|
||||
m_compositor = compositor;
|
||||
m_target = CreateWindowTarget(m_compositor);
|
||||
m_rootVisual = m_compositor.CreateContainerVisual();
|
||||
m_shadeVisual = m_compositor.CreateSpriteVisual();
|
||||
m_windowAreaVisual = m_compositor.CreateContainerVisual();
|
||||
m_selectionVisual = m_compositor.CreateSpriteVisual();
|
||||
|
||||
m_target.Root(m_rootVisual);
|
||||
auto children = m_rootVisual.Children();
|
||||
children.InsertAtBottom(m_shadeVisual);
|
||||
children.InsertAtTop(m_windowAreaVisual);
|
||||
m_windowAreaVisual.Children().InsertAtTop(m_selectionVisual);
|
||||
|
||||
m_rootVisual.RelativeSizeAdjustment({ 1, 1 });
|
||||
m_shadeBrush = m_compositor.CreateNineGridBrush();
|
||||
m_shadeBrush.IsCenterHollow(true);
|
||||
m_shadeBrush.Source(m_compositor.CreateColorBrush(winrt::Color{ 255, 0, 0, 0 }));
|
||||
m_shadeVisual.Brush(m_shadeBrush);
|
||||
m_shadeVisual.Opacity(0.6f);
|
||||
m_shadeVisual.RelativeSizeAdjustment({ 1, 1 });
|
||||
auto selectionBrush = m_compositor.CreateNineGridBrush();
|
||||
selectionBrush.SetInsets(BorderThickness);
|
||||
selectionBrush.IsCenterHollow(true);
|
||||
selectionBrush.Source(m_compositor.CreateColorBrush(winrt::Color{ 255, 255, 0, 0 }));
|
||||
m_selectionVisual.Brush(selectionBrush);
|
||||
|
||||
WINRT_VERIFY(windowToCrop != nullptr);
|
||||
m_currentWindow = windowToCrop;
|
||||
SetupOverlay();
|
||||
m_windowCropped = windowCropped;
|
||||
|
||||
ShowWindow(m_window, SW_SHOW);
|
||||
UpdateWindow(m_window);
|
||||
SetForegroundWindow(m_window);
|
||||
}
|
||||
|
||||
void OverlayWindow::SetupOverlay()
|
||||
{
|
||||
ResetCrop();
|
||||
|
||||
// Get the client bounds of the target window
|
||||
auto windowBounds = ClientAreaInScreenSpace(m_currentWindow);
|
||||
|
||||
// Get the union of all displays
|
||||
auto displaysRect = ComputeAllDisplaysUnion();
|
||||
|
||||
// Before we can use the window bounds, we need to
|
||||
// shift the origin to the top-left most point.
|
||||
m_currentWindowAreaBounds.left = windowBounds.left - displaysRect.left;
|
||||
m_currentWindowAreaBounds.top = windowBounds.top - displaysRect.top;
|
||||
m_currentWindowAreaBounds.right = m_currentWindowAreaBounds.left + (windowBounds.right - windowBounds.left);
|
||||
m_currentWindowAreaBounds.bottom = m_currentWindowAreaBounds.top + (windowBounds.bottom - windowBounds.top);
|
||||
|
||||
auto windowLeft = static_cast<float>(m_currentWindowAreaBounds.left);
|
||||
auto windowTop = static_cast<float>(m_currentWindowAreaBounds.top);
|
||||
auto windowWidth = static_cast<float>(windowBounds.right - windowBounds.left);
|
||||
auto windowHeight = static_cast<float>(windowBounds.bottom - windowBounds.top);
|
||||
|
||||
// Change the shade brush to match the window bounds
|
||||
// We need to make sure the values are non-negative, as they are invalid insets. We
|
||||
// can sometimes get negative values for the left and top when windows are maximized.
|
||||
m_shadeBrush.LeftInset(std::max(windowLeft, 0.0f));
|
||||
m_shadeBrush.TopInset(std::max(windowTop, 0.0f));
|
||||
m_shadeBrush.RightInset(std::max(static_cast<float>(displaysRect.right - windowBounds.right), 0.0f));
|
||||
m_shadeBrush.BottomInset(std::max(static_cast<float>(displaysRect.bottom - windowBounds.bottom), 0.0f));
|
||||
|
||||
// Change the window area visual to match the window bounds
|
||||
m_windowAreaVisual.Offset({ windowLeft, windowTop, 0 });
|
||||
m_windowAreaVisual.Size({ windowWidth, windowHeight });
|
||||
|
||||
// Reset the selection visual
|
||||
m_selectionVisual.Offset({ 0, 0, 0 });
|
||||
m_selectionVisual.Size({ 0, 0 });
|
||||
}
|
||||
|
||||
LRESULT OverlayWindow::MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_DESTROY:
|
||||
break;
|
||||
case WM_SETCURSOR:
|
||||
return OnSetCursor();
|
||||
case WM_KEYUP:
|
||||
{
|
||||
auto key = static_cast<uint32_t>(wparam);
|
||||
if (key == VK_ESCAPE)
|
||||
{
|
||||
DestroyWindow(m_window);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_LBUTTONDOWN:
|
||||
{
|
||||
auto xPos = GET_X_LPARAM(lparam);
|
||||
auto yPos = GET_Y_LPARAM(lparam);
|
||||
OnLeftButtonDown(xPos, yPos);
|
||||
}
|
||||
break;
|
||||
case WM_LBUTTONUP:
|
||||
{
|
||||
auto xPos = GET_X_LPARAM(lparam);
|
||||
auto yPos = GET_Y_LPARAM(lparam);
|
||||
OnLeftButtonUp(xPos, yPos);
|
||||
}
|
||||
break;
|
||||
case WM_MOUSEMOVE:
|
||||
{
|
||||
auto xPos = GET_X_LPARAM(lparam);
|
||||
auto yPos = GET_Y_LPARAM(lparam);
|
||||
OnMouseMove(xPos, yPos);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return base_type::MessageHandler(message, wparam, lparam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OverlayWindow::ResetCrop()
|
||||
{
|
||||
m_cropStatus = CropStatus::None;
|
||||
m_startPosition = {};
|
||||
m_cropRect = {};
|
||||
}
|
||||
|
||||
bool OverlayWindow::OnSetCursor()
|
||||
{
|
||||
switch (m_cursorType)
|
||||
{
|
||||
case CursorType::Standard:
|
||||
SetCursor(m_standardCursor.get());
|
||||
return true;
|
||||
case CursorType::Crosshair:
|
||||
SetCursor(m_crosshairCursor.get());
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void OverlayWindow::OnLeftButtonDown(int x, int y)
|
||||
{
|
||||
if (m_cropStatus == CropStatus::None)
|
||||
{
|
||||
if (!IsPointWithinRect({ x, y }, m_currentWindowAreaBounds))
|
||||
{
|
||||
DestroyWindow(m_window);
|
||||
return;
|
||||
}
|
||||
|
||||
m_cropStatus = CropStatus::Ongoing;
|
||||
|
||||
x -= m_currentWindowAreaBounds.left;
|
||||
y -= m_currentWindowAreaBounds.top;
|
||||
|
||||
m_selectionVisual.Offset({ x - BorderThickness, y - BorderThickness, 0 });
|
||||
m_startPosition = { x, y };
|
||||
}
|
||||
}
|
||||
|
||||
void OverlayWindow::OnLeftButtonUp(int x, int y)
|
||||
{
|
||||
if (m_cropStatus == CropStatus::Ongoing)
|
||||
{
|
||||
m_cropStatus = CropStatus::Completed;
|
||||
m_cursorType = CursorType::Standard;
|
||||
|
||||
// For debugging, it's easier if the window doesn't block the screen after this point
|
||||
ShowWindow(m_window, SW_HIDE);
|
||||
|
||||
if (x < m_currentWindowAreaBounds.left)
|
||||
{
|
||||
x = m_currentWindowAreaBounds.left;
|
||||
}
|
||||
else if (x > m_currentWindowAreaBounds.right)
|
||||
{
|
||||
x = m_currentWindowAreaBounds.right;
|
||||
}
|
||||
|
||||
if (y < m_currentWindowAreaBounds.top)
|
||||
{
|
||||
y = m_currentWindowAreaBounds.top;
|
||||
}
|
||||
else if (y > m_currentWindowAreaBounds.bottom)
|
||||
{
|
||||
y = m_currentWindowAreaBounds.bottom;
|
||||
}
|
||||
|
||||
x -= m_currentWindowAreaBounds.left;
|
||||
y -= m_currentWindowAreaBounds.top;
|
||||
|
||||
// Compute our crop rect
|
||||
if (x < m_startPosition.x)
|
||||
{
|
||||
m_cropRect.left = x;
|
||||
m_cropRect.right = m_startPosition.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cropRect.left = m_startPosition.x;
|
||||
m_cropRect.right = x;
|
||||
}
|
||||
if (y < m_startPosition.y)
|
||||
{
|
||||
m_cropRect.top = y;
|
||||
m_cropRect.bottom = m_startPosition.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cropRect.top = m_startPosition.y;
|
||||
m_cropRect.bottom = y;
|
||||
}
|
||||
|
||||
// Exit if the rect is empty
|
||||
if (m_cropRect.right - m_cropRect.left == 0 || m_cropRect.bottom - m_cropRect.top == 0)
|
||||
{
|
||||
DestroyWindow(m_window);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fire the callback
|
||||
if (m_windowCropped != nullptr)
|
||||
{
|
||||
m_windowCropped(m_currentWindow, m_cropRect);
|
||||
}
|
||||
DestroyWindow(m_window);
|
||||
}
|
||||
}
|
||||
|
||||
void OverlayWindow::OnMouseMove(int x, int y)
|
||||
{
|
||||
if (m_cropStatus == CropStatus::None)
|
||||
{
|
||||
if (IsPointWithinRect({ x, y }, m_currentWindowAreaBounds))
|
||||
{
|
||||
m_cursorType = CursorType::Crosshair;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cursorType = CursorType::Standard;
|
||||
}
|
||||
}
|
||||
else if (m_cropStatus == CropStatus::Ongoing)
|
||||
{
|
||||
if (x < m_currentWindowAreaBounds.left)
|
||||
{
|
||||
x = m_currentWindowAreaBounds.left;
|
||||
}
|
||||
else if (x > m_currentWindowAreaBounds.right)
|
||||
{
|
||||
x = m_currentWindowAreaBounds.right;
|
||||
}
|
||||
|
||||
if (y < m_currentWindowAreaBounds.top)
|
||||
{
|
||||
y = m_currentWindowAreaBounds.top;
|
||||
}
|
||||
else if (y > m_currentWindowAreaBounds.bottom)
|
||||
{
|
||||
y = m_currentWindowAreaBounds.bottom;
|
||||
}
|
||||
|
||||
x -= m_currentWindowAreaBounds.left;
|
||||
y -= m_currentWindowAreaBounds.top;
|
||||
|
||||
auto offset = m_selectionVisual.Offset();
|
||||
auto size = m_selectionVisual.Size();
|
||||
|
||||
if (x < m_startPosition.x)
|
||||
{
|
||||
offset.x = x - BorderThickness;
|
||||
size.x = (m_startPosition.x - x) + (2 * BorderThickness);
|
||||
}
|
||||
else
|
||||
{
|
||||
size.x = (x - m_startPosition.x) + (2 * BorderThickness);
|
||||
}
|
||||
|
||||
if (y < m_startPosition.y)
|
||||
{
|
||||
offset.y = y - BorderThickness;
|
||||
size.y = (m_startPosition.y - y) + (2 * BorderThickness);
|
||||
}
|
||||
else
|
||||
{
|
||||
size.y = (y - m_startPosition.y) + (2 * BorderThickness);
|
||||
}
|
||||
|
||||
m_selectionVisual.Offset(offset);
|
||||
m_selectionVisual.Size(size);
|
||||
}
|
||||
}
|
58
src/modules/CropAndLock/CropAndLock/OverlayWindow.h
Normal file
58
src/modules/CropAndLock/CropAndLock/OverlayWindow.h
Normal file
@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
#include <robmikh.common/DesktopWindow.h>
|
||||
|
||||
struct OverlayWindow : robmikh::common::desktop::DesktopWindow<OverlayWindow>
|
||||
{
|
||||
static const std::wstring ClassName;
|
||||
OverlayWindow(
|
||||
winrt::Windows::UI::Composition::Compositor const& compositor,
|
||||
HWND windowToCrop,
|
||||
std::function<void(HWND, RECT)> windowCropped);
|
||||
~OverlayWindow() { m_windowCropped = nullptr; DestroyWindow(m_window); }
|
||||
LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam);
|
||||
|
||||
private:
|
||||
enum class CursorType
|
||||
{
|
||||
Standard,
|
||||
Crosshair,
|
||||
};
|
||||
|
||||
enum class CropStatus
|
||||
{
|
||||
None,
|
||||
Ongoing,
|
||||
Completed,
|
||||
};
|
||||
|
||||
static const float BorderThickness;
|
||||
static void RegisterWindowClass();
|
||||
|
||||
void SetupOverlay();
|
||||
void ResetCrop();
|
||||
bool OnSetCursor();
|
||||
void OnLeftButtonDown(int x, int y);
|
||||
void OnLeftButtonUp(int x, int y);
|
||||
void OnMouseMove(int x, int y);
|
||||
|
||||
private:
|
||||
std::function<void(HWND, RECT)> m_windowCropped;
|
||||
winrt::Windows::UI::Composition::Compositor m_compositor{ nullptr };
|
||||
winrt::Windows::UI::Composition::CompositionTarget m_target{ nullptr };
|
||||
winrt::Windows::UI::Composition::ContainerVisual m_rootVisual{ nullptr };
|
||||
winrt::Windows::UI::Composition::SpriteVisual m_shadeVisual{ nullptr };
|
||||
winrt::Windows::UI::Composition::ContainerVisual m_windowAreaVisual{ nullptr };
|
||||
winrt::Windows::UI::Composition::SpriteVisual m_selectionVisual{ nullptr };
|
||||
winrt::Windows::UI::Composition::CompositionNineGridBrush m_shadeBrush{ nullptr };
|
||||
|
||||
HWND m_currentWindow = nullptr;
|
||||
RECT m_currentWindowAreaBounds = {};
|
||||
|
||||
CropStatus m_cropStatus = CropStatus::None;
|
||||
POINT m_startPosition = {};
|
||||
RECT m_cropRect = {};
|
||||
|
||||
CursorType m_cursorType = CursorType::Standard;
|
||||
wil::unique_hcursor m_standardCursor;
|
||||
wil::unique_hcursor m_crosshairCursor;
|
||||
};
|
16
src/modules/CropAndLock/CropAndLock/PropertySheet.props
Normal file
16
src/modules/CropAndLock/CropAndLock/PropertySheet.props
Normal 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>
|
@ -0,0 +1,160 @@
|
||||
#include "pch.h"
|
||||
#include "ReparentCropAndLockWindow.h"
|
||||
|
||||
const std::wstring ReparentCropAndLockWindow::ClassName = L"CropAndLock.ReparentCropAndLockWindow";
|
||||
std::once_flag ReparentCropAndLockWindowClassRegistration;
|
||||
|
||||
void ReparentCropAndLockWindow::RegisterWindowClass()
|
||||
{
|
||||
auto instance = winrt::check_pointer(GetModuleHandleW(nullptr));
|
||||
WNDCLASSEXW wcex = {};
|
||||
wcex.cbSize = sizeof(wcex);
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcex.lpfnWndProc = WndProc;
|
||||
wcex.hInstance = instance;
|
||||
wcex.hIcon = LoadIconW(instance, IDI_APPLICATION);
|
||||
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
|
||||
wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
|
||||
wcex.lpszClassName = ClassName.c_str();
|
||||
wcex.hIconSm = LoadIconW(wcex.hInstance, IDI_APPLICATION);
|
||||
winrt::check_bool(RegisterClassExW(&wcex));
|
||||
}
|
||||
|
||||
ReparentCropAndLockWindow::ReparentCropAndLockWindow(std::wstring const& titleString, int width, int height)
|
||||
{
|
||||
auto instance = winrt::check_pointer(GetModuleHandleW(nullptr));
|
||||
|
||||
std::call_once(ReparentCropAndLockWindowClassRegistration, []() { RegisterWindowClass(); });
|
||||
|
||||
auto exStyle = 0;
|
||||
auto style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
|
||||
style &= ~(WS_MAXIMIZEBOX | WS_THICKFRAME);
|
||||
|
||||
RECT rect = { 0, 0, width, height};
|
||||
winrt::check_bool(AdjustWindowRectEx(&rect, style, false, exStyle));
|
||||
auto adjustedWidth = rect.right - rect.left;
|
||||
auto adjustedHeight = rect.bottom - rect.top;
|
||||
|
||||
winrt::check_bool(CreateWindowExW(exStyle, ClassName.c_str(), titleString.c_str(), style,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, adjustedWidth, adjustedHeight, nullptr, nullptr, instance, this));
|
||||
WINRT_ASSERT(m_window);
|
||||
|
||||
m_childWindow = std::make_unique<ChildWindow>(width, height, m_window);
|
||||
}
|
||||
|
||||
ReparentCropAndLockWindow::~ReparentCropAndLockWindow()
|
||||
{
|
||||
DisconnectTarget();
|
||||
DestroyWindow(m_window);
|
||||
}
|
||||
|
||||
LRESULT ReparentCropAndLockWindow::MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_DESTROY:
|
||||
if (m_closedCallback != nullptr && !m_destroyed)
|
||||
{
|
||||
m_destroyed = true;
|
||||
m_closedCallback(m_window);
|
||||
}
|
||||
break;
|
||||
case WM_MOUSEACTIVATE:
|
||||
if (m_currentTarget != nullptr && GetForegroundWindow() != m_currentTarget)
|
||||
{
|
||||
SetForegroundWindow(m_currentTarget);
|
||||
}
|
||||
return MA_NOACTIVATE;
|
||||
case WM_ACTIVATE:
|
||||
if (static_cast<DWORD>(wparam) == WA_ACTIVE)
|
||||
{
|
||||
if (m_currentTarget != nullptr)
|
||||
{
|
||||
SetForegroundWindow(m_currentTarget);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_DPICHANGED:
|
||||
break;
|
||||
default:
|
||||
return base_type::MessageHandler(message, wparam, lparam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ReparentCropAndLockWindow::CropAndLock(HWND windowToCrop, RECT cropRect)
|
||||
{
|
||||
DisconnectTarget();
|
||||
m_currentTarget = windowToCrop;
|
||||
|
||||
// Adjust the crop rect to be in the window space as reported by win32k
|
||||
RECT windowRect = {};
|
||||
winrt::check_bool(GetWindowRect(m_currentTarget, &windowRect));
|
||||
auto clientRect = ClientAreaInScreenSpace(m_currentTarget);
|
||||
auto diffX = clientRect.left - windowRect.left;
|
||||
auto diffY = clientRect.top - windowRect.top;
|
||||
auto adjustedCropRect = cropRect;
|
||||
adjustedCropRect.left += diffX;
|
||||
adjustedCropRect.top += diffY;
|
||||
adjustedCropRect.right += diffX;
|
||||
adjustedCropRect.bottom += diffY;
|
||||
cropRect = adjustedCropRect;
|
||||
|
||||
// Save the previous position of the target so that we can restore it.
|
||||
m_previousPosition = { windowRect.left, windowRect.top };
|
||||
auto newX = adjustedCropRect.left + windowRect.left;
|
||||
auto newY = adjustedCropRect.top + windowRect.top;
|
||||
|
||||
auto monitor = winrt::check_pointer(MonitorFromWindow(m_currentTarget, MONITOR_DEFAULTTONULL));
|
||||
uint32_t dpiX = 0;
|
||||
uint32_t dpiY = 0;
|
||||
winrt::check_hresult(GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY));
|
||||
uint32_t dpi = dpiX > dpiY ? dpiX : dpiY;
|
||||
|
||||
// Reconfigure our window
|
||||
auto width = cropRect.right - cropRect.left;
|
||||
auto height = cropRect.bottom - cropRect.top;
|
||||
windowRect = { newX, newY, newX + width, newY + height };
|
||||
auto exStyle = static_cast<DWORD>(GetWindowLongPtrW(m_window, GWL_EXSTYLE));
|
||||
auto style = static_cast<DWORD>(GetWindowLongPtrW(m_window, GWL_STYLE));
|
||||
winrt::check_bool(AdjustWindowRectExForDpi(&windowRect, style, false, exStyle, dpi));
|
||||
auto adjustedWidth = windowRect.right - windowRect.left;
|
||||
auto adjustedHeight = windowRect.bottom - windowRect.top;
|
||||
|
||||
winrt::check_bool(SetWindowPos(m_window, HWND_TOPMOST, windowRect.left, windowRect.top, adjustedWidth, adjustedHeight, SWP_SHOWWINDOW | SWP_NOACTIVATE));
|
||||
winrt::check_bool(SetWindowPos(m_childWindow->m_window, nullptr, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE));
|
||||
|
||||
// Reparent the target window
|
||||
SetParent(m_currentTarget, m_childWindow->m_window);
|
||||
auto targetStyle = GetWindowLongPtrW(m_currentTarget, GWL_STYLE);
|
||||
targetStyle |= WS_CHILD;
|
||||
SetWindowLongPtrW(m_currentTarget, GWL_STYLE, targetStyle);
|
||||
auto x = -cropRect.left;
|
||||
auto y = -cropRect.top;
|
||||
winrt::check_bool(SetWindowPos(m_currentTarget, nullptr, x, y, 0, 0, SWP_NOSIZE | SWP_FRAMECHANGED | SWP_NOZORDER));
|
||||
}
|
||||
|
||||
void ReparentCropAndLockWindow::Hide()
|
||||
{
|
||||
DisconnectTarget();
|
||||
ShowWindow(m_window, SW_HIDE);
|
||||
}
|
||||
|
||||
void ReparentCropAndLockWindow::DisconnectTarget()
|
||||
{
|
||||
if (m_currentTarget != nullptr)
|
||||
{
|
||||
if (!IsWindow(m_currentTarget))
|
||||
{
|
||||
// The child window was closed by other means?
|
||||
m_currentTarget = nullptr;
|
||||
return;
|
||||
}
|
||||
winrt::check_bool(SetWindowPos(m_currentTarget, nullptr, m_previousPosition.x, m_previousPosition.y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_FRAMECHANGED));
|
||||
SetParent(m_currentTarget, nullptr);
|
||||
auto targetStyle = static_cast<DWORD>(GetWindowLongPtrW(m_currentTarget, GWL_STYLE));
|
||||
targetStyle &= ~WS_CHILD;
|
||||
SetWindowLongPtrW(m_currentTarget, GWL_STYLE, targetStyle);
|
||||
m_currentTarget = nullptr;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
#include <robmikh.common/DesktopWindow.h>
|
||||
#include "CropAndLockWindow.h"
|
||||
#include "ChildWindow.h"
|
||||
|
||||
struct ReparentCropAndLockWindow : robmikh::common::desktop::DesktopWindow<ReparentCropAndLockWindow>, CropAndLockWindow
|
||||
{
|
||||
static const std::wstring ClassName;
|
||||
ReparentCropAndLockWindow(std::wstring const& titleString, int width, int height);
|
||||
~ReparentCropAndLockWindow() override;
|
||||
LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam);
|
||||
|
||||
HWND Handle() override { return m_window; }
|
||||
void CropAndLock(HWND windowToCrop, RECT cropRect) override;
|
||||
void OnClosed(std::function<void(HWND)> callback) override { m_closedCallback = callback; }
|
||||
|
||||
private:
|
||||
static void RegisterWindowClass();
|
||||
|
||||
void Hide();
|
||||
void DisconnectTarget();
|
||||
|
||||
private:
|
||||
HWND m_currentTarget = nullptr;
|
||||
POINT m_previousPosition = {};
|
||||
std::unique_ptr<ChildWindow> m_childWindow;
|
||||
bool m_destroyed = false;
|
||||
std::function<void(HWND)> m_closedCallback;
|
||||
};
|
7
src/modules/CropAndLock/CropAndLock/SettingsWindow.h
Normal file
7
src/modules/CropAndLock/CropAndLock/SettingsWindow.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
enum class CropAndLockType
|
||||
{
|
||||
Reparent,
|
||||
Thumbnail,
|
||||
};
|
@ -0,0 +1,181 @@
|
||||
#include "pch.h"
|
||||
#include "ThumbnailCropAndLockWindow.h"
|
||||
|
||||
const std::wstring ThumbnailCropAndLockWindow::ClassName = L"CropAndLock.ThumbnailCropAndLockWindow";
|
||||
std::once_flag ThumbnailCropAndLockWindowClassRegistration;
|
||||
|
||||
float ComputeScaleFactor(RECT const& windowRect, RECT const& contentRect)
|
||||
{
|
||||
auto windowWidth = static_cast<float>(windowRect.right - windowRect.left);
|
||||
auto windowHeight = static_cast<float>(windowRect.bottom - windowRect.top);
|
||||
auto contentWidth = static_cast<float>(contentRect.right - contentRect.left);
|
||||
auto contentHeight = static_cast<float>(contentRect.bottom - contentRect.top);
|
||||
|
||||
auto windowRatio = windowWidth / windowHeight;
|
||||
auto contentRatio = contentWidth / contentHeight;
|
||||
|
||||
auto scaleFactor = windowWidth / contentWidth;
|
||||
if (windowRatio > contentRatio)
|
||||
{
|
||||
scaleFactor = windowHeight / contentHeight;
|
||||
}
|
||||
|
||||
return scaleFactor;
|
||||
}
|
||||
|
||||
RECT ComputeDestRect(RECT const& windowRect, RECT const& contentRect)
|
||||
{
|
||||
auto scaleFactor = ComputeScaleFactor(windowRect, contentRect);
|
||||
|
||||
auto windowWidth = static_cast<float>(windowRect.right - windowRect.left);
|
||||
auto windowHeight = static_cast<float>(windowRect.bottom - windowRect.top);
|
||||
auto contentWidth = static_cast<float>(contentRect.right - contentRect.left) * scaleFactor;
|
||||
auto contentHeight = static_cast<float>(contentRect.bottom - contentRect.top) * scaleFactor;
|
||||
|
||||
auto remainingWidth = windowWidth - contentWidth;
|
||||
auto remainingHeight = windowHeight - contentHeight;
|
||||
|
||||
auto left = static_cast<LONG>(remainingWidth / 2.0f);
|
||||
auto top = static_cast<LONG>(remainingHeight / 2.0f);
|
||||
auto right = left + static_cast<LONG>(contentWidth);
|
||||
auto bottom = top + static_cast<LONG>(contentHeight);
|
||||
|
||||
return RECT{ left, top, right, bottom };
|
||||
}
|
||||
|
||||
void ThumbnailCropAndLockWindow::RegisterWindowClass()
|
||||
{
|
||||
auto instance = winrt::check_pointer(GetModuleHandleW(nullptr));
|
||||
WNDCLASSEXW wcex = {};
|
||||
wcex.cbSize = sizeof(wcex);
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcex.lpfnWndProc = WndProc;
|
||||
wcex.hInstance = instance;
|
||||
wcex.hIcon = LoadIconW(instance, IDI_APPLICATION);
|
||||
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
|
||||
wcex.hbrBackground = static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH));
|
||||
wcex.lpszClassName = ClassName.c_str();
|
||||
wcex.hIconSm = LoadIconW(wcex.hInstance, IDI_APPLICATION);
|
||||
winrt::check_bool(RegisterClassExW(&wcex));
|
||||
}
|
||||
|
||||
ThumbnailCropAndLockWindow::ThumbnailCropAndLockWindow(std::wstring const& titleString, int width, int height)
|
||||
{
|
||||
auto instance = winrt::check_pointer(GetModuleHandleW(nullptr));
|
||||
|
||||
std::call_once(ThumbnailCropAndLockWindowClassRegistration, []() { RegisterWindowClass(); });
|
||||
|
||||
auto exStyle = 0;
|
||||
auto style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
|
||||
|
||||
RECT rect = { 0, 0, width, height};
|
||||
winrt::check_bool(AdjustWindowRectEx(&rect, style, false, exStyle));
|
||||
auto adjustedWidth = rect.right - rect.left;
|
||||
auto adjustedHeight = rect.bottom - rect.top;
|
||||
|
||||
winrt::check_bool(CreateWindowExW(exStyle, ClassName.c_str(), titleString.c_str(), style,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, adjustedWidth, adjustedHeight, nullptr, nullptr, instance, this));
|
||||
WINRT_ASSERT(m_window);
|
||||
}
|
||||
|
||||
ThumbnailCropAndLockWindow::~ThumbnailCropAndLockWindow()
|
||||
{
|
||||
DisconnectTarget();
|
||||
DestroyWindow(m_window);
|
||||
}
|
||||
|
||||
LRESULT ThumbnailCropAndLockWindow::MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_DESTROY:
|
||||
if (m_closedCallback != nullptr && !m_destroyed)
|
||||
{
|
||||
m_destroyed = true;
|
||||
m_closedCallback(m_window);
|
||||
}
|
||||
break;
|
||||
case WM_SIZE:
|
||||
case WM_SIZING:
|
||||
{
|
||||
if (m_thumbnail != nullptr)
|
||||
{
|
||||
RECT clientRect = {};
|
||||
winrt::check_bool(GetClientRect(m_window, &clientRect));
|
||||
|
||||
m_destRect = ComputeDestRect(clientRect, m_sourceRect);
|
||||
|
||||
DWM_THUMBNAIL_PROPERTIES properties = {};
|
||||
properties.dwFlags = DWM_TNP_RECTDESTINATION;
|
||||
properties.rcDestination = m_destRect;
|
||||
winrt::check_hresult(DwmUpdateThumbnailProperties(m_thumbnail.get(), &properties));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return base_type::MessageHandler(message, wparam, lparam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ThumbnailCropAndLockWindow::CropAndLock(HWND windowToCrop, RECT cropRect)
|
||||
{
|
||||
DisconnectTarget();
|
||||
m_currentTarget = windowToCrop;
|
||||
|
||||
// Adjust the crop rect to be in the window space as reported by the DWM
|
||||
RECT windowRect = {};
|
||||
winrt::check_hresult(DwmGetWindowAttribute(m_currentTarget, DWMWA_EXTENDED_FRAME_BOUNDS, reinterpret_cast<void*>(&windowRect), sizeof(windowRect)));
|
||||
auto clientRect = ClientAreaInScreenSpace(m_currentTarget);
|
||||
auto diffX = clientRect.left - windowRect.left;
|
||||
auto diffY = clientRect.top - windowRect.top;
|
||||
auto adjustedCropRect = cropRect;
|
||||
adjustedCropRect.left += diffX;
|
||||
adjustedCropRect.top += diffY;
|
||||
adjustedCropRect.right += diffX;
|
||||
adjustedCropRect.bottom += diffY;
|
||||
cropRect = adjustedCropRect;
|
||||
|
||||
// Resize our window
|
||||
auto width = cropRect.right - cropRect.left;
|
||||
auto height = cropRect.bottom - cropRect.top;
|
||||
windowRect = { 0, 0, width, height };
|
||||
auto exStyle = static_cast<DWORD>(GetWindowLongPtrW(m_window, GWL_EXSTYLE));
|
||||
auto style = static_cast<DWORD>(GetWindowLongPtrW(m_window, GWL_STYLE));
|
||||
winrt::check_bool(AdjustWindowRectEx(&windowRect, style, false, exStyle));
|
||||
auto adjustedWidth = windowRect.right - windowRect.left;
|
||||
auto adjustedHeight = windowRect.bottom - windowRect.top;
|
||||
winrt::check_bool(SetWindowPos(m_window, HWND_TOPMOST, 0, 0, adjustedWidth, adjustedHeight, SWP_NOMOVE | SWP_SHOWWINDOW));
|
||||
|
||||
// Setup the thumbnail
|
||||
winrt::check_hresult(DwmRegisterThumbnail(m_window, m_currentTarget, m_thumbnail.addressof()));
|
||||
|
||||
clientRect = {};
|
||||
winrt::check_bool(GetClientRect(m_window, &clientRect));
|
||||
m_destRect = clientRect;
|
||||
m_sourceRect = cropRect;
|
||||
|
||||
DWM_THUMBNAIL_PROPERTIES properties = {};
|
||||
properties.dwFlags = DWM_TNP_SOURCECLIENTAREAONLY | DWM_TNP_VISIBLE | DWM_TNP_OPACITY | DWM_TNP_RECTDESTINATION | DWM_TNP_RECTSOURCE;
|
||||
properties.fSourceClientAreaOnly = false;
|
||||
properties.fVisible = true;
|
||||
properties.opacity = 255;
|
||||
properties.rcDestination = m_destRect;
|
||||
properties.rcSource = m_sourceRect;
|
||||
winrt::check_hresult(DwmUpdateThumbnailProperties(m_thumbnail.get(), &properties));
|
||||
}
|
||||
|
||||
void ThumbnailCropAndLockWindow::Hide()
|
||||
{
|
||||
DisconnectTarget();
|
||||
ShowWindow(m_window, SW_HIDE);
|
||||
}
|
||||
|
||||
void ThumbnailCropAndLockWindow::DisconnectTarget()
|
||||
{
|
||||
if (m_currentTarget != nullptr)
|
||||
{
|
||||
m_thumbnail.reset();
|
||||
m_currentTarget = nullptr;
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#include <robmikh.common/DesktopWindow.h>
|
||||
#include "CropAndLockWindow.h"
|
||||
|
||||
struct ThumbnailCropAndLockWindow : robmikh::common::desktop::DesktopWindow<ThumbnailCropAndLockWindow>, CropAndLockWindow
|
||||
{
|
||||
static const std::wstring ClassName;
|
||||
ThumbnailCropAndLockWindow(std::wstring const& titleString, int width, int height);
|
||||
~ThumbnailCropAndLockWindow() override;
|
||||
LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam);
|
||||
|
||||
HWND Handle() override { return m_window; }
|
||||
void CropAndLock(HWND windowToCrop, RECT cropRect) override;
|
||||
void OnClosed(std::function<void(HWND)> callback) override { m_closedCallback = callback; }
|
||||
|
||||
private:
|
||||
static void RegisterWindowClass();
|
||||
|
||||
void Hide();
|
||||
void DisconnectTarget();
|
||||
|
||||
private:
|
||||
HWND m_currentTarget = nullptr;
|
||||
POINT m_previousPosition = {};
|
||||
|
||||
unique_hthumbnail m_thumbnail;
|
||||
RECT m_destRect = {};
|
||||
RECT m_sourceRect = {};
|
||||
|
||||
bool m_destroyed = false;
|
||||
std::function<void(HWND)> m_closedCallback;
|
||||
};
|
3
src/modules/CropAndLock/CropAndLock/ThumbnailUtil.h
Normal file
3
src/modules/CropAndLock/CropAndLock/ThumbnailUtil.h
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
typedef wil::unique_any<HTHUMBNAIL, decltype(&::DwmUnregisterThumbnail), ::DwmUnregisterThumbnail> unique_hthumbnail;
|
14
src/modules/CropAndLock/CropAndLock/WindowRectUtil.h
Normal file
14
src/modules/CropAndLock/CropAndLock/WindowRectUtil.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
inline RECT ClientAreaInScreenSpace(HWND window)
|
||||
{
|
||||
POINT clientOrigin = { 0, 0 };
|
||||
winrt::check_bool(ClientToScreen(window, &clientOrigin));
|
||||
RECT windowBounds = {};
|
||||
winrt::check_bool(GetClientRect(window, &windowBounds));
|
||||
windowBounds.left += clientOrigin.x;
|
||||
windowBounds.top += clientOrigin.y;
|
||||
windowBounds.right += clientOrigin.x;
|
||||
windowBounds.bottom += clientOrigin.y;
|
||||
return windowBounds;
|
||||
}
|
9
src/modules/CropAndLock/CropAndLock/app.manifest
Normal file
9
src/modules/CropAndLock/CropAndLock/app.manifest
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
BIN
src/modules/CropAndLock/CropAndLock/icon1.ico
Normal file
BIN
src/modules/CropAndLock/CropAndLock/icon1.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
270
src/modules/CropAndLock/CropAndLock/main.cpp
Normal file
270
src/modules/CropAndLock/CropAndLock/main.cpp
Normal file
@ -0,0 +1,270 @@
|
||||
#include "pch.h"
|
||||
#include "SettingsWindow.h"
|
||||
#include "OverlayWindow.h"
|
||||
#include "CropAndLockWindow.h"
|
||||
#include "ThumbnailCropAndLockWindow.h"
|
||||
#include "ReparentCropAndLockWindow.h"
|
||||
#include <common/interop/shared_constants.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include <common/utils/UnhandledExceptionHandler.h>
|
||||
#include <common/utils/gpo.h>
|
||||
#include "ModuleConstants.h"
|
||||
#include <common/utils/ProcessWaiter.h>
|
||||
#include "trace.h"
|
||||
|
||||
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::Foundation::Numerics;
|
||||
using namespace Windows::UI;
|
||||
using namespace Windows::UI::Composition;
|
||||
}
|
||||
|
||||
namespace util
|
||||
{
|
||||
using namespace robmikh::common::desktop;
|
||||
}
|
||||
|
||||
const std::wstring instanceMutexName = L"Local\\PowerToys_CropAndLock_InstanceMutex";
|
||||
bool m_running = true;
|
||||
|
||||
int WINAPI wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ PWSTR lpCmdLine, _In_ int)
|
||||
{
|
||||
// Initialize COM
|
||||
winrt::init_apartment(winrt::apartment_type::single_threaded);
|
||||
|
||||
// Initialize logger automatic logging of exceptions.
|
||||
LoggerHelpers::init_logger(NonLocalizable::ModuleKey, L"", LogSettings::cropAndLockLoggerName);
|
||||
InitUnhandledExceptionHandler();
|
||||
|
||||
if (powertoys_gpo::getConfiguredCropAndLockEnabledValue() == powertoys_gpo::gpo_rule_configured_disabled)
|
||||
{
|
||||
Logger::warn(L"Tried to start with a GPO policy setting the utility to always be disabled. Please contact your systems administrator.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Before we do anything, check to see if we're already running. If we are,
|
||||
// the hotkey won't register and we'll fail. Instead, we should tell the user
|
||||
// to kill the other instance and exit this one.
|
||||
auto mutex = CreateMutex(nullptr, true, instanceMutexName.c_str());
|
||||
if (mutex == nullptr)
|
||||
{
|
||||
Logger::error(L"Failed to create mutex. {}", get_last_error_or_default(GetLastError()));
|
||||
}
|
||||
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
// CropAndLock is already open.
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::wstring pid = std::wstring(lpCmdLine);
|
||||
if (pid.empty())
|
||||
{
|
||||
Logger::warn(L"Tried to run Crop And Lock as a standalone.");
|
||||
MessageBoxW(nullptr, L"CropAndLock can't run as a standalone. Start it from PowerToys.", L"CropAndLock", MB_ICONERROR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto mainThreadId = GetCurrentThreadId();
|
||||
ProcessWaiter::OnProcessTerminate(pid, [mainThreadId](int err) {
|
||||
if (err != ERROR_SUCCESS)
|
||||
{
|
||||
Logger::error(L"Failed to wait for parent process exit. {}", get_last_error_or_default(err));
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::trace(L"PowerToys runner exited.");
|
||||
}
|
||||
|
||||
Logger::trace(L"Exiting CropAndLock");
|
||||
PostThreadMessage(mainThreadId, WM_QUIT, 0, 0);
|
||||
});
|
||||
|
||||
// NOTE: reparenting a window with a different DPI context has consequences.
|
||||
// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setparent#remarks
|
||||
// for more info.
|
||||
winrt::check_bool(SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2));
|
||||
|
||||
// Create the DispatcherQueue that the compositor needs to run
|
||||
auto controller = util::CreateDispatcherQueueControllerForCurrentThread();
|
||||
|
||||
// Setup Composition
|
||||
auto compositor = winrt::Compositor();
|
||||
|
||||
// Create our overlay window
|
||||
std::unique_ptr<OverlayWindow> overlayWindow;
|
||||
|
||||
// Keep a list of our cropped windows
|
||||
std::vector<std::shared_ptr<CropAndLockWindow>> croppedWindows;
|
||||
|
||||
// Handles and thread for the events sent from runner
|
||||
HANDLE m_reparent_event_handle;
|
||||
HANDLE m_thumbnail_event_handle;
|
||||
HANDLE m_exit_event_handle;
|
||||
std::thread m_event_triggers_thread;
|
||||
|
||||
std::function<void(HWND)> removeWindowCallback = [&](HWND windowHandle)
|
||||
{
|
||||
if (!m_running)
|
||||
{
|
||||
// If we're not running, the reference to croppedWindows might no longer be valid and cause a crash at exit time, due to being called by destructors after wWinMain returns.
|
||||
return;
|
||||
}
|
||||
|
||||
auto pos = std::find_if(croppedWindows.begin(), croppedWindows.end(), [windowHandle](auto window) { return window->Handle() == windowHandle; });
|
||||
if (pos != croppedWindows.end())
|
||||
{
|
||||
croppedWindows.erase(pos);
|
||||
}
|
||||
};
|
||||
|
||||
std::function<void(CropAndLockType)> ProcessCommand = [&](CropAndLockType mode)
|
||||
{
|
||||
std::function<void(HWND, RECT)> windowCroppedCallback = [&, mode](HWND targetWindow, RECT cropRect) {
|
||||
auto targetInfo = util::WindowInfo(targetWindow);
|
||||
// TODO: Fix WindowInfo.h to not contain the null char at the end.
|
||||
auto nullCharIndex = std::wstring::npos;
|
||||
do
|
||||
{
|
||||
nullCharIndex = targetInfo.Title.rfind(L'\0');
|
||||
if (nullCharIndex != std::wstring::npos)
|
||||
{
|
||||
targetInfo.Title.erase(nullCharIndex);
|
||||
}
|
||||
} while (nullCharIndex != std::wstring::npos);
|
||||
|
||||
std::wstringstream titleStream;
|
||||
titleStream << targetInfo.Title << L" (Cropped)";
|
||||
auto title = titleStream.str();
|
||||
|
||||
std::shared_ptr<CropAndLockWindow> croppedWindow;
|
||||
switch (mode)
|
||||
{
|
||||
case CropAndLockType::Reparent:
|
||||
croppedWindow = std::make_shared<ReparentCropAndLockWindow>(title, 800, 600);
|
||||
Logger::trace(L"Creating a reparent window");
|
||||
Trace::CropAndLock::CreateReparentWindow();
|
||||
break;
|
||||
case CropAndLockType::Thumbnail:
|
||||
croppedWindow = std::make_shared<ThumbnailCropAndLockWindow>(title, 800, 600);
|
||||
Logger::trace(L"Creating a thumbnail window");
|
||||
Trace::CropAndLock::CreateThumbnailWindow();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
croppedWindow->CropAndLock(targetWindow, cropRect);
|
||||
croppedWindow->OnClosed(removeWindowCallback);
|
||||
croppedWindows.push_back(croppedWindow);
|
||||
};
|
||||
|
||||
overlayWindow.reset();
|
||||
|
||||
// Get the current window with focus
|
||||
auto foregroundWindow = GetForegroundWindow();
|
||||
if (foregroundWindow != nullptr)
|
||||
{
|
||||
bool match = false;
|
||||
for (auto&& croppedWindow : croppedWindows)
|
||||
{
|
||||
if (foregroundWindow == croppedWindow->Handle())
|
||||
{
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match)
|
||||
{
|
||||
overlayWindow = std::make_unique<OverlayWindow>(compositor, foregroundWindow, windowCroppedCallback);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Start a thread to listen on the events.
|
||||
m_reparent_event_handle = CreateEventW(nullptr, false, false, CommonSharedConstants::CROP_AND_LOCK_REPARENT_EVENT);
|
||||
m_thumbnail_event_handle = CreateEventW(nullptr, false, false, CommonSharedConstants::CROP_AND_LOCK_THUMBNAIL_EVENT);
|
||||
m_exit_event_handle = CreateEventW(nullptr, false, false, CommonSharedConstants::CROP_AND_LOCK_EXIT_EVENT);
|
||||
if (!m_reparent_event_handle || !m_reparent_event_handle || !m_exit_event_handle)
|
||||
{
|
||||
Logger::warn(L"Failed to create events. {}", get_last_error_or_default(GetLastError()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
m_event_triggers_thread = std::thread([&]() {
|
||||
MSG msg;
|
||||
HANDLE event_handles[3] = {m_reparent_event_handle, m_thumbnail_event_handle, m_exit_event_handle};
|
||||
while (m_running)
|
||||
{
|
||||
DWORD dwEvt = MsgWaitForMultipleObjects(3, event_handles, false, INFINITE, QS_ALLINPUT);
|
||||
if (!m_running)
|
||||
{
|
||||
break;
|
||||
}
|
||||
switch (dwEvt)
|
||||
{
|
||||
case WAIT_OBJECT_0:
|
||||
{
|
||||
// Reparent Event
|
||||
bool enqueueSucceeded = controller.DispatcherQueue().TryEnqueue([&]() {
|
||||
ProcessCommand(CropAndLockType::Reparent);
|
||||
});
|
||||
if (!enqueueSucceeded)
|
||||
{
|
||||
Logger::error("Couldn't enqueue message to reparent a window.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WAIT_OBJECT_0 + 1:
|
||||
{
|
||||
// Thumbnail Event
|
||||
bool enqueueSucceeded = controller.DispatcherQueue().TryEnqueue([&]() {
|
||||
ProcessCommand(CropAndLockType::Thumbnail);
|
||||
});
|
||||
if (!enqueueSucceeded)
|
||||
{
|
||||
Logger::error("Couldn't enqueue message to thumbnail a window.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WAIT_OBJECT_0 + 2:
|
||||
{
|
||||
// Exit Event
|
||||
Logger::trace(L"Received an exit event.");
|
||||
PostThreadMessage(mainThreadId, WM_QUIT, 0, 0);
|
||||
break;
|
||||
}
|
||||
case WAIT_OBJECT_0 + 3:
|
||||
if (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Message pump
|
||||
MSG msg = {};
|
||||
while (GetMessageW(&msg, nullptr, 0, 0))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
|
||||
m_running = false;
|
||||
// Needed to unblock MsgWaitForMultipleObjects one last time
|
||||
SetEvent(m_reparent_event_handle);
|
||||
CloseHandle(m_reparent_event_handle);
|
||||
CloseHandle(m_thumbnail_event_handle);
|
||||
CloseHandle(m_exit_event_handle);
|
||||
m_event_triggers_thread.join();
|
||||
|
||||
return util::ShutdownDispatcherQueueControllerAndWait(controller, static_cast<int>(msg.wParam));
|
||||
}
|
6
src/modules/CropAndLock/CropAndLock/packages.config
Normal file
6
src/modules/CropAndLock/CropAndLock/packages.config
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.220929.3" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.220914.1" targetFramework="native" />
|
||||
<package id="robmikh.common" version="0.0.22-beta" targetFramework="native" />
|
||||
</packages>
|
1
src/modules/CropAndLock/CropAndLock/pch.cpp
Normal file
1
src/modules/CropAndLock/CropAndLock/pch.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "pch.h"
|
78
src/modules/CropAndLock/CropAndLock/pch.h
Normal file
78
src/modules/CropAndLock/CropAndLock/pch.h
Normal file
@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
|
||||
// Collision from minWinDef min/max and std
|
||||
#define NOMINMAX
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
// Windows
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
|
||||
// Must come before C++/WinRT
|
||||
#include <wil/cppwinrt.h>
|
||||
|
||||
// WinRT
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/Windows.Foundation.Numerics.h>
|
||||
#include <winrt/Windows.System.h>
|
||||
#include <winrt/Windows.UI.h>
|
||||
#include <winrt/Windows.UI.Composition.h>
|
||||
#include <winrt/Windows.UI.Composition.Desktop.h>
|
||||
#include <winrt/Windows.UI.Popups.h>
|
||||
#include <winrt/Windows.Graphics.Capture.h>
|
||||
#include <winrt/Windows.Graphics.DirectX.h>
|
||||
#include <winrt/Windows.Graphics.DirectX.Direct3d11.h>
|
||||
|
||||
// WIL
|
||||
#include <wil/resource.h>
|
||||
|
||||
// DirectX
|
||||
#include <d3d11_4.h>
|
||||
#include <dxgi1_6.h>
|
||||
#include <d2d1_3.h>
|
||||
#include <wincodec.h>
|
||||
|
||||
// DWM
|
||||
#include <dwmapi.h>
|
||||
|
||||
// Shell
|
||||
#include <shellscalingapi.h>
|
||||
|
||||
// STL
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
|
||||
// robmikh.common
|
||||
#include <robmikh.common/composition.interop.h>
|
||||
#include <robmikh.common/direct3d11.interop.h>
|
||||
#include <robmikh.common/d3dHelpers.h>
|
||||
#include <robmikh.common/graphics.interop.h>
|
||||
#include <robmikh.common/dispatcherQueue.desktop.interop.h>
|
||||
#include <robmikh.common/d3dHelpers.desktop.h>
|
||||
#include <robmikh.common/composition.desktop.interop.h>
|
||||
#include <robmikh.common/hwnd.interop.h>
|
||||
#include <robmikh.common/capture.desktop.interop.h>
|
||||
#include <robmikh.common/DesktopWindow.h>
|
||||
#include <robmikh.common/DisplayInfo.h>
|
||||
#include <robmikh.common/shellHelpers.desktop.h>
|
||||
#include <robmikh.common/ControlsHelper.h>
|
||||
#include <robmikh.common/WindowInfo.h>
|
||||
|
||||
// Helpers
|
||||
#include "DisplaysUtil.h"
|
||||
#include "ThumbnailUtil.h"
|
||||
#include "WindowRectUtil.h"
|
||||
|
||||
// PowerToys
|
||||
#include <ProjectTelemetry.h>
|
||||
#include <common/logger/logger.h>
|
||||
|
||||
// Application resources
|
||||
#include "resource.h"
|
||||
#define MAIN_ICON MAKEINTRESOURCEW(IDI_ICON1)
|
26
src/modules/CropAndLock/CropAndLock/resource.h
Normal file
26
src/modules/CropAndLock/CropAndLock/resource.h
Normal file
@ -0,0 +1,26 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by CropAndLock.rc
|
||||
//
|
||||
#define IDI_ICON1 101
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//////////////////////////////
|
||||
// Non-localizable
|
||||
|
||||
#define FILE_DESCRIPTION "PowerToys CropAndLock"
|
||||
#define INTERNAL_NAME "PowerToys.CropAndLock"
|
||||
#define ORIGINAL_FILENAME "PowerToys.CropAndLock.exe"
|
||||
|
||||
// Non-localizable
|
||||
//////////////////////////////
|
95
src/modules/CropAndLock/CropAndLock/trace.cpp
Normal file
95
src/modules/CropAndLock/CropAndLock/trace.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
#include "pch.h"
|
||||
#include "trace.h"
|
||||
|
||||
// Telemetry strings should not be localized.
|
||||
#define LoggingProviderKey "Microsoft.PowerToys"
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
g_hProvider,
|
||||
LoggingProviderKey,
|
||||
// {38e8889b-9731-53f5-e901-e8a7c1753074}
|
||||
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
|
||||
TraceLoggingOptionProjectTelemetry());
|
||||
|
||||
void Trace::RegisterProvider() noexcept
|
||||
{
|
||||
TraceLoggingRegister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::UnregisterProvider() noexcept
|
||||
{
|
||||
TraceLoggingUnregister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::CropAndLock::Enable(bool enabled) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"CropAndLock_EnableCropAndLock",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingBoolean(enabled, "Enabled"));
|
||||
}
|
||||
|
||||
void Trace::CropAndLock::ActivateReparent() noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"CropAndLock_ActivateReparent",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
||||
|
||||
void Trace::CropAndLock::ActivateThumbnail() noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"CropAndLock_ActivateThumbnail",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
||||
|
||||
void Trace::CropAndLock::CreateReparentWindow() noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"CropAndLock_CreateReparentWindow",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
||||
|
||||
void Trace::CropAndLock::CreateThumbnailWindow() noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"CropAndLock_CreateThumbnailWindow",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
||||
|
||||
// Event to send settings telemetry.
|
||||
void Trace::CropAndLock::SettingsTelemetry(PowertoyModuleIface::Hotkey& reparentHotkey, PowertoyModuleIface::Hotkey& thumbnailHotkey) noexcept
|
||||
{
|
||||
std::wstring hotKeyStrReparent =
|
||||
std::wstring(reparentHotkey.win ? L"Win + " : L"") +
|
||||
std::wstring(reparentHotkey.ctrl ? L"Ctrl + " : L"") +
|
||||
std::wstring(reparentHotkey.shift ? L"Shift + " : L"") +
|
||||
std::wstring(reparentHotkey.alt ? L"Alt + " : L"") +
|
||||
std::wstring(L"VK ") + std::to_wstring(reparentHotkey.key);
|
||||
|
||||
std::wstring hotKeyStrThumbnail =
|
||||
std::wstring(thumbnailHotkey.win ? L"Win + " : L"") +
|
||||
std::wstring(thumbnailHotkey.ctrl ? L"Ctrl + " : L"") +
|
||||
std::wstring(thumbnailHotkey.shift ? L"Shift + " : L"") +
|
||||
std::wstring(thumbnailHotkey.alt ? L"Alt + " : L"") +
|
||||
std::wstring(L"VK ") + std::to_wstring(thumbnailHotkey.key);
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"CropAndLock_Settings",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingWideString(hotKeyStrReparent.c_str(), "ReparentHotKey"),
|
||||
TraceLoggingWideString(hotKeyStrThumbnail.c_str(), "ThumbnailHotkey")
|
||||
);
|
||||
}
|
20
src/modules/CropAndLock/CropAndLock/trace.h
Normal file
20
src/modules/CropAndLock/CropAndLock/trace.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include <modules/interface/powertoy_module_interface.h>
|
||||
|
||||
class Trace
|
||||
{
|
||||
public:
|
||||
static void RegisterProvider() noexcept;
|
||||
static void UnregisterProvider() noexcept;
|
||||
|
||||
class CropAndLock
|
||||
{
|
||||
public:
|
||||
static void Enable(bool enabled) noexcept;
|
||||
static void ActivateReparent() noexcept;
|
||||
static void ActivateThumbnail() noexcept;
|
||||
static void CreateReparentWindow() noexcept;
|
||||
static void CreateThumbnailWindow() noexcept;
|
||||
static void SettingsTelemetry(PowertoyModuleIface::Hotkey&, PowertoyModuleIface::Hotkey&) noexcept;
|
||||
};
|
||||
};
|
@ -0,0 +1,40 @@
|
||||
#include <windows.h>
|
||||
#include "resource.h"
|
||||
#include "../../../common/version/version.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
#include "winres.h"
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
1 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" // US English (0x0409), Unicode (0x04B0) charset
|
||||
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 // US English (0x0409), Unicode (1200) charset
|
||||
END
|
||||
END
|
@ -0,0 +1,118 @@
|
||||
<?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.220929.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{3157fa75-86cf-4ee2-8f62-c43f776493c6}</ProjectGuid>
|
||||
<RootNamespace>CropAndLockModuleInterface</RootNamespace>
|
||||
<ProjectName>CropAndLockModuleInterface</ProjectName>
|
||||
</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>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\</OutDir>
|
||||
<TargetName>PowerToys.CropAndLockModuleInterface</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\;$(SolutionDir)src\common\Telemetry;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\CropAndLock\ModuleConstants.h" />
|
||||
<ClInclude Include="..\CropAndLock\trace.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\CropAndLock\trace.cpp" />
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="CropAndLockModuleInterface.rc" />
|
||||
</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>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.211019.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.211019.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
<Import Project="..\..\..\..\packages\robmikh.common.0.0.22-beta\build\native\robmikh.common.targets" Condition="Exists('..\..\..\..\packages\robmikh.common.0.0.22-beta\build\native\robmikh.common.targets')" />
|
||||
</ImportGroup>
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<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.220929.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\robmikh.common.0.0.22-beta\build\native\robmikh.common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\robmikh.common.0.0.22-beta\build\native\robmikh.common.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
@ -0,0 +1,53 @@
|
||||
<?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>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\CropAndLock\trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\CropAndLock\ModuleConstants.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\CropAndLock\trace.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="CropAndLockModuleInterface.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
|
||||
</ItemGroup>
|
||||
</Project>
|
334
src/modules/CropAndLock/CropAndLockModuleInterface/dllmain.cpp
Normal file
334
src/modules/CropAndLock/CropAndLockModuleInterface/dllmain.cpp
Normal file
@ -0,0 +1,334 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include <modules/interface/powertoy_module_interface.h>
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include <common/utils/resources.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
|
||||
#include <CropAndLock/trace.h>
|
||||
#include <CropAndLock/ModuleConstants.h>
|
||||
|
||||
#include <shellapi.h>
|
||||
#include <common/interop/shared_constants.h>
|
||||
|
||||
namespace NonLocalizable
|
||||
{
|
||||
const wchar_t ModulePath[] = L"PowerToys.CropAndLock.exe";
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
const wchar_t JSON_KEY_PROPERTIES[] = L"properties";
|
||||
const wchar_t JSON_KEY_WIN[] = L"win";
|
||||
const wchar_t JSON_KEY_ALT[] = L"alt";
|
||||
const wchar_t JSON_KEY_CTRL[] = L"ctrl";
|
||||
const wchar_t JSON_KEY_SHIFT[] = L"shift";
|
||||
const wchar_t JSON_KEY_CODE[] = L"code";
|
||||
const wchar_t JSON_KEY_REPARENT_HOTKEY[] = L"reparent-hotkey";
|
||||
const wchar_t JSON_KEY_THUMBNAIL_HOTKEY[] = L"thumbnail-hotkey";
|
||||
const wchar_t JSON_KEY_VALUE[] = L"value";
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain( HMODULE /*hModule*/,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID /*lpReserved*/
|
||||
)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
Trace::RegisterProvider();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
Trace::UnregisterProvider();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
class CropAndLockModuleInterface : public PowertoyModuleIface
|
||||
{
|
||||
public:
|
||||
// Return the localized display name of the powertoy
|
||||
virtual PCWSTR get_name() override
|
||||
{
|
||||
return app_name.c_str();
|
||||
}
|
||||
|
||||
// Return the non localized key of the powertoy, this will be cached by the runner
|
||||
virtual const wchar_t* get_key() override
|
||||
{
|
||||
return app_key.c_str();
|
||||
}
|
||||
|
||||
// Return the configured status for the gpo policy for the module
|
||||
virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override
|
||||
{
|
||||
return powertoys_gpo::getConfiguredCropAndLockEnabledValue();
|
||||
}
|
||||
|
||||
// Return JSON with the configuration options.
|
||||
// These are the settings shown on the settings page along with their current values.
|
||||
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
|
||||
{
|
||||
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||
|
||||
// Create a Settings object.
|
||||
PowerToysSettings::Settings settings(hinstance, get_name());
|
||||
|
||||
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||
}
|
||||
|
||||
// Passes JSON with the configuration settings for the powertoy.
|
||||
// This is called when the user hits Save on the settings page.
|
||||
virtual void set_config(const wchar_t* config) override
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse the input JSON string.
|
||||
PowerToysSettings::PowerToyValues values =
|
||||
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
||||
|
||||
parse_hotkey(values);
|
||||
|
||||
values.save_to_settings_file();
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
// Improper JSON.
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool on_hotkey(size_t hotkeyId) override
|
||||
{
|
||||
if (m_enabled)
|
||||
{
|
||||
Logger::trace(L"CropAndLock hotkey pressed");
|
||||
if (!is_process_running())
|
||||
{
|
||||
Enable();
|
||||
}
|
||||
|
||||
if (hotkeyId == 0) { // Same order as set by get_hotkeys
|
||||
SetEvent(m_reparent_event_handle);
|
||||
Trace::CropAndLock::ActivateReparent();
|
||||
}
|
||||
if (hotkeyId == 1) { // Same order as set by get_hotkeys
|
||||
SetEvent(m_thumbnail_event_handle);
|
||||
Trace::CropAndLock::ActivateThumbnail();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual size_t get_hotkeys(Hotkey* hotkeys, size_t buffer_size) override
|
||||
{
|
||||
if (hotkeys && buffer_size >= 2)
|
||||
{
|
||||
hotkeys[0] = m_reparent_hotkey;
|
||||
hotkeys[1] = m_thumbnail_hotkey;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Enable the powertoy
|
||||
virtual void enable()
|
||||
{
|
||||
Logger::info("CropAndLock enabling");
|
||||
Enable();
|
||||
}
|
||||
|
||||
// Disable the powertoy
|
||||
virtual void disable()
|
||||
{
|
||||
Logger::info("CropAndLock disabling");
|
||||
Disable(true);
|
||||
}
|
||||
|
||||
// Returns if the powertoy is enabled
|
||||
virtual bool is_enabled() override
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
// Destroy the powertoy and free memory
|
||||
virtual void destroy() override
|
||||
{
|
||||
Disable(false);
|
||||
delete this;
|
||||
}
|
||||
|
||||
virtual void send_settings_telemetry() override
|
||||
{
|
||||
Logger::info("Send settings telemetry");
|
||||
Trace::CropAndLock::SettingsTelemetry(m_reparent_hotkey, m_thumbnail_hotkey);
|
||||
}
|
||||
|
||||
CropAndLockModuleInterface()
|
||||
{
|
||||
app_name = L"CropAndLock";
|
||||
app_key = NonLocalizable::ModuleKey;
|
||||
LoggerHelpers::init_logger(app_key, L"ModuleInterface", LogSettings::cropAndLockLoggerName);
|
||||
|
||||
m_reparent_event_handle = CreateDefaultEvent(CommonSharedConstants::CROP_AND_LOCK_REPARENT_EVENT);
|
||||
m_thumbnail_event_handle = CreateDefaultEvent(CommonSharedConstants::CROP_AND_LOCK_THUMBNAIL_EVENT);
|
||||
m_exit_event_handle = CreateDefaultEvent(CommonSharedConstants::CROP_AND_LOCK_EXIT_EVENT);
|
||||
|
||||
init_settings();
|
||||
}
|
||||
|
||||
private:
|
||||
void Enable()
|
||||
{
|
||||
m_enabled = true;
|
||||
|
||||
// Log telemetry
|
||||
Trace::CropAndLock::Enable(true);
|
||||
|
||||
// Pass the PID.
|
||||
unsigned long powertoys_pid = GetCurrentProcessId();
|
||||
std::wstring executable_args = L"";
|
||||
executable_args.append(std::to_wstring(powertoys_pid));
|
||||
|
||||
ResetEvent(m_reparent_event_handle);
|
||||
ResetEvent(m_thumbnail_event_handle);
|
||||
ResetEvent(m_exit_event_handle);
|
||||
|
||||
SHELLEXECUTEINFOW sei{ sizeof(sei) };
|
||||
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
|
||||
sei.lpFile = NonLocalizable::ModulePath;
|
||||
sei.nShow = SW_SHOWNORMAL;
|
||||
sei.lpParameters = executable_args.data();
|
||||
if (ShellExecuteExW(&sei) == false)
|
||||
{
|
||||
Logger::error(L"Failed to start CropAndLock");
|
||||
auto message = get_last_error_message(GetLastError());
|
||||
if (message.has_value())
|
||||
{
|
||||
Logger::error(message.value());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hProcess = sei.hProcess;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Disable(bool const traceEvent)
|
||||
{
|
||||
m_enabled = false;
|
||||
|
||||
// We can't just kill the process, since Crop and Lock might need to release any reparented windows first.
|
||||
SetEvent(m_exit_event_handle);
|
||||
|
||||
ResetEvent(m_reparent_event_handle);
|
||||
ResetEvent(m_thumbnail_event_handle);
|
||||
|
||||
// Log telemetry
|
||||
if (traceEvent)
|
||||
{
|
||||
Trace::CropAndLock::Enable(false);
|
||||
}
|
||||
|
||||
if (m_hProcess)
|
||||
{
|
||||
m_hProcess = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void parse_hotkey(PowerToysSettings::PowerToyValues& settings)
|
||||
{
|
||||
auto settingsObject = settings.get_raw_json();
|
||||
if (settingsObject.GetView().Size())
|
||||
{
|
||||
try
|
||||
{
|
||||
Hotkey _temp_reparent;
|
||||
auto jsonHotkeyObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_REPARENT_HOTKEY).GetNamedObject(JSON_KEY_VALUE);
|
||||
_temp_reparent.win = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_WIN);
|
||||
_temp_reparent.alt = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_ALT);
|
||||
_temp_reparent.shift = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_SHIFT);
|
||||
_temp_reparent.ctrl = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_CTRL);
|
||||
_temp_reparent.key = static_cast<unsigned char>(jsonHotkeyObject.GetNamedNumber(JSON_KEY_CODE));
|
||||
m_reparent_hotkey = _temp_reparent;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error("Failed to initialize CropAndLock reparent shortcut from settings. Value will keep unchanged.");
|
||||
}
|
||||
try
|
||||
{
|
||||
Hotkey _temp_thumbnail;
|
||||
auto jsonHotkeyObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_THUMBNAIL_HOTKEY).GetNamedObject(JSON_KEY_VALUE);
|
||||
_temp_thumbnail.win = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_WIN);
|
||||
_temp_thumbnail.alt = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_ALT);
|
||||
_temp_thumbnail.shift = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_SHIFT);
|
||||
_temp_thumbnail.ctrl = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_CTRL);
|
||||
_temp_thumbnail.key = static_cast<unsigned char>(jsonHotkeyObject.GetNamedNumber(JSON_KEY_CODE));
|
||||
m_thumbnail_hotkey = _temp_thumbnail;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error("Failed to initialize CropAndLock thumbnail shortcut from settings. Value will keep unchanged.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info("CropAndLock settings are empty");
|
||||
}
|
||||
}
|
||||
|
||||
bool is_process_running()
|
||||
{
|
||||
return WaitForSingleObject(m_hProcess, 0) == WAIT_TIMEOUT;
|
||||
}
|
||||
|
||||
void init_settings()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Load and parse the settings file for this PowerToy.
|
||||
PowerToysSettings::PowerToyValues settings =
|
||||
PowerToysSettings::PowerToyValues::load_from_settings_file(get_key());
|
||||
|
||||
parse_hotkey(settings);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
Logger::warn(L"An exception occurred while loading the settings file");
|
||||
// Error while loading from the settings file. Let default values stay as they are.
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring app_name;
|
||||
std::wstring app_key; //contains the non localized key of the powertoy
|
||||
|
||||
bool m_enabled = false;
|
||||
HANDLE m_hProcess = nullptr;
|
||||
|
||||
// TODO: actual default hotkey setting in line with other PowerToys.
|
||||
Hotkey m_reparent_hotkey = { .win = true, .ctrl = true, .shift = true, .alt = false, .key = 'R' };
|
||||
Hotkey m_thumbnail_hotkey = { .win = true, .ctrl = true, .shift = true, .alt = false, .key = 'T' };
|
||||
|
||||
HANDLE m_reparent_event_handle;
|
||||
HANDLE m_thumbnail_event_handle;
|
||||
HANDLE m_exit_event_handle;
|
||||
|
||||
};
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
{
|
||||
return new CropAndLockModuleInterface();
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.220929.3" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.220914.1" targetFramework="native" />
|
||||
</packages>
|
@ -0,0 +1,5 @@
|
||||
// pch.cpp: source file corresponding to the pre-compiled header
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
|
12
src/modules/CropAndLock/CropAndLockModuleInterface/pch.h
Normal file
12
src/modules/CropAndLock/CropAndLockModuleInterface/pch.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#include <windows.h>
|
||||
#include <Unknwn.h>
|
||||
#include <winrt/base.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <ProjectTelemetry.h>
|
||||
#include <TraceLoggingActivity.h>
|
||||
#include <wil\common.h>
|
||||
#include <wil\result.h>
|
@ -0,0 +1,13 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by CropAndLockModuleInterface.rc
|
||||
|
||||
//////////////////////////////
|
||||
// Non-localizable
|
||||
|
||||
#define FILE_DESCRIPTION "PowerToys CropAndLockModuleInterface"
|
||||
#define INTERNAL_NAME "PowerToys.CropAndLockModuleInterface"
|
||||
#define ORIGINAL_FILENAME "PowerToys.CropAndLockModuleInterface.dll"
|
||||
|
||||
// Non-localizable
|
||||
//////////////////////////////
|
@ -52,22 +52,6 @@
|
||||
<NoWarn>0436</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Assets\MeasureTool\SplashScreen.scale-200.png" />
|
||||
<Content Include="Assets\MeasureTool\LockScreenLogo.scale-200.png" />
|
||||
|
@ -26,7 +26,7 @@
|
||||
LightTintColor="#F3F3F3"
|
||||
LightTintOpacity="0" />
|
||||
</winuiex:WindowEx.Backdrop>
|
||||
|
||||
|
||||
<Grid>
|
||||
<Grid.Resources>
|
||||
<SolidColorBrush x:Key="ToggleButtonBackground" Color="Transparent" />
|
||||
@ -249,67 +249,90 @@
|
||||
|
||||
<StackPanel
|
||||
HorizontalAlignment="Center"
|
||||
Loaded="StackPanel_Loaded"
|
||||
Orientation="Horizontal"
|
||||
Spacing="8"
|
||||
Loaded="StackPanel_Loaded">
|
||||
Spacing="8">
|
||||
<ToggleButton
|
||||
Name="btnBounds"
|
||||
AutomationProperties.Name="{x:Bind p:Resources.Bounds}"
|
||||
x:Uid="BtnBounds"
|
||||
Click="BoundsTool_Click"
|
||||
Content=""
|
||||
Style="{StaticResource ToggleButtonRadioButtonStyle}"
|
||||
KeyboardAcceleratorPlacementMode="Auto"
|
||||
ToolTipService.ToolTip="{x:Bind p:Resources.Bounds}">
|
||||
Style="{StaticResource ToggleButtonRadioButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock x:Uid="BtnBoundsTooltip" />
|
||||
</ToolTipService.ToolTip>
|
||||
<ToggleButton.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Key="Number1" Modifiers="Control" Invoked="KeyboardAccelerator_Invoked"/>
|
||||
<KeyboardAccelerator
|
||||
Key="Number1"
|
||||
Invoked="KeyboardAccelerator_Invoked"
|
||||
Modifiers="Control" />
|
||||
</ToggleButton.KeyboardAccelerators>
|
||||
</ToggleButton>
|
||||
<ToggleButton
|
||||
Name="btnSpacing"
|
||||
AutomationProperties.Name="{x:Bind p:Resources.Spacing}"
|
||||
x:Uid="BtnSpacing"
|
||||
Click="MeasureTool_Click"
|
||||
Style="{StaticResource ToggleButtonRadioButtonStyle}"
|
||||
ToolTipService.ToolTip="{x:Bind p:Resources.Spacing}">
|
||||
Style="{StaticResource ToggleButtonRadioButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock x:Uid="BtnSpacingTooltip" />
|
||||
</ToolTipService.ToolTip>
|
||||
<FontIcon Glyph="" />
|
||||
<ToggleButton.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Key="Number2" Modifiers="Control" Invoked="KeyboardAccelerator_Invoked"/>
|
||||
<KeyboardAccelerator
|
||||
Key="Number2"
|
||||
Invoked="KeyboardAccelerator_Invoked"
|
||||
Modifiers="Control" />
|
||||
</ToggleButton.KeyboardAccelerators>
|
||||
</ToggleButton>
|
||||
|
||||
<ToggleButton
|
||||
Name="btnHorizontalSpacing"
|
||||
AutomationProperties.Name="{x:Bind p:Resources.HorizontalSpacing}"
|
||||
x:Uid="BtnHorizontalSpacing"
|
||||
Click="HorizontalMeasureTool_Click"
|
||||
Style="{StaticResource ToggleButtonRadioButtonStyle}"
|
||||
ToolTipService.ToolTip="{x:Bind p:Resources.HorizontalSpacing}">
|
||||
Style="{StaticResource ToggleButtonRadioButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock x:Uid="BtnHorizontalSpacingTooltip" />
|
||||
</ToolTipService.ToolTip>
|
||||
<FontIcon Glyph="" />
|
||||
<ToggleButton.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Key="Number3" Modifiers="Control" Invoked="KeyboardAccelerator_Invoked"/>
|
||||
<KeyboardAccelerator
|
||||
Key="Number3"
|
||||
Invoked="KeyboardAccelerator_Invoked"
|
||||
Modifiers="Control" />
|
||||
</ToggleButton.KeyboardAccelerators>
|
||||
</ToggleButton>
|
||||
<ToggleButton
|
||||
Name="btnVerticalSpacing"
|
||||
AutomationProperties.Name="{x:Bind p:Resources.VerticalSpacing}"
|
||||
x:Uid="BtnVerticalSpacing"
|
||||
Click="VerticalMeasureTool_Click"
|
||||
Style="{StaticResource ToggleButtonRadioButtonStyle}"
|
||||
ToolTipService.ToolTip="{x:Bind p:Resources.VerticalSpacing}">
|
||||
Style="{StaticResource ToggleButtonRadioButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock x:Uid="BtnVerticalSpacingTooltip" />
|
||||
</ToolTipService.ToolTip>
|
||||
<FontIcon Glyph="" RenderTransformOrigin="0.5,0.5">
|
||||
<FontIcon.RenderTransform>
|
||||
<RotateTransform Angle="90" />
|
||||
</FontIcon.RenderTransform>
|
||||
</FontIcon>
|
||||
<ToggleButton.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Key="Number4" Modifiers="Control" Invoked="KeyboardAccelerator_Invoked"/>
|
||||
<KeyboardAccelerator
|
||||
Key="Number4"
|
||||
Invoked="KeyboardAccelerator_Invoked"
|
||||
Modifiers="Control" />
|
||||
</ToggleButton.KeyboardAccelerators>
|
||||
</ToggleButton>
|
||||
<AppBarSeparator/>
|
||||
<AppBarSeparator />
|
||||
<Button
|
||||
x:Uid="BtnClosePanel"
|
||||
Click="ClosePanelTool_Click"
|
||||
Content=""
|
||||
ToolTipService.ToolTip="{x:Bind p:Resources.Close}"
|
||||
Foreground="{StaticResource CloseButtonBackgroundPointerOver}">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock x:Uid="BtnClosePanelTooltip" />
|
||||
</ToolTipService.ToolTip>
|
||||
<Button.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Key="Escape" Invoked="KeyboardAccelerator_Invoked"/>
|
||||
<KeyboardAccelerator Key="Escape" Invoked="KeyboardAccelerator_Invoked" />
|
||||
</Button.KeyboardAccelerators>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
|
@ -1,108 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace PowerToys.MeasureToolUI.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PowerToys.MeasureToolUI.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Bounds (Ctrl+1).
|
||||
/// </summary>
|
||||
public static string Bounds {
|
||||
get {
|
||||
return ResourceManager.GetString("Bounds", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Close (Esc).
|
||||
/// </summary>
|
||||
public static string Close {
|
||||
get {
|
||||
return ResourceManager.GetString("Close", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Horizontal spacing (Ctrl+3).
|
||||
/// </summary>
|
||||
public static string HorizontalSpacing {
|
||||
get {
|
||||
return ResourceManager.GetString("HorizontalSpacing", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Spacing (Ctrl+2).
|
||||
/// </summary>
|
||||
public static string Spacing {
|
||||
get {
|
||||
return ResourceManager.GetString("Spacing", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Vertical spacing (Ctrl+4).
|
||||
/// </summary>
|
||||
public static string VerticalSpacing {
|
||||
get {
|
||||
return ResourceManager.GetString("VerticalSpacing", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Bounds" xml:space="preserve">
|
||||
<value>Bounds (Ctrl+1)</value>
|
||||
</data>
|
||||
<data name="Spacing" xml:space="preserve">
|
||||
<value>Spacing (Ctrl+2)</value>
|
||||
</data>
|
||||
<data name="HorizontalSpacing" xml:space="preserve">
|
||||
<value>Horizontal spacing (Ctrl+3)</value>
|
||||
</data>
|
||||
<data name="VerticalSpacing" xml:space="preserve">
|
||||
<value>Vertical spacing (Ctrl+4)</value>
|
||||
</data>
|
||||
<data name="Close" xml:space="preserve">
|
||||
<value>Close (Esc)</value>
|
||||
</data>
|
||||
</root>
|
@ -39,4 +39,31 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="BtnBounds.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Bounds (Ctrl+1)</value>
|
||||
</data>
|
||||
<data name="BtnBoundsTooltip.Text" xml:space="preserve">
|
||||
<value>Bounds (Ctrl+1)</value>
|
||||
</data>
|
||||
<data name="BtnSpacing.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Spacing (Ctrl+2)</value>
|
||||
</data>
|
||||
<data name="BtnSpacingTooltip.Text" xml:space="preserve">
|
||||
<value>Spacing (Ctrl+2)</value>
|
||||
</data>
|
||||
<data name="BtnHorizontalSpacing.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Horizontal spacing (Ctrl+3)</value>
|
||||
</data>
|
||||
<data name="BtnHorizontalSpacingTooltip.Text" xml:space="preserve">
|
||||
<value>Horizontal spacing (Ctrl+3)</value>
|
||||
</data>
|
||||
<data name="BtnVerticalSpacing.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Vertical spacing (Ctrl+4)</value>
|
||||
</data>
|
||||
<data name="BtnVerticalSpacingTooltip.Text" xml:space="preserve">
|
||||
<value>Vertical spacing (Ctrl+4)</value>
|
||||
</data>
|
||||
<data name="BtnClosePanelTooltip.Text" xml:space="preserve">
|
||||
<value>Close (Esc)</value>
|
||||
</data>
|
||||
</root>
|
@ -52,4 +52,4 @@ void Trace::AlwaysOnTop::UnpinWindow() noexcept
|
||||
EventUnpinWindowKey,
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
||||
}
|
||||
|
@ -171,5 +171,20 @@ LayoutData DefaultLayouts::GetDefaultLayout(MonitorConfigurationType type) const
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case MonitorConfigurationType::Horizontal:
|
||||
return LayoutData{};
|
||||
case MonitorConfigurationType::Vertical:
|
||||
return LayoutData{
|
||||
.uuid = GUID_NULL,
|
||||
.type = FancyZonesDataTypes::ZoneSetLayoutType::Rows,
|
||||
.showSpacing = DefaultValues::ShowSpacing,
|
||||
.spacing = DefaultValues::Spacing,
|
||||
.zoneCount = DefaultValues::ZoneCount,
|
||||
.sensitivityRadius = DefaultValues::SensitivityRadius
|
||||
};
|
||||
}
|
||||
|
||||
return LayoutData{};
|
||||
}
|
||||
|
@ -96,15 +96,21 @@ namespace FancyZonesUnitTests
|
||||
.sensitivityRadius = DefaultValues::SensitivityRadius
|
||||
};
|
||||
|
||||
LayoutData rows{
|
||||
.uuid = GUID_NULL,
|
||||
.type = FancyZonesDataTypes::ZoneSetLayoutType::Rows,
|
||||
.showSpacing = DefaultValues::ShowSpacing,
|
||||
.spacing = DefaultValues::Spacing,
|
||||
.zoneCount = DefaultValues::ZoneCount,
|
||||
.sensitivityRadius = DefaultValues::SensitivityRadius
|
||||
};
|
||||
|
||||
Assert::IsTrue(priorityGrid == DefaultLayouts::instance().GetDefaultLayout(MonitorConfigurationType::Horizontal));
|
||||
Assert::IsTrue(priorityGrid == DefaultLayouts::instance().GetDefaultLayout(MonitorConfigurationType::Vertical));
|
||||
Assert::IsTrue(rows == DefaultLayouts::instance().GetDefaultLayout(MonitorConfigurationType::Vertical));
|
||||
}
|
||||
|
||||
TEST_METHOD (DefaultLayoutsNoFile)
|
||||
{
|
||||
// test
|
||||
DefaultLayouts::instance().LoadData();
|
||||
|
||||
LayoutData priorityGrid{
|
||||
.uuid = GUID_NULL,
|
||||
.type = FancyZonesDataTypes::ZoneSetLayoutType::PriorityGrid,
|
||||
@ -114,8 +120,20 @@ namespace FancyZonesUnitTests
|
||||
.sensitivityRadius = DefaultValues::SensitivityRadius
|
||||
};
|
||||
|
||||
LayoutData rows{
|
||||
.uuid = GUID_NULL,
|
||||
.type = FancyZonesDataTypes::ZoneSetLayoutType::Rows,
|
||||
.showSpacing = DefaultValues::ShowSpacing,
|
||||
.spacing = DefaultValues::Spacing,
|
||||
.zoneCount = DefaultValues::ZoneCount,
|
||||
.sensitivityRadius = DefaultValues::SensitivityRadius
|
||||
};
|
||||
|
||||
// test
|
||||
DefaultLayouts::instance().LoadData();
|
||||
|
||||
Assert::IsTrue(priorityGrid == DefaultLayouts::instance().GetDefaultLayout(MonitorConfigurationType::Horizontal));
|
||||
Assert::IsTrue(priorityGrid == DefaultLayouts::instance().GetDefaultLayout(MonitorConfigurationType::Vertical));
|
||||
Assert::IsTrue(rows == DefaultLayouts::instance().GetDefaultLayout(MonitorConfigurationType::Vertical));
|
||||
}
|
||||
};
|
||||
}
|
@ -78,8 +78,6 @@ namespace FancyZonesEditor
|
||||
|
||||
_themeManager = new ThemeManager(this);
|
||||
|
||||
var parseResult = FancyZonesEditorIO.ParseParams();
|
||||
|
||||
RunnerHelper.WaitForPowerToysRunner(PowerToysPID, () =>
|
||||
{
|
||||
Logger.LogInfo("Runner exited");
|
||||
@ -87,27 +85,8 @@ namespace FancyZonesEditor
|
||||
Application.Current.Dispatcher.Invoke(Application.Current.Shutdown);
|
||||
});
|
||||
|
||||
if (!parseResult.Result)
|
||||
{
|
||||
Logger.LogError(ParsingErrorReportTag + ": " + parseResult.Message + "; " + ParsingErrorDataTag + ": " + parseResult.MalformedData);
|
||||
MessageBox.Show(parseResult.Message, FancyZonesEditor.Properties.Resources.Error_Parsing_Data_Title, MessageBoxButton.OK);
|
||||
}
|
||||
var parseResult = FancyZonesEditorIO.ParseParams();
|
||||
|
||||
parseResult = FancyZonesEditorIO.ParseAppliedLayouts();
|
||||
if (!parseResult.Result)
|
||||
{
|
||||
Logger.LogError(ParsingErrorReportTag + ": " + parseResult.Message + "; " + ParsingErrorDataTag + ": " + parseResult.MalformedData);
|
||||
MessageBox.Show(parseResult.Message, FancyZonesEditor.Properties.Resources.Error_Parsing_Data_Title, MessageBoxButton.OK);
|
||||
}
|
||||
|
||||
parseResult = FancyZonesEditorIO.ParseCustomLayouts();
|
||||
if (!parseResult.Result)
|
||||
{
|
||||
Logger.LogError(ParsingErrorReportTag + ": " + parseResult.Message + "; " + ParsingErrorDataTag + ": " + parseResult.MalformedData);
|
||||
MessageBox.Show(parseResult.Message, FancyZonesEditor.Properties.Resources.Error_Parsing_Data_Title, MessageBoxButton.OK);
|
||||
}
|
||||
|
||||
parseResult = FancyZonesEditorIO.ParseLayoutHotkeys();
|
||||
if (!parseResult.Result)
|
||||
{
|
||||
Logger.LogError(ParsingErrorReportTag + ": " + parseResult.Message + "; " + ParsingErrorDataTag + ": " + parseResult.MalformedData);
|
||||
@ -121,6 +100,13 @@ namespace FancyZonesEditor
|
||||
MessageBox.Show(parseResult.Message, FancyZonesEditor.Properties.Resources.Error_Parsing_Data_Title, MessageBoxButton.OK);
|
||||
}
|
||||
|
||||
parseResult = FancyZonesEditorIO.ParseCustomLayouts();
|
||||
if (!parseResult.Result)
|
||||
{
|
||||
Logger.LogError(ParsingErrorReportTag + ": " + parseResult.Message + "; " + ParsingErrorDataTag + ": " + parseResult.MalformedData);
|
||||
MessageBox.Show(parseResult.Message, FancyZonesEditor.Properties.Resources.Error_Parsing_Data_Title, MessageBoxButton.OK);
|
||||
}
|
||||
|
||||
parseResult = FancyZonesEditorIO.ParseDefaultLayouts();
|
||||
if (!parseResult.Result)
|
||||
{
|
||||
@ -128,6 +114,20 @@ namespace FancyZonesEditor
|
||||
MessageBox.Show(parseResult.Message, FancyZonesEditor.Properties.Resources.Error_Parsing_Data_Title, MessageBoxButton.OK);
|
||||
}
|
||||
|
||||
parseResult = FancyZonesEditorIO.ParseLayoutHotkeys();
|
||||
if (!parseResult.Result)
|
||||
{
|
||||
Logger.LogError(ParsingErrorReportTag + ": " + parseResult.Message + "; " + ParsingErrorDataTag + ": " + parseResult.MalformedData);
|
||||
MessageBox.Show(parseResult.Message, FancyZonesEditor.Properties.Resources.Error_Parsing_Data_Title, MessageBoxButton.OK);
|
||||
}
|
||||
|
||||
parseResult = FancyZonesEditorIO.ParseAppliedLayouts();
|
||||
if (!parseResult.Result)
|
||||
{
|
||||
Logger.LogError(ParsingErrorReportTag + ": " + parseResult.Message + "; " + ParsingErrorDataTag + ": " + parseResult.MalformedData);
|
||||
MessageBox.Show(parseResult.Message, FancyZonesEditor.Properties.Resources.Error_Parsing_Data_Title, MessageBoxButton.OK);
|
||||
}
|
||||
|
||||
MainWindowSettingsModel settings = ((App)Current).MainWindowSettings;
|
||||
settings.UpdateSelectedLayoutModel();
|
||||
|
||||
|
@ -28,7 +28,7 @@ namespace FancyZonesEditor
|
||||
|
||||
MainWindowSettingsModel settings = ((App)Application.Current).MainWindowSettings;
|
||||
settings.SetAppliedModel(model);
|
||||
App.Overlay.SetLayoutSettings(App.Overlay.Monitors[App.Overlay.CurrentDesktop], model);
|
||||
App.Overlay.Monitors[App.Overlay.CurrentDesktop].SetLayoutSettings(model);
|
||||
}
|
||||
|
||||
App.FancyZonesEditorIO.SerializeLayoutTemplates();
|
||||
|
@ -296,7 +296,7 @@ namespace FancyZonesEditor
|
||||
|
||||
model.Persist();
|
||||
|
||||
App.Overlay.SetLayoutSettings(App.Overlay.Monitors[App.Overlay.CurrentDesktop], model);
|
||||
App.Overlay.Monitors[App.Overlay.CurrentDesktop].SetLayoutSettings(model);
|
||||
App.FancyZonesEditorIO.SerializeAppliedLayouts();
|
||||
App.FancyZonesEditorIO.SerializeCustomLayouts();
|
||||
}
|
||||
@ -318,7 +318,7 @@ namespace FancyZonesEditor
|
||||
if (mainEditor.CurrentDataContext is LayoutModel model)
|
||||
{
|
||||
_settings.SetAppliedModel(model);
|
||||
App.Overlay.SetLayoutSettings(App.Overlay.Monitors[App.Overlay.CurrentDesktop], model);
|
||||
App.Overlay.Monitors[App.Overlay.CurrentDesktop].SetLayoutSettings(model);
|
||||
App.FancyZonesEditorIO.SerializeAppliedLayouts();
|
||||
App.FancyZonesEditorIO.SerializeCustomLayouts();
|
||||
}
|
||||
@ -366,7 +366,7 @@ namespace FancyZonesEditor
|
||||
_backup = new CanvasLayoutModel(canvas);
|
||||
}
|
||||
|
||||
_defaultLayoutsBackup = new List<LayoutModel>(MainWindowSettingsModel.DefaultLayouts.DefaultLayouts);
|
||||
_defaultLayoutsBackup = new List<LayoutModel>(MainWindowSettingsModel.DefaultLayouts.Layouts);
|
||||
|
||||
Keyboard.ClearFocus();
|
||||
EditLayoutDialogTitle.Text = string.Format(CultureInfo.CurrentCulture, Properties.Resources.Edit_Template, ((LayoutModel)dataContext).Name);
|
||||
@ -480,7 +480,7 @@ namespace FancyZonesEditor
|
||||
// update current settings
|
||||
if (model == _settings.AppliedModel)
|
||||
{
|
||||
App.Overlay.SetLayoutSettings(App.Overlay.Monitors[App.Overlay.CurrentDesktop], model);
|
||||
App.Overlay.Monitors[App.Overlay.CurrentDesktop].SetLayoutSettings(model);
|
||||
}
|
||||
|
||||
App.FancyZonesEditorIO.SerializeAppliedLayouts();
|
||||
@ -528,7 +528,7 @@ namespace FancyZonesEditor
|
||||
{
|
||||
if (monitor.Settings.ZonesetUuid == model.Uuid)
|
||||
{
|
||||
App.Overlay.SetLayoutSettings(monitor, _settings.BlankModel);
|
||||
monitor.SetLayoutSettings(_settings.BlankModel);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ namespace FancyZonesEditor.Models
|
||||
{
|
||||
private static int Count { get; } = Enum.GetValues(typeof(MonitorConfigurationType)).Length;
|
||||
|
||||
public List<LayoutModel> DefaultLayouts { get; } = new List<LayoutModel>(Count);
|
||||
public List<LayoutModel> Layouts { get; } = new List<LayoutModel>(Count);
|
||||
|
||||
public DefaultLayoutsModel()
|
||||
{
|
||||
@ -23,30 +23,39 @@ namespace FancyZonesEditor.Models
|
||||
|
||||
public void Reset(MonitorConfigurationType type)
|
||||
{
|
||||
Set(MainWindowSettingsModel.TemplateModels[(int)LayoutType.PriorityGrid], type);
|
||||
switch (type)
|
||||
{
|
||||
case MonitorConfigurationType.Horizontal:
|
||||
Set(MainWindowSettingsModel.TemplateModels[(int)LayoutType.PriorityGrid], type);
|
||||
break;
|
||||
case MonitorConfigurationType.Vertical:
|
||||
Set(MainWindowSettingsModel.TemplateModels[(int)LayoutType.Rows], type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset(string uuid)
|
||||
{
|
||||
for (int i = 0; i < Count; i++)
|
||||
if (Layouts[(int)MonitorConfigurationType.Horizontal].Uuid == uuid)
|
||||
{
|
||||
if (DefaultLayouts[i].Uuid == uuid)
|
||||
{
|
||||
Set(MainWindowSettingsModel.TemplateModels[(int)LayoutType.PriorityGrid], (MonitorConfigurationType)i);
|
||||
break;
|
||||
}
|
||||
Set(MainWindowSettingsModel.TemplateModels[(int)LayoutType.PriorityGrid], MonitorConfigurationType.Horizontal);
|
||||
}
|
||||
|
||||
if (Layouts[(int)MonitorConfigurationType.Vertical].Uuid == uuid)
|
||||
{
|
||||
Set(MainWindowSettingsModel.TemplateModels[(int)LayoutType.Rows], MonitorConfigurationType.Vertical);
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(LayoutModel layout, MonitorConfigurationType type)
|
||||
{
|
||||
if (DefaultLayouts.Count <= (int)type)
|
||||
if (Layouts.Count <= (int)type)
|
||||
{
|
||||
DefaultLayouts.Insert((int)type, layout);
|
||||
Layouts.Insert((int)type, layout);
|
||||
}
|
||||
else
|
||||
{
|
||||
DefaultLayouts[(int)type] = layout;
|
||||
Layouts[(int)type] = layout;
|
||||
}
|
||||
|
||||
FirePropertyChanged();
|
||||
|
@ -150,7 +150,7 @@ namespace FancyZonesEditor.Models
|
||||
{
|
||||
get
|
||||
{
|
||||
return MainWindowSettingsModel.DefaultLayouts.DefaultLayouts[(int)MonitorConfigurationType.Horizontal].Uuid == this.Uuid;
|
||||
return MainWindowSettingsModel.DefaultLayouts.Layouts[(int)MonitorConfigurationType.Horizontal].Uuid == this.Uuid;
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,7 +158,7 @@ namespace FancyZonesEditor.Models
|
||||
{
|
||||
get
|
||||
{
|
||||
return MainWindowSettingsModel.DefaultLayouts.DefaultLayouts[(int)MonitorConfigurationType.Horizontal].Uuid != this.Uuid;
|
||||
return MainWindowSettingsModel.DefaultLayouts.Layouts[(int)MonitorConfigurationType.Horizontal].Uuid != this.Uuid;
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,7 +166,7 @@ namespace FancyZonesEditor.Models
|
||||
{
|
||||
get
|
||||
{
|
||||
return MainWindowSettingsModel.DefaultLayouts.DefaultLayouts[(int)MonitorConfigurationType.Vertical].Uuid == this.Uuid;
|
||||
return MainWindowSettingsModel.DefaultLayouts.Layouts[(int)MonitorConfigurationType.Vertical].Uuid == this.Uuid;
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ namespace FancyZonesEditor.Models
|
||||
{
|
||||
get
|
||||
{
|
||||
return MainWindowSettingsModel.DefaultLayouts.DefaultLayouts[(int)MonitorConfigurationType.Vertical].Uuid != this.Uuid;
|
||||
return MainWindowSettingsModel.DefaultLayouts.Layouts[(int)MonitorConfigurationType.Vertical].Uuid != this.Uuid;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ namespace FancyZonesEditor
|
||||
|
||||
// set default layouts
|
||||
DefaultLayouts.Set(priorityGridModel, MonitorConfigurationType.Horizontal);
|
||||
DefaultLayouts.Set(priorityGridModel, MonitorConfigurationType.Vertical);
|
||||
DefaultLayouts.Set(rowsModel, MonitorConfigurationType.Vertical);
|
||||
}
|
||||
|
||||
// IsShiftKeyPressed - is the shift key currently being held down
|
||||
@ -261,11 +261,6 @@ namespace FancyZonesEditor
|
||||
}
|
||||
}
|
||||
|
||||
if (foundModel == null)
|
||||
{
|
||||
foundModel = TemplateModels[(int)LayoutType.PriorityGrid];
|
||||
}
|
||||
|
||||
SetSelectedModel(foundModel);
|
||||
SetAppliedModel(foundModel);
|
||||
FirePropertyChanged(nameof(IsCustomLayoutActive));
|
||||
|
@ -14,21 +14,45 @@ namespace FancyZonesEditor.Models
|
||||
{
|
||||
public LayoutOverlayWindow Window { get; private set; }
|
||||
|
||||
public LayoutSettings Settings { get; set; }
|
||||
|
||||
public Device Device { get; set; }
|
||||
|
||||
public LayoutSettings Settings
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_settings != null)
|
||||
{
|
||||
return _settings;
|
||||
}
|
||||
|
||||
return DefaultLayoutSettings;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_settings = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsInitialized
|
||||
{
|
||||
get
|
||||
{
|
||||
return _settings != null;
|
||||
}
|
||||
}
|
||||
|
||||
public MonitorConfigurationType MonitorConfigurationType
|
||||
{
|
||||
get
|
||||
{
|
||||
return Device.MonitorSize.Width > Device.MonitorSize.Height ? MonitorConfigurationType.Horizontal : MonitorConfigurationType.Vertical;
|
||||
}
|
||||
}
|
||||
|
||||
public Monitor(Rect workArea, Size monitorSize)
|
||||
{
|
||||
Window = new LayoutOverlayWindow();
|
||||
Settings = new LayoutSettings();
|
||||
|
||||
// provide a good default for vertical monitors
|
||||
if (monitorSize.Height > monitorSize.Width)
|
||||
{
|
||||
Settings.Type = LayoutType.Rows;
|
||||
}
|
||||
|
||||
Device = new Device(workArea, monitorSize);
|
||||
|
||||
if (App.DebugMode)
|
||||
@ -54,6 +78,8 @@ namespace FancyZonesEditor.Models
|
||||
Device = new Device(monitorName, monitorInstanceId, monitorSerialNumber, virtualDesktop, dpi, workArea, monitorSize);
|
||||
}
|
||||
|
||||
private LayoutSettings _settings;
|
||||
|
||||
public void Scale(double scaleFactor)
|
||||
{
|
||||
Device.Scale(scaleFactor);
|
||||
@ -64,5 +90,48 @@ namespace FancyZonesEditor.Models
|
||||
Window.Width = workArea.Width;
|
||||
Window.Height = workArea.Height;
|
||||
}
|
||||
|
||||
public void SetLayoutSettings(LayoutModel model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_settings == null)
|
||||
{
|
||||
_settings = new LayoutSettings();
|
||||
}
|
||||
|
||||
_settings.ZonesetUuid = model.Uuid;
|
||||
_settings.Type = model.Type;
|
||||
_settings.SensitivityRadius = model.SensitivityRadius;
|
||||
_settings.ZoneCount = model.TemplateZoneCount;
|
||||
|
||||
if (model is GridLayoutModel grid)
|
||||
{
|
||||
_settings.ShowSpacing = grid.ShowSpacing;
|
||||
_settings.Spacing = grid.Spacing;
|
||||
}
|
||||
else
|
||||
{
|
||||
_settings.ShowSpacing = false;
|
||||
_settings.Spacing = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private LayoutSettings DefaultLayoutSettings
|
||||
{
|
||||
get
|
||||
{
|
||||
LayoutSettings settings = new LayoutSettings();
|
||||
if (MonitorConfigurationType == MonitorConfigurationType.Vertical)
|
||||
{
|
||||
settings.Type = LayoutType.Rows;
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -180,30 +180,6 @@ namespace FancyZonesEditor
|
||||
}
|
||||
}
|
||||
|
||||
public void SetLayoutSettings(Monitor monitor, LayoutModel model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
monitor.Settings.ZonesetUuid = model.Uuid;
|
||||
monitor.Settings.Type = model.Type;
|
||||
monitor.Settings.SensitivityRadius = model.SensitivityRadius;
|
||||
monitor.Settings.ZoneCount = model.TemplateZoneCount;
|
||||
|
||||
if (model is GridLayoutModel grid)
|
||||
{
|
||||
monitor.Settings.ShowSpacing = grid.ShowSpacing;
|
||||
monitor.Settings.Spacing = grid.Spacing;
|
||||
}
|
||||
else
|
||||
{
|
||||
monitor.Settings.ShowSpacing = false;
|
||||
monitor.Settings.Spacing = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void OpenEditor(LayoutModel model)
|
||||
{
|
||||
Logger.LogTrace();
|
||||
|
@ -1159,15 +1159,17 @@ namespace FancyZonesEditor.Utils
|
||||
|
||||
foreach (var layout in layouts)
|
||||
{
|
||||
LayoutModel defaultLayoutModel = null;
|
||||
MonitorConfigurationType type = JsonTagToMonitorConfigurationType(layout.MonitorConfiguration);
|
||||
|
||||
if (layout.Layout.Uuid != null && layout.Layout.Uuid != string.Empty)
|
||||
{
|
||||
MonitorConfigurationType type = JsonTagToMonitorConfigurationType(layout.MonitorConfiguration);
|
||||
|
||||
foreach (var customLayout in MainWindowSettingsModel.CustomModels)
|
||||
{
|
||||
if (customLayout.Uuid == layout.Layout.Uuid)
|
||||
{
|
||||
MainWindowSettingsModel.DefaultLayouts.Set(customLayout, type);
|
||||
defaultLayoutModel = customLayout;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1175,8 +1177,28 @@ namespace FancyZonesEditor.Utils
|
||||
else
|
||||
{
|
||||
LayoutType layoutType = JsonTagToLayoutType(layout.Layout.Type);
|
||||
MonitorConfigurationType type = JsonTagToMonitorConfigurationType(layout.MonitorConfiguration);
|
||||
MainWindowSettingsModel.DefaultLayouts.Set(MainWindowSettingsModel.TemplateModels[(int)layoutType], type);
|
||||
defaultLayoutModel = MainWindowSettingsModel.TemplateModels[(int)layoutType];
|
||||
defaultLayoutModel.TemplateZoneCount = layout.Layout.ZoneCount;
|
||||
defaultLayoutModel.SensitivityRadius = layout.Layout.SensitivityRadius;
|
||||
|
||||
if (defaultLayoutModel is GridLayoutModel gridDefaultLayoutModel)
|
||||
{
|
||||
gridDefaultLayoutModel.ShowSpacing = layout.Layout.ShowSpacing;
|
||||
gridDefaultLayoutModel.Spacing = layout.Layout.Spacing;
|
||||
}
|
||||
|
||||
MainWindowSettingsModel.DefaultLayouts.Set(defaultLayoutModel, type);
|
||||
}
|
||||
|
||||
if (defaultLayoutModel != null)
|
||||
{
|
||||
foreach (Monitor monitor in App.Overlay.Monitors)
|
||||
{
|
||||
if (!monitor.IsInitialized && monitor.MonitorConfigurationType == type)
|
||||
{
|
||||
monitor.SetLayoutSettings(defaultLayoutModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
|
||||
/// <summary>
|
||||
/// Gets the list of all open windows
|
||||
/// </summary>
|
||||
internal List<Window> Windows => windows;
|
||||
internal List<Window> Windows => new List<Window>(windows);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an instance property of this class that makes sure that
|
||||
|
@ -7,6 +7,7 @@
|
||||
#ifndef PCH_H
|
||||
#define PCH_H
|
||||
|
||||
#define NOMINMAX
|
||||
// add headers that you want to pre-compile here
|
||||
#include "framework.h"
|
||||
|
||||
|
@ -14,6 +14,7 @@ namespace PowerRenameUI
|
||||
ExplorerItemsSource ExplorerItems { get; };
|
||||
Windows.Foundation.Collections.IObservableVector<PatternSnippet> SearchRegExShortcuts { get; };
|
||||
Windows.Foundation.Collections.IObservableVector<PatternSnippet> DateTimeShortcuts { get; };
|
||||
Windows.Foundation.Collections.IObservableVector<PatternSnippet> CounterShortcuts { get; };
|
||||
|
||||
String OriginalCount;
|
||||
String RenamedCount;
|
||||
|
@ -323,6 +323,8 @@
|
||||
<Flyout x:Name="DateTimeFlyout" ShouldConstrainToRootBounds="False">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
@ -364,7 +366,45 @@
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
|
||||
<TextBlock x:Uid="CounterCheatSheet_Title"
|
||||
Margin="0,10,0,0"
|
||||
FontWeight="SemiBold" Grid.Row="2" />
|
||||
<ListView Margin="-4,12,0,0"
|
||||
IsItemClickEnabled="True"
|
||||
ItemClick="DateTimeItemClick"
|
||||
ItemsSource="{x:Bind CounterShortcuts}"
|
||||
SelectionMode="None" Grid.Row="3">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate
|
||||
x:DataType="local:PatternSnippet">
|
||||
<Grid Margin="-10,0,0,0"
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition
|
||||
Width="Auto" />
|
||||
<ColumnDefinition
|
||||
Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border Padding="8"
|
||||
HorizontalAlignment="Left"
|
||||
Background="{ThemeResource ButtonBackground}"
|
||||
BorderBrush="{ThemeResource ButtonBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<TextBlock
|
||||
FontFamily="Consolas"
|
||||
Foreground="{ThemeResource ButtonForeground}"
|
||||
Text="{x:Bind Code}" />
|
||||
</Border>
|
||||
<TextBlock Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Text="{x:Bind Description}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</Grid>
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
@ -391,9 +431,9 @@
|
||||
HorizontalAlignment="Stretch"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=ApplyToLabel}"
|
||||
SelectedIndex="0">
|
||||
<x:String>Filename + extension</x:String>
|
||||
<x:String>Filename only</x:String>
|
||||
<x:String>Extension only</x:String>
|
||||
<ComboBoxItem x:Uid="RenameParts_FilenameAndExtension" />
|
||||
<ComboBoxItem x:Uid="RenameParts_FilenameOnly" />
|
||||
<ComboBoxItem x:Uid="RenameParts_ExtensionOnly" />
|
||||
</ComboBox>
|
||||
<AppBarSeparator Margin="5,0,5,0" />
|
||||
<ToggleButton
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "microsoft.ui.xaml.window.h"
|
||||
#include <winrt/Microsoft.UI.Interop.h>
|
||||
#include <winrt/Windows.UI.ViewManagement.h>
|
||||
#include <winrt/Microsoft.UI.Windowing.h>
|
||||
#include <common/Themes/theme_helpers.h>
|
||||
#include <common/Themes/theme_listener.h>
|
||||
@ -133,8 +134,7 @@ namespace winrt::PowerRenameUI::implementation
|
||||
GetDpiForMonitor(hMonitor, MONITOR_DPI_TYPE::MDT_EFFECTIVE_DPI, &x_dpi, &x_dpi);
|
||||
UINT window_dpi = GetDpiForWindow(m_window);
|
||||
|
||||
int width = 1400;
|
||||
int height = 800;
|
||||
const auto& [width, height] = CSettingsInstance().GetLastWindowSize();
|
||||
|
||||
winrt::Windows::Graphics::RectInt32 rect;
|
||||
// Scale window size
|
||||
@ -196,6 +196,13 @@ namespace winrt::PowerRenameUI::implementation
|
||||
m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$ff", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_MilliSeconds2D").ValueAsString()));
|
||||
m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$f", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_MilliSeconds1D").ValueAsString()));
|
||||
|
||||
m_CounterShortcuts = winrt::single_threaded_observable_vector<PowerRenameUI::PatternSnippet>();
|
||||
m_CounterShortcuts.Append(winrt::make<PatternSnippet>(L"${}", manager.MainResourceMap().GetValue(L"Resources/CounterCheatSheet_Simple").ValueAsString()));
|
||||
m_CounterShortcuts.Append(winrt::make<PatternSnippet>(L"${start=10}", manager.MainResourceMap().GetValue(L"Resources/CounterCheatSheet_Start").ValueAsString()));
|
||||
m_CounterShortcuts.Append(winrt::make<PatternSnippet>(L"${increment=5}", manager.MainResourceMap().GetValue(L"Resources/CounterCheatSheet_Increment").ValueAsString()));
|
||||
m_CounterShortcuts.Append(winrt::make<PatternSnippet>(L"${padding=8}", manager.MainResourceMap().GetValue(L"Resources/CounterCheatSheet_Padding").ValueAsString()));
|
||||
m_CounterShortcuts.Append(winrt::make<PatternSnippet>(L"${increment=3,padding=4,start=900}", manager.MainResourceMap().GetValue(L"Resources/CounterCheatSheet_Complex").ValueAsString()));
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
listView_ExplorerItems().ApplyTemplate();
|
||||
@ -278,6 +285,23 @@ namespace winrt::PowerRenameUI::implementation
|
||||
InitAutoComplete();
|
||||
SearchReplaceChanged();
|
||||
InvalidateItemListViewState();
|
||||
|
||||
SizeChanged({ this, &MainWindow::OnSizeChanged });
|
||||
Closed({ this, &MainWindow::OnClosed });
|
||||
}
|
||||
|
||||
void MainWindow::OnSizeChanged(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::WindowSizeChangedEventArgs const& /*args*/)
|
||||
{
|
||||
const auto appWindow =
|
||||
Microsoft::UI::Windowing::AppWindow::GetFromWindowId(Microsoft::UI::GetWindowIdFromWindow(m_window));
|
||||
const auto [width, height] = appWindow.Size();
|
||||
|
||||
CSettingsInstance().UpdateLastWindowSize(static_cast<int>(width), static_cast<int>(height));
|
||||
}
|
||||
|
||||
void MainWindow::OnClosed(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::WindowEventArgs const&)
|
||||
{
|
||||
CSettingsInstance().Save();
|
||||
}
|
||||
|
||||
void MainWindow::InvalidateItemListViewState()
|
||||
|
@ -74,6 +74,9 @@ namespace winrt::PowerRenameUI::implementation
|
||||
|
||||
MainWindow();
|
||||
|
||||
void OnSizeChanged(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::WindowSizeChangedEventArgs const&);
|
||||
void OnClosed(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::WindowEventArgs const&);
|
||||
|
||||
void InvalidateItemListViewState();
|
||||
|
||||
Windows::Foundation::Collections::IObservableVector<hstring> SearchMRU() { return m_searchMRUList; }
|
||||
@ -81,6 +84,8 @@ namespace winrt::PowerRenameUI::implementation
|
||||
PowerRenameUI::ExplorerItemsSource ExplorerItems() { return m_explorerItems; }
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUI::PatternSnippet> SearchRegExShortcuts() { return m_searchRegExShortcuts; }
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUI::PatternSnippet> DateTimeShortcuts() { return m_dateTimeShortcuts; }
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUI::PatternSnippet> CounterShortcuts() { return m_CounterShortcuts; }
|
||||
|
||||
hstring OriginalCount();
|
||||
void OriginalCount(hstring value);
|
||||
hstring RenamedCount();
|
||||
@ -93,6 +98,7 @@ namespace winrt::PowerRenameUI::implementation
|
||||
void ShowRenamed(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);
|
||||
|
||||
private:
|
||||
winrt::Windows::Foundation::Size m_lastWindowSize;
|
||||
bool m_allSelected;
|
||||
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<hstring> m_searchMRUList;
|
||||
@ -100,6 +106,7 @@ namespace winrt::PowerRenameUI::implementation
|
||||
PowerRenameUI::ExplorerItemsSource m_explorerItems;
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUI::PatternSnippet> m_searchRegExShortcuts;
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUI::PatternSnippet> m_dateTimeShortcuts;
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUI::PatternSnippet> m_CounterShortcuts;
|
||||
|
||||
// Used by PowerRenameManagerEvents
|
||||
HRESULT OnRename(_In_ IPowerRenameItem* renameItem);
|
||||
|
@ -150,6 +150,24 @@
|
||||
<data name="ReplaceBox.PlaceholderText" xml:space="preserve">
|
||||
<value>Replace with</value>
|
||||
</data>
|
||||
<data name="CounterCheatSheet_Title.Text" xml:space="preserve">
|
||||
<value>Replace using advanced counter syntax.</value>
|
||||
</data>
|
||||
<data name="CounterCheatSheet_Simple" xml:space="preserve">
|
||||
<value>A simple counter that you can use anywhere in a replace string.</value>
|
||||
</data>
|
||||
<data name="CounterCheatSheet_Start" xml:space="preserve">
|
||||
<value>A counter with a customized start value.</value>
|
||||
</data>
|
||||
<data name="CounterCheatSheet_Increment" xml:space="preserve">
|
||||
<value>A counter with a customized increment value.</value>
|
||||
</data>
|
||||
<data name="CounterCheatSheet_Padding" xml:space="preserve">
|
||||
<value>A counter with a customized number of leading padding zeroes.</value>
|
||||
</data>
|
||||
<data name="CounterCheatSheet_Complex" xml:space="preserve">
|
||||
<value>A counter showing multiple customized properties.</value>
|
||||
</data>
|
||||
<data name="DateTimeCheatSheet_Title.Text" xml:space="preserve">
|
||||
<value>Replace using file creation date and time</value>
|
||||
</data>
|
||||
@ -336,6 +354,13 @@
|
||||
<data name="ErrorMessage_InvalidChar" xml:space="preserve">
|
||||
<value>File name contains invalid character(s):
 > < | " : ? * \ /</value>
|
||||
</data>
|
||||
|
||||
|
||||
<data name="RenameParts_FilenameAndExtension.Content" xml:space="preserve">
|
||||
<value>Filename + extension</value>
|
||||
</data>
|
||||
<data name="RenameParts_FilenameOnly.Content" xml:space="preserve">
|
||||
<value>Filename only</value>
|
||||
</data>
|
||||
<data name="RenameParts_ExtensionOnly.Content" xml:space="preserve">
|
||||
<value>Extension only</value>
|
||||
</data>
|
||||
</root>
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "targetver.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#define NOMINMAX
|
||||
// Windows Header Files:
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
|
46
src/modules/powerrename/lib/Enumerating.cpp
Normal file
46
src/modules/powerrename/lib/Enumerating.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include <pch.h>
|
||||
|
||||
#include "Enumerating.h"
|
||||
|
||||
#include <common\utils\string_utils.h>
|
||||
|
||||
std::vector<EnumOptions> parseEnumOptions(const std::wstring& replaceWith)
|
||||
{
|
||||
static const std::wregex enumStartRegex(LR"(start=(\d+))");
|
||||
static const std::wregex enumIncrementRegex(LR"(increment=(-?\d+))");
|
||||
static const std::wregex enumPaddingRegex(LR"(padding=(\d+))");
|
||||
|
||||
std::string buf;
|
||||
std::vector<EnumOptions> options;
|
||||
std::wregex enumGroupRegex(LR"(\$\{.*?\})");
|
||||
for (std::wsregex_iterator i{ begin(replaceWith), end(replaceWith), enumGroupRegex }, end; i != end; ++i)
|
||||
{
|
||||
std::wsmatch match = *i;
|
||||
std::wstring matchString = match.str();
|
||||
|
||||
EnumOptions option;
|
||||
option.replaceStrSpan.offset = match.position();
|
||||
option.replaceStrSpan.length = match.length();
|
||||
|
||||
std::wsmatch subMatch;
|
||||
if (std::regex_search(matchString, subMatch, enumStartRegex))
|
||||
{
|
||||
buf = unwide(subMatch[1].str());
|
||||
std::from_chars(buf.data(), buf.data() + buf.size(), option.start.emplace());
|
||||
}
|
||||
if (std::regex_search(matchString, subMatch, enumIncrementRegex))
|
||||
{
|
||||
buf = unwide(subMatch[1].str());
|
||||
std::from_chars(buf.data(), buf.data() + buf.size(), option.increment.emplace());
|
||||
}
|
||||
if (std::regex_search(matchString, subMatch, enumPaddingRegex))
|
||||
{
|
||||
buf = unwide(subMatch[1].str());
|
||||
std::from_chars(buf.data(), buf.data() + buf.size(), option.padding.emplace());
|
||||
}
|
||||
|
||||
options.emplace_back(std::move(option));
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
55
src/modules/powerrename/lib/Enumerating.h
Normal file
55
src/modules/powerrename/lib/Enumerating.h
Normal file
@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
struct EnumSpan
|
||||
{
|
||||
size_t offset = 0;
|
||||
size_t length = 0;
|
||||
};
|
||||
|
||||
struct EnumOptions
|
||||
{
|
||||
std::optional<int> start;
|
||||
std::optional<int> increment;
|
||||
std::optional<uint32_t> padding;
|
||||
|
||||
EnumSpan replaceStrSpan;
|
||||
|
||||
std::strong_ordering operator<=>(const EnumOptions& rhs) const noexcept
|
||||
{
|
||||
return std::make_tuple(start, increment, padding) <=> std::make_tuple(rhs.start, rhs.increment, rhs.padding);
|
||||
}
|
||||
|
||||
bool operator==(const EnumOptions& rhs) const noexcept
|
||||
{
|
||||
return std::make_tuple(start, increment, padding) == std::make_tuple(rhs.start, rhs.increment, rhs.padding);
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<EnumOptions> parseEnumOptions(const std::wstring& replaceWith);
|
||||
|
||||
struct Enumerator
|
||||
{
|
||||
inline Enumerator(EnumOptions options) :
|
||||
start{ options.start.value_or(0) }, increment{ options.increment.value_or(1) }, padding{ options.padding.value_or(0) }, replaceStrSpan{ options.replaceStrSpan }
|
||||
{
|
||||
}
|
||||
|
||||
inline int32_t enumerate(const unsigned long index) const { return start + static_cast<int32_t>(index * increment); }
|
||||
|
||||
inline size_t printTo(wchar_t* buf, const size_t bufSize, const unsigned long index) const
|
||||
{
|
||||
const int32_t enumeratedIndex = enumerate(index);
|
||||
wchar_t format[32];
|
||||
swprintf_s(format, sizeof(format) / sizeof(wchar_t), L"%%0%ud", padding);
|
||||
return swprintf_s(buf, bufSize, format, enumeratedIndex);
|
||||
}
|
||||
|
||||
EnumSpan replaceStrSpan;
|
||||
|
||||
private:
|
||||
int start;
|
||||
int increment;
|
||||
uint32_t padding;
|
||||
};
|
@ -188,7 +188,7 @@ HRESULT GetTransformedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR sour
|
||||
{
|
||||
hr = StringCchCopy(result, cchMax, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (flags & Capitalized)
|
||||
{
|
||||
if (!(flags & ExtensionOnly))
|
||||
@ -234,15 +234,13 @@ HRESULT GetTransformedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR sour
|
||||
return hr;
|
||||
}
|
||||
|
||||
bool isFileTimeUsed(_In_ PCWSTR source)
|
||||
bool isFileTimeUsed(_In_ PCWSTR source)
|
||||
{
|
||||
bool used = false;
|
||||
std::wstring patterns[] = { L"(([^\\$]|^)(\\$\\$)*)\\$Y", L"(([^\\$]|^)(\\$\\$)*)\\$M", L"(([^\\$]|^)(\\$\\$)*)\\$D",
|
||||
L"(([^\\$]|^)(\\$\\$)*)\\$h", L"(([^\\$]|^)(\\$\\$)*)\\$m", L"(([^\\$]|^)(\\$\\$)*)\\$s", L"(([^\\$]|^)(\\$\\$)*)\\$f" };
|
||||
size_t patternsLength = ARRAYSIZE(patterns);
|
||||
for (size_t i = 0; !used && i < patternsLength; i++)
|
||||
static const std::array patterns = { std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$Y" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$M" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$D" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$h" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$m" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$s" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$f" } };
|
||||
for (size_t i = 0; !used && i < patterns.size(); i++)
|
||||
{
|
||||
if (std::regex_search(source, std::wregex(patterns[i])))
|
||||
if (std::regex_search(source, patterns[i]))
|
||||
{
|
||||
used = true;
|
||||
}
|
||||
@ -253,7 +251,7 @@ bool isFileTimeUsed(_In_ PCWSTR source)
|
||||
HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SYSTEMTIME fileTime)
|
||||
{
|
||||
std::locale::global(std::locale(""));
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
if (source && wcslen(source) > 0)
|
||||
{
|
||||
std::wstring res(source);
|
||||
@ -274,17 +272,17 @@ HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SY
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", (fileTime.wYear % 10));
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$Y"), replaceTerm);
|
||||
|
||||
|
||||
GetDateFormatEx(localeName, NULL, &fileTime, L"MMMM", formattedDate, MAX_PATH, NULL);
|
||||
formattedDate[0] = towupper(formattedDate[0]);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%s"), L"$01", formattedDate);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$MMMM"), replaceTerm);
|
||||
|
||||
|
||||
GetDateFormatEx(localeName, NULL, &fileTime, L"MMM", formattedDate, MAX_PATH, NULL);
|
||||
formattedDate[0] = towupper(formattedDate[0]);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%s"), L"$01", formattedDate);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$MMM"), replaceTerm);
|
||||
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%02d"), L"$01", fileTime.wMonth);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$MM"), replaceTerm);
|
||||
|
||||
@ -295,7 +293,7 @@ HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SY
|
||||
formattedDate[0] = towupper(formattedDate[0]);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%s"), L"$01", formattedDate);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$DDDD"), replaceTerm);
|
||||
|
||||
|
||||
GetDateFormatEx(localeName, NULL, &fileTime, L"ddd", formattedDate, MAX_PATH, NULL);
|
||||
formattedDate[0] = towupper(formattedDate[0]);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%s"), L"$01", formattedDate);
|
||||
@ -328,10 +326,10 @@ HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SY
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%03d"), L"$01", fileTime.wMilliseconds);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$fff"), replaceTerm);
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%02d"), L"$01", fileTime.wMilliseconds/10);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%02d"), L"$01", fileTime.wMilliseconds / 10);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$ff"), replaceTerm);
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", fileTime.wMilliseconds/100);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", fileTime.wMilliseconds / 100);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$f"), replaceTerm);
|
||||
|
||||
hr = StringCchCopy(result, cchMax, res.c_str());
|
||||
|
@ -102,7 +102,10 @@ HRESULT CPowerRenameEnum::_ParseEnumItems(_In_ IEnumShellItems* pesi, _In_ int d
|
||||
l->Compare(r, SICHINT_DISPLAY, &res);
|
||||
return res < 0;
|
||||
};
|
||||
std::sort(begin(items), end(items), cmpShellItems);
|
||||
|
||||
// We need to sort only the first layer, because later ones are enumerated correctly
|
||||
if (depth == 0)
|
||||
std::sort(begin(items), end(items), cmpShellItems);
|
||||
|
||||
for (const auto& item : items)
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
IFACEMETHOD(PutFlags)(_In_ DWORD flags) = 0;
|
||||
IFACEMETHOD(PutFileTime)(_In_ SYSTEMTIME fileTime) = 0;
|
||||
IFACEMETHOD(ResetFileTime)() = 0;
|
||||
IFACEMETHOD(Replace)(_In_ PCWSTR source, _Outptr_ PWSTR* result) = 0;
|
||||
IFACEMETHOD(Replace)(_In_ PCWSTR source, _Outptr_ PWSTR* result, unsigned long& enumIndex) = 0;
|
||||
};
|
||||
|
||||
interface __declspec(uuid("C7F59201-4DE1-4855-A3A2-26FC3279C8A5")) IPowerRenameItem : public IUnknown
|
||||
|
@ -31,6 +31,7 @@
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Enumerating.h" />
|
||||
<ClInclude Include="Helpers.h" />
|
||||
<ClInclude Include="MRUListHandler.h" />
|
||||
<ClInclude Include="PowerRenameEnum.h" />
|
||||
@ -47,6 +48,7 @@
|
||||
<ClInclude Include="trace.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Enumerating.cpp" />
|
||||
<ClCompile Include="Helpers.cpp" />
|
||||
<ClCompile Include="MRUListHandler.cpp" />
|
||||
<ClCompile Include="PowerRenameEnum.cpp" />
|
||||
|
@ -923,7 +923,7 @@ DWORD WINAPI CPowerRenameManager::s_regexWorkerThread(_In_ void* pv)
|
||||
winrt::check_hresult(pwtd->spsrm->GetRenameRegEx(&spRenameRegEx));
|
||||
|
||||
UINT itemCount = 0;
|
||||
unsigned long itemEnumIndex = 1;
|
||||
unsigned long itemEnumIndex = 0;
|
||||
winrt::check_hresult(pwtd->spsrm->GetItemCount(&itemCount));
|
||||
|
||||
for (UINT u = 0; u < itemCount; u++)
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "pch.h"
|
||||
#include "PowerRenameRegEx.h"
|
||||
#include "Enumerating.h"
|
||||
#include "Settings.h"
|
||||
#include <regex>
|
||||
#include <string>
|
||||
@ -7,15 +8,17 @@
|
||||
#include <boost/regex.hpp>
|
||||
#include <helpers.h>
|
||||
|
||||
using namespace std;
|
||||
using std::conditional_t;
|
||||
using std::regex_error;
|
||||
|
||||
IFACEMETHODIMP_(ULONG) CPowerRenameRegEx::AddRef()
|
||||
IFACEMETHODIMP_(ULONG)
|
||||
CPowerRenameRegEx::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&m_refCount);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) CPowerRenameRegEx::Release()
|
||||
IFACEMETHODIMP_(ULONG)
|
||||
CPowerRenameRegEx::Release()
|
||||
{
|
||||
long refCount = InterlockedDecrement(&m_refCount);
|
||||
|
||||
@ -127,6 +130,26 @@ IFACEMETHODIMP CPowerRenameRegEx::GetReplaceTerm(_Outptr_ PWSTR* replaceTerm)
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CPowerRenameRegEx::_OnEnumerateItemsChanged()
|
||||
{
|
||||
m_enumerators.clear();
|
||||
const auto options = parseEnumOptions(m_RawReplaceTerm);
|
||||
for (const auto e : options)
|
||||
m_enumerators.emplace_back(e);
|
||||
|
||||
m_replaceWithEnumeratorOffsets.clear();
|
||||
std::wstring replaceWith{ m_RawReplaceTerm };
|
||||
// Remove counter expressions and calculate their offsets in replaceWith string.
|
||||
int32_t offset = 0;
|
||||
for (const auto& e : options)
|
||||
{
|
||||
replaceWith.erase(e.replaceStrSpan.offset + offset, e.replaceStrSpan.length);
|
||||
m_replaceWithEnumeratorOffsets.push_back(offset);
|
||||
offset -= static_cast<int32_t>(e.replaceStrSpan.length);
|
||||
}
|
||||
return SHStrDup(replaceWith.data(), &m_replaceTerm);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP CPowerRenameRegEx::PutReplaceTerm(_In_ PCWSTR replaceTerm, bool forceRenaming)
|
||||
{
|
||||
bool changed = false || forceRenaming;
|
||||
@ -134,11 +157,16 @@ IFACEMETHODIMP CPowerRenameRegEx::PutReplaceTerm(_In_ PCWSTR replaceTerm, bool f
|
||||
if (replaceTerm)
|
||||
{
|
||||
CSRWExclusiveAutoLock lock(&m_lock);
|
||||
if (m_replaceTerm == nullptr || lstrcmp(replaceTerm, m_replaceTerm) != 0)
|
||||
if (m_replaceTerm == nullptr || lstrcmp(replaceTerm, m_RawReplaceTerm.c_str()) != 0)
|
||||
{
|
||||
changed = true;
|
||||
CoTaskMemFree(m_replaceTerm);
|
||||
hr = SHStrDup(replaceTerm, &m_replaceTerm);
|
||||
m_RawReplaceTerm = replaceTerm;
|
||||
|
||||
if (m_flags & EnumerateItems)
|
||||
hr = _OnEnumerateItemsChanged();
|
||||
else
|
||||
hr = SHStrDup(replaceTerm, &m_replaceTerm);
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,7 +188,20 @@ IFACEMETHODIMP CPowerRenameRegEx::PutFlags(_In_ DWORD flags)
|
||||
{
|
||||
if (m_flags != flags)
|
||||
{
|
||||
const bool newEnumerate = flags & EnumerateItems;
|
||||
const bool refreshReplaceTerm = !!(m_flags & EnumerateItems) != newEnumerate;
|
||||
m_flags = flags;
|
||||
if (refreshReplaceTerm)
|
||||
{
|
||||
CSRWExclusiveAutoLock lock(&m_lock);
|
||||
if (newEnumerate)
|
||||
_OnEnumerateItemsChanged();
|
||||
else
|
||||
{
|
||||
CoTaskMemFree(m_replaceTerm);
|
||||
SHStrDup(m_RawReplaceTerm.c_str(), &m_replaceTerm);
|
||||
}
|
||||
}
|
||||
_OnFlagsChanged();
|
||||
}
|
||||
return S_OK;
|
||||
@ -202,7 +243,7 @@ HRESULT CPowerRenameRegEx::s_CreateInstance(_Outptr_ IPowerRenameRegEx** renameR
|
||||
{
|
||||
*renameRegEx = nullptr;
|
||||
|
||||
CPowerRenameRegEx *newRenameRegEx = new CPowerRenameRegEx();
|
||||
CPowerRenameRegEx* newRenameRegEx = new CPowerRenameRegEx();
|
||||
HRESULT hr = E_OUTOFMEMORY;
|
||||
if (newRenameRegEx)
|
||||
{
|
||||
@ -228,7 +269,20 @@ CPowerRenameRegEx::~CPowerRenameRegEx()
|
||||
CoTaskMemFree(m_replaceTerm);
|
||||
}
|
||||
|
||||
HRESULT CPowerRenameRegEx::Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result)
|
||||
template<bool Std, class Regex = conditional_t<Std, std::wregex, boost::wregex>, class Options = decltype(Regex::icase)>
|
||||
static std::wstring RegexReplaceEx(const std::wstring& source, const std::wstring& searchTerm, const std::wstring& replaceTerm, const bool matchAll, const bool caseInsensitive)
|
||||
{
|
||||
Regex pattern(searchTerm, Options::ECMAScript | (caseInsensitive ? Options::icase : Options{}));
|
||||
|
||||
using Flags = conditional_t<Std, std::regex_constants::match_flag_type, boost::regex_constants::match_flags>;
|
||||
const auto flags = matchAll ? Flags::match_default : Flags::format_first_only;
|
||||
|
||||
return regex_replace(source, pattern, replaceTerm, flags);
|
||||
}
|
||||
|
||||
static constexpr std::array RegexReplaceDispatch = { RegexReplaceEx<true>, RegexReplaceEx<false> };
|
||||
|
||||
HRESULT CPowerRenameRegEx::Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result, unsigned long& enumIndex)
|
||||
{
|
||||
*result = nullptr;
|
||||
|
||||
@ -238,7 +292,7 @@ HRESULT CPowerRenameRegEx::Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result)
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
wstring res = source;
|
||||
std::wstring res = source;
|
||||
try
|
||||
{
|
||||
// TODO: creating the regex could be costly. May want to cache this.
|
||||
@ -250,47 +304,49 @@ HRESULT CPowerRenameRegEx::Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result)
|
||||
fileTimeErrorOccurred = true;
|
||||
}
|
||||
|
||||
std::wstring sourceToUse(source);
|
||||
std::wstring sourceToUse;
|
||||
std::wstring originalSource;
|
||||
sourceToUse.reserve(MAX_PATH);
|
||||
originalSource.reserve(MAX_PATH);
|
||||
sourceToUse = source;
|
||||
originalSource = sourceToUse;
|
||||
|
||||
std::wstring searchTerm(m_searchTerm);
|
||||
std::wstring replaceTerm(L"");
|
||||
std::wstring replaceTerm;
|
||||
if (m_useFileTime && !fileTimeErrorOccurred)
|
||||
{
|
||||
replaceTerm = wstring(newReplaceTerm);
|
||||
replaceTerm = newReplaceTerm;
|
||||
}
|
||||
else if (m_replaceTerm)
|
||||
{
|
||||
replaceTerm = wstring(m_replaceTerm);
|
||||
replaceTerm = m_replaceTerm;
|
||||
}
|
||||
|
||||
replaceTerm = regex_replace(replaceTerm, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$[0]"), L"$1$$$0");
|
||||
replaceTerm = regex_replace(replaceTerm, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$([1-9])"), L"$1$0$4");
|
||||
static const std::wregex zeroGroupRegex(L"(([^\\$]|^)(\\$\\$)*)\\$[0]");
|
||||
static const std::wregex otherGroupsRegex(L"(([^\\$]|^)(\\$\\$)*)\\$([1-9])");
|
||||
|
||||
if (m_flags & EnumerateItems)
|
||||
{
|
||||
std::array<wchar_t, MAX_PATH> buffer;
|
||||
int32_t offset = 0;
|
||||
|
||||
for (size_t ei = 0; ei < m_enumerators.size(); ++ei)
|
||||
{
|
||||
const auto& e = m_enumerators[ei];
|
||||
const auto replacementLength = static_cast<int32_t>(e.printTo(buffer.data(), buffer.size(), enumIndex));
|
||||
replaceTerm.insert(e.replaceStrSpan.offset + offset + m_replaceWithEnumeratorOffsets[ei], buffer.data());
|
||||
offset += replacementLength;
|
||||
}
|
||||
}
|
||||
|
||||
bool replacedSomething = false;
|
||||
if (m_flags & UseRegularExpressions)
|
||||
{
|
||||
if (_useBoostLib)
|
||||
{
|
||||
boost::wregex pattern(m_searchTerm, (!(m_flags & CaseSensitive)) ? boost::regex::icase | boost::regex::ECMAScript : boost::regex::ECMAScript);
|
||||
if (m_flags & MatchAllOccurrences)
|
||||
{
|
||||
res = boost::regex_replace(wstring(source), pattern, replaceTerm);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = boost::regex_replace(wstring(source), pattern, replaceTerm, boost::regex_constants::format_first_only);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::wregex pattern(m_searchTerm, (!(m_flags & CaseSensitive)) ? regex_constants::icase | regex_constants::ECMAScript : regex_constants::ECMAScript);
|
||||
if (m_flags & MatchAllOccurrences)
|
||||
{
|
||||
res = regex_replace(wstring(source), pattern, replaceTerm);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = regex_replace(wstring(source), pattern, replaceTerm, regex_constants::format_first_only);
|
||||
}
|
||||
}
|
||||
replaceTerm = regex_replace(replaceTerm, zeroGroupRegex, L"$1$$$0");
|
||||
replaceTerm = regex_replace(replaceTerm, otherGroupsRegex, L"$1$0$4");
|
||||
|
||||
res = RegexReplaceDispatch[_useBoostLib](source, m_searchTerm, replaceTerm, m_flags & MatchAllOccurrences, !(m_flags & CaseSensitive));
|
||||
replacedSomething = originalSource != res;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -303,16 +359,17 @@ HRESULT CPowerRenameRegEx::Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result)
|
||||
{
|
||||
res = sourceToUse.replace(pos, searchTerm.length(), replaceTerm);
|
||||
pos += replaceTerm.length();
|
||||
replacedSomething = true;
|
||||
}
|
||||
|
||||
if (!(m_flags & MatchAllOccurrences))
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (pos != std::string::npos);
|
||||
}
|
||||
|
||||
hr = SHStrDup(res.c_str(), result);
|
||||
if (replacedSomething)
|
||||
enumIndex++;
|
||||
}
|
||||
catch (regex_error e)
|
||||
{
|
||||
|
@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "srwlock.h"
|
||||
|
||||
#include "Enumerating.h"
|
||||
#include "PowerRenameInterfaces.h"
|
||||
|
||||
#define DEFAULT_FLAGS 0
|
||||
@ -12,7 +11,7 @@ class CPowerRenameRegEx : public IPowerRenameRegEx
|
||||
{
|
||||
public:
|
||||
// IUnknown
|
||||
IFACEMETHODIMP QueryInterface(_In_ REFIID iid, _Outptr_ void** resultInterface);
|
||||
IFACEMETHODIMP QueryInterface(_In_ REFIID iid, _Outptr_ void** resultInterface);
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP_(ULONG) Release();
|
||||
|
||||
@ -27,9 +26,9 @@ public:
|
||||
IFACEMETHODIMP PutFlags(_In_ DWORD flags);
|
||||
IFACEMETHODIMP PutFileTime(_In_ SYSTEMTIME fileTime);
|
||||
IFACEMETHODIMP ResetFileTime();
|
||||
IFACEMETHODIMP Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result);
|
||||
IFACEMETHODIMP Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result, unsigned long& enumIndex);
|
||||
|
||||
static HRESULT s_CreateInstance(_Outptr_ IPowerRenameRegEx **renameRegEx);
|
||||
static HRESULT s_CreateInstance(_Outptr_ IPowerRenameRegEx** renameRegEx);
|
||||
|
||||
protected:
|
||||
CPowerRenameRegEx();
|
||||
@ -39,6 +38,7 @@ protected:
|
||||
void _OnReplaceTermChanged();
|
||||
void _OnFlagsChanged();
|
||||
void _OnFileTimeChanged();
|
||||
HRESULT _OnEnumerateItemsChanged();
|
||||
|
||||
size_t _Find(std::wstring data, std::wstring toSearch, bool caseInsensitive, size_t pos);
|
||||
|
||||
@ -46,8 +46,9 @@ protected:
|
||||
DWORD m_flags = DEFAULT_FLAGS;
|
||||
PWSTR m_searchTerm = nullptr;
|
||||
PWSTR m_replaceTerm = nullptr;
|
||||
std::wstring m_RawReplaceTerm;
|
||||
|
||||
SYSTEMTIME m_fileTime = {0};
|
||||
SYSTEMTIME m_fileTime = { 0 };
|
||||
bool m_useFileTime = false;
|
||||
|
||||
CSRWLock m_lock;
|
||||
@ -55,6 +56,9 @@ protected:
|
||||
|
||||
DWORD m_cookie = 0;
|
||||
|
||||
std::vector<Enumerator> m_enumerators;
|
||||
std::vector<int32_t> m_replaceWithEnumeratorOffsets;
|
||||
|
||||
struct RENAME_REGEX_EVENT
|
||||
{
|
||||
IPowerRenameRegExEvents* pEvents;
|
||||
|
@ -86,7 +86,7 @@ bool DoRename(CComPtr<IPowerRenameRegEx>& spRenameRegEx, unsigned long& itemEnum
|
||||
|
||||
// Failure here means we didn't match anything or had nothing to match
|
||||
// Call put_newName with null in that case to reset it
|
||||
winrt::check_hresult(spRenameRegEx->Replace(sourceName, &newName));
|
||||
winrt::check_hresult(spRenameRegEx->Replace(sourceName, &newName, itemEnumIndex));
|
||||
|
||||
if (useFileTime)
|
||||
{
|
||||
@ -166,17 +166,6 @@ bool DoRename(CComPtr<IPowerRenameRegEx>& spRenameRegEx, unsigned long& itemEnum
|
||||
newNameToUse = nullptr;
|
||||
}
|
||||
|
||||
wchar_t uniqueName[MAX_PATH] = { 0 };
|
||||
if (newNameToUse != nullptr && (flags & EnumerateItems))
|
||||
{
|
||||
unsigned long countUsed = 0;
|
||||
if (GetEnumeratedFileName(uniqueName, ARRAYSIZE(uniqueName), newNameToUse, nullptr, itemEnumIndex, &countUsed))
|
||||
{
|
||||
newNameToUse = uniqueName;
|
||||
}
|
||||
itemEnumIndex++;
|
||||
}
|
||||
|
||||
spItem->PutStatus(PowerRenameItemRenameStatus::ShouldRename);
|
||||
if (newNameToUse != nullptr)
|
||||
{
|
||||
|
@ -25,6 +25,8 @@ namespace
|
||||
const wchar_t c_replaceText[] = L"ReplaceText";
|
||||
const wchar_t c_mruEnabled[] = L"MRUEnabled";
|
||||
const wchar_t c_useBoostLib[] = L"UseBoostLib";
|
||||
const wchar_t c_lastWindowWidth[] = L"LastWindowWidth";
|
||||
const wchar_t c_lastWindowHeight[] = L"LastWindowHeight";
|
||||
|
||||
}
|
||||
|
||||
@ -49,6 +51,8 @@ void CSettings::Save()
|
||||
jsonData.SetNamedValue(c_searchText, json::value(settings.searchText));
|
||||
jsonData.SetNamedValue(c_replaceText, json::value(settings.replaceText));
|
||||
jsonData.SetNamedValue(c_useBoostLib, json::value(settings.useBoostLib));
|
||||
jsonData.SetNamedValue(c_lastWindowWidth, json::value(settings.lastWindowWidth));
|
||||
jsonData.SetNamedValue(c_lastWindowHeight, json::value(settings.lastWindowHeight));
|
||||
|
||||
json::to_file(jsonFilePath, jsonData);
|
||||
GetSystemTimeAsFileTime(&lastLoadedTime);
|
||||
@ -139,6 +143,9 @@ void CSettings::ParseJson()
|
||||
{
|
||||
settings.useBoostLib = jsonSettings.GetNamedBoolean(c_useBoostLib);
|
||||
}
|
||||
|
||||
settings.lastWindowWidth = static_cast<int>(jsonSettings.GetNamedNumber(c_lastWindowWidth, DEFAULT_WINDOW_WIDTH));
|
||||
settings.lastWindowHeight = static_cast<int>(jsonSettings.GetNamedNumber(c_lastWindowHeight, DEFAULT_WINDOW_HEIGHT));
|
||||
}
|
||||
catch (const winrt::hresult_error&)
|
||||
{
|
||||
|
@ -6,6 +6,9 @@
|
||||
class CSettings
|
||||
{
|
||||
public:
|
||||
static constexpr inline int DEFAULT_WINDOW_WIDTH = 1400;
|
||||
static constexpr inline int DEFAULT_WINDOW_HEIGHT = 800;
|
||||
|
||||
CSettings();
|
||||
|
||||
inline bool GetEnabled()
|
||||
@ -25,6 +28,17 @@ public:
|
||||
Save();
|
||||
}
|
||||
|
||||
inline std::tuple<int, int> GetLastWindowSize() const
|
||||
{
|
||||
return std::make_tuple(settings.lastWindowWidth, settings.lastWindowHeight);
|
||||
}
|
||||
|
||||
inline void UpdateLastWindowSize(const int width, const int height)
|
||||
{
|
||||
settings.lastWindowWidth = std::max(width, DEFAULT_WINDOW_WIDTH);
|
||||
settings.lastWindowHeight = std::max(height, DEFAULT_WINDOW_HEIGHT);
|
||||
}
|
||||
|
||||
inline bool GetShowIconOnMenu() const
|
||||
{
|
||||
return settings.showIconOnMenu;
|
||||
@ -134,6 +148,8 @@ private:
|
||||
unsigned int flags{ 0 };
|
||||
std::wstring searchText{};
|
||||
std::wstring replaceText{};
|
||||
int lastWindowWidth{ DEFAULT_WINDOW_WIDTH };
|
||||
int lastWindowHeight{ DEFAULT_WINDOW_HEIGHT };
|
||||
};
|
||||
|
||||
void Reload();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user