Compare commits

...

296 Commits

Author SHA1 Message Date
Enrico Giordani
6787af413e Increment version to 0.15.1 (#1428) 2020-03-03 22:31:57 +01:00
stefansjfw
0199b4e212 Handle exception while editor is parsing custom layouts (#1430)
* Fix migrating never applied custom zonesets

* Handle json parsing exception in LoadCustomModels()
2020-03-03 22:31:22 +01:00
stefansjfw
121be772df Fix migrating never applied custom zonesets (#1427) 2020-03-03 21:48:22 +01:00
Enrico Giordani
f3b3e3eded Sanity check for imported settings that may have invalid data. (#1426) 2020-03-03 21:45:25 +01:00
Clint Rutkas
02c08c942d 0.15 update to readme to master (#1408)
* Getting ready for v0.15 update for readme.

* getting ready for 0.15

* spelling tweak

* filled in update section

* fixed spelling mistakes

* updating to what POR is

* Update README.md

* Update README.md

* adding back in MSI

* getting readme ready for 0.15

* tweaks

* adding oss to oss links

* fixing links

* tweaking file names

* Update README.md

* Update README.md

* Update README.md

fixing typo

* Update README.md
2020-03-03 11:14:30 -08:00
Clint Rutkas
b2370f5c5f Update README.md (#1412) 2020-03-02 16:21:51 -08:00
vldmr11080
6556e1b4a2 Skip cloning device information from parent virtual desktop if it is deleted. (#1415) 2020-03-02 18:52:38 +01:00
Clint Rutkas
699921d464 build break, seeing if this was root case 2020-02-28 14:13:43 -08:00
Enrico Giordani
5c84fbba9a [CDPx] archive symbols to Symbol Server (#1407) 2020-02-28 13:44:37 -08:00
yuyoyuppe
0b02422e7d wix: add (Preview) for MSI product name 2020-02-28 12:23:43 +03:00
Clint Rutkas
677bff55c2 Update pipeline.user.windows.yml (#1398) 2020-02-27 17:29:22 -08:00
Enrico Giordani
3d03bea582 [CDPx] move build script out of .pipeline (#1394) 2020-02-27 19:18:11 +01:00
Enrico Giordani
278a77247d [CDPx] use explicit filenames for the MSIX assets (#1393)
Approved
2020-02-27 07:46:00 -08:00
Enrico Giordani
b83a8dcb5d [CDPx] remove 'signing_options' for package (#1390)
A global signing option is already defined.
2020-02-27 16:03:38 +01:00
Enrico Giordani
9bce103dad [CDPx] sign MSIX package and bundle (#1389) 2020-02-27 13:41:11 +01:00
Clint Rutkas
dfcc4e1b3a adding preview tag for desktop and start menu (#1384) 2020-02-27 13:10:08 +01:00
vldmr11080
66892aea60 Secure acces from multiple threads to JSONHelpers (add missing lock) (#1375) 2020-02-27 09:52:14 +01:00
yuyoyuppe
5c708b43c2 wix: add missing libs for FZ editor 2020-02-27 11:27:59 +03:00
stefansjfw
e2026aedbc Fix typo in powerrenamer README (#1378) 2020-02-26 16:33:50 -08:00
Enrico Giordani
1911fc2e65 Update BinSkim exclude list (#1377) 2020-02-26 13:44:25 -08:00
TorchGM
e0446a73fa Change Windows Store to Microsoft Store in README (#1369)
The Windows Store was renamed to the Microsoft Store back in 2017, best to keep things up-to-date to avoid potential confusion.
2020-02-26 12:34:05 -08:00
yuyoyuppe
16b1bfa4d0 increment version to 0.15 🎉 2020-02-26 23:21:17 +03:00
PrzemyslawTusinski
f015995ac4 Now updater is comparing versions instead of comparing thier strings 2020-02-26 23:06:44 +03:00
yuyoyuppe
0016836022 runner: periodically check if there's a new version available on github and offer a visit 2020-02-26 23:06:44 +03:00
yuyoyuppe
c543b7585a notifications: add support for unpackaged apps and protocol activation 2020-02-26 23:06:44 +03:00
yuyoyuppe
b90f1fc237 common: always use 0 for build number and make get_product_version return "vX.X.X" 2020-02-26 23:06:44 +03:00
Enrico Giordani
f892338098 [CDPx] fix for makeappx, update SDK for MSI (#1373) 2020-02-26 11:05:15 -08:00
Enrico Giordani
defead108a [CDPx] remove nuget.config and update restore script (#1370) 2020-02-26 10:23:53 -08:00
vldmr11080
1f8f9aaf81 Revert "Swallow shift keyboard event when dragging window (#1362)" (#1363)
This reverts commit 2f9b753c5b.
2020-02-26 08:11:39 +01:00
Enrico Giordani
3b32a3164b [CDPx] update nuget feed (#1364) 2020-02-25 19:38:47 -08:00
vldmr11080
2f9b753c5b Swallow shift keyboard event when dragging window (#1362) 2020-02-25 21:03:14 +01:00
Seraphima Zykova
b1ac1859be Removed FancyZones unit-test (#1360) 2020-02-25 17:14:59 +03:00
Enrico Giordani
74b076e31f [CDPx] update SDK, restore telemetry, build MSIX (#1358) 2020-02-24 23:49:28 +01:00
Bartosz Sosnowski
e3057b5e46 tools: add tool to debug FancyZones zonable windows (#1355)
Uses FancyZones logic to test if window is zonable or not. Displays
window styles and results for various tests if the window should be
zonable or not.
2020-02-24 17:45:50 +01:00
Enrico Giordani
92a8b5aa4d MSIX is "Experimental" (#1348) 2020-02-21 11:13:21 +01:00
Enrico Giordani
9b7f92188d Runner check for MSI and MSIX (#1345)
* Add startup check for the MSI version of PT

* Alert if another instance of PowerToys is already running
2020-02-21 11:12:04 +01:00
Clint Rutkas
77301e2930 bug fix 2020-02-19 13:10:42 -08:00
Clint Rutkas
babfc9ade3 Adding in HitTester App 2020-02-19 13:09:18 -08:00
Andrey Nekrasov
883bbf102a settings: add a clarifying label if running as elevated (#1330) 2020-02-19 19:31:09 +03:00
Andrey Nekrasov
e21f83267a settings: remove Restart as a user button in an elevated context (#1328) 2020-02-19 18:51:24 +03:00
yuyoyuppe
27f0782465 settings: fix general settings hanging on save for a non-admin user 2020-02-19 17:20:09 +03:00
yuyoyuppe
d45b0dee10 runner: fix Restart as... option 2020-02-19 17:20:09 +03:00
Enrico Giordani
2c2a29cd91 Setup: sign PowerRenameExt.dll (#1313) 2020-02-18 22:02:39 +01:00
Yevhenii Holovachov
607a297c4a "Always run as administrator" and "Restart as ..." only for administrator account (#1318) 2020-02-18 20:56:34 +01:00
Clint Rutkas
e177c5c94c moving to https://github.com/microsoft/PowerToys/wiki/Version-1.0-Strategy (#1315) 2020-02-18 10:50:43 -08:00
Clint Rutkas
7fb3456e83 Update v1.0.md 2020-02-18 10:19:21 -08:00
Clint Rutkas
d37bb2c7f9 v1 spec (#1275)
* v1 spec, from here we'll create a roadmap much like Terminal.  (https://github.com/microsoft/terminal/blob/master/doc/terminal-v1-roadmap.md)

* adding in more issue xref links

* add in UX migration time

* Update v1.0.md

* Update v1.0.md

* Update v1.0.md
2020-02-18 09:27:00 -08:00
Andrey Nekrasov
20519e3b81 MSIX: prompt and uninstall MSI PT version (#1248) 2020-02-18 18:11:01 +03:00
vldmr11080
733613ad28 Introduce handling of new/old work areas (#1296)
* Introduce handling of new/old work areas (defined by virtual desktop id and monitor)

* Save data to JSON storage only once after we register all deleted virtual desktops

* Update saving mechanism

* Remove resolution from unique identifier

* Update comments related to new unique identifier

* Don't handle NULL GUID as it is default one

* Revert "Remove resolution from unique identifier"

This reverts commit 5a36651217.

* Revert "Update comments related to new unique identifier"

This reverts commit 8e89802549.

* removed MigrateDeviceInfoFromRegistry

Co-authored-by: Seraphima Zykova <zykovas91@gmail.com>
2020-02-18 11:55:08 +01:00
Seraphima Zykova
604070763d Add telemetry event for FZ editor (#1294)
* trace zones settings changes
2020-02-17 19:40:02 +03:00
yuyoyuppe
93f88800b8 MSIX: do not kill explorer.exe, since it's only necessary for the MSI version 2020-02-17 18:38:14 +03:00
yuyoyuppe
9607888fc5 PowerRename: bring the rename dialog to foreground 2020-02-17 18:38:14 +03:00
Andrey Nekrasov
1e6936a8c3 Thread safety for FanncyZonesData (#1281)
* FancyZones: make FancyZonesData thread-safe

* fixup: format affected sources

* fixup: clang-format case-style and format FancyZones.cpp

* fixup! add missing lock
2020-02-17 18:28:49 +03:00
Clint Rutkas
cdf2f6b5b4 moving stuff to wiki (#1302) 2020-02-14 13:49:31 -08:00
Andrey Nekrasov
fa3ce8de64 MSIX: add missing dependencies for the FancyZonesEditor (#1298) 2020-02-14 11:57:20 +03:00
Seraphima
59d218d623 Add telemetry event for PowerRename settings (#1279)
* moved MAX_INPUT_STRING_LEN constant
* added settings changed event log
2020-02-13 12:44:03 +03:00
Jessica Yuwono
49fa1b6762 Added PowerLauncher spec and images (#1109)
* Added PowerLauncher spec and images

* Fixed images path

* Addressed review comments

* Fixed images

* Addressed review comments, and added link to keyboard shortcut manager PowerToy

* Added Ueli in comparison table

* Added keyboard input element

* Added suggestions from community

* Moved default shell and terminal settings

* Addressed feedback

* Added community suggestion

* Modified spec based on feedback

* Modified spec based on suggestions

* Added keyboard shortcuts to context menu options
2020-02-12 15:30:40 -08:00
Clint Rutkas
a2fe4a0b80 removing done specs to wiki (#1276) 2020-02-12 14:55:39 -08:00
vldmr11080
86e7a19a98 Update FancyZones-DCR.md (#1280) 2020-02-12 19:06:15 +01:00
Seraphima
8c86c3dc1b Update FancyZones telemetry event for settings changed (#1268) 2020-02-12 13:08:11 +03:00
Seraphima
2bef7631ae Add telemetry event for general settings (#1269)
* telemetry for general settings
2020-02-12 13:03:40 +03:00
vldmr11080
550d76a447 Add design change request for improvements in virtual desktops handling (#1270) 2020-02-12 08:18:57 +01:00
Chris Davis
679b26cde4 Set the rename button to the default button on the dialog. Prior to this change, users would setup the rename inputs and hit return only to discover the cancel button had the key focus and all work would be lost. (#1271) 2020-02-11 11:33:30 -08:00
Seraphima
79c625d737 Persist app zone history in real time (#1257)
* save settings every time changes are performed
* settings are not saved on app exit
2020-02-11 14:34:37 +03:00
Seraphima
a1d277e771 Unit-tests fixes (#1265)
* fixed typecast warnings
* removed unneded tests
2020-02-11 14:33:41 +03:00
vldmr11080
bde0f2f0ba Fix crash when saving any module settings while module being disabled (#1259) 2020-02-11 07:57:11 +01:00
stefansjfw
53f830bb38 Migrate FancyZones data persisting from Registry to JSON file (#1194)
* Migrate FancyZones data persisting from Registry to JSON file

* Address PR comment: Remove redundant check

* Addres PR comment: Remove unused Dpi and add CmdArgs enum

* Address PR comment: Make methods const and inline

* Address PR comments: Expose GenerateUniqueId function and use const ref instead of passing wstring by value

* Address PR comment: Use lamdba as callback

* Address PR comment: Move GenerateUniqueId to ZoneWindowUtils namespace

* Address PR comment: Use regular comparison instead of std::wstring::compare

* Address PR comment: Use std::wstring_view for tmp file paths

* Address PR comment: Use scoped lock when accessing member data

* Address PR comment: Remove typedefs to increase code readability

* Address PR comment: removed nullptr checks with corresponding tests

* Address PR comment: Move ZoneSet object instead of copying

* Address PR comment: Make FancyZonesData instance const where possible

* Remove unnecessary gutter variable during calculating zone coordinates

* Remove uneeded subclass

* Avoid unnecessary copying and reserve space for vector if possible

* Save FancyZones data after exiting editor

* App zone history (#18)

* added window and zone set ids to app zone history

* Rename JSON file

* Remove AppZoneHistory migration

* Move parsing of ZoneWindow independent temp files outside of it

* Unit tests update (#19)

* check device existence in map
* updated ZoneSet tests
* updated JsonHelpers tests

* Use single zone count information

* Remove uneeded tests

* Remove one more test

* Remove uneeded line

* Address PR comments - Missing whitespace

* Update zoneset data for new virtual desktops (#21)

* update active zone set with actual data

* Introduce Blank zone set (used to indicate that no layout applied yet). Move parsing completely outside of ZoneWindow.

* Fix unit tests to match modifications in implementation

* Fix applying layouts on startup (second monitor)

Co-authored-by: vldmr11080 <57061786+vldmr11080@users.noreply.github.com>
Co-authored-by: Seraphima <zykovas91@gmail.com>
2020-02-10 14:59:51 +01:00
Andrey Nekrasov
a5e3207715 sln: fix project dependency order (#1249) 2020-02-10 16:07:01 +03:00
Scott Hanselman
b357a085c8 Small English grammer issue "in the desktop" -> "on the desktop" (#1238)
Small English grammer issue "in the desktop" -> "on the desktop"
2020-02-07 16:51:57 -08:00
Arjun Balgovind
9722d808f9 Update MSIX Readme with sideloading steps (#1237) 2020-02-07 14:22:49 -08:00
Bartosz Sosnowski
0fdc1d0a1f ShortcutGuide, FancyZones: split window filtering (#1225)
Splits the code use to filter windows for FancyZones and the
"active window" for the ShortcutGuide. The FancyZones logic is preserved
and merged into a single function. We keep it in common.h, as it might
be also used in other PowerToys, like maximized to new desktop. We do
however change the return type to be more descriptive. It also returns
a separate flag for if the window has a visible owner. This can be used
to implement the approved apps list.

For the ShortcutGuide, the logic is relaxed to include more windows. One
example are Explorer properties windows. Those are (and should) filtered
by the FancyZones, but should appear in the window preview in the SCG.

The new return type also includes information if the window will react
to the default Windows Snap. This is not ideal though. Currently, SCG
can only disable the entire "Windows Controls" group. OTOH windows like
"Save As..." dialogs can be snapped to corners etc., but cannot be
minimized nor maximized. Until SCG can separately disable those buttons
we will display the buttons in the enabled state only if the window
supports all settings. In the future, we should integrate FancyZones
snap override here too.
2020-02-07 15:53:57 +01:00
Andrey Nekrasov
f963d28ba8 MSIX: keep PowerRename local COM server in memory (#1222) 2020-02-07 14:21:10 +03:00
Bartosz Sosnowski
09d1af9c46 Common: remove hwnd_data_cache (#1223)
The cache was introduced to improve performance by not querying the
OS for the window process path every time we need to check if the window
is interesting to FancyZones. Since then other changes were made to the
the way we check the windows. Right now, the IsInterestingWindow function is
called when:

  1) WinKey + arrows are used
  2) window is started to be dragged
  3) window is created

1) and 2) are initiated by the user, happen only once per interaction so
their performance impact can be dismissed. The 3) happens all the time
but for the most part the check for WS_CHILD or
GetAncestor(window, GA_ROOT) == window will filter those out. In the
end, only top-level windows will be queried for their path.

Removing the cache improves code readability and will make code
maintenance easier.
2020-02-06 18:04:10 +01:00
Bartosz Sosnowski
5d8e894802 FancyZones: if window is not interesting, allow Windows snap (#1186)
Do not swallow WinKey+Arrow events for non-interesting windows. This makes apps that are in the "excluded apps" list behave as if "Override windows snap keys" is disabled - they will react to the Windows default snap.
2020-02-06 13:12:59 +01:00
Bartosz Sosnowski
0ecfbfad53 FancyZones: filter out WM_POPUP windows if they dont have maximize/minimize button or a sizable frame (#1212)
This filters out TaskView and Win32 menus.
2020-02-05 12:31:35 +01:00
Bartosz Sosnowski
ed35a143ec FancyZones: allow windows with invisible or zero-sized owner to be zonable (#1216) 2020-02-05 12:27:51 +01:00
yuyoyuppe
5089729b18 MSIX: implement initial version of notifications library (#1178) 2020-02-04 19:41:00 +03:00
yuyoyuppe
b41d2d64cb MSIX: fix uninstallation from msix_reinstall and split the scripts (#1183) 2020-02-04 18:56:10 +03:00
Bartosz Sosnowski
25e882eb78 Fancyzones: unify window filtering (#1184)
Makes FancyZone use the same code for filtering windows when windows are
being dragged and when moved by WinKey + arrows.
2020-02-03 09:32:38 +01:00
Clint Rutkas
4ef8f3da2b Update README.md (#1198) 2020-01-31 18:17:07 -08:00
sakariya
b00ce8789f Adding KeyManager spec (#1112)
* Adding KeyManager spec

* adding req changes

* req changes

* changed wording

* md edits

* edit md

* Update doc/specs/KeyboardManager.md

Co-Authored-By: Jeroen van Warmerdam <jeronevw@hotmail.com>

* further edits

* Update KeyboardManager.md

* Update KeyboardManager.md

Co-authored-by: Jeroen van Warmerdam <jeronevw@hotmail.com>
2020-01-31 16:10:30 -08:00
Betsegaw Tadele
b4f81a0c2a Import the source code for Window Walker (#1177)
Import the codebase for Window Walker 

- Not loaded into the module list 
- Not added it to the installer list.
2020-01-31 15:14:37 -08:00
yuyoyuppe
aa714f7d80 Runner: fix startup task state setting for MSIX (#1181) 2020-01-31 20:35:21 +03:00
yuyoyuppe
ca203435d1 MSIX: hide the "Run at Startup" option if running as packaged 2020-01-29 16:15:18 +03:00
Enrico Giordani
ee8893a884 MSIX: update identity name and publisher (#1176) 2020-01-29 13:06:19 +01:00
Clint Rutkas
bf89238bdf MSIX build instructions adjustmnet (#1170) 2020-01-28 15:01:17 -08:00
yuyoyuppe
360f7cf9c3 Telemetry: add WebView init failure errors 2020-01-27 20:01:36 +03:00
yuyoyuppe
482ad0e5ee Settings: initialize COM security to allow communication between elevated Settings and WebView 2020-01-27 18:49:35 +03:00
yuyoyuppe
cd6ac4f8c2 Common: implement on_scope_exit helper and typed_storage 2020-01-27 18:49:35 +03:00
Clint Rutkas
79ac2be617 Changes for #1140 and #569 (#1152) 2020-01-27 07:00:41 -08:00
yuyoyuppe
9b4b7cf5d4 MSIX: reinstall script uses bundle instead of .msi to be able to reinstall in all cases 2020-01-27 17:33:50 +03:00
Bartosz Sosnowski
cc99abcd14 Runner: fix restarting with same elevation (#1133) 2020-01-23 15:12:02 +01:00
yuyoyuppe
f8bcf52741 MSIX: add a dedicated .rc for UWPUI which joins both UI and DLL .rc's (#1139) 2020-01-23 14:42:28 +03:00
vldmr11080
1a10366ab7 Align zone dimensions from layout preview with those from grid editor (#1115) 2020-01-22 20:15:35 +01:00
Alekhya
925b6694ac Localize C++ Projects of FancyZones (#1130)
* localized dllmain.cpp  of fancyzones project

* localized FancyZones.cpp

* format fancyzones.rc file

* Moved SuperFancyZones back to being a string instead of having it in the resource file as it is the window class name

* reverted changes for window name

* Formatted fancyzones rc file
2020-01-22 10:24:00 -08:00
Alekhya
1ad16ade86 Localize the Shortcut guide PowerToy (#199) (#1126)
* Localized shortcut_guide.cpp

* localized overlay_window.cpp

* formatting changes

* Localize overlay window

* removed the README link from the set of localized resources

* Typo: changed upper to lower
2020-01-22 09:43:49 -08:00
Alekhya
45e3f02832 Localizing C# Project of FancyZones (FancyZonesEditor) (#199) (#1122)
* removed hardcoded strings from CanvasEditorWindow.xaml

* removed hardcoded strings from GridEditorWindow.xaml

* loc

* Localized MainWindow

* reverting MainWindow.xaml as it is not rendering the window as expected

* Changed the resource settings from internal to public

* the culture is set based on the culture of the system UI set in the system settings

* Removed the french resource files used for testing

* Localized canvasWindow and mainwindow

* Removed setting the UI culture explicitly as it would be implicitly set to the culture of system UI

* Removed redundant header file
2020-01-21 12:02:31 -08:00
Alekhya
ba1a681aab Merge pull request #1106 from alekhyareddy28/locPowerRename
Localize PowerRename
2020-01-20 12:11:07 -08:00
Alekhya Kommuru
23bba969dd Merge remote-tracking branch 'upstream/master' into locPowerRename 2020-01-20 11:54:20 -08:00
Alekhya Kommuru
9c743acd2d Removed some IDs from resource file. Changed SHIFT to Shift 2020-01-20 11:52:46 -08:00
Bartosz Sosnowski
62da7c7be4 FancyZones: remove dialog boxes filtering (#1076)
* FancyZones: remove dialog boxes filtering

* FancyZones: add the "no owner window" filter to the WinKey + arrow zone snapping
2020-01-20 11:02:12 +01:00
Alekhya Kommuru
653a84d3a9 reverting formatting of files 2020-01-17 14:38:41 -08:00
Alekhya Kommuru
8132bbac2e updated formatting of common.cpp 2020-01-17 14:32:02 -08:00
Alekhya Kommuru
197286c21e moved app name to constructor to init only once 2020-01-17 14:23:07 -08:00
Alekhya Kommuru
bf48729354 rebuilt project PowerRename 2020-01-17 11:57:53 -08:00
Alekhya Kommuru
a504a75166 Removed string resources from the settings.cpp file 2020-01-17 11:25:42 -08:00
Alekhya Kommuru
44ac22c0de Added new lines to the end of the file 2020-01-17 11:12:23 -08:00
Alekhya Kommuru
df1c6b9b0b Removed get_res_string_wchar and used the get_resource_string() function instead which returns a wstring typecast into wchar* 2020-01-17 11:06:57 -08:00
Alekhya Kommuru
bde0e0b86a Merge remote-tracking branch 'upstream/master' into locPowerRename 2020-01-16 13:58:59 -08:00
Arjun Balgovind
c1232a7001 Shifted three functions to common (#1101) 2020-01-15 23:06:22 -08:00
Alekhya Kommuru
12c4dbf0e5 added common as a reference project 2020-01-15 16:44:18 -08:00
Alekhya Kommuru
31a01ab227 Modified resourceIDs for strings in the table 2020-01-15 13:57:05 -08:00
vldmr11080
5dc60b9f35 Fix reversed order of zones in layout (#1071) 2020-01-15 20:20:10 +01:00
vldmr11080
588f134de8 Revert "Fix misaligned display of zones in layout priview and grid editor (#1010)" (#1097)
This reverts commit d03690cffd.
2020-01-15 19:34:23 +01:00
Clint Rutkas
2ae867a7e0 adding in privacy statement, removing About in dialog (#1087)
* adding in privacy statement, removing About in dialog

* added Preview
2020-01-15 10:16:22 -08:00
Clint Rutkas
c77b029ee2 Update to MSIX README.md (#1095)
* Update README.md

few adjustments

* Update README.md

* Update README.md
2020-01-15 10:15:24 -08:00
Alekhya Kommuru
d0648d1754 built the proj 2020-01-14 16:40:40 -08:00
Alekhya Kommuru
1e3486af94 localized the settings file 2020-01-14 16:39:03 -08:00
Alekhya Kommuru
8f2b2aba12 localized powerRenameExt 2020-01-14 15:23:21 -08:00
Alekhya Kommuru
0b1232b65d localized dllmain powerrename 2020-01-14 15:17:08 -08:00
Alekhya Kommuru
969abe015c added the helper functions 2020-01-14 15:00:05 -08:00
yuyoyuppe
9e296cdb46 MSIX: Code sign msixbundle (#1093) 2020-01-14 22:05:09 +03:00
yuyoyuppe
b07627611f MSIX: label PowerToys as Preview (#1090) 2020-01-14 19:36:08 +03:00
yuyoyuppe
5e30721e01 MSIX: Extract MSIX building functionality from msix_reinstall.ps1 to a separate script (#1068) 2020-01-10 16:38:35 +03:00
vldmr11080
d03690cffd Fix misaligned display of zones in layout priview and grid editor (#1010)
Fix misaligned display of zones in layout preview and grid editor
2020-01-09 22:40:38 +01:00
Bartosz Sosnowski
dad732b7e6 runner: show message box when restarting with different elevation fails (#1061)
Also make the message box appear on top of the settings window.
2020-01-09 18:17:42 +01:00
Yosef Durr
a2a683d31e adding fancy zone opacity setting, enhancement #631 (#1008)
* adding fancy zone opacity setting, enhancement #631

* applying zone opacity setting to all zones during zone selection

* changing opacity setting to percentage
2020-01-06 09:59:18 -08:00
Chris Davis
3ffd007cc0 Ensure previous search and replace texts are evaluated and updated in the UI at startup (#1043)
Ensure stored settings get evaluated after initial enumeration

There was a bug where the list view was not getting updated with the results of the search and replace on launch when we are using a stored search or replace text from a previous session.
2020-01-04 00:39:02 -08:00
Enrico Giordani
c894d72b52 Remove unwanted files (#1037)
Add temp build files to gitignore
2020-01-03 16:10:32 +01:00
Clint Rutkas
a14784cfd4 Merge pull request #1026 from microsoft/updatePackages
Update packages for NPM
2019-12-27 13:48:20 -08:00
Clint Rutkas
32440567ad Merge pull request #1025 from microsoft/languageTweaks
Language tweaks for #937
2019-12-27 13:41:50 -08:00
Clint Rutkas
25f1dc325d slight bump for fabric ui 2019-12-27 13:35:34 -08:00
Clint Rutkas
38feeee464 npm audit fix to update stuff 2019-12-27 13:19:51 -08:00
Clint Rutkas
b2701ad911 Merge pull request #1024 from microsoft/DocTweakForSettings
Update settings-web.md
2019-12-27 12:51:08 -08:00
Clint Rutkas
d41962f9d1 adjusting elevated permission verbiage to match Windows 2019-12-27 12:28:27 -08:00
Clint Rutkas
ec5d01545a Update settings-web.md 2019-12-27 11:12:43 -08:00
Clint Rutkas
03ddadc1ed tweaking language 2019-12-27 10:26:00 -08:00
Bartosz Sosnowski
3e55b61ac0 Runner: fix run as elevated wording (#1023) 2019-12-27 16:20:36 +01:00
Bartosz Sosnowski
5a7f022e40 settings-web: use Windows build-in commands (#1019) 2019-12-27 13:25:34 +01:00
Clint Rutkas
f651e10684 Merge pull request #1017 from microsoft/languageTweaks
#768
2019-12-26 14:20:38 -08:00
Clint Rutkas
b753f920e1 #768 2019-12-26 11:06:59 -08:00
Enrico Giordani
415a0cdf28 Coding style (runner) (#1013) 2019-12-26 17:26:11 +01:00
Enrico Giordani
9708961654 Coding style (settings) (#1012) 2019-12-26 17:25:56 +01:00
Bartosz Sosnowski
47bcb117b4 FancyZones: do not zone windows on startup (#982) 2019-12-24 15:47:28 +01:00
yuyoyuppe
3eb38e558e project template: fix rc file in module template (#992) 2019-12-24 17:06:58 +03:00
yuyoyuppe
a321eb8737 MSIX: minor cleanup, add certificate generation script 2019-12-24 17:06:10 +03:00
yuyoyuppe
62c65659cc format changed files 2019-12-24 17:06:10 +03:00
yuyoyuppe
249addebff powerrename: implement shellext support for UWP 2019-12-24 17:06:10 +03:00
yuyoyuppe
860087d291 MSIX: implement initial msix installer 2019-12-24 17:06:10 +03:00
Clint Rutkas
b58d4e306a Merge pull request #1000 from crutkas/crutkas/923
fix for #923
2019-12-23 20:17:17 -08:00
Clint Rutkas
21a57a0c58 Merge pull request #1001 from microsoft/980
Update for #980
2019-12-23 20:16:03 -08:00
Clint Rutkas
06b1e43492 Update for #980
clearly stating when "Match all" needs to be enabled
2019-12-20 15:49:14 -08:00
Clint Rutkas
2c1ffde3ed fix for #923 2019-12-20 14:53:56 -08:00
vldmr11080
918ebc62a2 When spacing is set to 0 or turned off display 1px border so user can distinguish zone edges. No spacing will be applied in actual layout. (#994) 2019-12-20 19:46:14 +01:00
ryanbodrug-microsoft
465de438ce User/ryanbod/vstemplate fix issue 971 (#990)
* Updating ModuleTemplate zip, with vstemplate file.
* Exporting Template with powertoy icon
2019-12-19 13:39:08 -08:00
Bartosz Sosnowski
6ee848b279 FancyZones: handle minimized windows correctly (#986) 2019-12-19 16:36:24 +01:00
Bartosz Sosnowski
db5f1622bd FancyZones: do not zone invisible windows (#983) 2019-12-19 16:02:24 +01:00
Enrico Giordani
5e2f681761 Docs tweaks (#960)
Change header levels
Add Github workflow
Add reference to coding style
Minor tweaks
Fix links
Add border to images
Scale images
2019-12-17 17:02:45 +01:00
Bartosz Sosnowski
ad506d78ba Imrpove the settings doc (#958) 2019-12-17 15:18:27 +01:00
yuyoyuppe
48b89609e2 fancyzones: restrict dpi unaware windows horizontally to the current display to avoid unwanted resize 2019-12-17 15:37:10 +03:00
yuyoyuppe
0fd0a8b7cc format dpi_aware 2019-12-17 15:37:10 +03:00
yuyoyuppe
2e922019d7 DPIAware: implement GetAwarenessLevel and cleanup 2019-12-17 15:37:10 +03:00
yuyoyuppe
303d1fef6b PCH: remove headers which are actually could be changed (#950) 2019-12-17 11:21:46 +03:00
Bartosz Sosnowski
619ed234a9 Do not run elevated by default (#884)
Make the runner not run as elevated by default. Add a setting for
"run PowerToys as elevated" and buttons to restart the process
with the different elevation levels.
2019-12-16 18:36:52 +01:00
Enrico Giordani
fd8fc679be Run the Settings process un-elevated when possible
and if not possible run it elevated and let the Settings
process deal with it.
Add wrappers for GetModuleFileNameW.
2019-12-16 18:03:37 +01:00
Enrico Giordani
5a3c852b32 format 2019-12-16 18:03:37 +01:00
yuyoyuppe
4c7de77bfb fix solution configuration (#948) 2019-12-16 17:01:08 +03:00
yuyoyuppe
7e91121a33 PowerToy project template update (#934)
* Add PowerToy project template to the PowerToys solution
* Update PowerToy project template and create a separate solution for it
2019-12-16 13:12:36 +03:00
Tajetaje
7efe6f1d53 Correct readme links (#943)
Now in line with #913
2019-12-16 09:40:15 +01:00
Clint Rutkas
511f71c369 Merge pull request #927 from microsoft/dev/crutkas/codeAnalysis
code analysis / style cop adjustments for .NET
2019-12-13 14:09:19 -08:00
vldmr11080
d284ecdab4 Fix outstanding warning messages (#924) 2019-12-13 18:55:30 +01:00
Clint Rutkas
0ff2e212d5 #817 2019-12-12 17:11:47 -08:00
Clint Rutkas
107595fcb2 last stylecop issue 2019-12-12 15:18:31 -08:00
Clint Rutkas
32fb634a4d few more fixes 2019-12-12 15:07:52 -08:00
Clint Rutkas
51fbcc736e fix for CA0507 2019-12-12 15:02:22 -08:00
Clint Rutkas
360a22c537 fixed rest of info items 2019-12-12 15:00:24 -08:00
Clint Rutkas
63cb5ab883 fixed a bunch of infos 2019-12-12 14:50:25 -08:00
Clint Rutkas
151a937c10 fixed a bunch more 2019-12-12 14:34:25 -08:00
Clint Rutkas
4c88c9b029 adjusting event names 2019-12-12 13:59:58 -08:00
Clint Rutkas
24664cc859 moving converters, fixing spacing issues 2019-12-12 13:51:58 -08:00
Clint Rutkas
a187456ac3 Fixed a lot of line issues, few auto 2019-12-12 13:44:06 -08:00
Clint Rutkas
9e4752b114 fix line issues 2019-12-12 13:34:06 -08:00
Clint Rutkas
de64b33bb8 Fixing blank lines 2019-12-12 13:26:02 -08:00
Clint Rutkas
826858c170 Adding in sytlecop and fixing issues 2019-12-12 12:13:31 -08:00
Clint Rutkas
f2400ee089 Getting analysis up and going 2019-12-12 11:23:36 -08:00
Seraphima
6e3587dd43 Settings unit tests (#921) 2019-12-12 18:24:00 +01:00
yuyoyuppe
f385e46927 Devdocs reorganisation (#913)
* docs: split usage and dev docs

* # This is a combination of 2 commits.
# This is the 1st commit message:

docs: split usage and dev docs

# The commit message #2 will be skipped:

# fixup add docs

* docs: add runner documentation and move hooks documentation to devdocs

* docs: add stubs for modules technical description

* docs: add paragraph about event thread-safety

* docs: add 'Current modules' section header
2019-12-12 12:25:19 +03:00
vldmr11080
c31262b97e Flash zones only when new virtual desktop is created (#818) 2019-12-12 10:10:55 +01:00
ryanbodrug-microsoft
9fad2d68af Merge pull request #912 from ryanbodrug-microsoft/user/ryanbod/fix_unit_tests_fancyzones
[FancyZones][UnitTests] Fixing TestDeviceId, and TestUniqueId.
2019-12-11 08:49:45 -08:00
ryanbodrug-microsoft
51180adeb4 Autoformatting document. 2019-12-11 08:34:18 -08:00
vldmr11080
31c4ab8ac0 Make sure FancyZones Editor window is on top of PowerToys settings window (#911) 2019-12-11 09:41:05 +01:00
ryanbodrug-microsoft
4f9d31e832 [FancyZones][UnitTests] Fixing TestDeviceId, and TestUniqueId to unit tests.
1. Creating a mock ZoneWindowHost.   Previously creating a ZoneWindow would throw an exception if the ZoneWindowHost is null.
2. Passing in HWND() instead of null to get rig of SAL annotation warnings.
2019-12-10 17:17:40 -08:00
Clint Rutkas
22e13e8c40 SVG logo for PowerToys 2019-12-10 16:30:53 -08:00
ryanbodrug-microsoft
7fc168532c Merge pull request #902 from ryanbodrug-microsoft/user/ryanbod/getexampleprojecttobuild
Getting the example project to compile, and build.
2019-12-10 15:31:31 -08:00
ryanbodrug-microsoft
69b55bcbd3 Merge pull request #905 from ryanbodrug-microsoft/user/ryanbod/fixing_unit_tests_powerrenameregex
Fix for broken unit test in power rename using regular expressions and wildcard.
2019-12-10 14:13:12 -08:00
ryanbodrug-microsoft
c6e839271a This test brake was introduced in the following fix:
1efe5bff9f

It looks to me like the test cases just was also wrong and just wasn't updated with the fix.

I've modified some of the test cases to verify the expected behavior:
1) Slight refactor of the tests to pass in the SearchReplaceExpected and flags for the tests.
2) Using Assert::AreEqual instead of Assert::IsTrue for better error meesaging when failed.
3) Verifying that the behavior is the same with or without match all occurances when using *.
4) Verifying that without the `UseRegularExpressionsFlag` the `.*` characters get replaced, including when MatchAllOccurances is set.
2019-12-10 10:11:21 -08:00
yuyoyuppe
1760af50c8 Format unittests (#906) 2019-12-10 10:28:24 +03:00
ryanbodrug-microsoft
73e33d7ba9 Getting the example project to compile, and build.
1) Adding example project to Debug / Release Builds.
2) Including <string> in common.h
3) Using std::optional instead of PowerToysValues::is_[type]_value
4) Fixing warnings generated by unreferenced 'ex' variable in exception handling.
5) Updated relative path of version.h in exeample_powertoy.rc
2019-12-09 15:04:02 -08:00
yuyoyuppe
776a4d657d wix: run ngen on FancyZonesEditor (#898) 2019-12-09 19:02:47 +03:00
yuyoyuppe
8f0b962507 docs: add paragraph about clang-format (#896) 2019-12-09 16:37:43 +03:00
Enrico Giordani
1519843f6f Update WiX to 3.11.2 (#883) 2019-12-09 09:03:07 +01:00
vldmr11080
014c2c5249 Use same zone set initially for new virtual desktops of same monitor (#815) 2019-12-06 15:09:27 +01:00
Kevin Horecka
add63d2dde FancyZones: Added ability to use mouse only for interactions with zones (#729) 2019-12-06 12:32:43 +01:00
yuyoyuppe
81bed3d3d5 Format shortcut_example_powertoy according to .clang-format 2019-12-06 14:16:24 +03:00
yuyoyuppe
f22a30ca87 Format shortcut_guide according to .clang-format 2019-12-06 14:16:24 +03:00
yuyoyuppe
946e74a918 Use .clang-format style file from Terminal project 2019-12-06 14:16:24 +03:00
yuyoyuppe
3cd3cf9830 Implement powershell script which enables devs to clang-format modified source files 2019-12-06 14:16:24 +03:00
yuyoyuppe
bc634c5f8f Add initial .clang-format style file 2019-12-06 14:16:24 +03:00
yuyoyuppe
7357e40d3f Use WinRT JSON parser instead of custom cpprestsdk solution (#822) 2019-12-06 11:40:23 +03:00
Enrico Giordani
e714cb9e8b Now working on 0.14.2 (#871) 2019-12-05 19:09:32 +01:00
Bartosz Sosnowski
fed81c8e22 Improve FancyZones window filtering (#856)
Improve FancyZones window filtering and filter out dialog windows
2019-12-04 17:53:54 +01:00
vldmr11080
3a65d5ce23 Revert: Keep window in their zone after layout changes (#852) 2019-12-04 01:55:12 +01:00
Clint Rutkas
6d482cd934 Merge pull request #849 from matthidinger/patch-1
Add link to releases tab
2019-12-03 15:35:10 -08:00
Bartosz Sosnowski
0e2d93c630 Make FancyZones not zone invisible, child and tool windows
Fixes "Move newly created windows to their last known zone"
2019-12-03 19:45:03 +01:00
Matt Hidinger
de328c9dfd Add link to releases tab 2019-12-03 10:33:16 -08:00
Enrico Giordani
cbe6d19c79 Update FancyZone README for v0.14.0 (#806) 2019-12-02 18:00:14 +01:00
vldmr11080
57845a2739 Don't flash current zone setup when focused window is in full screen (#796) 2019-11-30 14:38:27 +01:00
vldmr11080
9a8ab29330 Reverse logic for keep windows in their zones when fancyzone layout changes (#812) 2019-11-30 12:15:16 +01:00
Enrico Giordani
3095ade94c Now working on 0.14.1 (#797) 2019-11-28 11:06:23 +01:00
yuyoyuppe
221df3d26d Fix lack of tray icon #268 by handling initial Shell_NotifyIcon failure (#789)
* Fix lack of tray icon #268 by handling initial Shell_NotifyIcon failure
2019-11-27 17:19:10 +03:00
yuyoyuppe
40db3a5d7d Wix installer: kill explorer if shellext is detected (#790) 2019-11-27 16:53:18 +03:00
Bartosz Sosnowski
ee1a1fd614 Prevent number being swallow while dragging. (#788) 2019-11-27 10:32:09 +01:00
Chris Davis
8e8be502fd Handle DPI change gracefully (#786)
* Ensure icon in context menu is not leaked

* Hande theme/dpi size change gracefully
2019-11-26 19:45:18 -08:00
Bartosz Sosnowski
ae4413d0aa Improve key code to key name mapping. (#784)
Use the key detected by WebUI and our mapping only for from_settings call.
Replace the old Win + ~ with the correct value
2019-11-26 16:14:34 +01:00
Enrico Giordani
51b791f9c0 Version 0.14.0 (#782) 2019-11-26 11:46:22 +01:00
Mike Harsh
767c3c942b Update README.md 2019-11-25 06:11:34 -08:00
Mike Harsh
3fcace6660 December update with info on 0.14, 0.15 and 0.16 2019-11-25 06:10:44 -08:00
Mike Harsh
4c600f5748 Updated shortcut key information 2019-11-25 06:06:29 -08:00
Bartosz Sosnowski
d84342733d Prevent ShortcutGuide from crashing when it is being disabled while shown. 2019-11-25 15:06:06 +01:00
Bartosz Sosnowski
d6f0f9ec0e FancyZones settings: show proper hotkey even when wrong key was saved before
This makes the Hotkey settings object ignore the key value stored in
json. Instead it will be deduced from the current keyboard layout and
the vk_code.
2019-11-25 11:54:10 +01:00
Bartosz Sosnowski
fbc922fe97 Add some margins to settings icons 2019-11-22 16:19:36 +01:00
Enrico Giordani
4be84e035f revert overrideSnapHotkeys logic after regression (#756) 2019-11-22 10:56:11 +01:00
Bartosz Sosnowski
254474d12d Make the hotkey control display correct key
Credit to @doterik for the idea in https://github.com/microsoft/PowerToys/issues/700#issuecomment-554329895

RApplies to https://github.com/microsoft/PowerToys/issues/700
2019-11-20 10:00:53 +01:00
Bartosz Sosnowski
5615987ea2 Make some settings descriptions wrap correctly
Applies to https://github.com/microsoft/PowerToys/issues/712
2019-11-20 10:00:53 +01:00
Bartosz Sosnowski
3a93246f08 More padding after PowerToy description
Applies to https://github.com/microsoft/PowerToys/issues/716
2019-11-20 10:00:53 +01:00
Bartosz Sosnowski
633784fae2 Use dynamic version in settings
Applies to https://github.com/microsoft/PowerToys/issues/736
2019-11-20 10:00:53 +01:00
Bret
af127468a6 Merge pull request #739 from TheMrJukes/master
FancyZones: Remove legacy editor
2019-11-19 10:00:49 -08:00
Clint Rutkas
f892c1284b Merge pull request #740 from docs-product/patch-1
Update README.md
2019-11-18 23:35:54 -08:00
docs
d762b5a017 Update README.md 2019-11-18 18:16:46 -08:00
Bret
28d7835327 User/bretan/fz remove legacy editor (#1)
* Removed and runs
Still needs some extra cleanup and addressing open issues

* Removed and runs
Still needs some extra cleanup and addressing open issues

* Clean

* Update
2019-11-18 15:29:42 -08:00
Bartosz Sosnowski
03438f9192 FancyZones: improve windows and apps filtering (#673)
Unifies the way windows are considered "interesting" by FancyZone.
Berfore the change WinKey + arrows would use different method than
dragging. This PR makes both use the WinKey + arrows method.

Cleans up FancyZones Settings.cpp by removing m_configStrings variable.
Contrary to its name it was used to create color picker control.

Adds a multiline option to the text input to settings. Uses this to
provide the user with a way to exclude certain apps from snapping to
zones.
2019-11-18 10:29:56 +01:00
Clint Rutkas
4df1d2093f Merge pull request #323 from casungo/master
Added Hi-res logo (4k PNG)
2019-11-15 15:28:18 -08:00
casungo
62a019cc5d Moved png to doc/images 2019-11-15 23:41:05 +01:00
casungo
36c78e9686 Delete Logo-HiRes.png 2019-11-15 23:36:36 +01:00
yuyoyuppe
cb13cfdda7 FancyZonesEditor: open a tab with the selected layout on startup (#715) 2019-11-15 10:40:10 +03:00
Clint Rutkas
0082f56b58 Update README.md 2019-11-13 15:45:59 -08:00
Chris Davis
b490a72c1d Ensure icon in context menu is not leaked (#709) 2019-11-13 14:13:14 -08:00
Chris Davis
3c0b479669 Merge pull request #697 from chrdavis/master
Update to PowerRename
2019-11-12 14:16:10 -08:00
Chris Davis
c9ad09226b Remove call to save_to_settings_file 2019-11-12 13:56:12 -08:00
yuyoyuppe
4e771ecfb7 initialize all OnThreadExecutor fields and clarify intent further (#701) 2019-11-12 18:29:54 +03:00
vldmr11080
be86cd4028 Customize system menu items through dedicated API (#677)
Document new interface changes.
2019-11-12 11:48:14 +01:00
Chris Davis
3ddbe92f37 Fix incorrect setting type in set_config handler 2019-11-11 23:28:31 -08:00
Chris Davis
ca67ea9b4c Merge pull request #2 from microsoft/master
PR from upstream
2019-11-11 23:03:31 -08:00
Clint Rutkas
9f78af29bf Merge pull request #694 from crutkas/master
adding in specs
2019-11-11 21:55:40 -08:00
Clint Rutkas
6821a05f76 Update Gif-Maker.md 2019-11-11 21:54:54 -08:00
Chris Davis
e328c5d505 * Fix crashing bug in event vector cleanup
* Fix warnings in settings.cpp
* Add settings to ui of powertoys
2019-11-11 20:58:39 -08:00
Clint Rutkas
f814d26a4a change of filename 2019-11-11 13:59:03 -08:00
Clint Rutkas
3fc06e6f4f Adding in specs from GH and from MIke's repo 2019-11-11 13:57:46 -08:00
Clint Rutkas
d876c267d6 Merge pull request #692 from microsoft/Readme-adjustment
Updates for readme
2019-11-11 13:16:29 -08:00
Clint Rutkas
1268a463ac Merge branch 'master' of https://github.com/microsoft/PowerToys 2019-11-11 12:46:06 -08:00
Clint Rutkas
e64d75a297 Revert "Work for .12 release. adjusted formatting a bit too"
This reverts commit cd9208b541.
2019-11-11 12:45:51 -08:00
Clint Rutkas
7900edc96c Merge pull request #691 from enricogior/remove-icons-from-root
Remove images from the root
2019-11-11 12:16:32 -08:00
Clint Rutkas
692421ee13 Updates for readme
- added in processor support type with issue links
- added in section to call out WinStore support issue
- reduced size on image
2019-11-11 11:57:10 -08:00
Chris Davis
1e89054897 * Ensure rename dialog is centered
* Ensure children are renamed before parent items
* Add settings handler
* Replace old text referencing smart rename with power rename
2019-11-11 11:00:42 -08:00
Enrico Giordani
ae1112ae11 Remove images from the root
the images are already available (and used) in doc/images/
2019-11-11 17:03:32 +01:00
Chris Davis
800984489d Merge pull request #679 from chrdavis/master
Small bugs fixes to PowerRename
2019-11-09 00:31:34 -08:00
Chris Davis
997ea3a2f5 A couple minor bug fixes 2019-11-09 00:30:00 -08:00
Chris Davis
b9b60a1346 Merge pull request #1 from microsoft/master
Sync with master
2019-11-08 12:05:57 -08:00
yuyoyuppe
e8edbd5394 clear FancyZones::m_zoneWindowMap on Destroy, since it stores 'this', causing a leak (#664) 2019-11-07 22:05:12 +03:00
yuyoyuppe
f3e25ae3e6 Fix for different per-monitor scaling (#657)
* Use DPIAware::DEFAULT_DPI

* Make runner DPI-unaware, since it doesn't need to use a Per Monitor V2 DPI.

* Programmatically enable "Per Monitor V2 DPI" for the runner proccess and use a separate DPI-unaware thread for the corresponding API calls

* Increase PCH memory limit for settings project

* Address review issues

* Draw zoneWindows properly scaled
2019-11-07 21:56:32 +03:00
yuyoyuppe
a9518c2e55 Wrap around colorIndex in a colors array (#669) 2019-11-07 17:50:04 +01:00
yuyoyuppe
c4fc67301c Add switch to turn off keyboard hooks while debugging, since they could mess system-wide input 2019-11-07 09:52:34 +01:00
Enrico Giordani
39cbc59c12 Don't auto close issues referenced in PR (#663)
Remove space in checkboxes
2019-11-06 10:37:42 +01:00
Bartosz Sosnowski
96aa6ae3ef Fix Chrome tab move leaving zone highlighted (#656)
Fixes: https://github.com/microsoft/PowerToys/issues/534
2019-11-05 14:29:42 +01:00
Mike Harsh
94d07833c5 Removed the batch renamer now that PowerRename is released 2019-11-04 09:42:29 -08:00
Chris Davis
1d3acbe40b Merge pull request #655 from chrdavis/master
Switch to modeless experience and resize list view columns on dialog size
2019-11-03 22:24:39 -08:00
Chris Davis
389590e45d Ensure columns are resized when the dialog is resized. Also switch to a modeless experience instead of modal for the dialog. We no longer disable the parent window. 2019-11-03 22:22:35 -08:00
Chris Davis
ea3cb026c7 Merge pull request #647 from chrdavis/master
Fix single regex search replace bug
2019-11-01 23:57:22 -07:00
Chris Davis
1efe5bff9f Fix single regex search replace
Fix an issue where regular expression search and replace was not being done correctly when MatchAllOccurences is not specified.
2019-11-01 23:56:29 -07:00
Chris Davis
df4fa549ef Allow resizing of PowerRename dialog (#635) 2019-11-01 08:54:49 -07:00
Chris Davis
cc7a706f52 Fix painting issue with buttons after resize 2019-11-01 08:52:54 -07:00
Chris Davis
d4256dad30 Allow resizing of PowerRename dialog 2019-10-31 23:57:42 -07:00
Chris Davis
d9320b7c05 Update README.md
Add example for appending an extension to files that do not have an extension
2019-10-31 11:20:50 -07:00
Chris Davis
27c9a4a6a9 Update README.md
Add example to append an extension for files that do not have an extension
2019-10-31 11:05:23 -07:00
Hyeonwoo Kang
18d4dc7321 Update README.md (#626)
Fix broken links in src/modules/README.md
2019-10-31 18:25:45 +01:00
Bartosz Sosnowski
6f241ef001 Now working on 0.13.0 (#617) 2019-10-31 17:51:20 +01:00
Chris Davis
296be2fbd5 Update README.md
Added more info about regular expression usage
2019-10-31 09:14:30 -07:00
Chris Davis
c1957272ea Bug Fixes for PowerRename (#614)
* Bug Fixes

Fixes include:
* Pass parent HWND to UI so dialog is no longer appearing in top corner all the time
* Fix duplicate entries for PowerRename in context menu for shortcuts
* Fix crashing bug due to telemetry not getting unregistered on unload
* Ensure we show the file extension in the UI even if extensions are hidden in Windows Explorer

* Update PowerRenameExt.cpp

Fix missed line to set parent HWND
2019-10-31 06:57:38 -07:00
Bartosz Sosnowski
e6afd33621 Hide Shortcut Guide when screenshots are taken (#605) 2019-10-31 10:26:24 +01:00
Bartosz Sosnowski
b767773742 ShortcutGuide: change vk_code to suppress Start
Use reserved 0xCF virtual key-code to suppress the Start menu from
appearing instead of 0x07 which is used by the Xbox Controller for the
Xbox Guide button.

Fixes: https://github.com/microsoft/PowerToys/issues/595
2019-10-31 10:26:01 +01:00
Mike Harsh
52ead7ad1b Updated the news section 2019-10-29 10:10:01 -07:00
Mike Harsh
b8e083f8fc Updated PowerRename image with the new name 2019-10-29 10:07:18 -07:00
Mike Harsh
6e3f8bdefd Merge pull request #577 from crutkas/master
prepping for 0.12 release
2019-10-29 10:04:21 -07:00
Clint Rutkas
8e55f2bf58 prepping for 0.12 release
Adjusted formatting a bit based on a linting project, also added in privacy policy.
2019-10-29 04:12:47 -07:00
Clint Rutkas
cd9208b541 Work for .12 release. adjusted formatting a bit too 2019-10-29 04:08:11 -07:00
casungo
38029efe50 Added Hi-res logo (4k PNG) 2019-09-09 16:58:37 +02:00
436 changed files with 39842 additions and 24874 deletions

94
.clang-format Normal file
View 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

View File

@@ -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
View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.PowerToys.Telemetry" version="1.0" />
</packages>

View File

@@ -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'

View File

@@ -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
Logo.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -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
View File

@@ -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/).
![logo](doc/images/Logo.jpg)
## Build Status
## Installation
[![Build Status](https://dev.azure.com/ms/PowerToys/_apis/build/status/microsoft.PowerToys?branchName=master)](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)
[![Build Status](https://dev.azure.com/ms/PowerToys/_apis/build/status/microsoft.PowerToys?branchName=master)](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
![SmartRename](https://github.com/chrdavis/SmartRename/raw/master/Images/SmartRenameDemo.gif)
### 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.
![FancyZones](src/modules/fancyzones/FancyZones.png)
### Shortcut
FancyZones Video Tutorial
[![FancyZones Video Tutorial](doc/images/FZTutorial.jpg)](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
![Windows key shortcut guide](doc/images/WindowsKeyShortcutGuide.jpg)
[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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 273 KiB

View File

@@ -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).

View File

@@ -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

View File

@@ -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&lt;utility::string_t&gt;</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&lt;utility::string_t, utility::string_t&gt;</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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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
View File

@@ -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"

View File

@@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -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();
}

File diff suppressed because it is too large Load Diff

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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.

View File

@@ -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
View 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).

View 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.

View 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

View File

@@ -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.

View 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

View 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. Its 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
View 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.
![Image of the tray icon](/doc/images/runner/tray.png)
### [`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
![Image of the Options](/doc/images/example_powertoy/settings.png)

36
doc/devdocs/runner.md Normal file
View 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.

View 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:
![Shortcut Guide settings](../images/settings/shorcut_guide_settings.png)
### 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:
![General settings](../images/settings/general_settings.png)
## 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:
![Bool Toggle](../images/settings/bool_toggle.png)
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:
![Int Spinner](../images/settings/int_spinner.png)
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:
![String](../images/settings/string.png)
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:
![Multiline](../images/settings/multiline.png)
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:
![Color Picker](../images/settings/color_picker.png)
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:
![Hotkey](../images/settings/hotkey.png)
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:
![Choice group](../images/settings/choice_group.png)
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:
![Dropdown 1](../images/settings/dropdown_1.png)
![Dropdown 2](../images/settings/dropdown_2.png)
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:
![Custom action](../images/settings/custom_action.png)
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"
}
```

View File

@@ -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
View 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.

View File

@@ -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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

30
doc/images/Logo.svg Normal file
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -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

View 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 its 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.

View File

@@ -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;
};
```

View File

@@ -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 Toys settings will be passed into the PTs 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
View 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
View 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!"

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View 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>

View 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>

View File

@@ -0,0 +1 @@
makeappx build /v /overwrite /f PackagingLayout.xml /id "PowerToys-x64" /op bin\

View 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

View 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

View File

@@ -0,0 +1 @@
Add-AppxPackage .\bin\PowerToys.msixbundle

View File

@@ -0,0 +1,7 @@
taskkill /f /im PowerRenameUWPUI.exe
.\uninstall_msix.ps1
.\build_msix.ps1
.\sign_msix.ps1
.\install_msix.ps1

View 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

View File

@@ -0,0 +1 @@
Get-AppxPackage -Name '*PowerToys' | select -ExpandProperty "PackageFullName" | Remove-AppxPackage

View File

@@ -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>

View File

@@ -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.

View File

@@ -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" />

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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." }
}
```

View 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;
}

View 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>

View 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>

View 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")]

View 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>

View 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"
}
}
}

View File

@@ -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.

View File

@@ -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());
}
}
};
}

View File

@@ -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>

View File

@@ -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">

View 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);
}
};
}

View 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;
}
}
}
}

View 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;
};

View 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;
};

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