mirror of
https://github.com/microsoft/PowerToys.git
synced 2024-11-23 19:49:17 +08:00
[DSC] Implement Microsoft.PowerToys.Configure DSCResource & winget support (#30918)
* [DSC] Microsoft.PowerToys.Configure module + winget configuration file support
* f: fix for an incorrect directory id reference
* f: update comment
* f: address review comments
* f: file locksmith bug fix
* f: add explorer preview switches in samples
* f: remove debug
* Sign DSC files
* f: implement docs/samples generator
* [ci]Sign FancyZonesEditorCommon.dll
* Sign DSC files in the Generated folder
* f: address review comments
* f: update usable options
* f: add autogenerated sample
* [Installer] Don't use same GUID for different components
* [Installer]Don't remove folders shared by other modules
* Allow configuring PTRun MaximumNumberOfResults
* Remove all settings DSC sample. Just random data
* Allow configuring Hosts Run as Administrator
* Revert "[Installer]Don't remove folders shared by other modules"
This reverts commit 6da3d6cfd5
.
* Add all PTRun plugins and Global and keyboard to DSC sample
* Fix issues with context menu modules not disabling
* Fix default enabled values when setting with DSC
* Fix tests regarding default modules in Settings
* Fix merge error
* Restart PowerToys process if we stopped it
---------
Co-authored-by: Andrey Nekrasov <1828123+yuyoyuppe@users.noreply.github.com>
Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
This commit is contained in:
parent
818d3e3035
commit
f23fa3f592
1
.github/actions/spell-check/expect.txt
vendored
1
.github/actions/spell-check/expect.txt
vendored
@ -1029,6 +1029,7 @@ NOSIZE
|
||||
NOTIFICATIONSDLL
|
||||
NOTIFYICONDATAW
|
||||
NOTIMPL
|
||||
notlike
|
||||
NOTOPMOST
|
||||
NOTRACK
|
||||
NOTSRCCOPY
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -33,6 +33,8 @@ bld/
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
Generated/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
51
.pipelines/ESRPSigning_DSC.json
Normal file
51
.pipelines/ESRPSigning_DSC.json
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
"Version": "1.0.0",
|
||||
"UseMinimatch": false,
|
||||
"SignBatches": [
|
||||
{
|
||||
"MatchedPath": [
|
||||
"Microsoft.PowerToys.Configure.psm1",
|
||||
"Microsoft.PowerToys.Configure.psd1"
|
||||
],
|
||||
"SigningInfo": {
|
||||
"Operations": [
|
||||
{
|
||||
"KeyCode": "CP-230012",
|
||||
"OperationSetCode": "SigntoolSign",
|
||||
"Parameters": [
|
||||
{
|
||||
"parameterName": "OpusName",
|
||||
"parameterValue": "Microsoft"
|
||||
},
|
||||
{
|
||||
"parameterName": "OpusInfo",
|
||||
"parameterValue": "http://www.microsoft.com"
|
||||
},
|
||||
{
|
||||
"parameterName": "FileDigest",
|
||||
"parameterValue": "/fd \"SHA256\""
|
||||
},
|
||||
{
|
||||
"parameterName": "PageHash",
|
||||
"parameterValue": "/NPH"
|
||||
},
|
||||
{
|
||||
"parameterName": "TimeStamp",
|
||||
"parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
|
||||
}
|
||||
],
|
||||
"ToolName": "sign",
|
||||
"ToolVersion": "1.0"
|
||||
},
|
||||
{
|
||||
"KeyCode": "CP-230012",
|
||||
"OperationSetCode": "SigntoolVerify",
|
||||
"Parameters": [],
|
||||
"ToolName": "sign",
|
||||
"ToolVersion": "1.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -349,6 +349,15 @@ extends:
|
||||
batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_core.json'
|
||||
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
|
||||
|
||||
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@3
|
||||
displayName: Sign DSC Powershell files
|
||||
inputs:
|
||||
ConnectedServiceName: 'Terminal/Console/WinAppDriver Team Code Signing Connection'
|
||||
FolderPath: 'src/dsc/Microsoft.PowerToys.Configure'
|
||||
signType: batchSigning
|
||||
batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_DSC.json'
|
||||
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
|
||||
|
||||
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@3
|
||||
displayName: Sign x86 directshow VCM
|
||||
inputs:
|
||||
|
@ -574,6 +574,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UITests-FancyZonesEditor",
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FancyZonesEditorCommon", "src\modules\fancyzones\FancyZonesEditorCommon\FancyZonesEditorCommon.csproj", "{C0974915-8A1D-4BF0-977B-9587D3807AB7}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DSC", "DSC", "{557C4636-D7E1-4838-A504-7D19B725EE95}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerToys.Settings.DSC.Schema.Generator", "src\dsc\PowerToys.Settings.DSC.Schema.Generator\PowerToys.Settings.DSC.Schema.Generator.csproj", "{1D6893CB-BC0C-46A8-A76C-9728706CA51A}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{020A7474-3601-4160-A159-D7B70B77B15F} = {020A7474-3601-4160-A159-D7B70B77B15F}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
@ -2536,6 +2543,18 @@ Global
|
||||
{C0974915-8A1D-4BF0-977B-9587D3807AB7}.Release|x64.Build.0 = Release|x64
|
||||
{C0974915-8A1D-4BF0-977B-9587D3807AB7}.Release|x86.ActiveCfg = Release|x64
|
||||
{C0974915-8A1D-4BF0-977B-9587D3807AB7}.Release|x86.Build.0 = Release|x64
|
||||
{1D6893CB-BC0C-46A8-A76C-9728706CA51A}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{1D6893CB-BC0C-46A8-A76C-9728706CA51A}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{1D6893CB-BC0C-46A8-A76C-9728706CA51A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1D6893CB-BC0C-46A8-A76C-9728706CA51A}.Debug|x64.Build.0 = Debug|x64
|
||||
{1D6893CB-BC0C-46A8-A76C-9728706CA51A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{1D6893CB-BC0C-46A8-A76C-9728706CA51A}.Debug|x86.Build.0 = Debug|x64
|
||||
{1D6893CB-BC0C-46A8-A76C-9728706CA51A}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{1D6893CB-BC0C-46A8-A76C-9728706CA51A}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{1D6893CB-BC0C-46A8-A76C-9728706CA51A}.Release|x64.ActiveCfg = Release|x64
|
||||
{1D6893CB-BC0C-46A8-A76C-9728706CA51A}.Release|x64.Build.0 = Release|x64
|
||||
{1D6893CB-BC0C-46A8-A76C-9728706CA51A}.Release|x86.ActiveCfg = Release|x64
|
||||
{1D6893CB-BC0C-46A8-A76C-9728706CA51A}.Release|x86.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -2748,6 +2767,7 @@ Global
|
||||
{FE38FC07-1C05-4B57-ADA3-2FE2F53C6A52} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{3A9A791E-94A9-49F8-8401-C11CE288D5FB} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{C0974915-8A1D-4BF0-977B-9587D3807AB7} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{1D6893CB-BC0C-46A8-A76C-9728706CA51A} = {557C4636-D7E1-4838-A504-7D19B725EE95}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
98
doc/devdocs/settingsv2/dsc-configure.md
Normal file
98
doc/devdocs/settingsv2/dsc-configure.md
Normal file
@ -0,0 +1,98 @@
|
||||
# What is it
|
||||
|
||||
We would like to enable our users to use [`winget configure`](https://learn.microsoft.com/en-us/windows/package-manager/winget/configure) command to install PowerToys and configure its settings with a [Winget configuration file](https://learn.microsoft.com/en-us/windows/package-manager/configuration/create). For example:
|
||||
|
||||
```yaml
|
||||
properties:
|
||||
resources:
|
||||
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
||||
directives:
|
||||
description: Install PowerToys
|
||||
allowPrerelease: true
|
||||
settings:
|
||||
id: PowerToys (Preview)
|
||||
source: winget
|
||||
|
||||
- resource: PowerToysConfigure
|
||||
directives:
|
||||
description: Configure PowerToys
|
||||
settings:
|
||||
ShortcutGuide:
|
||||
Enabled: false
|
||||
OverlayOpacity: 1
|
||||
FancyZones:
|
||||
Enabled: true
|
||||
FancyzonesEditorHotkey: "Shift+Ctrl+Alt+F"
|
||||
configurationVersion: 0.2.0
|
||||
```
|
||||
|
||||
This should install PowerToys and make `PowerToysConfigure` resource available. We can use it in the same file.
|
||||
|
||||
# How it works
|
||||
|
||||
`PowerToysConfigure` is a [class-based DSC resource](https://learn.microsoft.com/en-us/powershell/dsc/concepts/class-based-resources?view=dsc-2.0). It looks up whether each setting was specified or not by checking whether it's `$null` or `0` for `enum`s and invokes `PowerToys.Settings.exe` with the updated value like so:
|
||||
```
|
||||
PowerToys.Settings.exe set <ModuleName>.<SettingName> <SettingValue>
|
||||
```
|
||||
|
||||
So for the example the config above should perform 3 following invocations:
|
||||
```
|
||||
PowerToys.Settings.exe set ShortcutGuide.Enabled false
|
||||
PowerToys.Settings.exe set FancyZones.Enabled true
|
||||
PowerToys.Settings.exe set FancyZones.FancyzonesEditorHotkey "Shift+Ctrl+Alt+F"
|
||||
```
|
||||
|
||||
`PowerToys.Settings` uses dotnet reflection capabilities to determine `SettingName` type and tries to convert the supplied `SettingValue` string accordingly. We use `ICmdReprParsable` for custom setting types.
|
||||
|
||||
|
||||
# How DSC is implemented
|
||||
|
||||
We use `PowerToys.Settings.DSC.Schema.Generator` to generate the bulk of `PowerToysConfigure.psm1` file. It also uses dotnet reflection capabilities to inspect `PowerToys.Settings.UI.Lib.dll` assembly and generate properties for the modules we have. The actual generation is done as a `PowerToys.Settings.DSC.Schema.Generator.csproj` post-build action.
|
||||
|
||||
# Debugging DSC resources
|
||||
|
||||
First, make sure that PowerShell 7.4+ is installed. Then make sure that you have DSC installed:
|
||||
|
||||
```ps
|
||||
Install-Module -Name PSDesiredStateConfiguration -RequiredVersion 2.0.7
|
||||
```
|
||||
|
||||
After that, start a new `pwsh` session and `cd` to `src\dsc\Microsoft.PowerToys.Configure\Generated` directory. From there, you should execute:
|
||||
```ps
|
||||
$env:PSModulePath += ";$pwd"
|
||||
```
|
||||
|
||||
Now build `PowerToys.sln` and **move** `src\dsc\Microsoft.PowerToys.Configure\Microsoft.PowerToys.Configure.psd1` temporarily to `src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\0.0.1\` folder, so it's located alongside with the generated `Microsoft.PowerToys.Configure.psm1`.
|
||||
|
||||
This will allow DSC to discover our DSC Resource module. See [PSModulePath](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_psmodulepath?view=powershell-7.4#long-description) for more info.
|
||||
|
||||
If everything works, you should see that your module is discovered by executing the following command:
|
||||
|
||||
```ps
|
||||
Get-Module -ListAvailable | grep PowerToys
|
||||
```
|
||||
|
||||
The resource itself should also be available:
|
||||
```ps
|
||||
Get-DSCResource | grep PowerToys
|
||||
```
|
||||
|
||||
Otherwise, you can force-import the module to diagnose issues:
|
||||
|
||||
```
|
||||
Import-Module .\Microsoft.PowerToys.Configure.psd1
|
||||
```
|
||||
|
||||
If it's imported successfully, you could also try to invoke it directly:
|
||||
|
||||
```ps
|
||||
Invoke-DscResource -Name PowerToysConfigure -Method Set -ModuleName Microsoft.PowerToys.Configure -Property @{ Debug = $true; Awake = @{ Enabled = $false; Mode = "TIMED"; IntervalMinutes = "10" } }
|
||||
```
|
||||
|
||||
Note that we've supplied `Debug` option, so a `%TEMP\PowerToys.DSC.TestConfigure.txt` is created with the supplied properties, a current timestamp, and other debug output.
|
||||
|
||||
Finally, you can test it with winget by invoking it as such:
|
||||
|
||||
```ps
|
||||
winget configure .\configuration.dsc.yaml --accept-configuration-agreements --disable-interactivity
|
||||
```
|
@ -46,6 +46,49 @@
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<?if $(var.PerUser) = "true" ?>
|
||||
<DirectoryRef Id="PersonalFolder">
|
||||
<Directory Id="WindowsPowerShellFolder" Name="PowerShell">
|
||||
<Directory Id="PowerShellModulesFolder" Name="Modules">
|
||||
<Directory Id="PowerToysDscFolder" Name="Microsoft.PowerToys.Configure">
|
||||
<Directory Id="PowerToysDscVerFolder" Name="$(var.Version)">
|
||||
<Component Id="PowerToysDSC" Win64="yes" Guid="4A033E3B-6590-43FD-8FBD-27F9DF557F7F">
|
||||
<RegistryValue Root="HKCU"
|
||||
Key="Software\[Manufacturer]\[ProductName]"
|
||||
Name="DSCInstalled"
|
||||
Type="integer"
|
||||
Value="1"
|
||||
KeyPath="yes"/>
|
||||
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Microsoft.PowerToys.Configure.psd1" Id="PTConf.psd1" />
|
||||
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version)\Microsoft.PowerToys.Configure.psm1" Id="PTConf.psm1" />
|
||||
<RemoveFolder Id="RemoveThisFolder" On="uninstall" />
|
||||
<RemoveFolder Id="RemovePowerToysDscVerFolder" Directory="PowerToysDscVerFolder" On="uninstall" />
|
||||
<RemoveFolder Id="RemovePowerToysDscFolder" Directory="PowerToysDscFolder" On="uninstall" />
|
||||
<RemoveFolder Id="RemovePowerShellModulesFolder" Directory="PowerShellModulesFolder" On="uninstall" />
|
||||
<RemoveFolder Id="RemoveWindowsPowerShellFolder" Directory="WindowsPowerShellFolder" On="uninstall" />
|
||||
</Component>
|
||||
</Directory>
|
||||
</Directory>
|
||||
</Directory>
|
||||
</Directory>
|
||||
</DirectoryRef>
|
||||
<?else?>
|
||||
<DirectoryRef Id="ProgramFiles64Folder">
|
||||
<Directory Id="WindowsPowerShellFolder" Name="WindowsPowerShell">
|
||||
<Directory Id="PowerShellModulesFolder" Name="Modules">
|
||||
<Directory Id="PowerToysDscFolder" Name="Microsoft.PowerToys.Configure">
|
||||
<Directory Id="PowerToysDscVerFolder" Name="$(var.Version)">
|
||||
<Component Id="PowerToysDSC" Win64="yes" Guid="C52AECA0-DA73-49B8-BB49-31EF6640FF1F">
|
||||
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Microsoft.PowerToys.Configure.psd1" Id="PTConf.psd1" />
|
||||
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version)\Microsoft.PowerToys.Configure.psm1" Id="PTConf.psm1" />
|
||||
</Component>
|
||||
</Directory>
|
||||
</Directory>
|
||||
</Directory>
|
||||
</Directory>
|
||||
</DirectoryRef>
|
||||
<?endif?>
|
||||
|
||||
<DirectoryRef Id="ApplicationProgramsFolder">
|
||||
<Component Id="PowerToysStartMenuShortcut" >
|
||||
<Shortcut Id="ApplicationStartMenuShortcut"
|
||||
@ -101,6 +144,7 @@
|
||||
<ComponentRef Id="License_rtf" />
|
||||
<ComponentRef Id="Notice_md" />
|
||||
<ComponentRef Id="DesktopShortcut" />
|
||||
<ComponentRef Id="PowerToysDSC" />
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
||||
|
@ -395,6 +395,7 @@
|
||||
<Directory Id="ApplicationProgramsFolder" Name="PowerToys (Preview)"/>
|
||||
</Directory>
|
||||
<Directory Id="DesktopFolder" Name="Desktop" />
|
||||
<Directory Id="PersonalFolder" Name="UserHomeDocuments" />
|
||||
</Directory>
|
||||
</Fragment>
|
||||
</Wix>
|
||||
|
@ -20,7 +20,6 @@
|
||||
|
||||
#include <common/version/version.h>
|
||||
|
||||
|
||||
using namespace System;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
using System::Collections::Generic::List;
|
||||
@ -40,11 +39,17 @@ public
|
||||
delete _map;
|
||||
}
|
||||
|
||||
String ^ GetKeyName(DWORD key) {
|
||||
String ^ GetKeyName(DWORD key)
|
||||
{
|
||||
return gcnew String(_map->GetKeyName(key).c_str());
|
||||
}
|
||||
|
||||
void Updatelayout()
|
||||
DWORD GetKeyValue(String ^ name)
|
||||
{
|
||||
return _map->GetKeyFromName(msclr::interop::marshal_as<std::wstring>(name));
|
||||
}
|
||||
|
||||
void Updatelayout()
|
||||
{
|
||||
_map->UpdateLayout();
|
||||
}
|
||||
@ -129,13 +134,13 @@ public
|
||||
}
|
||||
|
||||
static List<String ^> ^ GetAllActiveMicrophoneDeviceNames() {
|
||||
auto names = gcnew List<String ^>();
|
||||
for (const auto& device : MicrophoneDevice::getAllActive())
|
||||
{
|
||||
names->Add(gcnew String(device->name().data()));
|
||||
auto names = gcnew List<String ^>();
|
||||
for (const auto& device : MicrophoneDevice::getAllActive())
|
||||
{
|
||||
names->Add(gcnew String(device->name().data()));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
static List<String ^> ^
|
||||
GetAllVideoCaptureDeviceNames() {
|
||||
|
@ -0,0 +1,83 @@
|
||||
#
|
||||
# Module manifest for module 'Microsoft.PowerToys.Configure'
|
||||
#
|
||||
# Generated by: Microsoft Corporation
|
||||
#
|
||||
# Generated on: 20.11.2023
|
||||
#
|
||||
|
||||
@{
|
||||
|
||||
# Script module or binary module file associated with this manifest.
|
||||
RootModule = 'Microsoft.PowerToys.Configure.psm1'
|
||||
|
||||
# Version number of this module.
|
||||
ModuleVersion = '0.0.1'
|
||||
|
||||
# ID used to uniquely identify this module
|
||||
GUID = '778ed7a1-489d-4dc9-b0f2-2da3b1fe14cb'
|
||||
|
||||
# Author of this module
|
||||
Author = 'Microsoft Corporation'
|
||||
|
||||
# Company or vendor of this module
|
||||
CompanyName = 'Microsoft'
|
||||
|
||||
# Copyright statement for this module
|
||||
Copyright = '(c) Microsoft Corporation. All rights reserved.'
|
||||
|
||||
# Description of the functionality provided by this module
|
||||
Description = 'The module enables settings configuration for an installed PowerToys application.'
|
||||
|
||||
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
|
||||
FunctionsToExport = '*'
|
||||
|
||||
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
|
||||
CmdletsToExport = @()
|
||||
|
||||
# Variables to export from this module
|
||||
VariablesToExport = @()
|
||||
|
||||
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
|
||||
AliasesToExport = @()
|
||||
|
||||
# DSC resources to export from this module
|
||||
DscResourcesToExport = @(
|
||||
'PowerToysConfigure'
|
||||
)
|
||||
|
||||
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
|
||||
PrivateData = @{
|
||||
|
||||
PSData = @{
|
||||
|
||||
# Tags applied to this module. These help with module discovery in online galleries.
|
||||
# Tags = @()
|
||||
|
||||
# A URL to the license for this module.
|
||||
# LicenseUri = ''
|
||||
|
||||
# A URL to the main website for this project.
|
||||
# ProjectUri = ''
|
||||
|
||||
# A URL to an icon representing this module.
|
||||
# IconUri = ''
|
||||
|
||||
# ReleaseNotes of this module
|
||||
# ReleaseNotes = ''
|
||||
|
||||
# Prerelease string of this module
|
||||
# Prerelease = ''
|
||||
|
||||
# Flag to indicate whether the module requires explicit user acceptance for install/update/save
|
||||
# RequireLicenseAcceptance = $false
|
||||
|
||||
# External dependent modules of this module
|
||||
# ExternalModuleDependencies = @()
|
||||
|
||||
} # End of PSData hashtable
|
||||
|
||||
} # End of PrivateData hashtable
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
properties:
|
||||
resources:
|
||||
# - resource: Microsoft.WinGet.DSC/WinGetPackage
|
||||
# directives:
|
||||
# description: Install PowerToys
|
||||
# allowPrerelease: true
|
||||
# settings:
|
||||
# id: PowerToys (Preview)
|
||||
# source: winget
|
||||
|
||||
- resource: PowerToysConfigure
|
||||
directives:
|
||||
description: Configure PowerToys
|
||||
settings:
|
||||
ShortcutGuide:
|
||||
Enabled: false
|
||||
OverlayOpacity: 50
|
||||
FancyZones:
|
||||
Enabled: true
|
||||
FancyzonesEditorHotkey: "Shift+Ctrl+Alt+F"
|
||||
FileLocksmith:
|
||||
Enabled: false
|
||||
configurationVersion: 0.2.0
|
@ -0,0 +1,53 @@
|
||||
properties:
|
||||
resources:
|
||||
- resource: PowerToysConfigure
|
||||
directives:
|
||||
description: Configure PowerToys
|
||||
settings:
|
||||
PowerLauncher:
|
||||
Enabled: true
|
||||
Plugins:
|
||||
- Name: "Calculator"
|
||||
Disabled: false
|
||||
- Name: "Folder"
|
||||
Disabled: false
|
||||
- Name: "History"
|
||||
Disabled: false
|
||||
- Name: "Windows Search"
|
||||
Disabled: false
|
||||
- Name: "OneNote"
|
||||
Disabled: false
|
||||
- Name: "PowerToys"
|
||||
Disabled: false
|
||||
- Name: "Program"
|
||||
Disabled: false
|
||||
ActionKeyword: "P:"
|
||||
IsGlobal: false
|
||||
- Name: "Registry Plugin"
|
||||
Disabled: false
|
||||
- Name: "Service"
|
||||
Disabled: false
|
||||
- Name: "Shell"
|
||||
Disabled: false
|
||||
- Name: "Windows System Commands"
|
||||
Disabled: false
|
||||
- Name: "Time and Date"
|
||||
Disabled: false
|
||||
- Name: "Unit Converter"
|
||||
Disabled: false
|
||||
- Name: "URI Handler"
|
||||
Disabled: false
|
||||
- Name: "Value Generator"
|
||||
Disabled: false
|
||||
- Name: "Visual Studio Code Workspaces"
|
||||
Disabled: false
|
||||
- Name: "Web Search"
|
||||
Disabled: false
|
||||
- Name: "Windows settings"
|
||||
Disabled: false
|
||||
- Name: "Windows Terminal"
|
||||
Disabled: false
|
||||
- Name: "Window Walker"
|
||||
Disabled: false
|
||||
|
||||
configurationVersion: 0.2.0
|
@ -0,0 +1,70 @@
|
||||
properties:
|
||||
resources:
|
||||
- resource: PowerToysConfigure
|
||||
directives:
|
||||
description: Configure PowerToys
|
||||
settings:
|
||||
AlwaysOnTop:
|
||||
Enabled: false
|
||||
Awake:
|
||||
Enabled: false
|
||||
ColorPicker:
|
||||
Enabled: false
|
||||
CropAndLock:
|
||||
Enabled: false
|
||||
EnvironmentVariables:
|
||||
Enabled: false
|
||||
FancyZones:
|
||||
Enabled: false
|
||||
FileLocksmith:
|
||||
Enabled: false
|
||||
ImageResizer:
|
||||
Enabled: false
|
||||
KeyboardManager:
|
||||
Enabled: false
|
||||
FindMyMouse:
|
||||
Enabled: false
|
||||
MouseHighlighter:
|
||||
Enabled: false
|
||||
MouseJump:
|
||||
Enabled: false
|
||||
MousePointerCrosshairs:
|
||||
Enabled: false
|
||||
MouseWithoutBorders:
|
||||
Enabled: false
|
||||
Peek:
|
||||
Enabled: false
|
||||
PowerRename:
|
||||
Enabled: false
|
||||
PowerLauncher:
|
||||
Enabled: false
|
||||
PowerAccent:
|
||||
Enabled: false
|
||||
PowerPreview:
|
||||
EnableSvgPreview: false
|
||||
EnableSvgThumbnail: false
|
||||
EnableMdPreview: false
|
||||
EnableMonacoPreview: false
|
||||
EnablePdfPreview: false
|
||||
EnablePdfThumbnail: false
|
||||
EnableGcodePreview: false
|
||||
EnableGcodeThumbnail: false
|
||||
EnableStlThumbnail: false
|
||||
EnableQoiPreview: false
|
||||
EnableQoiThumbnail: false
|
||||
PowerOcr:
|
||||
Enabled: false
|
||||
ShortcutGuide:
|
||||
Enabled: false
|
||||
VideoConference:
|
||||
Enabled: false
|
||||
MeasureTool:
|
||||
Enabled: false
|
||||
Hosts:
|
||||
Enabled: false
|
||||
PastePlain:
|
||||
Enabled: false
|
||||
RegistryPreview:
|
||||
Enabled: false
|
||||
|
||||
configurationVersion: 0.2.0
|
@ -0,0 +1,70 @@
|
||||
properties:
|
||||
resources:
|
||||
- resource: PowerToysConfigure
|
||||
directives:
|
||||
description: Configure PowerToys
|
||||
settings:
|
||||
AlwaysOnTop:
|
||||
Enabled: true
|
||||
Awake:
|
||||
Enabled: true
|
||||
ColorPicker:
|
||||
Enabled: true
|
||||
CropAndLock:
|
||||
Enabled: true
|
||||
EnvironmentVariables:
|
||||
Enabled: true
|
||||
FancyZones:
|
||||
Enabled: true
|
||||
FileLocksmith:
|
||||
Enabled: true
|
||||
ImageResizer:
|
||||
Enabled: true
|
||||
KeyboardManager:
|
||||
Enabled: true
|
||||
FindMyMouse:
|
||||
Enabled: true
|
||||
MouseHighlighter:
|
||||
Enabled: true
|
||||
MouseJump:
|
||||
Enabled: true
|
||||
MousePointerCrosshairs:
|
||||
Enabled: true
|
||||
MouseWithoutBorders:
|
||||
Enabled: true
|
||||
Peek:
|
||||
Enabled: true
|
||||
PowerRename:
|
||||
Enabled: true
|
||||
PowerLauncher:
|
||||
Enabled: true
|
||||
PowerAccent:
|
||||
Enabled: true
|
||||
PowerPreview:
|
||||
EnableSvgPreview: true
|
||||
EnableSvgThumbnail: true
|
||||
EnableMdPreview: true
|
||||
EnableMonacoPreview: true
|
||||
EnablePdfPreview: true
|
||||
EnablePdfThumbnail: true
|
||||
EnableGcodePreview: true
|
||||
EnableGcodeThumbnail: true
|
||||
EnableStlThumbnail: true
|
||||
EnableQoiPreview: true
|
||||
EnableQoiThumbnail: true
|
||||
PowerOcr:
|
||||
Enabled: true
|
||||
ShortcutGuide:
|
||||
Enabled: true
|
||||
VideoConference:
|
||||
Enabled: true
|
||||
MeasureTool:
|
||||
Enabled: true
|
||||
Hosts:
|
||||
Enabled: true
|
||||
PastePlain:
|
||||
Enabled: true
|
||||
RegistryPreview:
|
||||
Enabled: true
|
||||
|
||||
configurationVersion: 0.2.0
|
31
src/dsc/PowerToys.Settings.DSC.Schema.Generator/Common.cs
Normal file
31
src/dsc/PowerToys.Settings.DSC.Schema.Generator/Common.cs
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PowerToys.Settings.DSC.Schema;
|
||||
|
||||
internal sealed class Common
|
||||
{
|
||||
private static string[] TypeParts(string name)
|
||||
{
|
||||
return Regex.Split(name.ToLower(CultureInfo.CurrentCulture), @"(?<!^)(?=[A-Z])|\.");
|
||||
}
|
||||
|
||||
internal static bool InferIsBool(Type propertyInfo)
|
||||
{
|
||||
return TypeParts(propertyInfo.Name).Any(word => word.Equals("Bool", StringComparison.OrdinalIgnoreCase) || word.Equals("Boolean", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
internal static bool InferIsInt(Type propertyInfo)
|
||||
{
|
||||
return TypeParts(propertyInfo.Name).Any(word => word.Contains("Int", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
357
src/dsc/PowerToys.Settings.DSC.Schema.Generator/DSCGeneration.cs
Normal file
357
src/dsc/PowerToys.Settings.DSC.Schema.Generator/DSCGeneration.cs
Normal file
@ -0,0 +1,357 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using static PowerToys.Settings.DSC.Schema.Introspection;
|
||||
|
||||
namespace PowerToys.Settings.DSC.Schema;
|
||||
|
||||
internal sealed class DSCGeneration
|
||||
{
|
||||
private static readonly string DoubleNewLine = Environment.NewLine + Environment.NewLine;
|
||||
|
||||
private struct AdditionalPropertiesInfo
|
||||
{
|
||||
public string Name;
|
||||
|
||||
public string Type;
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, AdditionalPropertiesInfo> AdditionalPropertiesInfoPerModule = new Dictionary<string, AdditionalPropertiesInfo> { { "PowerLauncher", new AdditionalPropertiesInfo { Name = "Plugins", Type = "Hashtable[]" } } };
|
||||
|
||||
private static string EmitEnumDefinition(Type type)
|
||||
{
|
||||
var values = string.Empty;
|
||||
|
||||
int i = 0;
|
||||
foreach (var name in Enum.GetNames(type))
|
||||
{
|
||||
values += " " + name;
|
||||
|
||||
// Nullable enums seem to be not supported by winget, so the workaround is to always start with '1', because by default the values are initialized to zero. That allows us to use zero as a "lack of value" indicator.
|
||||
if (i == 0)
|
||||
{
|
||||
values += " = 1";
|
||||
}
|
||||
|
||||
values += Environment.NewLine;
|
||||
i++;
|
||||
}
|
||||
|
||||
return $$"""
|
||||
enum {{type.Name}} {
|
||||
{{values}}}
|
||||
""";
|
||||
}
|
||||
|
||||
private struct PropertyEmitInfo
|
||||
{
|
||||
public string Name;
|
||||
public string Type;
|
||||
public string Initializer;
|
||||
public string EqualityOperator;
|
||||
public string DefaultValue;
|
||||
|
||||
public PropertyEmitInfo(string name, Type property)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
bool intLike = Common.InferIsInt(property);
|
||||
bool boolLike = Common.InferIsBool(property);
|
||||
|
||||
var rawType = "string";
|
||||
var isNullable = true;
|
||||
DefaultValue = "$null";
|
||||
EqualityOperator = "-ne";
|
||||
Initializer = "= $null";
|
||||
|
||||
if (intLike)
|
||||
{
|
||||
rawType = "int";
|
||||
isNullable = false;
|
||||
}
|
||||
else if (boolLike)
|
||||
{
|
||||
rawType = "bool";
|
||||
isNullable = false;
|
||||
}
|
||||
else if (property.IsEnum)
|
||||
{
|
||||
rawType = property.Name;
|
||||
isNullable = true;
|
||||
Initializer = string.Empty;
|
||||
DefaultValue = "0";
|
||||
}
|
||||
|
||||
// For strings
|
||||
else
|
||||
{
|
||||
EqualityOperator = "-notlike";
|
||||
DefaultValue = "''";
|
||||
}
|
||||
|
||||
// We must make all our properties nullable to be able to detect which of them weren't supplied
|
||||
Type = isNullable ? rawType : $"Nullable[{rawType}]";
|
||||
}
|
||||
}
|
||||
|
||||
private static string EmitPropertyDefinition(PropertyEmitInfo info)
|
||||
{
|
||||
return $$"""
|
||||
[DscProperty()] [{{info.Type}}]
|
||||
${{info.Name}} {{info.Initializer}}
|
||||
""";
|
||||
}
|
||||
|
||||
private static string EmitPropertyApplyChangeStatements(string moduleName, PropertyEmitInfo info, string localPropertyName = null)
|
||||
{
|
||||
if (localPropertyName == null)
|
||||
{
|
||||
localPropertyName = info.Name;
|
||||
}
|
||||
|
||||
return $$"""
|
||||
if ($this.{{localPropertyName}} {{info.EqualityOperator}} {{info.DefaultValue}}) {
|
||||
$Changes.Value += "set {{moduleName}}.{{info.Name}} `"$($this.{{localPropertyName}})`""
|
||||
}
|
||||
""";
|
||||
}
|
||||
|
||||
private static string EmitModuleDefinition(SettingsStructure module)
|
||||
{
|
||||
bool generalSettings = module.Name == "GeneralSettings";
|
||||
|
||||
var properties = module.Properties
|
||||
.Where(property => !property.Value.IsIgnored)
|
||||
.Select(property => new PropertyEmitInfo(property.Key, property.Value.Type));
|
||||
|
||||
var propertyDefinitionsBlock = string.Empty;
|
||||
var applyChangesBlock = string.Empty;
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
var definition = EmitPropertyDefinition(property);
|
||||
var applyChanges = EmitPropertyApplyChangeStatements(module.Name, property);
|
||||
|
||||
propertyDefinitionsBlock += definition + DoubleNewLine;
|
||||
applyChangesBlock += applyChanges + DoubleNewLine;
|
||||
}
|
||||
|
||||
bool hasAdditionalProperties = AdditionalPropertiesInfoPerModule.TryGetValue(module.Name, out var additionalPropertiesInfo);
|
||||
|
||||
// Enabled property of each module is contained in General settings
|
||||
if (!generalSettings)
|
||||
{
|
||||
propertyDefinitionsBlock += $$"""
|
||||
[DscProperty(Key)] [Nullable[bool]]
|
||||
$Enabled = $null
|
||||
|
||||
""";
|
||||
|
||||
if (hasAdditionalProperties)
|
||||
{
|
||||
propertyDefinitionsBlock += $$"""
|
||||
|
||||
[DscProperty()] [{{additionalPropertiesInfo.Type}}]
|
||||
${{additionalPropertiesInfo.Name}} = @()
|
||||
|
||||
|
||||
""";
|
||||
}
|
||||
|
||||
applyChangesBlock += EmitPropertyApplyChangeStatements("General.Enabled", new PropertyEmitInfo($"{module.Name}", typeof(bool)), "Enabled");
|
||||
}
|
||||
|
||||
var additionalPropertiesCheckBlock = string.Empty;
|
||||
if (hasAdditionalProperties)
|
||||
{
|
||||
additionalPropertiesCheckBlock = $$"""
|
||||
if ($this.{{additionalPropertiesInfo.Name}}.Count -gt 0) {
|
||||
$AdditionalPropertiesTmpPath = [System.IO.Path]::GetTempFileName()
|
||||
$this.{{additionalPropertiesInfo.Name}} | ConvertTo-Json | Set-Content -Path $AdditionalPropertiesTmpPath
|
||||
$Changes.Value += "setAdditional {{module.Name}} `"$AdditionalPropertiesTmpPath`""
|
||||
}
|
||||
""";
|
||||
}
|
||||
|
||||
return $$"""
|
||||
class {{module.Name}} {
|
||||
{{propertyDefinitionsBlock}} ApplyChanges([ref]$Changes) {
|
||||
{{applyChangesBlock}}
|
||||
|
||||
{{additionalPropertiesCheckBlock}}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
""";
|
||||
}
|
||||
|
||||
public static string EmitModuleFileContents(SettingsStructure[] moduleSettings, SettingsStructure generalSettings, string debugSettingsPath)
|
||||
{
|
||||
var enumsToEmit = new HashSet<Type>();
|
||||
|
||||
var modulesBlock = string.Empty;
|
||||
var modulesResourcePropertiesBlock = string.Empty;
|
||||
var applyModulesChangesBlock = string.Empty;
|
||||
|
||||
foreach (var module in moduleSettings.Append(generalSettings))
|
||||
{
|
||||
enumsToEmit.UnionWith(module.Properties
|
||||
.Where(property => property.Value.Type.IsEnum)
|
||||
.Select(property => property.Value.Type));
|
||||
|
||||
modulesBlock += EmitModuleDefinition(module);
|
||||
|
||||
applyModulesChangesBlock += $$"""
|
||||
$this.{{module.Name}}.ApplyChanges([ref]$ChangesToApply)
|
||||
|
||||
""";
|
||||
|
||||
modulesResourcePropertiesBlock += $$"""
|
||||
[DscProperty()]
|
||||
[{{module.Name}}]${{module.Name}} = [{{module.Name}}]::new()
|
||||
|
||||
|
||||
""";
|
||||
}
|
||||
|
||||
var enumsBlock = string.Join(DoubleNewLine, enumsToEmit.Select(EmitEnumDefinition));
|
||||
var version = interop.CommonManaged.GetProductVersion().Replace("v", string.Empty);
|
||||
|
||||
return $$"""
|
||||
#region enums
|
||||
enum PowerToysConfigureEnsure {
|
||||
Absent
|
||||
Present
|
||||
}
|
||||
|
||||
{{enumsBlock}}
|
||||
#endregion enums
|
||||
|
||||
#region DscResources
|
||||
{{modulesBlock}}
|
||||
[DscResource()]
|
||||
class PowerToysConfigure {
|
||||
[DscProperty(Key)] [PowerToysConfigureEnsure]
|
||||
$Ensure = [PowerToysConfigureEnsure]::Present
|
||||
|
||||
[bool] $Debug = $false
|
||||
|
||||
{{modulesResourcePropertiesBlock}}
|
||||
[string] GetPowerToysSettingsPath() {
|
||||
# Obtain PowerToys install location
|
||||
if ($this.Debug -eq $true) {
|
||||
$SettingsExePath = "{{debugSettingsPath}}"
|
||||
} else {
|
||||
$installation = Get-WmiObject Win32_Product | Where-Object {$_.Name -eq "PowerToys (Preview)" -and $_.Version -eq "{{version}}"}
|
||||
|
||||
if ($installation) {
|
||||
$SettingsExePath = Join-Path (Join-Path $installation.InstallLocation WinUI3Apps) PowerToys.Settings.exe
|
||||
# Handle spaces in the path
|
||||
$SettingsExePath = "`"$SettingsExePath`""
|
||||
} else {
|
||||
throw "PowerToys installation wasn't found."
|
||||
}
|
||||
}
|
||||
|
||||
return $SettingsExePath
|
||||
}
|
||||
|
||||
[PowerToysConfigure] Get() {
|
||||
$CurrentState = [PowerToysConfigure]::new()
|
||||
$SettingsExePath = $this.GetPowerToysSettingsPath()
|
||||
$SettingsTmpFilePath = [System.IO.Path]::GetTempFileName()
|
||||
|
||||
$SettingsToRequest = @{}
|
||||
foreach ($module in $CurrentState.PSObject.Properties) {
|
||||
$moduleName = $module.Name
|
||||
# Skip utility properties
|
||||
if ($moduleName -eq "Ensure" -or $moduleName -eq "Debug") {
|
||||
continue
|
||||
}
|
||||
|
||||
$moduleProperties = $module.Value
|
||||
$propertiesArray = @()
|
||||
foreach ($property in $moduleProperties.PSObject.Properties) {
|
||||
$propertyName = $property.Name
|
||||
# Skip Enabled properties - they should be requested from GeneralSettings
|
||||
if ($propertyName -eq "Enabled") {
|
||||
continue
|
||||
}
|
||||
|
||||
$propertiesArray += $propertyName
|
||||
}
|
||||
|
||||
$SettingsToRequest[$moduleName] = $propertiesArray
|
||||
}
|
||||
|
||||
$settingsJson = $SettingsToRequest | ConvertTo-Json
|
||||
$settingsJson | Set-Content -Path $SettingsTmpFilePath
|
||||
|
||||
Start-Process -FilePath $SettingsExePath -Wait -Args "get `"$SettingsTmpFilePath`""
|
||||
$SettingsValues = Get-Content -Path $SettingsTmpFilePath -Raw
|
||||
|
||||
if ($this.Debug -eq $true) {
|
||||
$TempFilePath = Join-Path -Path $env:TEMP -ChildPath "PowerToys.DSC.TestConfigure.txt"
|
||||
Set-Content -Path "$TempFilePath" -Value ("Requested:`r`n" + $settingsJson + "`r`n" + "Got:`r`n" + $SettingsValues + "`r`n" + (Get-Date -Format "o")) -Force
|
||||
}
|
||||
|
||||
$SettingsValues = $SettingsValues | ConvertFrom-Json
|
||||
foreach ($module in $SettingsValues.PSObject.Properties) {
|
||||
$moduleName = $module.Name
|
||||
$obtainedModuleSettings = $module.Value
|
||||
$moduleRef = $CurrentState.$moduleName
|
||||
foreach ($property in $obtainedModuleSettings.PSObject.Properties) {
|
||||
$propertyName = $property.Name
|
||||
$moduleRef.$propertyName = $property.Value
|
||||
}
|
||||
}
|
||||
|
||||
Remove-Item -Path $SettingsTmpFilePath
|
||||
|
||||
return $CurrentState
|
||||
}
|
||||
|
||||
[bool] Test() {
|
||||
# NB: we must always assume that the configuration isn't applied, because changing some settings produce external side-effects
|
||||
return $false
|
||||
}
|
||||
|
||||
[void] Set() {
|
||||
$SettingsExePath = $this.GetPowerToysSettingsPath()
|
||||
$ChangesToApply = @()
|
||||
|
||||
{{applyModulesChangesBlock}}
|
||||
if ($this.Debug -eq $true) {
|
||||
$tmp_info = $ChangesToApply
|
||||
# $tmp_info = $this | ConvertTo-Json -Depth 10
|
||||
|
||||
$TempFilePath = Join-Path -Path $env:TEMP -ChildPath "PowerToys.DSC.TestConfigure.txt"
|
||||
Set-Content -Path "$TempFilePath" -Value ($tmp_info + "`r`n" + (Get-Date -Format "o")) -Force
|
||||
}
|
||||
|
||||
# Stop any running PowerToys instances
|
||||
Stop-Process -Name "PowerToys.Settings" -PassThru | Wait-Process
|
||||
$PowerToysProcessStopped = Stop-Process -Name "PowerToys" -PassThru
|
||||
$PowerToysProcessStopped | Wait-Process
|
||||
|
||||
foreach ($change in $ChangesToApply) {
|
||||
Start-Process -FilePath $SettingsExePath -Wait -Args "$change"
|
||||
}
|
||||
|
||||
# If the PowerToys was stopped, restart it.
|
||||
if ($PowerToysProcessStopped -ne $null) {
|
||||
Start-Process -FilePath $SettingsExePath
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion DscResources
|
||||
""";
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using static PowerToys.Settings.DSC.Schema.Introspection;
|
||||
|
||||
namespace PowerToys.Settings.DSC.Schema;
|
||||
|
||||
internal sealed class DocumentationGeneration
|
||||
{
|
||||
private static readonly string IsAvailableSymbol = "✅";
|
||||
private static readonly string IsUnavailableSymbol = "❌";
|
||||
private static readonly string MissingValueIndicator = "—";
|
||||
|
||||
private static readonly string PropertySuffix = "Property";
|
||||
|
||||
private static string SimplifyPropertyType(string typeName)
|
||||
{
|
||||
if (typeName.EndsWith(PropertySuffix, StringComparison.InvariantCulture))
|
||||
{
|
||||
typeName = typeName.Remove(typeName.LastIndexOf(PropertySuffix, StringComparison.InvariantCulture), PropertySuffix.Length);
|
||||
}
|
||||
|
||||
return typeName;
|
||||
}
|
||||
|
||||
private static string EmitPropertyTableLine(string name, ModulePropertyStructure info)
|
||||
{
|
||||
bool isAvailable = !info.IsIgnored;
|
||||
var availabilitySymbol = isAvailable ? IsAvailableSymbol : IsUnavailableSymbol;
|
||||
var documentation = MissingValueIndicator;
|
||||
if (info.Type.IsEnum)
|
||||
{
|
||||
documentation = "Possible values: ";
|
||||
foreach (var enumValue in Enum.GetValues(info.Type))
|
||||
{
|
||||
documentation += enumValue.ToString() + ' ';
|
||||
}
|
||||
}
|
||||
|
||||
var propertyType = isAvailable ? SimplifyPropertyType(info.Type.Name) : MissingValueIndicator;
|
||||
return $"| {name} | {propertyType} | {documentation} | {availabilitySymbol} |";
|
||||
}
|
||||
|
||||
private static string EmitModulePropertiesTable(SettingsStructure module)
|
||||
{
|
||||
bool generalSettings = module.Name == "GeneralSettings";
|
||||
|
||||
var properties = module.Properties
|
||||
.Where(p => !p.Value.IsIgnoredByJsonSerializer)
|
||||
.Select(property => EmitPropertyTableLine(property.Key, property.Value)).Aggregate((acc, line) => string.Join(Environment.NewLine, [acc, line]));
|
||||
|
||||
var propertyDefinitionsBlock = string.Empty;
|
||||
var applyChangesBlock = string.Empty;
|
||||
return $$"""
|
||||
### {{module.Name}}
|
||||
|
||||
| Name | Type | Description | Available |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
{{properties}}
|
||||
|
||||
|
||||
""";
|
||||
}
|
||||
|
||||
public static string EmitDocumentationFileContents(SettingsStructure[] moduleSettings, SettingsStructure generalSettings)
|
||||
{
|
||||
var moduleTables = string.Empty;
|
||||
|
||||
foreach (var module in moduleSettings.Append(generalSettings))
|
||||
{
|
||||
moduleTables += EmitModulePropertiesTable(module);
|
||||
}
|
||||
|
||||
return moduleTables;
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.Json.Serialization;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace PowerToys.Settings.DSC.Schema;
|
||||
|
||||
public class Introspection
|
||||
{
|
||||
public struct ModulePropertyStructure
|
||||
{
|
||||
public bool IsIgnoredByJsonSerializer;
|
||||
public bool IsIgnoredByCmdConfigureAttribute;
|
||||
|
||||
public bool IsIgnored
|
||||
{
|
||||
get { return IsIgnoredByJsonSerializer || IsIgnoredByCmdConfigureAttribute; }
|
||||
}
|
||||
|
||||
public Type Type;
|
||||
}
|
||||
|
||||
public struct SettingsStructure
|
||||
{
|
||||
public string Name;
|
||||
public Dictionary<string, ModulePropertyStructure> Properties;
|
||||
}
|
||||
|
||||
private static bool IsModuleNameField(FieldInfo info)
|
||||
{
|
||||
return info != null && info.IsLiteral && !info.IsInitOnly
|
||||
&& info.FieldType == typeof(string);
|
||||
}
|
||||
|
||||
private static bool IsSettingsClassType(Type type)
|
||||
{
|
||||
return type.IsClass && type.FullName.EndsWith("Settings", StringComparison.InvariantCulture);
|
||||
}
|
||||
|
||||
private static Dictionary<string, ModulePropertyStructure> ParseProperties(Type propertiesType)
|
||||
{
|
||||
return propertiesType.GetProperties().Select(property =>
|
||||
{
|
||||
var jsonIgnoreAttr = property.GetCustomAttribute<JsonIgnoreAttribute>();
|
||||
var cmdIgnoreAttr = property.GetCustomAttribute<CmdConfigureIgnoreAttribute>();
|
||||
|
||||
return (property.Name, new ModulePropertyStructure
|
||||
{
|
||||
Type = property.PropertyType,
|
||||
IsIgnoredByJsonSerializer = jsonIgnoreAttr != null,
|
||||
IsIgnoredByCmdConfigureAttribute = cmdIgnoreAttr != null,
|
||||
});
|
||||
}).ToDictionary();
|
||||
}
|
||||
|
||||
public static SettingsStructure ParseGeneralSettings(Assembly assembly)
|
||||
{
|
||||
return assembly
|
||||
.GetTypes()
|
||||
.Where(IsSettingsClassType)
|
||||
.Where(type => type.Name == "GeneralSettings")
|
||||
.Select(type => new SettingsStructure
|
||||
{
|
||||
Name = type.Name,
|
||||
Properties = ParseProperties(type),
|
||||
}).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static SettingsStructure[] ParseModuleSettings(Assembly assembly)
|
||||
{
|
||||
return assembly
|
||||
.GetTypes()
|
||||
.Where(IsSettingsClassType)
|
||||
.Select(type => new
|
||||
{
|
||||
Properties = type.GetProperty("Properties"),
|
||||
ModuleNameInfo = type.GetField("ModuleName", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy),
|
||||
TypeName = type.Name,
|
||||
})
|
||||
.Where(x => x.Properties?.PropertyType.IsClass == true && IsModuleNameField(x.ModuleNameInfo))
|
||||
.Select(x => new SettingsStructure
|
||||
{
|
||||
Name = x.TypeName.Replace("Settings", string.Empty),
|
||||
Properties = ParseProperties(x.Properties.PropertyType),
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\Version.props" />
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<RootNamespace>PowerToys.Settings.DSC.Schema</RootNamespace>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
|
||||
<WindowsPackageType>None</WindowsPackageType>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<SelfContained>true</SelfContained>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
|
||||
<PropertyGroup Condition="'$(Platform)'=='x64'">
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Platform)'=='ARM64'">
|
||||
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<NoWarn></NoWarn>
|
||||
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
|
||||
<WarningsNotAsErrors>CA1720</WarningsNotAsErrors>
|
||||
<Optimize>False</Optimize>
|
||||
<DebugType>full</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<NoWarn></NoWarn>
|
||||
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
|
||||
<WarningsNotAsErrors>CA1720</WarningsNotAsErrors>
|
||||
<Optimize>true</Optimize>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- See https://learn.microsoft.com/windows/apps/develop/platform/csharp-winrt/net-projection-from-cppwinrt-component for more info -->
|
||||
<PropertyGroup>
|
||||
<CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir>
|
||||
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
<ProjectReference Include="..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<GeneratedDSCModule>"$(ProjectDir)..\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(Version)\Microsoft.PowerToys.Configure.psm1"</GeneratedDSCModule>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- The following sections assume that the machine we're building on is always x64. That means we won't be able to run/inspect arm64 executables, therefore we must always execute x64 generator. -->
|
||||
|
||||
<Target Name="PostBuildAction" AfterTargets="Build" Outputs="$(GeneratedDSCModule)" Condition="'$(Platform)'!='ARM64'">
|
||||
<Exec Command=""$(OutDir)$(AssemblyName).exe" "$(SolutionDir)x64\$(Configuration)\WinUI3Apps\PowerToys.Settings.UI.Lib.dll" $(GeneratedDSCModule)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PreBuild" BeforeTargets="PreBuildEvent" Condition="'$(Platform)'=='ARM64'">
|
||||
<Exec Command=""$(MSBuildToolsPath)\msbuild.exe" PowerToys.sln -p:Configuration="$(Configuration)" -p:Platform="x64" -verbosity:m -t:DSC\PowerToys_Settings_DSC_Schema_Generator" WorkingDirectory="$(SolutionDir)" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
86
src/dsc/PowerToys.Settings.DSC.Schema.Generator/Program.cs
Normal file
86
src/dsc/PowerToys.Settings.DSC.Schema.Generator/Program.cs
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace PowerToys.Settings.DSC.Schema;
|
||||
|
||||
internal sealed class Program
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
if (args.Length != 2)
|
||||
{
|
||||
Console.WriteLine("Usage: Generator.exe <PowerToys.Settings.UI.Lib.dll path> <output path>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
var dllPath = args[0];
|
||||
var outputPath = args[1];
|
||||
|
||||
bool documentationMode = Path.GetExtension(outputPath) == ".md";
|
||||
bool sampleMode = Path.GetExtension(outputPath) == ".yaml";
|
||||
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
|
||||
|
||||
var assembly = Assembly.LoadFrom(dllPath);
|
||||
var moduleSettings = Introspection.ParseModuleSettings(assembly);
|
||||
var generalSettings = Introspection.ParseGeneralSettings(assembly);
|
||||
#if DEBUG
|
||||
PrintUniquePropertyTypes(moduleSettings);
|
||||
#endif
|
||||
var outputFileContents = string.Empty;
|
||||
if (documentationMode)
|
||||
{
|
||||
outputFileContents = DocumentationGeneration.EmitDocumentationFileContents(moduleSettings, generalSettings);
|
||||
}
|
||||
else if (sampleMode)
|
||||
{
|
||||
outputFileContents = SampleGeneration.EmitSampleFileContents(moduleSettings, generalSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
var debugSettingsPath = Path.Combine(Directory.GetParent(dllPath).FullName, "PowerToys.Settings.exe");
|
||||
outputFileContents = DSCGeneration.EmitModuleFileContents(moduleSettings, generalSettings, debugSettingsPath);
|
||||
}
|
||||
|
||||
File.WriteAllText(outputPath, outputFileContents);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error: {ex.Message}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static void PrintUniquePropertyTypes(Introspection.SettingsStructure[] moduleSettings)
|
||||
{
|
||||
Console.WriteLine("Detected the following module properties types:");
|
||||
var propertyTypes = new HashSet<Type>();
|
||||
foreach (var settings in moduleSettings)
|
||||
{
|
||||
Console.WriteLine($"{settings.Name}");
|
||||
foreach (var (_, property) in settings.Properties)
|
||||
{
|
||||
if (!property.IsIgnored)
|
||||
{
|
||||
propertyTypes.Add(property.Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("\nDetected the following unique property types:");
|
||||
foreach (var type in propertyTypes)
|
||||
{
|
||||
Console.WriteLine($"{type}");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using static PowerToys.Settings.DSC.Schema.Introspection;
|
||||
|
||||
namespace PowerToys.Settings.DSC.Schema;
|
||||
|
||||
internal sealed class SampleGeneration
|
||||
{
|
||||
private const int FixedSeed = 12345;
|
||||
private static readonly Random _random = new Random(FixedSeed);
|
||||
|
||||
private static string EmitPropertySetter(string name, ModulePropertyStructure info)
|
||||
{
|
||||
var randomPropertyValue = "\"<string>\"";
|
||||
if (Common.InferIsBool(info.Type))
|
||||
{
|
||||
randomPropertyValue = _random.Next(2) == 1 ? "true" : "false";
|
||||
}
|
||||
else if (Common.InferIsInt(info.Type))
|
||||
{
|
||||
randomPropertyValue = _random.Next(256).ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
else if (info.Type.IsEnum)
|
||||
{
|
||||
var enumValues = Enum.GetValues(info.Type);
|
||||
randomPropertyValue = enumValues.GetValue(_random.Next(enumValues.Length)).ToString();
|
||||
}
|
||||
|
||||
return $" {name}: {randomPropertyValue}";
|
||||
}
|
||||
|
||||
private static string EmitModulePropertiesSection(SettingsStructure module)
|
||||
{
|
||||
bool generalSettings = module.Name == "GeneralSettings";
|
||||
|
||||
var propertiesCollection = module.Properties
|
||||
.Where(p => !p.Value.IsIgnored)
|
||||
.Select(property => EmitPropertySetter(property.Key, property.Value))
|
||||
.ToList();
|
||||
|
||||
string properties = propertiesCollection.Count != 0
|
||||
? propertiesCollection.Aggregate((acc, line) => string.Join(Environment.NewLine, acc, line))
|
||||
: string.Empty;
|
||||
|
||||
var propertyDefinitionsBlock = string.Empty;
|
||||
var applyChangesBlock = string.Empty;
|
||||
return $$"""
|
||||
{{module.Name}}:
|
||||
{{properties}}
|
||||
|
||||
|
||||
""";
|
||||
}
|
||||
|
||||
public static string EmitSampleFileContents(SettingsStructure[] moduleSettings, SettingsStructure generalSettings)
|
||||
{
|
||||
var moduleTables = $$"""
|
||||
properties:
|
||||
resources:
|
||||
- resource: PowerToysConfigure
|
||||
directives:
|
||||
description: Configure PowerToys
|
||||
settings:
|
||||
|
||||
""";
|
||||
|
||||
foreach (var module in moduleSettings.Append(generalSettings))
|
||||
{
|
||||
moduleTables += EmitModulePropertiesSection(module);
|
||||
}
|
||||
|
||||
moduleTables += " configurationVersion: 0.2.0";
|
||||
return moduleTables;
|
||||
}
|
||||
}
|
21
src/dsc/PowerToys.Settings.DSC.Schema.Generator/app.manifest
Normal file
21
src/dsc/PowerToys.Settings.DSC.Schema.Generator/app.manifest
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="PowerToys.Settings.app"/>
|
||||
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<!-- The combination of below two tags have the following effect:
|
||||
1) Per-Monitor for >= Windows 10 Anniversary Update
|
||||
2) System < Windows 10 Anniversary Update
|
||||
-->
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
@ -90,14 +90,12 @@ public:
|
||||
}
|
||||
|
||||
m_enabled = true;
|
||||
save_settings();
|
||||
}
|
||||
|
||||
virtual void disable() override
|
||||
{
|
||||
Logger::info(L"File Locksmith disabled");
|
||||
m_enabled = false;
|
||||
save_settings();
|
||||
}
|
||||
|
||||
virtual bool is_enabled() override
|
||||
@ -123,7 +121,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_enabled;
|
||||
bool m_enabled = false;
|
||||
bool m_extended_only;
|
||||
|
||||
void init_settings()
|
||||
@ -136,7 +134,7 @@ private:
|
||||
void save_settings()
|
||||
{
|
||||
auto& settings = FileLocksmithSettingsInstance();
|
||||
settings.SetEnabled(m_enabled);
|
||||
m_enabled = FileLocksmithSettingsInstance().GetEnabled();
|
||||
settings.SetExtendedContextMenuOnly(m_extended_only);
|
||||
|
||||
settings.Save();
|
||||
|
@ -18,10 +18,12 @@ static bool LastModifiedTime(const std::wstring& filePath, FILETIME* lpFileTime)
|
||||
|
||||
FileLocksmithSettings::FileLocksmithSettings()
|
||||
{
|
||||
generalJsonFilePath = PTSettingsHelper::get_powertoys_general_save_file_location();
|
||||
std::wstring savePath = PTSettingsHelper::get_module_save_folder_location(constants::nonlocalizable::PowerToyKey);
|
||||
std::error_code ec;
|
||||
|
||||
jsonFilePath = savePath + constants::nonlocalizable::DataFilePath;
|
||||
RefreshEnabledState();
|
||||
Load();
|
||||
}
|
||||
|
||||
@ -29,7 +31,6 @@ void FileLocksmithSettings::Save()
|
||||
{
|
||||
json::JsonObject jsonData;
|
||||
|
||||
jsonData.SetNamedValue(constants::nonlocalizable::JsonKeyEnabled, json::value(settings.enabled));
|
||||
jsonData.SetNamedValue(constants::nonlocalizable::JsonKeyShowInExtendedContextMenu, json::value(settings.showInExtendedContextMenu));
|
||||
|
||||
json::to_file(jsonFilePath, jsonData);
|
||||
@ -48,6 +49,32 @@ void FileLocksmithSettings::Load()
|
||||
}
|
||||
}
|
||||
|
||||
void FileLocksmithSettings::RefreshEnabledState()
|
||||
{
|
||||
// Load json settings from data file if it is modified in the meantime.
|
||||
FILETIME lastModifiedTime{};
|
||||
if (!(LastModifiedTime(generalJsonFilePath, &lastModifiedTime) &&
|
||||
CompareFileTime(&lastModifiedTime, &lastLoadedGeneralSettingsTime) == 1))
|
||||
return;
|
||||
|
||||
lastLoadedGeneralSettingsTime = lastModifiedTime;
|
||||
|
||||
auto json = json::from_file(generalJsonFilePath);
|
||||
if (!json)
|
||||
return;
|
||||
|
||||
const json::JsonObject& jsonSettings = json.value();
|
||||
try
|
||||
{
|
||||
json::JsonObject modulesEnabledState;
|
||||
json::get(jsonSettings, L"enabled", modulesEnabledState, json::JsonObject{});
|
||||
json::get(modulesEnabledState, L"File Locksmith", settings.enabled, true);
|
||||
}
|
||||
catch (const winrt::hresult_error&)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void FileLocksmithSettings::Reload()
|
||||
{
|
||||
// Load json settings from data file if it is modified in the meantime.
|
||||
@ -67,11 +94,6 @@ void FileLocksmithSettings::ParseJson()
|
||||
const json::JsonObject& jsonSettings = json.value();
|
||||
try
|
||||
{
|
||||
if (json::has(jsonSettings, constants::nonlocalizable::JsonKeyEnabled, json::JsonValueType::Boolean))
|
||||
{
|
||||
settings.enabled = jsonSettings.GetNamedBoolean(constants::nonlocalizable::JsonKeyEnabled);
|
||||
}
|
||||
|
||||
if (json::has(jsonSettings, constants::nonlocalizable::JsonKeyShowInExtendedContextMenu, json::JsonValueType::Boolean))
|
||||
{
|
||||
settings.showInExtendedContextMenu = jsonSettings.GetNamedBoolean(constants::nonlocalizable::JsonKeyShowInExtendedContextMenu);
|
||||
|
@ -15,16 +15,10 @@ public:
|
||||
return true;
|
||||
if (gpoSetting == powertoys_gpo::gpo_rule_configured_disabled)
|
||||
return false;
|
||||
Reload();
|
||||
RefreshEnabledState();
|
||||
return settings.enabled;
|
||||
}
|
||||
|
||||
inline void SetEnabled(bool enabled)
|
||||
{
|
||||
settings.enabled = enabled;
|
||||
Save();
|
||||
}
|
||||
|
||||
inline bool GetShowInExtendedContextMenu() const
|
||||
{
|
||||
return settings.showInExtendedContextMenu;
|
||||
@ -45,12 +39,15 @@ private:
|
||||
bool showInExtendedContextMenu{ false };
|
||||
};
|
||||
|
||||
void RefreshEnabledState();
|
||||
void Reload();
|
||||
void ParseJson();
|
||||
|
||||
Settings settings;
|
||||
std::wstring generalJsonFilePath;
|
||||
std::wstring jsonFilePath;
|
||||
FILETIME lastLoadedTime;
|
||||
FILETIME lastLoadedTime{};
|
||||
FILETIME lastLoadedGeneralSettingsTime{};
|
||||
};
|
||||
|
||||
FileLocksmithSettings& FileLocksmithSettingsInstance();
|
||||
|
@ -26,6 +26,7 @@ using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||
// 2023- Included in PowerToys.
|
||||
// </history>
|
||||
using Microsoft.Win32;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Properties.Setting.Values.#LoadIntSetting(System.String,System.Int32)", Justification = "Dotnet port with style preservation")]
|
||||
[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Properties.Setting.Values.#SaveSetting(System.String,System.Object)", Justification = "Dotnet port with style preservation")]
|
||||
@ -766,6 +767,7 @@ namespace MouseWithoutBorders.Class
|
||||
}
|
||||
}
|
||||
|
||||
[CmdConfigureIgnore]
|
||||
internal bool DrawMouseEx
|
||||
{
|
||||
get
|
||||
|
@ -11,7 +11,8 @@ namespace
|
||||
{
|
||||
const wchar_t c_imageResizerDataFilePath[] = L"\\image-resizer-settings.json";
|
||||
const wchar_t c_rootRegPath[] = L"Software\\Microsoft\\ImageResizer";
|
||||
const wchar_t c_enabled[] = L"Enabled";
|
||||
const wchar_t c_enabled[] = L"enabled";
|
||||
const wchar_t c_ImageResizer[] = L"Image Resizer";
|
||||
|
||||
unsigned int RegReadInteger(const std::wstring& valueName, unsigned int defaultValue)
|
||||
{
|
||||
@ -45,6 +46,7 @@ namespace
|
||||
|
||||
CSettings::CSettings()
|
||||
{
|
||||
generalJsonFilePath = PTSettingsHelper::get_powertoys_general_save_file_location();
|
||||
std::wstring oldSavePath = PTSettingsHelper::get_module_save_folder_location(ImageResizerConstants::ModuleOldSaveFolderKey);
|
||||
std::wstring savePath = PTSettingsHelper::get_module_save_folder_location(ImageResizerConstants::ModuleSaveFolderKey);
|
||||
std::error_code ec;
|
||||
@ -62,8 +64,6 @@ void CSettings::Save()
|
||||
{
|
||||
json::JsonObject jsonData;
|
||||
|
||||
jsonData.SetNamedValue(c_enabled, json::value(settings.enabled));
|
||||
|
||||
json::to_file(jsonFilePath, jsonData);
|
||||
GetSystemTimeAsFileTime(&lastLoadedTime);
|
||||
}
|
||||
@ -82,6 +82,32 @@ void CSettings::Load()
|
||||
}
|
||||
}
|
||||
|
||||
void CSettings::RefreshEnabledState()
|
||||
{
|
||||
// Load json settings from data file if it is modified in the meantime.
|
||||
FILETIME lastModifiedTime{};
|
||||
if (!(LastModifiedTime(generalJsonFilePath, &lastModifiedTime) &&
|
||||
CompareFileTime(&lastModifiedTime, &lastLoadedGeneralSettingsTime) == 1))
|
||||
return;
|
||||
|
||||
lastLoadedGeneralSettingsTime = lastModifiedTime;
|
||||
|
||||
auto json = json::from_file(generalJsonFilePath);
|
||||
if (!json)
|
||||
return;
|
||||
|
||||
const json::JsonObject& jsonSettings = json.value();
|
||||
try
|
||||
{
|
||||
json::JsonObject modulesEnabledState;
|
||||
json::get(jsonSettings, c_enabled, modulesEnabledState, json::JsonObject{});
|
||||
json::get(modulesEnabledState, c_ImageResizer, settings.enabled, true);
|
||||
}
|
||||
catch (const winrt::hresult_error&)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void CSettings::Reload()
|
||||
{
|
||||
// Load json settings from data file if it is modified in the meantime.
|
||||
@ -106,10 +132,7 @@ void CSettings::ParseJson()
|
||||
const json::JsonObject& jsonSettings = json.value();
|
||||
try
|
||||
{
|
||||
if (json::has(jsonSettings, c_enabled, json::JsonValueType::Boolean))
|
||||
{
|
||||
settings.enabled = jsonSettings.GetNamedBoolean(c_enabled);
|
||||
}
|
||||
// NB: add any new settings here
|
||||
}
|
||||
catch (const winrt::hresult_error&)
|
||||
{
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
#include <common/utils/gpo.h>
|
||||
|
||||
class CSettings
|
||||
@ -14,16 +15,10 @@ public:
|
||||
return true;
|
||||
if (gpoSetting == powertoys_gpo::gpo_rule_configured_disabled)
|
||||
return false;
|
||||
Reload();
|
||||
RefreshEnabledState();
|
||||
return settings.enabled;
|
||||
}
|
||||
|
||||
inline void SetEnabled(bool enabled)
|
||||
{
|
||||
settings.enabled = enabled;
|
||||
Save();
|
||||
}
|
||||
|
||||
void Save();
|
||||
void Load();
|
||||
|
||||
@ -33,13 +28,16 @@ private:
|
||||
bool enabled{ true };
|
||||
};
|
||||
|
||||
void RefreshEnabledState();
|
||||
void Reload();
|
||||
void MigrateFromRegistry();
|
||||
void ParseJson();
|
||||
|
||||
Settings settings;
|
||||
std::wstring jsonFilePath;
|
||||
std::wstring generalJsonFilePath;
|
||||
FILETIME lastLoadedTime;
|
||||
FILETIME lastLoadedGeneralSettingsTime{};
|
||||
};
|
||||
|
||||
CSettings& CSettingsInstance();
|
@ -37,7 +37,7 @@ class ImageResizerModule : public PowertoyModuleIface
|
||||
{
|
||||
private:
|
||||
// Enabled by default
|
||||
bool m_enabled = true;
|
||||
bool m_enabled = false;
|
||||
std::wstring app_name;
|
||||
//contains the non localized key of the powertoy
|
||||
std::wstring app_key;
|
||||
@ -101,7 +101,6 @@ public:
|
||||
virtual void enable()
|
||||
{
|
||||
m_enabled = true;
|
||||
CSettingsInstance().SetEnabled(m_enabled);
|
||||
|
||||
if (package::IsWin11OrGreater())
|
||||
{
|
||||
@ -121,7 +120,6 @@ public:
|
||||
virtual void disable()
|
||||
{
|
||||
m_enabled = false;
|
||||
CSettingsInstance().SetEnabled(m_enabled);
|
||||
Trace::EnableImageResizer(m_enabled);
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ namespace Microsoft.PowerToys.Run.Plugin.PowerToys
|
||||
_utilities.Add(new Utility(
|
||||
UtilityKey.PowerOCR,
|
||||
Resources.Text_Extractor,
|
||||
generalSettings.Enabled.PowerOCR,
|
||||
generalSettings.Enabled.PowerOcr,
|
||||
(_) =>
|
||||
{
|
||||
using var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowPowerOCRSharedEvent());
|
||||
@ -223,7 +223,7 @@ namespace Microsoft.PowerToys.Run.Plugin.PowerToys
|
||||
case UtilityKey.ColorPicker: u.Enable(generalSettings.Enabled.ColorPicker); break;
|
||||
case UtilityKey.FancyZones: u.Enable(generalSettings.Enabled.FancyZones); break;
|
||||
case UtilityKey.Hosts: u.Enable(generalSettings.Enabled.Hosts); break;
|
||||
case UtilityKey.PowerOCR: u.Enable(generalSettings.Enabled.PowerOCR); break;
|
||||
case UtilityKey.PowerOCR: u.Enable(generalSettings.Enabled.PowerOcr); break;
|
||||
case UtilityKey.MeasureTool: u.Enable(generalSettings.Enabled.MeasureTool); break;
|
||||
case UtilityKey.ShortcutGuide: u.Enable(generalSettings.Enabled.ShortcutGuide); break;
|
||||
case UtilityKey.RegistryPreview: u.Enable(generalSettings.Enabled.RegistryPreview); break;
|
||||
|
@ -266,20 +266,25 @@ namespace PowerLauncher
|
||||
private static void UpdateSettings(PowerLauncherSettings settings)
|
||||
{
|
||||
var defaultPlugins = GetDefaultPluginsSettings().ToDictionary(x => x.Id);
|
||||
var defaultPluginsByName = GetDefaultPluginsSettings().ToDictionary(x => x.Name);
|
||||
|
||||
foreach (PowerLauncherPluginSettings plugin in settings.Plugins)
|
||||
{
|
||||
if (defaultPlugins.TryGetValue(plugin.Id, out PowerLauncherPluginSettings value))
|
||||
PowerLauncherPluginSettings value = null;
|
||||
if ((plugin.Id != null && defaultPlugins.TryGetValue(plugin.Id, out value)) || (!string.IsNullOrEmpty(plugin.Name) && defaultPluginsByName.TryGetValue(plugin.Name, out value)))
|
||||
{
|
||||
var additionalOptions = CombineAdditionalOptions(value.AdditionalOptions, plugin.AdditionalOptions);
|
||||
var enabledPolicyState = GPOWrapper.GetRunPluginEnabledValue(plugin.Id);
|
||||
plugin.Name = value.Name;
|
||||
var id = value.Id;
|
||||
var name = value.Name;
|
||||
var additionalOptions = plugin.AdditionalOptions != null ? CombineAdditionalOptions(value.AdditionalOptions, plugin.AdditionalOptions) : value.AdditionalOptions;
|
||||
var enabledPolicyState = GPOWrapper.GetRunPluginEnabledValue(id);
|
||||
plugin.Name = name;
|
||||
plugin.Description = value.Description;
|
||||
plugin.Author = value.Author;
|
||||
plugin.IconPathDark = value.IconPathDark;
|
||||
plugin.IconPathLight = value.IconPathLight;
|
||||
plugin.EnabledPolicyUiState = (int)enabledPolicyState;
|
||||
defaultPlugins[plugin.Id] = plugin;
|
||||
defaultPlugins[plugin.Id].AdditionalOptions = additionalOptions;
|
||||
defaultPlugins[id] = plugin;
|
||||
defaultPlugins[id].AdditionalOptions = additionalOptions;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using ManagedCommon;
|
||||
|
||||
using Wox.Plugin;
|
||||
|
||||
namespace Wox.Infrastructure.UserSettings
|
||||
|
@ -63,9 +63,6 @@ public:
|
||||
|
||||
static HRESULT s_CreateInstance(_In_opt_ IUnknown* punkOuter, _In_ REFIID riid, _Outptr_ void** ppv);
|
||||
|
||||
static bool SetEnabled(_In_ bool enabled);
|
||||
static bool IsEnabled();
|
||||
|
||||
private:
|
||||
~CPowerRenameMenu();
|
||||
|
||||
|
@ -162,7 +162,7 @@ class PowerRenameModule : public PowertoyModuleIface
|
||||
{
|
||||
private:
|
||||
// Enabled by default
|
||||
bool m_enabled = true;
|
||||
bool m_enabled = false;
|
||||
std::wstring app_name;
|
||||
//contains the non localized key of the powertoy
|
||||
std::wstring app_key;
|
||||
@ -202,16 +202,13 @@ public:
|
||||
package::RegisterSparsePackage(path, packageUri);
|
||||
}
|
||||
}
|
||||
|
||||
save_settings();
|
||||
}
|
||||
|
||||
// Disable the powertoy
|
||||
virtual void disable()
|
||||
{
|
||||
Logger::info(L"PowerRename disabled");
|
||||
m_enabled = false;
|
||||
save_settings();
|
||||
Logger::info(L"PowerRename disabled");
|
||||
}
|
||||
|
||||
// Returns if the powertoy is enabled
|
||||
@ -316,8 +313,6 @@ public:
|
||||
|
||||
void save_settings()
|
||||
{
|
||||
CSettingsInstance().SetEnabled(m_enabled);
|
||||
CSettingsInstance().Save();
|
||||
Trace::EnablePowerRename(m_enabled);
|
||||
}
|
||||
|
||||
|
@ -33,9 +33,11 @@ namespace
|
||||
|
||||
CSettings::CSettings()
|
||||
{
|
||||
generalJsonFilePath = PTSettingsHelper::get_powertoys_general_save_file_location();
|
||||
std::wstring result = PTSettingsHelper::get_module_save_folder_location(PowerRenameConstants::ModuleKey);
|
||||
jsonFilePath = result + std::wstring(c_powerRenameDataFilePath);
|
||||
moduleJsonFilePath = result + std::wstring(c_powerRenameDataFilePath);
|
||||
UIFlagsFilePath = result + std::wstring(c_powerRenameUIFlagsFilePath);
|
||||
RefreshEnabledState();
|
||||
Load();
|
||||
}
|
||||
|
||||
@ -43,7 +45,6 @@ void CSettings::Save()
|
||||
{
|
||||
json::JsonObject jsonData;
|
||||
|
||||
jsonData.SetNamedValue(c_enabled, json::value(settings.enabled));
|
||||
jsonData.SetNamedValue(c_showIconOnMenu, json::value(settings.showIconOnMenu));
|
||||
jsonData.SetNamedValue(c_extendedContextMenuOnly, json::value(settings.extendedContextMenuOnly));
|
||||
jsonData.SetNamedValue(c_persistState, json::value(settings.persistState));
|
||||
@ -51,13 +52,13 @@ void CSettings::Save()
|
||||
jsonData.SetNamedValue(c_maxMRUSize, json::value(settings.maxMRUSize));
|
||||
jsonData.SetNamedValue(c_useBoostLib, json::value(settings.useBoostLib));
|
||||
|
||||
json::to_file(jsonFilePath, jsonData);
|
||||
json::to_file(moduleJsonFilePath, jsonData);
|
||||
GetSystemTimeAsFileTime(&lastLoadedTime);
|
||||
}
|
||||
|
||||
void CSettings::Load()
|
||||
{
|
||||
if (!std::filesystem::exists(jsonFilePath))
|
||||
if (!std::filesystem::exists(moduleJsonFilePath))
|
||||
{
|
||||
MigrateFromRegistry();
|
||||
|
||||
@ -71,20 +72,35 @@ void CSettings::Load()
|
||||
}
|
||||
}
|
||||
|
||||
void CSettings::Reload()
|
||||
void CSettings::RefreshEnabledState()
|
||||
{
|
||||
// Load json settings from data file if it is modified in the meantime.
|
||||
FILETIME lastModifiedTime{};
|
||||
if (LastModifiedTime(jsonFilePath, &lastModifiedTime) &&
|
||||
CompareFileTime(&lastModifiedTime, &lastLoadedTime) == 1)
|
||||
if (!(LastModifiedTime(generalJsonFilePath, &lastModifiedTime) &&
|
||||
CompareFileTime(&lastModifiedTime, &lastLoadedGeneralSettingsTime) == 1))
|
||||
return;
|
||||
|
||||
lastLoadedGeneralSettingsTime = lastModifiedTime;
|
||||
|
||||
auto json = json::from_file(generalJsonFilePath);
|
||||
if (!json)
|
||||
return;
|
||||
|
||||
const json::JsonObject& jsonSettings = json.value();
|
||||
try
|
||||
{
|
||||
json::JsonObject modulesEnabledState;
|
||||
json::get(jsonSettings, L"enabled", modulesEnabledState, json::JsonObject{});
|
||||
json::get(modulesEnabledState, L"PowerRename", settings.enabled, true);
|
||||
}
|
||||
catch (const winrt::hresult_error&)
|
||||
{
|
||||
Load();
|
||||
}
|
||||
}
|
||||
|
||||
void CSettings::MigrateFromRegistry()
|
||||
{
|
||||
settings.enabled = GetRegBoolean(c_enabled, true);
|
||||
//settings.enabled = GetRegBoolean(c_enabled, true);
|
||||
settings.showIconOnMenu = GetRegBoolean(c_showIconOnMenu, true);
|
||||
settings.extendedContextMenuOnly = GetRegBoolean(c_extendedContextMenuOnly, false); // Disabled by default.
|
||||
settings.persistState = GetRegBoolean(c_persistState, true);
|
||||
@ -100,16 +116,12 @@ void CSettings::MigrateFromRegistry()
|
||||
|
||||
void CSettings::ParseJson()
|
||||
{
|
||||
auto json = json::from_file(jsonFilePath);
|
||||
auto json = json::from_file(moduleJsonFilePath);
|
||||
if (json)
|
||||
{
|
||||
const json::JsonObject& jsonSettings = json.value();
|
||||
try
|
||||
{
|
||||
if (json::has(jsonSettings, c_enabled, json::JsonValueType::Boolean))
|
||||
{
|
||||
settings.enabled = jsonSettings.GetNamedBoolean(c_enabled);
|
||||
}
|
||||
if (json::has(jsonSettings, c_showIconOnMenu, json::JsonValueType::Boolean))
|
||||
{
|
||||
settings.showIconOnMenu = jsonSettings.GetNamedBoolean(c_showIconOnMenu);
|
||||
|
@ -15,16 +15,10 @@ public:
|
||||
return true;
|
||||
if (gpoSetting == powertoys_gpo::gpo_rule_configured_disabled)
|
||||
return false;
|
||||
Reload();
|
||||
RefreshEnabledState();
|
||||
return settings.enabled;
|
||||
}
|
||||
|
||||
inline void SetEnabled(bool enabled)
|
||||
{
|
||||
settings.enabled = enabled;
|
||||
Save();
|
||||
}
|
||||
|
||||
inline bool GetShowIconOnMenu() const
|
||||
{
|
||||
return settings.showIconOnMenu;
|
||||
@ -112,7 +106,7 @@ private:
|
||||
unsigned int flags{ 0 };
|
||||
};
|
||||
|
||||
void Reload();
|
||||
void RefreshEnabledState();
|
||||
void MigrateFromRegistry();
|
||||
void ParseJson();
|
||||
|
||||
@ -120,9 +114,11 @@ private:
|
||||
void WriteFlags();
|
||||
|
||||
Settings settings;
|
||||
std::wstring jsonFilePath;
|
||||
std::wstring generalJsonFilePath;
|
||||
std::wstring moduleJsonFilePath;
|
||||
std::wstring UIFlagsFilePath;
|
||||
FILETIME lastLoadedTime;
|
||||
FILETIME lastLoadedTime{};
|
||||
FILETIME lastLoadedGeneralSettingsTime{};
|
||||
};
|
||||
|
||||
CSettings& CSettingsInstance();
|
||||
|
@ -0,0 +1,16 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Settings.UI.Library.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// Adding this attribute to a property makes it not configurable from the command line.
|
||||
/// Typical use cases:
|
||||
/// - Property represents internal module state.
|
||||
/// - Property has a type that is unwieldy to type as a command line string.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
|
||||
public class CmdConfigureIgnoreAttribute : Attribute;
|
@ -5,6 +5,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
@ -36,6 +37,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
public DateTimeOffset ExpirationDateTime { get; set; }
|
||||
|
||||
[JsonPropertyName("customTrayTimes")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public Dictionary<string, int> CustomTrayTimes { get; set; }
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ using System.Text.Json.Serialization;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class BoolProperty
|
||||
public record BoolProperty : ICmdLineRepresentable
|
||||
{
|
||||
public BoolProperty()
|
||||
{
|
||||
@ -22,9 +22,28 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
[JsonPropertyName("value")]
|
||||
public bool Value { get; set; }
|
||||
|
||||
public static bool TryParseFromCmd(string cmd, out object result)
|
||||
{
|
||||
result = null;
|
||||
|
||||
if (!bool.TryParse(cmd, out bool value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
result = new BoolProperty { Value = value };
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return JsonSerializer.Serialize(this);
|
||||
}
|
||||
|
||||
public bool TryToCmdRepresentable(out string result)
|
||||
{
|
||||
result = Value.ToString();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,11 +7,13 @@ using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Enumerations;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class ColorPickerProperties
|
||||
{
|
||||
[CmdConfigureIgnore]
|
||||
public HotkeySettings DefaultActivationShortcut => new HotkeySettings(true, false, false, true, 0x43);
|
||||
|
||||
public ColorPickerProperties()
|
||||
@ -43,6 +45,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
|
||||
[JsonPropertyName("changecursor")]
|
||||
[JsonConverter(typeof(BoolPropertyJsonConverter))]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public bool ChangeCursor { get; set; }
|
||||
|
||||
[JsonPropertyName("copiedcolorrepresentation")]
|
||||
@ -53,12 +56,15 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
|
||||
// Property ColorHistory is not used, the color history is saved separately in the colorHistory.json file
|
||||
[JsonPropertyName("colorhistory")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public List<string> ColorHistory { get; set; }
|
||||
|
||||
[JsonPropertyName("colorhistorylimit")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public int ColorHistoryLimit { get; set; }
|
||||
|
||||
[JsonPropertyName("visiblecolorformats")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public Dictionary<string, KeyValuePair<bool, string>> VisibleColorFormats { get; set; }
|
||||
|
||||
[JsonPropertyName("showcolorname")]
|
||||
|
@ -15,6 +15,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
private Action notifyEnabledChangedAction;
|
||||
|
||||
// Default values for enabled modules should match their expected "enabled by default" values.
|
||||
// Otherwise, a run of DSC on clean settings will not match the expected default result.
|
||||
public EnabledModules()
|
||||
{
|
||||
}
|
||||
@ -55,7 +57,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
private bool fileExplorerPreview = true;
|
||||
|
||||
[JsonPropertyName("File Explorer Preview")]
|
||||
public bool FileExplorerPreview
|
||||
public bool PowerPreview
|
||||
{
|
||||
get => fileExplorerPreview;
|
||||
set
|
||||
@ -116,7 +118,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
}
|
||||
}
|
||||
|
||||
private bool keyboardManager = true;
|
||||
private bool keyboardManager; // defaulting to off
|
||||
|
||||
[JsonPropertyName("Keyboard Manager")]
|
||||
public bool KeyboardManager
|
||||
@ -183,7 +185,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
}
|
||||
}
|
||||
|
||||
private bool awake;
|
||||
private bool awake = true;
|
||||
|
||||
[JsonPropertyName("Awake")]
|
||||
public bool Awake
|
||||
@ -199,7 +201,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
}
|
||||
}
|
||||
|
||||
private bool mouseWithoutBorders = true;
|
||||
private bool mouseWithoutBorders; // defaulting to off
|
||||
|
||||
[JsonPropertyName("MouseWithoutBorders")]
|
||||
public bool MouseWithoutBorders
|
||||
@ -247,7 +249,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
}
|
||||
}
|
||||
|
||||
private bool mouseJump = true;
|
||||
private bool mouseJump; // defaulting to off
|
||||
|
||||
[JsonPropertyName("MouseJump")]
|
||||
public bool MouseJump
|
||||
@ -279,7 +281,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
}
|
||||
}
|
||||
|
||||
private bool mousePointerCrosshairs = true;
|
||||
private bool mousePointerCrosshairs; // defaulting to off
|
||||
|
||||
[JsonPropertyName("MousePointerCrosshairs")]
|
||||
public bool MousePointerCrosshairs
|
||||
@ -295,7 +297,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
}
|
||||
}
|
||||
|
||||
private bool powerAccent;
|
||||
private bool powerAccent; // defaulting to off
|
||||
|
||||
[JsonPropertyName("QuickAccent")]
|
||||
public bool PowerAccent
|
||||
@ -311,10 +313,10 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
}
|
||||
}
|
||||
|
||||
private bool powerOCR = true;
|
||||
private bool powerOCR; // defaulting to off
|
||||
|
||||
[JsonPropertyName("TextExtractor")]
|
||||
public bool PowerOCR
|
||||
public bool PowerOcr
|
||||
{
|
||||
get => powerOCR;
|
||||
set
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
@ -110,6 +111,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
public BoolProperty FancyzonesMakeDraggedWindowTransparent { get; set; }
|
||||
|
||||
[JsonPropertyName("fancyzones_allowPopupWindowSnap")]
|
||||
[CmdConfigureIgnore]
|
||||
public BoolProperty FancyzonesAllowPopupWindowSnap { get; set; }
|
||||
|
||||
[JsonPropertyName("fancyzones_allowChildWindowSnap")]
|
||||
|
@ -3,11 +3,13 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class FindMyMouseProperties
|
||||
{
|
||||
[CmdConfigureIgnore]
|
||||
public HotkeySettings DefaultActivationShortcut => new HotkeySettings(true, false, false, true, 0x46);
|
||||
|
||||
[JsonPropertyName("activation_method")]
|
||||
|
@ -8,6 +8,7 @@ using System.Text.Json.Serialization;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
@ -18,15 +19,18 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
public bool Startup { get; set; }
|
||||
|
||||
// Gets or sets a value indicating whether the powertoy elevated.
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
[JsonPropertyName("is_elevated")]
|
||||
public bool IsElevated { get; set; }
|
||||
|
||||
// Gets or sets a value indicating whether powertoys should run elevated.
|
||||
[JsonPropertyName("run_elevated")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public bool RunElevated { get; set; }
|
||||
|
||||
// Gets or sets a value indicating whether is admin.
|
||||
[JsonPropertyName("is_admin")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public bool IsAdmin { get; set; }
|
||||
|
||||
// Gets or sets a value indicating whether is warnings of elevated apps enabled.
|
||||
@ -39,16 +43,20 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
|
||||
// Gets or sets system theme name.
|
||||
[JsonPropertyName("system_theme")]
|
||||
[CmdConfigureIgnore]
|
||||
public string SystemTheme { get; set; }
|
||||
|
||||
// Gets or sets powertoys version number.
|
||||
[JsonPropertyName("powertoys_version")]
|
||||
[CmdConfigureIgnore]
|
||||
public string PowertoysVersion { get; set; }
|
||||
|
||||
[JsonPropertyName("action_name")]
|
||||
[CmdConfigureIgnore]
|
||||
public string CustomActionName { get; set; }
|
||||
|
||||
[JsonPropertyName("enabled")]
|
||||
[CmdConfigureIgnore]
|
||||
public EnabledModules Enabled { get; set; }
|
||||
|
||||
[JsonPropertyName("show_new_updates_toast_notification")]
|
||||
|
@ -3,10 +3,11 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class GenericProperty<T>
|
||||
public class GenericProperty<T> : ICmdLineRepresentable
|
||||
{
|
||||
[JsonPropertyName("value")]
|
||||
public T Value { get; set; }
|
||||
@ -20,5 +21,25 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
public GenericProperty()
|
||||
{
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1000:Do not declare static members on generic types", Justification = "Adding ICmdLineRepresentable support")]
|
||||
public static bool TryParseFromCmd(string cmd, out object result)
|
||||
{
|
||||
result = null;
|
||||
|
||||
if (ICmdLineRepresentable.TryParseFromCmdFor(typeof(T), cmd, out var value))
|
||||
{
|
||||
result = new GenericProperty<T> { Value = (T)value };
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryToCmdRepresentable(out string result)
|
||||
{
|
||||
result = Value.ToString();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using Settings.UI.Library.Attributes;
|
||||
using Settings.UI.Library.Enumerations;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
|
@ -2,14 +2,16 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class HotkeySettings
|
||||
public record HotkeySettings : ICmdLineRepresentable
|
||||
{
|
||||
private const int VKTAB = 0x09;
|
||||
|
||||
@ -39,11 +41,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
Code = code;
|
||||
}
|
||||
|
||||
public HotkeySettings Clone()
|
||||
{
|
||||
return new HotkeySettings(Win, Ctrl, Alt, Shift, Code);
|
||||
}
|
||||
|
||||
[JsonPropertyName("win")]
|
||||
public bool Win { get; set; }
|
||||
|
||||
@ -176,5 +173,72 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryParseFromCmd(string cmd, out object result)
|
||||
{
|
||||
bool win = false, ctrl = false, alt = false, shift = false;
|
||||
int code = 0;
|
||||
|
||||
var parts = cmd.Split('+');
|
||||
foreach (var part in parts)
|
||||
{
|
||||
switch (part.Trim().ToLower(CultureInfo.InvariantCulture))
|
||||
{
|
||||
case "win":
|
||||
win = true;
|
||||
break;
|
||||
case "ctrl":
|
||||
ctrl = true;
|
||||
break;
|
||||
case "alt":
|
||||
alt = true;
|
||||
break;
|
||||
case "shift":
|
||||
shift = true;
|
||||
break;
|
||||
default:
|
||||
if (!TryParseKeyCode(part, out code))
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result = new HotkeySettings(win, ctrl, alt, shift, code);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryParseKeyCode(string key, out int keyCode)
|
||||
{
|
||||
// ASCII symbol
|
||||
if (key.Length == 1 && char.IsLetterOrDigit(key[0]))
|
||||
{
|
||||
keyCode = char.ToUpper(key[0], CultureInfo.InvariantCulture);
|
||||
return true;
|
||||
}
|
||||
|
||||
// VK code
|
||||
else if (key.Length == 4 && key.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return int.TryParse(key.AsSpan(2), NumberStyles.HexNumber, null, out keyCode);
|
||||
}
|
||||
|
||||
// Alias
|
||||
else
|
||||
{
|
||||
keyCode = (int)Utilities.Helper.GetKeyValue(key);
|
||||
return keyCode != 0;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryToCmdRepresentable(out string result)
|
||||
{
|
||||
result = ToString();
|
||||
result = result.Replace(" ", null);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
@ -69,6 +70,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
public StringProperty ImageresizerFileName { get; set; }
|
||||
|
||||
[JsonPropertyName("imageresizer_sizes")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public ImageResizerSizes ImageresizerSizes { get; set; }
|
||||
|
||||
[JsonPropertyName("imageresizer_keepDateModified")]
|
||||
@ -78,6 +80,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
public StringProperty ImageresizerFallbackEncoder { get; set; }
|
||||
|
||||
[JsonPropertyName("imageresizer_customSize")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public ImageResizerCustomSizeProperty ImageresizerCustomSize { get; set; }
|
||||
|
||||
public string ToJsonString()
|
||||
|
@ -3,13 +3,14 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
// Represents the configuration property of the settings that store Integer type.
|
||||
public class IntProperty
|
||||
public record IntProperty : ICmdLineRepresentable
|
||||
{
|
||||
public IntProperty()
|
||||
{
|
||||
@ -25,6 +26,19 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
[JsonPropertyName("value")]
|
||||
public int Value { get; set; }
|
||||
|
||||
public static bool TryParseFromCmd(string cmd, out object result)
|
||||
{
|
||||
result = null;
|
||||
|
||||
if (!int.TryParse(cmd, out var value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
result = new IntProperty { Value = value };
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns a JSON version of the class settings configuration class.
|
||||
public override string ToString()
|
||||
{
|
||||
@ -40,5 +54,11 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool TryToCmdRepresentable(out string result)
|
||||
{
|
||||
result = Value.ToString(CultureInfo.InvariantCulture);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,126 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library;
|
||||
|
||||
/// <summary>
|
||||
/// A helper interface to allow parsing property values from their command line representation.
|
||||
/// </summary>
|
||||
public interface ICmdLineRepresentable
|
||||
{
|
||||
public static abstract bool TryParseFromCmd(string cmd, out object result);
|
||||
|
||||
public abstract bool TryToCmdRepresentable(out string result);
|
||||
|
||||
public static sealed bool TryToCmdRepresentableFor(Type type, object value, out string result)
|
||||
{
|
||||
result = null;
|
||||
if (!typeof(ICmdLineRepresentable).IsAssignableFrom(type))
|
||||
{
|
||||
throw new ArgumentException($"{type} doesn't implement {nameof(ICmdLineRepresentable)}");
|
||||
}
|
||||
|
||||
var method = type.GetMethod(nameof(TryToCmdRepresentable));
|
||||
var parameters = new object[] { result };
|
||||
if ((bool)method.Invoke(value, parameters))
|
||||
{
|
||||
result = (string)parameters[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static sealed bool TryParseFromCmdFor(Type type, string cmd, out object result)
|
||||
{
|
||||
result = null;
|
||||
if (!typeof(ICmdLineRepresentable).IsAssignableFrom(type))
|
||||
{
|
||||
throw new ArgumentException($"{type} doesn't implement {nameof(ICmdLineRepresentable)}");
|
||||
}
|
||||
|
||||
var method = type.GetMethod(nameof(TryParseFromCmd), BindingFlags.Static | BindingFlags.Public);
|
||||
var parameters = new object[] { cmd, null };
|
||||
if ((bool)method.Invoke(null, parameters))
|
||||
{
|
||||
result = parameters[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static sealed object ParseFor(Type type, string cmdRepr)
|
||||
{
|
||||
if (type.IsEnum)
|
||||
{
|
||||
return Enum.Parse(type, cmdRepr);
|
||||
}
|
||||
else if (type.IsPrimitive)
|
||||
{
|
||||
if (type == typeof(bool))
|
||||
{
|
||||
return bool.Parse(cmdRepr.ToLowerInvariant());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Converts numeric types like Uint32
|
||||
return Convert.ChangeType(cmdRepr, type, CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
else if (type.IsValueType && type == typeof(DateTimeOffset))
|
||||
{
|
||||
if (DateTimeOffset.TryParse(cmdRepr, out var structResult))
|
||||
{
|
||||
return structResult;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Invalid DateTimeOffset format '{cmdRepr}'");
|
||||
}
|
||||
else if (type.IsClass)
|
||||
{
|
||||
if (type == typeof(string))
|
||||
{
|
||||
return cmdRepr;
|
||||
}
|
||||
else
|
||||
{
|
||||
TryParseFromCmdFor(type, cmdRepr, out var classResult);
|
||||
return classResult;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotImplementedException($"Parsing type {type} is not supported yet");
|
||||
}
|
||||
|
||||
public static string ToCmdRepr(Type type, object value)
|
||||
{
|
||||
if (type.IsEnum || type.IsPrimitive)
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
else if (type.IsValueType && type == typeof(DateTimeOffset))
|
||||
{
|
||||
return ((DateTimeOffset)value).ToString("o");
|
||||
}
|
||||
else if (type.IsClass)
|
||||
{
|
||||
if (type == typeof(string))
|
||||
{
|
||||
return (string)value;
|
||||
}
|
||||
else
|
||||
{
|
||||
TryToCmdRepresentableFor(type, value, out var result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotImplementedException($"CmdRepr of {type} is not supported yet");
|
||||
}
|
||||
}
|
@ -2,11 +2,12 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Globalization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class KeyboardKeysProperty
|
||||
public record KeyboardKeysProperty : ICmdLineRepresentable
|
||||
{
|
||||
public KeyboardKeysProperty()
|
||||
{
|
||||
@ -20,5 +21,24 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
|
||||
[JsonPropertyName("value")]
|
||||
public HotkeySettings Value { get; set; }
|
||||
|
||||
public static bool TryParseFromCmd(string cmd, out object result)
|
||||
{
|
||||
if (!HotkeySettings.TryParseFromCmd(cmd, out var hotkey))
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = new KeyboardKeysProperty { Value = (HotkeySettings)hotkey };
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryToCmdRepresentable(out string result)
|
||||
{
|
||||
return Value.TryToCmdRepresentable(out result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,16 +5,19 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class KeyboardManagerProperties
|
||||
{
|
||||
[JsonPropertyName("activeConfiguration")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public GenericProperty<string> ActiveConfiguration { get; set; }
|
||||
|
||||
// List of all Keyboard Configurations.
|
||||
[JsonPropertyName("keyboardConfigurations")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public GenericProperty<List<string>> KeyboardConfigurations { get; set; }
|
||||
|
||||
public KeyboardManagerProperties()
|
||||
|
@ -4,12 +4,14 @@
|
||||
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Settings.UI.Library.Attributes;
|
||||
using Settings.UI.Library.Enumerations;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class MeasureToolProperties
|
||||
{
|
||||
[CmdConfigureIgnore]
|
||||
public HotkeySettings DefaultActivationShortcut => new HotkeySettings(true, false, false, true, 0x4D);
|
||||
|
||||
public MeasureToolProperties()
|
||||
@ -35,6 +37,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
[JsonConverter(typeof(BoolPropertyJsonConverter))]
|
||||
public bool PerColorChannelEdgeDetection { get; set; }
|
||||
|
||||
[CmdConfigureIgnore]
|
||||
public IntProperty UnitsOfMeasure { get; set; }
|
||||
|
||||
public IntProperty PixelTolerance { get; set; }
|
||||
|
@ -3,11 +3,13 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class MouseHighlighterProperties
|
||||
{
|
||||
[CmdConfigureIgnore]
|
||||
public HotkeySettings DefaultActivationShortcut => new HotkeySettings(true, false, false, true, 0x48);
|
||||
|
||||
[JsonPropertyName("activation_shortcut")]
|
||||
@ -20,6 +22,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
public StringProperty RightButtonClickColor { get; set; }
|
||||
|
||||
[JsonPropertyName("highlight_opacity")]
|
||||
[CmdConfigureIgnore]
|
||||
public IntProperty HighlightOpacity { get; set; }
|
||||
|
||||
[JsonPropertyName("always_color")]
|
||||
|
@ -3,11 +3,13 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class MouseJumpProperties
|
||||
{
|
||||
[CmdConfigureIgnore]
|
||||
public HotkeySettings DefaultActivationShortcut => new HotkeySettings(true, false, false, true, 0x44);
|
||||
|
||||
[JsonPropertyName("activation_shortcut")]
|
||||
|
@ -9,7 +9,7 @@ using System.Text.Json.Serialization;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class MouseJumpThumbnailSize : INotifyPropertyChanged
|
||||
public record MouseJumpThumbnailSize : INotifyPropertyChanged, ICmdLineRepresentable
|
||||
{
|
||||
private int _width;
|
||||
private int _height;
|
||||
@ -64,5 +64,30 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
public static bool TryParseFromCmd(string cmd, out object result)
|
||||
{
|
||||
result = null;
|
||||
|
||||
var parts = cmd.Split('x');
|
||||
if (parts.Length != 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (int.TryParse(parts[0], out int width) && int.TryParse(parts[1], out int height))
|
||||
{
|
||||
result = new MouseJumpThumbnailSize { Width = width, Height = height };
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryToCmdRepresentable(out string result)
|
||||
{
|
||||
result = $"{Width}x{Height}";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,13 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class MousePointerCrosshairsProperties
|
||||
{
|
||||
[CmdConfigureIgnore]
|
||||
public HotkeySettings DefaultActivationShortcut => new HotkeySettings(true, false, true, false, 0x50); // Win + Alt + P
|
||||
|
||||
[JsonPropertyName("activation_shortcut")]
|
||||
|
@ -6,6 +6,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
@ -23,16 +24,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
|
||||
public class MouseWithoutBordersProperties : ICloneable
|
||||
{
|
||||
[CmdConfigureIgnore]
|
||||
public static HotkeySettings DefaultHotKeySwitch2AllPC => new HotkeySettings();
|
||||
|
||||
[CmdConfigureIgnore]
|
||||
public static HotkeySettings DefaultHotKeyLockMachine => new HotkeySettings(true, true, true, false, 0x4C);
|
||||
|
||||
[CmdConfigureIgnore]
|
||||
public static HotkeySettings DefaultHotKeyReconnect => new HotkeySettings(true, true, true, false, 0x52);
|
||||
|
||||
[CmdConfigureIgnore]
|
||||
public static HotkeySettings DefaultHotKeyToggleEasyMouse => new HotkeySettings(true, true, true, false, 0x45);
|
||||
|
||||
[CmdConfigureIgnore]
|
||||
public StringProperty SecurityKey { get; set; }
|
||||
|
||||
[CmdConfigureIgnore]
|
||||
[JsonConverter(typeof(BoolPropertyJsonConverter))]
|
||||
public bool UseService { get; set; }
|
||||
|
||||
@ -72,42 +79,54 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
[JsonConverter(typeof(BoolPropertyJsonConverter))]
|
||||
public bool ShowClipboardAndNetworkStatusMessages { get; set; }
|
||||
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public List<string> MachineMatrixString { get; set; }
|
||||
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public StringProperty MachinePool { get; set; }
|
||||
|
||||
[JsonConverter(typeof(BoolPropertyJsonConverter))]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public bool MatrixOneRow { get; set; }
|
||||
|
||||
public IntProperty EasyMouse { get; set; }
|
||||
|
||||
[CmdConfigureIgnore]
|
||||
public IntProperty MachineID { get; set; }
|
||||
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public IntProperty LastX { get; set; }
|
||||
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public IntProperty LastY { get; set; }
|
||||
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public IntProperty PackageID { get; set; }
|
||||
|
||||
[JsonConverter(typeof(BoolPropertyJsonConverter))]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public bool FirstRun { get; set; }
|
||||
|
||||
public IntProperty HotKeySwitchMachine { get; set; }
|
||||
|
||||
[ObsoleteAttribute("Use ToggleEasyMouseShortcut instead", false)]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public IntProperty HotKeyToggleEasyMouse { get; set; }
|
||||
|
||||
[ObsoleteAttribute("Use LockMachineShortcut instead", false)]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public IntProperty HotKeyLockMachine { get; set; }
|
||||
|
||||
[ObsoleteAttribute("Use ReconnectShortcut instead", false)]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public IntProperty HotKeyReconnect { get; set; }
|
||||
|
||||
[ObsoleteAttribute("Use Switch2AllPCShortcut instead", false)]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public IntProperty HotKeySwitch2AllPC { get; set; }
|
||||
|
||||
public HotkeySettings ToggleEasyMouseShortcut { get; set; }
|
||||
@ -118,6 +137,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
|
||||
public HotkeySettings Switch2AllPCShortcut { get; set; }
|
||||
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public IntProperty TCPPort { get; set; }
|
||||
|
||||
[JsonConverter(typeof(BoolPropertyJsonConverter))]
|
||||
@ -126,8 +146,10 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
public StringProperty Name2IP { get; set; }
|
||||
|
||||
[JsonConverter(typeof(BoolPropertyJsonConverter))]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public bool FirstCtrlShiftS { get; set; }
|
||||
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public StringProperty DeviceID { get; set; }
|
||||
|
||||
public MouseWithoutBordersProperties()
|
||||
|
@ -3,11 +3,13 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Text.Json;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class PastePlainProperties
|
||||
{
|
||||
[CmdConfigureIgnore]
|
||||
public HotkeySettings DefaultActivationShortcut => new HotkeySettings(true, true, true, false, 0x56); // Ctrl+Win+Alt+V
|
||||
|
||||
public PastePlainProperties()
|
||||
|
@ -3,11 +3,13 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Text.Json;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class PeekProperties
|
||||
{
|
||||
[CmdConfigureIgnore]
|
||||
public HotkeySettings DefaultActivationShortcut => new HotkeySettings(false, true, false, false, 0x20);
|
||||
|
||||
public PeekProperties()
|
||||
|
@ -4,15 +4,18 @@
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using ManagedCommon;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class PowerLauncherProperties
|
||||
{
|
||||
[JsonPropertyName("search_result_preference")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public string SearchResultPreference { get; set; }
|
||||
|
||||
[JsonPropertyName("search_type_preference")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public string SearchTypePreference { get; set; }
|
||||
|
||||
[JsonPropertyName("maximum_number_of_results")]
|
||||
@ -22,18 +25,23 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
public HotkeySettings OpenPowerLauncher { get; set; }
|
||||
|
||||
[JsonPropertyName("open_file_location")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public HotkeySettings OpenFileLocation { get; set; }
|
||||
|
||||
[JsonPropertyName("copy_path_location")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public HotkeySettings CopyPathLocation { get; set; }
|
||||
|
||||
[JsonPropertyName("open_console")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public HotkeySettings OpenConsole { get; set; }
|
||||
|
||||
[JsonPropertyName("override_win_r_key")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public bool OverrideWinkeyR { get; set; }
|
||||
|
||||
[JsonPropertyName("override_win_s_key")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public bool OverrideWinkeyS { get; set; }
|
||||
|
||||
[JsonPropertyName("ignore_hotkeys_in_fullscreen")]
|
||||
@ -49,6 +57,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
public Theme Theme { get; set; }
|
||||
|
||||
[JsonPropertyName("show_plugins_overview")]
|
||||
[CmdConfigureIgnore]
|
||||
public int ShowPluginsOverview { get; set; }
|
||||
|
||||
[JsonPropertyName("title_fontsize")]
|
||||
@ -84,10 +93,13 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
[JsonPropertyName("generate_thumbnails_from_files")]
|
||||
public bool GenerateThumbnailsFromFiles { get; set; }
|
||||
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public HotkeySettings DefaultOpenPowerLauncher => new HotkeySettings(false, false, true, false, 32);
|
||||
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public HotkeySettings DefaultOpenFileLocation => new HotkeySettings();
|
||||
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public HotkeySettings DefaultCopyPathLocation => new HotkeySettings();
|
||||
|
||||
public PowerLauncherProperties()
|
||||
|
@ -3,11 +3,13 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Text.Json;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class PowerOcrProperties
|
||||
{
|
||||
[CmdConfigureIgnore]
|
||||
public HotkeySettings DefaultActivationShortcut => new HotkeySettings(true, false, false, true, 0x54); // Win+Shift+T
|
||||
|
||||
public PowerOcrProperties()
|
||||
|
@ -2,7 +2,9 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
@ -16,12 +18,14 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
ShowIcon = new BoolProperty();
|
||||
ExtendedContextMenuOnly = new BoolProperty();
|
||||
UseBoostLib = new BoolProperty();
|
||||
Enabled = new BoolProperty();
|
||||
}
|
||||
|
||||
[ObsoleteAttribute("Now controlled from the general settings", false)]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public BoolProperty Enabled { get; set; }
|
||||
|
||||
[JsonPropertyName("bool_persist_input")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public BoolProperty PersistState { get; set; }
|
||||
|
||||
[JsonPropertyName("bool_mru_enabled")]
|
||||
@ -31,6 +35,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
public IntProperty MaxMRUSize { get; set; }
|
||||
|
||||
[JsonPropertyName("bool_show_icon_on_menu")]
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public BoolProperty ShowIcon { get; set; }
|
||||
|
||||
[JsonPropertyName("bool_show_extended_menu")]
|
||||
|
@ -1,8 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\..\Version.props" />
|
||||
<Import Project="..\..\Version.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0-windows</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<Version>$(Version).0</Version>
|
||||
<Authors>Microsoft Corporation</Authors>
|
||||
@ -20,42 +22,42 @@
|
||||
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="backup_restore_settings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<None Include="backup_restore_settings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.Abstractions" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.Abstractions" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\common\interop\PowerToys.Interop.vcxproj" />
|
||||
<ProjectReference Include="..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
<ProjectReference Include="..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\common\interop\PowerToys.Interop.vcxproj" />
|
||||
<ProjectReference Include="..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
<ProjectReference Include="..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Resources\Resources.Designer.cs">
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="Resources\Resources.Designer.cs">
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Resources\Resources.resx">
|
||||
<SubType>Designer</SubType>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Resources\Resources.resx">
|
||||
<SubType>Designer</SubType>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -3,11 +3,13 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class ShortcutGuideProperties
|
||||
{
|
||||
[CmdConfigureIgnore]
|
||||
public HotkeySettings DefaultOpenShortcutGuide => new HotkeySettings(true, false, false, true, 0xBF);
|
||||
|
||||
public ShortcutGuideProperties()
|
||||
|
@ -8,7 +8,7 @@ using System.Text.Json.Serialization;
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
// Represents the configuration property of the settings that store string type.
|
||||
public class StringProperty
|
||||
public record StringProperty : ICmdLineRepresentable
|
||||
{
|
||||
public StringProperty()
|
||||
{
|
||||
@ -35,6 +35,18 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
return new StringProperty(v);
|
||||
}
|
||||
|
||||
public static bool TryParseFromCmd(string cmd, out object result)
|
||||
{
|
||||
result = new StringProperty(cmd);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryToCmdRepresentable(out string result)
|
||||
{
|
||||
result = Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static implicit operator StringProperty(string v)
|
||||
{
|
||||
return new StringProperty(v);
|
||||
|
@ -0,0 +1,81 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library;
|
||||
|
||||
public class CommandLineUtils
|
||||
{
|
||||
private static Type GetSettingsConfigType(string moduleName, Assembly settingsLibraryAssembly)
|
||||
{
|
||||
var settingsClassName = moduleName == "GeneralSettings" ? moduleName : moduleName + "Settings";
|
||||
return settingsLibraryAssembly.GetType(typeof(CommandLineUtils).Namespace + "." + settingsClassName);
|
||||
}
|
||||
|
||||
public static ISettingsConfig GetSettingsConfigFor(string moduleName, ISettingsUtils settingsUtils, Assembly settingsLibraryAssembly)
|
||||
{
|
||||
return GetSettingsConfigFor(GetSettingsConfigType(moduleName, settingsLibraryAssembly), settingsUtils);
|
||||
}
|
||||
|
||||
/// Executes SettingsRepository<moduleSettingsType>.GetInstance(settingsUtils).SettingsConfig
|
||||
public static ISettingsConfig GetSettingsConfigFor(Type moduleSettingsType, ISettingsUtils settingsUtils)
|
||||
{
|
||||
var genericSettingsRepositoryType = typeof(SettingsRepository<>);
|
||||
var moduleSettingsRepositoryType = genericSettingsRepositoryType.MakeGenericType(moduleSettingsType);
|
||||
|
||||
// Note: GeneralSettings is only used here only to satisfy nameof constrains, i.e. the choice of this particular type doesn't have any special significance.
|
||||
var getInstanceInfo = moduleSettingsRepositoryType.GetMethod(nameof(SettingsRepository<GeneralSettings>.GetInstance));
|
||||
var settingsRepository = getInstanceInfo.Invoke(null, new object[] { settingsUtils });
|
||||
var settingsConfigProperty = getInstanceInfo.ReturnType.GetProperty(nameof(SettingsRepository<GeneralSettings>.SettingsConfig));
|
||||
return settingsConfigProperty.GetValue(settingsRepository) as ISettingsConfig;
|
||||
}
|
||||
|
||||
public static Assembly GetSettingsAssembly()
|
||||
{
|
||||
return AppDomain.CurrentDomain.GetAssemblies()
|
||||
.FirstOrDefault(a => a.GetName().Name == "PowerToys.Settings.UI.Lib");
|
||||
}
|
||||
|
||||
public static object GetPropertyValue(string propertyName, ISettingsConfig settingsConfig)
|
||||
{
|
||||
var (settingInfo, properties) = LocateSetting(propertyName, settingsConfig);
|
||||
return settingInfo.GetValue(properties);
|
||||
}
|
||||
|
||||
public static object GetProperties(ISettingsConfig settingsConfig)
|
||||
{
|
||||
var settingsType = settingsConfig.GetType();
|
||||
if (settingsType == typeof(GeneralSettings))
|
||||
{
|
||||
return settingsConfig;
|
||||
}
|
||||
|
||||
var settingsConfigInfo = settingsType.GetProperty("Properties");
|
||||
return settingsConfigInfo.GetValue(settingsConfig);
|
||||
}
|
||||
|
||||
public static (PropertyInfo SettingInfo, object Properties) LocateSetting(string propertyName, ISettingsConfig settingsConfig)
|
||||
{
|
||||
var properties = GetProperties(settingsConfig);
|
||||
var propertiesType = properties.GetType();
|
||||
if (propertiesType == typeof(GeneralSettings) && propertyName.StartsWith("Enabled.", StringComparison.InvariantCulture))
|
||||
{
|
||||
var moduleNameToToggle = propertyName.Replace("Enabled.", string.Empty);
|
||||
properties = propertiesType.GetProperty("Enabled").GetValue(properties);
|
||||
propertiesType = properties.GetType();
|
||||
propertyName = moduleNameToToggle;
|
||||
}
|
||||
|
||||
return (propertiesType.GetProperty(propertyName), properties);
|
||||
}
|
||||
|
||||
public static PropertyInfo GetSettingPropertyInfo(string propertyName, ISettingsConfig settingsConfig)
|
||||
{
|
||||
return LocateSetting(propertyName, settingsConfig).SettingInfo;
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using System.Xml;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library;
|
||||
|
||||
/// <summary>
|
||||
/// This user flow allows DSC resources to use PowerToys.Settings executable to get settings values by querying them from command line using the following syntax:
|
||||
/// PowerToys.Settings.exe get <path to a json file containing a list of modules and their corresponding properties>
|
||||
///
|
||||
/// Example: PowerToys.Settings.exe get %TEMP%\properties.json
|
||||
/// `properties.json` file contents:
|
||||
/// {
|
||||
/// "AlwaysOnTop": ["FrameEnabled", "FrameAccentColor"],
|
||||
/// "FancyZones": ["FancyzonesShiftDrag", "FancyzonesShowOnAllMonitors"]
|
||||
/// }
|
||||
///
|
||||
/// Upon PowerToys.Settings.exe completion, it'll update `properties.json` file to contain something like this:
|
||||
/// {
|
||||
/// "AlwaysOnTop": {
|
||||
/// "FrameEnabled": true,
|
||||
/// "FrameAccentColor": "#0099cc"
|
||||
/// },
|
||||
/// "FancyZones": {
|
||||
/// "FancyzonesShiftDrag": true,
|
||||
/// "FancyzonesShowOnAllMonitors": false
|
||||
/// }
|
||||
/// }
|
||||
/// </summary>
|
||||
public sealed class GetSettingCommandLineCommand
|
||||
{
|
||||
private static JsonSerializerOptions _serializerOptions = new JsonSerializerOptions
|
||||
{
|
||||
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||
};
|
||||
|
||||
public static string Execute(Dictionary<string, List<string>> settingNamesForModules)
|
||||
{
|
||||
var modulesSettings = new Dictionary<string, Dictionary<string, object>>();
|
||||
|
||||
var settingsAssembly = CommandLineUtils.GetSettingsAssembly();
|
||||
var settingsUtils = new SettingsUtils();
|
||||
|
||||
var enabledModules = SettingsRepository<GeneralSettings>.GetInstance(settingsUtils).SettingsConfig.Enabled;
|
||||
|
||||
foreach (var (moduleName, settings) in settingNamesForModules)
|
||||
{
|
||||
var moduleSettings = new Dictionary<string, object>();
|
||||
if (moduleName != nameof(GeneralSettings))
|
||||
{
|
||||
moduleSettings.Add("Enabled", typeof(EnabledModules).GetProperty(moduleName).GetValue(enabledModules));
|
||||
}
|
||||
|
||||
var settingsConfig = CommandLineUtils.GetSettingsConfigFor(moduleName, settingsUtils, settingsAssembly);
|
||||
foreach (var settingName in settings)
|
||||
{
|
||||
var value = CommandLineUtils.GetPropertyValue(settingName, settingsConfig);
|
||||
if (value != null)
|
||||
{
|
||||
var cmdReprValue = ICmdLineRepresentable.ToCmdRepr(value.GetType(), value);
|
||||
moduleSettings.Add(settingName, cmdReprValue);
|
||||
}
|
||||
}
|
||||
|
||||
modulesSettings.Add(moduleName, moduleSettings);
|
||||
}
|
||||
|
||||
return JsonSerializer.Serialize(modulesSettings, _serializerOptions);
|
||||
}
|
||||
}
|
@ -103,6 +103,11 @@ namespace Microsoft.PowerToys.Settings.UI.Library.Utilities
|
||||
return LayoutMap.GetKeyName(key);
|
||||
}
|
||||
|
||||
public static uint GetKeyValue(string key)
|
||||
{
|
||||
return LayoutMap.GetKeyValue(key);
|
||||
}
|
||||
|
||||
public static string GetProductVersion()
|
||||
{
|
||||
return interop.CommonManaged.GetProductVersion();
|
||||
|
@ -0,0 +1,109 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library;
|
||||
|
||||
/// <summary>
|
||||
/// This user flow allows DSC resources to use PowerToys.Settings executable to set custom settings values by suppling them from command line using the following syntax:
|
||||
/// PowerToys.Settings.exe setAdditional <module struct name> <path to a json file containing the properties>
|
||||
/// </summary>
|
||||
public sealed class SetAdditionalSettingsCommandLineCommand
|
||||
{
|
||||
private static readonly string KeyPropertyName = "Name";
|
||||
|
||||
private static JsonSerializerOptions _serializerOptions = new JsonSerializerOptions
|
||||
{
|
||||
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||
};
|
||||
|
||||
private struct AdditionalPropertyInfo
|
||||
{
|
||||
public string RootPropertyName;
|
||||
public JsonValueKind RootObjectType;
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, AdditionalPropertyInfo> SupportedAdditionalPropertiesInfoForModules = new Dictionary<string, AdditionalPropertyInfo> { { "PowerLauncher", new AdditionalPropertyInfo { RootPropertyName = "Plugins", RootObjectType = JsonValueKind.Array } } };
|
||||
|
||||
private static void ExecuteRootArray(JsonElement.ArrayEnumerator properties, IEnumerable<object> currentPropertyValuesArray)
|
||||
{
|
||||
// In case it's an array of object -> combine the existing values with the provided
|
||||
var currentPropertyValueType = currentPropertyValuesArray.FirstOrDefault()?.GetType();
|
||||
|
||||
object matchedElement = null;
|
||||
foreach (var arrayElement in properties)
|
||||
{
|
||||
var newElementPropertyValues = new Dictionary<string, object>();
|
||||
foreach (var elementProperty in arrayElement.EnumerateObject())
|
||||
{
|
||||
var elementPropertyName = elementProperty.Name;
|
||||
var elementPropertyType = currentPropertyValueType.GetProperty(elementPropertyName).PropertyType;
|
||||
var elemePropertyValue = ICmdLineRepresentable.ParseFor(elementPropertyType, elementProperty.Value.ToString());
|
||||
if (elementPropertyName == KeyPropertyName)
|
||||
{
|
||||
foreach (var currentElementValue in currentPropertyValuesArray)
|
||||
{
|
||||
var currentElementType = currentElementValue.GetType();
|
||||
var keyPropertyNameInfo = currentElementType.GetProperty(KeyPropertyName);
|
||||
var keyPropertyValue = keyPropertyNameInfo.GetValue(currentElementValue);
|
||||
if (string.Equals(keyPropertyValue, elemePropertyValue))
|
||||
{
|
||||
matchedElement = currentElementValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newElementPropertyValues.Add(elementPropertyName, elemePropertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
if (matchedElement != null)
|
||||
{
|
||||
foreach (var overriddenProperty in newElementPropertyValues)
|
||||
{
|
||||
var propertyInfo = currentPropertyValueType.GetProperty(overriddenProperty.Key);
|
||||
propertyInfo.SetValue(matchedElement, overriddenProperty.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Execute(string moduleName, JsonDocument settings, ISettingsUtils settingsUtils)
|
||||
{
|
||||
Assembly settingsLibraryAssembly = CommandLineUtils.GetSettingsAssembly();
|
||||
|
||||
var settingsConfig = CommandLineUtils.GetSettingsConfigFor(moduleName, settingsUtils, settingsLibraryAssembly);
|
||||
var settingsConfigType = settingsConfig.GetType();
|
||||
|
||||
if (!SupportedAdditionalPropertiesInfoForModules.TryGetValue(moduleName, out var additionalPropertiesInfo))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var propertyValueInfo = settingsConfigType.GetProperty(additionalPropertiesInfo.RootPropertyName);
|
||||
var currentPropertyValue = propertyValueInfo.GetValue(settingsConfig);
|
||||
|
||||
// For now, only a certain data shapes are supported
|
||||
switch (additionalPropertiesInfo.RootObjectType)
|
||||
{
|
||||
case JsonValueKind.Array:
|
||||
ExecuteRootArray(settings.RootElement.EnumerateArray(), currentPropertyValue as IEnumerable<object>);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
settingsUtils.SaveSettings(settingsConfig.ToJsonString(), settingsConfig.GetModuleName());
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library;
|
||||
|
||||
/// <summary>
|
||||
/// This user flow allows DSC resources to use PowerToys.Settings executable to set settings values by suppling them from command line using the following syntax:
|
||||
/// PowerToys.Settings.exe set <module struct name>.<field name> <field_value>
|
||||
///
|
||||
/// Example: PowerToys.Settings.exe set MeasureTool.MeasureCrossColor "#00FF00"
|
||||
/// </summary>
|
||||
public sealed class SetSettingCommandLineCommand
|
||||
{
|
||||
private static readonly char[] SettingNameSeparator = { '.' };
|
||||
|
||||
private static (string ModuleName, string PropertyName) ParseSettingName(string settingName)
|
||||
{
|
||||
var parts = settingName.Split(SettingNameSeparator, 2, StringSplitOptions.RemoveEmptyEntries);
|
||||
return (parts[0], parts[1]);
|
||||
}
|
||||
|
||||
public static void Execute(string settingName, string settingValue, ISettingsUtils settingsUtils)
|
||||
{
|
||||
Assembly settingsLibraryAssembly = CommandLineUtils.GetSettingsAssembly();
|
||||
|
||||
var (moduleName, propertyName) = ParseSettingName(settingName);
|
||||
|
||||
var settingsConfig = CommandLineUtils.GetSettingsConfigFor(moduleName, settingsUtils, settingsLibraryAssembly);
|
||||
|
||||
var propertyInfo = CommandLineUtils.GetSettingPropertyInfo(propertyName, settingsConfig);
|
||||
if (propertyInfo == null)
|
||||
{
|
||||
throw new ArgumentException($"Property '{propertyName}' wasn't found");
|
||||
}
|
||||
|
||||
if (propertyInfo.PropertyType.GetCustomAttribute<CmdConfigureIgnoreAttribute>() != null)
|
||||
{
|
||||
throw new ArgumentException($"Property '{propertyName}' is explicitly ignored");
|
||||
}
|
||||
|
||||
// Execute settingsConfig.Properties.<propertyName> = settingValue
|
||||
var propertyValue = ICmdLineRepresentable.ParseFor(propertyInfo.PropertyType, settingValue);
|
||||
var (settingInfo, properties) = CommandLineUtils.LocateSetting(propertyName, settingsConfig);
|
||||
settingInfo.SetValue(properties, propertyValue);
|
||||
|
||||
settingsUtils.SaveSettings(settingsConfig.ToJsonString(), settingsConfig.GetModuleName());
|
||||
}
|
||||
}
|
@ -4,11 +4,13 @@
|
||||
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Settings.UI.Library.Attributes;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class VideoConferenceConfigProperties
|
||||
{
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public HotkeySettings DefaultMuteCameraAndMicrophoneHotkey => new HotkeySettings()
|
||||
{
|
||||
Win = true,
|
||||
@ -19,6 +21,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
Code = 81,
|
||||
};
|
||||
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public HotkeySettings DefaultMuteMicrophoneHotkey => new HotkeySettings()
|
||||
{
|
||||
Win = true,
|
||||
@ -29,6 +32,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
Code = 65,
|
||||
};
|
||||
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public HotkeySettings DefaultPushToTalkMicrophoneHotkey => new HotkeySettings()
|
||||
{
|
||||
Win = true,
|
||||
@ -39,6 +43,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
Code = 73,
|
||||
};
|
||||
|
||||
[CmdConfigureIgnoreAttribute]
|
||||
public HotkeySettings DefaultMuteCameraHotkey => new HotkeySettings()
|
||||
{
|
||||
Win = true,
|
||||
|
@ -9,10 +9,12 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class VideoConferenceSettings : BasePTModuleSettings, ISettingsConfig
|
||||
{
|
||||
public const string ModuleName = "Video Conference";
|
||||
|
||||
public VideoConferenceSettings()
|
||||
{
|
||||
Version = "1";
|
||||
Name = "Video Conference";
|
||||
Name = ModuleName;
|
||||
Properties = new VideoConferenceConfigProperties();
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,75 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace Settings.UI.UnitTests.Settings;
|
||||
|
||||
[TestClass]
|
||||
public class ICmdReprParsableTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void KeyboardKeysPropertyParsing()
|
||||
{
|
||||
{
|
||||
Assert.IsTrue(KeyboardKeysProperty.TryParseFromCmd("win+ctrl+Alt+sHifT+Q", out var hotkey));
|
||||
|
||||
Assert.AreEqual(new KeyboardKeysProperty { Value = new HotkeySettings(true, true, true, true, 0x51) }, hotkey);
|
||||
}
|
||||
|
||||
{
|
||||
Assert.IsTrue(KeyboardKeysProperty.TryParseFromCmd("CTRL+z", out var hotkey));
|
||||
Assert.AreEqual(new KeyboardKeysProperty { Value = new HotkeySettings(false, true, false, false, 0x5A) }, hotkey);
|
||||
}
|
||||
|
||||
{
|
||||
Assert.IsTrue(KeyboardKeysProperty.TryParseFromCmd("shift+ALT+0x59", out var hotkey));
|
||||
Assert.AreEqual(new KeyboardKeysProperty { Value = new HotkeySettings(false, false, true, true, 0x59) }, hotkey);
|
||||
}
|
||||
|
||||
{
|
||||
Assert.IsTrue(KeyboardKeysProperty.TryParseFromCmd("alt+Space", out var hotkey));
|
||||
Assert.AreEqual(new KeyboardKeysProperty { Value = new HotkeySettings(false, false, true, false, 0x20) }, hotkey);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void BoolPropertyParsing()
|
||||
{
|
||||
{
|
||||
Assert.IsTrue(BoolProperty.TryParseFromCmd("True", out var result));
|
||||
Assert.AreEqual(new BoolProperty(true), result);
|
||||
}
|
||||
|
||||
{
|
||||
Assert.IsTrue(BoolProperty.TryParseFromCmd("false", out var result));
|
||||
Assert.AreEqual(new BoolProperty(false), result);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void IntPropertyParsing()
|
||||
{
|
||||
{
|
||||
Assert.IsTrue(IntProperty.TryParseFromCmd("123", out var result));
|
||||
Assert.AreEqual(new IntProperty(123), result);
|
||||
}
|
||||
|
||||
{
|
||||
Assert.IsTrue(IntProperty.TryParseFromCmd("1500", out var result));
|
||||
Assert.AreEqual(new IntProperty(1500), result);
|
||||
Assert.AreNotEqual(new IntProperty(15), result);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MouseJumpThumbnailSizeParsing()
|
||||
{
|
||||
{
|
||||
Assert.IsTrue(MouseJumpThumbnailSize.TryParseFromCmd("1920x1080", out var result));
|
||||
Assert.AreEqual(new MouseJumpThumbnailSize { Width = 1920, Height = 1080 }, result);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using static Microsoft.PowerToys.Settings.UI.Library.SetSettingCommandLineCommand;
|
||||
|
||||
namespace Settings.UI.UnitTests.Cmd;
|
||||
|
||||
[TestClass]
|
||||
public class SetSettingCommandTests
|
||||
{
|
||||
private SettingsUtils settingsUtils;
|
||||
|
||||
[TestInitialize]
|
||||
public void Setup()
|
||||
{
|
||||
settingsUtils = new SettingsUtils(new MockFileSystem());
|
||||
}
|
||||
|
||||
private void SetSetting(Type moduleSettingsType, string settingName, string newValueStr)
|
||||
{
|
||||
var settings = CommandLineUtils.GetSettingsConfigFor(moduleSettingsType, settingsUtils);
|
||||
var defaultValue = CommandLineUtils.GetPropertyValue(settingName, settings);
|
||||
var qualifiedName = moduleSettingsType.Name.Replace("Settings", string.Empty) + "." + settingName;
|
||||
var type = CommandLineUtils.GetSettingPropertyInfo(settingName, settings).PropertyType;
|
||||
var newValue = ICmdLineRepresentable.ParseFor(type, newValueStr);
|
||||
|
||||
Execute(qualifiedName, newValueStr, settingsUtils);
|
||||
|
||||
Assert.AreNotEqual(defaultValue, newValue);
|
||||
Assert.AreEqual(newValue, CommandLineUtils.GetPropertyValue(settingName, settings));
|
||||
}
|
||||
|
||||
// Each setting has a different type.
|
||||
[TestMethod]
|
||||
[DataRow(typeof(PowerRenameSettings), nameof(PowerRenameProperties.MaxMRUSize), "123")]
|
||||
[DataRow(typeof(FancyZonesSettings), nameof(FZConfigProperties.FancyzonesBorderColor), "#00FF00")]
|
||||
[DataRow(typeof(MeasureToolSettings), nameof(MeasureToolProperties.ActivationShortcut), "Ctrl+Alt+Delete")]
|
||||
[DataRow(typeof(AlwaysOnTopSettings), nameof(AlwaysOnTopProperties.SoundEnabled), "False")]
|
||||
[DataRow(typeof(PowerAccentSettings), nameof(PowerAccentProperties.ShowUnicodeDescription), "true")]
|
||||
[DataRow(typeof(AwakeSettings), nameof(AwakeProperties.Mode), "EXPIRABLE")]
|
||||
[DataRow(typeof(AwakeSettings), nameof(AwakeProperties.ExpirationDateTime), "March 31, 2020 15:00 +00:00")]
|
||||
[DataRow(typeof(PowerLauncherSettings), nameof(PowerLauncherProperties.MaximumNumberOfResults), "322")]
|
||||
|
||||
[DataRow(typeof(ColorPickerSettings), nameof(ColorPickerProperties.CopiedColorRepresentation), "RGB")]
|
||||
public void SetModuleSetting(Type moduleSettingsType, string settingName, string newValueStr)
|
||||
{
|
||||
SetSetting(moduleSettingsType, settingName, newValueStr);
|
||||
}
|
||||
|
||||
[DataRow(typeof(GeneralSettings), "Enabled.MouseWithoutBorders", "true")]
|
||||
[DataRow(typeof(GeneralSettings), nameof(GeneralSettings.AutoDownloadUpdates), "true")]
|
||||
[TestMethod]
|
||||
public void SetGeneralSetting(Type moduleSettingsType, string settingName, string newValueStr)
|
||||
{
|
||||
SetSetting(moduleSettingsType, settingName, newValueStr);
|
||||
}
|
||||
}
|
@ -237,10 +237,9 @@ namespace ViewModelTests
|
||||
// Assert
|
||||
Assert.IsTrue(modules.FancyZones);
|
||||
Assert.IsTrue(modules.ImageResizer);
|
||||
Assert.IsTrue(modules.FileExplorerPreview);
|
||||
Assert.IsTrue(modules.PowerPreview);
|
||||
Assert.IsTrue(modules.ShortcutGuide);
|
||||
Assert.IsTrue(modules.PowerRename);
|
||||
Assert.IsTrue(modules.KeyboardManager);
|
||||
Assert.IsTrue(modules.PowerLauncher);
|
||||
Assert.IsTrue(modules.ColorPicker);
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
||||
case ModuleType.RegistryPreview: return generalSettingsConfig.Enabled.RegistryPreview;
|
||||
case ModuleType.MeasureTool: return generalSettingsConfig.Enabled.MeasureTool;
|
||||
case ModuleType.ShortcutGuide: return generalSettingsConfig.Enabled.ShortcutGuide;
|
||||
case ModuleType.PowerOCR: return generalSettingsConfig.Enabled.PowerOCR;
|
||||
case ModuleType.PowerOCR: return generalSettingsConfig.Enabled.PowerOcr;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
@ -99,7 +99,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
||||
case ModuleType.RegistryPreview: generalSettingsConfig.Enabled.RegistryPreview = isEnabled; break;
|
||||
case ModuleType.MeasureTool: generalSettingsConfig.Enabled.MeasureTool = isEnabled; break;
|
||||
case ModuleType.ShortcutGuide: generalSettingsConfig.Enabled.ShortcutGuide = isEnabled; break;
|
||||
case ModuleType.PowerOCR: generalSettingsConfig.Enabled.PowerOCR = isEnabled; break;
|
||||
case ModuleType.PowerOCR: generalSettingsConfig.Enabled.PowerOcr = isEnabled; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,9 +3,15 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http.Json;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Common.UI;
|
||||
using interop;
|
||||
@ -42,8 +48,11 @@ namespace Microsoft.PowerToys.Settings.UI
|
||||
ContainsFlyoutPosition,
|
||||
}
|
||||
|
||||
// Quantity of arguments
|
||||
private const int RequiredArgumentsQty = 12;
|
||||
private const int RequiredArgumentsSetSettingQty = 4;
|
||||
private const int RequiredArgumentsSetAdditionalSettingsQty = 4;
|
||||
private const int RequiredArgumentsGetSettingQty = 3;
|
||||
|
||||
private const int RequiredArgumentsLaunchedFromRunnerQty = 12;
|
||||
|
||||
// Create an instance of the IPC wrapper.
|
||||
private static TwoWayPipeMessageIPCManaged ipcmanager;
|
||||
@ -100,6 +109,171 @@ namespace Microsoft.PowerToys.Settings.UI
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLaunchedToSetSetting(string[] cmdArgs)
|
||||
{
|
||||
var settingName = cmdArgs[2];
|
||||
var settingValue = cmdArgs[3];
|
||||
try
|
||||
{
|
||||
SetSettingCommandLineCommand.Execute(settingName, settingValue, new SettingsUtils());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"SetSettingCommandLineCommand exception: '{settingName}' setting couldn't be set to {settingValue}", ex);
|
||||
}
|
||||
|
||||
Exit();
|
||||
}
|
||||
|
||||
private void OnLaunchedToSetAdditionalSetting(string[] cmdArgs)
|
||||
{
|
||||
var moduleName = cmdArgs[2];
|
||||
var ipcFileName = cmdArgs[3];
|
||||
try
|
||||
{
|
||||
using (var settings = JsonDocument.Parse(File.ReadAllText(ipcFileName)))
|
||||
{
|
||||
SetAdditionalSettingsCommandLineCommand.Execute(moduleName, settings, new SettingsUtils());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"SetAdditionalSettingsCommandLineCommand exception: couldn't set additional settings for '{moduleName}'", ex);
|
||||
}
|
||||
|
||||
Exit();
|
||||
}
|
||||
|
||||
private void OnLaunchedToGetSetting(string[] cmdArgs)
|
||||
{
|
||||
var ipcFileName = cmdArgs[2];
|
||||
|
||||
try
|
||||
{
|
||||
var requestedSettings = JsonSerializer.Deserialize<Dictionary<string, List<string>>>(File.ReadAllText(ipcFileName));
|
||||
File.WriteAllText(ipcFileName, GetSettingCommandLineCommand.Execute(requestedSettings));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"GetSettingCommandLineCommand exception", ex);
|
||||
}
|
||||
|
||||
Exit();
|
||||
}
|
||||
|
||||
private void OnLaunchedFromRunner(string[] cmdArgs)
|
||||
{
|
||||
// Skip the first argument which is prepended when launched by explorer
|
||||
if (cmdArgs[0].EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase) && cmdArgs[1].EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase) && (cmdArgs.Length >= RequiredArgumentsLaunchedFromRunnerQty + 1))
|
||||
{
|
||||
cmdArgs = cmdArgs.Skip(1).ToArray();
|
||||
}
|
||||
|
||||
_ = int.TryParse(cmdArgs[(int)Arguments.PTPid], out int powerToysPID);
|
||||
PowerToysPID = powerToysPID;
|
||||
|
||||
IsElevated = cmdArgs[(int)Arguments.ElevatedStatus] == "true";
|
||||
IsUserAnAdmin = cmdArgs[(int)Arguments.IsUserAdmin] == "true";
|
||||
ShowOobe = cmdArgs[(int)Arguments.ShowOobeWindow] == "true";
|
||||
ShowScoobe = cmdArgs[(int)Arguments.ShowScoobeWindow] == "true";
|
||||
ShowFlyout = cmdArgs[(int)Arguments.ShowFlyout] == "true";
|
||||
bool containsSettingsWindow = cmdArgs[(int)Arguments.ContainsSettingsWindow] == "true";
|
||||
bool containsFlyoutPosition = cmdArgs[(int)Arguments.ContainsFlyoutPosition] == "true";
|
||||
|
||||
// To keep track of variable arguments
|
||||
int currentArgumentIndex = RequiredArgumentsLaunchedFromRunnerQty;
|
||||
|
||||
if (containsSettingsWindow)
|
||||
{
|
||||
// Open specific window
|
||||
StartupPage = GetPage(cmdArgs[currentArgumentIndex]);
|
||||
|
||||
currentArgumentIndex++;
|
||||
}
|
||||
|
||||
int flyout_x = 0;
|
||||
int flyout_y = 0;
|
||||
if (containsFlyoutPosition)
|
||||
{
|
||||
// get the flyout position arguments
|
||||
_ = int.TryParse(cmdArgs[currentArgumentIndex++], out flyout_x);
|
||||
_ = int.TryParse(cmdArgs[currentArgumentIndex++], out flyout_y);
|
||||
}
|
||||
|
||||
RunnerHelper.WaitForPowerToysRunner(PowerToysPID, () =>
|
||||
{
|
||||
Environment.Exit(0);
|
||||
});
|
||||
|
||||
ipcmanager = new TwoWayPipeMessageIPCManaged(cmdArgs[(int)Arguments.SettingsPipeName], cmdArgs[(int)Arguments.PTPipeName], (string message) =>
|
||||
{
|
||||
if (IPCMessageReceivedCallback != null && message.Length > 0)
|
||||
{
|
||||
IPCMessageReceivedCallback(message);
|
||||
}
|
||||
});
|
||||
ipcmanager.Start();
|
||||
|
||||
if (!ShowOobe && !ShowScoobe && !ShowFlyout)
|
||||
{
|
||||
settingsWindow = new MainWindow();
|
||||
settingsWindow.Activate();
|
||||
settingsWindow.ExtendsContentIntoTitleBar = true;
|
||||
settingsWindow.NavigateToSection(StartupPage);
|
||||
|
||||
// https://github.com/microsoft/microsoft-ui-xaml/issues/7595 - Activate doesn't bring window to the foreground
|
||||
// Need to call SetForegroundWindow to actually gain focus.
|
||||
WindowHelpers.BringToForeground(settingsWindow.GetWindowHandle());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create the Settings window hidden so that it's fully initialized and
|
||||
// it will be ready to receive the notification if the user opens
|
||||
// the Settings from the tray icon.
|
||||
settingsWindow = new MainWindow(true);
|
||||
|
||||
if (ShowOobe)
|
||||
{
|
||||
PowerToysTelemetry.Log.WriteEvent(new OobeStartedEvent());
|
||||
OobeWindow oobeWindow = new OobeWindow(OOBE.Enums.PowerToysModules.Overview);
|
||||
oobeWindow.Activate();
|
||||
oobeWindow.ExtendsContentIntoTitleBar = true;
|
||||
SetOobeWindow(oobeWindow);
|
||||
}
|
||||
else if (ShowScoobe)
|
||||
{
|
||||
PowerToysTelemetry.Log.WriteEvent(new ScoobeStartedEvent());
|
||||
OobeWindow scoobeWindow = new OobeWindow(OOBE.Enums.PowerToysModules.WhatsNew);
|
||||
scoobeWindow.Activate();
|
||||
scoobeWindow.ExtendsContentIntoTitleBar = true;
|
||||
SetOobeWindow(scoobeWindow);
|
||||
}
|
||||
else if (ShowFlyout)
|
||||
{
|
||||
POINT? p = null;
|
||||
if (containsFlyoutPosition)
|
||||
{
|
||||
p = new POINT(flyout_x, flyout_y);
|
||||
}
|
||||
|
||||
ShellPage.OpenFlyoutCallback(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (SelectedTheme() == ElementTheme.Default)
|
||||
{
|
||||
try
|
||||
{
|
||||
themeListener = new ThemeListener();
|
||||
themeListener.ThemeChanged += (_) => HandleThemeChange();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"HandleThemeChange exception. Please install .NET 4.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the application is launched normally by the end user. Other entry points
|
||||
/// will be used such as when the application is launched to open a specific file.
|
||||
@ -109,117 +283,21 @@ namespace Microsoft.PowerToys.Settings.UI
|
||||
{
|
||||
var cmdArgs = Environment.GetCommandLineArgs();
|
||||
|
||||
if (cmdArgs != null && cmdArgs.Length >= RequiredArgumentsQty)
|
||||
if (cmdArgs?.Length >= RequiredArgumentsLaunchedFromRunnerQty)
|
||||
{
|
||||
// Skip the first argument which is prepended when launched by explorer
|
||||
if (cmdArgs[0].EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase) && cmdArgs[1].EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase) && (cmdArgs.Length >= RequiredArgumentsQty + 1))
|
||||
{
|
||||
cmdArgs = cmdArgs.Skip(1).ToArray();
|
||||
}
|
||||
|
||||
_ = int.TryParse(cmdArgs[(int)Arguments.PTPid], out int powerToysPID);
|
||||
PowerToysPID = powerToysPID;
|
||||
|
||||
IsElevated = cmdArgs[(int)Arguments.ElevatedStatus] == "true";
|
||||
IsUserAnAdmin = cmdArgs[(int)Arguments.IsUserAdmin] == "true";
|
||||
ShowOobe = cmdArgs[(int)Arguments.ShowOobeWindow] == "true";
|
||||
ShowScoobe = cmdArgs[(int)Arguments.ShowScoobeWindow] == "true";
|
||||
ShowFlyout = cmdArgs[(int)Arguments.ShowFlyout] == "true";
|
||||
bool containsSettingsWindow = cmdArgs[(int)Arguments.ContainsSettingsWindow] == "true";
|
||||
bool containsFlyoutPosition = cmdArgs[(int)Arguments.ContainsFlyoutPosition] == "true";
|
||||
|
||||
// To keep track of variable arguments
|
||||
int currentArgumentIndex = RequiredArgumentsQty;
|
||||
|
||||
if (containsSettingsWindow)
|
||||
{
|
||||
// Open specific window
|
||||
StartupPage = GetPage(cmdArgs[currentArgumentIndex]);
|
||||
|
||||
currentArgumentIndex++;
|
||||
}
|
||||
|
||||
int flyout_x = 0;
|
||||
int flyout_y = 0;
|
||||
if (containsFlyoutPosition)
|
||||
{
|
||||
// get the flyout position arguments
|
||||
_ = int.TryParse(cmdArgs[currentArgumentIndex++], out flyout_x);
|
||||
_ = int.TryParse(cmdArgs[currentArgumentIndex++], out flyout_y);
|
||||
}
|
||||
|
||||
RunnerHelper.WaitForPowerToysRunner(PowerToysPID, () =>
|
||||
{
|
||||
Environment.Exit(0);
|
||||
});
|
||||
|
||||
ipcmanager = new TwoWayPipeMessageIPCManaged(cmdArgs[(int)Arguments.SettingsPipeName], cmdArgs[(int)Arguments.PTPipeName], (string message) =>
|
||||
{
|
||||
if (IPCMessageReceivedCallback != null && message.Length > 0)
|
||||
{
|
||||
IPCMessageReceivedCallback(message);
|
||||
}
|
||||
});
|
||||
ipcmanager.Start();
|
||||
|
||||
if (!ShowOobe && !ShowScoobe && !ShowFlyout)
|
||||
{
|
||||
settingsWindow = new MainWindow();
|
||||
settingsWindow.Activate();
|
||||
settingsWindow.ExtendsContentIntoTitleBar = true;
|
||||
settingsWindow.NavigateToSection(StartupPage);
|
||||
|
||||
// https://github.com/microsoft/microsoft-ui-xaml/issues/7595 - Activate doesn't bring window to the foreground
|
||||
// Need to call SetForegroundWindow to actually gain focus.
|
||||
WindowHelpers.BringToForeground(settingsWindow.GetWindowHandle());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create the Settings window hidden so that it's fully initialized and
|
||||
// it will be ready to receive the notification if the user opens
|
||||
// the Settings from the tray icon.
|
||||
settingsWindow = new MainWindow(true);
|
||||
|
||||
if (ShowOobe)
|
||||
{
|
||||
PowerToysTelemetry.Log.WriteEvent(new OobeStartedEvent());
|
||||
OobeWindow oobeWindow = new OobeWindow(OOBE.Enums.PowerToysModules.Overview);
|
||||
oobeWindow.Activate();
|
||||
oobeWindow.ExtendsContentIntoTitleBar = true;
|
||||
SetOobeWindow(oobeWindow);
|
||||
}
|
||||
else if (ShowScoobe)
|
||||
{
|
||||
PowerToysTelemetry.Log.WriteEvent(new ScoobeStartedEvent());
|
||||
OobeWindow scoobeWindow = new OobeWindow(OOBE.Enums.PowerToysModules.WhatsNew);
|
||||
scoobeWindow.Activate();
|
||||
scoobeWindow.ExtendsContentIntoTitleBar = true;
|
||||
SetOobeWindow(scoobeWindow);
|
||||
}
|
||||
else if (ShowFlyout)
|
||||
{
|
||||
POINT? p = null;
|
||||
if (containsFlyoutPosition)
|
||||
{
|
||||
p = new POINT(flyout_x, flyout_y);
|
||||
}
|
||||
|
||||
ShellPage.OpenFlyoutCallback(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (SelectedTheme() == ElementTheme.Default)
|
||||
{
|
||||
try
|
||||
{
|
||||
themeListener = new ThemeListener();
|
||||
themeListener.ThemeChanged += (_) => HandleThemeChange();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"HandleThemeChange exception. Please install .NET 4.", ex);
|
||||
}
|
||||
}
|
||||
OnLaunchedFromRunner(cmdArgs);
|
||||
}
|
||||
else if (cmdArgs?.Length == RequiredArgumentsSetSettingQty && cmdArgs[1] == "set")
|
||||
{
|
||||
OnLaunchedToSetSetting(cmdArgs);
|
||||
}
|
||||
else if (cmdArgs?.Length == RequiredArgumentsSetAdditionalSettingsQty && cmdArgs[1] == "setAdditional")
|
||||
{
|
||||
OnLaunchedToSetAdditionalSetting(cmdArgs);
|
||||
}
|
||||
else if (cmdArgs?.Length == RequiredArgumentsGetSettingQty && cmdArgs[1] == "get")
|
||||
{
|
||||
OnLaunchedToGetSetting(cmdArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -417,7 +495,7 @@ namespace Microsoft.PowerToys.Settings.UI
|
||||
case "QuickAccent": return typeof(PowerAccentPage);
|
||||
case "FileExplorer": return typeof(PowerPreviewPage);
|
||||
case "ShortcutGuide": return typeof(ShortcutGuidePage);
|
||||
case "PowerOCR": return typeof(PowerOcrPage);
|
||||
case "PowerOcr": return typeof(PowerOcrPage);
|
||||
case "VideoConference": return typeof(VideoConferencePage);
|
||||
case "MeasureTool": return typeof(MeasureToolPage);
|
||||
case "Hosts": return typeof(HostsPage);
|
||||
|
@ -321,7 +321,7 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
|
||||
// Tab and Shift+Tab are accessible keys and should not be displayed in the hotkey control.
|
||||
if (internalSettings.Code > 0 && !internalSettings.IsAccessibleShortcut())
|
||||
{
|
||||
lastValidSettings = internalSettings.Clone();
|
||||
lastValidSettings = internalSettings with { };
|
||||
|
||||
if (!ComboIsValid(lastValidSettings))
|
||||
{
|
||||
@ -436,7 +436,7 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
|
||||
{
|
||||
if (ComboIsValid(lastValidSettings))
|
||||
{
|
||||
HotkeySettings = lastValidSettings.Clone();
|
||||
HotkeySettings = lastValidSettings with { };
|
||||
}
|
||||
|
||||
PreviewKeysControl.ItemsSource = hotkeySettings.GetKeysList();
|
||||
|
@ -109,7 +109,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
}
|
||||
else
|
||||
{
|
||||
_isEnabled = GeneralSettingsConfig.Enabled.PowerOCR;
|
||||
_isEnabled = GeneralSettingsConfig.Enabled.PowerOcr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,8 +129,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
_isEnabled = value;
|
||||
OnPropertyChanged(nameof(IsEnabled));
|
||||
|
||||
// Set the status of PowerOCR in the general settings
|
||||
GeneralSettingsConfig.Enabled.PowerOCR = value;
|
||||
// Set the status of PowerOcr in the general settings
|
||||
GeneralSettingsConfig.Enabled.PowerOcr = value;
|
||||
var outgoing = new OutGoingGeneralSettings(GeneralSettingsConfig);
|
||||
|
||||
SendConfigMSG(outgoing.ToString());
|
||||
|
Loading…
Reference in New Issue
Block a user