Compare commits
296 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6787af413e | ||
|
|
0199b4e212 | ||
|
|
121be772df | ||
|
|
f3b3e3eded | ||
|
|
02c08c942d | ||
|
|
b2370f5c5f | ||
|
|
6556e1b4a2 | ||
|
|
699921d464 | ||
|
|
5c84fbba9a | ||
|
|
0b02422e7d | ||
|
|
677bff55c2 | ||
|
|
3d03bea582 | ||
|
|
278a77247d | ||
|
|
b83a8dcb5d | ||
|
|
9bce103dad | ||
|
|
dfcc4e1b3a | ||
|
|
66892aea60 | ||
|
|
5c708b43c2 | ||
|
|
e2026aedbc | ||
|
|
1911fc2e65 | ||
|
|
e0446a73fa | ||
|
|
16b1bfa4d0 | ||
|
|
f015995ac4 | ||
|
|
0016836022 | ||
|
|
c543b7585a | ||
|
|
b90f1fc237 | ||
|
|
f892338098 | ||
|
|
defead108a | ||
|
|
1f8f9aaf81 | ||
|
|
3b32a3164b | ||
|
|
2f9b753c5b | ||
|
|
b1ac1859be | ||
|
|
74b076e31f | ||
|
|
e3057b5e46 | ||
|
|
92a8b5aa4d | ||
|
|
9b7f92188d | ||
|
|
77301e2930 | ||
|
|
babfc9ade3 | ||
|
|
883bbf102a | ||
|
|
e21f83267a | ||
|
|
27f0782465 | ||
|
|
d45b0dee10 | ||
|
|
2c2a29cd91 | ||
|
|
607a297c4a | ||
|
|
e177c5c94c | ||
|
|
7fb3456e83 | ||
|
|
d37bb2c7f9 | ||
|
|
20519e3b81 | ||
|
|
733613ad28 | ||
|
|
604070763d | ||
|
|
93f88800b8 | ||
|
|
9607888fc5 | ||
|
|
1e6936a8c3 | ||
|
|
cdf2f6b5b4 | ||
|
|
fa3ce8de64 | ||
|
|
59d218d623 | ||
|
|
49fa1b6762 | ||
|
|
a2fe4a0b80 | ||
|
|
86e7a19a98 | ||
|
|
8c86c3dc1b | ||
|
|
2bef7631ae | ||
|
|
550d76a447 | ||
|
|
679b26cde4 | ||
|
|
79c625d737 | ||
|
|
a1d277e771 | ||
|
|
bde0f2f0ba | ||
|
|
53f830bb38 | ||
|
|
a5e3207715 | ||
|
|
b357a085c8 | ||
|
|
9722d808f9 | ||
|
|
0fdc1d0a1f | ||
|
|
f963d28ba8 | ||
|
|
09d1af9c46 | ||
|
|
5d8e894802 | ||
|
|
0ecfbfad53 | ||
|
|
ed35a143ec | ||
|
|
5089729b18 | ||
|
|
b41d2d64cb | ||
|
|
25e882eb78 | ||
|
|
4ef8f3da2b | ||
|
|
b00ce8789f | ||
|
|
b4f81a0c2a | ||
|
|
aa714f7d80 | ||
|
|
ca203435d1 | ||
|
|
ee8893a884 | ||
|
|
bf89238bdf | ||
|
|
360f7cf9c3 | ||
|
|
482ad0e5ee | ||
|
|
cd6ac4f8c2 | ||
|
|
79ac2be617 | ||
|
|
9b4b7cf5d4 | ||
|
|
cc99abcd14 | ||
|
|
f8bcf52741 | ||
|
|
1a10366ab7 | ||
|
|
925b6694ac | ||
|
|
1ad16ade86 | ||
|
|
45e3f02832 | ||
|
|
ba1a681aab | ||
|
|
23bba969dd | ||
|
|
9c743acd2d | ||
|
|
62da7c7be4 | ||
|
|
653a84d3a9 | ||
|
|
8132bbac2e | ||
|
|
197286c21e | ||
|
|
bf48729354 | ||
|
|
a504a75166 | ||
|
|
44ac22c0de | ||
|
|
df1c6b9b0b | ||
|
|
bde0e0b86a | ||
|
|
c1232a7001 | ||
|
|
12c4dbf0e5 | ||
|
|
31a01ab227 | ||
|
|
5dc60b9f35 | ||
|
|
588f134de8 | ||
|
|
2ae867a7e0 | ||
|
|
c77b029ee2 | ||
|
|
d0648d1754 | ||
|
|
1e3486af94 | ||
|
|
8f2b2aba12 | ||
|
|
0b1232b65d | ||
|
|
969abe015c | ||
|
|
9e296cdb46 | ||
|
|
b07627611f | ||
|
|
5e30721e01 | ||
|
|
d03690cffd | ||
|
|
dad732b7e6 | ||
|
|
a2a683d31e | ||
|
|
3ffd007cc0 | ||
|
|
c894d72b52 | ||
|
|
a14784cfd4 | ||
|
|
32440567ad | ||
|
|
25f1dc325d | ||
|
|
38feeee464 | ||
|
|
b2701ad911 | ||
|
|
d41962f9d1 | ||
|
|
ec5d01545a | ||
|
|
03ddadc1ed | ||
|
|
3e55b61ac0 | ||
|
|
5a7f022e40 | ||
|
|
f651e10684 | ||
|
|
b753f920e1 | ||
|
|
415a0cdf28 | ||
|
|
9708961654 | ||
|
|
47bcb117b4 | ||
|
|
3eb38e558e | ||
|
|
a321eb8737 | ||
|
|
62c65659cc | ||
|
|
249addebff | ||
|
|
860087d291 | ||
|
|
b58d4e306a | ||
|
|
21a57a0c58 | ||
|
|
06b1e43492 | ||
|
|
2c1ffde3ed | ||
|
|
918ebc62a2 | ||
|
|
465de438ce | ||
|
|
6ee848b279 | ||
|
|
db5f1622bd | ||
|
|
5e2f681761 | ||
|
|
ad506d78ba | ||
|
|
48b89609e2 | ||
|
|
0fd0a8b7cc | ||
|
|
2e922019d7 | ||
|
|
303d1fef6b | ||
|
|
619ed234a9 | ||
|
|
fd8fc679be | ||
|
|
5a3c852b32 | ||
|
|
4c7de77bfb | ||
|
|
7e91121a33 | ||
|
|
7efe6f1d53 | ||
|
|
511f71c369 | ||
|
|
d284ecdab4 | ||
|
|
0ff2e212d5 | ||
|
|
107595fcb2 | ||
|
|
32fb634a4d | ||
|
|
51fbcc736e | ||
|
|
360a22c537 | ||
|
|
63cb5ab883 | ||
|
|
151a937c10 | ||
|
|
4c88c9b029 | ||
|
|
24664cc859 | ||
|
|
a187456ac3 | ||
|
|
9e4752b114 | ||
|
|
de64b33bb8 | ||
|
|
826858c170 | ||
|
|
f2400ee089 | ||
|
|
6e3587dd43 | ||
|
|
f385e46927 | ||
|
|
c31262b97e | ||
|
|
9fad2d68af | ||
|
|
51180adeb4 | ||
|
|
31c4ab8ac0 | ||
|
|
4f9d31e832 | ||
|
|
22e13e8c40 | ||
|
|
7fc168532c | ||
|
|
69b55bcbd3 | ||
|
|
c6e839271a | ||
|
|
1760af50c8 | ||
|
|
73e33d7ba9 | ||
|
|
776a4d657d | ||
|
|
8f0b962507 | ||
|
|
1519843f6f | ||
|
|
014c2c5249 | ||
|
|
add63d2dde | ||
|
|
81bed3d3d5 | ||
|
|
f22a30ca87 | ||
|
|
946e74a918 | ||
|
|
3cd3cf9830 | ||
|
|
bc634c5f8f | ||
|
|
7357e40d3f | ||
|
|
e714cb9e8b | ||
|
|
fed81c8e22 | ||
|
|
3a65d5ce23 | ||
|
|
6d482cd934 | ||
|
|
0e2d93c630 | ||
|
|
de328c9dfd | ||
|
|
cbe6d19c79 | ||
|
|
57845a2739 | ||
|
|
9a8ab29330 | ||
|
|
3095ade94c | ||
|
|
221df3d26d | ||
|
|
40db3a5d7d | ||
|
|
ee1a1fd614 | ||
|
|
8e8be502fd | ||
|
|
ae4413d0aa | ||
|
|
51b791f9c0 | ||
|
|
767c3c942b | ||
|
|
3fcace6660 | ||
|
|
4c600f5748 | ||
|
|
d84342733d | ||
|
|
d6f0f9ec0e | ||
|
|
fbc922fe97 | ||
|
|
4be84e035f | ||
|
|
254474d12d | ||
|
|
5615987ea2 | ||
|
|
3a93246f08 | ||
|
|
633784fae2 | ||
|
|
af127468a6 | ||
|
|
f892c1284b | ||
|
|
d762b5a017 | ||
|
|
28d7835327 | ||
|
|
03438f9192 | ||
|
|
4df1d2093f | ||
|
|
62a019cc5d | ||
|
|
36c78e9686 | ||
|
|
cb13cfdda7 | ||
|
|
0082f56b58 | ||
|
|
b490a72c1d | ||
|
|
3c0b479669 | ||
|
|
c9ad09226b | ||
|
|
4e771ecfb7 | ||
|
|
be86cd4028 | ||
|
|
3ddbe92f37 | ||
|
|
ca67ea9b4c | ||
|
|
9f78af29bf | ||
|
|
6821a05f76 | ||
|
|
e328c5d505 | ||
|
|
f814d26a4a | ||
|
|
3fc06e6f4f | ||
|
|
d876c267d6 | ||
|
|
1268a463ac | ||
|
|
e64d75a297 | ||
|
|
7900edc96c | ||
|
|
692421ee13 | ||
|
|
1e89054897 | ||
|
|
ae1112ae11 | ||
|
|
800984489d | ||
|
|
997ea3a2f5 | ||
|
|
b9b60a1346 | ||
|
|
e8edbd5394 | ||
|
|
f3e25ae3e6 | ||
|
|
a9518c2e55 | ||
|
|
c4fc67301c | ||
|
|
39cbc59c12 | ||
|
|
96aa6ae3ef | ||
|
|
94d07833c5 | ||
|
|
1d3acbe40b | ||
|
|
389590e45d | ||
|
|
ea3cb026c7 | ||
|
|
1efe5bff9f | ||
|
|
df4fa549ef | ||
|
|
cc7a706f52 | ||
|
|
d4256dad30 | ||
|
|
d9320b7c05 | ||
|
|
27c9a4a6a9 | ||
|
|
18d4dc7321 | ||
|
|
6f241ef001 | ||
|
|
296be2fbd5 | ||
|
|
c1957272ea | ||
|
|
e6afd33621 | ||
|
|
b767773742 | ||
|
|
52ead7ad1b | ||
|
|
b8e083f8fc | ||
|
|
6e3f8bdefd | ||
|
|
8e55f2bf58 | ||
|
|
cd9208b541 | ||
|
|
38029efe50 |
94
.clang-format
Normal file
@@ -0,0 +1,94 @@
|
||||
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
#AllowAllArgumentsOnNextLine: false
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
#AllowAllConstructorInitializersOnNextLine: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
#AllowShortLambdasOnASingleLine: Inline
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: true
|
||||
AfterClass: true
|
||||
AfterControlStatement: true
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterObjCDeclaration: true
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: true
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializers: AfterColon
|
||||
BreakInheritanceList: AfterColon
|
||||
ColumnLimit: 0
|
||||
CommentPragmas: "suppress"
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: false
|
||||
DerivePointerAlignment: false
|
||||
FixNamespaceComments: false
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^.*(precomp|pch|stdafx)'
|
||||
Priority: -1
|
||||
- Regex: '^".*"'
|
||||
Priority: 1
|
||||
- Regex: '^<.*>'
|
||||
Priority: 2
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: "BEGIN_TEST_METHOD_PROPERTIES|BEGIN_MODULE|BEGIN_TEST_CLASS|BEGIN_TEST_METHOD"
|
||||
MacroBlockEnd: "END_TEST_METHOD_PROPERTIES|END_MODULE|END_TEST_CLASS|END_TEST_METHOD"
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: All
|
||||
PointerAlignment: Left
|
||||
ReflowComments: false
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
#SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
10
.github/pull_request_template.md
vendored
@@ -6,11 +6,11 @@
|
||||
|
||||
<!-- Please review the items on the PR checklist before submitting-->
|
||||
## PR Checklist
|
||||
* [ ] Closes #xxx
|
||||
* [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/PowerToys) and sign the CLA
|
||||
* [ ] Tests added/passed
|
||||
* [ ] Requires documentation to be updated
|
||||
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
|
||||
* [] Applies to #xxx
|
||||
* [] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/PowerToys) and sign the CLA
|
||||
* [] Tests added/passed
|
||||
* [] Requires documentation to be updated
|
||||
* [] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
|
||||
|
||||
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
|
||||
## Detailed Description of the Pull Request / Additional comments
|
||||
|
||||
4
.gitignore
vendored
@@ -328,3 +328,7 @@ ASALocalRun/
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Temp build files
|
||||
src/settings/settings-html/200.html
|
||||
src/settings/settings-html/404.html
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
cd /D "%~dp0"
|
||||
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 -winsdk=10.0.16299.0
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 -winsdk=10.0.18362.0
|
||||
call msbuild ../installer/PowerToysSetup.sln /p:Configuration=Release /p:Platform=x64 || exit /b 1
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
cd /D "%~dp0"
|
||||
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 -winsdk=10.0.16299.0
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 -winsdk=10.0.18362.0
|
||||
call msbuild ../src/common/notifications/notifications_dll.vcxproj /p:Configuration=Release /p:Platform=x64 || exit /b 1
|
||||
call msbuild ../src/common/notifications_winrt/notifications.vcxproj /p:Configuration=Release /p:Platform=x64 || exit /b 1
|
||||
call msbuild ../PowerToys.sln /p:Configuration=Release /p:Platform=x64 || exit /b 1
|
||||
|
||||
4
.pipelines/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.PowerToys.Telemetry" version="1.0" />
|
||||
</packages>
|
||||
@@ -2,10 +2,10 @@ environment:
|
||||
host:
|
||||
os: 'windows'
|
||||
flavor: 'server'
|
||||
version: '2016'
|
||||
version: '2019'
|
||||
runtime:
|
||||
provider: 'appcontainer'
|
||||
image: 'cdpxwin.azurecr.io/user/powertoys/vs2019:3.0'
|
||||
image: 'cdpxwinrs5.azurecr.io/global/vse2019:16.4.3'
|
||||
source_mode: 'map'
|
||||
|
||||
version:
|
||||
@@ -44,11 +44,12 @@ build:
|
||||
- from: 'x64/Release'
|
||||
to: 'Build_Output'
|
||||
include:
|
||||
- 'PowerToys.exe'
|
||||
- 'PowerToysSettings.exe'
|
||||
- 'modules\FancyZonesEditor.exe'
|
||||
- 'modules\fancyzones.dll'
|
||||
- 'modules\shortcut_guide.dll'
|
||||
- 'PowerToys.exe'
|
||||
- 'PowerToysSettings.exe'
|
||||
- 'modules\FancyZonesEditor.exe'
|
||||
- 'modules\fancyzones.dll'
|
||||
- 'modules\shortcut_guide.dll'
|
||||
- 'modules\PowerRenameExt.dll'
|
||||
signing_options:
|
||||
sign_inline: true # This does signing a soon as this command completes
|
||||
- !!buildcommand
|
||||
@@ -61,21 +62,48 @@ build:
|
||||
- 'PowerToysSetup.msi'
|
||||
signing_options:
|
||||
sign_inline: true # This does signing a soon as this command completes
|
||||
# - !!buildcommand
|
||||
# name: 'Archive symbols to Symbol Server'
|
||||
# artifacts:
|
||||
# - to: 'x64 Symbols'
|
||||
# include:
|
||||
# - 'x64/Release/action_runner.pdb'
|
||||
# - 'x64/Release/Notifications.pdb'
|
||||
# - 'x64/Release/PowerRenameUWPUI.pdb'
|
||||
# - 'x64/Release/PowerToys.pdb'
|
||||
# - 'x64/Release/PowerToysSettings.pdb'
|
||||
# - 'x64/Release/modules/fancyzones.pdb'
|
||||
# - 'x64/Release/modules/FancyZonesEditor.pdb'
|
||||
# - 'x64/Release/modules/PowerRenameExt.pdb'
|
||||
# - 'x64/Release/modules/shortcut_guide.pdb'
|
||||
|
||||
package:
|
||||
commands:
|
||||
- !!buildcommand
|
||||
name: 'Build MSIX package'
|
||||
command: 'installer\msix\build_msix_cdpx.cmd'
|
||||
artifacts:
|
||||
- from: 'installer\msix\bin'
|
||||
to: 'Build_MSIX_Package_Output'
|
||||
include:
|
||||
- '*.msix'
|
||||
- '*.msixbundle'
|
||||
signing_options:
|
||||
profile: '400'
|
||||
|
||||
static_analysis_options:
|
||||
binskim_options:
|
||||
files_to_scan:
|
||||
- from: 'installer/packages'
|
||||
exclude:
|
||||
exclude:
|
||||
- 'WiX.3.11.1/**/*.dll'
|
||||
- 'Wix.3.11.1/**/*.exe'
|
||||
- 'WiX.*/**/*.dll'
|
||||
- 'Wix.*/**/*.exe'
|
||||
moderncop_options:
|
||||
files_to_scan:
|
||||
- from: 'src'
|
||||
exclude:
|
||||
- '**/just.config.js'
|
||||
- '**/webpack.config.js'
|
||||
- '**/webpack.serve.config.js'
|
||||
- '**/dist/bundle.js'
|
||||
|
||||
- '**/just.config.js'
|
||||
- '**/webpack.config.js'
|
||||
- '**/webpack.serve.config.js'
|
||||
- '**/dist/bundle.js'
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
cd /D "%~dp0"
|
||||
|
||||
set PROJECT="..\src\modules\fancyzones\editor\FancyZonesEditor\FancyZonesEditor.csproj"
|
||||
set TELEMETRY_PKG="Microsoft.PowerToys.Telemetry"
|
||||
call nuget.exe restore -PackagesDirectory . packages.config || exit /b 1
|
||||
|
||||
dotnet add %PROJECT% package %TELEMETRY_PKG%
|
||||
move /Y "Microsoft.PowerToys.Telemetry.1.0.0\build\include\TraceLoggingDefines.h" "..\src\common\Telemetry\TraceLoggingDefines.h" || exit /b 1
|
||||
|
||||
BIN
MTNDWidget.jpg
|
Before Width: | Height: | Size: 4.7 KiB |
110
PowerToys.sln
@@ -6,16 +6,25 @@ MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "src\runner\runner.vcxproj", "{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227} = {48804216-2A0E-4168-A6D8-9CD068D14227}
|
||||
{51D3BD1F-07A8-48EB-B2A0-0A249CD4E1A6} = {51D3BD1F-07A8-48EB-B2A0-0A249CD4E1A6}
|
||||
{74485049-C722-400F-ABE5-86AC52D929B3} = {74485049-C722-400F-ABE5-86AC52D929B3}
|
||||
{B9BDF8BE-FED7-49B5-A7AE-DD4D1CA2D9EB} = {B9BDF8BE-FED7-49B5-A7AE-DD4D1CA2D9EB}
|
||||
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA} = {A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E} = {17DA04DF-E393-4397-9CF0-84DABE11032E}
|
||||
{07C389E3-6BC8-41CF-923E-307B1265FA2D} = {07C389E3-6BC8-41CF-923E-307B1265FA2D}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "src\common\common.vcxproj", "{74485049-C722-400F-ABE5-86AC52D929B3}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shortcut_guide", "src\modules\shortcut_guide\shortcut_guide.vcxproj", "{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{74485049-C722-400F-ABE5-86AC52D929B3} = {74485049-C722-400F-ABE5-86AC52D929B3}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_powertoy", "src\modules\example_powertoy\example_powertoy.vcxproj", "{44CC9375-3E6E-4D99-8913-7FB748807EBD}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{74485049-C722-400F-ABE5-86AC52D929B3} = {74485049-C722-400F-ABE5-86AC52D929B3}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "modules", "modules", "{4574FDD0-F61D-4376-98BF-E5A1262C11EC}"
|
||||
EndProject
|
||||
@@ -23,6 +32,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "interface", "interface", "{
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
src\modules\interface\lowlevel_keyboard_event_data.h = src\modules\interface\lowlevel_keyboard_event_data.h
|
||||
src\modules\interface\powertoy_module_interface.h = src\modules\interface\powertoy_module_interface.h
|
||||
src\modules\interface\powertoy_system_menu.h = src\modules\interface\powertoy_system_menu.h
|
||||
src\modules\interface\win_hook_event_data.h = src\modules\interface\win_hook_event_data.h
|
||||
EndProjectSection
|
||||
EndProject
|
||||
@@ -34,18 +44,22 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FancyZonesLib", "src\module
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fancyzones", "src\modules\fancyzones\dll\FancyZonesModule.vcxproj", "{48804216-2A0E-4168-A6D8-9CD068D14227}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{74485049-C722-400F-ABE5-86AC52D929B3} = {74485049-C722-400F-ABE5-86AC52D929B3}
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481} = {5CCC8468-DEC8-4D36-99D4-5C891BEBD481}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests-FancyZones", "src\modules\fancyzones\tests\UnitTests\UnitTests.vcxproj", "{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprestsdk", "deps\cpprestsdk\cpprestsdk.vcxproj", "{4E577735-DFAB-41AF-8A6E-B6E8872A2928}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deps", "deps", "{1FAF749F-0D6F-4BF5-A563-31A4B5279D27}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{74485049-C722-400F-ABE5-86AC52D929B3} = {74485049-C722-400F-ABE5-86AC52D929B3}
|
||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99} = {F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "common", "common", "{1AFB6476-670D-4E80-A464-657E01DFF482}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests-CommonLib", "src\common\UnitTests-CommonLib\UnitTests-CommonLib.vcxproj", "{1A066C63-64B3-45F8-92FE-664E1CCE8077}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{74485049-C722-400F-ABE5-86AC52D929B3} = {74485049-C722-400F-ABE5-86AC52D929B3}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FancyZonesEditor", "src\modules\fancyzones\editor\FancyZonesEditor\FancyZonesEditor.csproj", "{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}"
|
||||
EndProject
|
||||
@@ -55,6 +69,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameExt", "src\modul
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798} = {0E072714-D127-460B-AFAD-B4C40B412798}
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
|
||||
{74485049-C722-400F-ABE5-86AC52D929B3} = {74485049-C722-400F-ABE5-86AC52D929B3}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameLib", "src\modules\powerrename\lib\PowerRenameLib.vcxproj", "{51920F1F-C28C-4ADF-8660-4238766796C2}"
|
||||
@@ -68,15 +83,53 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameTest", "src\modu
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798} = {0E072714-D127-460B-AFAD-B4C40B412798}
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
|
||||
{74485049-C722-400F-ABE5-86AC52D929B3} = {74485049-C722-400F-ABE5-86AC52D929B3}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameUnitTests", "src\modules\powerrename\unittests\PowerRenameLibUnitTests.vcxproj", "{2151F984-E006-4A9F-92EF-C6DDE3DC8413}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798} = {0E072714-D127-460B-AFAD-B4C40B412798}
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
|
||||
{74485049-C722-400F-ABE5-86AC52D929B3} = {74485049-C722-400F-ABE5-86AC52D929B3}
|
||||
{B25AC7A5-FB9F-4789-B392-D5C85E948670} = {B25AC7A5-FB9F-4789-B392-D5C85E948670}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{BEEAB7F2-FFF6-45AB-9CDB-B04CC0734B88}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ModuleTemplateCompileTest", "tools\project_template\ModuleTemplate\ModuleTemplateCompileTest.vcxproj", "{64A80062-4D8B-4229-8A38-DFA1D7497749}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{74485049-C722-400F-ABE5-86AC52D929B3} = {74485049-C722-400F-ABE5-86AC52D929B3}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameUWPUI", "src\modules\powerrename\UWPui\PowerRenameUWPUI.vcxproj", "{0485F45C-EA7A-4BB5-804B-3E8D14699387}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798} = {0E072714-D127-460B-AFAD-B4C40B412798}
|
||||
{74485049-C722-400F-ABE5-86AC52D929B3} = {74485049-C722-400F-ABE5-86AC52D929B3}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "notifications", "src\common\notifications_winrt\notifications.vcxproj", "{0B593A6C-4143-4337-860E-DB5710FB87DB}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "notifications_dll", "src\common\notifications\notifications_dll.vcxproj", "{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB} = {0B593A6C-4143-4337-860E-DB5710FB87DB}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "windowwalker", "windowwalker", "{8DC78AF7-DC3E-4C57-A8FB-7E347DE74A03}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Window Walker", "src\modules\windowwalker\app\Window Walker\Window Walker.csproj", "{B9BDF8BE-FED7-49B5-A7AE-DD4D1CA2D9EB}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowWalker", "src\modules\windowwalker\dll\WindowWalker.vcxproj", "{51D3BD1F-07A8-48EB-B2A0-0A249CD4E1A6}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{74485049-C722-400F-ABE5-86AC52D929B3} = {74485049-C722-400F-ABE5-86AC52D929B3}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "action_runner", "src\action_runner\action_runner.vcxproj", "{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E} = {17DA04DF-E393-4397-9CF0-84DABE11032E}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msi_to_msix_upgrade_lib", "src\common\msi_to_msix_upgrade_lib\msi_to_msix_upgrade_lib.vcxproj", "{17DA04DF-E393-4397-9CF0-84DABE11032E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
@@ -96,7 +149,9 @@ Global
|
||||
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}.Release|x64.ActiveCfg = Release|x64
|
||||
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}.Release|x64.Build.0 = Release|x64
|
||||
{44CC9375-3E6E-4D99-8913-7FB748807EBD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{44CC9375-3E6E-4D99-8913-7FB748807EBD}.Debug|x64.Build.0 = Debug|x64
|
||||
{44CC9375-3E6E-4D99-8913-7FB748807EBD}.Release|x64.ActiveCfg = Release|x64
|
||||
{44CC9375-3E6E-4D99-8913-7FB748807EBD}.Release|x64.Build.0 = Release|x64
|
||||
{07C389E3-6BC8-41CF-923E-307B1265FA2D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{07C389E3-6BC8-41CF-923E-307B1265FA2D}.Debug|x64.Build.0 = Debug|x64
|
||||
{07C389E3-6BC8-41CF-923E-307B1265FA2D}.Release|x64.ActiveCfg = Release|x64
|
||||
@@ -113,10 +168,6 @@ Global
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Debug|x64.Build.0 = Debug|x64
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Release|x64.ActiveCfg = Release|x64
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Release|x64.Build.0 = Release|x64
|
||||
{4E577735-DFAB-41AF-8A6E-B6E8872A2928}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4E577735-DFAB-41AF-8A6E-B6E8872A2928}.Debug|x64.Build.0 = Debug|x64
|
||||
{4E577735-DFAB-41AF-8A6E-B6E8872A2928}.Release|x64.ActiveCfg = Release|x64
|
||||
{4E577735-DFAB-41AF-8A6E-B6E8872A2928}.Release|x64.Build.0 = Release|x64
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Debug|x64.Build.0 = Debug|x64
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Release|x64.ActiveCfg = Release|x64
|
||||
@@ -145,6 +196,38 @@ Global
|
||||
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Debug|x64.Build.0 = Debug|x64
|
||||
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Release|x64.ActiveCfg = Release|x64
|
||||
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Release|x64.Build.0 = Release|x64
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Debug|x64.Build.0 = Debug|x64
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|x64.ActiveCfg = Release|x64
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|x64.Build.0 = Release|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Debug|x64.Build.0 = Debug|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Release|x64.ActiveCfg = Release|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Release|x64.Build.0 = Release|x64
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Debug|x64.Build.0 = Debug|x64
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Release|x64.ActiveCfg = Release|x64
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Release|x64.Build.0 = Release|x64
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Debug|x64.Build.0 = Debug|x64
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Release|x64.ActiveCfg = Release|x64
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Release|x64.Build.0 = Release|x64
|
||||
{B9BDF8BE-FED7-49B5-A7AE-DD4D1CA2D9EB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B9BDF8BE-FED7-49B5-A7AE-DD4D1CA2D9EB}.Debug|x64.Build.0 = Debug|x64
|
||||
{B9BDF8BE-FED7-49B5-A7AE-DD4D1CA2D9EB}.Release|x64.ActiveCfg = Release|x64
|
||||
{B9BDF8BE-FED7-49B5-A7AE-DD4D1CA2D9EB}.Release|x64.Build.0 = Release|x64
|
||||
{51D3BD1F-07A8-48EB-B2A0-0A249CD4E1A6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{51D3BD1F-07A8-48EB-B2A0-0A249CD4E1A6}.Debug|x64.Build.0 = Debug|x64
|
||||
{51D3BD1F-07A8-48EB-B2A0-0A249CD4E1A6}.Release|x64.ActiveCfg = Release|x64
|
||||
{51D3BD1F-07A8-48EB-B2A0-0A249CD4E1A6}.Release|x64.Build.0 = Release|x64
|
||||
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Debug|x64.Build.0 = Debug|x64
|
||||
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Release|x64.ActiveCfg = Release|x64
|
||||
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Release|x64.Build.0 = Release|x64
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Debug|x64.Build.0 = Debug|x64
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Release|x64.ActiveCfg = Release|x64
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -152,13 +235,12 @@ Global
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{74485049-C722-400F-ABE5-86AC52D929B3} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{44CC9375-3E6E-4D99-8913-7FB748807EBD} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{44CC9375-3E6E-4D99-8913-7FB748807EBD} = {BEEAB7F2-FFF6-45AB-9CDB-B04CC0734B88}
|
||||
{3BB8493E-D18E-4485-A320-CB40F90F55AE} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{D1D6BC88-09AE-4FB4-AD24-5DED46A791DD} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{4E577735-DFAB-41AF-8A6E-B6E8872A2928} = {1FAF749F-0D6F-4BF5-A563-31A4B5279D27}
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
@@ -167,6 +249,14 @@ Global
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
|
||||
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
|
||||
{2151F984-E006-4A9F-92EF-C6DDE3DC8413} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749} = {BEEAB7F2-FFF6-45AB-9CDB-B04CC0734B88}
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{8DC78AF7-DC3E-4C57-A8FB-7E347DE74A03} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{B9BDF8BE-FED7-49B5-A7AE-DD4D1CA2D9EB} = {8DC78AF7-DC3E-4C57-A8FB-7E347DE74A03}
|
||||
{51D3BD1F-07A8-48EB-B2A0-0A249CD4E1A6} = {8DC78AF7-DC3E-4C57-A8FB-7E347DE74A03}
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
||||
174
README.md
@@ -1,136 +1,140 @@
|
||||
# Overview
|
||||
|
||||
PowerToys is a set of utilities for power users to tune and streamline their Windows experience for greater productivity.
|
||||
<img align="right" width="200" src="./doc/images/Logo.jpg" />
|
||||
|
||||
Inspired by the [Windows 95 era PowerToys project](https://en.wikipedia.org/wiki/Microsoft_PowerToys), this reboot provides power users with ways to squeeze more efficiency out of the Windows 10 shell and customize it for individual workflows. A great overview of the Windows 95 PowerToys can be found [here](https://socket3.wordpress.com/2016/10/22/using-windows-95-powertoys/).
|
||||
Microsoft PowerToys is a set of utilities for power users to tune and streamline their Windows experience for greater productivity. Inspired by the [Windows 95 era PowerToys project](https://en.wikipedia.org/wiki/Microsoft_PowerToys), this reboot provides power users with ways to squeeze more efficiency out of the Windows 10 shell and customize it for individual workflows. A great overview of the Windows 95 PowerToys can be found [here](https://socket3.wordpress.com/2016/10/22/using-windows-95-powertoys/).
|
||||
|
||||

|
||||
## Build Status
|
||||
|
||||
## Installation
|
||||
[](https://dev.azure.com/ms/PowerToys/_build?definitionId=35096)
|
||||
|
||||
_(Note: in order to run PowerToys, you'll need to be running at least Windows build 17134 or higher. Also, PowerToys does not currently support Windows ARM machines)_
|
||||
## Installing and running Microsoft PowerToys
|
||||
|
||||
### GitHub
|
||||
> 👉 **Note:** Microsoft PowerToys requires Windows 10 1803 (build 17134) or later.
|
||||
|
||||
The first preview of these utilities can be installed from the [PowerToys GitHub releases page](https://github.com/Microsoft/powertoys/releases).
|
||||
> 👉 **Upgrading to 0.15:** You need to reapply your zone layout for FancyZones. Don't worry, your custom zone sets are preserved.
|
||||
|
||||
### Chocolatey (Unofficial)
|
||||
### Via Github with MSI [Recommended]
|
||||
|
||||
Download and upgrade PowerToys from [Chocolatey](https://chocolatey.org).
|
||||
Install from the [Microsoft PowerToys GitHub releases page][github-release-link]. Click on `Assets` to show the files available in the release and then click on `PowerToysSetup-0.15.0-x64.msi` to download the PowerToys installer.
|
||||
|
||||
This is our preferred method.
|
||||
|
||||
### Other install methods
|
||||
|
||||
#### Via GitHub with MSIX - ⚠ Experimental ⚠
|
||||
|
||||
The experimental version of PowerToys using MSIX is available. It can be installed from the [PowerToys GitHub releases page][github-release-link].
|
||||
|
||||
Click on `Assets` to show the files available in the release and then click on `PowerToysSetup-MSIX-0.15.0.zip` to download the PowerToys installer zip. From there, please read the ReadMe and you can double click to install the MSIX file.
|
||||
|
||||
##### Known issues with MSIX Build
|
||||
|
||||
- For PowerRename, you may need to restart your machine to get this to work for the first time.
|
||||
|
||||
#### Via Chocolatey - ⚠ Unofficial ⚠
|
||||
|
||||
Download and upgrade PowerToys from [Chocolatey](https://chocolatey.org). If you have any issues when installing/upgrading the package please go to the [package page](https://chocolatey.org/packages/powertoys) and follow the [Chocolatey triage process](https://chocolatey.org/docs/package-triage-process)
|
||||
|
||||
To install PowerToys, run the following command from the command line / PowerShell:
|
||||
|
||||
To install PowerToys, run the following command from the command line or from PowerShell:
|
||||
```powershell
|
||||
choco install powertoys
|
||||
```
|
||||
|
||||
To upgrade PowerToys, run the following command from the command line or from PowerShell:
|
||||
To upgrade PowerToys, run the following command from the command line / PowerShell:
|
||||
|
||||
```powershell
|
||||
choco upgrade powertoys
|
||||
```
|
||||
|
||||
If you have any issues when installing/upgrading the package please go to the [package page](https://chocolatey.org/packages/powertoys) and follow the [Chocolatey triage process](https://chocolatey.org/docs/package-triage-process)
|
||||
### Microsoft Store
|
||||
|
||||
### Build Status
|
||||
On backlog, [Issue #413](https://github.com/microsoft/PowerToys/issues/413)
|
||||
|
||||
[](https://dev.azure.com/ms/PowerToys/_build?definitionId=35096)
|
||||
### Processor support
|
||||
|
||||
# What's Happening
|
||||
We currently support the matrix below. Adding MSIX support will make supporting x86 and ARM much easier.
|
||||
|
||||
## October Update
|
||||
A big thanks to everyone who has downloaded and started using the first PowerToys preview. There's been over 150K downloads so far. An even bigger thanks to everyone who has provided feedback and suggestions in the issues. The community engagement has been really awesome to see.
|
||||
| x64 | x86 | ARM |
|
||||
|:---:|:---:|:---:|
|
||||
| [Install][github-release-link] | [Issue #602](https://github.com/microsoft/PowerToys/issues/602) | [Issue #490](https://github.com/microsoft/PowerToys/issues/490)|
|
||||
|
||||
The team has been hard at working fixing bugs, addressing issues and implementing feature suggestions. If you've downloaded the code and built the latest on your machine recently you've seen many of these improvements (dark mode!). We're hoping to have a new official build out shortly with all these improvements and will also be signed by Microsoft. A new utility is also coming soon: Chris Davis is working to integrate his [SmartRename tool](https://github.com/chrdavis/SmartRename) into PowerToys!
|
||||
## Current PowerToy Utilities
|
||||
|
||||

|
||||
### FancyZones
|
||||
|
||||
1. [FancyZones](/src/modules/fancyzones/) - FancyZones is a window manager that makes it easy to create complex window layouts and quickly position windows into those layouts. The FancyZones backlog can be found [here](https://github.com/Microsoft/PowerToys/tree/master/doc/planning/FancyZonesBacklog.md)
|
||||
[FancyZones](/src/modules/fancyzones/) - FancyZones is a window manager that makes it easy to create complex window layouts and quickly position windows into those layouts.
|
||||
|
||||

|
||||
### Shortcut
|
||||
|
||||
FancyZones Video Tutorial
|
||||
[](https://www.youtube.com/watch?v=rTtGzZYAXgY)
|
||||
[Windows key shortcut guide](/src/modules/shortcut_guide) - The shortcut guide appears when a user holds the Windows key down for more than one second and shows the available shortcuts for the current state of the desktop.
|
||||
|
||||
2. [Windows key shortcut guide](/src/modules/shortcut_guide) - The shortcut guide appears when a user holds the Windows key down for more than one second and shows the available shortcuts for the current state of the desktop. The shortcut guide backlog can be found [here](https://github.com/Microsoft/PowerToys/tree/master/doc/planning/ShortcutGuideBacklog.md)
|
||||
### PowerRename
|
||||
|
||||

|
||||
[PowerRename](/src/modules/powerrename) - PowerRename is a Windows Shell Extension for advanced bulk renaming using search and replace or regular expressions. PowerRename allows simple search and replace or more advanced regular expression matching. While you type in the search and replace input fields, the preview area will show what the items will be renamed to. PowerRename then calls into the Windows Explorer file operations engine to perform the rename. This has the benefit of allowing the rename operation to be undone after PowerRename exits.
|
||||
|
||||
Additional utilities in the pipeline are:
|
||||
### Version 1.0 plan
|
||||
|
||||
* Maximize to new desktop widget - The MTND widget shows a pop-up button when a user hovers over the maximize / restore button on any window. Clicking it creates a new desktop, sends the app to that desktop and maximizes the app on the new desktop.
|
||||
* [Process terminate tool](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/Terminate%20Spec.md)
|
||||
* [Animated gif screen recorder](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/GIF%20Maker%20Spec.md)
|
||||
Our plan for all the [goals and utilities for v1.0 detailed over here in the wiki][v1].
|
||||
|
||||
# Backlog
|
||||
## What's Happening
|
||||
|
||||
The full backlog of utilities can be found [here](https://github.com/Microsoft/PowerToys/tree/master/doc/planning/PowerToysBacklog.md)
|
||||
### February 2020 Update
|
||||
|
||||
# Where to download PowerToys
|
||||
Our mantra for the 0.15 was infrastructure, quality, stability and work toward getting a way to auto-update PowerToys. While it took a bit longer to get here, we feel it was worth the extra time to fix bugs that really impacted your experience with PowerToys.
|
||||
|
||||
The latest release of PowerToys can be downloaded from https://github.com/microsoft/PowerToys/releases <br />
|
||||
Click on `Assets` to show the files available in the release and then click on `PowerToysSetup.msi` to download the PowerToys installer. <br />
|
||||
PDB symbols for the release are available in a separate zip file `PDB symbols.zip`.
|
||||
Below are just a few of the bullet items from this release.
|
||||
|
||||
# Developer Guidance
|
||||
- We shipped [v0.15][github-release-link]!
|
||||
- Make you aware there is a new version from within PowerToys
|
||||
- Removed requirement to always 'run as admin'
|
||||
- Added almost 300 unit tests to increase stability and prevent regressions.
|
||||
- Resolved almost 100 issues
|
||||
- Made .NET Framework parts of the source run faster with NGEN
|
||||
- Improved for how we store data locally
|
||||
- Increased FancyZones compatibility with applications
|
||||
- Initial work for 4 new PowerToys added for 0.16!
|
||||
- Created the [v1.0 strategy][v1], the [launcher](https://github.com/microsoft/PowerToys/wiki/Launcher), the [keyboard manager](https://github.com/microsoft/PowerToys/wiki/Keyboard-Manager) specs
|
||||
- Work on cleaning up our issue backlog and labels
|
||||
|
||||
## Build Prerequisites
|
||||
* Windows 10 1803 (build 10.0.17134.0) or above to build and run PowerToys.
|
||||
* Visual Studio 2019 Community edition or higher, with the 'Desktop Development with C++' component and the Windows 10 SDK version 10.0.18362.0 or higher.
|
||||
|
||||
## Building the Code
|
||||
* Open `powertoys.sln` in Visual Studio, in the `Solutions Configuration` drop-down menu select `Release` or `Debug`, from the `Build` menu choose `Build Solution`.
|
||||
* The PowerToys binaries will be in your repo under `x64\Release`.
|
||||
* If you want to copy the `PowerToys.exe` binary to a different location, you'll also need to copy the `modules` and the `svgs` folders.
|
||||
For 0.16, we have some fun things planned and hopefully will be able to ship pretty quickly. Here are the new utilities we'll enable:
|
||||
|
||||
## Prerequisites to Build the Installer
|
||||
* Install the [WiX Toolset Visual Studio 2019 Extension](https://marketplace.visualstudio.com/items?itemName=RobMensching.WiXToolset).
|
||||
* Install the [WiX Toolset build tools](https://wixtoolset.org/releases/).
|
||||
|
||||
## Building the .msi Installer
|
||||
* From the `installer` folder open `PowerToysSetup.sln` in Visual Studio, in the `Solutions Configuration` drop-down menu select `Release` or `Debug`, from the `Build` menu choose `Build Solution`.
|
||||
* The resulting `PowerToysSetup.msi` installer will be available in the `installer\PowerToysSetup\x64\Release\` folder.
|
||||
- An alternative to Alt-Tab PowerToy
|
||||
- SVG preview pane for support Explorer
|
||||
- Markdown preview pane support for Explorer
|
||||
- Image Resizer PowerToy
|
||||
|
||||
## Debugging
|
||||
The following configuration issue only applies if the user is a member of the Administrators group.
|
||||
|
||||
Some PowerToys modules require being run with the highest permission level if the current user is a member of the Administrators group. The highest permission level is required to be able to perform some actions when an elevated application (e.g. Task Manager) is in the foreground or is the target of an action. Without elevated privileges some PowerToys modules will still work but with some limitations:
|
||||
- the `FancyZones` module will be not be able to move an elevated window to a zone.
|
||||
- the `Shortcut Guide` module will not appear if the foreground window belongs to an elevated application.
|
||||
|
||||
To run and debug PowerToys from Visual Studio when the user is a member of the Administrators group, Visual Studio has to be started with elevated privileges. If you want to avoid running Visual Studio with elevated privileges and don't mind the limitations described above, you can do the following: open the `runner` project properties and navigate to the `Linker -> Manifest File` settings, edit the `UAC Execution Level` property and change it from `highestAvailable (/level='highestAvailable')` to `asInvoker (/level='asInvoker')`, save the changes.
|
||||
|
||||
## How to create new PowerToys
|
||||
## Developer Guidance
|
||||
|
||||
See the instructions on [how to install the PowerToys Module project template](tools/project_template). <br />
|
||||
Specifications for the [PowerToys settings API](doc/specs/PowerToys-settings.md).
|
||||
Please read the [developer docs](/doc/devdocs) for a detailed breakdown.
|
||||
|
||||
## Coding Guidance
|
||||
## Contributing
|
||||
|
||||
Please review these brief docs below relating to our coding standards etc.
|
||||
|
||||
> 👉 If you find something missing from these docs, feel free to contribute to any of our documentation files anywhere in the repository (or make some new ones\!)
|
||||
|
||||
This is a work in progress as we learn what we'll need to provide people in order to be effective contributors to our project.
|
||||
- [Coding Style](doc/coding/style.md)
|
||||
- [Code Organization](doc/coding/organization.md)
|
||||
|
||||
# Contributing
|
||||
This project welcomes contributions and suggestions and we are excited to work with the power user community to build a set of tools for helping you get the most out of Windows.
|
||||
This project welcomes contributions of all times. Help spec'ing, design, documentation, finding bugs are ways everyone can help on top of coding features / bug fixes. We are excited to work with the power user community to build a set of tools for helping you get the most out of Windows.
|
||||
|
||||
We ask that **before you start work on a feature that you would like to contribute**, please read our [Contributor's Guide](contributing.md). We will be happy to work with you to figure out the best approach, provide guidance and mentorship throughout feature development, and help avoid any wasted or duplicate effort.
|
||||
|
||||
> ⚠ **Note**: PowerToys is still a nascent project and the team is actively working out of this repository. We will be periodically re-structuring the code to make it easier to comprehend, navigate, build, test, and contribute to, so **DO expect significant changes to code layout on a regular basis**.
|
||||
### ⚠ State of code ⚠
|
||||
|
||||
> ⚠ **License Info**: Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
|
||||
PowerToys is still a very fluidic project and the team is actively working out of this repository. We will be periodically re-structuring/refactoring the code to make it easier to comprehend, navigate, build, test, and contribute to, so **DO expect significant changes to code layout on a regular basis**.
|
||||
|
||||
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
|
||||
a CLA and decorate the PR appropriately (e.g. status check, comment). Simply follow the instructions
|
||||
provided by the bot. You will only need to do this once across all repos using our CLA.
|
||||
### License Info
|
||||
|
||||
# Code of Conduct
|
||||
Most contributions require you to agree to a [Contributor License Agreement (CLA)][oss-CLA] declaring that you have the right to, and actually do, grant us the rights to use your contribution.
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct][conduct-code]. <br />
|
||||
For more information see the [Code of Conduct FAQ][conduct-FAQ] or contact [opencode@microsoft.com][conduct-email] with any additional questions or comments.
|
||||
## Code of Conduct
|
||||
|
||||
[conduct-code]: https://opensource.microsoft.com/codeofconduct/
|
||||
[conduct-FAQ]: https://opensource.microsoft.com/codeofconduct/faq/
|
||||
[conduct-email]: mailto:opencode@microsoft.com
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct][oss-conduct-code]. For more information see the [Code of Conduct FAQ][oss-conduct-FAQ] or contact [opencode@microsoft.com][oss-conduct-email] with any additional questions or comments.
|
||||
|
||||
## Privacy Statement
|
||||
|
||||
The application logs basic telemetry. Our Telemetry Data page (Coming Soon) has the trends from the telemetry. Please read the [Microsoft privacy statement][privacyLink] for more information.
|
||||
|
||||
[oss-CLA]: https://cla.opensource.microsoft.com
|
||||
[oss-conduct-code]: https://opensource.microsoft.com/codeofconduct/
|
||||
[oss-conduct-FAQ]: https://opensource.microsoft.com/codeofconduct/faq/
|
||||
[oss-conduct-email]: mailto:opencode@microsoft.com
|
||||
[github-release-link]: https://github.com/microsoft/PowerToys/releases/
|
||||
[v1]: https://github.com/microsoft/PowerToys/wiki/Version-1.0-Strategy
|
||||
[privacyLink]: http://go.microsoft.com/fwlink/?LinkId=521839
|
||||
|
||||
|
Before Width: | Height: | Size: 273 KiB |
12
deps/cpprestsdk/README.md
vendored
@@ -1,12 +0,0 @@
|
||||
# C++ Rest SDK - JSON library
|
||||
|
||||
This JSON library is taken from the C++ REST SDK in https://github.com/microsoft/cpprestsdk
|
||||
|
||||
Based in the [v2.10.13 release](https://github.com/microsoft/cpprestsdk/tree/v2.10.13/Release), it consists of the needed files to build and use the JSON classes described in `include/cpprest/json.h`.
|
||||
|
||||
Changes made to the files in order to build in the PowerToys project:
|
||||
- Removal of `#include` references to files that are not needed.
|
||||
- `#include "pch.h"` instead of `#include "stdafx.h"` to use the PowerToys pre-compiled header.
|
||||
- `#define _NO_ASYNCRTIMP` in [`include/cpprest/details/cpprest_compat.h`](./include/cpprest/details/cpprest_compat.h) since this class will be statically linked.
|
||||
|
||||
The contents of the C++ Rest SDK license are included in [license.txt](./license.txt).
|
||||
697
deps/cpprestsdk/include/cpprest/asyncrt_utils.h
vendored
@@ -1,697 +0,0 @@
|
||||
/***
|
||||
* Copyright (C) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
|
||||
*
|
||||
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
*
|
||||
* Various common utilities.
|
||||
*
|
||||
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
|
||||
*
|
||||
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
****/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpprest/details/basic_types.h"
|
||||
//#include "pplx/pplxtasks.h"
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <vector>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h>
|
||||
#if !defined(ANDROID) && !defined(__ANDROID__) && defined(HAVE_XLOCALE_H) // CodePlex 269
|
||||
/* Systems using glibc: xlocale.h has been removed from glibc 2.26
|
||||
The above include of locale.h is sufficient
|
||||
Further details: https://sourceware.org/git/?p=glibc.git;a=commit;h=f0be25b6336db7492e47d2e8e72eb8af53b5506d */
|
||||
#include <xlocale.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Various utilities for string conversions and date and time manipulation.
|
||||
namespace utility
|
||||
{
|
||||
// Left over from VS2010 support, remains to avoid breaking.
|
||||
typedef std::chrono::seconds seconds;
|
||||
|
||||
/// Functions for converting to/from std::chrono::seconds to xml string.
|
||||
namespace timespan
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a timespan/interval in seconds to xml duration string as specified by
|
||||
/// http://www.w3.org/TR/xmlschema-2/#duration
|
||||
/// </summary>
|
||||
_ASYNCRTIMP utility::string_t __cdecl seconds_to_xml_duration(utility::seconds numSecs);
|
||||
|
||||
/// <summary>
|
||||
/// Converts an xml duration to timespan/interval in seconds
|
||||
/// http://www.w3.org/TR/xmlschema-2/#duration
|
||||
/// </summary>
|
||||
_ASYNCRTIMP utility::seconds __cdecl xml_duration_to_seconds(const utility::string_t& timespanString);
|
||||
} // namespace timespan
|
||||
|
||||
/// Functions for Unicode string conversions.
|
||||
namespace conversions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a UTF-16 string to a UTF-8 string.
|
||||
/// </summary>
|
||||
/// <param name="w">A two byte character UTF-16 string.</param>
|
||||
/// <returns>A single byte character UTF-8 string.</returns>
|
||||
_ASYNCRTIMP std::string __cdecl utf16_to_utf8(const utf16string& w);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a UTF-8 string to a UTF-16
|
||||
/// </summary>
|
||||
/// <param name="s">A single byte character UTF-8 string.</param>
|
||||
/// <returns>A two byte character UTF-16 string.</returns>
|
||||
_ASYNCRTIMP utf16string __cdecl utf8_to_utf16(const std::string& s);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a ASCII (us-ascii) string to a UTF-16 string.
|
||||
/// </summary>
|
||||
/// <param name="s">A single byte character us-ascii string.</param>
|
||||
/// <returns>A two byte character UTF-16 string.</returns>
|
||||
_ASYNCRTIMP utf16string __cdecl usascii_to_utf16(const std::string& s);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Latin1 (iso-8859-1) string to a UTF-16 string.
|
||||
/// </summary>
|
||||
/// <param name="s">A single byte character UTF-8 string.</param>
|
||||
/// <returns>A two byte character UTF-16 string.</returns>
|
||||
_ASYNCRTIMP utf16string __cdecl latin1_to_utf16(const std::string& s);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Latin1 (iso-8859-1) string to a UTF-8 string.
|
||||
/// </summary>
|
||||
/// <param name="s">A single byte character UTF-8 string.</param>
|
||||
/// <returns>A single byte character UTF-8 string.</returns>
|
||||
_ASYNCRTIMP utf8string __cdecl latin1_to_utf8(const std::string& s);
|
||||
|
||||
/// <summary>
|
||||
/// Converts to a platform dependent Unicode string type.
|
||||
/// </summary>
|
||||
/// <param name="s">A single byte character UTF-8 string.</param>
|
||||
/// <returns>A platform dependent string type.</returns>
|
||||
#ifdef _UTF16_STRINGS
|
||||
_ASYNCRTIMP utility::string_t __cdecl to_string_t(std::string&& s);
|
||||
#else
|
||||
inline utility::string_t&& to_string_t(std::string&& s) { return std::move(s); }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Converts to a platform dependent Unicode string type.
|
||||
/// </summary>
|
||||
/// <param name="s">A two byte character UTF-16 string.</param>
|
||||
/// <returns>A platform dependent string type.</returns>
|
||||
#ifdef _UTF16_STRINGS
|
||||
inline utility::string_t&& to_string_t(utf16string&& s) { return std::move(s); }
|
||||
#else
|
||||
_ASYNCRTIMP utility::string_t __cdecl to_string_t(utf16string&& s);
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Converts to a platform dependent Unicode string type.
|
||||
/// </summary>
|
||||
/// <param name="s">A single byte character UTF-8 string.</param>
|
||||
/// <returns>A platform dependent string type.</returns>
|
||||
#ifdef _UTF16_STRINGS
|
||||
_ASYNCRTIMP utility::string_t __cdecl to_string_t(const std::string& s);
|
||||
#else
|
||||
inline const utility::string_t& to_string_t(const std::string& s) { return s; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Converts to a platform dependent Unicode string type.
|
||||
/// </summary>
|
||||
/// <param name="s">A two byte character UTF-16 string.</param>
|
||||
/// <returns>A platform dependent string type.</returns>
|
||||
#ifdef _UTF16_STRINGS
|
||||
inline const utility::string_t& to_string_t(const utf16string& s) { return s; }
|
||||
#else
|
||||
_ASYNCRTIMP utility::string_t __cdecl to_string_t(const utf16string& s);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Converts to a UTF-16 from string.
|
||||
/// </summary>
|
||||
/// <param name="value">A single byte character UTF-8 string.</param>
|
||||
/// <returns>A two byte character UTF-16 string.</returns>
|
||||
_ASYNCRTIMP utf16string __cdecl to_utf16string(const std::string& value);
|
||||
|
||||
/// <summary>
|
||||
/// Converts to a UTF-16 from string.
|
||||
/// </summary>
|
||||
/// <param name="value">A two byte character UTF-16 string.</param>
|
||||
/// <returns>A two byte character UTF-16 string.</returns>
|
||||
inline const utf16string& to_utf16string(const utf16string& value) { return value; }
|
||||
/// <summary>
|
||||
/// Converts to a UTF-16 from string.
|
||||
/// </summary>
|
||||
/// <param name="value">A two byte character UTF-16 string.</param>
|
||||
/// <returns>A two byte character UTF-16 string.</returns>
|
||||
inline utf16string&& to_utf16string(utf16string&& value) { return std::move(value); }
|
||||
|
||||
/// <summary>
|
||||
/// Converts to a UTF-8 string.
|
||||
/// </summary>
|
||||
/// <param name="value">A single byte character UTF-8 string.</param>
|
||||
/// <returns>A single byte character UTF-8 string.</returns>
|
||||
inline std::string&& to_utf8string(std::string&& value) { return std::move(value); }
|
||||
|
||||
/// <summary>
|
||||
/// Converts to a UTF-8 string.
|
||||
/// </summary>
|
||||
/// <param name="value">A single byte character UTF-8 string.</param>
|
||||
/// <returns>A single byte character UTF-8 string.</returns>
|
||||
inline const std::string& to_utf8string(const std::string& value) { return value; }
|
||||
|
||||
/// <summary>
|
||||
/// Converts to a UTF-8 string.
|
||||
/// </summary>
|
||||
/// <param name="value">A two byte character UTF-16 string.</param>
|
||||
/// <returns>A single byte character UTF-8 string.</returns>
|
||||
_ASYNCRTIMP std::string __cdecl to_utf8string(const utf16string& value);
|
||||
|
||||
/// <summary>
|
||||
/// Encode the given byte array into a base64 string
|
||||
/// </summary>
|
||||
_ASYNCRTIMP utility::string_t __cdecl to_base64(const std::vector<unsigned char>& data);
|
||||
|
||||
/// <summary>
|
||||
/// Encode the given 8-byte integer into a base64 string
|
||||
/// </summary>
|
||||
_ASYNCRTIMP utility::string_t __cdecl to_base64(uint64_t data);
|
||||
|
||||
/// <summary>
|
||||
/// Decode the given base64 string to a byte array
|
||||
/// </summary>
|
||||
_ASYNCRTIMP std::vector<unsigned char> __cdecl from_base64(const utility::string_t& str);
|
||||
|
||||
template<typename Source>
|
||||
CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if "
|
||||
"locale support is required.")
|
||||
utility::string_t print_string(const Source& val, const std::locale& loc = std::locale())
|
||||
{
|
||||
utility::ostringstream_t oss;
|
||||
oss.imbue(loc);
|
||||
oss << val;
|
||||
if (oss.bad())
|
||||
{
|
||||
throw std::bad_cast();
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if "
|
||||
"locale support is required.")
|
||||
inline utility::string_t print_string(const utility::string_t& val) { return val; }
|
||||
|
||||
namespace details
|
||||
{
|
||||
#if defined(__ANDROID__)
|
||||
template<class T>
|
||||
inline std::string to_string(const T t)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os.imbue(std::locale::classic());
|
||||
os << t;
|
||||
return os.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
template<class T>
|
||||
inline utility::string_t to_string_t(const T t)
|
||||
{
|
||||
#ifdef _UTF16_STRINGS
|
||||
using std::to_wstring;
|
||||
return to_wstring(t);
|
||||
#else
|
||||
#if !defined(__ANDROID__)
|
||||
using std::to_string;
|
||||
#endif
|
||||
return to_string(t);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Source>
|
||||
utility::string_t print_string(const Source& val)
|
||||
{
|
||||
utility::ostringstream_t oss;
|
||||
oss.imbue(std::locale::classic());
|
||||
oss << val;
|
||||
if (oss.bad())
|
||||
{
|
||||
throw std::bad_cast();
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline const utility::string_t& print_string(const utility::string_t& val) { return val; }
|
||||
|
||||
template<typename Source>
|
||||
utf8string print_utf8string(const Source& val)
|
||||
{
|
||||
return conversions::to_utf8string(print_string(val));
|
||||
}
|
||||
inline const utf8string& print_utf8string(const utf8string& val) { return val; }
|
||||
|
||||
template<typename Target>
|
||||
Target scan_string(const utility::string_t& str)
|
||||
{
|
||||
Target t;
|
||||
utility::istringstream_t iss(str);
|
||||
iss.imbue(std::locale::classic());
|
||||
iss >> t;
|
||||
if (iss.bad())
|
||||
{
|
||||
throw std::bad_cast();
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
inline const utility::string_t& scan_string(const utility::string_t& str) { return str; }
|
||||
} // namespace details
|
||||
|
||||
template<typename Target>
|
||||
CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if "
|
||||
"locale support is required.")
|
||||
Target scan_string(const utility::string_t& str, const std::locale& loc = std::locale())
|
||||
{
|
||||
Target t;
|
||||
utility::istringstream_t iss(str);
|
||||
iss.imbue(loc);
|
||||
iss >> t;
|
||||
if (iss.bad())
|
||||
{
|
||||
throw std::bad_cast();
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if "
|
||||
"locale support is required.")
|
||||
inline utility::string_t scan_string(const utility::string_t& str) { return str; }
|
||||
} // namespace conversions
|
||||
|
||||
namespace details
|
||||
{
|
||||
/// <summary>
|
||||
/// Cross platform RAII container for setting thread local locale.
|
||||
/// </summary>
|
||||
class scoped_c_thread_locale
|
||||
{
|
||||
public:
|
||||
_ASYNCRTIMP scoped_c_thread_locale();
|
||||
_ASYNCRTIMP ~scoped_c_thread_locale();
|
||||
|
||||
#if !defined(ANDROID) && !defined(__ANDROID__) // CodePlex 269
|
||||
#ifdef _WIN32
|
||||
typedef _locale_t xplat_locale;
|
||||
#else
|
||||
typedef locale_t xplat_locale;
|
||||
#endif
|
||||
|
||||
static _ASYNCRTIMP xplat_locale __cdecl c_locale();
|
||||
#endif
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
std::string m_prevLocale;
|
||||
int m_prevThreadSetting;
|
||||
#elif !(defined(ANDROID) || defined(__ANDROID__))
|
||||
locale_t m_prevLocale;
|
||||
#endif
|
||||
scoped_c_thread_locale(const scoped_c_thread_locale&);
|
||||
scoped_c_thread_locale& operator=(const scoped_c_thread_locale&);
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Our own implementation of alpha numeric instead of std::isalnum to avoid
|
||||
/// taking global lock for performance reasons.
|
||||
/// </summary>
|
||||
inline bool __cdecl is_alnum(const unsigned char uch) CPPREST_NOEXCEPT
|
||||
{ // test if uch is an alnum character
|
||||
// special casing char to avoid branches
|
||||
// clang-format off
|
||||
static CPPREST_CONSTEXPR bool is_alnum_table[UCHAR_MAX + 1] = {
|
||||
/* X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF */
|
||||
/* 0X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 1X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 2X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 3X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0-9 */
|
||||
/* 4X */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* A-Z */
|
||||
/* 5X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
|
||||
/* 6X */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a-z */
|
||||
/* 7X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
|
||||
/* non-ASCII values initialized to 0 */
|
||||
};
|
||||
// clang-format on
|
||||
return (is_alnum_table[uch]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Our own implementation of alpha numeric instead of std::isalnum to avoid
|
||||
/// taking global lock for performance reasons.
|
||||
/// </summary>
|
||||
inline bool __cdecl is_alnum(const char ch) CPPREST_NOEXCEPT { return (is_alnum(static_cast<unsigned char>(ch))); }
|
||||
|
||||
/// <summary>
|
||||
/// Our own implementation of alpha numeric instead of std::isalnum to avoid
|
||||
/// taking global lock for performance reasons.
|
||||
/// </summary>
|
||||
template<class Elem>
|
||||
inline bool __cdecl is_alnum(Elem ch) CPPREST_NOEXCEPT
|
||||
{
|
||||
// assumes 'x' == L'x' for the ASCII range
|
||||
typedef typename std::make_unsigned<Elem>::type UElem;
|
||||
const auto uch = static_cast<UElem>(ch);
|
||||
return (uch <= static_cast<UElem>('z') && is_alnum(static_cast<unsigned char>(uch)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simplistic implementation of make_unique. A better implementation would be based on variadic templates
|
||||
/// and therefore not be compatible with Dev10.
|
||||
/// </summary>
|
||||
template<typename _Type>
|
||||
std::unique_ptr<_Type> make_unique()
|
||||
{
|
||||
return std::unique_ptr<_Type>(new _Type());
|
||||
}
|
||||
|
||||
template<typename _Type, typename _Arg1>
|
||||
std::unique_ptr<_Type> make_unique(_Arg1&& arg1)
|
||||
{
|
||||
return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1)));
|
||||
}
|
||||
|
||||
template<typename _Type, typename _Arg1, typename _Arg2>
|
||||
std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2)
|
||||
{
|
||||
return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2)));
|
||||
}
|
||||
|
||||
template<typename _Type, typename _Arg1, typename _Arg2, typename _Arg3>
|
||||
std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3)
|
||||
{
|
||||
return std::unique_ptr<_Type>(
|
||||
new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3)));
|
||||
}
|
||||
|
||||
template<typename _Type, typename _Arg1, typename _Arg2, typename _Arg3, typename _Arg4>
|
||||
std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4)
|
||||
{
|
||||
return std::unique_ptr<_Type>(new _Type(
|
||||
std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3), std::forward<_Arg4>(arg4)));
|
||||
}
|
||||
|
||||
template<typename _Type, typename _Arg1, typename _Arg2, typename _Arg3, typename _Arg4, typename _Arg5>
|
||||
std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4, _Arg5&& arg5)
|
||||
{
|
||||
return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1),
|
||||
std::forward<_Arg2>(arg2),
|
||||
std::forward<_Arg3>(arg3),
|
||||
std::forward<_Arg4>(arg4),
|
||||
std::forward<_Arg5>(arg5)));
|
||||
}
|
||||
|
||||
template<typename _Type, typename _Arg1, typename _Arg2, typename _Arg3, typename _Arg4, typename _Arg5, typename _Arg6>
|
||||
std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4, _Arg5&& arg5, _Arg6&& arg6)
|
||||
{
|
||||
return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1),
|
||||
std::forward<_Arg2>(arg2),
|
||||
std::forward<_Arg3>(arg3),
|
||||
std::forward<_Arg4>(arg4),
|
||||
std::forward<_Arg5>(arg5),
|
||||
std::forward<_Arg6>(arg6)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cross platform utility function for performing case insensitive string equality comparison.
|
||||
/// </summary>
|
||||
/// <param name="left">First string to compare.</param>
|
||||
/// <param name="right">Second strong to compare.</param>
|
||||
/// <returns>true if the strings are equivalent, false otherwise</returns>
|
||||
_ASYNCRTIMP bool __cdecl str_iequal(const std::string& left, const std::string& right) CPPREST_NOEXCEPT;
|
||||
|
||||
/// <summary>
|
||||
/// Cross platform utility function for performing case insensitive string equality comparison.
|
||||
/// </summary>
|
||||
/// <param name="left">First string to compare.</param>
|
||||
/// <param name="right">Second strong to compare.</param>
|
||||
/// <returns>true if the strings are equivalent, false otherwise</returns>
|
||||
_ASYNCRTIMP bool __cdecl str_iequal(const std::wstring& left, const std::wstring& right) CPPREST_NOEXCEPT;
|
||||
|
||||
/// <summary>
|
||||
/// Cross platform utility function for performing case insensitive string less-than comparison.
|
||||
/// </summary>
|
||||
/// <param name="left">First string to compare.</param>
|
||||
/// <param name="right">Second strong to compare.</param>
|
||||
/// <returns>true if a lowercase view of left is lexicographically less than a lowercase view of right; otherwise,
|
||||
/// false.</returns>
|
||||
_ASYNCRTIMP bool __cdecl str_iless(const std::string& left, const std::string& right) CPPREST_NOEXCEPT;
|
||||
|
||||
/// <summary>
|
||||
/// Cross platform utility function for performing case insensitive string less-than comparison.
|
||||
/// </summary>
|
||||
/// <param name="left">First string to compare.</param>
|
||||
/// <param name="right">Second strong to compare.</param>
|
||||
/// <returns>true if a lowercase view of left is lexicographically less than a lowercase view of right; otherwise,
|
||||
/// false.</returns>
|
||||
_ASYNCRTIMP bool __cdecl str_iless(const std::wstring& left, const std::wstring& right) CPPREST_NOEXCEPT;
|
||||
|
||||
/// <summary>
|
||||
/// Convert a string to lowercase in place.
|
||||
/// </summary>
|
||||
/// <param name="target">The string to convert to lowercase.</param>
|
||||
_ASYNCRTIMP void __cdecl inplace_tolower(std::string& target) CPPREST_NOEXCEPT;
|
||||
|
||||
/// <summary>
|
||||
/// Convert a string to lowercase in place.
|
||||
/// </summary>
|
||||
/// <param name="target">The string to convert to lowercase.</param>
|
||||
_ASYNCRTIMP void __cdecl inplace_tolower(std::wstring& target) CPPREST_NOEXCEPT;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/// <summary>
|
||||
/// Category error type for Windows OS errors.
|
||||
/// </summary>
|
||||
class windows_category_impl : public std::error_category
|
||||
{
|
||||
public:
|
||||
virtual const char* name() const CPPREST_NOEXCEPT { return "windows"; }
|
||||
|
||||
virtual std::string message(int errorCode) const CPPREST_NOEXCEPT;
|
||||
|
||||
virtual std::error_condition default_error_condition(int errorCode) const CPPREST_NOEXCEPT;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the one global instance of the windows error category.
|
||||
/// </summary>
|
||||
/// </returns>An error category instance.</returns>
|
||||
_ASYNCRTIMP const std::error_category& __cdecl windows_category();
|
||||
|
||||
#else
|
||||
|
||||
/// <summary>
|
||||
/// Gets the one global instance of the linux error category.
|
||||
/// </summary>
|
||||
/// </returns>An error category instance.</returns>
|
||||
_ASYNCRTIMP const std::error_category& __cdecl linux_category();
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Gets the one global instance of the current platform's error category.
|
||||
/// </summary>
|
||||
_ASYNCRTIMP const std::error_category& __cdecl platform_category();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of std::system_error from a OS error code.
|
||||
/// </summary>
|
||||
inline std::system_error __cdecl create_system_error(unsigned long errorCode)
|
||||
{
|
||||
std::error_code code((int)errorCode, platform_category());
|
||||
return std::system_error(code, code.message());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a std::error_code from a OS error code.
|
||||
/// </summary>
|
||||
inline std::error_code __cdecl create_error_code(unsigned long errorCode)
|
||||
{
|
||||
return std::error_code((int)errorCode, platform_category());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the corresponding error message from a OS error code.
|
||||
/// </summary>
|
||||
inline utility::string_t __cdecl create_error_message(unsigned long errorCode)
|
||||
{
|
||||
return utility::conversions::to_string_t(create_error_code(errorCode).message());
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
class datetime
|
||||
{
|
||||
public:
|
||||
typedef uint64_t interval_type;
|
||||
|
||||
/// <summary>
|
||||
/// Defines the supported date and time string formats.
|
||||
/// </summary>
|
||||
enum date_format
|
||||
{
|
||||
RFC_1123,
|
||||
ISO_8601
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current UTC time.
|
||||
/// </summary>
|
||||
static _ASYNCRTIMP datetime __cdecl utc_now();
|
||||
|
||||
/// <summary>
|
||||
/// An invalid UTC timestamp value.
|
||||
/// </summary>
|
||||
enum : interval_type
|
||||
{
|
||||
utc_timestamp_invalid = static_cast<interval_type>(-1)
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Returns seconds since Unix/POSIX time epoch at 01-01-1970 00:00:00.
|
||||
/// If time is before epoch, utc_timestamp_invalid is returned.
|
||||
/// </summary>
|
||||
static interval_type utc_timestamp()
|
||||
{
|
||||
const auto seconds = utc_now().to_interval() / _secondTicks;
|
||||
if (seconds >= 11644473600LL)
|
||||
{
|
||||
return seconds - 11644473600LL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return utc_timestamp_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
datetime() : m_interval(0) {}
|
||||
|
||||
/// <summary>
|
||||
/// Creates <c>datetime</c> from a string representing time in UTC in RFC 1123 format.
|
||||
/// </summary>
|
||||
/// <returns>Returns a <c>datetime</c> of zero if not successful.</returns>
|
||||
static _ASYNCRTIMP datetime __cdecl from_string(const utility::string_t& timestring, date_format format = RFC_1123);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string representation of the <c>datetime</c>.
|
||||
/// </summary>
|
||||
_ASYNCRTIMP utility::string_t to_string(date_format format = RFC_1123) const;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the integral time value.
|
||||
/// </summary>
|
||||
interval_type to_interval() const { return m_interval; }
|
||||
|
||||
datetime operator-(interval_type value) const { return datetime(m_interval - value); }
|
||||
|
||||
datetime operator+(interval_type value) const { return datetime(m_interval + value); }
|
||||
|
||||
bool operator==(datetime dt) const { return m_interval == dt.m_interval; }
|
||||
|
||||
bool operator!=(const datetime& dt) const { return !(*this == dt); }
|
||||
|
||||
static interval_type from_milliseconds(unsigned int milliseconds) { return milliseconds * _msTicks; }
|
||||
|
||||
static interval_type from_seconds(unsigned int seconds) { return seconds * _secondTicks; }
|
||||
|
||||
static interval_type from_minutes(unsigned int minutes) { return minutes * _minuteTicks; }
|
||||
|
||||
static interval_type from_hours(unsigned int hours) { return hours * _hourTicks; }
|
||||
|
||||
static interval_type from_days(unsigned int days) { return days * _dayTicks; }
|
||||
|
||||
bool is_initialized() const { return m_interval != 0; }
|
||||
|
||||
private:
|
||||
friend int operator-(datetime t1, datetime t2);
|
||||
|
||||
static const interval_type _msTicks = static_cast<interval_type>(10000);
|
||||
static const interval_type _secondTicks = 1000 * _msTicks;
|
||||
static const interval_type _minuteTicks = 60 * _secondTicks;
|
||||
static const interval_type _hourTicks = 60 * 60 * _secondTicks;
|
||||
static const interval_type _dayTicks = 24 * 60 * 60 * _secondTicks;
|
||||
|
||||
// Private constructor. Use static methods to create an instance.
|
||||
datetime(interval_type interval) : m_interval(interval) {}
|
||||
|
||||
// Storing as hundreds of nanoseconds 10e-7, i.e. 1 here equals 100ns.
|
||||
interval_type m_interval;
|
||||
};
|
||||
|
||||
inline int operator-(datetime t1, datetime t2)
|
||||
{
|
||||
auto diff = (t1.m_interval - t2.m_interval);
|
||||
|
||||
// Round it down to seconds
|
||||
diff /= 10 * 1000 * 1000;
|
||||
|
||||
return static_cast<int>(diff);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Nonce string generator class.
|
||||
/// </summary>
|
||||
class nonce_generator
|
||||
{
|
||||
public:
|
||||
/// <summary>
|
||||
/// Define default nonce length.
|
||||
/// </summary>
|
||||
enum
|
||||
{
|
||||
default_length = 32
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Nonce generator constructor.
|
||||
/// </summary>
|
||||
/// <param name="length">Length of the generated nonce string.</param>
|
||||
nonce_generator(int length = default_length)
|
||||
: m_random(static_cast<unsigned int>(utility::datetime::utc_timestamp())), m_length(length)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a nonce string containing random alphanumeric characters (A-Za-z0-9).
|
||||
/// Length of the generated string is set by length().
|
||||
/// </summary>
|
||||
/// <returns>The generated nonce string.</returns>
|
||||
_ASYNCRTIMP utility::string_t generate();
|
||||
|
||||
/// <summary>
|
||||
/// Get length of generated nonce string.
|
||||
/// </summary>
|
||||
/// <returns>Nonce string length.</returns>
|
||||
int length() const { return m_length; }
|
||||
|
||||
/// <summary>
|
||||
/// Set length of the generated nonce string.
|
||||
/// </summary>
|
||||
/// <param name="length">Lenght of nonce string.</param>
|
||||
void set_length(int length) { m_length = length; }
|
||||
|
||||
private:
|
||||
std::mt19937 m_random;
|
||||
int m_length;
|
||||
};
|
||||
|
||||
} // namespace utility
|
||||
391
deps/cpprestsdk/include/cpprest/base_uri.h
vendored
@@ -1,391 +0,0 @@
|
||||
/***
|
||||
* Copyright (C) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
|
||||
*
|
||||
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
*
|
||||
* Protocol independent support for URIs.
|
||||
*
|
||||
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
|
||||
*
|
||||
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
****/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpprest/asyncrt_utils.h"
|
||||
#include "cpprest/details/basic_types.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace web
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
struct uri_components
|
||||
{
|
||||
uri_components() : m_path(_XPLATSTR("/")), m_port(-1) {}
|
||||
|
||||
uri_components(const uri_components&) = default;
|
||||
uri_components& operator=(const uri_components&) = default;
|
||||
|
||||
// This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped.
|
||||
uri_components(uri_components&& other) CPPREST_NOEXCEPT : m_scheme(std::move(other.m_scheme)),
|
||||
m_host(std::move(other.m_host)),
|
||||
m_user_info(std::move(other.m_user_info)),
|
||||
m_path(std::move(other.m_path)),
|
||||
m_query(std::move(other.m_query)),
|
||||
m_fragment(std::move(other.m_fragment)),
|
||||
m_port(other.m_port)
|
||||
{
|
||||
}
|
||||
|
||||
// This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped.
|
||||
uri_components& operator=(uri_components&& other) CPPREST_NOEXCEPT
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
m_scheme = std::move(other.m_scheme);
|
||||
m_host = std::move(other.m_host);
|
||||
m_user_info = std::move(other.m_user_info);
|
||||
m_path = std::move(other.m_path);
|
||||
m_query = std::move(other.m_query);
|
||||
m_fragment = std::move(other.m_fragment);
|
||||
m_port = other.m_port;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
_ASYNCRTIMP utility::string_t join();
|
||||
|
||||
utility::string_t m_scheme;
|
||||
utility::string_t m_host;
|
||||
utility::string_t m_user_info;
|
||||
utility::string_t m_path;
|
||||
utility::string_t m_query;
|
||||
utility::string_t m_fragment;
|
||||
int m_port;
|
||||
};
|
||||
} // namespace details
|
||||
|
||||
/// <summary>
|
||||
/// A single exception type to represent errors in parsing, encoding, and decoding URIs.
|
||||
/// </summary>
|
||||
class uri_exception : public std::exception
|
||||
{
|
||||
public:
|
||||
uri_exception(std::string msg) : m_msg(std::move(msg)) {}
|
||||
|
||||
~uri_exception() CPPREST_NOEXCEPT {}
|
||||
|
||||
const char* what() const CPPREST_NOEXCEPT { return m_msg.c_str(); }
|
||||
|
||||
private:
|
||||
std::string m_msg;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A flexible, protocol independent URI implementation.
|
||||
///
|
||||
/// URI instances are immutable. Querying the various fields on an empty URI will return empty strings. Querying
|
||||
/// various diagnostic members on an empty URI will return false.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This implementation accepts both URIs ('http://msn.com/path') and URI relative-references
|
||||
/// ('/path?query#frag').
|
||||
///
|
||||
/// This implementation does not provide any scheme-specific handling -- an example of this
|
||||
/// would be the following: 'http://path1/path'. This is a valid URI, but it's not a valid
|
||||
/// http-uri -- that is, it's syntactically correct but does not conform to the requirements
|
||||
/// of the http scheme (http requires a host).
|
||||
/// We could provide this by allowing a pluggable 'scheme' policy-class, which would provide
|
||||
/// extra capability for validating and canonicalizing a URI according to scheme, and would
|
||||
/// introduce a layer of type-safety for URIs of differing schemes, and thus differing semantics.
|
||||
///
|
||||
/// One issue with implementing a scheme-independent URI facility is that of comparing for equality.
|
||||
/// For instance, these URIs are considered equal 'http://msn.com', 'http://msn.com:80'. That is --
|
||||
/// the 'default' port can be either omitted or explicit. Since we don't have a way to map a scheme
|
||||
/// to it's default port, we don't have a way to know these are equal. This is just one of a class of
|
||||
/// issues with regard to scheme-specific behavior.
|
||||
/// </remarks>
|
||||
class uri
|
||||
{
|
||||
public:
|
||||
/// <summary>
|
||||
/// The various components of a URI. This enum is used to indicate which
|
||||
/// URI component is being encoded to the encode_uri_component. This allows
|
||||
/// specific encoding to be performed.
|
||||
///
|
||||
/// Scheme and port don't allow '%' so they don't need to be encoded.
|
||||
/// </summary>
|
||||
class components
|
||||
{
|
||||
public:
|
||||
enum component
|
||||
{
|
||||
user_info,
|
||||
host,
|
||||
path,
|
||||
query,
|
||||
fragment,
|
||||
full_uri
|
||||
};
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Encodes a URI component according to RFC 3986.
|
||||
/// Note if a full URI is specified instead of an individual URI component all
|
||||
/// characters not in the unreserved set are escaped.
|
||||
/// </summary>
|
||||
/// <param name="raw">The URI as a string.</param>
|
||||
/// <returns>The encoded string.</returns>
|
||||
_ASYNCRTIMP static utility::string_t __cdecl encode_uri(const utility::string_t& raw,
|
||||
uri::components::component = components::full_uri);
|
||||
|
||||
/// <summary>
|
||||
/// Encodes a string by converting all characters except for RFC 3986 unreserved characters to their
|
||||
/// hexadecimal representation.
|
||||
/// </summary>
|
||||
/// <returns>The encoded string.</returns>
|
||||
_ASYNCRTIMP static utility::string_t __cdecl encode_data_string(const utility::string_t& data);
|
||||
|
||||
/// <summary>
|
||||
/// Decodes an encoded string.
|
||||
/// </summary>
|
||||
/// <param name="encoded">The URI as a string.</param>
|
||||
/// <returns>The decoded string.</returns>
|
||||
_ASYNCRTIMP static utility::string_t __cdecl decode(const utility::string_t& encoded);
|
||||
|
||||
/// <summary>
|
||||
/// Splits a path into its hierarchical components.
|
||||
/// </summary>
|
||||
/// <param name="path">The path as a string</param>
|
||||
/// <returns>A <c>std::vector<utility::string_t></c> containing the segments in the path.</returns>
|
||||
_ASYNCRTIMP static std::vector<utility::string_t> __cdecl split_path(const utility::string_t& path);
|
||||
|
||||
/// <summary>
|
||||
/// Splits a query into its key-value components.
|
||||
/// </summary>
|
||||
/// <param name="query">The query string</param>
|
||||
/// <returns>A <c>std::map<utility::string_t, utility::string_t></c> containing the key-value components of
|
||||
/// the query.</returns>
|
||||
_ASYNCRTIMP static std::map<utility::string_t, utility::string_t> __cdecl split_query(
|
||||
const utility::string_t& query);
|
||||
|
||||
/// <summary>
|
||||
/// Validates a string as a URI.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This function accepts both uris ('http://msn.com') and uri relative-references ('path1/path2?query').
|
||||
/// </remarks>
|
||||
/// <param name="uri_string">The URI string to be validated.</param>
|
||||
/// <returns><c>true</c> if the given string represents a valid URI, <c>false</c> otherwise.</returns>
|
||||
_ASYNCRTIMP static bool __cdecl validate(const utility::string_t& uri_string);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an empty uri
|
||||
/// </summary>
|
||||
uri() : m_uri(_XPLATSTR("/")) {}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a URI from the given encoded string. This will throw an exception if the string
|
||||
/// does not contain a valid URI. Use uri::validate if processing user-input.
|
||||
/// </summary>
|
||||
/// <param name="uri_string">A pointer to an encoded string to create the URI instance.</param>
|
||||
_ASYNCRTIMP uri(const utility::char_t* uri_string);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a URI from the given encoded string. This will throw an exception if the string
|
||||
/// does not contain a valid URI. Use uri::validate if processing user-input.
|
||||
/// </summary>
|
||||
/// <param name="uri_string">An encoded URI string to create the URI instance.</param>
|
||||
_ASYNCRTIMP uri(const utility::string_t& uri_string);
|
||||
|
||||
/// <summary>
|
||||
/// Copy constructor.
|
||||
/// </summary>
|
||||
uri(const uri&) = default;
|
||||
|
||||
/// <summary>
|
||||
/// Copy assignment operator.
|
||||
/// </summary>
|
||||
uri& operator=(const uri&) = default;
|
||||
|
||||
/// <summary>
|
||||
/// Move constructor.
|
||||
/// </summary>
|
||||
// This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped.
|
||||
uri(uri&& other) CPPREST_NOEXCEPT : m_uri(std::move(other.m_uri)), m_components(std::move(other.m_components)) {}
|
||||
|
||||
/// <summary>
|
||||
/// Move assignment operator
|
||||
/// </summary>
|
||||
// This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped.
|
||||
uri& operator=(uri&& other) CPPREST_NOEXCEPT
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
m_uri = std::move(other.m_uri);
|
||||
m_components = std::move(other.m_components);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the scheme component of the URI as an encoded string.
|
||||
/// </summary>
|
||||
/// <returns>The URI scheme as a string.</returns>
|
||||
const utility::string_t& scheme() const { return m_components.m_scheme; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the user information component of the URI as an encoded string.
|
||||
/// </summary>
|
||||
/// <returns>The URI user information as a string.</returns>
|
||||
const utility::string_t& user_info() const { return m_components.m_user_info; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the host component of the URI as an encoded string.
|
||||
/// </summary>
|
||||
/// <returns>The URI host as a string.</returns>
|
||||
const utility::string_t& host() const { return m_components.m_host; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the port component of the URI. Returns -1 if no port is specified.
|
||||
/// </summary>
|
||||
/// <returns>The URI port as an integer.</returns>
|
||||
int port() const { return m_components.m_port; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the path component of the URI as an encoded string.
|
||||
/// </summary>
|
||||
/// <returns>The URI path as a string.</returns>
|
||||
const utility::string_t& path() const { return m_components.m_path; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the query component of the URI as an encoded string.
|
||||
/// </summary>
|
||||
/// <returns>The URI query as a string.</returns>
|
||||
const utility::string_t& query() const { return m_components.m_query; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the fragment component of the URI as an encoded string.
|
||||
/// </summary>
|
||||
/// <returns>The URI fragment as a string.</returns>
|
||||
const utility::string_t& fragment() const { return m_components.m_fragment; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new uri object with the same authority portion as this one, omitting the resource and query portions.
|
||||
/// </summary>
|
||||
/// <returns>The new uri object with the same authority.</returns>
|
||||
_ASYNCRTIMP uri authority() const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path, query, and fragment portion of this uri, which may be empty.
|
||||
/// </summary>
|
||||
/// <returns>The new URI object with the path, query and fragment portion of this URI.</returns>
|
||||
_ASYNCRTIMP uri resource() const;
|
||||
|
||||
/// <summary>
|
||||
/// An empty URI specifies no components, and serves as a default value
|
||||
/// </summary>
|
||||
bool is_empty() const { return this->m_uri.empty() || this->m_uri == _XPLATSTR("/"); }
|
||||
|
||||
/// <summary>
|
||||
/// A loopback URI is one which refers to a hostname or ip address with meaning only on the local machine.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Examples include "localhost", or ip addresses in the loopback range (127.0.0.0/24).
|
||||
/// </remarks>
|
||||
/// <returns><c>true</c> if this URI references the local host, <c>false</c> otherwise.</returns>
|
||||
bool is_host_loopback() const
|
||||
{
|
||||
return !is_empty() &&
|
||||
((host() == _XPLATSTR("localhost")) || (host().size() > 4 && host().substr(0, 4) == _XPLATSTR("127.")));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A wildcard URI is one which refers to all hostnames that resolve to the local machine (using the * or +)
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// http://*:80
|
||||
/// </example>
|
||||
bool is_host_wildcard() const
|
||||
{
|
||||
return !is_empty() && (this->host() == _XPLATSTR("*") || this->host() == _XPLATSTR("+"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A portable URI is one with a hostname that can be resolved globally (used from another machine).
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if this URI can be resolved globally (used from another machine), <c>false</c>
|
||||
/// otherwise.</returns> <remarks> The hostname "localhost" is a reserved name that is guaranteed to resolve to the
|
||||
/// local machine, and cannot be used for inter-machine communication. Likewise the hostnames "*" and "+" on Windows
|
||||
/// represent wildcards, and do not map to a resolvable address.
|
||||
/// </remarks>
|
||||
bool is_host_portable() const { return !(is_empty() || is_host_loopback() || is_host_wildcard()); }
|
||||
|
||||
/// <summary>
|
||||
/// A default port is one where the port is unspecified, and will be determined by the operating system.
|
||||
/// The choice of default port may be dictated by the scheme (http -> 80) or not.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if this URI instance has a default port, <c>false</c> otherwise.</returns>
|
||||
bool is_port_default() const { return !is_empty() && this->port() == 0; }
|
||||
|
||||
/// <summary>
|
||||
/// An "authority" URI is one with only a scheme, optional userinfo, hostname, and (optional) port.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if this is an "authority" URI, <c>false</c> otherwise.</returns>
|
||||
bool is_authority() const { return !is_empty() && is_path_empty() && query().empty() && fragment().empty(); }
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the other URI has the same authority as this one
|
||||
/// </summary>
|
||||
/// <param name="other">The URI to compare the authority with.</param>
|
||||
/// <returns><c>true</c> if both the URI's have the same authority, <c>false</c> otherwise.</returns>
|
||||
bool has_same_authority(const uri& other) const { return !is_empty() && this->authority() == other.authority(); }
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the path portion of this URI is empty
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if the path portion of this URI is empty, <c>false</c> otherwise.</returns>
|
||||
bool is_path_empty() const { return path().empty() || path() == _XPLATSTR("/"); }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the full (encoded) URI as a string.
|
||||
/// </summary>
|
||||
/// <returns>The full encoded URI string.</returns>
|
||||
utility::string_t to_string() const { return m_uri; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns an URI resolved against <c>this</c> as the base URI
|
||||
/// according to RFC3986, Section 5 (https://tools.ietf.org/html/rfc3986#section-5).
|
||||
/// </summary>
|
||||
/// <param name="relativeUri">The relative URI to be resolved against <c>this</c> as base.</param>
|
||||
/// <returns>The new resolved URI string.</returns>
|
||||
_ASYNCRTIMP utility::string_t resolve_uri(const utility::string_t& relativeUri) const;
|
||||
|
||||
_ASYNCRTIMP bool operator==(const uri& other) const;
|
||||
|
||||
bool operator<(const uri& other) const { return m_uri < other.m_uri; }
|
||||
|
||||
bool operator!=(const uri& other) const { return !(this->operator==(other)); }
|
||||
|
||||
private:
|
||||
friend class uri_builder;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a URI from the given URI components.
|
||||
/// </summary>
|
||||
/// <param name="components">A URI components object to create the URI instance.</param>
|
||||
_ASYNCRTIMP uri(const details::uri_components& components);
|
||||
|
||||
// Used by uri_builder
|
||||
static utility::string_t __cdecl encode_query_impl(const utf8string& raw);
|
||||
|
||||
utility::string_t m_uri;
|
||||
details::uri_components m_components;
|
||||
};
|
||||
|
||||
} // namespace web
|
||||
7482
deps/cpprestsdk/include/cpprest/details/SafeInt3.hpp
vendored
@@ -1,131 +0,0 @@
|
||||
/***
|
||||
* Copyright (C) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
|
||||
*
|
||||
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
*
|
||||
* Platform-dependent type definitions
|
||||
*
|
||||
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
|
||||
*
|
||||
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
****/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpprest/details/cpprest_compat.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#ifndef _WIN32
|
||||
#ifndef __STDC_LIMIT_MACROS
|
||||
#define __STDC_LIMIT_MACROS
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#include <cstdint>
|
||||
#endif
|
||||
|
||||
#include "cpprest/details/SafeInt3.hpp"
|
||||
|
||||
namespace utility
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#define _UTF16_STRINGS
|
||||
#endif
|
||||
|
||||
// We should be using a 64-bit size type for most situations that do
|
||||
// not involve specifying the size of a memory allocation or buffer.
|
||||
typedef uint64_t size64_t;
|
||||
|
||||
#ifndef _WIN32
|
||||
typedef uint32_t HRESULT; // Needed for PPLX
|
||||
#endif
|
||||
|
||||
#ifdef _UTF16_STRINGS
|
||||
//
|
||||
// On Windows, all strings are wide
|
||||
//
|
||||
typedef wchar_t char_t;
|
||||
typedef std::wstring string_t;
|
||||
#define _XPLATSTR(x) L##x
|
||||
typedef std::wostringstream ostringstream_t;
|
||||
typedef std::wofstream ofstream_t;
|
||||
typedef std::wostream ostream_t;
|
||||
typedef std::wistream istream_t;
|
||||
typedef std::wifstream ifstream_t;
|
||||
typedef std::wistringstream istringstream_t;
|
||||
typedef std::wstringstream stringstream_t;
|
||||
#define ucout std::wcout
|
||||
#define ucin std::wcin
|
||||
#define ucerr std::wcerr
|
||||
#else
|
||||
//
|
||||
// On POSIX platforms, all strings are narrow
|
||||
//
|
||||
typedef char char_t;
|
||||
typedef std::string string_t;
|
||||
#define _XPLATSTR(x) x
|
||||
typedef std::ostringstream ostringstream_t;
|
||||
typedef std::ofstream ofstream_t;
|
||||
typedef std::ostream ostream_t;
|
||||
typedef std::istream istream_t;
|
||||
typedef std::ifstream ifstream_t;
|
||||
typedef std::istringstream istringstream_t;
|
||||
typedef std::stringstream stringstream_t;
|
||||
#define ucout std::cout
|
||||
#define ucin std::cin
|
||||
#define ucerr std::cerr
|
||||
#endif // endif _UTF16_STRINGS
|
||||
|
||||
#ifndef _TURN_OFF_PLATFORM_STRING
|
||||
// The 'U' macro can be used to create a string or character literal of the platform type, i.e. utility::char_t.
|
||||
// If you are using a library causing conflicts with 'U' macro, it can be turned off by defining the macro
|
||||
// '_TURN_OFF_PLATFORM_STRING' before including the C++ REST SDK header files, and e.g. use '_XPLATSTR' instead.
|
||||
#define U(x) _XPLATSTR(x)
|
||||
#endif // !_TURN_OFF_PLATFORM_STRING
|
||||
|
||||
} // namespace utility
|
||||
|
||||
typedef char utf8char;
|
||||
typedef std::string utf8string;
|
||||
typedef std::stringstream utf8stringstream;
|
||||
typedef std::ostringstream utf8ostringstream;
|
||||
typedef std::ostream utf8ostream;
|
||||
typedef std::istream utf8istream;
|
||||
typedef std::istringstream utf8istringstream;
|
||||
|
||||
#ifdef _UTF16_STRINGS
|
||||
typedef wchar_t utf16char;
|
||||
typedef std::wstring utf16string;
|
||||
typedef std::wstringstream utf16stringstream;
|
||||
typedef std::wostringstream utf16ostringstream;
|
||||
typedef std::wostream utf16ostream;
|
||||
typedef std::wistream utf16istream;
|
||||
typedef std::wistringstream utf16istringstream;
|
||||
#else
|
||||
typedef char16_t utf16char;
|
||||
typedef std::u16string utf16string;
|
||||
typedef std::basic_stringstream<utf16char> utf16stringstream;
|
||||
typedef std::basic_ostringstream<utf16char> utf16ostringstream;
|
||||
typedef std::basic_ostream<utf16char> utf16ostream;
|
||||
typedef std::basic_istream<utf16char> utf16istream;
|
||||
typedef std::basic_istringstream<utf16char> utf16istringstream;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
// Include on everything except Windows Desktop ARM, unless explicitly excluded.
|
||||
#if !defined(CPPREST_EXCLUDE_WEBSOCKETS)
|
||||
#if defined(WINAPI_FAMILY)
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && defined(_M_ARM)
|
||||
#define CPPREST_EXCLUDE_WEBSOCKETS
|
||||
#endif
|
||||
#else
|
||||
#if defined(_M_ARM)
|
||||
#define CPPREST_EXCLUDE_WEBSOCKETS
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,91 +0,0 @@
|
||||
/***
|
||||
* Copyright (C) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
|
||||
*
|
||||
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
*
|
||||
* Standard macros and definitions.
|
||||
* This header has minimal dependency on windows headers and is safe for use in the public API
|
||||
*
|
||||
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
|
||||
*
|
||||
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
****/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#if _MSC_VER >= 1900
|
||||
#define CPPREST_NOEXCEPT noexcept
|
||||
#define CPPREST_CONSTEXPR constexpr
|
||||
#else
|
||||
#define CPPREST_NOEXCEPT
|
||||
#define CPPREST_CONSTEXPR const
|
||||
#endif // _MSC_VER >= 1900
|
||||
|
||||
#define CASABLANCA_UNREFERENCED_PARAMETER(x) (x)
|
||||
|
||||
#include <sal.h>
|
||||
|
||||
#else // ^^^ _WIN32 ^^^ // vvv !_WIN32 vvv
|
||||
|
||||
#define __declspec(x) __attribute__((x))
|
||||
#define dllimport
|
||||
#define novtable /* no novtable equivalent */
|
||||
#define __assume(x) \
|
||||
do \
|
||||
{ \
|
||||
if (!(x)) __builtin_unreachable(); \
|
||||
} while (false)
|
||||
#define CASABLANCA_UNREFERENCED_PARAMETER(x) (void)x
|
||||
#define CPPREST_NOEXCEPT noexcept
|
||||
#define CPPREST_CONSTEXPR constexpr
|
||||
|
||||
#include <assert.h>
|
||||
#define _ASSERTE(x) assert(x)
|
||||
|
||||
// No SAL on non Windows platforms
|
||||
#include "cpprest/details/nosal.h"
|
||||
|
||||
#if !defined(__cdecl)
|
||||
#if defined(cdecl)
|
||||
#define __cdecl __attribute__((cdecl))
|
||||
#else // ^^^ defined cdecl ^^^ // vvv !defined cdecl vvv
|
||||
#define __cdecl
|
||||
#endif // defined cdecl
|
||||
#endif // not defined __cdecl
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
// This is needed to disable the use of __thread inside the boost library.
|
||||
// Android does not support thread local storage -- if boost is included
|
||||
// without this macro defined, it will create references to __tls_get_addr
|
||||
// which (while able to link) will not be available at runtime and prevent
|
||||
// the .so from loading.
|
||||
#if not defined BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION
|
||||
#define BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION
|
||||
#endif // not defined BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION
|
||||
#endif // defined(__ANDROID__)
|
||||
|
||||
#ifdef __clang__
|
||||
#include <cstdio>
|
||||
#endif // __clang__
|
||||
#endif // _WIN32
|
||||
|
||||
#define _NO_ASYNCRTIMP
|
||||
|
||||
#ifdef _NO_ASYNCRTIMP
|
||||
#define _ASYNCRTIMP
|
||||
#else // ^^^ _NO_ASYNCRTIMP ^^^ // vvv !_NO_ASYNCRTIMP vvv
|
||||
#ifdef _ASYNCRT_EXPORT
|
||||
#define _ASYNCRTIMP __declspec(dllexport)
|
||||
#else // ^^^ _ASYNCRT_EXPORT ^^^ // vvv !_ASYNCRT_EXPORT vvv
|
||||
#define _ASYNCRTIMP __declspec(dllimport)
|
||||
#endif // _ASYNCRT_EXPORT
|
||||
#endif // _NO_ASYNCRTIMP
|
||||
|
||||
#ifdef CASABLANCA_DEPRECATION_NO_WARNINGS
|
||||
#define CASABLANCA_DEPRECATED(x)
|
||||
#else
|
||||
#define CASABLANCA_DEPRECATED(x) __declspec(deprecated(x))
|
||||
#endif // CASABLANCA_DEPRECATION_NO_WARNINGS
|
||||
@@ -1,223 +0,0 @@
|
||||
/***
|
||||
* Copyright (C) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
|
||||
*
|
||||
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
*
|
||||
* utility classes used by the different web:: clients
|
||||
*
|
||||
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
****/
|
||||
#pragma once
|
||||
|
||||
#include "cpprest/asyncrt_utils.h"
|
||||
#include "cpprest/uri.h"
|
||||
|
||||
namespace web
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
class zero_memory_deleter
|
||||
{
|
||||
public:
|
||||
_ASYNCRTIMP void operator()(::utility::string_t* data) const;
|
||||
};
|
||||
typedef std::unique_ptr<::utility::string_t, zero_memory_deleter> plaintext_string;
|
||||
|
||||
#if defined(_WIN32) && !defined(CPPREST_TARGET_XP)
|
||||
#if defined(__cplusplus_winrt)
|
||||
class winrt_encryption
|
||||
{
|
||||
public:
|
||||
winrt_encryption() {}
|
||||
_ASYNCRTIMP winrt_encryption(const std::wstring& data);
|
||||
_ASYNCRTIMP plaintext_string decrypt() const;
|
||||
|
||||
private:
|
||||
::pplx::task<Windows::Storage::Streams::IBuffer ^> m_buffer;
|
||||
};
|
||||
#else
|
||||
class win32_encryption
|
||||
{
|
||||
public:
|
||||
win32_encryption() {}
|
||||
_ASYNCRTIMP win32_encryption(const std::wstring& data);
|
||||
_ASYNCRTIMP ~win32_encryption();
|
||||
_ASYNCRTIMP plaintext_string decrypt() const;
|
||||
|
||||
private:
|
||||
std::vector<char> m_buffer;
|
||||
size_t m_numCharacters;
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
} // namespace details
|
||||
|
||||
/// <summary>
|
||||
/// Represents a set of user credentials (user name and password) to be used
|
||||
/// for authentication.
|
||||
/// </summary>
|
||||
class credentials
|
||||
{
|
||||
public:
|
||||
/// <summary>
|
||||
/// Constructs an empty set of credentials without a user name or password.
|
||||
/// </summary>
|
||||
credentials() {}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs credentials from given user name and password.
|
||||
/// </summary>
|
||||
/// <param name="username">User name as a string.</param>
|
||||
/// <param name="password">Password as a string.</param>
|
||||
credentials(utility::string_t username, const utility::string_t& password)
|
||||
: m_username(std::move(username)), m_password(password)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The user name associated with the credentials.
|
||||
/// </summary>
|
||||
/// <returns>A string containing the user name.</returns>
|
||||
const utility::string_t& username() const { return m_username; }
|
||||
|
||||
/// <summary>
|
||||
/// The password for the user name associated with the credentials.
|
||||
/// </summary>
|
||||
/// <returns>A string containing the password.</returns>
|
||||
CASABLANCA_DEPRECATED(
|
||||
"This API is deprecated for security reasons to avoid unnecessary password copies stored in plaintext.")
|
||||
utility::string_t password() const
|
||||
{
|
||||
#if defined(_WIN32) && !defined(CPPREST_TARGET_XP)
|
||||
return utility::string_t(*m_password.decrypt());
|
||||
#else
|
||||
return m_password;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if credentials have been set
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if user name and password is set, <c>false</c> otherwise.</returns>
|
||||
bool is_set() const { return !m_username.empty(); }
|
||||
|
||||
details::plaintext_string _internal_decrypt() const
|
||||
{
|
||||
// Encryption APIs not supported on XP
|
||||
#if defined(_WIN32) && !defined(CPPREST_TARGET_XP)
|
||||
return m_password.decrypt();
|
||||
#else
|
||||
return details::plaintext_string(new ::utility::string_t(m_password));
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
::utility::string_t m_username;
|
||||
|
||||
#if defined(_WIN32) && !defined(CPPREST_TARGET_XP)
|
||||
#if defined(__cplusplus_winrt)
|
||||
details::winrt_encryption m_password;
|
||||
#else
|
||||
details::win32_encryption m_password;
|
||||
#endif
|
||||
#else
|
||||
::utility::string_t m_password;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// web_proxy represents the concept of the web proxy, which can be auto-discovered,
|
||||
/// disabled, or specified explicitly by the user.
|
||||
/// </summary>
|
||||
class web_proxy
|
||||
{
|
||||
enum web_proxy_mode_internal
|
||||
{
|
||||
use_default_,
|
||||
use_auto_discovery_,
|
||||
disabled_,
|
||||
user_provided_
|
||||
};
|
||||
|
||||
public:
|
||||
enum web_proxy_mode
|
||||
{
|
||||
use_default = use_default_,
|
||||
use_auto_discovery = use_auto_discovery_,
|
||||
disabled = disabled_
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a proxy with the default settings.
|
||||
/// </summary>
|
||||
web_proxy() : m_address(_XPLATSTR("")), m_mode(use_default_) {}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a proxy with specified mode.
|
||||
/// </summary>
|
||||
/// <param name="mode">Mode to use.</param>
|
||||
web_proxy(web_proxy_mode mode) : m_address(_XPLATSTR("")), m_mode(static_cast<web_proxy_mode_internal>(mode)) {}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a proxy explicitly with provided address.
|
||||
/// </summary>
|
||||
/// <param name="address">Proxy URI to use.</param>
|
||||
web_proxy(uri address) : m_address(address), m_mode(user_provided_) {}
|
||||
|
||||
/// <summary>
|
||||
/// Gets this proxy's URI address. Returns an empty URI if not explicitly set by user.
|
||||
/// </summary>
|
||||
/// <returns>A reference to this proxy's URI.</returns>
|
||||
const uri& address() const { return m_address; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the credentials used for authentication with this proxy.
|
||||
/// </summary>
|
||||
/// <returns>Credentials to for this proxy.</returns>
|
||||
const web::credentials& credentials() const { return m_credentials; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the credentials to use for authentication with this proxy.
|
||||
/// </summary>
|
||||
/// <param name="cred">Credentials to use for this proxy.</param>
|
||||
void set_credentials(web::credentials cred)
|
||||
{
|
||||
if (m_mode == disabled_)
|
||||
{
|
||||
throw std::invalid_argument("Cannot attach credentials to a disabled proxy");
|
||||
}
|
||||
m_credentials = std::move(cred);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if this proxy was constructed with default settings.
|
||||
/// </summary>
|
||||
/// <returns>True if default, false otherwise.</param>
|
||||
bool is_default() const { return m_mode == use_default_; }
|
||||
|
||||
/// <summary>
|
||||
/// Checks if using a proxy is disabled.
|
||||
/// </summary>
|
||||
/// <returns>True if disabled, false otherwise.</returns>
|
||||
bool is_disabled() const { return m_mode == disabled_; }
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the auto discovery protocol, WPAD, is to be used.
|
||||
/// </summary>
|
||||
/// <returns>True if auto discovery enabled, false otherwise.</returns>
|
||||
bool is_auto_discovery() const { return m_mode == use_auto_discovery_; }
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a proxy address is explicitly specified by the user.
|
||||
/// </summary>
|
||||
/// <returns>True if a proxy address was explicitly specified, false otherwise.</returns>
|
||||
bool is_specified() const { return m_mode == user_provided_; }
|
||||
|
||||
private:
|
||||
web::uri m_address;
|
||||
web_proxy_mode_internal m_mode;
|
||||
web::credentials m_credentials;
|
||||
};
|
||||
|
||||
} // namespace web
|
||||
1786
deps/cpprestsdk/include/cpprest/json.h
vendored
21
deps/cpprestsdk/include/cpprest/uri.h
vendored
@@ -1,21 +0,0 @@
|
||||
/***
|
||||
* Copyright (C) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
|
||||
*
|
||||
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
*
|
||||
* Protocol independent support for URIs.
|
||||
*
|
||||
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
|
||||
*
|
||||
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
****/
|
||||
#pragma once
|
||||
|
||||
#ifndef CASA_URI_H
|
||||
#define CASA_URI_H
|
||||
|
||||
#include "cpprest/base_uri.h"
|
||||
#include "cpprest/uri_builder.h"
|
||||
|
||||
#endif
|
||||
295
deps/cpprestsdk/include/cpprest/uri_builder.h
vendored
@@ -1,295 +0,0 @@
|
||||
/***
|
||||
* Copyright (C) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
|
||||
*
|
||||
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
*
|
||||
* Builder style class for creating URIs.
|
||||
*
|
||||
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
|
||||
*
|
||||
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
****/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpprest/base_uri.h"
|
||||
#include <string>
|
||||
|
||||
namespace web
|
||||
{
|
||||
/// <summary>
|
||||
/// Builder for constructing URIs incrementally.
|
||||
/// </summary>
|
||||
class uri_builder
|
||||
{
|
||||
public:
|
||||
/// <summary>
|
||||
/// Creates a builder with an initially empty URI.
|
||||
/// </summary>
|
||||
uri_builder() = default;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a builder with a existing URI object.
|
||||
/// </summary>
|
||||
/// <param name="uri_str">Encoded string containing the URI.</param>
|
||||
uri_builder(const uri& uri_str) : m_uri(uri_str.m_components) {}
|
||||
|
||||
/// <summary>
|
||||
/// Get the scheme component of the URI as an encoded string.
|
||||
/// </summary>
|
||||
/// <returns>The URI scheme as a string.</returns>
|
||||
const utility::string_t& scheme() const { return m_uri.m_scheme; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the user information component of the URI as an encoded string.
|
||||
/// </summary>
|
||||
/// <returns>The URI user information as a string.</returns>
|
||||
const utility::string_t& user_info() const { return m_uri.m_user_info; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the host component of the URI as an encoded string.
|
||||
/// </summary>
|
||||
/// <returns>The URI host as a string.</returns>
|
||||
const utility::string_t& host() const { return m_uri.m_host; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the port component of the URI. Returns -1 if no port is specified.
|
||||
/// </summary>
|
||||
/// <returns>The URI port as an integer.</returns>
|
||||
int port() const { return m_uri.m_port; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the path component of the URI as an encoded string.
|
||||
/// </summary>
|
||||
/// <returns>The URI path as a string.</returns>
|
||||
const utility::string_t& path() const { return m_uri.m_path; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the query component of the URI as an encoded string.
|
||||
/// </summary>
|
||||
/// <returns>The URI query as a string.</returns>
|
||||
const utility::string_t& query() const { return m_uri.m_query; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the fragment component of the URI as an encoded string.
|
||||
/// </summary>
|
||||
/// <returns>The URI fragment as a string.</returns>
|
||||
const utility::string_t& fragment() const { return m_uri.m_fragment; }
|
||||
|
||||
/// <summary>
|
||||
/// Set the scheme of the URI.
|
||||
/// </summary>
|
||||
/// <param name="scheme">Uri scheme.</param>
|
||||
/// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>
|
||||
uri_builder& set_scheme(const utility::string_t& scheme)
|
||||
{
|
||||
m_uri.m_scheme = scheme;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the user info component of the URI.
|
||||
/// </summary>
|
||||
/// <param name="user_info">User info as a decoded string.</param>
|
||||
/// <param name="do_encoding">Specify whether to apply URI encoding to the given string.</param>
|
||||
/// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>
|
||||
uri_builder& set_user_info(const utility::string_t& user_info, bool do_encoding = false)
|
||||
{
|
||||
if (do_encoding)
|
||||
{
|
||||
m_uri.m_user_info = uri::encode_uri(user_info, uri::components::user_info);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_uri.m_user_info = user_info;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the host component of the URI.
|
||||
/// </summary>
|
||||
/// <param name="host">Host as a decoded string.</param>
|
||||
/// <param name="do_encoding">Specify whether to apply URI encoding to the given string.</param>
|
||||
/// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>
|
||||
uri_builder& set_host(const utility::string_t& host, bool do_encoding = false)
|
||||
{
|
||||
if (do_encoding)
|
||||
{
|
||||
m_uri.m_host = uri::encode_uri(host, uri::components::host);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_uri.m_host = host;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the port component of the URI.
|
||||
/// </summary>
|
||||
/// <param name="port">Port as an integer.</param>
|
||||
/// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>
|
||||
uri_builder& set_port(int port)
|
||||
{
|
||||
m_uri.m_port = port;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the port component of the URI.
|
||||
/// </summary>
|
||||
/// <param name="port">Port as a string.</param>
|
||||
/// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>
|
||||
/// <remarks>When string can't be converted to an integer the port is left unchanged.</remarks>
|
||||
_ASYNCRTIMP uri_builder& set_port(const utility::string_t& port);
|
||||
|
||||
/// <summary>
|
||||
/// Set the path component of the URI.
|
||||
/// </summary>
|
||||
/// <param name="path">Path as a decoded string.</param>
|
||||
/// <param name="do_encoding">Specify whether to apply URI encoding to the given string.</param>
|
||||
/// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>
|
||||
uri_builder& set_path(const utility::string_t& path, bool do_encoding = false)
|
||||
{
|
||||
if (do_encoding)
|
||||
{
|
||||
m_uri.m_path = uri::encode_uri(path, uri::components::path);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_uri.m_path = path;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the query component of the URI.
|
||||
/// </summary>
|
||||
/// <param name="query">Query as a decoded string.</param>
|
||||
/// <param name="do_encoding">Specify whether apply URI encoding to the given string.</param>
|
||||
/// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>
|
||||
uri_builder& set_query(const utility::string_t& query, bool do_encoding = false)
|
||||
{
|
||||
if (do_encoding)
|
||||
{
|
||||
m_uri.m_query = uri::encode_uri(query, uri::components::query);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_uri.m_query = query;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the fragment component of the URI.
|
||||
/// </summary>
|
||||
/// <param name="fragment">Fragment as a decoded string.</param>
|
||||
/// <param name="do_encoding">Specify whether to apply URI encoding to the given string.</param>
|
||||
/// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>
|
||||
uri_builder& set_fragment(const utility::string_t& fragment, bool do_encoding = false)
|
||||
{
|
||||
if (do_encoding)
|
||||
{
|
||||
m_uri.m_fragment = uri::encode_uri(fragment, uri::components::fragment);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_uri.m_fragment = fragment;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all components of the underlying URI in this uri_builder.
|
||||
/// </summary>
|
||||
void clear() { m_uri = details::uri_components(); }
|
||||
|
||||
/// <summary>
|
||||
/// Appends another path to the path of this uri_builder.
|
||||
/// </summary>
|
||||
/// <param name="path">Path to append as a already encoded string.</param>
|
||||
/// <param name="do_encoding">Specify whether to apply URI encoding to the given string.</param>
|
||||
/// <returns>A reference to this uri_builder to support chaining.</returns>
|
||||
_ASYNCRTIMP uri_builder& append_path(const utility::string_t& path, bool do_encoding = false);
|
||||
|
||||
/// <summary>
|
||||
/// Appends the raw contents of the path argument to the path of this uri_builder with no separator de-duplication.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The path argument is appended after adding a '/' separator without regards to the contents of path. If an empty
|
||||
/// string is provided, this function will immediately return without changes to the stored path value. For example:
|
||||
/// if the current contents are "/abc" and path="/xyz", the result will be "/abc//xyz".
|
||||
/// </remarks>
|
||||
/// <param name="path">Path to append as a already encoded string.</param>
|
||||
/// <param name="do_encoding">Specify whether to apply URI encoding to the given string.</param>
|
||||
/// <returns>A reference to this uri_builder to support chaining.</returns>
|
||||
_ASYNCRTIMP uri_builder& append_path_raw(const utility::string_t& path, bool do_encoding = false);
|
||||
|
||||
/// <summary>
|
||||
/// Appends another query to the query of this uri_builder.
|
||||
/// </summary>
|
||||
/// <param name="query">Query to append as a decoded string.</param>
|
||||
/// <param name="do_encoding">Specify whether to apply URI encoding to the given string.</param>
|
||||
/// <returns>A reference to this uri_builder to support chaining.</returns>
|
||||
_ASYNCRTIMP uri_builder& append_query(const utility::string_t& query, bool do_encoding = false);
|
||||
|
||||
/// <summary>
|
||||
/// Appends an relative uri (Path, Query and fragment) at the end of the current uri.
|
||||
/// </summary>
|
||||
/// <param name="relative_uri">The relative uri to append.</param>
|
||||
/// <returns>A reference to this uri_builder to support chaining.</returns>
|
||||
_ASYNCRTIMP uri_builder& append(const uri& relative_uri);
|
||||
|
||||
/// <summary>
|
||||
/// Appends another query to the query of this uri_builder, encoding it first. This overload is useful when building
|
||||
/// a query segment of the form "element=10", where the right hand side of the query is stored as a type other than
|
||||
/// a string, for instance, an integral type.
|
||||
/// </summary>
|
||||
/// <param name="name">The name portion of the query string</param>
|
||||
/// <param name="value">The value portion of the query string</param>
|
||||
/// <returns>A reference to this uri_builder to support chaining.</returns>
|
||||
template<typename T>
|
||||
uri_builder& append_query(const utility::string_t& name, const T& value, bool do_encoding = true)
|
||||
{
|
||||
if (do_encoding)
|
||||
append_query_encode_impl(name, utility::conversions::details::print_utf8string(value));
|
||||
else
|
||||
append_query_no_encode_impl(name, utility::conversions::details::print_string(value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Combine and validate the URI components into a encoded string. An exception will be thrown if the URI is
|
||||
/// invalid.
|
||||
/// </summary>
|
||||
/// <returns>The created URI as a string.</returns>
|
||||
_ASYNCRTIMP utility::string_t to_string() const;
|
||||
|
||||
/// <summary>
|
||||
/// Combine and validate the URI components into a URI class instance. An exception will be thrown if the URI is
|
||||
/// invalid.
|
||||
/// </summary>
|
||||
/// <returns>The create URI as a URI class instance.</returns>
|
||||
_ASYNCRTIMP uri to_uri() const;
|
||||
|
||||
/// <summary>
|
||||
/// Validate the generated URI from all existing components of this uri_builder.
|
||||
/// </summary>
|
||||
/// <returns>Whether the URI is valid.</returns>
|
||||
_ASYNCRTIMP bool is_valid();
|
||||
|
||||
private:
|
||||
_ASYNCRTIMP void append_query_encode_impl(const utility::string_t& name, const utf8string& value);
|
||||
_ASYNCRTIMP void append_query_no_encode_impl(const utility::string_t& name, const utility::string_t& value);
|
||||
|
||||
details::uri_components m_uri;
|
||||
};
|
||||
} // namespace web
|
||||
10
deps/cpprestsdk/include/cpprest/version.h
vendored
@@ -1,10 +0,0 @@
|
||||
/***
|
||||
* Copyright (C) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
|
||||
*
|
||||
*/
|
||||
#define CPPREST_VERSION_MINOR 10
|
||||
#define CPPREST_VERSION_MAJOR 2
|
||||
#define CPPREST_VERSION_REVISION 13
|
||||
|
||||
#define CPPREST_VERSION (CPPREST_VERSION_MAJOR * 100000 + CPPREST_VERSION_MINOR * 100 + CPPREST_VERSION_REVISION)
|
||||
25
deps/cpprestsdk/license.txt
vendored
@@ -1,25 +0,0 @@
|
||||
C++ REST SDK
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
34
deps/cpprestsdk/pch.h
vendored
@@ -1,34 +0,0 @@
|
||||
#include <winrt/base.h>
|
||||
#include <Windows.h>
|
||||
#include <dxgi1_3.h>
|
||||
#include <d3d11_2.h>
|
||||
#include <d2d1_3.h>
|
||||
#include <d2d1_3helper.h>
|
||||
#include <d2d1helper.h>
|
||||
#include <dwrite.h>
|
||||
#include <dcomp.h>
|
||||
#include <dwmapi.h>
|
||||
#include <Shobjidl.h>
|
||||
#include <Shlwapi.h>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
#include <condition_variable>
|
||||
#include <stdexcept>
|
||||
#include <tuple>
|
||||
#include <unordered_set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// cpprestsdk headers
|
||||
#include "cpprest/details/basic_types.h"
|
||||
#include "cpprest/details/cpprest_compat.h"
|
||||
#include "cpprest/version.h"
|
||||
// json
|
||||
#include "cpprest/json.h"
|
||||
// utilities
|
||||
#include "cpprest/asyncrt_utils.h"
|
||||
#include "cpprest/details/web_utilities.h"
|
||||
475
deps/cpprestsdk/src/json/json.cpp
vendored
@@ -1,475 +0,0 @@
|
||||
/***
|
||||
* Copyright (C) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
|
||||
*
|
||||
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
*
|
||||
* HTTP Library: JSON parser and writer
|
||||
*
|
||||
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
|
||||
*
|
||||
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
****/
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
using namespace web;
|
||||
|
||||
bool json::details::g_keep_json_object_unsorted = false;
|
||||
void json::keep_object_element_order(bool keep_order) { json::details::g_keep_json_object_unsorted = keep_order; }
|
||||
|
||||
utility::ostream_t& web::json::operator<<(utility::ostream_t& os, const web::json::value& val)
|
||||
{
|
||||
val.serialize(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
utility::istream_t& web::json::operator>>(utility::istream_t& is, json::value& val)
|
||||
{
|
||||
val = json::value::parse(is);
|
||||
return is;
|
||||
}
|
||||
|
||||
web::json::value::value()
|
||||
: m_value(utility::details::make_unique<web::json::details::_Null>())
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
, m_kind(value::Null)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
web::json::value::value(int32_t value)
|
||||
: m_value(utility::details::make_unique<web::json::details::_Number>(value))
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
, m_kind(value::Number)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
web::json::value::value(uint32_t value)
|
||||
: m_value(utility::details::make_unique<web::json::details::_Number>(value))
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
, m_kind(value::Number)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
web::json::value::value(int64_t value)
|
||||
: m_value(utility::details::make_unique<web::json::details::_Number>(value))
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
, m_kind(value::Number)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
web::json::value::value(uint64_t value)
|
||||
: m_value(utility::details::make_unique<web::json::details::_Number>(value))
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
, m_kind(value::Number)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
web::json::value::value(double value)
|
||||
: m_value(utility::details::make_unique<web::json::details::_Number>(value))
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
, m_kind(value::Number)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
web::json::value::value(bool value)
|
||||
: m_value(utility::details::make_unique<web::json::details::_Boolean>(value))
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
, m_kind(value::Boolean)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
web::json::value::value(utility::string_t value)
|
||||
: m_value(utility::details::make_unique<web::json::details::_String>(std::move(value)))
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
, m_kind(value::String)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
web::json::value::value(utility::string_t value, bool has_escape_chars)
|
||||
: m_value(utility::details::make_unique<web::json::details::_String>(std::move(value), has_escape_chars))
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
, m_kind(value::String)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
web::json::value::value(const utility::char_t* value)
|
||||
: m_value(utility::details::make_unique<web::json::details::_String>(value))
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
, m_kind(value::String)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
web::json::value::value(const utility::char_t* value, bool has_escape_chars)
|
||||
: m_value(utility::details::make_unique<web::json::details::_String>(utility::string_t(value), has_escape_chars))
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
, m_kind(value::String)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
web::json::value::value(const value& other)
|
||||
: m_value(other.m_value->_copy_value())
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
, m_kind(other.m_kind)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
web::json::value& web::json::value::operator=(const value& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
m_value = std::unique_ptr<details::_Value>(other.m_value->_copy_value());
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
m_kind = other.m_kind;
|
||||
#endif
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
web::json::value::value(value&& other) CPPREST_NOEXCEPT : m_value(std::move(other.m_value))
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
,
|
||||
m_kind(other.m_kind)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
web::json::value& web::json::value::operator=(web::json::value&& other) CPPREST_NOEXCEPT
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
m_value.swap(other.m_value);
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
m_kind = other.m_kind;
|
||||
#endif
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
web::json::value web::json::value::null() { return web::json::value(); }
|
||||
|
||||
web::json::value web::json::value::number(double value) { return web::json::value(value); }
|
||||
|
||||
web::json::value web::json::value::number(int32_t value) { return web::json::value(value); }
|
||||
|
||||
web::json::value web::json::value::number(uint32_t value) { return web::json::value(value); }
|
||||
|
||||
web::json::value web::json::value::number(int64_t value) { return web::json::value(value); }
|
||||
|
||||
web::json::value web::json::value::number(uint64_t value) { return web::json::value(value); }
|
||||
|
||||
web::json::value web::json::value::boolean(bool value) { return web::json::value(value); }
|
||||
|
||||
web::json::value web::json::value::string(utility::string_t value)
|
||||
{
|
||||
std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_String>(std::move(value));
|
||||
return web::json::value(std::move(ptr)
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
,
|
||||
value::String
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
web::json::value web::json::value::string(utility::string_t value, bool has_escape_chars)
|
||||
{
|
||||
std::unique_ptr<details::_Value> ptr =
|
||||
utility::details::make_unique<details::_String>(std::move(value), has_escape_chars);
|
||||
return web::json::value(std::move(ptr)
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
,
|
||||
value::String
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
web::json::value web::json::value::string(const std::string& value)
|
||||
{
|
||||
std::unique_ptr<details::_Value> ptr =
|
||||
utility::details::make_unique<details::_String>(utility::conversions::to_utf16string(value));
|
||||
return web::json::value(std::move(ptr)
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
,
|
||||
value::String
|
||||
#endif
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
web::json::value web::json::value::object(bool keep_order)
|
||||
{
|
||||
std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_Object>(keep_order);
|
||||
return web::json::value(std::move(ptr)
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
,
|
||||
value::Object
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
web::json::value web::json::value::object(std::vector<std::pair<::utility::string_t, value>> fields, bool keep_order)
|
||||
{
|
||||
std::unique_ptr<details::_Value> ptr =
|
||||
utility::details::make_unique<details::_Object>(std::move(fields), keep_order);
|
||||
return web::json::value(std::move(ptr)
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
,
|
||||
value::Object
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
web::json::value web::json::value::array()
|
||||
{
|
||||
std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_Array>();
|
||||
return web::json::value(std::move(ptr)
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
,
|
||||
value::Array
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
web::json::value web::json::value::array(size_t size)
|
||||
{
|
||||
std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_Array>(size);
|
||||
return web::json::value(std::move(ptr)
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
,
|
||||
value::Array
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
web::json::value web::json::value::array(std::vector<value> elements)
|
||||
{
|
||||
std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_Array>(std::move(elements));
|
||||
return web::json::value(std::move(ptr)
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
,
|
||||
value::Array
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
const web::json::number& web::json::value::as_number() const { return m_value->as_number(); }
|
||||
|
||||
double web::json::value::as_double() const { return m_value->as_double(); }
|
||||
|
||||
int web::json::value::as_integer() const { return m_value->as_integer(); }
|
||||
|
||||
bool web::json::value::as_bool() const { return m_value->as_bool(); }
|
||||
|
||||
json::array& web::json::value::as_array() { return m_value->as_array(); }
|
||||
|
||||
const json::array& web::json::value::as_array() const { return m_value->as_array(); }
|
||||
|
||||
json::object& web::json::value::as_object() { return m_value->as_object(); }
|
||||
|
||||
const json::object& web::json::value::as_object() const { return m_value->as_object(); }
|
||||
|
||||
bool web::json::number::is_int32() const
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case signed_type:
|
||||
return m_intval >= (std::numeric_limits<int32_t>::min)() && m_intval <= (std::numeric_limits<int32_t>::max)();
|
||||
case unsigned_type: return m_uintval <= (std::numeric_limits<int32_t>::max)();
|
||||
case double_type:
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool web::json::number::is_uint32() const
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case signed_type: return m_intval >= 0 && m_intval <= (std::numeric_limits<uint32_t>::max)();
|
||||
case unsigned_type: return m_uintval <= (std::numeric_limits<uint32_t>::max)();
|
||||
case double_type:
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool web::json::number::is_int64() const
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case signed_type: return true;
|
||||
case unsigned_type: return m_uintval <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)());
|
||||
case double_type:
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool web::json::details::_String::has_escape_chars(const _String& str)
|
||||
{
|
||||
return std::any_of(std::begin(str.m_string), std::end(str.m_string), [](utility::string_t::value_type const x) {
|
||||
if (x <= 31)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (x == '"')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (x == '\\')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
web::json::value::value_type json::value::type() const { return m_value->type(); }
|
||||
|
||||
bool json::value::is_integer() const
|
||||
{
|
||||
if (!is_number())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return m_value->is_integer();
|
||||
}
|
||||
|
||||
bool json::value::is_double() const
|
||||
{
|
||||
if (!is_number())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return m_value->is_double();
|
||||
}
|
||||
|
||||
json::value& web::json::details::_Object::index(const utility::string_t& key) { return m_object[key]; }
|
||||
|
||||
bool web::json::details::_Object::has_field(const utility::string_t& key) const
|
||||
{
|
||||
return m_object.find(key) != m_object.end();
|
||||
}
|
||||
|
||||
bool web::json::value::has_number_field(const utility::string_t& key) const
|
||||
{
|
||||
return has_field(key) && at(key).is_number();
|
||||
}
|
||||
|
||||
bool web::json::value::has_integer_field(const utility::string_t& key) const
|
||||
{
|
||||
return has_field(key) && at(key).is_integer();
|
||||
}
|
||||
|
||||
bool web::json::value::has_double_field(const utility::string_t& key) const
|
||||
{
|
||||
return has_field(key) && at(key).is_double();
|
||||
}
|
||||
|
||||
bool web::json::value::has_boolean_field(const utility::string_t& key) const
|
||||
{
|
||||
return has_field(key) && at(key).is_boolean();
|
||||
}
|
||||
|
||||
bool web::json::value::has_string_field(const utility::string_t& key) const
|
||||
{
|
||||
return has_field(key) && at(key).is_string();
|
||||
}
|
||||
|
||||
bool web::json::value::has_array_field(const utility::string_t& key) const
|
||||
{
|
||||
return has_field(key) && at(key).is_array();
|
||||
}
|
||||
|
||||
bool web::json::value::has_object_field(const utility::string_t& key) const
|
||||
{
|
||||
return has_field(key) && at(key).is_object();
|
||||
}
|
||||
|
||||
utility::string_t json::value::to_string() const
|
||||
{
|
||||
#ifndef _WIN32
|
||||
utility::details::scoped_c_thread_locale locale;
|
||||
#endif
|
||||
return m_value->to_string();
|
||||
}
|
||||
|
||||
bool json::value::operator==(const json::value& other) const
|
||||
{
|
||||
if (this->m_value.get() == other.m_value.get()) return true;
|
||||
if (this->type() != other.type()) return false;
|
||||
|
||||
switch (this->type())
|
||||
{
|
||||
case Null: return true;
|
||||
case Number: return this->as_number() == other.as_number();
|
||||
case Boolean: return this->as_bool() == other.as_bool();
|
||||
case String: return this->as_string() == other.as_string();
|
||||
case Object:
|
||||
return static_cast<const json::details::_Object*>(this->m_value.get())
|
||||
->is_equal(static_cast<const json::details::_Object*>(other.m_value.get()));
|
||||
case Array:
|
||||
return static_cast<const json::details::_Array*>(this->m_value.get())
|
||||
->is_equal(static_cast<const json::details::_Array*>(other.m_value.get()));
|
||||
}
|
||||
__assume(0);
|
||||
}
|
||||
|
||||
void web::json::value::erase(size_t index) { return this->as_array().erase(index); }
|
||||
|
||||
void web::json::value::erase(const utility::string_t& key) { return this->as_object().erase(key); }
|
||||
|
||||
// at() overloads
|
||||
web::json::value& web::json::value::at(size_t index) { return this->as_array().at(index); }
|
||||
|
||||
const web::json::value& web::json::value::at(size_t index) const { return this->as_array().at(index); }
|
||||
|
||||
web::json::value& web::json::value::at(const utility::string_t& key) { return this->as_object().at(key); }
|
||||
|
||||
const web::json::value& web::json::value::at(const utility::string_t& key) const { return this->as_object().at(key); }
|
||||
|
||||
web::json::value& web::json::value::operator[](const utility::string_t& key)
|
||||
{
|
||||
if (this->is_null())
|
||||
{
|
||||
m_value.reset(new web::json::details::_Object(details::g_keep_json_object_unsorted));
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
m_kind = value::Object;
|
||||
#endif
|
||||
}
|
||||
return m_value->index(key);
|
||||
}
|
||||
|
||||
web::json::value& web::json::value::operator[](size_t index)
|
||||
{
|
||||
if (this->is_null())
|
||||
{
|
||||
m_value.reset(new web::json::details::_Array());
|
||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
|
||||
m_kind = value::Array;
|
||||
#endif
|
||||
}
|
||||
return m_value->index(index);
|
||||
}
|
||||
|
||||
// Remove once VS 2013 is no longer supported.
|
||||
#if defined(_WIN32) && _MSC_VER < 1900
|
||||
static web::json::details::json_error_category_impl instance;
|
||||
#endif
|
||||
const web::json::details::json_error_category_impl& web::json::details::json_error_category()
|
||||
{
|
||||
#if !defined(_WIN32) || _MSC_VER >= 1900
|
||||
static web::json::details::json_error_category_impl instance;
|
||||
#endif
|
||||
return instance;
|
||||
}
|
||||
1279
deps/cpprestsdk/src/json/json_parsing.cpp
vendored
254
deps/cpprestsdk/src/json/json_serialization.cpp
vendored
@@ -1,254 +0,0 @@
|
||||
/***
|
||||
* Copyright (C) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
|
||||
*
|
||||
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
*
|
||||
* HTTP Library: JSON parser and writer
|
||||
*
|
||||
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
|
||||
*
|
||||
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
****/
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
using namespace web;
|
||||
using namespace web::json;
|
||||
using namespace utility;
|
||||
using namespace utility::conversions;
|
||||
|
||||
//
|
||||
// JSON Serialization
|
||||
//
|
||||
|
||||
#ifdef _WIN32
|
||||
void web::json::value::serialize(std::ostream& stream) const
|
||||
{
|
||||
// This has better performance than writing directly to stream.
|
||||
std::string str;
|
||||
m_value->serialize_impl(str);
|
||||
stream << str;
|
||||
}
|
||||
void web::json::value::format(std::basic_string<wchar_t>& string) const { m_value->format(string); }
|
||||
#endif
|
||||
|
||||
void web::json::value::serialize(utility::ostream_t& stream) const
|
||||
{
|
||||
#ifndef _WIN32
|
||||
utility::details::scoped_c_thread_locale locale;
|
||||
#endif
|
||||
|
||||
// This has better performance than writing directly to stream.
|
||||
utility::string_t str;
|
||||
m_value->serialize_impl(str);
|
||||
stream << str;
|
||||
}
|
||||
|
||||
void web::json::value::format(std::basic_string<char>& string) const { m_value->format(string); }
|
||||
|
||||
template<typename CharType>
|
||||
void web::json::details::append_escape_string(std::basic_string<CharType>& str,
|
||||
const std::basic_string<CharType>& escaped)
|
||||
{
|
||||
for (const auto& ch : escaped)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case '\"':
|
||||
str += '\\';
|
||||
str += '\"';
|
||||
break;
|
||||
case '\\':
|
||||
str += '\\';
|
||||
str += '\\';
|
||||
break;
|
||||
case '\b':
|
||||
str += '\\';
|
||||
str += 'b';
|
||||
break;
|
||||
case '\f':
|
||||
str += '\\';
|
||||
str += 'f';
|
||||
break;
|
||||
case '\r':
|
||||
str += '\\';
|
||||
str += 'r';
|
||||
break;
|
||||
case '\n':
|
||||
str += '\\';
|
||||
str += 'n';
|
||||
break;
|
||||
case '\t':
|
||||
str += '\\';
|
||||
str += 't';
|
||||
break;
|
||||
default:
|
||||
|
||||
// If a control character then must unicode escaped.
|
||||
if (ch >= 0 && ch <= 0x1F)
|
||||
{
|
||||
static const std::array<CharType, 16> intToHex = {
|
||||
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}};
|
||||
str += '\\';
|
||||
str += 'u';
|
||||
str += '0';
|
||||
str += '0';
|
||||
str += intToHex[(ch & 0xF0) >> 4];
|
||||
str += intToHex[ch & 0x0F];
|
||||
}
|
||||
else
|
||||
{
|
||||
str += ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void web::json::details::format_string(const utility::string_t& key, utility::string_t& str)
|
||||
{
|
||||
str.push_back('"');
|
||||
append_escape_string(str, key);
|
||||
str.push_back('"');
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void web::json::details::format_string(const utility::string_t& key, std::string& str)
|
||||
{
|
||||
str.push_back('"');
|
||||
append_escape_string(str, utility::conversions::to_utf8string(key));
|
||||
str.push_back('"');
|
||||
}
|
||||
#endif
|
||||
|
||||
void web::json::details::_String::format(std::basic_string<char>& str) const
|
||||
{
|
||||
str.push_back('"');
|
||||
|
||||
if (m_has_escape_char)
|
||||
{
|
||||
append_escape_string(str, utility::conversions::to_utf8string(m_string));
|
||||
}
|
||||
else
|
||||
{
|
||||
str.append(utility::conversions::to_utf8string(m_string));
|
||||
}
|
||||
|
||||
str.push_back('"');
|
||||
}
|
||||
|
||||
void web::json::details::_Number::format(std::basic_string<char>& stream) const
|
||||
{
|
||||
if (m_number.m_type != number::type::double_type)
|
||||
{
|
||||
// #digits + 1 to avoid loss + 1 for the sign + 1 for null terminator.
|
||||
const size_t tempSize = std::numeric_limits<uint64_t>::digits10 + 3;
|
||||
char tempBuffer[tempSize];
|
||||
|
||||
#ifdef _WIN32
|
||||
// This can be improved performance-wise if we implement our own routine
|
||||
if (m_number.m_type == number::type::signed_type)
|
||||
_i64toa_s(m_number.m_intval, tempBuffer, tempSize, 10);
|
||||
else
|
||||
_ui64toa_s(m_number.m_uintval, tempBuffer, tempSize, 10);
|
||||
|
||||
const auto numChars = strnlen_s(tempBuffer, tempSize);
|
||||
#else
|
||||
int numChars;
|
||||
if (m_number.m_type == number::type::signed_type)
|
||||
numChars = snprintf(tempBuffer, tempSize, "%" PRId64, m_number.m_intval);
|
||||
else
|
||||
numChars = snprintf(tempBuffer, tempSize, "%" PRIu64, m_number.m_uintval);
|
||||
#endif
|
||||
stream.append(tempBuffer, numChars);
|
||||
}
|
||||
else
|
||||
{
|
||||
// #digits + 2 to avoid loss + 1 for the sign + 1 for decimal point + 5 for exponent (e+xxx) + 1 for null
|
||||
// terminator
|
||||
const size_t tempSize = std::numeric_limits<double>::digits10 + 10;
|
||||
char tempBuffer[tempSize];
|
||||
#ifdef _WIN32
|
||||
const auto numChars = _sprintf_s_l(tempBuffer,
|
||||
tempSize,
|
||||
"%.*g",
|
||||
utility::details::scoped_c_thread_locale::c_locale(),
|
||||
std::numeric_limits<double>::digits10 + 2,
|
||||
m_number.m_value);
|
||||
#else
|
||||
const auto numChars =
|
||||
snprintf(tempBuffer, tempSize, "%.*g", std::numeric_limits<double>::digits10 + 2, m_number.m_value);
|
||||
#endif
|
||||
stream.append(tempBuffer, numChars);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
void web::json::details::_String::format(std::basic_string<wchar_t>& str) const
|
||||
{
|
||||
str.push_back(L'"');
|
||||
|
||||
if (m_has_escape_char)
|
||||
{
|
||||
append_escape_string(str, m_string);
|
||||
}
|
||||
else
|
||||
{
|
||||
str.append(m_string);
|
||||
}
|
||||
|
||||
str.push_back(L'"');
|
||||
}
|
||||
|
||||
void web::json::details::_Number::format(std::basic_string<wchar_t>& stream) const
|
||||
{
|
||||
if (m_number.m_type != number::type::double_type)
|
||||
{
|
||||
// #digits + 1 to avoid loss + 1 for the sign + 1 for null terminator.
|
||||
const size_t tempSize = std::numeric_limits<uint64_t>::digits10 + 3;
|
||||
wchar_t tempBuffer[tempSize];
|
||||
|
||||
if (m_number.m_type == number::type::signed_type)
|
||||
_i64tow_s(m_number.m_intval, tempBuffer, tempSize, 10);
|
||||
else
|
||||
_ui64tow_s(m_number.m_uintval, tempBuffer, tempSize, 10);
|
||||
|
||||
stream.append(tempBuffer, wcsnlen_s(tempBuffer, tempSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
// #digits + 2 to avoid loss + 1 for the sign + 1 for decimal point + 5 for exponent (e+xxx) + 1 for null
|
||||
// terminator
|
||||
const size_t tempSize = std::numeric_limits<double>::digits10 + 10;
|
||||
wchar_t tempBuffer[tempSize];
|
||||
const int numChars = _swprintf_s_l(tempBuffer,
|
||||
tempSize,
|
||||
L"%.*g",
|
||||
utility::details::scoped_c_thread_locale::c_locale(),
|
||||
std::numeric_limits<double>::digits10 + 2,
|
||||
m_number.m_value);
|
||||
stream.append(tempBuffer, numChars);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const utility::string_t& web::json::details::_String::as_string() const { return m_string; }
|
||||
|
||||
const utility::string_t& web::json::value::as_string() const { return m_value->as_string(); }
|
||||
|
||||
utility::string_t json::value::serialize() const
|
||||
{
|
||||
#ifndef _WIN32
|
||||
utility::details::scoped_c_thread_locale locale;
|
||||
#endif
|
||||
return m_value->to_string();
|
||||
}
|
||||
1490
deps/cpprestsdk/src/utilities/asyncrt_utils.cpp
vendored
260
deps/cpprestsdk/src/utilities/base64.cpp
vendored
@@ -1,260 +0,0 @@
|
||||
/***
|
||||
* Copyright (C) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
|
||||
*
|
||||
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
*
|
||||
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
|
||||
*
|
||||
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
****/
|
||||
#include "pch.h"
|
||||
|
||||
using namespace web;
|
||||
using namespace utility;
|
||||
|
||||
std::vector<unsigned char> _from_base64(const utility::string_t& str);
|
||||
utility::string_t _to_base64(const unsigned char* ptr, size_t size);
|
||||
|
||||
std::vector<unsigned char> __cdecl conversions::from_base64(const utility::string_t& str) { return _from_base64(str); }
|
||||
|
||||
utility::string_t __cdecl conversions::to_base64(const std::vector<unsigned char>& input)
|
||||
{
|
||||
if (input.size() == 0)
|
||||
{
|
||||
// return empty string
|
||||
return utility::string_t();
|
||||
}
|
||||
|
||||
return _to_base64(&input[0], input.size());
|
||||
}
|
||||
|
||||
utility::string_t __cdecl conversions::to_base64(uint64_t input)
|
||||
{
|
||||
return _to_base64(reinterpret_cast<const unsigned char*>(&input), sizeof(input));
|
||||
}
|
||||
|
||||
static const char* _base64_enctbl = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
const std::array<unsigned char, 128> _base64_dectbl = {
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62,
|
||||
255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 254, 255, 255, 255, 0,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
|
||||
23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
|
||||
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255}};
|
||||
|
||||
struct _triple_byte
|
||||
{
|
||||
unsigned char _1_1 : 2;
|
||||
unsigned char _0 : 6;
|
||||
unsigned char _2_1 : 4;
|
||||
unsigned char _1_2 : 4;
|
||||
unsigned char _3 : 6;
|
||||
unsigned char _2_2 : 2;
|
||||
};
|
||||
|
||||
struct _double_byte
|
||||
{
|
||||
unsigned char _1_1 : 2;
|
||||
unsigned char _0 : 6;
|
||||
unsigned char _2_1 : 4;
|
||||
unsigned char _1_2 : 4;
|
||||
};
|
||||
|
||||
struct _single_byte
|
||||
{
|
||||
unsigned char _1_1 : 2;
|
||||
unsigned char _0 : 6;
|
||||
};
|
||||
|
||||
//
|
||||
// A note on the implementation of BASE64 encoding and decoding:
|
||||
//
|
||||
// This is a fairly basic and naive implementation; there is probably a lot of room for
|
||||
// performance improvement, as well as for adding options such as support for URI-safe base64,
|
||||
// ignoring CRLF, relaxed validation rules, etc. The decoder is currently pretty strict.
|
||||
//
|
||||
|
||||
#ifdef __GNUC__
|
||||
// gcc is concerned about the bitfield uses in the code, something we simply need to ignore.
|
||||
#pragma GCC diagnostic ignored "-Wconversion"
|
||||
#endif
|
||||
std::vector<unsigned char> _from_base64(const utility::string_t& input)
|
||||
{
|
||||
std::vector<unsigned char> result;
|
||||
|
||||
if (input.empty()) return result;
|
||||
|
||||
size_t padding = 0;
|
||||
|
||||
// Validation
|
||||
{
|
||||
auto size = input.size();
|
||||
|
||||
if ((size % 4) != 0)
|
||||
{
|
||||
throw std::runtime_error("length of base64 string is not an even multiple of 4");
|
||||
}
|
||||
|
||||
for (auto iter = input.begin(); iter != input.end(); ++iter, --size)
|
||||
{
|
||||
const size_t ch_sz = static_cast<size_t>(*iter);
|
||||
if (ch_sz >= _base64_dectbl.size() || _base64_dectbl[ch_sz] == 255)
|
||||
{
|
||||
throw std::runtime_error("invalid character found in base64 string");
|
||||
}
|
||||
if (_base64_dectbl[ch_sz] == 254)
|
||||
{
|
||||
padding++;
|
||||
// padding only at the end
|
||||
if (size > 2)
|
||||
{
|
||||
throw std::runtime_error("invalid padding character found in base64 string");
|
||||
}
|
||||
if (size == 2)
|
||||
{
|
||||
const size_t ch2_sz = static_cast<size_t>(*(iter + 1));
|
||||
if (ch2_sz >= _base64_dectbl.size() || _base64_dectbl[ch2_sz] != 254)
|
||||
{
|
||||
throw std::runtime_error("invalid padding character found in base64 string");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto size = input.size();
|
||||
const char_t* ptr = &input[0];
|
||||
|
||||
auto outsz = (size / 4) * 3;
|
||||
outsz -= padding;
|
||||
|
||||
result.resize(outsz);
|
||||
|
||||
size_t idx = 0;
|
||||
for (; size > 4; ++idx)
|
||||
{
|
||||
unsigned char target[3];
|
||||
memset(target, 0, sizeof(target));
|
||||
_triple_byte* record = reinterpret_cast<_triple_byte*>(target);
|
||||
|
||||
unsigned char val0 = _base64_dectbl[ptr[0]];
|
||||
unsigned char val1 = _base64_dectbl[ptr[1]];
|
||||
unsigned char val2 = _base64_dectbl[ptr[2]];
|
||||
unsigned char val3 = _base64_dectbl[ptr[3]];
|
||||
|
||||
record->_0 = val0;
|
||||
record->_1_1 = val1 >> 4;
|
||||
result[idx] = target[0];
|
||||
|
||||
record->_1_2 = val1 & 0xF;
|
||||
record->_2_1 = val2 >> 2;
|
||||
result[++idx] = target[1];
|
||||
|
||||
record->_2_2 = val2 & 0x3;
|
||||
record->_3 = val3 & 0x3F;
|
||||
result[++idx] = target[2];
|
||||
|
||||
ptr += 4;
|
||||
size -= 4;
|
||||
}
|
||||
|
||||
// Handle the last four bytes separately, to avoid having the conditional statements
|
||||
// in all the iterations (a performance issue).
|
||||
|
||||
{
|
||||
unsigned char target[3];
|
||||
memset(target, 0, sizeof(target));
|
||||
_triple_byte* record = reinterpret_cast<_triple_byte*>(target);
|
||||
|
||||
unsigned char val0 = _base64_dectbl[ptr[0]];
|
||||
unsigned char val1 = _base64_dectbl[ptr[1]];
|
||||
unsigned char val2 = _base64_dectbl[ptr[2]];
|
||||
unsigned char val3 = _base64_dectbl[ptr[3]];
|
||||
|
||||
record->_0 = val0;
|
||||
record->_1_1 = val1 >> 4;
|
||||
result[idx] = target[0];
|
||||
|
||||
record->_1_2 = val1 & 0xF;
|
||||
if (val2 != 254)
|
||||
{
|
||||
record->_2_1 = val2 >> 2;
|
||||
result[++idx] = target[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// There shouldn't be any information (ones) in the unused bits,
|
||||
if (record->_1_2 != 0)
|
||||
{
|
||||
throw std::runtime_error("Invalid end of base64 string");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
record->_2_2 = val2 & 0x3;
|
||||
if (val3 != 254)
|
||||
{
|
||||
record->_3 = val3 & 0x3F;
|
||||
result[++idx] = target[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
// There shouldn't be any information (ones) in the unused bits.
|
||||
if (record->_2_2 != 0)
|
||||
{
|
||||
throw std::runtime_error("Invalid end of base64 string");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
utility::string_t _to_base64(const unsigned char* ptr, size_t size)
|
||||
{
|
||||
utility::string_t result;
|
||||
|
||||
for (; size >= 3;)
|
||||
{
|
||||
const _triple_byte* record = reinterpret_cast<const _triple_byte*>(ptr);
|
||||
unsigned char idx0 = record->_0;
|
||||
unsigned char idx1 = (record->_1_1 << 4) | record->_1_2;
|
||||
unsigned char idx2 = (record->_2_1 << 2) | record->_2_2;
|
||||
unsigned char idx3 = record->_3;
|
||||
result.push_back(char_t(_base64_enctbl[idx0]));
|
||||
result.push_back(char_t(_base64_enctbl[idx1]));
|
||||
result.push_back(char_t(_base64_enctbl[idx2]));
|
||||
result.push_back(char_t(_base64_enctbl[idx3]));
|
||||
size -= 3;
|
||||
ptr += 3;
|
||||
}
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
const _single_byte* record = reinterpret_cast<const _single_byte*>(ptr);
|
||||
unsigned char idx0 = record->_0;
|
||||
unsigned char idx1 = (record->_1_1 << 4);
|
||||
result.push_back(char_t(_base64_enctbl[idx0]));
|
||||
result.push_back(char_t(_base64_enctbl[idx1]));
|
||||
result.push_back('=');
|
||||
result.push_back('=');
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
const _double_byte* record = reinterpret_cast<const _double_byte*>(ptr);
|
||||
unsigned char idx0 = record->_0;
|
||||
unsigned char idx1 = (record->_1_1 << 4) | record->_1_2;
|
||||
unsigned char idx2 = (record->_2_1 << 2);
|
||||
result.push_back(char_t(_base64_enctbl[idx0]));
|
||||
result.push_back(char_t(_base64_enctbl[idx1]));
|
||||
result.push_back(char_t(_base64_enctbl[idx2]));
|
||||
result.push_back('=');
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
157
deps/cpprestsdk/src/utilities/web_utilities.cpp
vendored
@@ -1,157 +0,0 @@
|
||||
/***
|
||||
* Copyright (C) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
|
||||
*
|
||||
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
*
|
||||
* Credential and proxy utilities.
|
||||
*
|
||||
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
|
||||
*
|
||||
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
****/
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(__cplusplus_winrt)
|
||||
#include <Wincrypt.h>
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus_winrt)
|
||||
#include <robuffer.h>
|
||||
#endif
|
||||
|
||||
namespace web
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
#if defined(_WIN32) && !defined(CPPREST_TARGET_XP)
|
||||
#if defined(__cplusplus_winrt)
|
||||
|
||||
// Helper function to zero out memory of an IBuffer.
|
||||
void winrt_secure_zero_buffer(Windows::Storage::Streams::IBuffer ^ buffer)
|
||||
{
|
||||
Microsoft::WRL::ComPtr<IInspectable> bufferInspectable(reinterpret_cast<IInspectable*>(buffer));
|
||||
Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
|
||||
bufferInspectable.As(&bufferByteAccess);
|
||||
|
||||
// This shouldn't happen but if can't get access to the raw bytes for some reason
|
||||
// then we can't zero out.
|
||||
byte* rawBytes;
|
||||
if (bufferByteAccess->Buffer(&rawBytes) == S_OK)
|
||||
{
|
||||
SecureZeroMemory(rawBytes, buffer->Length);
|
||||
}
|
||||
}
|
||||
|
||||
winrt_encryption::winrt_encryption(const std::wstring& data)
|
||||
{
|
||||
auto provider = ref new Windows::Security::Cryptography::DataProtection::DataProtectionProvider(
|
||||
ref new Platform::String(L"Local=user"));
|
||||
|
||||
// Create buffer containing plain text password.
|
||||
Platform::ArrayReference<unsigned char> arrayref(
|
||||
reinterpret_cast<unsigned char*>(const_cast<std::wstring::value_type*>(data.c_str())),
|
||||
static_cast<unsigned int>(data.size()) * sizeof(std::wstring::value_type));
|
||||
Windows::Storage::Streams::IBuffer ^ plaintext =
|
||||
Windows::Security::Cryptography::CryptographicBuffer::CreateFromByteArray(arrayref);
|
||||
m_buffer = pplx::create_task(provider->ProtectAsync(plaintext));
|
||||
m_buffer.then(
|
||||
[plaintext](pplx::task<Windows::Storage::Streams::IBuffer ^>) { winrt_secure_zero_buffer(plaintext); });
|
||||
}
|
||||
|
||||
plaintext_string winrt_encryption::decrypt() const
|
||||
{
|
||||
// To fully guarantee asynchrony would require significant impact on existing code. This code path
|
||||
// is never run on a user's thread and is only done once when setting up a connection.
|
||||
auto encrypted = m_buffer.get();
|
||||
auto provider = ref new Windows::Security::Cryptography::DataProtection::DataProtectionProvider();
|
||||
auto plaintext = pplx::create_task(provider->UnprotectAsync(encrypted)).get();
|
||||
|
||||
// Get access to raw bytes in plain text buffer.
|
||||
Microsoft::WRL::ComPtr<IInspectable> bufferInspectable(reinterpret_cast<IInspectable*>(plaintext));
|
||||
Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
|
||||
bufferInspectable.As(&bufferByteAccess);
|
||||
byte* rawPlaintext;
|
||||
const auto& result = bufferByteAccess->Buffer(&rawPlaintext);
|
||||
if (result != S_OK)
|
||||
{
|
||||
throw ::utility::details::create_system_error(result);
|
||||
}
|
||||
|
||||
// Construct string and zero out memory from plain text buffer.
|
||||
auto data = plaintext_string(
|
||||
new std::wstring(reinterpret_cast<const std::wstring::value_type*>(rawPlaintext), plaintext->Length / 2));
|
||||
SecureZeroMemory(rawPlaintext, plaintext->Length);
|
||||
return std::move(data);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
win32_encryption::win32_encryption(const std::wstring& data) : m_numCharacters(data.size())
|
||||
{
|
||||
// Early return because CryptProtectMemory crashes with empty string
|
||||
if (m_numCharacters == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.size() > (std::numeric_limits<DWORD>::max)() / sizeof(wchar_t))
|
||||
{
|
||||
throw std::length_error("Encryption string too long");
|
||||
}
|
||||
|
||||
const auto dataSizeDword = static_cast<DWORD>(data.size() * sizeof(wchar_t));
|
||||
|
||||
// Round up dataSizeDword to be a multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE
|
||||
static_assert(CRYPTPROTECTMEMORY_BLOCK_SIZE == 16, "Power of 2 assumptions in this bit masking violated");
|
||||
const auto mask = static_cast<DWORD>(CRYPTPROTECTMEMORY_BLOCK_SIZE - 1u);
|
||||
const auto dataNumBytes = (dataSizeDword & ~mask) + ((dataSizeDword & mask) != 0) * CRYPTPROTECTMEMORY_BLOCK_SIZE;
|
||||
assert((dataNumBytes % CRYPTPROTECTMEMORY_BLOCK_SIZE) == 0);
|
||||
assert(dataNumBytes >= dataSizeDword);
|
||||
m_buffer.resize(dataNumBytes);
|
||||
memcpy_s(m_buffer.data(), m_buffer.size(), data.c_str(), dataNumBytes);
|
||||
if (!CryptProtectMemory(m_buffer.data(), dataNumBytes, CRYPTPROTECTMEMORY_SAME_PROCESS))
|
||||
{
|
||||
throw ::utility::details::create_system_error(GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
win32_encryption::~win32_encryption() { SecureZeroMemory(m_buffer.data(), m_buffer.size()); }
|
||||
|
||||
plaintext_string win32_encryption::decrypt() const
|
||||
{
|
||||
// Copy the buffer and decrypt to avoid having to re-encrypt.
|
||||
auto result = plaintext_string(new std::wstring(reinterpret_cast<const std::wstring::value_type*>(m_buffer.data()),
|
||||
m_buffer.size() / sizeof(wchar_t)));
|
||||
auto& data = *result;
|
||||
if (!m_buffer.empty())
|
||||
{
|
||||
if (!CryptUnprotectMemory(&data[0], static_cast<DWORD>(m_buffer.size()), CRYPTPROTECTMEMORY_SAME_PROCESS))
|
||||
{
|
||||
throw ::utility::details::create_system_error(GetLastError());
|
||||
}
|
||||
|
||||
assert(m_numCharacters <= m_buffer.size());
|
||||
SecureZeroMemory(&data[m_numCharacters], data.size() - m_numCharacters);
|
||||
data.erase(m_numCharacters);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void zero_memory_deleter::operator()(::utility::string_t* data) const
|
||||
{
|
||||
CASABLANCA_UNREFERENCED_PARAMETER(data);
|
||||
#if defined(_WIN32)
|
||||
SecureZeroMemory(&(*data)[0], data->size() * sizeof(::utility::string_t::value_type));
|
||||
delete data;
|
||||
#endif
|
||||
}
|
||||
} // namespace details
|
||||
|
||||
} // namespace web
|
||||
@@ -1,26 +0,0 @@
|
||||
# Code Organization
|
||||
|
||||
## Rules
|
||||
|
||||
- **Follow the pattern of what you already see in the code**
|
||||
- Try to package new ideas/components into libraries that have nicely defined interfaces
|
||||
- Package new ideas into classes or refactor existing ideas into a class as you extend
|
||||
|
||||
## Code Overview
|
||||
|
||||
General project organization:
|
||||
|
||||
#### The [`deps`](/deps) folder
|
||||
Contains other projects that PowerToys uses as dependencies.
|
||||
|
||||
#### The [`doc`](/doc) folder
|
||||
Documentation for the project, including a [coding guide](/doc/coding) and [design docs](/doc/specs).
|
||||
|
||||
#### The [`installer`](/installer) folder
|
||||
Contains the source code of the PowerToys installer.
|
||||
|
||||
#### The [`src`](/src) folder
|
||||
Contains the source code of the PowerToys runner and of all of the PowerToys modules. **This is where the most of the magic happens.**
|
||||
|
||||
#### The [`tools`](/tools) folder
|
||||
Various tools used by PowerToys. Includes the Visual Studio 2019 project template for new PowerToys.
|
||||
@@ -1,5 +0,0 @@
|
||||
# Coding Style
|
||||
|
||||
## Philosophy
|
||||
1. If it's inserting something into the existing classes/functions, try to follow the existing style as closely as possible.
|
||||
1. If it's brand new code or refactoring a complete class or area of the code, please follow as Modern C++ of a style as you can and reference the [C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines) as much as you possibly can.
|
||||
109
doc/devdocs/common.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# Classes and structures
|
||||
|
||||
#### class Animation: [header](/src/common/animation.h) [source](/src/common/animation.cpp)
|
||||
Animation helper class with two easing-in animations: linear and exponential.
|
||||
|
||||
#### class AsyncMessageQueue: [header](/src/common/async_message_queue.h)
|
||||
Header-only asynchronous message queue. Used by `TwoWayPipeMessageIPC`.
|
||||
|
||||
#### class TwoWayPipeMessageIPC: [header](/src/common/two_way_pipe_message_ipc.h)
|
||||
Header-only asynchronous IPC messaging class. Used by the runner to communicate with the settings window.
|
||||
|
||||
#### class D2DSVG: [header](/src/common/d2d_svg.h) [source](/src/common/d2d_svg.cpp)
|
||||
Class for loading, rendering and for some basic modifications of SVG graphics.
|
||||
|
||||
#### class D2DText: [header](/src/common/d2d_text.h) [source](/src/common/d2d_text.cpp)
|
||||
Class for rendering text using DirectX.
|
||||
|
||||
#### class D2DWindow: [header](/src/common/d2d_window.h) [source](/src/common/d2d_window.cpp)
|
||||
Base class for creating borderless windows, with DirectX enabled rendering pipeline.
|
||||
|
||||
#### class DPIAware: [header](/src/common/dpi_aware.h) [source](/src/common/dpi_aware.cpp)
|
||||
Helper class for creating DPI-aware applications.
|
||||
|
||||
#### struct MonitorInfo: [header](/src/common/monitors.h) [source](/src/common/monitors.cpp)
|
||||
Class for obtaining information about physical displays connected to the machine.
|
||||
|
||||
#### class Settings, class PowerToyValues, class CustomActionObject: [header](/src/common/settings_objects.h) [source](/src/common/settings_objects.cpp)
|
||||
Classes used to define settings screens for the PowerToys modules.
|
||||
|
||||
#### class Tasklist: [header](/src/common/tasklist_positions.h) [source](/src/common/tasklist_positions.cpp)
|
||||
Class that can detect the position of the windows buttons on the taskbar. It also detects which window will react to pressing `WinKey + number`.
|
||||
|
||||
#### struct WindowsColors: [header](/src/common/windows_colors.h) [source](/src/common/windows_colors.cpp)
|
||||
Class for detecting the current Windows color scheme.
|
||||
|
||||
# Helpers
|
||||
|
||||
#### Common helpers: [header](/src/common/common.h) [source](/src/common/common.cpp)
|
||||
Various helper functions.
|
||||
|
||||
#### Settings helpers: [header](/src/common/settings_helpers.h)
|
||||
Helper methods for the settings.
|
||||
|
||||
#### Start visible helper: [header](/src/common/start_visible.h) [source](/src/common/start_visible.cpp)
|
||||
Contains function to test if the Start menu is visible.
|
||||
|
||||
# Toast Notifications
|
||||
|
||||
#### Notifications API [header](/src/common/notifications.h) [source](/src/common/notifications.cpp)
|
||||
To use UWP-style toast notifications, simply include the header and call one of these functions:
|
||||
|
||||
```cpp
|
||||
void show_toast(std::wstring_view message); // #1
|
||||
|
||||
void show_toast_background_activated( // #2
|
||||
std::wstring_view message,
|
||||
std::wstring_view background_handler_id,
|
||||
std::vector<std::wstring_view> button_labels);
|
||||
```
|
||||
We might add more functions in the future if the need arises, e.g. `show_toast_xml` which will accept raw XML for rich customization.
|
||||
|
||||
Description:
|
||||
- `#1` is for sending simple notifications without any callbacks or buttons
|
||||
- `#2` is capable of showing a toast with multiple buttons and background activation
|
||||
- `message` is a plain-text argument
|
||||
|
||||
Implement a toast activation handler/callback as a function in [handler_functions.cpp](/src/common/notifications_winrt/handler_functions.cpp) and register its `background_handler_id` via `handlers_map`, e.g.:
|
||||
|
||||
```cpp
|
||||
// Your .cpp where you'd like to show a toast
|
||||
|
||||
#include <common/notifications.h>
|
||||
|
||||
void some_func() {
|
||||
// ...
|
||||
notifications::show_toast_background_activated(
|
||||
L"Toast message!", // text displayed in a toast
|
||||
L"awesome_toast", // activation handler id
|
||||
{L"Press me!", L"Also could press me!", L"I'm here to be pressed!"} // buttons in a toast
|
||||
);
|
||||
```
|
||||
|
||||
```cpp
|
||||
// handler_functions.cpp
|
||||
void awesome_toast_handler(IBackgroundTaskInstance, const size_t button_id)
|
||||
{
|
||||
switch(button_id)
|
||||
{
|
||||
case 0:
|
||||
// handle "Press me!" button click
|
||||
case 1:
|
||||
// handle "Also could press me!" button click
|
||||
case 2:
|
||||
// handle "I'm here to be pressed!" button click
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
const std::unordered_map<std::wstring_view, handler_function_t> handlers_map = {
|
||||
// ...other handlers...
|
||||
{L"awesome_toast", awesome_toast_handler}
|
||||
};}
|
||||
|
||||
```
|
||||
|
||||
Note: since _background activation_ implies that your toast handler will be invoked in a separate process, you can't share data directly from within a handler and your PT process. Also, since PT is currently a Desktop Bridge app, _foreground activation_ is [handled the same as background](https://docs.microsoft.com/en-US/windows/uwp/design/shell/tiles-and-notifications/send-local-toast-desktop-cpp-wrl#foreground-vs-background-activation), therefore we don't make a dedicated API for it. You can read more on the rationale of the current design [here](https://github.com/microsoft/PowerToys/pull/1178#issue-368768337).
|
||||
|
||||
|
||||
5
doc/devdocs/modules/example_powertoy.md
Normal file
@@ -0,0 +1,5 @@
|
||||
#### [`dllmain.cpp`](/src/modules/example_powertoy/dllmain.cpp)
|
||||
Contains DLL boilerplate code and implementation of the [PowerToys interface](/src/modules/interface/).
|
||||
|
||||
#### [`trace.cpp`](/src/modules/example_powertoy/trace.cpp)
|
||||
Contains code for telemetry.
|
||||
85
doc/devdocs/modules/fancyzones.md
Normal file
@@ -0,0 +1,85 @@
|
||||
## FancyZones Lib
|
||||
|
||||
#### [`FancyZones.cpp`](/src/modules/fancyzones/lib/FancyZones.cpp)
|
||||
TODO
|
||||
|
||||
#### [`Settings.cpp`](/src/modules/fancyzones/lib/Settings.cpp)
|
||||
TODO
|
||||
|
||||
#### [`trace.cpp`](/src/modules/fancyzones/lib/trace.cpp)
|
||||
TODO
|
||||
|
||||
#### [`Zone.cpp`](/src/modules/fancyzones/lib/Zone.cpp)
|
||||
TODO
|
||||
|
||||
#### [`ZoneSet.cpp`](/src/modules/fancyzones/lib/ZoneSet.cpp)
|
||||
TODO
|
||||
|
||||
#### [`ZoneWindow.cpp`](/src/modules/fancyzones/lib/ZoneWindow.cpp)
|
||||
TODO
|
||||
|
||||
## FancyZones Editor
|
||||
|
||||
#### [`App.xaml.cs`](/src/modules/fancyzones/editor/App.xaml.cs)
|
||||
TODO
|
||||
|
||||
#### [`Properties\AssemblyInfo.cs`](/src/modules/fancyzones/editor/Properties\AssemblyInfo.cs)
|
||||
TODO
|
||||
|
||||
#### [`CanvasEditor.xaml.cs`](/src/modules/fancyzones/editor/CanvasEditor.xaml.cs)
|
||||
TODO
|
||||
|
||||
#### [`CanvasEditorWindow.xaml.cs`](/src/modules/fancyzones/editor/CanvasEditorWindow.xaml.cs)
|
||||
TODO
|
||||
|
||||
#### [`Models\CanvasLayoutModel.cs`](/src/modules/fancyzones/editor/Models\CanvasLayoutModel.cs)
|
||||
TODO
|
||||
|
||||
#### [`CanvasZone.xaml.cs`](/src/modules/fancyzones/editor/CanvasZone.xaml.cs)
|
||||
TODO
|
||||
|
||||
#### [`EditorOverlay.xaml.cs`](/src/modules/fancyzones/editor/EditorOverlay.xaml.cs)
|
||||
TODO
|
||||
|
||||
#### [`EditorWindow.cs`](/src/modules/fancyzones/editor/EditorWindow.cs)
|
||||
TODO
|
||||
|
||||
#### [`GridEditor.xaml.cs`](/src/modules/fancyzones/editor/GridEditor.xaml.cs)
|
||||
TODO
|
||||
|
||||
#### [`GridEditorWindow.xaml.cs`](/src/modules/fancyzones/editor/GridEditorWindow.xaml.cs)
|
||||
TODO
|
||||
|
||||
#### [`Models\GridLayoutModel.cs`](/src/modules/fancyzones/editor/Models\GridLayoutModel.cs)
|
||||
TODO
|
||||
|
||||
#### [`GridResizer.xaml.cs`](/src/modules/fancyzones/editor/GridResizer.xaml.cs)
|
||||
TODO
|
||||
|
||||
#### [`GridZone.xaml.cs`](/src/modules/fancyzones/editor/GridZone.xaml.cs)
|
||||
TODO
|
||||
|
||||
#### [`Models\LayoutModel.cs`](/src/modules/fancyzones/editor/Models/LayoutModel.cs)
|
||||
TODO
|
||||
|
||||
#### [`LayoutPreview.xaml.cs`](/src/modules/fancyzones/editor/LayoutPreview.xaml.cs)
|
||||
TODO
|
||||
|
||||
#### [`MainWindow.xaml.cs`](/src/modules/fancyzones/editor/MainWindow.xaml.cs)
|
||||
TODO
|
||||
|
||||
#### [`Properties\Resources.Designer.cs`](/src/modules/fancyzones/editor/Properties/Resources.Designer.cs)
|
||||
TODO
|
||||
|
||||
#### [`RowColInfo.cs`](/src/modules/fancyzones/editor/RowColInfo.cs)
|
||||
TODO
|
||||
|
||||
#### [`Models\Settings.cs`](/src/modules/fancyzones/editor/Models/Settings.cs)
|
||||
TODO
|
||||
|
||||
#### [`Properties\Settings.Designer.cs`](/src/modules/fancyzones/editor/Properties/Settings.Designer.cs)
|
||||
TODO
|
||||
|
||||
#### [`WindowLayout.xaml.cs`](/src/modules/fancyzones/editor/WindowLayout.xaml.cs)
|
||||
TODO
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
# PowerToys Interface
|
||||
|
||||
The PowerToys interface that each PowerToy must implement.
|
||||
See [`the example PowerToy`](/src/modules/example_powertoy) for a PowerToys module example that uses this interface.
|
||||
|
||||
## Interface definition
|
||||
|
||||
This is the interface definition:
|
||||
# Interface definition
|
||||
|
||||
```cpp
|
||||
class PowertoyModuleIface {
|
||||
@@ -19,13 +12,15 @@ public:
|
||||
virtual void disable() = 0;
|
||||
virtual bool is_enabled() = 0;
|
||||
virtual intptr_t signal_event(const wchar_t* name, intptr_t data) = 0;
|
||||
virtual void register_system_menu_helper(PowertoySystemMenuIface* helper) = 0;
|
||||
virtual void signal_system_menu_action(const wchar_t* name) = 0;
|
||||
virtual void destroy() = 0;
|
||||
};
|
||||
|
||||
typedef PowertoyModuleIface* (__cdecl *powertoy_create_func)();
|
||||
```
|
||||
|
||||
### Runtime logic
|
||||
# Runtime logic
|
||||
|
||||
The PowerToys runner will, for each PowerToy DLL:
|
||||
- load the DLL,
|
||||
@@ -43,6 +38,8 @@ and destroy():
|
||||
- [`set_config()`](#set_config) to set settings after they have been edited in the Settings editor,
|
||||
- [`call_custom_action()`](#call_custom_action) when the user selects a custom action in the Settings editor,
|
||||
- [`signal_event()`](#signal_event) to send an event the PowerToy registered to.
|
||||
- [`register_system_menu_helper()`](#register_system_menu_helper) to pass object, responsible for handling customized system menus, to module.
|
||||
- [`signal_system_menu_action()`](#signal_system_menu_action) to send an event when action is taken on system menu item.
|
||||
|
||||
When terminating, the runner will:
|
||||
- call [`disable()`](#disable),
|
||||
@@ -50,11 +47,11 @@ When terminating, the runner will:
|
||||
- unload the DLL.
|
||||
|
||||
|
||||
### Method definition
|
||||
# Method definition
|
||||
|
||||
This section contains a more detailed description of each of the interface methods.
|
||||
|
||||
#### powertoy_create_func
|
||||
## powertoy_create_func
|
||||
|
||||
```cpp
|
||||
typedef PowertoyModuleIface* (__cdecl *powertoy_create_func)()
|
||||
@@ -82,7 +79,7 @@ ExamplePowertoy::ExamplePowertoy() {
|
||||
}
|
||||
```
|
||||
|
||||
#### get_name
|
||||
## get_name
|
||||
|
||||
```cpp
|
||||
virtual const wchar_t* get_name()
|
||||
@@ -97,7 +94,7 @@ Sample code from [`the example PowerToy`](/src/modules/example_powertoy/dllmain.
|
||||
}
|
||||
```
|
||||
|
||||
#### get_events
|
||||
## get_events
|
||||
|
||||
```cpp
|
||||
virtual const wchar_t** get_events()
|
||||
@@ -120,7 +117,7 @@ Sample code from [`the example PowerToy`](/src/modules/example_powertoy/dllmain.
|
||||
}
|
||||
```
|
||||
|
||||
#### get_config
|
||||
## get_config
|
||||
|
||||
```
|
||||
virtual bool get_config(wchar_t* buffer, int *buffer_size)
|
||||
@@ -170,7 +167,7 @@ Sample code from [`the example PowerToy`](/src/modules/example_powertoy/dllmain.
|
||||
}
|
||||
```
|
||||
|
||||
#### set_config
|
||||
## set_config
|
||||
|
||||
```cpp
|
||||
virtual void set_config(const wchar_t* config)
|
||||
@@ -203,7 +200,7 @@ Sample code from [`the example PowerToy`](/src/modules/example_powertoy/dllmain.
|
||||
}
|
||||
```
|
||||
|
||||
#### call_custom_action
|
||||
## call_custom_action
|
||||
|
||||
```cpp
|
||||
virtual void call_custom_action(const wchar_t* action)
|
||||
@@ -237,7 +234,7 @@ Sample code from [`the example PowerToy`](/src/modules/example_powertoy/dllmain.
|
||||
}
|
||||
```
|
||||
|
||||
#### enable
|
||||
## enable
|
||||
|
||||
```cpp
|
||||
virtual void enable()
|
||||
@@ -253,7 +250,7 @@ Sample code from [`the example PowerToy`](/src/modules/example_powertoy/dllmain.
|
||||
}
|
||||
```
|
||||
|
||||
#### disable
|
||||
## disable
|
||||
|
||||
```cpp
|
||||
virtual void disable()
|
||||
@@ -269,7 +266,7 @@ Sample code from [`the example PowerToy`](/src/modules/example_powertoy/dllmain.
|
||||
}
|
||||
```
|
||||
|
||||
#### is_enabled
|
||||
## is_enabled
|
||||
|
||||
```cpp
|
||||
virtual bool is_enabled() = 0;
|
||||
@@ -284,7 +281,7 @@ Sample code from [`the example PowerToy`](/src/modules/example_powertoy/dllmain.
|
||||
return m_enabled;
|
||||
}
|
||||
```
|
||||
#### signal_event
|
||||
## signal_event
|
||||
|
||||
```cpp
|
||||
virtual intptr_t signal_event(const wchar_t* name, intptr_t data) = 0;
|
||||
@@ -295,6 +292,8 @@ The data argument and return value meaning are event-specific:
|
||||
* ll_keyboard: see [`lowlevel_keyboard_event_data.h`](./lowlevel_keyboard_event_data.h).
|
||||
* win_hook_event: see [`win_hook_event_data.h`](./win_hook_event_data.h)
|
||||
|
||||
Please note that some of the events are currently being signalled from a separate thread.
|
||||
|
||||
Sample code from [`the example PowerToy`](/src/modules/example_powertoy/dllmain.cpp):
|
||||
|
||||
```cpp
|
||||
@@ -313,7 +312,26 @@ Sample code from [`the example PowerToy`](/src/modules/example_powertoy/dllmain.
|
||||
}
|
||||
```
|
||||
|
||||
#### destroy
|
||||
## register_system_menu_helper
|
||||
|
||||
```cpp
|
||||
virtual void register_system_menu_helper(PowertoySystemMenuIface* helper) = 0;
|
||||
```
|
||||
|
||||
Register helper class to handle all system menu items related actions. Creation, deletion
|
||||
and all other actions taken on system menu item will be handled by provided class.
|
||||
Module will be informed when action is taken on any item created on request of the module.
|
||||
|
||||
## signal_system_menu_action
|
||||
|
||||
```cpp
|
||||
virtual void signal_system_menu_action(const wchar_t* name) = 0;
|
||||
```
|
||||
|
||||
Runner invokes this API when action is taken on item created on request from the module.
|
||||
Item name is passed as an argument, so that module can distinguish between different menu items.
|
||||
|
||||
## destroy
|
||||
|
||||
```cpp
|
||||
virtual void destroy()
|
||||
@@ -328,14 +346,62 @@ Sample code from [`the example PowerToy`](/src/modules/example_powertoy/dllmain.
|
||||
}
|
||||
```
|
||||
|
||||
## Code organization
|
||||
## Powertoys system menu helper interface
|
||||
|
||||
#### [`powertoy_module_interface.h`](./powertoy_module_interface.h)
|
||||
Interface for helper class responsible for handling all system menu related actions.
|
||||
```cpp
|
||||
class PowertoySystemMenuIface {
|
||||
public:
|
||||
struct ItemInfo {
|
||||
std::wstring name{};
|
||||
bool enable{ false };
|
||||
bool checkBox{ false };
|
||||
};
|
||||
virtual void SetConfiguration(PowertoyModuleIface* module, const std::vector<ItemInfo>& config) = 0;
|
||||
virtual void ProcessSelectedItem(PowertoyModuleIface* module, HWND window, const wchar_t* itemName) = 0;
|
||||
};
|
||||
```
|
||||
|
||||
## ItemInfo
|
||||
|
||||
```cpp
|
||||
struct ItemInfo {
|
||||
std::wstring name{};
|
||||
bool enable{ false };
|
||||
bool checkBox{ false };
|
||||
};
|
||||
```
|
||||
|
||||
Structure containing all relevant information for system menu item: name (and hotkey if available), item
|
||||
status at creation (enabled/disabled) and whether check box will appear next to item name when action is taken.
|
||||
|
||||
## SetConfiguration
|
||||
|
||||
```cpp
|
||||
virtual void SetConfiguration(PowertoyModuleIface* module, const std::vector<ItemInfo>& config) = 0;
|
||||
```
|
||||
|
||||
Module should use this interface to inform system menu helper class which custom system menu items to create.
|
||||
|
||||
## ProcessSelectedItem
|
||||
|
||||
```cpp
|
||||
virtual void ProcessSelectedItem(PowertoyModuleIface* module, HWND window, const wchar_t* itemName) = 0;
|
||||
```
|
||||
|
||||
Process action taken on specific system menu item.
|
||||
|
||||
# Code organization
|
||||
|
||||
### [`powertoy_module_interface.h`](/src/modules/example_powertoy/powertoy_module_interface.h)
|
||||
Contains the PowerToys interface definition.
|
||||
|
||||
#### [`lowlevel_keyboard_event_data.h`](./lowlevel_keyboard_event_data.h)
|
||||
### [`powertoy_system_menu.h`](/src/modules/example_powertoy/powertoy_system_module.h)
|
||||
Contains the PowerToys system menu helper interface definition.
|
||||
|
||||
### [`lowlevel_keyboard_event_data.h`](/src/modules/example_powertoy/lowlevel_keyboard_event_data.h)
|
||||
Contains the `LowlevelKeyboardEvent` structure that's passed to `signal_event` for `ll_keyboard` events.
|
||||
|
||||
#### [`win_hook_event_data.h`](./win_hook_event_data.h)
|
||||
### [`win_hook_event_data.h`](/src/modules/example_powertoy/win_hook_event_data.h)
|
||||
Contains the `WinHookEvent` structure that's passed to `signal_event` for `win_hook_event` events.
|
||||
|
||||
26
doc/devdocs/modules/powerrename.md
Normal file
@@ -0,0 +1,26 @@
|
||||
#### [`dllmain.cpp`](/src/modules/powerrename/dll/dllmain.cpp)
|
||||
TODO
|
||||
|
||||
#### [`PowerRenameExt.cpp`](/src/modules/powerrename/dll/PowerRenameExt.cpp)
|
||||
TODO
|
||||
|
||||
#### [`Helpers.cpp`](/src/modules/powerrename/lib/Helpers.cpp)
|
||||
TODO
|
||||
|
||||
#### [`PowerRenameItem.cpp`](/src/modules/powerrename/lib/PowerRenameItem.cpp)
|
||||
TODO
|
||||
|
||||
#### [`PowerRenameManager.cpp`](/src/modules/powerrename/lib/PowerRenameManager.cpp)
|
||||
TODO
|
||||
|
||||
#### [`PowerRenameRegEx.cpp`](/src/modules/powerrename/lib/PowerRenameRegEx.cpp)
|
||||
TODO
|
||||
|
||||
#### [`Settings.cpp`](/src/modules/powerrename/lib/Settings.cpp)
|
||||
TODO
|
||||
|
||||
#### [`trace.cpp`](/src/modules/powerrename/lib/trace.cpp)
|
||||
TODO
|
||||
|
||||
#### [`PowerRenameUI.cpp`](/src/modules/powerrename/ui/PowerRenameUI.cpp)
|
||||
TODO
|
||||
17
doc/devdocs/modules/shortcut_guide.md
Normal file
@@ -0,0 +1,17 @@
|
||||
#### [`dllmain.cpp`](/src/modules/shortcut_guide/dllmain.cpp)
|
||||
Contains DLL boilerplate code.
|
||||
|
||||
#### [`shortcut_guide.cpp`](/src/modules/shortcut_guide/shortcut_guide.cpp)
|
||||
Contains the module interface code. It initializes the settings values and the keyboard event listener.
|
||||
|
||||
#### [`overlay_window.cpp`](/src/modules/shortcut_guide/overlay_window.cpp)
|
||||
Contains the code for loading the SVGs, creating and rendering of the overlay window.
|
||||
|
||||
#### [`keyboard_state.cpp`](/src/modules/shortcut_guide/keyboard_state.cpp)
|
||||
Contains helper methods for checking the current state of the keyboard.
|
||||
|
||||
#### [`target_state.cpp`](/src/modules/shortcut_guide/target_state.cpp)
|
||||
State machine that handles the keyboard events. It’s responsible for deciding when to show the overlay, when to suppress the Start menu (if the overlay is displayed long enough), etc.
|
||||
|
||||
#### [`trace.cpp`](/src/modules/shortcut_guide/trace.cpp)
|
||||
Contains code for telemetry.
|
||||
147
doc/devdocs/readme.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# Dev Documentation
|
||||
|
||||
## Rules
|
||||
|
||||
- **Follow the pattern of what you already see in the code.**
|
||||
- [Coding style](style.md).
|
||||
- Try to package new ideas/components into libraries that have nicely defined interfaces.
|
||||
- Package new ideas into classes or refactor existing ideas into a class as you extend.
|
||||
- When adding new classes/methos/changing existing code: add new unit tests or update the existing tests.
|
||||
|
||||
## Github Workflow
|
||||
|
||||
- Follow the PR template, in particular make sure there is open issue for the new PR.
|
||||
- When the PR is approved, let the owner of the PR merge it.
|
||||
- Use the `Squash and merge` option to merge a PR, if you don't want to squash it because there are logically different commits, use `Rebase and merge`.
|
||||
- We don't close issues automatically when referenced in a PR, so after the OR is merged:
|
||||
- mark the issue(s) fixed by the PR with the `resolved` label.
|
||||
- don't close the issue if it's a bug in the current release since users tend to not search for closed issues, we will close the resolved issues when a new released is published.
|
||||
|
||||
## Repository Overview
|
||||
|
||||
General project organization:
|
||||
|
||||
### The [`doc`](/doc) folder
|
||||
|
||||
Documentation for the project.
|
||||
|
||||
### The [`Wiki`](/wiki)
|
||||
|
||||
The Wiki contains the current specs for the project.
|
||||
|
||||
### The [`installer`](/installer) folder
|
||||
|
||||
Contains the source code of the PowerToys installer.
|
||||
|
||||
### The [`src`](/src) folder
|
||||
|
||||
Contains the source code of the PowerToys runner and of all of the PowerToys modules. **This is where the most of the magic happens.**
|
||||
|
||||
### The [`tools`](/tools) folder
|
||||
|
||||
Various tools used by PowerToys. Includes the Visual Studio 2019 project template for new PowerToys.
|
||||
|
||||
## Building code
|
||||
|
||||
### Build Prerequisites
|
||||
|
||||
- Windows 10 1803 (build 10.0.17134.0) or above to build and run PowerToys.
|
||||
- Visual Studio 2019 Community edition or higher, with the 'Desktop Development with C++' component and the Windows 10 SDK version 10.0.18362.0 or higher.
|
||||
|
||||
### Building the Code
|
||||
|
||||
- Open `powertoys.sln` in Visual Studio, in the `Solutions Configuration` drop-down menu select `Release` or `Debug`, from the `Build` menu choose `Build Solution`.
|
||||
- The PowerToys binaries will be in your repo under `x64\Release`.
|
||||
- If you want to copy the `PowerToys.exe` binary to a different location, you'll also need to copy the `modules` and the `svgs` folders.
|
||||
|
||||
### Building the .msi Installer
|
||||
|
||||
* From the `installer` folder open `PowerToysSetup.sln` in Visual Studio, in the `Solutions Configuration` drop-down menu select `Release` or `Debug`, from the `Build` menu choose `Build Solution`.
|
||||
* The resulting `PowerToysSetup.msi` installer will be available in the `installer\PowerToysSetup\x64\Release\` folder.
|
||||
|
||||
#### Prerequisites to Build the MSI Installer
|
||||
|
||||
* Install the [WiX Toolset Visual Studio 2019 Extension](https://marketplace.visualstudio.com/items?itemName=RobMensching.WiXToolset).
|
||||
* Install the [WiX Toolset build tools](https://wixtoolset.org/releases/).
|
||||
|
||||
### Building the MSIX Installer
|
||||
|
||||
Please follow the [installer instructions](./installer/readme.md) which include items such as creating the self-signed cert for testing.
|
||||
|
||||
## Debugging
|
||||
|
||||
The following configuration issue only applies if the user is a member of the Administrators group.
|
||||
|
||||
Some PowerToys modules require being run with the highest permission level if the current user is a member of the Administrators group. The highest permission level is required to be able to perform some actions when an elevated application (e.g. Task Manager) is in the foreground or is the target of an action. Without elevated privileges some PowerToys modules will still work but with some limitations:
|
||||
|
||||
- the `FancyZones` module will be not be able to move an elevated window to a zone.
|
||||
- the `Shortcut Guide` module will not appear if the foreground window belongs to an elevated application.
|
||||
|
||||
To run and debug PowerToys from Visual Studio when the user is a member of the Administrators group, Visual Studio has to be started with elevated privileges. If you want to avoid running Visual Studio with elevated privileges and don't mind the limitations described above, you can do the following: open the `runner` project properties and navigate to the `Linker -> Manifest File` settings, edit the `UAC Execution Level` property and change it from `highestAvailable (level='highestAvailable')` to `asInvoker (/level='asInvoker')`, save the changes.
|
||||
|
||||
## How to create new PowerToys
|
||||
|
||||
See the instructions on [how to install the PowerToys Module project template](tools/project_template). <br />
|
||||
Specifications for the [PowerToys settings API](doc/specs/PowerToys-settings.md).
|
||||
|
||||
## Implementation details
|
||||
|
||||
### [`Runner`](runner.md)
|
||||
|
||||
The PowerToys Runner contains the project for the PowerToys.exe executable.
|
||||
It's responsible for:
|
||||
|
||||
- Loading the individual PowerToys modules.
|
||||
- Passing registered events to the PowerToys.
|
||||
- Showing a system tray icon to manage the PowerToys.
|
||||
- Bridging between the PowerToys modules and the Settings editor.
|
||||
|
||||

|
||||
|
||||
### [`Interface`](modules/interface.md)
|
||||
|
||||
Definition of the interface used by the [`runner`](/src/runner) to manage the PowerToys. All PowerToys must implement this interface.
|
||||
|
||||
### [`Common`](common.md)
|
||||
|
||||
The common lib, as the name suggests, contains code shared by multiple PowerToys components and modules, e.g. [json parsing](/src/common/json.h) and [IPC primitives](/src/common/two_way_pipe_message_ipc.h).
|
||||
|
||||
### [`Settings`](settings.md)
|
||||
|
||||
WebView project for editing the PowerToys settings.
|
||||
|
||||
The html portion of the project that is shown in the WebView is contained in [`settings-html`](/src/settings/settings-heml).
|
||||
Instructions on how build a new version and update this project are in the [Web project for the Settings UI](./settings-web.md).
|
||||
|
||||
While developing, it's possible to connect the WebView to the development server running in localhost by setting the `_DEBUG_WITH_LOCALHOST` flag to `1` and following the instructions near it in `./main.cpp`.
|
||||
|
||||
### [`Settings-web`](settings-web.md)
|
||||
This project generates the web UI shown in the [PowerToys Settings](/src/editor).
|
||||
It's a `ReactJS` project created using [UI Fabric](https://developer.microsoft.com/en-us/fabric#/).
|
||||
|
||||
## Current modules
|
||||
### [`FancyZones`](modules/fancyzones.md)
|
||||
The FancyZones PowerToy that allows users to create custom zones on the screen, to which the windows will snap when moved.
|
||||
|
||||
### [`PowerRename`](modules/powerrename.md)
|
||||
PowerRename is a Windows Shell Context Menu Extension for advanced bulk renaming using simple search and replace or more powerful regular expression matching.
|
||||
|
||||
### [`Shortcut Guide`](modules/shortcut_guide.md)
|
||||
The Windows Shortcut Guide, displayed when the WinKey is held for some time.
|
||||
|
||||
### _obsolete_ [`example_powertoy`](modules/example_powertoy.md)
|
||||
An example PowerToy, that demonstrates how to create new ones. Please note, that this is going to become a Visual Studio project template soon.
|
||||
|
||||
This PowerToy serves as a sample to show how to implement the [PowerToys interface](/src/modules/interface/) when creating a PowerToy. It also showcases the currently implemented settings.
|
||||
|
||||
#### Options
|
||||
|
||||
This module has a setting to serve as an example for each of the currently implemented settings property:
|
||||
|
||||
- BoolToggle property
|
||||
- IntSpinner property
|
||||
- String property
|
||||
- ColorPicker property
|
||||
- CustomAction property
|
||||
|
||||

|
||||
36
doc/devdocs/runner.md
Normal file
@@ -0,0 +1,36 @@
|
||||
#### [`main.cpp`](/src/runner/main.cpp)
|
||||
Contains the executable starting point, initialization code and the list of known PowerToys. All singletones are also initialized here at the start. Loads all the powertoys by scanning the `./modules` folder and `enable()`s those makred as enabled in `%LOCALAPPDATA%\Microsoft\PowerToys\settings.json` config. Then it runs [a message loop](https://docs.microsoft.com/en-us/windows/win32/winmsg/using-messages-and-message-queues) for the tray UI. Note that this message loop also [handles lowlevel_keyboard_hook events](https://github.com/microsoft/PowerToys/blob/1760af50c8803588cb575167baae0439af38a9c1/src/runner/lowlevel_keyboard_event.cpp#L24).
|
||||
|
||||
#### [`general_settings.cpp`](./general_settings.cpp)
|
||||
#### [`powertoy_module.h`](/src/runner/powertoy_module.h) and [`powertoy_module.cpp`](/src/runner/powertoy_module.cpp)
|
||||
Contains code for initializing and managing the PowerToy modules. `PowertoyModule` is a RAII-style holder for the `PowertoyModuleIface` pointer, which we got by [invoking module DLL's `powertoy_create` function](https://github.com/microsoft/PowerToys/blob/1760af50c8803588cb575167baae0439af38a9c1/src/runner/powertoy_module.cpp#L13-L24).
|
||||
|
||||
#### [`powertoys_events.cpp`](/src/runner/powertoys_events.cpp)
|
||||
Contains code that handles the various events listeners, and forwards those events to the PowerToys modules. You can learn more about the current event architecture [here](/doc/devdocs/shared-hooks.md).
|
||||
|
||||
#### [`lowlevel_keyboard_event.cpp`](/src/runner/lowlevel_keyboard_event.cpp)
|
||||
Contains code for registering the low level keyboard event hook that listens for keyboard events. Please note that `signal_event` is called from the main thread for this event.
|
||||
|
||||
#### [`win_hook_event.cpp`](/src/runner/win_hook_event.cpp)
|
||||
Contains code for registering a Windows event hook through `SetWinEventHook`, that listens for various events raised when a window is interacted with. Please note, that `signal_event` is called from a separate `dispatch_thread_proc` worker thread, so you must provide thread-safety for your `signal_event` if you intend to receive it. This is a subject to change.
|
||||
|
||||
#### [`tray_icon.cpp`](/src/runner/tray_icon.cpp)
|
||||
Contains code for managing the PowerToys tray icon and its menu commands. Note that `dispatch_run_on_main_ui_thread` is used to
|
||||
transfer received json message from the [Settings window](/doc/devdocs/settings.md) to the main thread, since we're communicating with it from [a dedicated thread](https://github.com/microsoft/PowerToys/blob/7357e40d3f54de51176efe54fda6d57028837b8c/src/runner/settings_window.cpp#L267-L271).
|
||||
#### [`settings_window.cpp`](/src/runner/settings_window.cpp)
|
||||
Contains code for starting the PowerToys settings window and communicating with it. Settings window is a separate process, so we're using [Windows pipes](https://docs.microsoft.com/en-us/windows/win32/ipc/pipes) as a transport for json messages.
|
||||
|
||||
#### [`general_settings.cpp`](/src/runner/general_settings.cpp)
|
||||
Contains code for loading, saving and applying the general setings.
|
||||
|
||||
#### [`auto_start_helper.cpp`](/src/runner/auto_start_helper.cpp)
|
||||
Contains helper code for registering and unregistering PowerToys to run when the user logs in.
|
||||
|
||||
#### [`unhandled_exception_handler.cpp`](/src/runner/unhandled_exception_handler.cpp)
|
||||
Contains helper code to get stack traces in builds. Can be used by adding a call to `init_global_error_handlers` in [`WinMain`](./main.cpp).
|
||||
|
||||
#### [`trace.cpp`](/src/runner/trace.cpp)
|
||||
Contains code for telemetry.
|
||||
|
||||
#### [`svgs`](/src/runner/svgs/)
|
||||
Contains the SVG assets used by the PowerToys modules.
|
||||
597
doc/devdocs/settings-reference.md
Normal file
@@ -0,0 +1,597 @@
|
||||
# Settings
|
||||
|
||||
While the module interface passes the settings and values thorough a JSON string, **use our helper functions**. In future we might move to a different implementation. All current modules use:
|
||||
* `load_module_settings` to load the settings from the disk.
|
||||
* `PowerToySettings::Settings` class to define module properties and the settings screen.
|
||||
* `PowerToySettings::PowerToyValues` class to parse the JSON passed by the runner.
|
||||
* `save_module_settings` to store the settings on the disk.
|
||||
|
||||
Most functions provide two overloads - one that accepts UINT with a resource ID and one that accepts strings. **Put all strings in the resource file and use the resource ID overload.**
|
||||
|
||||
|
||||
The following documents internal workings of the settings system.
|
||||
|
||||
## Overview
|
||||
|
||||
PowerToys runner provides a generic way for modules to define their settings.
|
||||
|
||||
Each module on startup is responsible for loading its own settings and initializing accordingly. When the user wants to edit settings, the runner will call [`get_config()`](modules/interface.md#get_config) module method. The module must provide a JSON which includes the module name, description but also what settings options are provided.
|
||||
|
||||
When settings from all modules are collected, a separate [settings editor app](/src/settings) is spawned. The editor wraps [an React app](/src/settings-web) and handles the communication with the runner.
|
||||
|
||||
When loaded, the React app receives the JSON passed by the runner. When user saves the settings, the editor passes the new settings values as JSON string to the runner. Runner in turn will call [`set_config()`](modules/interface.md#set_config) for all modules with appropriate JSON. When user initiates a custom action (like the Zone Editor in FancyZones), the runner will call [`call_custom_action()`](modules/interface.md#call_custom_action) providing the action name in a JSON.
|
||||
|
||||
There are C++ helper functions in [/src/common/settings_objects.h](/src/common/settings_objects.h) and [/src/common/settings_helpers.h](/src/common/settings_helpers.h). Those include classes for creating the settings options JSON and ones for parsing the incoming settings JSON.
|
||||
|
||||
### Module settings
|
||||
The value returned by the [`get_config()`](modules/interface.md#get_config) call should provide a JSON object with following fields:
|
||||
* `name` - The name of the PowerToy. Used on the nav panel on the left.
|
||||
* `version` - The settings version. Needs to be set to `"1.0"`.
|
||||
* `description` - Description of the PowerToy module.
|
||||
* `overview_link`, `video_link` - Optional links to the documentation and video preview of the PowerToy module.
|
||||
* `icon_key` - Name of the icon of the PowerToy. The SVGs for the icons are located in [/src/settings-web/src/svg](/src/settings-web/src/svg). They also need to be added in [/settings-web/src/setup_icons.tsx](/settings-web/src/setup_icons.tsx).
|
||||
* `properties` - Optional object that contains the definition of the settings screen.
|
||||
|
||||
The `properties` JSON object defines what settings controls are available to the user. Each key defines one control. The controls have some common properties:
|
||||
* The key in the `properties` which identifies the control.
|
||||
* `editor_type` - Defines the type of the control. Those are listed further.
|
||||
* `order` - Defines the order of the elements on the settings screen.
|
||||
|
||||
Each `editor_type` has its own set of properties.
|
||||
|
||||
Example module JSON (taken from Shortcut Guide):
|
||||
```json
|
||||
{
|
||||
"name": "Shortcut Guide",
|
||||
"version": "1.0",
|
||||
"description": "Shows a help overlay with Windows shortcuts when the Windows key is pressed.",
|
||||
"overview_link": "https://github.com/.../README.md",
|
||||
"icon_key": "pt-shortcut-guide",
|
||||
"properties": {
|
||||
"press_time": {
|
||||
"editor_type": "int_spinner",
|
||||
"order": 1,
|
||||
"display_name": "How long to press the Windows key before showing the Shortcut Guide (ms)",
|
||||
"value": 900,
|
||||
"min": 100,
|
||||
"max": 10000,
|
||||
"step": 100
|
||||
},
|
||||
"overlay_opacity": {
|
||||
"editor_type": "int_spinner",
|
||||
"order": 2,
|
||||
"display_name": "Opacity of the Shortcut Guide's overlay background (%)",
|
||||
"value": 90,
|
||||
"min": 0,
|
||||
"max": 100,
|
||||
"step": 1
|
||||
},
|
||||
"theme":{
|
||||
"editor_type": "choice_group",
|
||||
"order": 3,
|
||||
"display_name": "Choose Shortcut Guide overlay color",
|
||||
"value": "system",
|
||||
"options": [ {"key": "system", "text": "System default app mode"},
|
||||
{"key": "light", "text": "Light"},
|
||||
{"key": "dark", "text": "Dark"} ]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
produces this settings screen:
|
||||
|
||||

|
||||
|
||||
### Helper methods
|
||||
|
||||
PowerToys provides [a helper class](/src/common/json.h) to parse and generate JSON strings.
|
||||
|
||||
In [`settings_helpers.h`](/src/common/settings_helpers.h) there are two helper functions: `load_module_settings(powertoy_name)` and `save_general_settings(settings)` for loading and saving the module configuration.
|
||||
|
||||
In [`settings_objects.h`](/src/common/settings_objects.h) there are some helper classes:
|
||||
* `Settings` - for generating JSON with module settings definition.
|
||||
* `PowerToyValues` - for parsing JSON with settings - either loaded from file or from the settings editor.
|
||||
* `CustomActionObject` and `HotkeyObject` - for parsing custom actions and hotkey input specific JSON.
|
||||
|
||||
### General settings
|
||||
General settings control the PowerToys runner and decide which modules are enabled and which are not. The general settings screen is special - while modules provide the definition of the settings controls, the available settings on the general screen are hardcoded.
|
||||
|
||||
General settings has following properties:
|
||||
* `enabled` - Enabled/disabled status of each PowerToy.
|
||||
* `startup` - Should PowerToys start at user logon.
|
||||
* `theme` - Settings editor theme - `light`, `dark` or `system`.
|
||||
* `system_theme` - Current Windows theme - `light` or `dark`.
|
||||
* `powertoys_version` - The version of the PowerToys.
|
||||
|
||||
This JSON:
|
||||
```json
|
||||
{
|
||||
"enabled": {
|
||||
"FancyZones": true,
|
||||
"PowerRename": true,
|
||||
"Shortcut Guide": true
|
||||
},
|
||||
"startup": true,
|
||||
"theme": "light",
|
||||
"system_theme": "dark",
|
||||
"powertoys_version": "0.14.2.0"
|
||||
}
|
||||
```
|
||||
Produces this general settings screen:
|
||||
|
||||

|
||||
|
||||
## Putting it all together
|
||||
The runner combines general settings and each module settings into a single JSON that is passed to the settings editor. Example combined settings look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"general": {
|
||||
"enabled": {
|
||||
"FancyZones": true,
|
||||
"PowerRename": true,
|
||||
"Shortcut Guide": true
|
||||
},
|
||||
"startup": true,
|
||||
"theme": "light",
|
||||
"system_theme": "dark",
|
||||
"powertoys_version": "0.14.2.0"
|
||||
},
|
||||
"powertoys": {
|
||||
"FancyZones": { ... },
|
||||
"PowerRename": { ... },
|
||||
"Shortcut Guide":{
|
||||
"name": "Shortcut Guide",
|
||||
"version": "1.0",
|
||||
"description": "Shows a help overlay with Windows shortcuts when the Windows key is pressed.",
|
||||
"overview_link": "https://github.com/.../README.md",
|
||||
"icon_key": "pt-shortcut-guide",
|
||||
"properties": { ... }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## C++ helpers
|
||||
While you can generate and parse JSON yourself there are helper methods provided.
|
||||
|
||||
### Loading settings
|
||||
When a PowerToy module is created, it should load its configuration. This can be done by calling
|
||||
```c++
|
||||
json::JsonObject PTSettingsHelper::load_module_settings(std::wstring_view powertoy_name);
|
||||
```
|
||||
declared in [`settings_helpers.h`](/src/common/settings_helpers.h). The function will return an `json::JsonObject` object containing the module settings.
|
||||
|
||||
Another option is using [`PowerToySettings::PowerToyValues`](/src/common/settings_objects.h#L67) class. A static method
|
||||
```c++
|
||||
PowerToyValues PowerToyValues::load_from_settings_file(std::wstring_view powertoy_name);
|
||||
```
|
||||
will load and parse the settings. You can also use
|
||||
```c++
|
||||
PowerToyValues PowerToyValues::from_json_string(std::wstring_view json);
|
||||
```
|
||||
to parse JSON string - for example when implementing [`set_config()`](modules/interface.md#set_config). The returned `PowerToyValues` object has helper methods that return `std::optional` with values, for example:
|
||||
```c++
|
||||
auto settings = PowerToyValues::load_from_settings_file(L"some_powertoy");
|
||||
std::optional<std::wstring> str_prop = settings.get_string_value(L"some_string_property");
|
||||
auto int_prop = settings.get_int_value(L"some_int_property");
|
||||
```
|
||||
|
||||
### Generating settings screen
|
||||
The [`PowerToySettings::Settings`](/src/common/settings_objects.h) can be used to generate settings:
|
||||
```c++
|
||||
// Need to get strings from the resource file.
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
auto hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||
PowerToysSettings::Settings settings(hinstance, L"example_powertoy");
|
||||
settings.set_description(L"Example powertoy.");
|
||||
settings.set_overview_link(L"https://example.com");
|
||||
settings.set_icon_key(L"pt-example");
|
||||
settings.add_string(L"string_val", L"Example string label", L"example value");
|
||||
settings.add_int_spinner(L"int_val", L"Example int label", 0, 0, 100, 10);
|
||||
```
|
||||
You can then use `std::wstring serialize()` or `bool serialize_to_buffer(wchar_t* buffer, int* uffer_size)` methods to generate output JSON string.
|
||||
|
||||
### Saving settings
|
||||
Use
|
||||
```c++
|
||||
void PTSettingsHelper::save_module_settings(std::wstring_view powertoy_name, json::JsonObject& settings);
|
||||
```
|
||||
declared in [`settings_helpers.h`](/src/common/settings_helpers.h).
|
||||
|
||||
## Module settings elements
|
||||
|
||||
### Bool toggle
|
||||
```c++
|
||||
add_bool_toogle(name, description, value)
|
||||
```
|
||||
A simple on-off toggle. Parameters:
|
||||
* `name` - Key for the element in the JSON.
|
||||
* `description` - String or resource ID of the text displayed to the user.
|
||||
* `value` - Initial state of the toggle (`true` - on, `false` - off).
|
||||
|
||||
This C++:
|
||||
```c++
|
||||
settings.add_bool_toogle(L"bool_name", L"description", true);
|
||||
```
|
||||
produces this settings element:
|
||||
|
||||

|
||||
|
||||
and this generated JSON:
|
||||
```json
|
||||
{
|
||||
"properties": {
|
||||
"bool_name": {
|
||||
"editor_type": "bool_toggle",
|
||||
"order": autoincremented_number,
|
||||
"display_name": "description",
|
||||
"value": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The toggle value is stored as bool:
|
||||
```c++
|
||||
std::optional<bool> bool_value = settings.get_bool_value(L"bool_name");
|
||||
```
|
||||
|
||||
### Int Spinner
|
||||
```c++
|
||||
add_int_spinner(name, description, value, min, max, step)
|
||||
```
|
||||
Numeric input with dials to increment and decrement the value. Parameters:
|
||||
* `name` - Key for element in the JSON.
|
||||
* `description` - String or resource ID of the text displayed to the user.
|
||||
* `value` - Initial control value.
|
||||
* `min`, `max` - Minimum and maximum values for the input. User cannot use dials to move beyond those values, if a value out of range is inserted using the keyboard, it will get clamped to the allowed range.
|
||||
* `step` - How much the dials change the value.
|
||||
|
||||
This C++:
|
||||
```c++
|
||||
settings.add_int_spinner(L"int_spinner_name", L"description", 50, -100, 100, 10);
|
||||
```
|
||||
produces this settings element:
|
||||
|
||||

|
||||
|
||||
and this generated JSON:
|
||||
```json
|
||||
{
|
||||
"properties": {
|
||||
"int_spinner_name": {
|
||||
"editor_type": "int_spinner",
|
||||
"order": autoincremented_number,
|
||||
"display_name": "description",
|
||||
"value": 50,
|
||||
"min": -100,
|
||||
"max": 100,
|
||||
"step": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The spinner value is stored as int:
|
||||
```c++
|
||||
std::optional<int> int_value = settings.get_int_value(L"int_spinner_name");
|
||||
```
|
||||
|
||||
### String
|
||||
```c++
|
||||
add_string(name, description, value)
|
||||
```
|
||||
Single line text input. Parameters:
|
||||
* `name` - Key for element in the JSON.
|
||||
* `description` - String or resource ID of the text displayed to the user.
|
||||
* `value` - Default value for the input.
|
||||
|
||||
This C++:
|
||||
```c++
|
||||
settings.add_string(L"string_name", L"description", L"value");
|
||||
```
|
||||
produces this settings element:
|
||||
|
||||

|
||||
|
||||
and this generated JSON:
|
||||
```json
|
||||
{
|
||||
"properties": {
|
||||
"string_name": {
|
||||
"editor_type": "string_text",
|
||||
"order": autoincremented_number,
|
||||
"display_name": "description",
|
||||
"value": "value"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The input value is stored as `std::wstring`:
|
||||
```c++
|
||||
std::optional<std::wstring> string_value = settings.get_string_value(L"string_name");
|
||||
```
|
||||
|
||||
### Multiline string
|
||||
```c++
|
||||
add_multiline_string(name, description, value)
|
||||
```
|
||||
Multiline text input. Parameters:
|
||||
* `name` - Key for element in the JSON.
|
||||
* `description` - String or resource ID of the text displayed to the user.
|
||||
* `value` - Default value for the input. Can have multiple lines.
|
||||
|
||||
This C++:
|
||||
```c++
|
||||
settings.add_multiline_string(L"multiline_name", L"description", L"multiline1\nmultiline2");
|
||||
```
|
||||
produces this settings element:
|
||||
|
||||

|
||||
|
||||
and this generated JSON:
|
||||
```json
|
||||
{
|
||||
"properties": {
|
||||
"multiline_name": {
|
||||
"editor_type": "string_text",
|
||||
"multiline": true,
|
||||
"order": autoincremented_number,
|
||||
"display_name": "description",
|
||||
"value": "multiline1\nmultiline2"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The input value is stored as string:
|
||||
```c++
|
||||
std::optional<std::wstring> value = settings.get_string_value(L"multiline_name");
|
||||
```
|
||||
|
||||
### Color picker
|
||||
```c++
|
||||
add_color_picker(name, description, value)
|
||||
```
|
||||
|
||||
Allows user to pick a color. Parameters:
|
||||
* `name` - Key for element in the JSON.
|
||||
* `description` - String or resource ID of the text displayed to the user.
|
||||
* `value` - Initial color, as a string in `"#RRGGBB"` format.
|
||||
|
||||
This C++:
|
||||
```c++
|
||||
settings.add_color_picker(L"colorpicker_name", L"description", L"#102040");
|
||||
```
|
||||
produces this settings element:
|
||||
|
||||

|
||||
|
||||
and this generated JSON:
|
||||
```json
|
||||
{
|
||||
"properties": {
|
||||
"colorpicker_name": {
|
||||
"editor_type": "color_picker",
|
||||
"order": autoincremented_number,
|
||||
"display_name": "description",
|
||||
"value": "#102040"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The color picker value is stored as `std::wstring`:
|
||||
```c++
|
||||
std::optional<std::wstring> value = settings.get_string_value(L"colorpicker_name");
|
||||
```
|
||||
|
||||
### Hotkey
|
||||
```c++
|
||||
settings.add_hotkey(name, description, hotkey)
|
||||
```
|
||||
Input for capturing hotkeys. Parameters:
|
||||
* `name` - Key for element in the JSON.
|
||||
* `description` - String or resource ID of the text displayed to the user.
|
||||
* `hotkey` - Instance of `PowerToysSettings::HotkeyObject` class.
|
||||
|
||||
You can create `PowerToysSettings::HotkeyObject` object either by using helper `from_settings` static method or by providing JSON object to `from_json` static method:
|
||||
|
||||
The `PowerToysSettings::HotkeyObject::from_settings` take following parameters:
|
||||
* `win_pressed` - Is the WinKey pressed.
|
||||
* `ctrl_pressed` - Is the Ctrl key pressed.
|
||||
* `alt_pressed` - Is the Alt key pressed.
|
||||
* `shift_pressed` - Is the Shift key pressed.
|
||||
* `vk_code` - The [virtual key-code](https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes) of the key.
|
||||
|
||||
The displayed key is deduced from the `vk_code` using the users keyboard layout and language settings.
|
||||
|
||||
Similar parameters can be passed using the `from_json` static method:
|
||||
```c++
|
||||
json::JsonObject json;
|
||||
json.SetNamedValue(L"win", json::value(win_pressed));
|
||||
json.SetNamedValue(L"ctrl", json::value(ctrl_pressed));
|
||||
json.SetNamedValue(L"alt", json::value(alt_pressed));
|
||||
json.SetNamedValue(L"shift", json::value(shift_pressed));
|
||||
json.SetNamedValue(L"code", json::value(vk_code));
|
||||
json.SetNamedValue(L"key", json::value(L"string with key name"));
|
||||
auto hotkey = PowerToysSettings::HotkeyObject::from_json(json);
|
||||
```
|
||||
|
||||
|
||||
This C++:
|
||||
```c++
|
||||
settings.add_hotkey(L"hotkey_name",
|
||||
L"description",
|
||||
PowerToysSettings::HotkeyObject::from_settings(true, true, true, true, VK_F5));
|
||||
```
|
||||
produces this settings element:
|
||||
|
||||

|
||||
|
||||
and this generated JSON (`114` is the value of `VK_F5`):
|
||||
```json
|
||||
{
|
||||
"properties": {
|
||||
"hotkey_name": {
|
||||
"editor_type": "hotkey",
|
||||
"order": autoincremented_number,
|
||||
"display_name": "description",
|
||||
"value": {
|
||||
"win": true,
|
||||
"ctrl": true,
|
||||
"alt": true,
|
||||
"shift": true,
|
||||
"code": 114,
|
||||
"key": "F5"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The hotkey value is returned as JSON, with the same format as `from_json` method uses. You can use `HotkeyObject` class to parse this JSON, since it offers some helper methods. A typical example of registering a hotkey:
|
||||
```c++
|
||||
std::optional<json::JsonObject> value = settings.get_json(L"hotkey_name");
|
||||
if (value) {
|
||||
auto hotkey = PowerToysSettings::HotkeyObject::from_json(*value);
|
||||
RegisterHotKey(hwnd, 1, hotkey.get_modifiers(), hotkey.get_code());
|
||||
}
|
||||
```
|
||||
|
||||
### Choice group
|
||||
```c++
|
||||
add_choice_group(name, description, value, vector<pair<wstring, wstring>> keys_and_texts)
|
||||
add_choice_group(name, description, value, vector<pair<wstring, UINT>> keys_and_texts)
|
||||
```
|
||||
|
||||
A radio buttons group. Parameters:
|
||||
* `name` - Key for element in the JSON.
|
||||
* `description` - String or resource ID of the text displayed to the user.
|
||||
* `value` - Key selected by default.
|
||||
* `keys_and_text` - Vector of radio buttons definitions: key and the displayed label. The texts can either be strings or resource IDs.
|
||||
|
||||
This C++:
|
||||
```c++
|
||||
settings.add_choice_group(L"choice_group_name", L"description", L"val1", { { L"val1", L"value-1" },
|
||||
{ L"val2", L"value-2" },
|
||||
{ L"val3", L"value-3" } });
|
||||
```
|
||||
produces this settings element:
|
||||
|
||||

|
||||
|
||||
and this generated JSON:
|
||||
```json
|
||||
{
|
||||
"properties": {
|
||||
"choice_group_name": {
|
||||
"editor_type": "choice_group",
|
||||
"order": autoincremented_number,
|
||||
"display_name": "description",
|
||||
"value": "val1",
|
||||
"options": [ {"key": "val1", "text": "value-1"},
|
||||
{"key": "val2", "text": "value-2"},
|
||||
{"key": "val3", "text": "value-3"} ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The chosen button value is stored as a string with the key of the button selected by the user:
|
||||
```c++
|
||||
std::optional<std::wstring> value = settings.get_string_value(L"choice_group_name");
|
||||
```
|
||||
|
||||
### Dropdown
|
||||
```c++
|
||||
add_dropdown(name, description, value, vector<pair<wstring, wstring>> keys_and_texts)
|
||||
add_dropdown(name, description, value, vector<pair<wstring, UINT>> keys_and_texts)
|
||||
```
|
||||
|
||||
A dropdown. Parameters:
|
||||
* `name` - Key for element in the JSON.
|
||||
* `description` - String or resource ID of the text displayed to the user.
|
||||
* `value` - Key selected by default.
|
||||
* `keys_and_text` - Vector of the options definitions: key and the displayed label. The texts can either be strings or resource IDs.
|
||||
|
||||
This C++:
|
||||
```c++
|
||||
settings.add_dropdown(L"dropdown_name", L"description", L"val2", { { L"val1", L"value-1" },
|
||||
{ L"val2", L"value-2" },
|
||||
{ L"val3", L"value-3" } });
|
||||
```
|
||||
produces this settings element:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
and this generated JSON:
|
||||
```json
|
||||
{
|
||||
"properties": {
|
||||
"dropdown_name": {
|
||||
"editor_type": "dropdown",
|
||||
"order": autoincremented_number,
|
||||
"display_name": "description",
|
||||
"value": "val1",
|
||||
"options": [ {"key": "val1", "text": "value-1"},
|
||||
{"key": "val2", "text": "value-2"},
|
||||
{"key": "val3", "text": "value-3"} ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The chosen value is stored as a string with the key of the option selected by the user:
|
||||
```c++
|
||||
std::optional<std::wstring> value = settings.get_string_value(L"dropdown_name");
|
||||
```
|
||||
### Custom action
|
||||
|
||||
```c++
|
||||
add_custom_action(name, description, button_text, ext_description)
|
||||
```
|
||||
|
||||
Adds a button with a description. Parameters:
|
||||
* `name` - Key for element in the JSON.
|
||||
* `description` - String or resource ID of the text displayed to the user.
|
||||
* `button_text` - String or resource ID for the button label.
|
||||
* `ext_description` - String or resource ID for the extended description.
|
||||
|
||||
This C++:
|
||||
```c++
|
||||
settings.add_custom_action(L"custom_action_name", L"description", L"button_text", L"ext_description");
|
||||
```
|
||||
produces this settings element:
|
||||
|
||||

|
||||
|
||||
and this generated JSON:
|
||||
```json
|
||||
{
|
||||
"properties": {
|
||||
"custom_action_name": {
|
||||
"editor_type": "custom_action",
|
||||
"order": autoincremented_number,
|
||||
"display_name": "description",
|
||||
"button_text": "button_text",
|
||||
"value": "ext_description"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When the button is pressed, the `call_custom_action` method of the module will be called, with JSON containing the name of the action. In our example:
|
||||
```json
|
||||
{
|
||||
"action_name":"custom_action_name",
|
||||
"value":"ext_description"
|
||||
}
|
||||
```
|
||||
@@ -1,10 +1,3 @@
|
||||
# Web project for the Settings UI
|
||||
|
||||
## Introduction
|
||||
|
||||
This project generates the web UI shown in the [PowerToys Settings](/src/editor).
|
||||
It's a `ReactJS` project created using [UI Fabric](https://developer.microsoft.com/en-us/fabric#/).
|
||||
|
||||
## Build Commands
|
||||
|
||||
Here are the commands to build and test this project:
|
||||
@@ -22,9 +15,11 @@ npm run start
|
||||
npm run build
|
||||
```
|
||||
|
||||
**Note:** you will need to rebuild the settings project to pick up the changes
|
||||
|
||||
## Updating the icons
|
||||
|
||||
Icons inside [`src/icons/`](./src/icons/) were generated from the [Office UI Fabric Icons subset generation tool.](https://uifabricicons.azurewebsites.net/)
|
||||
Icons inside [`src/icons/`](/src/settings-web/src/icons/) were generated from the [Office UI Fabric Icons subset generation tool.](https://uifabricicons.azurewebsites.net/)
|
||||
|
||||
In case the subset needs to be changed, additional steps are needed to include the icon font in the built `dist/bundle.js`:
|
||||
- Copy the inline font data taken from [`src/icons/css/fabric-icons-inline.css`](src/icons/css/fabric-icons-inline.css) and place it in the `fontFace` `src` value in [`src/icons/src/fabric-icons.ts`](src/icons/src/fabric-icons.ts).
|
||||
@@ -37,44 +32,44 @@ SVG icons, including the icons for each PowerToy listed in the Settings, are con
|
||||
|
||||
The project structure is based on the [`UI Fabric` scaffold](https://developer.microsoft.com/en-us/fabric#/get-started/web#option-1-quick-start) obtained by initializing it with `npm init uifabric`.
|
||||
|
||||
#### [index.html](./index.html)
|
||||
#### [index.html](/src/settings-web/index.html)
|
||||
The HTML entry-point of the project.
|
||||
Loads the `ReactJS` distribution script.
|
||||
Defines JavaScript functions to receive and send messages to the [PowerToys Settings](/src/editor) window.
|
||||
|
||||
#### [src/index.tsx](./src/index.tsx)
|
||||
#### [src/index.tsx](/src/settings-web/src/index.tsx)
|
||||
Main `ReactJS` entrypoint, initializing the `ReactDOM`.
|
||||
|
||||
#### [src/setup_icons.tsx](./src/setup_icons.tsx)
|
||||
#### [src/setup_icons.tsx](/src/settings-web/src/setup_icons.tsx)
|
||||
Defines the `setup_powertoys_icons` function that registers the icons to be used in the components.
|
||||
|
||||
#### [src/components/](./src/components/)
|
||||
#### [src/components/](/src/settings-web/src/components/)
|
||||
Contains the `ReactJS` components, including the Settings controls for each type of setting.
|
||||
|
||||
#### [src/components/App.tsx](./src/components/App.tsx)
|
||||
#### [src/components/App.tsx](/src/settings-web/src/components/App.tsx)
|
||||
Defines the main App component, containing the UI layout, navigation menu, dialogs and main load/save logic.
|
||||
|
||||
#### [src/components/GeneralSettings.tsx](./src/components/GeneralSettings.tsx)
|
||||
#### [src/components/GeneralSettings.tsx](/src/settings-web/src/components/GeneralSettings.tsx)
|
||||
Defines the PowerToys General Settings component, including logic to construct the object sent to PowerToys to change the General settings.
|
||||
|
||||
#### [src/components/ModuleSettings.tsx](./src/components/ModuleSettings.tsx)
|
||||
#### [src/components/ModuleSettings.tsx](/src/settings-web/src/components/ModuleSettings.tsx)
|
||||
Defines the component that generates the settings screen for a PowerToy depending on its settings definition.
|
||||
|
||||
#### [src/components/BaseSettingsControl.tsx](./src/components/BaseSettingsControl.tsx)
|
||||
#### [src/components/BaseSettingsControl.tsx](/src/settings-web/src/components/BaseSettingsControl.tsx)
|
||||
Defines the base class for a Settings control.
|
||||
|
||||
#### [src/css/layout.css](./src/css/layout.css)
|
||||
#### [src/css/layout.css](/src/settings-web/src/css/layout.css)
|
||||
General layout styles.
|
||||
|
||||
#### [src/icons/](./src/icons/)
|
||||
#### [src/icons/](/src/settings-web/src/icons/)
|
||||
Icons generated from the [Office UI Fabric Icons subset generation tool.](https://uifabricicons.azurewebsites.net/)
|
||||
|
||||
#### [src/svg/](./src/svg/)
|
||||
#### [src/svg/](/src/settings-web/src/svg/)
|
||||
SVG icon assets.
|
||||
|
||||
## Creating a new settings control
|
||||
|
||||
The [`BaseSettingsControl` class](./src/components/BaseSettingsControl.tsx) can be extended to create a new Settings control type.
|
||||
The [`BaseSettingsControl` class](/src/settings-web/src/components/BaseSettingsControl.tsx) can be extended to create a new Settings control type.
|
||||
|
||||
```tsx
|
||||
export class BaseSettingsControl extends React.Component <any, any> {
|
||||
@@ -92,7 +87,7 @@ export class BaseSettingsControl extends React.Component <any, any> {
|
||||
A settings control overrides the `get_value` function to return the value to be used for the Setting the control is representing.
|
||||
It will use the `parent_on_change` property to signal that the user made some changes to the settings.
|
||||
|
||||
Here's the [`StringTextSettingsControl`](./src/components/StringTextSettingsControl.tsx) component to serve as an example:
|
||||
Here's the [`StringTextSettingsControl`](/src/settings-web/src/components/StringTextSettingsControl.tsx) component to serve as an example:
|
||||
|
||||
```tsx
|
||||
export class StringTextSettingsControl extends BaseSettingsControl {
|
||||
@@ -153,8 +148,8 @@ Each settings property has a `editor_type` field that's used to differentiate be
|
||||
}
|
||||
```
|
||||
|
||||
A new Settings control component can be added to [`src/components/`](./src/components/).
|
||||
To render the new Settings control, its `editor_type` and component instance need to be added to the [`ModuleSettings` component render()](./src/components/ModuleSettings.tsx):
|
||||
A new Settings control component can be added to [`src/components/`](/src/settings-web/src/components/).
|
||||
To render the new Settings control, its `editor_type` and component instance need to be added to the [`ModuleSettings` component render()](/src/settings-web/src/components/ModuleSettings.tsx):
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import {StringTextSettingsControl} from './StringTextSettingsControl';
|
||||
287
doc/devdocs/settings.md
Normal file
@@ -0,0 +1,287 @@
|
||||
# Settings
|
||||
|
||||
## Overview
|
||||
|
||||
PowerToys provides a common framework for settings. It can be used to save and load settings on disk, and provides a user interface for changing the options.
|
||||
|
||||
## Initialization
|
||||
When a PowerToy module is created, it should load its configuration using [`PowerToyValues`](/src/common/settings_objects.h) class. The class provides static `load_from_settings_file` method which takes one parameter - the PowerToy module name. The `PowerToyValues` class provides methods to extract values. The method return `std::optional` - it is possible, that the method will return `std::nullopt` in which case you must use defaults.
|
||||
```c++
|
||||
class ExamplePowertoy : public PowertoyModuleIface
|
||||
{
|
||||
public:
|
||||
ExamplePowertoy()
|
||||
{
|
||||
auto settings = PowerToySettings::PowerToyValues::load_from_settings_file(L"Example Powertoy");
|
||||
// See if value is set, otherwise keep the default value
|
||||
if (auto int_value = settings.get_int_value(L"int_setting"))
|
||||
{
|
||||
m_int_setting = *int_value;
|
||||
}
|
||||
if (auto string_value = setting.get_string_value("string_setting"))
|
||||
{
|
||||
m_string_setting = *string_value;
|
||||
}
|
||||
}
|
||||
// ...
|
||||
private:
|
||||
// Settings and their default values
|
||||
int m_int_setting = 10;
|
||||
std::wstring m_string_setting = L"default";
|
||||
}
|
||||
```
|
||||
|
||||
## Settings screen
|
||||
When users starts the settings screen, the runner will call the [`get_config()`](modules/interface.md) method. The interface expects the method to fill provided buffer. Use the [`Settings`](/src/common/settings_objects.h) class to construct proper response with proper format. The class has helper method to set description and links fields, it also provides a way to define the content of the settings screen. Keep all the strings in the resource file and provide the resource IDs to the methods.
|
||||
```c++
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase; // Needed to get strings from the resource file
|
||||
|
||||
bool ExamplePowertoy::get_config(wchar_t* buffer, int* buffer_size)
|
||||
{
|
||||
PowerToySettings::Settings settings(reinterpret_cast<HINSTANCE>(&__ImageBase), L"Example Powertoy");
|
||||
// Set PowerToy description
|
||||
settings.set_description(IDS_POWERTOY_DESCRIPTION);
|
||||
settings.set_icon_key("pt_icon_key");
|
||||
settings.set_overview_link(IDS_POWERTOY_OVERVIEW_LINK);
|
||||
settings.set_video_link(IDS_POWERTOY_OVERVIEW_LINK);
|
||||
|
||||
// Add int and string settings, provide current values:
|
||||
settings.add_int_spinner(L"int_setting", IDS_INT_SETTING_DESCRIPTION, m_int_setting, 0, 100, 10);
|
||||
settings.add_string(L"string_setting", IDS_STRING_SETTING_DESCRIPTION, m_string_setting);
|
||||
|
||||
// Use the build-in machinery to return the configuration:
|
||||
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||
}
|
||||
```
|
||||
The list of all the available settings elements and their description is [further in this doc](#available-settings-elements). New PowerToy icons need to be [added to the `settings-web` project](https://github.com/microsoft/PowerToys/blob/master/doc/devdocs/settings-web.md#updating-the-icons).
|
||||
|
||||
## User changes settings
|
||||
When user closes the settings screen, the runner will call the [`get_config()`](modules/interface.md) method. Use [`PowerToyValues`](/src/common/settings_objects.h) class static `from_json_string` method to parse the settings. After that, the code is similar to loading the settings from disk:
|
||||
```c++
|
||||
void ExamplePowertoy::set_config(const wchar_t* config)
|
||||
{
|
||||
auto settings = PowerToySettings::PowerToyValues::from_json_string(config);
|
||||
// See if value is set update the values
|
||||
if (auto int_value = settings.get_int_value(L"int_setting"))
|
||||
{
|
||||
m_int_setting = *int_value;
|
||||
}
|
||||
if (auto string_value = setting.get_string_value("string_setting"))
|
||||
{
|
||||
m_string_setting = *string_value;
|
||||
}
|
||||
// Save the new settings to disk
|
||||
settings.save_to_settings_file();
|
||||
}
|
||||
```
|
||||
|
||||
## Detailed reference
|
||||
For a detailed reference of how the settings are implemented in the runner and in the settings editor, consult [this detailed guide](settings-reference.md).
|
||||
|
||||
# Available settings elements
|
||||
|
||||
## Bool toggle
|
||||
<table><tr><td align="center">
|
||||
<img src="../images/settings/bool_toggle.png" width="80%">
|
||||
</td></tr></table>
|
||||
|
||||
```c++
|
||||
settings.add_bool_toogle(name, description, value)
|
||||
```
|
||||
A simple on-off toggle. Parameters:
|
||||
* `name` - Key for the element in the JSON.
|
||||
* `description` - Resource ID of the text displayed to the user.
|
||||
* `value` - Initial state of the toggle (`true` - on, `false` - off).
|
||||
|
||||
The toggle value is stored as bool:
|
||||
```c++
|
||||
std::optional<bool> bool_value = settings.get_bool_value(L"bool_name");
|
||||
```
|
||||
|
||||
## Int Spinner
|
||||
<table><tr><td align="center">
|
||||
<img src="../images/settings/int_spinner.png" width="80%">
|
||||
</td></tr></table>
|
||||
|
||||
```c++
|
||||
settings.add_int_spinner(name, description, value, min, max, step)
|
||||
```
|
||||
Numeric input with dials to increment and decrement the value. Parameters:
|
||||
* `name` - Key for element in the JSON.
|
||||
* `description` - Resource ID of the text displayed to the user.
|
||||
* `value` - Initial control value.
|
||||
* `min`, `max` - Minimum and maximum values for the input. User cannot use dials to move beyond those values, if a value out of range is inserted using the keyboard, it will get clamped to the allowed range.
|
||||
* `step` - How much the dials change the value.
|
||||
|
||||
The spinner value is stored as int:
|
||||
```c++
|
||||
std::optional<int> int_value = settings.get_int_value(L"int_spinner_name");
|
||||
```
|
||||
|
||||
## String
|
||||
<table><tr><td align="center">
|
||||
<img src="../images/settings/string.png" width="80%">
|
||||
</td></tr></table>
|
||||
|
||||
```c++
|
||||
settings.add_string(name, description, value)
|
||||
```
|
||||
Single line text input. Parameters:
|
||||
* `name` - Key for element in the JSON.
|
||||
* `description` - Resource ID of the text displayed to the user.
|
||||
* `value` - Default value for the input.
|
||||
|
||||
The input value is stored as `std::wstring`:
|
||||
```c++
|
||||
std::optional<std::wstring> string_value = settings.get_string_value(L"string_name");
|
||||
```
|
||||
|
||||
## Multiline string
|
||||
<table><tr><td align="center">
|
||||
<img src="../images/settings/multiline.png" width="80%">
|
||||
</td></tr></table>
|
||||
|
||||
```c++
|
||||
settings.add_multiline_string(name, description, value)
|
||||
```
|
||||
Multiline text input. Parameters:
|
||||
* `name` - Key for element in the JSON.
|
||||
* `description` - Resource ID of the text displayed to the user.
|
||||
* `value` - Default value for the input. Can have multiple lines.
|
||||
|
||||
The input value is stored as string:
|
||||
```c++
|
||||
std::optional<std::wstring> value = settings.get_string_value(L"multiline_name");
|
||||
```
|
||||
|
||||
## Color picker
|
||||
<table><tr><td align="center">
|
||||
<img src="../images/settings/color_picker.png" width="80%">
|
||||
</td></tr></table>
|
||||
|
||||
```c++
|
||||
settings.add_color_picker(name, description, value)
|
||||
```
|
||||
|
||||
Allows user to pick a color. Parameters:
|
||||
* `name` - Key for element in the JSON.
|
||||
* `description` - Resource ID of the text displayed to the user.
|
||||
* `value` - Initial color, as a string in `"#RRGGBB"` format.
|
||||
|
||||
The color picker value is stored as `std::wstring` as `#RRGGBB`:
|
||||
```c++
|
||||
std::optional<std::wstring> value = settings.get_string_value(L"colorpicker_name");
|
||||
```
|
||||
|
||||
## Hotkey
|
||||
<table><tr><td align="center">
|
||||
<img src="../images/settings/hotkey.png" width="80%">
|
||||
</td></tr></table>
|
||||
|
||||
```c++
|
||||
settings.add_hotkey(name, description, hotkey)
|
||||
```
|
||||
Input for capturing hotkeys. Parameters:
|
||||
* `name` - Key for element in the JSON.
|
||||
* `description` - Resource ID of the text displayed to the user.
|
||||
* `hotkey` - Instance of `PowerToysSettings::HotkeyObject` class.
|
||||
|
||||
You can create `PowerToysSettings::HotkeyObject` object either by using helper `from_settings` static method or by providing a JSON object to `from_json` static method.
|
||||
|
||||
The `PowerToysSettings::HotkeyObject::from_settings` take following parameters:
|
||||
* `win_pressed` - Is the WinKey pressed.
|
||||
* `ctrl_pressed` - Is the Ctrl key pressed.
|
||||
* `alt_pressed` - Is the Alt key pressed.
|
||||
* `shift_pressed` - Is the Shift key pressed.
|
||||
* `vk_code` - The [virtual key-code](https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes) of the key.
|
||||
|
||||
The displayed key is deduced from the `vk_code` using the users keyboard layout and language settings.
|
||||
|
||||
The hotkey value is returned as JSON, which can be used with the `from_json` method to create a `HotkeyObject` object. A typical example of registering a hotkey:
|
||||
```c++
|
||||
std::optional<json::JsonObject> value = settings.get_json(L"hotkey_name");
|
||||
if (value) {
|
||||
auto hotkey = PowerToysSettings::HotkeyObject::from_json(*value);
|
||||
RegisterHotKey(hwnd, 1, hotkey.get_modifiers(), hotkey.get_code());
|
||||
}
|
||||
```
|
||||
|
||||
## Choice group
|
||||
<table><tr><td align="center">
|
||||
<img src="../images/settings/choice_group.png" width="80%">
|
||||
</td></tr></table>
|
||||
|
||||
```c++
|
||||
add_choice_group(name, description, value, vector<pair<wstring, UINT>> keys_and_texts)
|
||||
```
|
||||
A radio buttons group. Parameters:
|
||||
* `name` - Key for element in the JSON.
|
||||
* `description` - Resource ID of the text displayed to the user.
|
||||
* `value` - Key selected by default.
|
||||
* `keys_and_text` - Vector of radio buttons definitions: key and the displayed label.
|
||||
|
||||
|
||||
The chosen button value is stored as a string with the key of the button selected by the user:
|
||||
```c++
|
||||
std::optional<std::wstring> value = settings.get_string_value(L"choice_group_name");
|
||||
```
|
||||
|
||||
## Dropdown
|
||||
<table>
|
||||
<tr><td align="center">
|
||||
<img src="../images/settings/dropdown_1.png" width="80%">
|
||||
</td></tr>
|
||||
<tr><td align="center">
|
||||
<img src="../images/settings/dropdown_2.png" width="80%">
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
```c++
|
||||
add_dropdown(name, description, value, vector<pair<wstring, UINT>> keys_and_texts)
|
||||
```
|
||||
|
||||
A dropdown. Parameters:
|
||||
* `name` - Key for element in the JSON.
|
||||
* `description` - Resource ID of the text displayed to the user.
|
||||
* `value` - Key selected by default.
|
||||
* `keys_and_text` - Vector of the options definitions: key and the displayed label.
|
||||
|
||||
The chosen value is stored as a string with the key of the option selected by the user:
|
||||
```c++
|
||||
std::optional<std::wstring> value = settings.get_string_value(L"dropdown_name");
|
||||
```
|
||||
## Custom action
|
||||
<table><tr><td align="center">
|
||||
<img src="../images/settings/custom_action.png" width="80%">
|
||||
</td></tr></table>
|
||||
|
||||
```c++
|
||||
add_custom_action(name, description, button_text, ext_description)
|
||||
```
|
||||
|
||||
Adds a button with a description. Parameters:
|
||||
* `name` - Key for element in the JSON.
|
||||
* `description` - Resource ID of the text displayed to the user.
|
||||
* `button_text` - Resource ID for the button label.
|
||||
* `ext_description` - Resource ID for the extended description.
|
||||
|
||||
When the button is pressed, the `call_custom_action` method of the module will be called, with JSON containing the name of the action. Parse it using `PowerToysSettings::CustomActionObject`:
|
||||
```c++
|
||||
void ExamplePowertoy::call_custom_action(const wchar_t* action) override
|
||||
{
|
||||
auto action_object = PowerToysSettings::CustomActionObject::from_json_string(action);
|
||||
auto name = action_object.get_name(); // same value as the 'name' parameter
|
||||
// .. do stuff ..
|
||||
}
|
||||
```
|
||||
|
||||
# File organization
|
||||
|
||||
### [main.cpp](/src/settings/main.cpp)
|
||||
Contains the main executable code, initializing and managing the Window containing the WebView and communication with the main PowerToys executable.
|
||||
|
||||
### [StreamURIResolverFromFile.cpp](/src/settings/StreamURIResolverFromFile.cpp)
|
||||
Defines a class implementing `IUriToStreamResolver`. Allows the WebView to navigate to filesystem files in this Win32 project.
|
||||
|
||||
### [settings-html/](/src/settings/settings-html/)
|
||||
Contains the assets file from building the [Web project for the Settings UI](/src/settings./settings-web). It will be loaded by the WebView.
|
||||
@@ -1,85 +1,85 @@
|
||||
# Shared hooks
|
||||
|
||||
To minimize the performance impact on the machine only `runner` installs global hooks, passing the events to registered callbacks in each PowerToy module.
|
||||
|
||||
When a PowerToy module is loaded, the `runner` calls the [`get_events()`](/src/modules/interface/powertoy_module_interface.h#L40) method to get a NULL-terminated array of NULL-terminated strings with the names of the events that the PowerToy wants to subscribe to. A `const wchar_t*` string is provided for each of the event names.
|
||||
|
||||
Events are signalled by the `runner` calling the [`signal_event(name, data)`](/src/modules/interface/powertoy_module_interface.h#L53) method of the PowerToy module. The `name` parameter contains the NULL-terminated name of the event. The `data` parameter and the method return value are specific for each event.
|
||||
|
||||
Currently supported hooks:
|
||||
* `"ll_keyboard"` - [Low Level Keyboard Hook](#low-level-keyboard-hook)
|
||||
* `"win_hook_event"` - [Windows Event Hook](#windows-event-hook)
|
||||
|
||||
## Low Level Keyboard Hook
|
||||
|
||||
This event is signaled whenever the user presses or releases a key on the keyboard. To subscribe to this event, add `"ll_keyboard"` to the table returned by the `get_events()` method.
|
||||
|
||||
The PowerToys runner installs low-level keyboard hook using `SetWindowsHookEx(WH_KEYBOARD_LL, ...)`. See [this MSDN page](https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms644985(v%3Dvs.85)) for details.
|
||||
|
||||
When a keyboard event is signaled and `ncCode` equals `HC_ACTION`, the `wParam` and `lParam` event parameters are passed to all subscribed clients in the [`LowlevelKeyboardEvent`](/src/modules/interface/lowlevel_keyboard_event_data.h#L38-L41) struct.
|
||||
|
||||
The `intptr_t data` event argument is a pointer to the `LowlevelKeyboardEvent` struct.
|
||||
|
||||
A non-zero return value from any of the subscribed PowerToys will cause the runner hook proc to return 1, thus swallowing the keyboard event.
|
||||
|
||||
Example usage, that makes Windows ignore the L key:
|
||||
|
||||
```c++
|
||||
virtual const wchar_t** get_events() override {
|
||||
static const wchar_t* events[2] = { ll_keyboard,
|
||||
nullptr };
|
||||
return events;
|
||||
}
|
||||
|
||||
virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override {
|
||||
if (wcscmp(name, ll_keyboard) == 0) {
|
||||
auto& event = *(reinterpret_cast<LowlevelKeyboardEvent*>(data));
|
||||
// The L key has vkCode of 0x4C, see:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
if (event.wParam == WM_KEYDOWN && event.lParam->vkCode == 0x4C) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Windows Event Hook
|
||||
|
||||
This event is signaled for [a range of events](https://docs.microsoft.com/pl-pl/windows/win32/winauto/event-constants). To subscribe to this event, add `"win_hook_event"` to the table returned by the `get_events()` method. See [this MSDN doc](https://docs.microsoft.com/pl-pl/windows/win32/api/winuser/nf-winuser-setwineventhook) for details.
|
||||
|
||||
The `intptr_t data` event argument is a pointer to the [`WinHookEvent`](/src/modules/interface/win_hook_event_data.h#L43-L50) struct.
|
||||
|
||||
The return value of the event handler is ignored.
|
||||
|
||||
Example usage, that detects a window being resized:
|
||||
|
||||
```c++
|
||||
virtual const wchar_t** get_events() override {
|
||||
static const wchar_t* events[2] = { win_hook_event,
|
||||
nullptr };
|
||||
return events;
|
||||
}
|
||||
|
||||
virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override {
|
||||
if (wcscmp(name, win_hook_event) == 0) {
|
||||
auto& event = *(reinterpret_cast<WinHookEvent*>(data));
|
||||
switch (event.event) {
|
||||
case EVENT_SYSTEM_MOVESIZESTART:
|
||||
size_start(event.hwnd);
|
||||
break;
|
||||
case EVENT_SYSTEM_MOVESIZEEND:
|
||||
size_end(event.hwnd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Taking too long to process the events has negative impact on the whole system performance. To address this, the events are signaled from a different thread, not from the event hook callback itself.
|
||||
# Shared hooks
|
||||
|
||||
To minimize the performance impact on the machine only `runner` installs global hooks, passing the events to registered callbacks in each PowerToy module.
|
||||
|
||||
When a PowerToy module is loaded, the `runner` calls the [`get_events()`](/src/modules/interface/powertoy_module_interface.h#L40) method to get a NULL-terminated array of NULL-terminated strings with the names of the events that the PowerToy wants to subscribe to. A `const wchar_t*` string is provided for each of the event names.
|
||||
|
||||
Events are signalled by the `runner` calling the [`signal_event(name, data)`](/src/modules/interface/powertoy_module_interface.h#L53) method of the PowerToy module. The `name` parameter contains the NULL-terminated name of the event. The `data` parameter and the method return value are specific for each event.
|
||||
|
||||
Currently supported hooks:
|
||||
* `"ll_keyboard"` - [Low Level Keyboard Hook](#low-level-keyboard-hook)
|
||||
* `"win_hook_event"` - [Windows Event Hook](#windows-event-hook)
|
||||
|
||||
## Low Level Keyboard Hook
|
||||
|
||||
This event is signaled whenever the user presses or releases a key on the keyboard. To subscribe to this event, add `"ll_keyboard"` to the table returned by the `get_events()` method.
|
||||
|
||||
The PowerToys runner installs low-level keyboard hook using `SetWindowsHookEx(WH_KEYBOARD_LL, ...)`. See [this MSDN page](https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms644985(v%3Dvs.85)) for details.
|
||||
|
||||
When a keyboard event is signaled and `ncCode` equals `HC_ACTION`, the `wParam` and `lParam` event parameters are passed to all subscribed clients in the [`LowlevelKeyboardEvent`](/src/modules/interface/lowlevel_keyboard_event_data.h#L38-L41) struct.
|
||||
|
||||
The `intptr_t data` event argument is a pointer to the `LowlevelKeyboardEvent` struct.
|
||||
|
||||
A non-zero return value from any of the subscribed PowerToys will cause the runner hook proc to return 1, thus swallowing the keyboard event.
|
||||
|
||||
Example usage, that makes Windows ignore the L key:
|
||||
|
||||
```c++
|
||||
virtual const wchar_t** get_events() override {
|
||||
static const wchar_t* events[2] = { ll_keyboard,
|
||||
nullptr };
|
||||
return events;
|
||||
}
|
||||
|
||||
virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override {
|
||||
if (wcscmp(name, ll_keyboard) == 0) {
|
||||
auto& event = *(reinterpret_cast<LowlevelKeyboardEvent*>(data));
|
||||
// The L key has vkCode of 0x4C, see:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
if (event.wParam == WM_KEYDOWN && event.lParam->vkCode == 0x4C) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Windows Event Hook
|
||||
|
||||
This event is signaled for [a range of events](https://docs.microsoft.com/pl-pl/windows/win32/winauto/event-constants). To subscribe to this event, add `"win_hook_event"` to the table returned by the `get_events()` method. See [this MSDN doc](https://docs.microsoft.com/pl-pl/windows/win32/api/winuser/nf-winuser-setwineventhook) for details.
|
||||
|
||||
The `intptr_t data` event argument is a pointer to the [`WinHookEvent`](/src/modules/interface/win_hook_event_data.h#L43-L50) struct.
|
||||
|
||||
The return value of the event handler is ignored.
|
||||
|
||||
Example usage, that detects a window being resized:
|
||||
|
||||
```c++
|
||||
virtual const wchar_t** get_events() override {
|
||||
static const wchar_t* events[2] = { win_hook_event,
|
||||
nullptr };
|
||||
return events;
|
||||
}
|
||||
|
||||
virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override {
|
||||
if (wcscmp(name, win_hook_event) == 0) {
|
||||
auto& event = *(reinterpret_cast<WinHookEvent*>(data));
|
||||
switch (event.event) {
|
||||
case EVENT_SYSTEM_MOVESIZESTART:
|
||||
size_start(event.hwnd);
|
||||
break;
|
||||
case EVENT_SYSTEM_MOVESIZEEND:
|
||||
size_end(event.hwnd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Taking too long to process the events has negative impact on the whole system performance. To address this, the events are signaled from a different thread, not from the event hook callback itself.
|
||||
12
doc/devdocs/style.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# Coding Style
|
||||
|
||||
## Philosophy
|
||||
1. If it's inserting something into the existing classes/functions, try to follow the existing style as closely as possible.
|
||||
1. If it's brand new code or refactoring a complete class or area of the code, please follow as Modern C++ of a style as you can and reference the [C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines) as much as you possibly can.
|
||||
|
||||
## Formatting
|
||||
|
||||
- We use [`.clang-format`](https://github.com/microsoft/PowerToys/blob/master/.clang-format) style file to enable automatic code formatting. You can [easily format source files from Visual Studio](https://devblogs.microsoft.com/cppblog/clangformat-support-in-visual-studio-2017-15-7-preview-1/). For example, `CTRL+K CTRL+D` formats the current document.
|
||||
- If you prefer another text editor or have ClangFormat disabled in Visual Studio, you could invoke [`format_sources`](https://github.com/microsoft/PowerToys/blob/master/format_sources.ps1) powershell script from command line. It gets a list of all currently modified files from `git` and invokes clang-format on them.
|
||||
Please note that you should also have `clang-format.exe` in `%PATH%` for it to work. The script can infer the path of `clang-format.exe` version which is shipped with Visual Studio at `%VCINSTALLDIR%\Tools\Llvm\bin\`, if you launch it from the *Native Tools Command Prompt for VS*.
|
||||
- CI doesn't enforce code formatting yet, since we're gradually applying code formatting to the codebase, but please adhere to our formatting style for any new code.
|
||||
BIN
doc/images/Logo-HiRes.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
30
doc/images/Logo.svg
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="176px" height="60px" viewBox="0 0 176 60" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 54.1 (76490) - https://sketchapp.com -->
|
||||
<title>Microsoft PowerToys</title>
|
||||
<desc>Logo for Microsoft PowerToys</desc>
|
||||
<g id="Devices" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Final-Logo" transform="translate(-309.000000, -228.000000)">
|
||||
<g id="Group" transform="translate(309.000000, 228.000000)">
|
||||
<g id="Group-2-Copy-7">
|
||||
<rect id="Rectangle-Copy-40" fill="#E4292E" x="12.3529412" y="8.82352941" width="7" height="21.1764706"></rect>
|
||||
<rect id="Rectangle-Copy-41" fill="#E76643" x="19" y="8.82352941" width="7" height="21.1764706"></rect>
|
||||
<rect id="Rectangle-Copy-42" fill="#F4C81D" x="26" y="8.82352941" width="7" height="21.1764706"></rect>
|
||||
<rect id="Rectangle-Copy-43" fill="#4EB445" x="33" y="8.82352941" width="7" height="21.1764706"></rect>
|
||||
<rect id="Rectangle-Copy-50" fill="#02A3E8" x="40" y="8.82352941" width="7" height="21.1764706"></rect>
|
||||
<rect id="Rectangle-Copy-44" fill="#D6CDB2" x="12.3529412" y="33.5294118" width="7.05882353" height="7.05882353"></rect>
|
||||
<rect id="Rectangle-Copy-45" fill="#D6CDB2" x="26.4705882" y="33.5294118" width="7.05882353" height="7.05882353"></rect>
|
||||
<rect id="Rectangle-Copy-46" fill="#D6CDB2" x="40.5882353" y="33.5294118" width="7.05882353" height="7.05882353"></rect>
|
||||
<rect id="Rectangle-Copy-47" fill="#D6CDB2" x="12.3529412" y="44.1176471" width="7.05882353" height="7.05882353"></rect>
|
||||
<rect id="Rectangle-Copy-48" fill="#D6CDB2" x="26.4705882" y="44.1176471" width="7.05882353" height="7.05882353"></rect>
|
||||
<rect id="Rectangle-Copy-49" fill="#D6CDB2" x="40.5882353" y="44.1176471" width="7.05882353" height="7.05882353"></rect>
|
||||
<polygon id="Line-5-Copy-13" fill="#D6CDB2" fill-rule="nonzero" points="3.52941176 3.52941176 3.52941176 0 56.4705882 0 56.4705882 3.52941176"></polygon>
|
||||
<polygon id="Line-5-Copy-14" fill="#D6CDB2" fill-rule="nonzero" points="3.52941176 60 3.52941176 56.4705882 56.4705882 56.4705882 56.4705882 60"></polygon>
|
||||
<polygon id="Line-5-Copy-15" fill="#D6CDB2" fill-rule="nonzero" transform="translate(58.235294, 30.000000) rotate(-270.000000) translate(-58.235294, -30.000000) " points="31.7647059 31.7647059 31.7647059 28.2352941 84.7058824 28.2352941 84.7058824 31.7647059"></polygon>
|
||||
<polygon id="Line-5-Copy-16" fill="#D6CDB2" fill-rule="nonzero" transform="translate(1.764706, 30.000000) rotate(-270.000000) translate(-1.764706, -30.000000) " points="-24.7058824 31.7647059 -24.7058824 28.2352941 28.2352941 28.2352941 28.2352941 31.7647059"></polygon>
|
||||
</g>
|
||||
<path d="M87.9970703,10.0039062 L87.9970703,6 L79.9990234,6 L79.9990234,10.0039062 L87.9970703,10.0039062 Z M76,26 L76,2.00097656 L91.9960938,2.00097656 L91.9960938,14.0029297 L79.9990234,14.0029297 L79.9990234,26 L76,26 Z M99.9990234,26 L99.9990234,22.0009766 L107.99707,22.0009766 L107.99707,26 L99.9990234,26 Z M96,22.0009766 L96,10.0039062 L99.9990234,10.0039062 L99.9990234,22.0009766 L96,22.0009766 Z M107.99707,22.0009766 L107.99707,10.0039062 L111.996094,10.0039062 L111.996094,22.0009766 L107.99707,22.0009766 Z M99.9990234,10.0039062 L99.9990234,6 L107.99707,6 L107.99707,10.0039062 L99.9990234,10.0039062 Z M119.999023,26 L119.999023,22.0009766 L123.998047,22.0009766 L123.998047,26 L119.999023,26 Z M127.99707,26 L127.99707,22.0009766 L131.996094,22.0009766 L131.996094,26 L127.99707,26 Z M123.998047,22.0009766 L123.998047,14.0029297 L127.99707,14.0029297 L127.99707,22.0009766 L123.998047,22.0009766 Z M116,22.0009766 L116,6 L119.999023,6 L119.999023,22.0009766 L116,22.0009766 Z M131.996094,22.0009766 L131.996094,6 L136,6 L136,22.0009766 L131.996094,22.0009766 Z M151.996094,14.0029297 L151.996094,10.0039062 L143.998047,10.0039062 L143.998047,14.0029297 L151.996094,14.0029297 Z M143.996094,10.0029297 L143.996094,6.00390625 L139.996094,6.00390625 L139.996094,10.0029297 L143.996094,10.0029297 Z M139.999023,26 L139.999023,6 L155.995117,6 L155.995117,18.0019531 L143.998047,18.0019531 L143.998047,22.0009766 L155.995117,22.0009766 L155.995117,26 L139.999023,26 Z M159.999023,26 L159.999023,6 L175.995117,6 L175.995117,10.0039062 L163.998047,10.0039062 L163.998047,26 L159.999023,26 Z M83.9980469,56 L83.9980469,36 L76,36 L76,32.0009766 L96,32.0009766 L96,36 L87.9970703,36 L87.9970703,56 L83.9980469,56 Z M103.998047,56 L103.998047,52.0009766 L111.996094,52.0009766 L111.996094,56 L103.998047,56 Z M99.9990234,52.0009766 L99.9990234,40.0039062 L103.998047,40.0039062 L103.998047,52.0009766 L99.9990234,52.0009766 Z M111.996094,52.0009766 L111.996094,40.0039062 L115.995117,40.0039062 L115.995117,52.0009766 L111.996094,52.0009766 Z M103.998047,40.0039062 L103.998047,36 L111.996094,36 L111.996094,40.0039062 L103.998047,40.0039062 Z M119.999023,56 L119.999023,52.0009766 L131.996094,52.0009766 L131.996094,48.0019531 L119.999023,48.0019531 L119.999023,36 L123.998047,36 L123.998047,44.0029297 L131.996094,44.0029297 L131.996094,36 L135.995117,36 L135.995117,56 L119.999023,56 Z M139.999023,56 L139.999023,52.0009766 L151.996094,52.0009766 L151.996094,48.0019531 L139.999023,48.0019531 L139.999023,36 L155.995117,36 L155.995117,40.0039062 L143.998047,40.0039062 L143.998047,44.0029297 L155.995117,44.0029297 L155.995117,56 L139.999023,56 Z" id="PowerToys-Copy-2" fill="#D6CDB2" fill-rule="nonzero"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.7 KiB |
BIN
doc/images/settings/bool_toggle.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
doc/images/settings/choice_group.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
doc/images/settings/color_picker.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
doc/images/settings/custom_action.png
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
doc/images/settings/dropdown_1.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
doc/images/settings/dropdown_2.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
doc/images/settings/general_settings.png
Normal file
|
After Width: | Height: | Size: 97 KiB |
BIN
doc/images/settings/hotkey.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
doc/images/settings/int_spinner.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
doc/images/settings/multiline.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
doc/images/settings/shorcut_guide_settings.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
doc/images/settings/string.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
@@ -6,7 +6,6 @@ The list below is the set of utilities we're considering and the rough priority
|
||||
|
||||
* Maximize to new desktop widget - The MTND widget shows a pop-up button when a user hovers over the maximize / restore button on any window. Clicking it creates a new desktop, sends the app to that desktop and maximizes the app on the new desktop.
|
||||
* [Process terminate tool](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/Terminate%20Spec.md)
|
||||
* [Batch file renamer](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/File%20Classification%20Spec.md)
|
||||
* [Animated gif screen recorder](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/GIF%20Maker%20Spec.md)
|
||||
|
||||
## Backlog
|
||||
|
||||
18
doc/specs/FancyZones-DCR.md
Normal file
@@ -0,0 +1,18 @@
|
||||
### FancyZones library brief overview
|
||||
---
|
||||
|
||||
1. `Zone` - Class which is basically wrapper around rectangle structure, representing one zone inside applied zone layout. ZoneSet is holding array of these which represent zone layout.
|
||||
2. `ZoneSet` - Class implementing actual zone layout applied. What this means is that ZoneSet is responsible for actual calculation of rectangle coordinates (whether is grid or canvas layout) and moving window through them. ZoneWindow holds ZoneSet structure which represents currently active zone set.
|
||||
3. `ZoneWindow` - Class representing work area, which is defined by monitor and current virtual desktop. For an example, if You have two monitors connected and two virtual desktops, You have 4 work areas available, and each of them can have separate zone layout. ZoneWindow is describing single work area. As mentioned before it holds active ZoneSet.
|
||||
4. `FancyZones` - Top level entity and entry point for all user actions (which goes through actual module interface). Some of the main responsibilities of FancyZones class:
|
||||
|
||||
1. Starting FancyZones Editor (C#) with appropriate command line arguments on user request.
|
||||
2. Keeping track of ZoneWindow per monitor (currently active work area on each connected monitor).
|
||||
3. Keeping track of active virtual desktops. This is performed in separate thread by polling VirtualDesktopIDs registry key and parsing its content.
|
||||
4. Detecting every change in work environment, such as creating / destroying / switching between virtual desktops, closing FancyZones Editor, changing display settings and handling those changes.
|
||||
|
||||
### Proposal for modifications of handling described in 4.4:
|
||||
|
||||
Currently after each of the mentioned changes in work environment we are calling EnumDisplayMonitors windows API, and passing callback function to it. EnumDisplayMonitors works asynchronous and triggers that callback for each work area available (as mentioned in previous example, for two monitors and two virtual desktops, we have this callback triggered four times). As mentioned previously, we have ZoneWindow class as our representation of this work area. And what we do, every time this callback is triggered we destroy previous ZoneWindow object for that work area and create new one, even though that it is most likely that nothing has changed (e.g. just switching back and forth between virtual desktops). This constant creation and deletion of ZoneWindow has caused some problems in the past and it's not ideal for some other fixes we would like to make in the multi-monitor/multi-desktop scenario.
|
||||
|
||||
As mentioned in 4.3 we already have tracker of virtual desktops implemented. Idea is to use this functionality and to extend it bit more, so we can track if work area (ZoneWindow) is new one, or already processed and skip creating new ZoneWindow objects and deleting old ones every time, even if nothing changed in it. We will keep map, where virtual desktop id is the key, and values are already processed monitors (virtual desktop exists across all monitors). Once we receive callback from EnumDisplayMonitors, indicating work area (defined by virtual desktop id and monitor) we can check if it’s new or not, and act accordingly (create new ZoneWindow for it or not). Deleting virtual desktop (which is also registered in 4.3), will trigger updates in this map, and also updates in our JSON storage.
|
||||
@@ -1,215 +0,0 @@
|
||||
# FancyZones
|
||||
|
||||
## FancyZones
|
||||
FancyZones is the base class that runs the show. It uses hooks to monitor for windows entering and exiting the move/size loop and to listen for key presses for hotkey interception. For every connected display, it creates a ZoneWindow which is used to display the active ZoneSet per monitor for use when editing the layout or displaying the drop targets. A ZoneSet is composed of one or more Zones which are the locations where windows can be easily positioned.
|
||||
|
||||
### SetWinEventHook
|
||||
The main driving force behind FancyZones is the accessibility hook used to know when a window enters the move/size loop. It listens for EVENT_SYSTEM_MOVESIZESTART, EVENT_SYSTEM_MOVESIZEEND, and EVENT_OBJECT_LOCATIONCHANGE. For each of these three events, it forwards on to the ZoneWindow associated with the monitor that the window being dragged is currently on.
|
||||
|
||||
### Keyboard Hook
|
||||
A low-level keyboard hook is installed in order to, optionally, intercept Window+Arrow hotkeys. Traditionally, Win+Left/Right arrow will move a window between Windows Snap regions. This hook allows FancyZones to use Win+Left/Right arrow to move windows between Zones.
|
||||
The hook also allows using 0-9 to change the active ZoneSet during a drag operation.
|
||||
|
||||
### Display Changes
|
||||
During initial standup, FancyZones creates a ZoneWindow for each connected monitor. When it receives a WM_DISPLAYCHANGE, it updates the available ZoneWindows to reflect the state of the system (eg add a new ZoneWindow for newly connected monitor, delete ZoneWindow for disconnected monitor, etc)
|
||||
|
||||
### Interface
|
||||
```
|
||||
interface IFancyZones : public IUnknown
|
||||
{
|
||||
// Returns the main application window
|
||||
IFACEMETHOD_(HWND, GetWindow)() = 0;
|
||||
|
||||
// Returns the global HINSTANCE for the process
|
||||
IFACEMETHOD_(HINSTANCE, GetHInstance)() = 0;
|
||||
|
||||
// Returns the global Settings object used to look up individual settings throughout the product
|
||||
IFACEMETHOD_(Settings, GetSettings)() = 0;
|
||||
|
||||
// Used in WinMain to initialize FancyZones and enter the message loop
|
||||
IFACEMETHOD_(void, Run)() = 0;
|
||||
|
||||
// Toggles the visibility of all ZoneWindows
|
||||
IFACEMETHOD_(void, ToggleZoneViewers)() = 0;
|
||||
|
||||
// Shows a single ZoneWindow in editor mode on the provided monitor
|
||||
IFACEMETHOD_(void, ShowZoneEditorForMonitor)(_In_ HMONITOR monitor) = 0;
|
||||
|
||||
// Returns true if we are currently detecting a movesize loop
|
||||
IFACEMETHOD_(bool, InMoveSize)() = 0;
|
||||
|
||||
// Called by the event hook in response to EVENT_SYSTEM_MOVESIZESTART
|
||||
IFACEMETHOD(MoveSizeEnter)(_In_ HWND window, _In_ HMONITOR monitor, POINT ptScreen) = 0;
|
||||
|
||||
// Called by the event hook in response to EVENT_SYSTEM_MOVESIZEEND
|
||||
IFACEMETHOD(MoveSizeExit)(_In_ HWND window, POINT ptScreen) = 0;
|
||||
|
||||
// Called by the event hook in response to EVENT_OBJECT_LOCATIONCHANGE
|
||||
IFACEMETHOD(MoveSizeUpdate)(_In_ HMONITOR monitor, POINT ptScreen) = 0;
|
||||
|
||||
// Called during startup or on WM_DISPLAYCHANGE to add a ZoneWindow to the collection
|
||||
// There will be one ZoneWindow per connected monitor
|
||||
IFACEMETHOD(AddZoneWindow)(_In_ IZoneWindow* zoneWindow, _In_ HMONITOR monitor) = 0;
|
||||
|
||||
// Called in response to WM_DISPLAYCHANGE from the main application window
|
||||
IFACEMETHOD_(void, OnDisplayChange)(DisplayChangeType changeType) = 0;
|
||||
|
||||
// Used to move the specified HWND into Zone
|
||||
// The ZoneSet used is found by looking up the monitor that window is currently on
|
||||
// This gets called to keep windows in their current zones after a WM_DISPLAYCHANGE
|
||||
IFACEMETHOD_(void, MoveWindowIntoZoneByIndex)(_In_ HWND window, int index) = 0;
|
||||
|
||||
// Used to filter out windows that the hook should not be processing
|
||||
// Currently checks if the window's GWL_STYLE has WS_MAXIMIZEBOX
|
||||
IFACEMETHOD_(bool, IsInterestingWindow)(_In_ HWND window) = 0;
|
||||
|
||||
// Called byt the event hook in response to EVENT_OBJECT_NAMECHANGE on the Desktop window
|
||||
// The accessible name of the desktop window changes when the current virtual desktop changes
|
||||
IFACEMETHOD_(void, VirtualDesktopChanged)() = 0;
|
||||
|
||||
// Returns the GUID of the current active virtual desktop
|
||||
IFACEMETHOD_(GUID, GetCurrentVirtualDesktopId)() = 0;
|
||||
|
||||
// Called by the LL keyboard hook
|
||||
// Used to override snap hotkeys and to change the active ZoneSet during a drag
|
||||
IFACEMETHOD_(bool, OnKeyDown)(LPARAM lparam) = 0;
|
||||
|
||||
// Keep windows positioned inside their zones when the active ZoneSet changes
|
||||
IFACEMETHOD_(void, MoveWindowsOnActiveZoneSetChange)() = 0;
|
||||
};
|
||||
```
|
||||
|
||||
## ZoneWindow
|
||||
ZoneWindow is used to display the Zones a user can drop a window in during a drag operation, flash the Zones when the ZoneSet changes, and draw the Zone Editor UI when in edit mode. Basically, when a ZoneSet needs to be visualized, ZoneWindow does it.
|
||||
|
||||
### Interface
|
||||
```
|
||||
interface IZoneWindow : public IUnknown
|
||||
{
|
||||
// Shows the ZoneWindow
|
||||
// If activate is true, set foreground to the window otherwise just show
|
||||
IFACEMETHOD(ShowZoneWindow)(bool activate) = 0;
|
||||
|
||||
// Hide the ZoneWindow
|
||||
IFACEMETHOD(HideZoneWindow)() = 0;
|
||||
|
||||
// Called when the drag enters the monitor this ZoneWindow is assigned to
|
||||
IFACEMETHOD(MoveSizeEnter)(_In_ HWND window, POINT ptScreen, DragMode dragMode) = 0;
|
||||
|
||||
// Called when the drag exits the monitor
|
||||
IFACEMETHOD(MoveSizeExit)(_In_ HWND window, POINT ptScreen) = 0;
|
||||
|
||||
// Called when the drag updates position on this monitor
|
||||
IFACEMETHOD(MoveSizeUpdate)(POINT ptScreen, DragMode dragMode) = 0;
|
||||
|
||||
// Called when a drag ends and the window is not dropped in a Zone
|
||||
IFACEMETHOD(MoveSizeCancel)() = 0;
|
||||
|
||||
// Returns the DragMode of the current drag operation
|
||||
// DragMode allows for overriding drag behavior via settings or via hotkey
|
||||
IFACEMETHOD_(DragMode, GetDragMode)() = 0;
|
||||
|
||||
// Part of the chain to move a window into a specific Zone
|
||||
IFACEMETHOD_(void, MoveWindowIntoZoneByIndex)(_In_ HWND window, int index) = 0;
|
||||
|
||||
// Used to cycle a window between zones via the hijacked snap hotkeys
|
||||
IFACEMETHOD_(void, MoveWindowIntoZoneByDirection)(_In_ HWND window, DWORD vkCode) = 0;
|
||||
|
||||
// Called in response to WM_DISPLAYCHANGE
|
||||
// Allows cleanup, if necessary, since ZoneWindow will be destroyed shortly thereafter
|
||||
IFACEMETHOD_(void, OnDisplayChange)(DisplayChangeType type) = 0;
|
||||
|
||||
// Allows changing the active ZoneSet via key press either during a drag or while the ZoneWindow is in foreground
|
||||
IFACEMETHOD_(void, CycleActiveZoneSet)(DWORD vkCode) = 0;
|
||||
};
|
||||
```
|
||||
|
||||
## ZoneSet
|
||||
Collection of one or more Zones. Only one ZoneSet is active at a time per monitor.
|
||||
|
||||
### Interface
|
||||
```
|
||||
interface IZoneSet : public IUnknown
|
||||
{
|
||||
// Gets the unique ID used to identify this ZoneSet
|
||||
IFACEMETHOD_(GUID, GetId)() = 0;
|
||||
|
||||
// Adds a Zone to the collection
|
||||
IFACEMETHOD(AddZone)(_In_ Microsoft::WRL::ComPtr<IZone> zone, bool front) = 0;
|
||||
|
||||
// Removes a Zone from the collection
|
||||
IFACEMETHOD(RemoveZone)(_In_ Microsoft::WRL::ComPtr<IZone> zone) = 0;
|
||||
|
||||
// Returns the topmost Zone at the given point
|
||||
IFACEMETHOD_(Microsoft::WRL::ComPtr<IZone>, ZoneFromPoint)(POINT pt) = 0;
|
||||
|
||||
// Returns a Zone that the window is in
|
||||
// Will return nullptr if the window is not in a Zone
|
||||
IFACEMETHOD_(Microsoft::WRL::ComPtr<IZone>, ZoneFromWindow)(_In_ HWND window) = 0;
|
||||
|
||||
// Gets all the Zones
|
||||
IFACEMETHOD_(std::vector<Microsoft::WRL::ComPtr<IZone>>, GetZones)() = 0;
|
||||
|
||||
// ZoneSetLayout
|
||||
// * Grid - Pregenerated layout (2x2, 3x3, etc)
|
||||
// * Row - Pregenerated layout in a single row
|
||||
// * Focus - Pregenerated layout with a central focus Zone and fanned peripheral Zones
|
||||
// * Custom - User generated Zone
|
||||
IFACEMETHOD_(ZoneSetLayout, GetLayout)() = 0;
|
||||
|
||||
// The amount of default padding between Zones in a generated layout
|
||||
IFACEMETHOD_(int, GetInnerPadding)() = 0;
|
||||
|
||||
// Makes a copy of the IZoneSet and marks it as ZoneSetLayout::Custom
|
||||
IFACEMETHOD_(Microsoft::WRL::ComPtr<IZoneSet>, MakeCustomClone)() = 0;
|
||||
|
||||
// Persists ZoneSet data to the registry
|
||||
IFACEMETHOD_(void, Save)() = 0;
|
||||
|
||||
// Moves a Zone to the front of the collection
|
||||
IFACEMETHOD_(void, MoveZoneToFront)(_In_ Microsoft::WRL::ComPtr<IZone> zone) = 0;
|
||||
|
||||
// Moves a Zone to the back of the collection
|
||||
IFACEMETHOD_(void, MoveZoneToBack)(_In_ Microsoft::WRL::ComPtr<IZone> zone) = 0;
|
||||
|
||||
// Part of the chain to move a window into a specific Zone
|
||||
IFACEMETHOD_(void, MoveWindowIntoZoneByIndex)(_In_ HWND window, _In_ HWND zoneWindow, int index) = 0;
|
||||
|
||||
// Part of the chain to move a window into a specific Zone
|
||||
IFACEMETHOD_(void, MoveWindowIntoZoneByDirection)(_In_ HWND window, _In_ HWND zoneWindow, DWORD vkCode) = 0;
|
||||
|
||||
// Called when a drag ends or leaves the monitor this ZoneWindow is on
|
||||
// This will remove the window from its currently assigned Zone and assign it
|
||||
// to a different Zone based on the current cursor position
|
||||
IFACEMETHOD_(void, MoveSizeExit)(_In_ HWND window, _In_ HWND zoneWindow, _In_ POINT ptClient) = 0;
|
||||
};
|
||||
```
|
||||
|
||||
## Zone
|
||||
Basically a RECT and a map of HWND->RECT to keep track of where windows can be placed and which windows are currently in the Zone.
|
||||
|
||||
### Interface
|
||||
```
|
||||
interface IZone : public IUnknown
|
||||
{
|
||||
// Returns the RECT that this Zone represents
|
||||
IFACEMETHOD_(RECT, GetZoneRect)() = 0;
|
||||
|
||||
// Returns true if the specified window is in this Zone's collection
|
||||
IFACEMETHOD_(bool, ContainsWindow)(_In_ HWND window) = 0;
|
||||
|
||||
// Adds the window the collection
|
||||
IFACEMETHOD_(void, AddWindowToZone)(_In_ HWND window, _In_ HWND zoneWindow, bool stampZone) = 0;
|
||||
|
||||
// Removes the window from the collection
|
||||
IFACEMETHOD_(void, RemoveWindowFromZone)(_In_ HWND window, bool restoreSize) = 0;
|
||||
|
||||
// Sets an id for this Zone
|
||||
// The id will be unique per ZoneSet
|
||||
IFACEMETHOD_(void, SetId)(size_t id) = 0;
|
||||
|
||||
// Returns the id given to this Zone
|
||||
IFACEMETHOD_(size_t, GetId)() = 0;
|
||||
};
|
||||
```
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
# Power Toys Settings Framework and Core Infrastructure
|
||||
The Power Toys app will have a settings framework that each Power Toy can plug into. The settings framework has a UI frame that creates a page for each Power Toy. The UI frame should use the Navigation View “hamburger” UI. Each Power Toy will represent its settings as a json blob as described below.
|
||||
|
||||
Each Power Toy will live in a separate .dll and be run in a separate thread by the main Power Toys process. The main Power Toys .exe will expose key global Windows event handlers so that there is only one system-level hook for these critical events. The current set of Power Toys require these global events. This list will be amended as new Power Toys are authored that require additional global hooks.
|
||||
* SetWinEventHook - FancyZones requires knowledge of when a window enters the move/size loop. It listens for EVENT_SYSTEM_MOVESIZESTART, EVENT_SYSTEM_MOVESIZEEND, and EVENT_OBJECT_LOCATIONCHANGE messages from SetWinEventHook.
|
||||
* Low-level keyboard hook - The Windows key Shortcut Guide and FancyZones both require low-level keybord hooks to intercept keyboard input and get a first chance to process it. Other Power Toys will require this as well
|
||||
|
||||
* Each Power Toy must listen for 4 events:
|
||||
* Enable – When invoked, enables the Power Toys’ functionality and performs any necessary initialization. Invoked with a JSON string from the persisted settings store
|
||||
* Disable – When invoked, disables the Power Toys’ functionality and performs any clean-up to suspend all resource use
|
||||
* OutputSettings – Return a json serialized blob of the settings for the Power Toy
|
||||
* InputSettings – Invoked with a JSON string with updated settings from the UI which is then deserialized and the state is applied. If the settings cannot be applied by the Power Toy, the PT must return an error and an error string for the end user
|
||||
* Each Power Toy may optionally provide one or more custom configuration UIs that can be invoked from its settings page
|
||||
* Each custom UI is specified as a JSON string in the settings property bag
|
||||
* The Power Toy must provide a named method that returns a serialized JSON settings string for the settings framework to call
|
||||
* The method should launch UI to edit the settings but the UI shown must be asynchronous and not block the setting UI
|
||||
* The Power Toys main .exe will provide a method called InvokeSettingsUI that will show the settings dialog for the calling Power Toy.
|
||||
* Settings will be serialized by the settings framework and will be read at launch of the Power Toys framework and each Power Toy’s settings will be passed into the PT’s Enable method
|
||||
* Settings will be serialized on a per-user basis
|
||||
* The Settings JSON format will be versioned and each payload must specify it's version attribute. The initial version is 1.0
|
||||
|
||||
## Power Toys Settings Object
|
||||
The settings JSON object for each Power Toy should provide:
|
||||
* Title string
|
||||
* Icon
|
||||
* Logo Image
|
||||
* Credits string
|
||||
* Credits link
|
||||
* Settings property bag. Each item in the property bag has two items:
|
||||
* String: display name
|
||||
* String: property / editor type
|
||||
* Version number: Currently only 1.0 is supported
|
||||
|
||||
Property Bag of settings in priority order (type->editor)
|
||||
* Bool->slide switch
|
||||
* Int->free text box
|
||||
* String->free text box
|
||||
* Int ->Up/Down spinner
|
||||
* Color-> Color picker
|
||||
* Image->File picker, preview area, drag and drop
|
||||
* Cursor->file picker and drop down, possibly an image
|
||||
* Property Bag JSON string->Button to launch a custom editor from the Power Toy
|
||||
* Method name to invoke. The method will return a serialized JSON string with the updated custom editor settings
|
||||
* String to display on the button
|
||||
* Percentage->Slider
|
||||
* Time->Time picker
|
||||
* Date->Date picker
|
||||
* IP address->masked text box
|
||||
|
||||
## PowerToys Main Settings Page
|
||||
* Need to get Nick to help with the settings UI design (see attached for a whiteboard sketch)
|
||||
* Need to have a settings page for overall PowerToys which will include the following
|
||||
* Check for updates
|
||||
* Startup at launch
|
||||
* Enable / disable for each utility.
|
||||
* This invokes the Enable and Disable events for the PowerToy and suspends all resource use including CPU, GPU, Networking, Disk I/O and memory commit
|
||||
* The settings UI should have an “Apply” button which will push the settings object to
|
||||
15
doc/specs/readme.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Specs
|
||||
|
||||
All approved specs are inside the [Wiki](https://github.com/microsoft/PowerToys/wiki)
|
||||
|
||||
## Spec process
|
||||
|
||||
1. A proposed item is either new or requesting additional design
|
||||
2. Spec is written inside the Specs folder and a PR happens with feedback.
|
||||
3. Once spec is signed off, we move it into the [Wiki](https://github.com/microsoft/PowerToys/wiki).
|
||||
|
||||
## Thought process behind this
|
||||
|
||||
We want a single wholistic for PowerToys. This includes both source code, docs, and specs. At the same time, we want to ensure items have pull requests and feedback. Since the wiki cannot do PR's, we will do the process above.
|
||||
|
||||
This process will allow specs to be image rich but not impact the primary repository's size as more items come online.
|
||||
50
format_sources.ps1
Normal file
@@ -0,0 +1,50 @@
|
||||
param (
|
||||
[switch]$all = $false
|
||||
)
|
||||
|
||||
if(!(Get-Command "git" -ErrorAction SilentlyContinue)) {
|
||||
throw "You need to have a git in path to be able to format only the dirty files!"
|
||||
}
|
||||
|
||||
$clangFormat = "clang-format.exe"
|
||||
if(!(Get-Command $clangFormat -ErrorAction SilentlyContinue)) {
|
||||
Write-Information "Can't find clang-format.exe in %PATH%, trying to use %VCINSTALLDIR%..."
|
||||
$clangFormat="$env:VCINSTALLDIR\Tools\Llvm\bin\clang-format.exe"
|
||||
if(!(Test-Path -Path $clangFormat -PathType leaf)) {
|
||||
throw "Can't find clang-format.exe executable. Make sure you either have it in %PATH% or run this script from vcvars.bat!"
|
||||
}
|
||||
}
|
||||
|
||||
$sourceExtensions = New-Object System.Collections.Generic.HashSet[string]
|
||||
$sourceExtensions.Add(".cpp") | Out-Null
|
||||
$sourceExtensions.Add(".h") | Out-Null
|
||||
|
||||
function Get-Dirty-Files-From-Git() {
|
||||
$staged = & git diff --name-only --diff-filter=d --cached
|
||||
$unstaged = & git ls-files -m
|
||||
$untracked = & git ls-files --others --exclude-standard
|
||||
$result = New-Object System.Collections.Generic.List[string]
|
||||
$staged, $unstaged, $untracked | % {
|
||||
$_.Split(" ") |
|
||||
where {$sourceExtensions.Contains((Get-Item $_).Extension)} |
|
||||
foreach {$result.Add($_)}
|
||||
}
|
||||
return $result
|
||||
}
|
||||
|
||||
if($all) {
|
||||
$filesToFormat =
|
||||
Get-ChildItem -Recurse -File src |
|
||||
Resolve-Path -Relative |
|
||||
where {$sourceExtensions.Contains((Get-Item $_).Extension)}
|
||||
}
|
||||
else {
|
||||
$filesToFormat = Get-Dirty-Files-From-Git
|
||||
}
|
||||
|
||||
$filesToFormat | % {
|
||||
Write-Host "Formatting $_"
|
||||
& $clangFormat -i -style=file -fallback-style=none $_ 2>&1
|
||||
}
|
||||
|
||||
Write-Host "Done!"
|
||||
BIN
installer/MSIX/Images/logo.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
installer/MSIX/Images/logo150.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
installer/MSIX/Images/logo44.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
40
installer/MSIX/PackagingLayout.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<PackagingLayout xmlns="http://schemas.microsoft.com/appx/makeappx/2017">
|
||||
<PackageFamily ID="PowerToys" FlatBundle="true" ManifestPath="appxmanifest.xml" ResourceManager="false">
|
||||
|
||||
<Package ID="PowerToys-x64" ProcessorArchitecture="x64">
|
||||
<Files>
|
||||
<File DestinationPath="License.rtf" SourcePath="..\..\License.rtf"/>
|
||||
|
||||
<File DestinationPath="action_runner.exe" SourcePath="..\..\x64\Release\action_runner.exe"/>
|
||||
<File DestinationPath="PowerToys.exe" SourcePath="..\..\x64\Release\PowerToys.exe"/>
|
||||
<File DestinationPath="PowerToysSettings.exe" SourcePath="..\..\x64\Release\PowerToysSettings.exe"/>
|
||||
|
||||
<File DestinationPath="modules\FancyZonesEditor.exe" SourcePath="..\..\x64\Release\modules\FancyZonesEditor.exe"/>
|
||||
<File DestinationPath="modules\ControlzEx.dll" SourcePath="..\..\x64\Release\modules\ControlzEx.dll"/>
|
||||
<File DestinationPath="modules\fancyzones.dll" SourcePath="..\..\x64\Release\modules\fancyzones.dll"/>
|
||||
<File DestinationPath="modules\MahApps.Metro.dll" SourcePath="..\..\x64\Release\modules\MahApps.Metro.dll"/>
|
||||
<File DestinationPath="modules\Microsoft.Xaml.Behaviors.dll" SourcePath="..\..\x64\Release\modules\Microsoft.Xaml.Behaviors.dll"/>
|
||||
<File DestinationPath="modules\PowerRenameExt.dll" SourcePath="..\..\x64\Release\modules\PowerRenameExt.dll"/>
|
||||
<File DestinationPath="modules\shortcut_guide.dll" SourcePath="..\..\x64\Release\modules\shortcut_guide.dll"/>
|
||||
<File DestinationPath="modules\PowerRenameUWPUI.exe" SourcePath="..\..\x64\Release\PowerRenameUWPUI.exe"/>
|
||||
<File DestinationPath="modules\System.Text.Json.dll" SourcePath="..\..\x64\Release\modules\System.Text.Json.dll"/>
|
||||
<File DestinationPath="modules\System.Memory.dll" SourcePath="..\..\x64\Release\modules\System.Memory.dll"/>
|
||||
<File DestinationPath="modules\System.Buffers.dll" SourcePath="..\..\x64\Release\modules\System.Buffers.dll"/>
|
||||
<File DestinationPath="modules\System.Runtime.CompilerServices.Unsafe.dll" SourcePath="..\..\x64\Release\modules\System.Runtime.CompilerServices.Unsafe.dll"/>
|
||||
<File DestinationPath="modules\System.Text.Encodings.Web.dll" SourcePath="..\..\x64\Release\modules\System.Text.Encodings.Web.dll"/>
|
||||
<File DestinationPath="modules\System.Threading.Tasks.Extensions.dll" SourcePath="..\..\x64\Release\modules\System.Threading.Tasks.Extensions.dll"/>
|
||||
<File DestinationPath="modules\System.ValueTuple.dll" SourcePath="..\..\x64\Release\modules\System.ValueTuple.dll"/>
|
||||
<File DestinationPath="modules\System.Numerics.Vectors.dll" SourcePath="..\..\x64\Release\modules\System.Numerics.Vectors.dll"/>
|
||||
<File DestinationPath="modules\Microsoft.Bcl.AsyncInterfaces.dll" SourcePath="..\..\x64\Release\modules\Microsoft.Bcl.AsyncInterfaces.dll"/>
|
||||
|
||||
<File DestinationPath="modules\FancyZonesEditor.exe.config" SourcePath="..\..\x64\Release\modules\FancyZonesEditor.exe.config"/>
|
||||
|
||||
<File DestinationPath="Notifications.dll" SourcePath="..\..\x64\Release\Notifications.dll"/>
|
||||
|
||||
<File DestinationPath="svgs\*" SourcePath="..\..\x64\Release\svgs\*"/>
|
||||
<File DestinationPath="settings-html\**" SourcePath="..\..\x64\Release\settings-html\**"/>
|
||||
<File DestinationPath="Images\*.png" SourcePath="Images\*.png"/>
|
||||
</Files>
|
||||
</Package>
|
||||
</PackageFamily>
|
||||
</PackagingLayout>
|
||||
67
installer/MSIX/appxmanifest.xml
Normal file
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
|
||||
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5" IgnorableNamespaces="desktop4">
|
||||
<Identity Name="Microsoft.PowerToys" Version="0.15.1.0" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" ProcessorArchitecture="x64" />
|
||||
<Properties>
|
||||
<DisplayName>PowerToys</DisplayName>
|
||||
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
|
||||
<Description>Windows system utilities to maximize productivity</Description>
|
||||
<Logo>Images\logo.png</Logo>
|
||||
</Properties>
|
||||
<Resources>
|
||||
<Resource Language="en-us" />
|
||||
</Resources>
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.18362.30" />
|
||||
</Dependencies>
|
||||
<Capabilities>
|
||||
<rescap:Capability Name="runFullTrust"/>
|
||||
<rescap:Capability Name="allowElevation"/>
|
||||
</Capabilities>
|
||||
<Applications>
|
||||
<Application Id="PowerToys" Executable="PowerToys.exe" EntryPoint="Windows.FullTrustApplication">
|
||||
<uap:VisualElements DisplayName="PowerToys (Experimental)" Description="Windows system utilities to maximize productivity" Square150x150Logo="Images\logo150.png" Square44x44Logo="Images\logo44.png" BackgroundColor="transparent" />
|
||||
<Extensions>
|
||||
<uap5:Extension Category="windows.startupTask" Executable="PowerToys.exe" EntryPoint="Windows.FullTrustApplication">
|
||||
<uap5:StartupTask TaskId="PowerToysStartupTaskID" Enabled="true" DisplayName="PowerToys" />
|
||||
</uap5:Extension>
|
||||
<com:Extension Category="windows.comServer">
|
||||
<com:ComServer>
|
||||
<com:ExeServer Executable="modules\PowerRenameUWPUI.exe" DisplayName="PowerRenameUWPUI">
|
||||
<com:Class Id="0440049F-D1DC-4E46-B27B-98393D79486B"/>
|
||||
</com:ExeServer>
|
||||
</com:ComServer>
|
||||
</com:Extension>
|
||||
<desktop4:Extension Category="windows.fileExplorerContextMenus">
|
||||
<desktop4:FileExplorerContextMenus>
|
||||
<desktop4:ItemType Type="*">
|
||||
<desktop4:Verb Id="FilePowerRename" Clsid="0440049F-D1DC-4E46-B27B-98393D79486B" />
|
||||
</desktop4:ItemType>
|
||||
<desktop5:ItemType Type="Directory">
|
||||
<desktop5:Verb Id="DirectoryPowerRename" Clsid="0440049F-D1DC-4E46-B27B-98393D79486B" />
|
||||
</desktop5:ItemType>
|
||||
</desktop4:FileExplorerContextMenus>
|
||||
</desktop4:Extension>
|
||||
<Extension Category="windows.backgroundTasks" EntryPoint="PowerToysNotifications.BackgroundHandler">
|
||||
<BackgroundTasks>
|
||||
<Task Type="general" />
|
||||
</BackgroundTasks>
|
||||
</Extension>
|
||||
</Extensions>
|
||||
</Application>
|
||||
</Applications>
|
||||
<Extensions>
|
||||
<Extension Category="windows.activatableClass.inProcessServer">
|
||||
<InProcessServer>
|
||||
<Path>Notifications.dll</Path>
|
||||
<ActivatableClass ActivatableClassId="PowerToysNotifications.BackgroundHandler" ThreadingModel="both"/>
|
||||
</InProcessServer>
|
||||
</Extension>
|
||||
</Extensions>
|
||||
</Package>
|
||||
1
installer/MSIX/build_msix.ps1
Normal file
@@ -0,0 +1 @@
|
||||
makeappx build /v /overwrite /f PackagingLayout.xml /id "PowerToys-x64" /op bin\
|
||||
4
installer/MSIX/build_msix_cdpx.cmd
Normal file
@@ -0,0 +1,4 @@
|
||||
cd /D "%~dp0"
|
||||
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 -winsdk=10.0.18362.0
|
||||
call makeappx build /v /overwrite /f PackagingLayout.xml /id "PowerToys-x64" /op bin\ || exit /b 1
|
||||
5
installer/MSIX/generate_self_sign_cert.ps1
Normal file
@@ -0,0 +1,5 @@
|
||||
$expirationDate = {Get-Date}.Invoke().AddYears(5)
|
||||
$pass = ConvertTo-SecureString -String "12345" -Force -AsPlainText
|
||||
$thumbprint = (New-SelfSignedCertificate -notafter $expirationDate -Type CodeSigningCert -Subject "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" -FriendlyName "PowerToys Test Certificate" -KeyDescription "PowerToys Test Certificate" -KeyFriendlyName "PowerToys Test Key" -KeyUsage "DigitalSignature" -CertStoreLocation Cert:\LocalMachine\My).Thumbprint
|
||||
Export-PfxCertificate -Cert cert:\LocalMachine\My\$thumbprint -FilePath PowerToys_TemporaryKey.pfx -Password $pass
|
||||
Import-PfxCertificate -CertStoreLocation Cert:\LocalMachine\Root -FilePath PowerToys_TemporaryKey.pfx -Password $pass
|
||||
1
installer/MSIX/install_msix.ps1
Normal file
@@ -0,0 +1 @@
|
||||
Add-AppxPackage .\bin\PowerToys.msixbundle
|
||||
7
installer/MSIX/reinstall_msix.ps1
Normal file
@@ -0,0 +1,7 @@
|
||||
taskkill /f /im PowerRenameUWPUI.exe
|
||||
|
||||
.\uninstall_msix.ps1
|
||||
.\build_msix.ps1
|
||||
.\sign_msix.ps1
|
||||
.\install_msix.ps1
|
||||
|
||||
2
installer/MSIX/sign_msix.ps1
Normal file
@@ -0,0 +1,2 @@
|
||||
signtool sign /debug /a /fd SHA256 /f PowerToys_TemporaryKey.pfx /p 12345 bin\PowerToys-x64.msix
|
||||
signtool sign /debug /a /fd SHA256 /f PowerToys_TemporaryKey.pfx /p 12345 bin\PowerToys.msixbundle
|
||||
1
installer/MSIX/uninstall_msix.ps1
Normal file
@@ -0,0 +1 @@
|
||||
Get-AppxPackage -Name '*PowerToys' | select -ExpandProperty "PackageFullName" | Remove-AppxPackage
|
||||
@@ -21,7 +21,7 @@
|
||||
<Control Id="FolderLabel" Type="Text" X="20" Y="60" Width="290" Height="30" NoPrefix="yes" Text="!(loc.InstallDirDlgFolderLabel)" />
|
||||
<Control Id="Folder" Type="PathEdit" X="20" Y="100" Width="320" Height="18" Property="WIXUI_INSTALLDIR" Indirect="yes" />
|
||||
<Control Id="ChangeFolder" Type="PushButton" X="20" Y="120" Width="56" Height="17" Text="!(loc.InstallDirDlgChange)" />
|
||||
<Control Id="DesktopShortcutCheckBox" Type="CheckBox" X="20" Y="160" Width="290" Height="17" Property="INSTALLDESKTOPSHORTCUT" CheckBoxValue="1" Text="Create a shortcut for [ProductName] in the desktop." />
|
||||
<Control Id="DesktopShortcutCheckBox" Type="CheckBox" X="20" Y="160" Width="290" Height="17" Property="INSTALLDESKTOPSHORTCUT" CheckBoxValue="1" Text="Create a shortcut for [ProductName] on the desktop." />
|
||||
<Control Id="ScheduledTaskCheckBox" Type="CheckBox" X="20" Y="180" Width="330" Height="17" Property="CREATESCHEDULEDTASK" CheckBoxValue="1" Text="Automatically start [ProductName] at logon." />
|
||||
</Dialog>
|
||||
</UI>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" InitialTargets="EnsureNuGetPackageBuildImports" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\WiX.3.11.1\build\wix.props" Condition="Exists('..\packages\WiX.3.11.1\build\wix.props')" />
|
||||
<Import Project="..\packages\WiX.3.11.2\build\wix.props" Condition="Exists('..\packages\WiX.3.11.2\build\wix.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x64</Platform>
|
||||
@@ -37,6 +37,10 @@
|
||||
<HintPath>$(WixExtDir)\WixUIExtension.dll</HintPath>
|
||||
<Name>WixUIExtension</Name>
|
||||
</WixExtension>
|
||||
<WixExtension Include="WixNetFxExtension">
|
||||
<HintPath>$(WixExtDir)\WixNetFxExtension.dll</HintPath>
|
||||
<Name>WixNetFxExtension</Name>
|
||||
</WixExtension>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="CustomDialogs" />
|
||||
@@ -54,12 +58,12 @@
|
||||
<ItemGroup>
|
||||
<Content Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(WixTargetsPath)"/>
|
||||
<Import Project="$(WixTargetsPath)" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\WiX.3.11.1\build\wix.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WiX.3.11.1\build\wix.props'))" />
|
||||
<Error Condition="!Exists('..\packages\WiX.3.11.2\build\wix.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WiX.3.11.2\build\wix.props'))" />
|
||||
</Target>
|
||||
<!--
|
||||
To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
|
||||
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
|
||||
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
|
||||
xmlns:netfx="http://schemas.microsoft.com/wix/NetFxExtension" >
|
||||
|
||||
<?define RepoDir="$(var.ProjectDir)..\..\" ?>
|
||||
<?define BinX64Dir="$(var.RepoDir)x64\$(var.Configuration)\" ?>
|
||||
<Product Id="*"
|
||||
Name="PowerToys"
|
||||
Name="PowerToys (Preview)"
|
||||
Language="1033"
|
||||
Version="0.12.0"
|
||||
Version="0.15.1"
|
||||
Manufacturer="Microsoft"
|
||||
UpgradeCode="42B84BF7-5FBF-473B-9C8B-049DC16F7708">
|
||||
|
||||
@@ -17,7 +18,7 @@
|
||||
|
||||
<Upgrade Id="42B84BF7-5FBF-473B-9C8B-049DC16F7708">
|
||||
<UpgradeVersion
|
||||
Minimum="0.11.0" Maximum="0.12.0"
|
||||
Minimum="0.11.0" Maximum="0.14.1"
|
||||
Property="PREVIOUSVERSIONSINSTALLED"
|
||||
IncludeMinimum="yes" IncludeMaximum="yes" />
|
||||
</Upgrade>
|
||||
@@ -62,6 +63,10 @@
|
||||
<Property Id="WixShellExecTarget" Value="[#PowerToys.exe]" />
|
||||
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
|
||||
|
||||
<Property Id ="EXISTINGPOWERRENAMEEXTPATH">
|
||||
<RegistrySearch Id="ExistingExtPath" Root="HKCR" Key="CLSID\{0440049F-D1DC-4E46-B27B-98393D79486B}\InprocServer32" Type="raw"/>
|
||||
</Property>
|
||||
|
||||
<InstallExecuteSequence>
|
||||
<Custom Action="SetRegisterPowerToysSchTaskParam" Before="RegisterPowerToysSchTask" />
|
||||
<Custom Action="RegisterPowerToysSchTask" After="InstallFiles">
|
||||
@@ -156,6 +161,10 @@
|
||||
|
||||
<!-- Close 'PowerToys.exe' before uninstall-->
|
||||
<Property Id="MSIRESTARTMANAGERCONTROL" Value="Disable" />
|
||||
<!-- Restart explorer.exe if we detect existing powerrenameext.dll installation -->
|
||||
<util:CloseApplication Target="explorer.exe" RebootPrompt="no" TerminateProcess="0">
|
||||
EXISTINGPOWERRENAMEEXTPATH
|
||||
</util:CloseApplication>
|
||||
<util:CloseApplication CloseMessage="yes" Target="PowerToys.exe" ElevatedCloseMessage="yes" RebootPrompt="no" TerminateProcess="0" />
|
||||
</Product>
|
||||
|
||||
@@ -183,16 +192,26 @@
|
||||
|
||||
<Fragment>
|
||||
<DirectoryRef Id="INSTALLFOLDER" FileSource="$(var.BinX64Dir)">
|
||||
<Component Id="powertoys_toast_clsid" Win64="yes">
|
||||
<RegistryKey Root="HKCU" Key="Software\Classes\CLSID\{DD5CACDA-7C2E-4997-A62A-04A597B58F76}">
|
||||
<RegistryValue Type="string" Value="PowerToys Toast Notifications Background Activator" />
|
||||
<RegistryValue Type="string" Key="LocalServer32" Value="[INSTALLFOLDER]PowerToys.exe -ToastActivated" />
|
||||
<RegistryValue Type="string" Key="LocalServer32" Name="ThreadingModel" Value="Apartment" />
|
||||
</RegistryKey>
|
||||
</Component>
|
||||
<Component Id="powertoys_exe" Guid="A2C66D91-3485-4D00-B04D-91844E6B345B" Win64="yes">
|
||||
<File Id="PowerToys.exe" KeyPath="yes" Checksum="yes">
|
||||
<Shortcut Id="ApplicationStartMenuShortcut"
|
||||
Name="PowerToys"
|
||||
Name="PowerToys (Preview)"
|
||||
Description="PowerToys - Windows system utilities to maximize productivity"
|
||||
Directory="ApplicationProgramsFolder"
|
||||
WorkingDirectory="INSTALLFOLDER"
|
||||
Icon="powertoys.ico"
|
||||
IconIndex="0"
|
||||
Advertise="yes" />
|
||||
Advertise="yes">
|
||||
<ShortcutProperty Key="System.AppUserModel.ID" Value="Microsoft.PowerToysWin32"/>
|
||||
<ShortcutProperty Key="System.AppUserModel.ToastActivatorCLSID" Value="{DD5CACDA-7C2E-4997-A62A-04A597B58F76}"/>
|
||||
</Shortcut>
|
||||
</File>
|
||||
|
||||
<RemoveFolder Id="DeleteShortcutFolder" Directory="ApplicationProgramsFolder" On="uninstall" />
|
||||
@@ -200,6 +219,9 @@
|
||||
<Component Id="settings_exe" Guid="A5A461A9-7097-4CBA-9D39-3DBBB6B7B80C" Win64="yes">
|
||||
<File Id="PowerToysSettings.exe" KeyPath="yes" Checksum="yes" />
|
||||
</Component>
|
||||
<Component Id="notifications_dll" Guid="23B25EE4-BCA2-45DF-BBCD-82FBDF01C5AB" Win64="yes">
|
||||
<File Id="Notifications.dll" KeyPath="yes" Checksum="yes" />
|
||||
</Component>
|
||||
<Component Id="License_rtf" Guid="3E5AE43B-CFB4-449B-A346-94CAAFF3312E" Win64="yes">
|
||||
<File Source="$(var.RepoDir)\License.rtf" Id="License.rtf" KeyPath="yes" />
|
||||
</Component>
|
||||
@@ -227,10 +249,22 @@
|
||||
</Component>
|
||||
<Component Id="Module_FancyZones" Guid="C6B5272E-6ED4-4B80-B0E7-2FF0355D8CF4" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)\modules\fancyzones.dll" KeyPath="yes" />
|
||||
<File Source="$(var.BinX64Dir)\modules\FancyZonesEditor.exe" />
|
||||
<File Source="$(var.BinX64Dir)\modules\FancyZonesEditor.exe" >
|
||||
<netfx:NativeImage Id="FancyZonesEditor.exe" Platform="64bit" Priority="0" />
|
||||
</File>
|
||||
<File Source="$(var.BinX64Dir)\modules\ControlzEx.dll" />
|
||||
<File Source="$(var.BinX64Dir)\modules\MahApps.Metro.dll" />
|
||||
<File Source="$(var.BinX64Dir)\modules\Microsoft.Xaml.Behaviors.dll" />
|
||||
<File Source="$(var.BinX64Dir)\modules\FancyZonesEditor.exe.config" />
|
||||
<File Source="$(var.BinX64Dir)\modules\Microsoft.Bcl.AsyncInterfaces.dll" />
|
||||
<File Source="$(var.BinX64Dir)\modules\System.Buffers.dll" />
|
||||
<File Source="$(var.BinX64Dir)\modules\System.Memory.dll" />
|
||||
<File Source="$(var.BinX64Dir)\modules\System.Numerics.Vectors.dll" />
|
||||
<File Source="$(var.BinX64Dir)\modules\System.Runtime.CompilerServices.Unsafe.dll" />
|
||||
<File Source="$(var.BinX64Dir)\modules\System.Text.Encodings.Web.dll" />
|
||||
<File Source="$(var.BinX64Dir)\modules\System.Text.Json.dll" />
|
||||
<File Source="$(var.BinX64Dir)\modules\System.Threading.Tasks.Extensions.dll" />
|
||||
<File Source="$(var.BinX64Dir)\modules\System.ValueTuple.dll" />
|
||||
</Component>
|
||||
<Component Id="Module_PowerRename" Guid="E4401D08-27FE-4F96-BA17-0C61FD79E684" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)\modules\PowerRenameExt.dll" KeyPath="yes" />
|
||||
@@ -268,7 +302,7 @@
|
||||
Value="1"
|
||||
KeyPath="yes"/>
|
||||
<Shortcut Id="DesktopShortcutId"
|
||||
Name="PowerToys"
|
||||
Name="PowerToys (Preview)"
|
||||
Description="PowerToys - Windows system utilities to maximize productivity"
|
||||
Target="[!PowerToys.exe]"
|
||||
WorkingDirectory="INSTALLFOLDER"
|
||||
@@ -281,6 +315,8 @@
|
||||
<Fragment>
|
||||
<ComponentGroup Id="CoreComponents" Directory="INSTALLFOLDER">
|
||||
<ComponentRef Id="powertoys_exe" />
|
||||
<ComponentRef Id="notifications_dll" />
|
||||
<ComponentRef Id="powertoys_toast_clsid" />
|
||||
<ComponentRef Id="License_rtf" />
|
||||
<ComponentRef Id="PowerToysSvgs" />
|
||||
<ComponentRef Id="Module_ShortcutGuide" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="WiX" version="3.11.1" />
|
||||
<package id="WiX" version="3.11.2" />
|
||||
</packages>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" InitialTargets="EnsureNuGetPackageBuildImports" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\WiX.3.11.1\build\wix.props" Condition="Exists('..\packages\WiX.3.11.1\build\wix.props')" />
|
||||
<Import Project="..\packages\WiX.3.11.2\build\wix.props" Condition="Exists('..\packages\WiX.3.11.2\build\wix.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
@@ -50,7 +50,7 @@
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>inc;telemetry;$(WIX)sdk\$(WixPlatformToolset)\inc;$(SolutionDir)\packages\WiX.3.11.1\tools\sdk\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>inc;telemetry;$(WIX)sdk\$(WixPlatformToolset)\inc;$(SolutionDir)\packages\WiX.3.11.2\tools\sdk\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;CUSTOMACTIONTEST_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
@@ -60,7 +60,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>msi.lib;dutil.lib;wcautil.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(WIX)sdk\$(WixPlatformToolset)\lib\x64;$(SolutionDir)\packages\WiX.3.11.1\tools\sdk\vs2017\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>$(WIX)sdk\$(WixPlatformToolset)\lib\x64;$(SolutionDir)\packages\WiX.3.11.2\tools\sdk\vs2017\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<ModuleDefinitionFile>CustomAction.def</ModuleDefinitionFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -71,7 +71,7 @@
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>inc;telemetry;$(WIX)sdk\$(WixPlatformToolset)\inc;$(SolutionDir)\packages\WiX.3.11.1\tools\sdk\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>inc;telemetry;$(WIX)sdk\$(WixPlatformToolset)\inc;$(SolutionDir)\packages\WiX.3.11.2\tools\sdk\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;CUSTOMACTIONTEST_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
@@ -81,7 +81,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>msi.lib;dutil.lib;wcautil.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(WIX)sdk\$(WixPlatformToolset)\lib\x64;$(SolutionDir)\packages\WiX.3.11.1\tools\sdk\vs2017\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>$(WIX)sdk\$(WixPlatformToolset)\lib\x64;$(SolutionDir)\packages\WiX.3.11.2\tools\sdk\vs2017\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<ModuleDefinitionFile>CustomAction.def</ModuleDefinitionFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -113,6 +113,6 @@
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\WiX.3.11.1\build\wix.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WiX.3.11.1\build\wix.props'))" />
|
||||
<Error Condition="!Exists('..\packages\WiX.3.11.2\build\wix.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WiX.3.11.2\build\wix.props'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="WiX" version="3.11.1" targetFramework="native" />
|
||||
<package id="WiX" version="3.11.2" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -1,7 +1,47 @@
|
||||
# PowerToys Setup Project
|
||||
# PowerToys installer instructions
|
||||
|
||||
## Build instructions
|
||||
* Install the [WiX Toolset Visual Studio 2019 Extension](https://marketplace.visualstudio.com/items?itemName=RobMensching.WiXToolset).
|
||||
* Install the [WiX Toolset build tools](https://wixtoolset.org/releases/) in the development machine.
|
||||
* Open `powertoys.sln`, select the "Release" and "x64" configurations and build the `PowerToysSetup` project.
|
||||
* The resulting installer will be built to `PowerToysSetup\bin\Release\PowerToysSetup.msi`.
|
||||
## MSI installer instructions
|
||||
|
||||
1. Install the [WiX Toolset Visual Studio 2019 Extension](https://marketplace.visualstudio.com/items?itemName=RobMensching.WiXToolset).
|
||||
2. Install the [WiX Toolset build tools](https://wixtoolset.org/releases/) in the development machine.
|
||||
3. Open `powertoys.sln`, select the "Release" and "x64" configurations and build the `PowerToysSetup` project.
|
||||
4. The resulting installer will be built to `PowerToysSetup\bin\Release\PowerToysSetup.msi`.
|
||||
|
||||
## MSIX installer instructions
|
||||
|
||||
### One-time tasks
|
||||
|
||||
#### Create and install the self-sign certificate
|
||||
For the first-time installation, you'll need to generate a self-signed certificate. The script below will generate and add a cert to your [TRCA store](https://docs.microsoft.com/en-us/windows-hardware/drivers/install/trusted-root-certification-authorities-certificate-store).
|
||||
1. Open `Developer PowerShell for VS` as an Admin
|
||||
2. Navigate to your repo's `installer\MSIX`
|
||||
3. Run `.\generate_self_sign_cert.ps1`
|
||||
|
||||
**Note:** if you delete the folder, you will have to regenerate the key
|
||||
|
||||
#### Elevate `Developer PowerShell for VS` permissions due to unsigned file
|
||||
`msix_reinstall.ps1` is unsigned, you'll need to elevate your prompt.
|
||||
1. Open `Developer PowerShell for VS` as admin
|
||||
2. Run `Set-ExecutionPolicy -executionPolicy Unrestricted`
|
||||
|
||||
#### Allow Sideloaded apps
|
||||
In order to install the MSIX package without using the Microsoft Store, sideloading apps needs to be enabled. This can be done by enabling `Developer Options > Sideload apps` or `Developer Options > Developer mode`.
|
||||
|
||||
### Building the MSIX package
|
||||
1. Make sure you've built the `Release` configuration of `powertoys.sln`
|
||||
2. Open `Developer PowerShell for VS`
|
||||
3. Navigate to your repo's `installer\MSIX`
|
||||
4. Run `.\msix_reinstall.ps1` from the devenv powershell
|
||||
|
||||
### What msix_reinstall.ps1 does
|
||||
`msix_reinstall.ps1` removes the current PowerToys installation, restarts explorer.exe (to update PowerRename shell extension), builds `PowerToys-x64.msix` package, signs it with a PowerToys_TemporaryKey.pfx, and finally installs it.
|
||||
|
||||
## Cleanup - Removing all .msi/.msix PowerToys installations
|
||||
```ps
|
||||
$name='PowerToys'
|
||||
Get-AppxPackage -Name $name | select -ExpandProperty "PackageFullName" | Remove-AppxPackage
|
||||
gwmi win32_product -filter "Name = '$name'" -namespace root/cimv2 | foreach {
|
||||
if ($_.uninstall().returnvalue -eq 0) { write-host "Successfully uninstalled $name " }
|
||||
else { write-warning "Failed to uninstall $name." }
|
||||
}
|
||||
```
|
||||
|
||||
52
src/action_runner/action_runner.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include <common/msi_to_msix_upgrade_lib/msi_to_msix_upgrade.h>
|
||||
|
||||
#include <winrt/Windows.ApplicationModel.h>
|
||||
#include <winrt/Windows.Storage.h>
|
||||
|
||||
int uninstall_msi_action()
|
||||
{
|
||||
const auto package_path = get_msi_package_path();
|
||||
if (package_path.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (!uninstall_msi_version(package_path))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Launch PowerToys again, since it's been terminated by the MSI uninstaller
|
||||
std::wstring runner_path{ winrt::Windows::ApplicationModel::Package::Current().InstalledLocation().Path() };
|
||||
runner_path += L"\\PowerToys.exe";
|
||||
SHELLEXECUTEINFOW sei{ sizeof(sei) };
|
||||
sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC };
|
||||
sei.lpFile = runner_path.c_str();
|
||||
sei.nShow = SW_SHOWNORMAL;
|
||||
ShellExecuteExW(&sei);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
||||
{
|
||||
int nArgs = 0;
|
||||
LPWSTR* args = CommandLineToArgvW(GetCommandLineW(), &nArgs);
|
||||
if (!args || nArgs < 2)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
std::wstring_view action{ args[1] };
|
||||
|
||||
if (action == L"-uninstall_msi")
|
||||
{
|
||||
return uninstall_msi_action();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
168
src/action_runner/action_runner.vcxproj
Normal file
@@ -0,0 +1,168 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}</ProjectGuid>
|
||||
<RootNamespace>actionrunner</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>action_runner</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>../;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>../;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>WindowsApp.lib;Msi.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>WindowsApp.lib;Msi.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="action_runner.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\common\common.vcxproj">
|
||||
<Project>{74485049-c722-400f-abe5-86ac52d929b3}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\common\msi_to_msix_upgrade_lib\msi_to_msix_upgrade_lib.vcxproj">
|
||||
<Project>{17da04df-e393-4397-9cf0-84dabe11032e}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\runner\msi_to_msix_upgrade.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
27
src/action_runner/service_runner.vcxproj.filters
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="action_runner.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\runner\msi_to_msix_upgrade.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
47
src/codeAnalysis/GlobalSuppressions.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
// This file is used by Code Analysis to maintain SuppressMessage
|
||||
// attributes that are applied to this project.
|
||||
// Project-level suppressions either have no target or are given
|
||||
// a specific target and scoped to a namespace, type, member, etc.
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1009:ClosingParenthesisMustBeSpacedCorrectly", Justification = "All current violations are due to Tuple shorthand and so valid.")]
|
||||
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:PrefixLocalCallsWithThis", Justification = "We follow the C# Core Coding Style which avoids using `this` unless absolutely necessary.")]
|
||||
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1200:UsingDirectivesMustBePlacedWithinNamespace", Justification = "We follow the C# Core Coding Style which puts using statements outside the namespace.")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:ElementsMustAppearInTheCorrectOrder", Justification = "It is not a priority and have hight impact in code changes.")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:ElementsMustBeOrderedByAccess", Justification = "It is not a priority and have hight impact in code changes.")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1203:ConstantsMustAppearBeforeFields", Justification = "It is not a priority and have hight impact in code changes.")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1204:StaticElementsMustAppearBeforeInstanceElements", Justification = "It is not a priority and have hight impact in code changes.")]
|
||||
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.NamingRules", "SA1309:FieldNamesMustNotBeginWithUnderscore", Justification = "We follow the C# Core Coding Style which uses underscores as prefixes rather than using `this.`.")]
|
||||
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.SpecialRules", "SA0001:XmlCommentAnalysisDisabled", Justification = "Not enabled as we don't want or need XML documentation.")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1629:DocumentationTextMustEndWithAPeriod", Justification = "Not enabled as we don't want or need XML documentation.")]
|
||||
|
||||
[assembly: SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly", Scope = "member", Target = "Microsoft.Templates.Core.Locations.TemplatesSynchronization.#SyncStatusChanged", Justification = "Using an Action<object, SyncStatusEventArgs> does not allow the required notation")]
|
||||
|
||||
// Non general supressions
|
||||
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "The WebBrowser is loading source code to be shown to the user. No localization required.", MessageId = "System.Windows.Controls.WebBrowser.NavigateToString(System.String)", Scope = "member", Target = "Microsoft.Templates.UI.Controls.CodeViewer.#UpdateCodeView(System.Func`2<System.String,System.String>,System.String,System.String,System.Boolean)")]
|
||||
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "This is part of the markdown processing", MessageId = "System.Windows.Documents.Run.#ctor(System.String)", Scope = "member", Target = "Microsoft.Templates.UI.Controls.Markdown.#ImageInlineEvaluator(System.Text.RegularExpressions.Match)")]
|
||||
[assembly: SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "We need to have the names of these keys in lowercase to be able to compare with the keys becoming form the template json. ContainsKey does not allow StringComparer especification to IgnoreCase", Scope = "member", Target = "Microsoft.Templates.Core.ITemplateInfoExtensions.#GetQueryableProperties(Microsoft.TemplateEngine.Abstractions.ITemplateInfo)")]
|
||||
[assembly: SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "We need to have the names of these keys in lowercase to be able to compare with the keys becoming form the template json. ContainsKey does not allow StringComparer especification to IgnoreCase", Scope = "member", Target = "Microsoft.Templates.Core.Composition.CompositionQuery.#Match(System.Collections.Generic.IEnumerable`1<Microsoft.Templates.Core.Composition.QueryNode>,Microsoft.Templates.Core.Composition.QueryablePropertyDictionary)")]
|
||||
[assembly: SuppressMessage("Usage", "VSTHRD103:Call async methods when in an async method", Justification = "Resource DictionaryWriter does not implement flush async", Scope = "member", Target = "~M:Microsoft.Templates.Core.PostActions.Catalog.Merge.MergeResourceDictionaryPostAction.ExecuteInternalAsync~System.Threading.Tasks.Task")]
|
||||
|
||||
// Threading supressions
|
||||
[assembly: SuppressMessage("Microsoft.VisualStudio.Threading.Analyzers", "VSTHRD100:Avoid async void methods", Justification = "Event handlers needs async void", Scope = "member", Target = "~M:Microsoft.Templates.UI.Controls.Notification.OnClose")]
|
||||
[assembly: SuppressMessage("Microsoft.VisualStudio.Threading.Analyzers", "VSTHRD100:Avoid async void methods", Justification = "Event handlers needs async void", Scope = "member", Target = "~M:Microsoft.Templates.UI.ViewModels.Common.SavedTemplateViewModel.OnDelete")]
|
||||
[assembly: SuppressMessage("Microsoft.VisualStudio.Threading.Analyzers", "VSTHRD100:Avoid async void methods", Justification = "Event handlers needs async void", Scope = "member", Target = "~M:Microsoft.Templates.UI.ViewModels.Common.WizardNavigation.GoBack")]
|
||||
[assembly: SuppressMessage("Microsoft.VisualStudio.Threading.Analyzers", "VSTHRD100:Avoid async void methods", Justification = "Event handlers needs async void", Scope = "member", Target = "~M:Microsoft.Templates.UI.ViewModels.Common.WizardNavigation.GoForward")]
|
||||
[assembly: SuppressMessage("Microsoft.VisualStudio.Threading.Analyzers", "VSTHRD100:Avoid async void methods", Justification = "Event handlers needs async void", Scope = "member", Target = "~M:Microsoft.Templates.UI.ViewModels.Common.SavedTemplateViewModel.OnDelete(Microsoft.Templates.UI.ViewModels.Common.SavedTemplateViewModel)")]
|
||||
|
||||
// Localization suppressions
|
||||
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.ThrowLastWin32Error(System.String)", Scope = "member", Target = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.#CreateJunction(System.String,System.String,System.Boolean)", Justification = "Only used for local generation")]
|
||||
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.ThrowLastWin32Error(System.String)", Scope = "member", Target = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.#DeleteJunction(System.String)", Justification = "Only used for local generation")]
|
||||
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.ThrowLastWin32Error(System.String)", Scope = "member", Target = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.#InternalGetTarget(Microsoft.Win32.SafeHandles.SafeFileHandle)", Justification = "Only used for local generation")]
|
||||
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.ThrowLastWin32Error(System.String)", Scope = "member", Target = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.#OpenReparsePoint(System.String,Microsoft.Templates.Core.Locations.JunctionNativeMethods+EFileAccess)", Justification = "Only used for local generation")]
|
||||
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "System.Windows.Documents.InlineCollection.Add(System.String)", Scope = "member", Target = "Microsoft.Templates.UI.Extensions.TextBlockExtensions.#OnSequentialFlowStepChanged(System.Windows.DependencyObject,System.Windows.DependencyPropertyChangedEventArgs)", Justification = "No text here")]
|
||||
74
src/codeAnalysis/Rules.ruleset
Normal file
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RuleSet Name="PowerToys Rules" Description="Based on Microsoft Minimum Recomended Rules and customized to include other required rules. These rules focus on the most critical problems in your code, including potential security holes, application crashes, and other important logic and design errors. It is recommended to include this rule set in any custom rule set you create for your projects." ToolsVersion="15.0">
|
||||
<Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
|
||||
<Rule Id="CA1001" Action="Warning" />
|
||||
<Rule Id="CA1009" Action="Warning" />
|
||||
<Rule Id="CA1016" Action="Warning" />
|
||||
<Rule Id="CA1033" Action="Warning" />
|
||||
<Rule Id="CA1049" Action="Warning" />
|
||||
<Rule Id="CA1060" Action="Warning" />
|
||||
<Rule Id="CA1061" Action="Warning" />
|
||||
<Rule Id="CA1063" Action="Warning" />
|
||||
<Rule Id="CA1065" Action="Warning" />
|
||||
<Rule Id="CA1301" Action="Warning" />
|
||||
<Rule Id="CA1302" Action="Warning" />
|
||||
<Rule Id="CA1303" Action="Warning" />
|
||||
<Rule Id="CA1304" Action="Warning" />
|
||||
<Rule Id="CA1306" Action="Warning" />
|
||||
<Rule Id="CA1307" Action="Warning" />
|
||||
<Rule Id="CA1308" Action="Warning" />
|
||||
<Rule Id="CA1309" Action="Warning" />
|
||||
<Rule Id="CA1400" Action="Warning" />
|
||||
<Rule Id="CA1401" Action="Warning" />
|
||||
<Rule Id="CA1403" Action="Warning" />
|
||||
<Rule Id="CA1404" Action="Warning" />
|
||||
<Rule Id="CA1405" Action="Warning" />
|
||||
<Rule Id="CA1410" Action="Warning" />
|
||||
<Rule Id="CA1415" Action="Warning" />
|
||||
<Rule Id="CA1821" Action="Warning" />
|
||||
<Rule Id="CA1900" Action="Warning" />
|
||||
<Rule Id="CA1901" Action="Warning" />
|
||||
<Rule Id="CA2002" Action="Warning" />
|
||||
<Rule Id="CA2100" Action="Warning" />
|
||||
<Rule Id="CA2101" Action="Warning" />
|
||||
<Rule Id="CA2108" Action="Warning" />
|
||||
<Rule Id="CA2111" Action="Warning" />
|
||||
<Rule Id="CA2112" Action="Warning" />
|
||||
<Rule Id="CA2114" Action="Warning" />
|
||||
<Rule Id="CA2116" Action="Warning" />
|
||||
<Rule Id="CA2117" Action="Warning" />
|
||||
<Rule Id="CA2122" Action="Warning" />
|
||||
<Rule Id="CA2123" Action="Warning" />
|
||||
<Rule Id="CA2124" Action="Warning" />
|
||||
<Rule Id="CA2126" Action="Warning" />
|
||||
<Rule Id="CA2131" Action="Warning" />
|
||||
<Rule Id="CA2132" Action="Warning" />
|
||||
<Rule Id="CA2133" Action="Warning" />
|
||||
<Rule Id="CA2134" Action="Warning" />
|
||||
<Rule Id="CA2137" Action="Warning" />
|
||||
<Rule Id="CA2138" Action="Warning" />
|
||||
<Rule Id="CA2140" Action="Warning" />
|
||||
<Rule Id="CA2141" Action="Warning" />
|
||||
<Rule Id="CA2146" Action="Warning" />
|
||||
<Rule Id="CA2147" Action="Warning" />
|
||||
<Rule Id="CA2149" Action="Warning" />
|
||||
<Rule Id="CA2200" Action="Warning" />
|
||||
<Rule Id="CA2202" Action="Warning" />
|
||||
<Rule Id="CA2207" Action="Warning" />
|
||||
<Rule Id="CA2212" Action="Warning" />
|
||||
<Rule Id="CA2213" Action="Warning" />
|
||||
<Rule Id="CA2214" Action="Warning" />
|
||||
<Rule Id="CA2216" Action="Warning" />
|
||||
<Rule Id="CA2220" Action="Warning" />
|
||||
<Rule Id="CA2229" Action="Warning" />
|
||||
<Rule Id="CA2231" Action="Warning" />
|
||||
<Rule Id="CA2232" Action="Warning" />
|
||||
<Rule Id="CA2235" Action="Warning" />
|
||||
<Rule Id="CA2236" Action="Warning" />
|
||||
<Rule Id="CA2237" Action="Warning" />
|
||||
<Rule Id="CA2238" Action="Warning" />
|
||||
<Rule Id="CA2240" Action="Warning" />
|
||||
<Rule Id="CA2241" Action="Warning" />
|
||||
<Rule Id="CA2242" Action="Warning" />
|
||||
</Rules>
|
||||
</RuleSet>
|
||||
21
src/codeAnalysis/StyleCop.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
|
||||
"settings": {
|
||||
"documentationRules": {
|
||||
"companyName": "Microsoft Corporation",
|
||||
"copyrightText": "Copyright (c) {companyName}\r\nThe {companyName} licenses this file to you under the MIT license.\r\nSee the LICENSE file in the project root for more information.",
|
||||
"xmlHeader": false,
|
||||
"headerDecoration": "",
|
||||
"fileNamingConvention": "metadata",
|
||||
"documentInterfaces": false,
|
||||
"documentExposedElements": false,
|
||||
"documentInternalElements": false
|
||||
},
|
||||
"layoutRules": {
|
||||
"newlineAtEndOfFile": "require"
|
||||
},
|
||||
"orderingRules": {
|
||||
"usingDirectivesPlacement": "outsideNamespace"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
# Introduction
|
||||
The common lib, as the name suggests, contains code shared by multiple PowerToys components and modules.
|
||||
|
||||
# Classes and structures
|
||||
|
||||
#### class Animation: [header](./animation.h) [source](./animation.cpp)
|
||||
Animation helper class with two easing-in animations: linear and exponential.
|
||||
|
||||
#### class AsyncMessageQueue: [header](./async_message_queue.h)
|
||||
Header-only asynchronous message queue. Used by `TwoWayPipeMessageIPC`.
|
||||
|
||||
#### class TwoWayPipeMessageIPC: [header](./two_way_pipe_message_ipc.h)
|
||||
Header-only asynchronous IPC messaging class. Used by the runner to communicate with the settings window.
|
||||
|
||||
#### class D2DSVG: [header](./d2d_svg.h) [source](./d2d_svg.cpp)
|
||||
Class for loading, rendering and for some basic modifications of SVG graphics.
|
||||
|
||||
#### class D2DText: [header](./d2d_text.h) [source](./d2d_text.cpp)
|
||||
Class for rendering text using DirectX.
|
||||
|
||||
#### class D2DWindow: [header](./d2d_window.h) [source](./d2d_window.cpp)
|
||||
Base class for creating borderless windows, with DirectX enabled rendering pipeline.
|
||||
|
||||
#### class DPIAware: [header](./dpi_aware.h) [source](./dpi_aware.cpp)
|
||||
Helper class for creating DPI-aware applications.
|
||||
|
||||
#### struct MonitorInfo: [header](./monitors.h) [source](./monitors.cpp)
|
||||
Class for obtaining information about physical displays connected to the machine.
|
||||
|
||||
#### class Settings, class PowerToyValues, class CustomActionObject: [header](./settings_objects.h) [source](./settings_objects.cpp)
|
||||
Classes used to define settings screens for the PowerToys modules.
|
||||
|
||||
#### class Tasklist: [header](./tasklist_positions.h) [source](./tasklist_positions.cpp)
|
||||
Class that can detect the position of the windows buttons on the taskbar. It also detects which window will react to pressing `WinKey + number`.
|
||||
|
||||
#### struct WindowsColors: [header](./windows_colors.h) [source](./windows_colors.cpp)
|
||||
Class for detecting the current Windows color scheme.
|
||||
|
||||
# Helpers
|
||||
|
||||
#### Common helpers: [header](./common.h) [source](./common.cpp)
|
||||
Various helper functions.
|
||||
|
||||
#### Settings helpers: [header](./settings_helpers.h)
|
||||
Helper methods for the settings.
|
||||
|
||||
#### Start visible helper: [header](./start_visible.h) [source](./start_visible.cpp)
|
||||
Contains function to test if the Start menu is visible.
|
||||
@@ -1,62 +1,822 @@
|
||||
#include "pch.h"
|
||||
#include <settings_objects.h>
|
||||
|
||||
#include "VersionHelper.h"
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace PowerToysSettings;
|
||||
|
||||
namespace UnitTestsCommonLib
|
||||
{
|
||||
TEST_CLASS(SettingsUnitTests)
|
||||
{
|
||||
private:
|
||||
const std::wstring m_json = L"{\"name\":\"Module Name\",\"properties\" : {\"bool_toggle_true\":{\"value\":true},\"bool_toggle_false\":{\"value\":false},\"color_picker\" : {\"value\":\"#ff8d12\"},\"int_spinner\" : {\"value\":10},\"string_text\" : {\"value\":\"a quick fox\"}},\"version\" : \"1.0\" }";
|
||||
|
||||
public:
|
||||
TEST_METHOD(LoadFromJsonBoolTrue)
|
||||
void compareJsons(const json::JsonObject& expected, const json::JsonObject& actual, bool recursive = true)
|
||||
{
|
||||
PowerToyValues values = PowerToyValues::from_json_string(m_json);
|
||||
Assert::IsTrue(values.is_bool_value(L"bool_toggle_true"));
|
||||
auto iter = expected.First();
|
||||
while (iter.HasCurrent())
|
||||
{
|
||||
const auto key = iter.Current().Key();
|
||||
Assert::IsTrue(actual.HasKey(key));
|
||||
|
||||
bool value = values.get_bool_value(L"bool_toggle_true");
|
||||
Assert::AreEqual(true, value);
|
||||
const std::wstring expectedStringified = iter.Current().Value().Stringify().c_str();
|
||||
const std::wstring actualStringified = actual.GetNamedValue(key).Stringify().c_str();
|
||||
|
||||
if (recursive)
|
||||
{
|
||||
json::JsonObject expectedJson;
|
||||
if (json::JsonObject::TryParse(expectedStringified, expectedJson))
|
||||
{
|
||||
json::JsonObject actualJson;
|
||||
if (json::JsonObject::TryParse(actualStringified, actualJson))
|
||||
{
|
||||
compareJsons(expectedJson, actualJson, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert::IsTrue(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert::AreEqual(expectedStringified, actualStringified);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert::AreEqual(expectedStringified, actualStringified);
|
||||
}
|
||||
|
||||
iter.MoveNext();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_METHOD(LoadFromJsonBoolFalse)
|
||||
TEST_CLASS(PowerToyValuesUnitTests)
|
||||
{
|
||||
PowerToyValues values = PowerToyValues::from_json_string(m_json);
|
||||
Assert::IsTrue(values.is_bool_value(L"bool_toggle_false"));
|
||||
private:
|
||||
const std::wstring m_json = L"{\"name\":\"Module Name\",\"properties\" : {\"bool_toggle_true\":{\"value\":true},\"bool_toggle_false\":{\"value\":false},\"color_picker\" : {\"value\":\"#ff8d12\"},\"int_spinner\" : {\"value\":10},\"string_text\" : {\"value\":\"a quick fox\"}},\"version\" : \"1.0\" }";
|
||||
const std::wstring m_moduleName = L"Module Name";
|
||||
|
||||
bool value = values.get_bool_value(L"bool_toggle_false");
|
||||
Assert::AreEqual(false, value);
|
||||
}
|
||||
public:
|
||||
TEST_METHOD(LoadFromJsonBoolTrue)
|
||||
{
|
||||
PowerToyValues values = PowerToyValues::from_json_string(m_json);
|
||||
auto value = values.get_bool_value(L"bool_toggle_true");
|
||||
Assert::IsTrue(value.has_value());
|
||||
Assert::AreEqual(true, *value);
|
||||
}
|
||||
|
||||
TEST_METHOD(LoadFromJsonInt)
|
||||
TEST_METHOD(LoadFromJsonBoolFalse)
|
||||
{
|
||||
PowerToyValues values = PowerToyValues::from_json_string(m_json);
|
||||
auto value = values.get_bool_value(L"bool_toggle_false");
|
||||
Assert::IsTrue(value.has_value());
|
||||
Assert::AreEqual(false, *value);
|
||||
}
|
||||
|
||||
TEST_METHOD(LoadFromJsonInt)
|
||||
{
|
||||
PowerToyValues values = PowerToyValues::from_json_string(m_json);
|
||||
auto value = values.get_int_value(L"int_spinner");
|
||||
Assert::IsTrue(value.has_value());
|
||||
Assert::AreEqual(10, *value);
|
||||
}
|
||||
|
||||
TEST_METHOD(LoadFromJsonString)
|
||||
{
|
||||
PowerToyValues values = PowerToyValues::from_json_string(m_json);
|
||||
auto value = values.get_string_value(L"string_text");
|
||||
|
||||
Assert::IsTrue(value.has_value());
|
||||
std::wstring expected = L"a quick fox";
|
||||
Assert::AreEqual(expected, *value);
|
||||
}
|
||||
|
||||
TEST_METHOD(LoadFromJsonColorPicker)
|
||||
{
|
||||
PowerToyValues values = PowerToyValues::from_json_string(m_json);
|
||||
auto value = values.get_string_value(L"color_picker");
|
||||
|
||||
Assert::IsTrue(value.has_value());
|
||||
std::wstring expected = L"#ff8d12";
|
||||
Assert::AreEqual(expected, *value);
|
||||
}
|
||||
|
||||
TEST_METHOD(LoadFromEmptyString)
|
||||
{
|
||||
auto func = [] { PowerToyValues values = PowerToyValues::from_json_string(L""); };
|
||||
Assert::ExpectException<winrt::hresult_error>(func);
|
||||
}
|
||||
|
||||
TEST_METHOD(LoadFromInvalidString_NameMissed)
|
||||
{
|
||||
auto func = [] { PowerToyValues values = PowerToyValues::from_json_string(L"{\"properties\" : {\"bool_toggle_true\":{\"value\":true},\"bool_toggle_false\":{\"value\":false},\"color_picker\" : {\"value\":\"#ff8d12\"},\"int_spinner\" : {\"value\":10},\"string_text\" : {\"value\":\"a quick fox\"}},\"version\" : \"1.0\" }"); };
|
||||
Assert::ExpectException<winrt::hresult_error>(func);
|
||||
}
|
||||
|
||||
TEST_METHOD(LoadFromInvalidString_VersionMissed)
|
||||
{
|
||||
PowerToyValues values = PowerToyValues::from_json_string(L"{\"name\":\"Module Name\",\"properties\" : {}}");
|
||||
const std::wstring expectedStr = L"{\"name\" : \"Module Name\", \"properties\" : {},\"version\" : \"1.0\"}";
|
||||
const auto expected = json::JsonObject::Parse(expectedStr);
|
||||
const auto actual = json::JsonObject::Parse(values.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(LoadFromInvalidString_PropertiesMissed)
|
||||
{
|
||||
PowerToyValues values = PowerToyValues::from_json_string(L"{\"name\":\"Module Name\",\"version\" : \"1.0\" }");
|
||||
const std::wstring expectedStr = L"{\"name\":\"Module Name\",\"version\" : \"1.0\" }";
|
||||
const auto expected = json::JsonObject::Parse(expectedStr);
|
||||
const auto actual = json::JsonObject::Parse(values.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(LoadFromValidString_EmptyProperties)
|
||||
{
|
||||
PowerToyValues values = PowerToyValues::from_json_string(L"{\"name\":\"Module Name\",\"properties\" : {}, \"version\" : \"1.0\" }");
|
||||
const std::wstring expectedStr = L"{\"name\":\"Module Name\",\"properties\" : {},\"version\" : \"1.0\" }";
|
||||
const auto expected = json::JsonObject::Parse(expectedStr);
|
||||
const auto actual = json::JsonObject::Parse(values.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(LoadFromValidString_ChangedVersion)
|
||||
{
|
||||
PowerToyValues values = PowerToyValues::from_json_string(L"{\"name\":\"Module Name\",\"properties\" : {},\"version\" : \"2.0\"}");
|
||||
const std::wstring expectedStr = L"{\"name\" : \"Module Name\", \"properties\" : {},\"version\" : \"1.0\"}"; //version from input json is ignored
|
||||
|
||||
const auto expected = json::JsonObject::Parse(expectedStr);
|
||||
const auto actual = json::JsonObject::Parse(values.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(CreateWithName)
|
||||
{
|
||||
PowerToyValues values(m_moduleName);
|
||||
const std::wstring expectedStr = L"{\"name\":\"Module Name\",\"properties\" : {},\"version\" : \"1.0\" }";
|
||||
|
||||
const auto expected = json::JsonObject::Parse(expectedStr);
|
||||
const auto actual = json::JsonObject::Parse(values.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(AddPropertyBoolPositive)
|
||||
{
|
||||
PowerToyValues values(m_moduleName);
|
||||
values.add_property<bool>(L"positive_bool_value", true);
|
||||
|
||||
auto value = values.get_bool_value(L"positive_bool_value");
|
||||
Assert::IsTrue(value.has_value());
|
||||
Assert::AreEqual(true, *value);
|
||||
}
|
||||
|
||||
TEST_METHOD(AddPropertyBoolNegative)
|
||||
{
|
||||
PowerToyValues values(m_moduleName);
|
||||
values.add_property<bool>(L"negative_bool_value", false);
|
||||
|
||||
auto value = values.get_bool_value(L"negative_bool_value");
|
||||
Assert::IsTrue(value.has_value());
|
||||
Assert::AreEqual(false, *value);
|
||||
}
|
||||
|
||||
TEST_METHOD(AddPropertyIntPositive)
|
||||
{
|
||||
PowerToyValues values(m_moduleName);
|
||||
const int intVal = 4392854;
|
||||
values.add_property<int>(L"integer", intVal);
|
||||
|
||||
auto value = values.get_int_value(L"integer");
|
||||
Assert::IsTrue(value.has_value());
|
||||
Assert::AreEqual(intVal, *value);
|
||||
}
|
||||
|
||||
TEST_METHOD(AddPropertyIntNegative)
|
||||
{
|
||||
PowerToyValues values(m_moduleName);
|
||||
const int intVal = -4392854;
|
||||
values.add_property<int>(L"integer", intVal);
|
||||
|
||||
auto value = values.get_int_value(L"integer");
|
||||
Assert::IsTrue(value.has_value());
|
||||
Assert::AreEqual(intVal, *value);
|
||||
}
|
||||
|
||||
TEST_METHOD(AddPropertyIntZero)
|
||||
{
|
||||
PowerToyValues values(m_moduleName);
|
||||
const int intVal = 0;
|
||||
values.add_property<int>(L"integer", intVal);
|
||||
|
||||
auto value = values.get_int_value(L"integer");
|
||||
Assert::IsTrue(value.has_value());
|
||||
Assert::AreEqual(intVal, *value);
|
||||
}
|
||||
|
||||
TEST_METHOD(AddPropertyStringEmpty)
|
||||
{
|
||||
PowerToyValues values(m_moduleName);
|
||||
const std::wstring stringVal = L"";
|
||||
values.add_property<std::wstring>(L"stringval", stringVal);
|
||||
|
||||
auto value = values.get_string_value(L"stringval");
|
||||
Assert::IsTrue(value.has_value());
|
||||
Assert::AreEqual(stringVal, *value);
|
||||
}
|
||||
|
||||
TEST_METHOD(AddPropertyString)
|
||||
{
|
||||
PowerToyValues values(m_moduleName);
|
||||
const std::wstring stringVal = L"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
|
||||
values.add_property<std::wstring>(L"stringval", stringVal);
|
||||
|
||||
auto value = values.get_string_value(L"stringval");
|
||||
Assert::IsTrue(value.has_value());
|
||||
Assert::AreEqual(stringVal, *value);
|
||||
}
|
||||
|
||||
TEST_METHOD(AddPropertyJsonEmpty)
|
||||
{
|
||||
PowerToyValues values(m_moduleName);
|
||||
const auto json = json::JsonObject();
|
||||
values.add_property<json::JsonObject>(L"jsonval", json);
|
||||
|
||||
auto value = values.get_json(L"jsonval");
|
||||
Assert::IsTrue(value.has_value());
|
||||
compareJsons(json, *value);
|
||||
}
|
||||
|
||||
TEST_METHOD(AddPropertyJsonObject)
|
||||
{
|
||||
PowerToyValues values(m_moduleName);
|
||||
const auto json = json::JsonObject::Parse(m_json);
|
||||
values.add_property<json::JsonObject>(L"jsonval", json);
|
||||
|
||||
auto value = values.get_json(L"jsonval");
|
||||
Assert::IsTrue(value.has_value());
|
||||
compareJsons(json, *value);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CLASS(SettingsUnitTests)
|
||||
{
|
||||
PowerToyValues values = PowerToyValues::from_json_string(m_json);
|
||||
Assert::IsTrue(values.is_int_value(L"int_spinner"));
|
||||
private:
|
||||
const std::wstring m_moduleName = L"Module Name";
|
||||
const std::wstring m_defaultSettingsName = L"Default setting name";
|
||||
const std::wstring m_defaultSettingsDescription = L"Default setting description";
|
||||
const json::JsonObject m_defaultSettingsJson = json::JsonObject::Parse(L"{\"name\" : \"Module Name\", \"properties\" : {},\"version\" : \"1.0\"}");
|
||||
|
||||
int value = values.get_int_value(L"int_spinner");
|
||||
Assert::AreEqual(10, value);
|
||||
}
|
||||
json::JsonObject createSettingsProperties(const std::wstring& editorType)
|
||||
{
|
||||
json::JsonObject properties = json::JsonObject();
|
||||
properties.SetNamedValue(L"display_name", json::JsonValue::CreateStringValue(m_defaultSettingsDescription));
|
||||
properties.SetNamedValue(L"editor_type", json::JsonValue::CreateStringValue(editorType));
|
||||
properties.SetNamedValue(L"order", json::JsonValue::CreateNumberValue(1));
|
||||
return properties;
|
||||
}
|
||||
|
||||
TEST_METHOD(LoadFromJsonString)
|
||||
public:
|
||||
TEST_METHOD(SettingsSerialization)
|
||||
{
|
||||
Settings settings(nullptr, m_moduleName);
|
||||
|
||||
const auto expected = m_defaultSettingsJson;
|
||||
const auto actual = json::JsonObject::Parse(settings.serialize());
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(SettingsSerializationToBuffer)
|
||||
{
|
||||
Settings settings(nullptr, m_moduleName);
|
||||
|
||||
const auto expected = m_defaultSettingsJson;
|
||||
int expectedSize = expected.Stringify().size() + 1;
|
||||
|
||||
int actualSize = expectedSize;
|
||||
wchar_t* buffer = new wchar_t[expectedSize];
|
||||
bool serizalizationSuccess = settings.serialize_to_buffer(buffer, &actualSize);
|
||||
|
||||
Assert::IsTrue(serizalizationSuccess);
|
||||
Assert::AreEqual(expectedSize, actualSize);
|
||||
|
||||
auto actualJson = json::JsonObject::Parse(std::wstring(buffer));
|
||||
|
||||
compareJsons(m_defaultSettingsJson, actualJson);
|
||||
}
|
||||
|
||||
TEST_METHOD(SettingsSetDescription)
|
||||
{
|
||||
const auto value = L"description value";
|
||||
Settings settings(nullptr, m_moduleName);
|
||||
settings.set_description(value);
|
||||
|
||||
const auto expected = m_defaultSettingsJson;
|
||||
expected.SetNamedValue(L"description", json::JsonValue::CreateStringValue(value));
|
||||
const auto actual = json::JsonObject::Parse(settings.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(SettingsSetIconKey)
|
||||
{
|
||||
const auto value = L"icon key";
|
||||
Settings settings(nullptr, m_moduleName);
|
||||
settings.set_icon_key(value);
|
||||
|
||||
const auto expected = m_defaultSettingsJson;
|
||||
expected.SetNamedValue(L"icon_key", json::JsonValue::CreateStringValue(value));
|
||||
const auto actual = json::JsonObject::Parse(settings.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(SettingsSetOverviewLink)
|
||||
{
|
||||
const auto value = L"overview link";
|
||||
Settings settings(nullptr, m_moduleName);
|
||||
settings.set_overview_link(value);
|
||||
|
||||
const auto expected = m_defaultSettingsJson;
|
||||
expected.SetNamedValue(L"overview_link", json::JsonValue::CreateStringValue(value));
|
||||
const auto actual = json::JsonObject::Parse(settings.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(SettingsSetVideoLink)
|
||||
{
|
||||
const auto value = L"video link";
|
||||
Settings settings(nullptr, m_moduleName);
|
||||
settings.set_video_link(value);
|
||||
|
||||
const auto expected = m_defaultSettingsJson;
|
||||
expected.SetNamedValue(L"video_link", json::JsonValue::CreateStringValue(value));
|
||||
const auto actual = json::JsonObject::Parse(settings.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(SettingsAddBoolTogglePositive)
|
||||
{
|
||||
const auto value = true;
|
||||
|
||||
Settings settings(nullptr, m_moduleName);
|
||||
settings.add_bool_toogle(m_defaultSettingsName, m_defaultSettingsDescription, value);
|
||||
|
||||
auto expected = m_defaultSettingsJson;
|
||||
auto expectedProperties = createSettingsProperties(L"bool_toggle");
|
||||
expectedProperties.SetNamedValue(L"value", json::JsonValue::CreateBooleanValue(value));
|
||||
expected.GetNamedObject(L"properties").SetNamedValue(m_defaultSettingsName, expectedProperties);
|
||||
|
||||
const auto actual = json::JsonObject::Parse(settings.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(SettingsAddBoolToggleNegative)
|
||||
{
|
||||
const auto value = false;
|
||||
|
||||
Settings settings(nullptr, m_moduleName);
|
||||
settings.add_bool_toogle(m_defaultSettingsName, m_defaultSettingsDescription, value);
|
||||
|
||||
auto expected = m_defaultSettingsJson;
|
||||
auto expectedProperties = createSettingsProperties(L"bool_toggle");
|
||||
expectedProperties.SetNamedValue(L"value", json::JsonValue::CreateBooleanValue(value));
|
||||
expected.GetNamedObject(L"properties").SetNamedValue(m_defaultSettingsName, expectedProperties);
|
||||
|
||||
const auto actual = json::JsonObject::Parse(settings.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(SettingsAddSpinner)
|
||||
{
|
||||
const int value = 738543;
|
||||
const int min = 0;
|
||||
const int max = 1000000;
|
||||
const int step = 10;
|
||||
|
||||
Settings settings(nullptr, m_moduleName);
|
||||
settings.add_int_spinner(m_defaultSettingsName, m_defaultSettingsDescription, value, min, max, step);
|
||||
|
||||
auto expected = m_defaultSettingsJson;
|
||||
auto expectedProperties = createSettingsProperties(L"int_spinner");
|
||||
expectedProperties.SetNamedValue(L"value", json::JsonValue::CreateNumberValue(value));
|
||||
expectedProperties.SetNamedValue(L"min", json::JsonValue::CreateNumberValue(min));
|
||||
expectedProperties.SetNamedValue(L"max", json::JsonValue::CreateNumberValue(max));
|
||||
expectedProperties.SetNamedValue(L"step", json::JsonValue::CreateNumberValue(step));
|
||||
expected.GetNamedObject(L"properties").SetNamedValue(m_defaultSettingsName, expectedProperties);
|
||||
|
||||
const auto actual = json::JsonObject::Parse(settings.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(SettingsAddString)
|
||||
{
|
||||
const auto value = L"string text ";
|
||||
|
||||
Settings settings(nullptr, m_moduleName);
|
||||
settings.add_string(m_defaultSettingsName, m_defaultSettingsDescription, value);
|
||||
|
||||
auto expected = m_defaultSettingsJson;
|
||||
auto expectedProperties = createSettingsProperties(L"string_text");
|
||||
expectedProperties.SetNamedValue(L"value", json::JsonValue::CreateStringValue(value));
|
||||
expected.GetNamedObject(L"properties").SetNamedValue(m_defaultSettingsName, expectedProperties);
|
||||
|
||||
const auto actual = json::JsonObject::Parse(settings.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(SettingsAddStringMultiline)
|
||||
{
|
||||
const auto value = L"Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit,\nsed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\nUt enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\nDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\nExcepteur sint occaecat cupidatat non proident,\nsunt in culpa qui officia deserunt mollit anim id est laborum.";
|
||||
|
||||
Settings settings(nullptr, m_moduleName);
|
||||
settings.add_multiline_string(m_defaultSettingsName, m_defaultSettingsDescription, value);
|
||||
|
||||
auto expected = m_defaultSettingsJson;
|
||||
auto expectedProperties = createSettingsProperties(L"string_text");
|
||||
expectedProperties.SetNamedValue(L"value", json::JsonValue::CreateStringValue(value));
|
||||
expectedProperties.SetNamedValue(L"multiline", json::JsonValue::CreateBooleanValue(true));
|
||||
expected.GetNamedObject(L"properties").SetNamedValue(m_defaultSettingsName, expectedProperties);
|
||||
|
||||
const auto actual = json::JsonObject::Parse(settings.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(SettingsAddColorPicker)
|
||||
{
|
||||
const auto value = L"#ffffff";
|
||||
|
||||
Settings settings(nullptr, m_moduleName);
|
||||
settings.add_color_picker(m_defaultSettingsName, m_defaultSettingsDescription, value);
|
||||
|
||||
auto expected = m_defaultSettingsJson;
|
||||
auto expectedProperties = createSettingsProperties(L"color_picker");
|
||||
expectedProperties.SetNamedValue(L"value", json::JsonValue::CreateStringValue(value));
|
||||
expected.GetNamedObject(L"properties").SetNamedValue(m_defaultSettingsName, expectedProperties);
|
||||
|
||||
const auto actual = json::JsonObject::Parse(settings.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(SettingsAddHotkey)
|
||||
{
|
||||
const auto value = PowerToysSettings::HotkeyObject::from_settings(true, true, true, true, 0);
|
||||
|
||||
Settings settings(nullptr, m_moduleName);
|
||||
settings.add_hotkey(m_defaultSettingsName, m_defaultSettingsDescription, value);
|
||||
|
||||
auto expected = m_defaultSettingsJson;
|
||||
auto expectedProperties = createSettingsProperties(L"hotkey");
|
||||
expectedProperties.SetNamedValue(L"value", value.get_json());
|
||||
expected.GetNamedObject(L"properties").SetNamedValue(m_defaultSettingsName, expectedProperties);
|
||||
|
||||
const auto actual = json::JsonObject::Parse(settings.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(SettingsAddChoiceGroup)
|
||||
{
|
||||
const auto value = L"choice group value";
|
||||
const auto keysAndTexts = {
|
||||
std::make_pair<std::wstring, std::wstring>(L"key1", L"value1"),
|
||||
std::make_pair<std::wstring, std::wstring>(L"key2", L"value2"),
|
||||
std::make_pair<std::wstring, std::wstring>(L"key3", L"value3")
|
||||
};
|
||||
|
||||
Settings settings(nullptr, m_moduleName);
|
||||
settings.add_choice_group(m_defaultSettingsName, m_defaultSettingsDescription, value, keysAndTexts);
|
||||
|
||||
auto expected = m_defaultSettingsJson;
|
||||
auto expectedProperties = createSettingsProperties(L"choice_group");
|
||||
expectedProperties.SetNamedValue(L"value", json::JsonValue::CreateStringValue(value));
|
||||
json::JsonArray options;
|
||||
for (const auto& [key, text] : keysAndTexts)
|
||||
{
|
||||
json::JsonObject entry;
|
||||
entry.SetNamedValue(L"key", json::value(key));
|
||||
entry.SetNamedValue(L"text", json::value(text));
|
||||
options.Append(std::move(entry));
|
||||
}
|
||||
expectedProperties.SetNamedValue(L"options", std::move(options));
|
||||
expected.GetNamedObject(L"properties").SetNamedValue(m_defaultSettingsName, expectedProperties);
|
||||
|
||||
const auto actual = json::JsonObject::Parse(settings.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(SettingsAddChoiceGroupEmpty)
|
||||
{
|
||||
const auto value = L"choice group value";
|
||||
|
||||
Settings settings(nullptr, m_moduleName);
|
||||
settings.add_choice_group(m_defaultSettingsName, m_defaultSettingsDescription, value, {});
|
||||
|
||||
auto expected = m_defaultSettingsJson;
|
||||
auto expectedProperties = createSettingsProperties(L"choice_group");
|
||||
expectedProperties.SetNamedValue(L"value", json::JsonValue::CreateStringValue(value));
|
||||
expectedProperties.SetNamedValue(L"options", json::JsonArray());
|
||||
expected.GetNamedObject(L"properties").SetNamedValue(m_defaultSettingsName, expectedProperties);
|
||||
|
||||
const auto actual = json::JsonObject::Parse(settings.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(SettingsAddDropdown)
|
||||
{
|
||||
const auto value = L"dropdown value";
|
||||
const auto keysAndTexts = {
|
||||
std::make_pair<std::wstring, std::wstring>(L"key1", L"value1"),
|
||||
std::make_pair<std::wstring, std::wstring>(L"key2", L"value2"),
|
||||
std::make_pair<std::wstring, std::wstring>(L"key3", L"value3")
|
||||
};
|
||||
|
||||
Settings settings(nullptr, m_moduleName);
|
||||
settings.add_dropdown(m_defaultSettingsName, m_defaultSettingsDescription, value, keysAndTexts);
|
||||
|
||||
auto expected = m_defaultSettingsJson;
|
||||
auto expectedProperties = createSettingsProperties(L"dropdown");
|
||||
expectedProperties.SetNamedValue(L"value", json::JsonValue::CreateStringValue(value));
|
||||
json::JsonArray options;
|
||||
for (const auto& [key, text] : keysAndTexts)
|
||||
{
|
||||
json::JsonObject entry;
|
||||
entry.SetNamedValue(L"key", json::value(key));
|
||||
entry.SetNamedValue(L"text", json::value(text));
|
||||
options.Append(std::move(entry));
|
||||
}
|
||||
expectedProperties.SetNamedValue(L"options", std::move(options));
|
||||
expected.GetNamedObject(L"properties").SetNamedValue(m_defaultSettingsName, expectedProperties);
|
||||
|
||||
const auto actual = json::JsonObject::Parse(settings.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(SettingsAddDropdownEmpty)
|
||||
{
|
||||
const auto value = L"dropdown value";
|
||||
|
||||
Settings settings(nullptr, m_moduleName);
|
||||
settings.add_dropdown(m_defaultSettingsName, m_defaultSettingsDescription, value, {});
|
||||
|
||||
auto expected = m_defaultSettingsJson;
|
||||
auto expectedProperties = createSettingsProperties(L"dropdown");
|
||||
expectedProperties.SetNamedValue(L"value", json::JsonValue::CreateStringValue(value));
|
||||
expected.GetNamedObject(L"properties").SetNamedValue(m_defaultSettingsName, expectedProperties);
|
||||
|
||||
const auto actual = json::JsonObject::Parse(settings.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(SettingsAddCustomAction)
|
||||
{
|
||||
const auto value = L"custom action value";
|
||||
const std::wstring buttonText = L"button text";
|
||||
|
||||
Settings settings(nullptr, m_moduleName);
|
||||
settings.add_custom_action(m_defaultSettingsName, m_defaultSettingsDescription, buttonText, value);
|
||||
|
||||
auto expected = m_defaultSettingsJson;
|
||||
auto expectedProperties = createSettingsProperties(L"custom_action");
|
||||
expectedProperties.SetNamedValue(L"value", json::JsonValue::CreateStringValue(value));
|
||||
expectedProperties.SetNamedValue(L"button_text", json::JsonValue::CreateStringValue(buttonText));
|
||||
expected.GetNamedObject(L"properties").SetNamedValue(m_defaultSettingsName, expectedProperties);
|
||||
|
||||
const auto actual = json::JsonObject::Parse(settings.serialize());
|
||||
|
||||
compareJsons(expected, actual);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CLASS(CustomActionObjectUnitTests)
|
||||
{
|
||||
PowerToyValues values = PowerToyValues::from_json_string(m_json);
|
||||
Assert::IsTrue(values.is_string_value(L"string_text"));
|
||||
public:
|
||||
TEST_METHOD(CustomActionObjectName)
|
||||
{
|
||||
const std::wstring json = L"{\"action_name\": \"action name\", \"value\": \"action value\"}";
|
||||
CustomActionObject obj = CustomActionObject::from_json_string(json);
|
||||
Assert::AreEqual(std::wstring(L"action name"), obj.get_name());
|
||||
}
|
||||
|
||||
std::wstring value = values.get_string_value(L"string_text");
|
||||
std::wstring expected = L"a quick fox";
|
||||
Assert::AreEqual(expected, value);
|
||||
}
|
||||
TEST_METHOD(CustomActionObjectValue)
|
||||
{
|
||||
const std::wstring json = L"{\"action_name\": \"action name\", \"value\": \"action value\"}";
|
||||
CustomActionObject obj = CustomActionObject::from_json_string(json);
|
||||
Assert::AreEqual(std::wstring(L"action value"), obj.get_value());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_METHOD(LoadFromJsonColorPicker)
|
||||
TEST_CLASS(HotkeyObjectUnitTests)
|
||||
{
|
||||
PowerToyValues values = PowerToyValues::from_json_string(m_json);
|
||||
Assert::IsTrue(values.is_string_value(L"color_picker"));
|
||||
private:
|
||||
json::JsonObject m_defaultHotkeyJson = json::JsonObject::Parse(L"{\"key\":\"(Key 0)\", \"code\": 123, \"win\": true, \"ctrl\": true, \"alt\": true, \"shift\": true}");
|
||||
json::JsonObject m_defaultHotkeyJsonAlternative = json::JsonObject::Parse(L"{\"key\":\"(Key 0)\", \"code\": 123, \"win\": false, \"ctrl\": false, \"alt\": false, \"shift\": false}");
|
||||
|
||||
std::wstring value = values.get_string_value(L"color_picker");
|
||||
std::wstring expected = L"#ff8d12";
|
||||
Assert::AreEqual(expected, value);
|
||||
}
|
||||
};
|
||||
public:
|
||||
TEST_METHOD(GetKeyFromJson)
|
||||
{
|
||||
HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson);
|
||||
Assert::AreEqual(std::wstring(L"(Key 0)"), object.get_key());
|
||||
}
|
||||
|
||||
TEST_METHOD(GetKeyFromJsonString)
|
||||
{
|
||||
HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify());
|
||||
Assert::AreEqual(std::wstring(L"(Key 0)"), object.get_key());
|
||||
}
|
||||
|
||||
TEST_METHOD(GetCodeFromJson)
|
||||
{
|
||||
HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson);
|
||||
Assert::AreEqual(UINT(123), object.get_code());
|
||||
}
|
||||
|
||||
TEST_METHOD(GetCodeFromJsonString)
|
||||
{
|
||||
HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify());
|
||||
Assert::AreEqual(UINT(123), object.get_code());
|
||||
}
|
||||
|
||||
TEST_METHOD(GetCodeFromSettings)
|
||||
{
|
||||
HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123);
|
||||
Assert::AreEqual(UINT(123), object.get_code());
|
||||
}
|
||||
|
||||
TEST_METHOD(GetWinPressedFromJson)
|
||||
{
|
||||
HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson);
|
||||
Assert::AreEqual(true, object.win_pressed());
|
||||
|
||||
HotkeyObject objectNegativeValues = HotkeyObject::from_json(m_defaultHotkeyJsonAlternative);
|
||||
Assert::AreEqual(false, objectNegativeValues.win_pressed());
|
||||
}
|
||||
|
||||
TEST_METHOD(GetWinPressedFromJsonString)
|
||||
{
|
||||
HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify());
|
||||
Assert::AreEqual(true, object.win_pressed());
|
||||
|
||||
HotkeyObject objectNegativeValues = HotkeyObject::from_json_string(m_defaultHotkeyJsonAlternative.Stringify());
|
||||
Assert::AreEqual(false, objectNegativeValues.win_pressed());
|
||||
}
|
||||
|
||||
TEST_METHOD(GetWinPressedFromSettings)
|
||||
{
|
||||
HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123);
|
||||
Assert::AreEqual(true, object.win_pressed());
|
||||
|
||||
HotkeyObject objectNegativeValues = HotkeyObject::from_settings(false, true, true, true, 123);
|
||||
Assert::AreEqual(false, objectNegativeValues.win_pressed());
|
||||
}
|
||||
|
||||
TEST_METHOD(GetCtrlPressedFromJson)
|
||||
{
|
||||
HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson);
|
||||
Assert::AreEqual(true, object.ctrl_pressed());
|
||||
|
||||
HotkeyObject objectNegativeValues = HotkeyObject::from_json(m_defaultHotkeyJsonAlternative);
|
||||
Assert::AreEqual(false, objectNegativeValues.ctrl_pressed());
|
||||
}
|
||||
|
||||
TEST_METHOD(GetCtrlPressedFromJsonString)
|
||||
{
|
||||
HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify());
|
||||
Assert::AreEqual(true, object.ctrl_pressed());
|
||||
|
||||
HotkeyObject objectNegativeValues = HotkeyObject::from_json_string(m_defaultHotkeyJsonAlternative.Stringify());
|
||||
Assert::AreEqual(false, objectNegativeValues.ctrl_pressed());
|
||||
}
|
||||
|
||||
TEST_METHOD(GetCtrlPressedFromSettings)
|
||||
{
|
||||
HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123);
|
||||
Assert::AreEqual(true, object.ctrl_pressed());
|
||||
|
||||
HotkeyObject objectNegativeValues = HotkeyObject::from_settings(true, false, true, true, 123);
|
||||
Assert::AreEqual(false, objectNegativeValues.ctrl_pressed());
|
||||
}
|
||||
|
||||
TEST_METHOD(GetAltPressedFromJson)
|
||||
{
|
||||
HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson);
|
||||
Assert::AreEqual(true, object.alt_pressed());
|
||||
|
||||
HotkeyObject objectNegativeValues = HotkeyObject::from_json(m_defaultHotkeyJsonAlternative);
|
||||
Assert::AreEqual(false, objectNegativeValues.alt_pressed());
|
||||
}
|
||||
|
||||
TEST_METHOD(GetAltPressedFromJsonString)
|
||||
{
|
||||
HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify());
|
||||
Assert::AreEqual(true, object.alt_pressed());
|
||||
|
||||
HotkeyObject objectNegativeValues = HotkeyObject::from_json_string(m_defaultHotkeyJsonAlternative.Stringify());
|
||||
Assert::AreEqual(false, objectNegativeValues.alt_pressed());
|
||||
}
|
||||
|
||||
TEST_METHOD(GetAltPressedFromSettings)
|
||||
{
|
||||
HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123);
|
||||
Assert::AreEqual(true, object.alt_pressed());
|
||||
|
||||
HotkeyObject objectNegativeValues = HotkeyObject::from_settings(true, true, false, true, 123);
|
||||
Assert::AreEqual(false, objectNegativeValues.alt_pressed());
|
||||
}
|
||||
|
||||
TEST_METHOD(GetShiftPressedFromJson)
|
||||
{
|
||||
HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson);
|
||||
Assert::AreEqual(true, object.shift_pressed());
|
||||
|
||||
HotkeyObject objectNegativeValues = HotkeyObject::from_json(m_defaultHotkeyJsonAlternative);
|
||||
Assert::AreEqual(false, objectNegativeValues.shift_pressed());
|
||||
}
|
||||
|
||||
TEST_METHOD(GetShiftPressedFromJsonString)
|
||||
{
|
||||
HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify());
|
||||
Assert::AreEqual(true, object.shift_pressed());
|
||||
|
||||
HotkeyObject objectNegativeValues = HotkeyObject::from_json_string(m_defaultHotkeyJsonAlternative.Stringify());
|
||||
Assert::AreEqual(false, objectNegativeValues.shift_pressed());
|
||||
}
|
||||
|
||||
TEST_METHOD(GetShiftPressedFromSettings)
|
||||
{
|
||||
HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123);
|
||||
Assert::AreEqual(true, object.shift_pressed());
|
||||
|
||||
HotkeyObject objectNegativeValues = HotkeyObject::from_settings(true, true, true, false, 123);
|
||||
Assert::AreEqual(false, objectNegativeValues.shift_pressed());
|
||||
}
|
||||
|
||||
TEST_METHOD(GetModifiersRepeat)
|
||||
{
|
||||
std::map<UINT, HotkeyObject> expectedMap = {
|
||||
std::make_pair(0x0000, HotkeyObject::from_settings(false, false, false, false, 0)),
|
||||
std::make_pair(0x0001, HotkeyObject::from_settings(false, false, true, false, 0)),
|
||||
std::make_pair(0x0002, HotkeyObject::from_settings(false, true, false, false, 0)),
|
||||
std::make_pair(0x0003, HotkeyObject::from_settings(false, true, true, false, 0)),
|
||||
std::make_pair(0x0004, HotkeyObject::from_settings(false, false, false, true, 0)),
|
||||
std::make_pair(0x0005, HotkeyObject::from_settings(false, false, true, true, 0)),
|
||||
std::make_pair(0x0006, HotkeyObject::from_settings(false, true, false, true, 0)),
|
||||
std::make_pair(0x0007, HotkeyObject::from_settings(false, true, true, true, 0)),
|
||||
std::make_pair(0x0008, HotkeyObject::from_settings(true, false, false, false, 0)),
|
||||
std::make_pair(0x0009, HotkeyObject::from_settings(true, false, true, false, 0)),
|
||||
std::make_pair(0x000A, HotkeyObject::from_settings(true, true, false, false, 0)),
|
||||
std::make_pair(0x000B, HotkeyObject::from_settings(true, true, true, false, 0)),
|
||||
std::make_pair(0x000C, HotkeyObject::from_settings(true, false, false, true, 0)),
|
||||
std::make_pair(0x000D, HotkeyObject::from_settings(true, false, true, true, 0)),
|
||||
std::make_pair(0x000E, HotkeyObject::from_settings(true, true, false, true, 0)),
|
||||
std::make_pair(0x000F, HotkeyObject::from_settings(true, true, true, true, 0))
|
||||
};
|
||||
|
||||
for (const auto& iter : expectedMap)
|
||||
{
|
||||
Assert::AreEqual(iter.first, iter.second.get_modifiers_repeat());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_METHOD(GetModifiers)
|
||||
{
|
||||
std::map<UINT, HotkeyObject> expectedMap = {
|
||||
std::make_pair(0x4000, HotkeyObject::from_settings(false, false, false, false, 0)),
|
||||
std::make_pair(0x4001, HotkeyObject::from_settings(false, false, true, false, 0)),
|
||||
std::make_pair(0x4002, HotkeyObject::from_settings(false, true, false, false, 0)),
|
||||
std::make_pair(0x4003, HotkeyObject::from_settings(false, true, true, false, 0)),
|
||||
std::make_pair(0x4004, HotkeyObject::from_settings(false, false, false, true, 0)),
|
||||
std::make_pair(0x4005, HotkeyObject::from_settings(false, false, true, true, 0)),
|
||||
std::make_pair(0x4006, HotkeyObject::from_settings(false, true, false, true, 0)),
|
||||
std::make_pair(0x4007, HotkeyObject::from_settings(false, true, true, true, 0)),
|
||||
std::make_pair(0x4008, HotkeyObject::from_settings(true, false, false, false, 0)),
|
||||
std::make_pair(0x4009, HotkeyObject::from_settings(true, false, true, false, 0)),
|
||||
std::make_pair(0x400A, HotkeyObject::from_settings(true, true, false, false, 0)),
|
||||
std::make_pair(0x400B, HotkeyObject::from_settings(true, true, true, false, 0)),
|
||||
std::make_pair(0x400C, HotkeyObject::from_settings(true, false, false, true, 0)),
|
||||
std::make_pair(0x400D, HotkeyObject::from_settings(true, false, true, true, 0)),
|
||||
std::make_pair(0x400E, HotkeyObject::from_settings(true, true, false, true, 0)),
|
||||
std::make_pair(0x400F, HotkeyObject::from_settings(true, true, true, true, 0))
|
||||
};
|
||||
|
||||
for (const auto& iter : expectedMap)
|
||||
{
|
||||
Assert::AreEqual(iter.first, iter.second.get_modifiers());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -95,6 +95,7 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="UnitTestsVersionHelper.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
<ClCompile Include="Settings.Tests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="UnitTestsVersionHelper.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
|
||||
97
src/common/UnitTests-CommonLib/UnitTestsVersionHelper.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "VersionHelper.h"
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
|
||||
namespace UnitTestsVersionHelper
|
||||
{
|
||||
const int MAJOR_VERSION_0 = 0;
|
||||
const int MINOR_VERSION_12 = 12;
|
||||
const int REVISION_VERSION_0 = 0;
|
||||
|
||||
TEST_CLASS(UnitTestsVersionHelper)
|
||||
{
|
||||
public:
|
||||
TEST_METHOD(integerConstructorShouldProprelyInitializateVersionNumbers)
|
||||
{
|
||||
VersionHelper sut(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);
|
||||
|
||||
Assert::AreEqual(MAJOR_VERSION_0, sut.major);
|
||||
Assert::AreEqual(MINOR_VERSION_12, sut.minor);
|
||||
Assert::AreEqual(REVISION_VERSION_0, sut.revision);
|
||||
}
|
||||
TEST_METHOD(integerConstructorShouldProprelyInitializateWithDifferentVersionNumbers)
|
||||
{
|
||||
const int testcaseMajor = 2;
|
||||
const int testcaseMinor = 25;
|
||||
const int testcaseRevision = 1;
|
||||
VersionHelper sut(testcaseMajor, testcaseMinor, testcaseRevision);
|
||||
|
||||
Assert::AreEqual(testcaseMajor, sut.major);
|
||||
Assert::AreEqual(testcaseMinor, sut.minor);
|
||||
Assert::AreEqual(testcaseRevision, sut.revision);
|
||||
}
|
||||
TEST_METHOD(stringConstructorShouldProprelyInitializateVersionNumbers)
|
||||
{
|
||||
|
||||
VersionHelper sut("v0.12.3");
|
||||
|
||||
Assert::AreEqual(0, sut.major);
|
||||
Assert::AreEqual(12, sut.minor);
|
||||
Assert::AreEqual(3, sut.revision);
|
||||
}
|
||||
TEST_METHOD(stringConstructorShouldProprelyInitializateWithDifferentVersionNumbers)
|
||||
{
|
||||
VersionHelper sut("v2.25.1");
|
||||
|
||||
Assert::AreEqual(2, sut.major);
|
||||
Assert::AreEqual(25, sut.minor);
|
||||
Assert::AreEqual(1, sut.revision);
|
||||
}
|
||||
TEST_METHOD(whenMajorVersionIsGreaterComparationOperatorShouldReturnProperValue)
|
||||
{
|
||||
VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);
|
||||
VersionHelper lhs(MAJOR_VERSION_0 + 1, MINOR_VERSION_12, REVISION_VERSION_0);
|
||||
|
||||
Assert::IsTrue(lhs > rhs);
|
||||
}
|
||||
TEST_METHOD(whenMajorVersionIsLesserComparationOperatorShouldReturnProperValue)
|
||||
{
|
||||
VersionHelper rhs(MAJOR_VERSION_0 + 1, MINOR_VERSION_12, REVISION_VERSION_0);
|
||||
VersionHelper lhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);
|
||||
|
||||
Assert::IsFalse(lhs > rhs);
|
||||
}
|
||||
TEST_METHOD(whenMajorVersionIsEqualComparationOperatorShouldCompareMinorVersionValue)
|
||||
{
|
||||
VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12 - 1, REVISION_VERSION_0);
|
||||
|
||||
VersionHelper lhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);
|
||||
|
||||
Assert::IsTrue(lhs > rhs);
|
||||
}
|
||||
TEST_METHOD(whenMajorVersionIsEqualComparationOperatorShouldCompareMinorVersionValue2)
|
||||
{
|
||||
VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);
|
||||
VersionHelper lhs(MAJOR_VERSION_0, MINOR_VERSION_12 - 1, REVISION_VERSION_0);
|
||||
|
||||
Assert::IsFalse(lhs > rhs);
|
||||
}
|
||||
|
||||
TEST_METHOD(whenMajorAndMinorVersionIsEqualComparationOperatorShouldCompareRevisionValue)
|
||||
{
|
||||
VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);
|
||||
VersionHelper lhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0 + 1);
|
||||
|
||||
Assert::IsTrue(lhs > rhs);
|
||||
}
|
||||
TEST_METHOD(whenMajorAndMinorVersionIsEqualComparationOperatorShouldCompareRevisionValue2)
|
||||
{
|
||||
VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0 + 1);
|
||||
VersionHelper lhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);
|
||||
|
||||
Assert::IsFalse(lhs > rhs);
|
||||
}
|
||||
};
|
||||
}
|
||||
63
src/common/VersionHelper.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "pch.h"
|
||||
#include "VersionHelper.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
VersionHelper::VersionHelper(std::string str)
|
||||
{
|
||||
std::replace(str.begin(), str.end(), '.', ' ');
|
||||
std::replace(str.begin(), str.end(), 'v', ' ');
|
||||
std::stringstream ss;
|
||||
|
||||
ss << str;
|
||||
|
||||
std::string temp;
|
||||
ss >> temp;
|
||||
std::stringstream(temp) >> major;
|
||||
ss >> temp;
|
||||
std::stringstream(temp) >> minor;
|
||||
ss >> temp;
|
||||
std::stringstream(temp) >> revision;
|
||||
}
|
||||
|
||||
VersionHelper::VersionHelper(int major, int minor, int revision) :
|
||||
major(major),
|
||||
minor(minor),
|
||||
revision(revision)
|
||||
{
|
||||
}
|
||||
|
||||
bool VersionHelper::operator>(const VersionHelper& rhs)
|
||||
{
|
||||
if (major < rhs.major)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (major > rhs.major)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (minor < rhs.minor)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (minor > rhs.minor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (revision < rhs.revision)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/common/VersionHelper.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
struct VersionHelper
|
||||
{
|
||||
VersionHelper(std::string str);
|
||||
VersionHelper(int major, int minor, int revision);
|
||||
|
||||
bool operator>(const VersionHelper& rhs);
|
||||
|
||||
int major;
|
||||
int minor;
|
||||
int revision;
|
||||
};
|
||||
60
src/common/com_object_factory.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include <Unknwn.h>
|
||||
#include <winrt/base.h>
|
||||
#include <atomic>
|
||||
|
||||
template<typename T>
|
||||
class com_object_factory : public IClassFactory
|
||||
{
|
||||
public:
|
||||
HRESULT __stdcall QueryInterface(const IID & riid, void** ppv) override
|
||||
{
|
||||
static const QITAB qit[] = {
|
||||
QITABENT(com_object_factory, IClassFactory),
|
||||
{ 0 }
|
||||
};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
ULONG __stdcall AddRef() override
|
||||
{
|
||||
return ++_refCount;
|
||||
}
|
||||
|
||||
ULONG __stdcall Release() override
|
||||
{
|
||||
LONG refCount = --_refCount;
|
||||
return refCount;
|
||||
}
|
||||
|
||||
HRESULT __stdcall CreateInstance(IUnknown* punkOuter, const IID & riid, void** ppv)
|
||||
{
|
||||
*ppv = nullptr;
|
||||
HRESULT hr;
|
||||
if (punkOuter)
|
||||
{
|
||||
hr = CLASS_E_NOAGGREGATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
T* psrm = new (std::nothrow) T();
|
||||
HRESULT hr = psrm ? S_OK : E_OUTOFMEMORY;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = psrm->QueryInterface(riid, ppv);
|
||||
psrm->Release();
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT __stdcall LockServer(BOOL)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<long> _refCount;
|
||||
};
|
||||