Compare commits

...

128 Commits

Author SHA1 Message Date
Enrico Giordani
a27c013196 Fix for FZ losing layout settings 2020-10-07 17:08:36 +02:00
Enrico Giordani
e9a7b5d08e Update version to 0.23.2 2020-10-06 19:39:03 +02:00
Enrico Giordani
2b0896dded [FancyZones] Clone parent data only for new VD 2020-10-06 18:40:01 +02:00
Divyansh Srivastava
d246bdd32f Add exception handling in win32 program (#6958)
* Add exception handling to prevent program from failing due to error in one program

* Error handling for program path function

* Fix incorrect log value in ProgramLogger
2020-10-05 18:55:14 +02:00
Divyansh Srivastava
7116d69002 Fix autocomplete due to error in returned autocomplete text (#6988) 2020-10-03 10:41:53 +02:00
Arjun Balgovind
d8f0ebe105 [KBM] Moved unregistering of key delays to always run on the dispatcher thread to avoid mutex re-entrancy (#6959)
* Moved unregistering of key delays to always run on the dispatcher thread

* Updated comments
2020-10-02 09:38:21 +02:00
stefansjfw
2946b08823 [FancyZones] Fix stuck chrome tab when merging into existing window (#6931)
* Fix stuck Chrome tab when merging with existing window
2020-10-02 09:33:53 +02:00
Arjun Balgovind
7bcbda39ef [KBM] Avoid checking reserved/unassigned/oem-specific/undefined key codes during shortcut remaps (#6952)
* Updated list of key codes to be ignored

* Added comments
2020-10-02 09:20:03 +02:00
Enrico Giordani
b90363a041 Update version to 0.23.0 2020-09-28 18:49:36 +02:00
Arjun Balgovind
de870c843e Fix settings UpgradeConfiguration code path (#6839) 2020-09-25 13:59:14 -07:00
Arjun Balgovind
9c32e32097 Updated winUI version (#6840) 2020-09-25 13:52:43 -07:00
Alekhya
f61db8ed3f Add delay to File System watchers to prevent Calibre installation issue (#6821)
* add a separate task to dequeue and create an app on installation

* Added tests to validate the behavior of the event handler

* release unmanaged memory
2020-09-25 10:36:38 -07:00
Arjun Balgovind
9e1711cbb9 [Settings] Added recursive delete for IOProvider DeleteDirectory to prevent crash on non-empty directory (#6818)
* Added recursive delete flag

* Changed to named parameter
2020-09-24 11:36:26 -07:00
Alekhya
c941b5333c Fix settings changes that were made in PR #6620 (#6817)
* validated that restart elevated and check for updates work.Removed isettingsUtils and reused settings repository

* reverted the name to ImageResizer instead of using ImageResizerSettings.Modulename to make it backward compatible
2020-09-24 10:50:49 -07:00
csigs
8d934df0c0 LEGO: check in for master to temporary branch. (#6805) 2020-09-24 09:14:25 -07:00
csigs
2f0937951a LEGO: check in for master to temporary branch. (#6802) 2020-09-24 08:01:13 -07:00
Ivan Stošić
a676537e26 [FancyZones editor] Rudimentary crash handler (#6783)
* Handle crashes in the FZ editor

* Removed reference to .NET frameworks, added a message box

* log => txt

* Update text shown
2020-09-24 12:29:53 +02:00
Clint Rutkas
b071220b6c Improve logging for PT Run (#6800)
* init code pass

* adjusting tabbing for readabilty

* few small adjustments
2020-09-23 16:32:06 -07:00
Alekhya
dafc1e0c7d Fixed scaling Accessibility issues in Settings (#6774)
* fixed scaling issues in settings

* reduced the size to 375 from 380

* Set scrollviewer visibility to auto so that it is visible only when needed
2020-09-23 13:20:58 -07:00
Alekhya
5a07579b73 Fix for settings crash on toggling enable button for any PowerToy (#6620)
* Removed getSettings from moduleEnabled so that it doesn't have to reopen the file everytime

* To Lower to while checking the theme

* color picker doesn't reopen the file

* use the generalView model config directly for FZ

* Made the same change for all the viewmodels so that they access the general view model value directly instead of opening and reading the value from a file each time

* removed unused variable

* Fix initialization in tests

* should read the file only if general settings does not exist

* Added interfaces for all the powertoys to use the generalSettings singleton class

* Runner is responding to changes in settings, only issue is that every time the general settings page is loaded the information is being read because isInitialized property could not be ignored during serialization

* All tests pass

* Settings and runner are working as expected with the settings cache

* added a null check to read from the file only when the settings process is started

* use converter to deserialize an interface

* Renamed generalSettings within the cache to be called CommonSettingsConfig

* All tests pass, had to initialize the common settings config instance

* Added few comments to newly created classes

* encapsulating load and store of general view model

* reading from file is encapsulated

* settings and runner wotk with generic singleton

* Shortcut guide works as expected

* Fancyzones, shortcutguide and power preview use the settings repository and work as expected

* referencing GeneralSettings instead of the settingsRepository<GeneralSettings> within viewmodels

* unified access to General settings and removed the IGeneralSettingsData interface

* Passing settings to viewmodel as a parameter

* removed ISettingsConfig interface from the viewmodels which are not using the singleton to access settings

* have to use ISettingsConfig to use GetSettings

* refactored tests, all tests pass

* Added test for settingsRepository that a single instance is created

* Added comments and removed unnecessary headers/code

* added settings repository tests

* moq for each settings file

* Img resizer tests pass

* General tests pass

* FancyZones tests pass

* PowerPreview tests pass

* PowerRename tests pass

* shortcut guide tests pass

* Added GetModuleName to ISettingsConfig

* unify the way the Modulename is accessed. It was redeclared in multiple places and this would cause an issue if the name is changed only in one place. All the module names are accessed using the <T>Settings.ModuleName, eg: ShortcutGuideSettings.ModuleName.

* create PTRun settings file if it does not exist

* GetFile is now a private function. Modified the logic of KBM default.json access and PT Run so that we can re-use GetSettings instead of GetFile.

* Added UpgradeSettingsConfiguration to the ISettingsConfig interface so that the settings file can be upgraded based on some condition. Presently, only the GeneralSettings file is utilizing this to change the PT Version number based on the old PT version and the current PT version that it receives from the helper function. Verified that if the PT version is lower in the general settings.json file, settings saves the file with the new version info.

* The naming for the PowerToys was inconsistent and the variables were redeclared in multiple places. To have the settings.ModuleName as the main name, all other places should refer to that name. In the tests file the module name for ImgResizer was 'ImageResizer' and not 'Image Resizer'.

* renamed lock

* Remove unnecessary GetSettingsFileNAme function. It is no longer in use because the code does not use types to create a new BasePTModule object
2020-09-23 13:20:32 -07:00
Clint Rutkas
0148669e98 [fxcop] preview handler common (#6762)
* FxCop adjustments

* initing due to change for abstract
2020-09-23 10:22:17 -07:00
Arjun Balgovind
75ace74d37 [Keyboard Manager] Enabled horizontal scroll on scroll viewers and tweaked ScrollViewer layout (#6755)
* Enabled horizontal scroll on scroll viewers and tweaked layout

* Added code to constrain the minimum window sizes
2020-09-22 17:46:57 -07:00
Arjun Balgovind
1ef4c43382 [Keyboard Manager] Fix crash in Keyboard Manager by ignoring MapToSameKey warnings on loading (#6714)
* Add extra argument to ignore MapToSameKey error for Key To Shortcut mapping

* added comment
2020-09-22 13:54:53 -07:00
Clint Rutkas
c1e9f2de6a FxCop enabled (#6758) 2020-09-22 09:14:42 -07:00
Clint Rutkas
55b36d44fa adding in frontmatter and latex (#6711) 2020-09-22 09:10:18 -07:00
Enrico Giordani
d2201cbb79 [SG] change suppress key code (#6750) 2020-09-22 13:12:19 +02:00
Clint Rutkas
934949725b FxCop and StyleCop for SVG thumbnail (#6757)
* FxCop work for SvgThumbnail

* enabling stylecop
2020-09-21 19:44:12 -07:00
Clint Rutkas
57972c6653 Update README.md 2020-09-21 13:43:23 -07:00
ryanbodrug-microsoft
0f6428eed0 User/ryanbod/mock settings disk access (#6188)
* 1) Making Directory Methods private.
2) Removing the CreateDirectory / DeleteDirectory functionality from all Settings Unit Tests.

* Abstracting disk access via IIOProvider to be able to provide mocks for unit tests instead of writing to disk.   This also prevents developers who are running unit tests from interfering with the PowerToys settings on their local dev box.

* Dependency Injecting stub SettingsUtils for all tests

* Removing ISettingsUtils from constructors of objects that need to be deserialized (ColorPickerSettings/PowerLauncherSettings) as this breaks System.Text.Json

* Removing unused namespace reference

* Removing redifined mock

* As per PR feedback.  Stub Settings utils should work with any settings type if the intent is to compile / avoid null ref exceptions.

Strangely when implementing this fix it became apparent that a stub settings isn't enough, and disk access needed to be mocked.  I can't explain why the tests were passing previously.

* Leveraging GetMockIOProviderForSaveLoadExists
2020-09-21 10:14:44 -07:00
Ivan Stošić
6e89ef62e4 [Launcher] Kill the Launcher immediately (#6747)
* Kill the Launcher immediately

* Also rename the shared file
2020-09-21 13:51:30 +02:00
Ivan Stošić
b266e336b5 [Launcher] Use a keyboard hook in the runner to invoke the Launcher (#6660)
* Added a keyboard hook to the runner

* Update RootKeyboardHook

* Enable reading the whole JsonObject property

* Renamed RootKeyboardHook to CentralizedKeyboardHook

* Fixed build break, changed callback return type to bool

* Added Hotkey struct which somehow went missing

+ Cherry-pick fixes

* Reorganized the kb hook

* Basic version works

* Various fixes

* Finishing touches

* Fix potential threading issue

* int -> size_t

* Add default initializers to the Hotkey struct

* Added a suggested comment

* Unified a constant

* Use C# classes instead of native calls for sync

* Added a claryfing comment

* Use std::move

* Renamed a method

* Possible fix for compilation errors

* Fix a regression

* Show a message on failure

* Added DISABLE_LOWLEVEL_HOOK support

* Allow running Launcher as standalone

* Rename string constants
2020-09-21 12:44:16 +02:00
Arjun Balgovind
e135153c45 [Keyboard Manager] Fix focusable elements should have different names accessibility issue (#6672)
* Add listview

* Added row index to accessible names

* Cleanup rowIndex

* Fixed accessibility issue with ComboBox

* Updated comments
2020-09-18 17:12:37 -07:00
Divyansh Srivastava
28cae124d1 Nit fix in logging (#6708) 2020-09-18 13:32:28 -07:00
Clint Rutkas
94d8b4a122 rerouting to Log class vs custom logic (#6688) 2020-09-18 12:58:52 -07:00
Arjun Balgovind
ce835418cb Enable localization on all folders under PowerToys root (#6692)
* Changed to repo root

* Removed backslash

* Revert testing change

* Add comment
2020-09-18 10:27:59 -07:00
vldmr11080
3aa7a52c21 [FancyZones] Initial improvements in FancyZones exception handling (#6063)
* Initial improvements in FancyZones exception handling

* Add callback

* Disable FancyZones if error durign loading data occurrs

* Remove logs

* Add resource strings

* Add 1sec retry when failure during initialization occurs

* Rephrase error descriptions

* Error handling during loading of module in runner

* Pass error handling on the runner

* Remove unneeded string

* Remove unnedeed changes
2020-09-18 15:18:01 +02:00
yuyoyuppe
2bc3480396 common: fix trim functions for wchar_t 2020-09-18 13:33:02 +03:00
Remy Blok
7893f387d5 [FancyZones] Configurable sensitivity radius (#6554)
* Add the setting for the Sensitivity Radius to JSON and the Editor
Use the setting when determining Zones to highligh

* Fix FanzyZones unit tests
Add test for Json upgrade

* Updated texts in FancyZone Editor
More Text to Resources / Use Resources

* Added constant for default of Sensitivity Radius

* When installing from scratch of when a new device is added set the sensitivity radius to the default.
Move all the constant values to a single namespace

* restore correct formatting

Co-authored-by: Remy Blok <remy.blok@prodware.nl>
2020-09-18 09:16:06 +02:00
Divyansh Srivastava
00187269de handle error in Packaged program loading (#6674) 2020-09-17 16:17:02 -07:00
Roy
b3833fcf1a [PowerToys Run] Add Suport for Commandline arguments in Program Plugin (#5791)
* Implemented possibility to add commandline arguments in the Program Plugin

* Add missing return statement inc ommandArgumentParser loop

* Fix typos

* Fix Additional Typo

* Changed -c to /c to make it a valid cmd argument

* Added small comment about importance of order in _programArgumentParsers

Co-authored-by: Roy <royvou@hotmailcom>
2020-09-17 15:39:28 -07:00
Aaron Junker
923972dd49 Update contributing.md (#6636)
* Update contributing.md

* Update contributing.md
2020-09-17 15:06:40 -07:00
Arjun Balgovind
f19bad3761 Revert "[FxCop] Telemetry.csproj" (#6690)
* Revert "marking all warnings (#6642)"

This reverts commit b0f0940534.

* Added warning comment
2020-09-17 14:02:25 -07:00
stefansjfw
b5cc24fcff [FancyZones] Remove migration from registry logic and delete registry data if present (#6657)
* Remove migration from registry logic

* Address PR comments
2020-09-17 20:57:44 +02:00
yuyoyuppe
d414d52156 localization: move localizable strings to .resw for runner/bootstrapper 2020-09-17 20:32:18 +03:00
Clint Rutkas
85c0eaa598 Update readme.md (#6670) 2020-09-16 14:27:37 -07:00
Clint Rutkas
d409a71000 Getting FxCop online (#6668) 2020-09-16 12:26:58 -07:00
Clint Rutkas
0a716c253b Upgrade nuget packages (#6641)
* upgrade mahapps

* update nlog

* all launcher packages now updated

* tests and Setting UI

* markdown

* removing unneeded DLL now from nuget update
2020-09-16 12:24:21 -07:00
Clint Rutkas
13fd6bd6e1 [FxCop] Svg preview handler (#6647)
* Adjusting namespace

* Getting FxCop working e2e
2020-09-16 12:24:07 -07:00
Clint Rutkas
b0f0940534 marking all warnings (#6642) 2020-09-16 12:23:50 -07:00
Clint Rutkas
dc284d9cbb Clean up some unused dependencies, nlog and some newtonsoft (#6650)
* remove nlog

* removing unused referecnes to newtonsoft
2020-09-16 11:36:52 -07:00
Clint Rutkas
0a86360948 Fxcop markdown preview handler (#6646)
* migrating namespace conflict

* Fixing all errors

* removing todo

* tweak wxs
2020-09-16 11:15:34 -07:00
Divyansh Srivastava
e49900f927 Fix sync issue in SelectedItem (#6582) 2020-09-16 09:59:04 -07:00
Arjun Balgovind
5e301133ff [Settings] Fix settings process not terminating on closing settings while minimized (#6626)
* Added code to set CoreWindow to visible on closing while minimized

* Changed to environment.exit
2020-09-16 09:47:43 -07:00
Aaron Junker
5b684cca9a Update style.md (#6323) 2020-09-15 11:24:55 -07:00
stefansjfw
3d36779e19 [FancyZones] Do not zone window if it should be maximized (#6619)
* Do not zone window if it should be maximized

* Update comment

* Remove uneeded field

* Address PR comment
2020-09-15 13:03:17 +02:00
Enrico Giordani
eaf54ca525 Fix typo in URL (#6630) 2020-09-15 12:38:34 +02:00
Arjun Balgovind
25f93e8b94 Fix for issue 3886 (#6585) 2020-09-14 13:12:02 -07:00
Arjun Balgovind
7328aa7df5 Fixed Visibility property changed invoked on clicking away from PT Run (#6588) 2020-09-14 13:10:56 -07:00
Divyansh Srivastava
d75dd71848 Fix for null reference exception (#6589) 2020-09-14 11:03:17 -07:00
Ivan Stošić
3d5c790fb6 [FZ Editor] Improved a function in GridData.cs (#6565)
* Improved a function in GridData.cs

* Allocate the extra values proportionally

* Refactor a constant
2020-09-14 10:05:28 +02:00
Clint Rutkas
5af88de27b tweaking text and adding in headers (#6586) 2020-09-11 17:10:51 -07:00
Clint Rutkas
997a7bc60f adding in trim (#6584) 2020-09-11 16:15:18 -07:00
Arjun Balgovind
bfbd7b53a1 Unregister key delays on closing KBM windows (#6583) 2020-09-11 15:16:34 -07:00
Alekhya
1dec80902d unify the name as it is present in the plugin.json file (#6547) 2020-09-11 13:45:32 -07:00
Alekhya
0478d99aac To catch URI Format Exception in PT Run (#6580)
* add a catch block for uri format exceptions

* Added link to watson crash
2020-09-11 13:04:25 -07:00
stefansjfw
db9677bb4a [FancyZones] Do not zone window if it merges with other window (#6549)
* Do not zone window if it merges with other window (e.g. merge Chrome tab into other Chrome window

* Small move of func call

* Address PR comment

* remove include

* Address PR comment 2
2020-09-11 12:35:43 +02:00
Ivan Stošić
0e32edb603 [FancyZones] Use Ctrl+Win+Alt+arrows to Expand/shrink windows to adjacent zones (#6446)
* Added an Alt key hook

* Refactor a block of code into a method

* Again refactored existing code

* Apparently Win+Alt does not reach FancyZones

* Using Ctrl+alt instead of Win+alt for now

* It works

* Fixed VD change

* Remove unused member

* Fix compilation error

* Enable shrinking

* Fixed comments in .h files

* Remove newline

* Refactored a function into two

The next task is to simplify their code.

* Updated a comment

* Update a variable name

* Reverted to the old implementation of directional move

* More refactoring

* Remove space

* Fixed windows getting stuck

* Changed function name
2020-09-11 11:32:45 +02:00
Arjun Balgovind
82e1be2839 [Launcher] Categorize Lnk files in program plugin correctly as per the target file type (#6348)
* Updated UnregisteredApps code

* Added file type checking code and Folder and File classifications

* Added more file formats

* Removed run as admin for lnk folders

* Added script files as executable and changed hashset to case insensitive

* Removed runasadmin for generic files

* Removed FileTypes enum

* Extended ApplicationTypes enum

* Fix file format error

* Cleaned use of ApplicationType enum to public and match AppType and used ApplicationType in OnAppRenamed

* Modify tests to use ApplicationType enum

* Added tests for new App types

* Modified dummy appref

* Mock Directory.Exists and add tests for GetAppTypeFromPath

* Combined tests
2020-09-10 15:06:37 -07:00
Arjun Balgovind
ab8bec8866 [KBM] Prevent keyboard manager crash when index is not found (#6488)
* Added Sleep(5000) for repro

* Added check to prevent kbm crash for index not found

* Add more safeguards
2020-09-10 11:31:49 -07:00
Arjun Balgovind
3b8fa8b4ce Fixed KBM shortcut remapping not working after using Japanese IME (#6450) 2020-09-10 10:46:33 -07:00
ryanbodrug-microsoft
c4cb3df306 Adding FxCop to Microsoft.Plugin.WindowWalker (#6260)
* Adding FxCop to Microsoft.Plugin.WindowWalker

* Delete WindowResult.cs -- Fix for CA1812 WindowResult is an internal class that is apparently never instantiated. If so, remove the code from the assembly. If this class is intended to contain only static members, make it static (Shared in Visual Basic).

* Fix for CA1806 UpdateOpenWindowsList calls EnumWindows but does not use the HRESULT or error code that the method returns. This could lead to unexpected behavior in error conditions or low-resource situations. Use the result in a conditional statement, assign the result to a variable, or pass it as an argument to another method.

* Fix for: CA1066 Type Microsoft.Plugin.WindowWalker.Components.InteropAndHelpers.RECT should implement IEquatable<T> because it overrides Equals

* Fix for:  CA1052 Type 'FuzzyMatching' is a static holder type but is neither static nor NotInheritable

* Suppress for CA1069 - These values are defined in
https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles.

CA1069 The enum member 'WS_EX_LTRREADING' has the same constant value '0' as member 'WS_EX_LEFT'
CA1069 The enum member 'WS_EX_RIGHTSCROLLBAR' has the same constant value '0' as member 'WS_EX_LEFT'

* Supress CA1069

Code Description
CA1069 The enum member 'SWP_NOREPOSITION' has the same constant value '512' as member 'SWP_NOOWNERZORDER'
CA1069 The enum member 'SWP_FRAMECHANGED' has the same constant value '32' as member 'SWP_DRAWFRAME'

* Suprress CA1069 for ShowWindow values.  See

https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow

CA1069 The enum member 'ShowMaximized' has the same constant value '3' as member 'Maximize'

* Fix code formatting error

* Fix for CA2235: Making POINT serializable

CA2235 Field MinPosition is a member of type WINDOWPLACEMENT which is serializable but is of type Microsoft.Plugin.WindowWalker.Components.InteropAndHelpers.POINT which is not serializable
CA2235 Field MaxPosition is a member of type WINDOWPLACEMENT which is serializable but is of type Microsoft.Plugin.WindowWalker.Components.InteropAndHelpers.POINT which is not serializable

* Fix CA2235 Making RECT serializable

CA2235 Field NormalPosition is a member of type WINDOWPLACEMENT which is serializable but is of type Microsoft.Plugin.WindowWalker.Components.InteropAndHelpers.RECT which is not serializable

* Fixes for CA2101 Specify marshaling for P/Invoke string arguments.

* Fixes for CA2007 Consider calling ConfigureAwait on the awaited task

* Fixes for the following (CA1822 / CA1801):
CA1822 Member 'OnOpenWindowsUpdate' does not access instance data and can be marked as static
Code Description
CA1801 Parameter value of method add_OnOpenWindowsUpdate is never used. Remove the parameter or use it in the method body.
CA1801 Parameter value of method remove_OnOpenWindowsUpdate is never used. Remove the parameter or use it in the method body.

* Fix: CA1710 Rename OpenWindowsUpdateHandler to end in 'EventHandler'

* Fix CA1822 Member 'GetProcessIDFromWindowHandle' does not access instance data and can be marked as static

* Fix CA1062 In externally visible method 'List<int> FuzzyMatching.FindBestFuzzyMatch(string text, string searchText)', validate parameter 'searchText' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.

* Fixes for CA1304 The behavior of 'string.ToLower()' could vary based on the current user's locale settings.

CA1304 The behavior of 'string.ToLower()' could vary based on the current user's locale settings. Replace this call in 'FuzzyMatching.FindBestFuzzyMatch(string, string)' with a call to 'string.ToLower(CultureInfo)'.

Code Description
CA1304 The behavior of 'string.ToLower()' could vary based on the current user's locale settings. Replace this call in 'FuzzyMatching.FindBestFuzzyMatch(string, string)' with a call to 'string.ToLower(CultureInfo)'.

* Supressing warning for CA1814: Prefer jagged arrays over multidimensional however this might be something to consider if needing to optimize the window walker search.

* Fix: CA1062 In externally visible method 'List<List<int>> FuzzyMatching.GetAllMatchIndexes(bool[,] matches)', validate parameter 'matches' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.

* Fix for CA1062 In externally visible method 'int FuzzyMatching.CalculateScoreForMatches(List<int> matches)', validate parameter 'matches' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.

* Fixes for CA1806 Calls x...  but does not use the HRESULT or error code that the method returns. This could lead to unexpected behavior in error conditions or low-resource situations. Use the result in a conditional statement, assign the result to a variable, or pass it as an argument to another method.

Using discard for methods that return void, and checking the hresult before returning parameters.

* Fix for CA1820 Test for empty strings using 'string.Length' property or 'string.IsNullOrEmpty' method instead of an Equality check

* Supress CA1031 Modify 'get_WindowIcon' to catch a more specific allowed exception type, or rethrow the exception

* Code Description
CA1062 In externally visible method 'List<Result> Main.Query(Query query)', validate parameter 'query' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.

* Fixes For CA1304 The behavior of 'string.ToUpper()' could vary based on the current user's locale settings.

CA1304 The behavior of 'string.ToLower()' could vary based on the current user's locale settings. Replace this call in 'SearchController.SearchText.set' with a call to 'string.ToLower(CultureInfo)'.
CA1304 The behavior of 'string.ToLower()' could vary based on the current user's locale settings. Replace this call in 'Window.ProcessName.get' with a call to 'string.ToLower(CultureInfo)'.
CA1304 The behavior of 'string.ToLower()' could vary based on the current user's locale settings. Replace this call in 'Window.SwitchToWindow()' with a call to 'string.ToLower(CultureInfo)'.
CA1304 The behavior of 'string.ToUpper()' could vary based on the current user's locale settings. Replace this call in 'Window.ToString()' with a call to 'string.ToUpper(CultureInfo)'.
CA1307 The behavior of 'string.Equals(string?)' could vary based on the current user's locale settings. Replace this call in 'Microsoft.Plugin.WindowWalker.Components.Window.SwitchToWindow()' with a call to 'string.Equals(string?, System.StringComparison)'.

* Fix: CA1710 Rename SearchResultUpdateHandler to end in 'EventHandler'

* Fix CA1060 Move pinvokes to native methods class

* Fix: CS0067 The event 'OpenWindows.OnOpenWindowsUpdateEventHandler' is never used

1) Remove SearchController::OpenWindowsUpdateHandler(object sender, SearchResultUpdateEventArgs e) as it wasn't being called and was redundant with Update Search Text.
2) In Main.cs calling UpdateOpenWindowsList before UpdateSearchText so that the latest enumerated windows will be called.
3) Removing unused OnOpenWindowsUpdateEventHandler and related code.

* Revert "Fixes for CA2101 Specify marshaling for P/Invoke string arguments."

This reverts commit b3dfe07915.

* Fixing CA2101 by turning off best fit mapping for methods that require ANSI marshalling.

See: https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2101?view=vs-2019

* Previous fix for CA1806 misunderstood int result as hresult.  The actual return value is number of characters written.
NativeMethods.GetWindowText(hwnd, titleBuffer, sizeOfTitle);

* Previous fix for CA1806 misunderstood int result as hresult.  The actual return value is number of characters written.

NativeMethods.GetClassName(Hwnd, windowClassName, windowClassName.MaxCapacity);

* Removing unused window code.  This was done instead of validating fxcop changes in WindowIcon.

* Fixing typos in Window.cs (charachter -> character)
2020-09-10 09:44:22 -07:00
Alekhya
efd5c33a92 set object before using it (#6497) 2020-09-10 09:44:10 -07:00
Niels Laute
f589103f5d Change searchbox order to make text selectable (#6400)
Co-authored-by: Niels Laute <niels9001@hotmail.com>
2020-09-10 09:42:20 -07:00
vldmr11080
19175e9bde Introduce several fallback scenarios when obtaining GUID for current virtual desktop (#6534) 2020-09-10 14:42:36 +02:00
P-Storm
3137aaa660 Create unit tests for Calculator plugin (#6356)
* Refactored logic and made it unit testable

* Changes after code review

* Added to build steps, and modified bracket to new class with unittest. Validates complexer cases now.

Co-authored-by: p-storm <paul.de.man@gmail.com>
2020-09-09 20:01:30 -07:00
Clint Rutkas
cfda69a120 FxCop with ColorPicker (#6464)
* fxcop fixes

* more fixes, not done yet

* supressing 1031 and ca2000 since we are expressly disposing this correctly

* catching a possible crash due to null ref if run twice

* addressing feedback
2020-09-09 17:08:37 -07:00
Clint Rutkas
1027b7de72 Enabling FxCop on tests (#6481) 2020-09-09 15:33:18 -07:00
Arjun Balgovind
fb1888f01f Add in verbose error message and telemetry for SetWindowsHookEx failure (#6454)
* Updated error message when SetWindowsHookEx fails to show correct error message

* Added telemetry for exception in SG, FZ and KBM

* Rename exception to error
2020-09-09 14:27:40 -07:00
Divyansh Srivastava
f61e9d389f catch unhandled FileNotFoundException exception (#6456) 2020-09-09 11:33:28 -07:00
dependabot[bot]
936b02865f Bump http-proxy from 1.17.0 to 1.18.1 in /src/settings-web (#6455)
Bumps [http-proxy](https://github.com/http-party/node-http-proxy) from 1.17.0 to 1.18.1.
- [Release notes](https://github.com/http-party/node-http-proxy/releases)
- [Changelog](https://github.com/http-party/node-http-proxy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/http-party/node-http-proxy/compare/1.17.0...1.18.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-09-09 16:14:58 +02:00
yuyoyuppe
cbd3516fc4 installer: reduce notification spam 2020-09-09 12:50:31 +03:00
yuyoyuppe
c2d6f740a1 bootstrapper: handle the unhandled 2020-09-09 12:50:31 +03:00
Niels Laute
305a04ce69 [Settings] NumberBox headers fixes (#6227)
* Update from master

* Updated Numberbox headers
2020-09-08 15:28:57 -07:00
Arjun Balgovind
fdd7d6afa4 Add in missing telemetry for Keyboard Manager usage (#6393)
* Added key remap invoked telemetry event

* Added queryperformance call

* Added in telemetry for key and shortcut remaps

* Removed redundant if check
2020-09-08 14:40:02 -07:00
Alekhya
1a51f77fce Fix KBM Accessibility issues (#6379)
* Added an accessible name for the combo box

* Add name for the type shortcut button

* Add accessible name for the add new remapping button in both key remapping as well as shortcut remapping windows

* Set accessible names for the delete button

* Set the accessible name to the remapped to icon

* Fix the font icon issue faced while using narrator

* Fix accessible name for Add shortcut remapping button

* Set the accessible name for the target app text box when it loses focus

* fix comment
2020-09-08 12:24:59 -07:00
Arjun Balgovind
8ea8db7994 [PowerToys Run] Remove unused wox resources and move hardcoded strings to resx file (#6181)
* Removed xaml files, added resx file and removed references for PowerLauncher project

* Added resx file for wox.plugin

* Moved Calculator resources to resx

* Migrated resources for Folder and Indexer plugins

* Migrated resources for Program and Shell plugin

* Migrated resources for URI and Window Walker

* Removed GetTranslation, tests need to be refactored

* Removed internationalization classes

* Removed Wox.Core.Resource references

* Fixed Programs plugin tests

* Fixed tests

* Removed language xaml files from installer

* Added locProject.json files

* Fixed resource not found error

* Remove unused strings from PowerLauncher

* Removed all unused strings

* Reverted addition of resx file for Wox.Plugin

* Added more resources for Folder plugin

* Added resources for Folder and Indexer plugin

* Added resources for Program, Shell, Uri and WW plugins

* Changed string from Wox to PT Run

* managed common files
2020-09-08 11:51:24 -07:00
Divyansh Srivastava
cd906b0a6f Corrected querytext display on action keyword (#6341)
* Corrected querytexdisplay on action keyword

* Added tests for UpdateResultWithActionKeyword
2020-09-08 10:32:01 -07:00
Alekhya
85fa644aca Fix KBM Settings page Property related and screen reader Accessibility issues (#6289)
* Add accessible names for the KBM key remapping list and list item

* Add accessible name for the shortcut list item

* Add accessible name for shortcut remapping list

* Added accessible names to all icons

* Add accessible name for image

* Fix font icon narrator issue
2020-09-08 10:25:53 -07:00
Clint Rutkas
839d3f89d8 Update build-powertoys-ci.yml (#6384) 2020-09-08 10:24:33 -07:00
Divyansh Srivastava
52a06b5cdc [PT Run] Mitigate JSON Deserialization exception (#6295)
* Add error reporting window on deserialisation error

* Add message box to show launcher errors

* Change report window to messagebox

* nit fix in error window

* Localized string for error window

* update messagebox interface

* Correct ShowMessageBox argument order
2020-09-08 10:04:17 -07:00
Enrico Giordani
5065239266 [CDPx] add bootstrapper symbols (#6431) 2020-09-08 18:59:57 +02:00
vldmr11080
13426eac50 [FancyZones] Validate zone rect before adding it into layout (#6249)
* Validate zone rect before adding it into layout

* Rename variables for better code readability
2020-09-08 12:06:54 +02:00
Enrico Giordani
c5f90272d1 ImageResizer new icon (#6443) 2020-09-08 11:29:51 +02:00
yuyoyuppe
e0d6c2a4cd tools: add wmi monitor info powershell script 2020-09-07 15:47:40 +03:00
stefansjfw
3c76942799 [FancyZones] Update 'span zones across monitors' feature description and add message box warning accordingly (#6381)
* Update span accross monitors feature description in Settings App

* Add warning if scalings are different

* Address PR comments

* Address comment
2020-09-07 12:24:13 +02:00
twig
4ff888b2b0 Updated links under "How to create new PowerToys" (#6412)
They were 404'ing
2020-09-06 18:02:36 +02:00
Divyansh Srivastava
a0eaf077de [Pt Run] Show context menu for first folder plugin result (#6301)
* Added context menu to first folder result

* Added context menu to first folder result

* Add localization for string in folder plugin

* Fixed issue with context menu not showing on first selected item

* Add exception  logging
2020-09-04 15:12:04 -07:00
Arjun Balgovind
726f94e2a2 [Settings] Fix tabbing issues on KBM settings page (#6304)
* Removed listview items from tab ordering

* Removed tabstops on key/shortcut item controls to prevent double tab requirement
2020-09-04 12:42:41 -07:00
Kamesh Kotwani
19771b171c Updated .exe installer version number from 0.21.0 to 0.21.1 (#6355)
* fixed the .exe installer number

* updated .exe installer version number
2020-09-04 12:15:02 -07:00
Clint Rutkas
b4223967e8 Update README.md
adjusting to aka links
2020-09-04 10:39:50 -07:00
Niranjan
e57283460a devdocs: readme: fix grammar (#6375) 2020-09-04 09:22:28 -07:00
stefansjfw
78edaf5edc [FancyZones] Set 3-zones PriorityGrid as default layout (#6248)
* 3-zones Priority Grid as default layout

* Update tests

* Address PR comments
2020-09-04 16:37:06 +02:00
yuyoyuppe
91f0d40d1a docs: add bootstrapper cmd args description 2020-09-04 17:33:21 +03:00
yuyoyuppe
dacccf1415 docs: add monitor info report readme 2020-09-04 17:19:12 +03:00
yuyoyuppe
8fcb76e300 tools: monitor report info 2020-09-04 17:19:12 +03:00
vldmr11080
24906e6fa5 [FancyZones] FancyZones draw layout test tool (#6358)
* FancyZones draw layout test tool

* Fix formatting in resource file
2020-09-04 11:55:26 +02:00
Seraphima Zykova
570065175c [Settings] Temporary string showing the latest available version (#6254) 2020-09-04 11:56:52 +03:00
stefansjfw
e84a293642 Fix span accross monitors feature (#6335) 2020-09-04 10:11:05 +02:00
Adrian Campos
41559d8742 Fix typo in readme (#6350)
"Experiential" -> "Experimental"
2020-09-04 09:42:46 +02:00
martinchrzan
6e898ae52d Added pixel reveal effect, increased max zoom level to 4, added rounded corners to main and zoom window (#6242) 2020-09-03 23:31:27 +02:00
Arjun Balgovind
288d929477 [Settings] Changed ImageSize class to parse as double instead of int (#6299)
* Changed ImageSize class to parse as double instead of int

* Tweaked fix to resolve empty ImageResizer box fix
2020-09-03 13:43:55 -07:00
Jeremy Wu
807fbd4d89 fix missing fragment portion of LocalPath (#6257) 2020-09-03 12:46:34 -07:00
ryanbodrug-microsoft
6ce47e5cd9 Adding fxcop to PowerLauncher.TelemetryProject (#6259) 2020-09-03 10:44:51 -07:00
Clint Rutkas
712d5fbfa7 fixing the fody warning (#6164)
* fixing the fody warning

* removing the ignored item from the installer
2020-09-03 09:49:28 -07:00
Aaron Junker
8d3380b388 Implement #6312 (#6315) 2020-09-03 09:19:00 -07:00
Seraphima Zykova
c9855a2671 [FancyZones] Fixed type cast warning (#6311) 2020-09-03 17:50:49 +03:00
Enrico Giordani
c887f0ce5b [chore] disable PowerRename unit tests in CI (#6319) 2020-09-03 12:59:54 +02:00
Enrico Giordani
64ee0015d1 [chore] fix line endings (#6307) 2020-09-03 11:44:46 +02:00
Arjun Balgovind
1b598ad87e [Localization] Move PowerToys Run string resources from xaml files to resx (#6165)
* Removed xaml files, added resx file and removed references for PowerLauncher project

* Added resx file for wox.plugin

* Moved Calculator resources to resx

* Migrated resources for Folder and Indexer plugins

* Migrated resources for Program and Shell plugin

* Migrated resources for URI and Window Walker

* Removed GetTranslation, tests need to be refactored

* Removed internationalization classes

* Removed Wox.Core.Resource references

* Fixed Programs plugin tests

* Fixed tests

* Removed language xaml files from installer

* Added locProject.json files

* Fixed resource not found error

* Reverted addition of resx file for Wox.Plugin
2020-09-02 15:24:59 -07:00
Alekhya
c9f536c635 fix for argument out of range exception (#6269) 2020-09-02 13:39:57 -07:00
Divyansh Srivastava
742f4fe36d [Pt Run] Narrator support for result view navigation (#6146)
* Screen reader detecting List view

* Fixed narrator text for listview items and context menu items

* Renamed custom textbox to a more meanigful name

* Renamed custom textbox to a more meanigful name

* Fix formatting of LauncherControl.xaml

* Added support to control multiple elements
2020-09-02 13:34:07 -07:00
Clint Rutkas
fc34c05a2f Update README.md 2020-09-02 12:36:40 -07:00
Clint Rutkas
84055a420b 0.21 readme (#6291)
* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md
2020-09-02 12:26:35 -07:00
Niels Laute
e5ec08ff9d [Read me] Adding videoconference images (#6287)
* Update from master

* Added videoconference images
2020-09-02 10:37:44 -07:00
Enrico Giordani
06267f5a03 Now working on 0.21.2 (#6286) 2020-09-02 10:18:14 -07:00
Enrico Giordani
824bec2784 Update version to 0.21.1 (#6284) 2020-09-02 09:57:55 -07:00
Seraphima Zykova
cb81f7b057 [FancyZones] Convert ARGB color values to RGB (#6277) 2020-09-02 19:27:35 +03:00
Seraphima Zykova
ce43b10b5b [FancyZones] HEX to RGB util (#6275) 2020-09-02 18:34:17 +03:00
882 changed files with 73959 additions and 8810 deletions

View File

@@ -1,5 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: "\U0001F4F7 VideoConference"
url: https://github.com/microsoft/PowerToys/issues/6246
about: Report Bug for the VideoConference Power Toy
- name: "\U0001F6A8 Microsoft Security Response Center (MSRC)"
url: https://msrc.microsoft.com/create-report
about: Report security bugs
@@ -9,3 +12,4 @@ contact_links:
- name: "\U0001F4DA PowerToys dev documentation"
url: https://github.com/microsoft/PowerToys/tree/master/doc/devdocs
about: Documentation for people interested in developing for PowerToys

View File

@@ -10,7 +10,8 @@ setlocal
rem In this sample, the repo root is identical to the script directory path. Adjust the value of the RepoRoot variable accordingly based on your environment.
rem Again, ensure the RepoRoot variable is set to the real repo root location, otherwise the localization toolset wouldn't work as intended.
rem Note that the resolved %~dp0 ends with \.
set RepoRoot=%~dp0..\
set RepoRootWithoutBackslash=%~dp0..
set RepoRoot=%RepoRootWithoutBackslash%\
set OutDir=%RepoRoot%out
set NUGET_PACKAGES=%RepoRoot%packages
set LocalizationXLocPkgVer=2.0.0
@@ -18,9 +19,9 @@ set LocalizationXLocPkgVer=2.0.0
echo Running localization build...
set XLocPath=%NUGET_PACKAGES%\Localization.XLoc.%LocalizationXLocPkgVer%
set LocProjectDirectory=%RepoRoot%src
set LocProjectDirectory=%RepoRootWithoutBackslash%
rem Run the localization tool on all LocProject.json files in the src directory and it's subdirectories
rem Run the localization tool on all LocProject.json files in the src directory and it's subdirectories (directory format must not end with \)
dotnet "%XLocPath%\tools\netcore\Microsoft.Localization.XLoc.dll" /f "%LocProjectDirectory%"
echo Localization build finished with exit code '%errorlevel%'.

View File

@@ -10,7 +10,9 @@ jobs:
BuildConfiguration: ${{ parameters.configuration }}
BuildPlatform: ${{ parameters.platform }}
pool: { vmImage: windows-2019 }
timeoutInMinutes: 120
strategy:
maxParallel: 10
steps:
- template: build-powertoys-steps.yml
parameters:

View File

@@ -82,6 +82,7 @@ steps:
testSelector: 'testAssemblies'
testAssemblyVer2: |
**\Microsoft.Plugin.Program.UnitTests.dll
**\Microsoft.Plugin.Calculator.UnitTest.dll
**\Microsoft.Plugin.Uri.UnitTests.dll
**\Wox.Test.dll
**\*Microsoft.PowerToys.Settings.UI.UnitTests.dll
@@ -96,10 +97,10 @@ steps:
testAssemblyVer2: |
**\ImageResizer.Test.dll
**\KeyboardManagerTest.dll
**\PowerRenameUnitTests.dll
**\UnitTests-CommonLib.dll
**\PreviewPaneUnitTests.dll #this is the markdown tests
**\UnitTests-PreviewHandlerCommon.dll
**\UnitTests-SvgPreviewHandler.dll
**\powerpreviewTest.dll
!**\obj\**
# **\PowerRenameUnitTests.dll

View File

@@ -143,6 +143,9 @@ build:
name: 'Build Power Toys Bootstrapper'
command: '.pipelines\build-bootstrapper.cmd'
artifacts:
- to: 'Symbols'
include:
- 'installer\PowerToysBootstrapper\x64\Release\PowerToysSetup-*.pdb'
- from: 'installer\PowerToysBootstrapper\x64\Release'
to: 'Build_Installer_Output'
include:

View File

@@ -265,6 +265,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Plugin.Uri.UnitTe
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Settings.UI.UnitTests", "src\core\Microsoft.PowerToys.Settings.UI.UnitTests\Microsoft.PowerToys.Settings.UI.UnitTests.csproj", "{0F85E674-34AE-443D-954C-8321EB8B93B1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Plugin.Calculator.UnitTest", "src\modules\launcher\Plugins\Microsoft.Plugin.Calculator.UnitTest\Microsoft.Plugin.Calculator.UnitTest.csproj", "{632BBE62-5421-49EA-835A-7FFA4F499BD6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -531,6 +533,10 @@ Global
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Debug|x64.Build.0 = Debug|x64
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Release|x64.ActiveCfg = Release|x64
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Release|x64.Build.0 = Release|x64
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Debug|x64.ActiveCfg = Debug|x64
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Debug|x64.Build.0 = Debug|x64
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Release|x64.ActiveCfg = Release|x64
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -607,6 +613,7 @@ Global
{03276A39-D4E9-417C-8FFD-200B0EE5E871} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{B81FB7B6-D30E-428F-908A-41422EFC1172} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{0F85E674-34AE-443D-954C-8321EB8B93B1} = {C3081D9A-1586-441A-B5F4-ED815B3719C1}
{632BBE62-5421-49EA-835A-7FFA4F499BD6} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}

122
README.md
View File

@@ -18,15 +18,14 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
### Color Picker
[<img align="left" src="./doc/images/overview/ColorPicker_small.png" />](https://aka.ms/PowerToysOverview_ColorPicker) [ColorPicker](https://aka.ms/PowerToysOverview_ColorPicker) is a simple and quick system-wide color picker with <kbd>Win</kbd>+<kbd>Shift</kbd>+<kbd>C</kbd>. Color Picker allows to pick colors from any currently running application and automatically copies the HEX or RGB values to your clipboard. This code is based on [Martin Chrzan's Color Picker](https://github.com/martinchrzan/ColorPicker).
<br/>
[<img align="left" src="https://aka.ms/powerToysColorPickerImageSmall" />](https://aka.ms/PowerToysOverview_ColorPicker) [ColorPicker](https://aka.ms/PowerToysOverview_ColorPicker) is a simple and quick system-wide color picker with <kbd>Win</kbd>+<kbd>Shift</kbd>+<kbd>C</kbd>. Color Picker allows to pick colors from any currently running application and automatically copies the HEX or RGB values to your clipboard. This code is based on [Martin Chrzan's Color Picker](https://github.com/martinchrzan/ColorPicker).
<br/>
<br/>
<br/>
### FancyZones
[<img align="left" src="./doc/images/overview/FancyZones_small.png" />](https://aka.ms/PowerToysOverview_FancyZones) [FancyZones](https://aka.ms/PowerToysOverview_FancyZones) is a window manager that makes it easy to create complex window layouts and quickly position windows into those layouts.
[<img align="left" src="https://aka.ms/powerToysFancyZoneImageSmall" />](https://aka.ms/PowerToysOverview_FancyZones) [FancyZones](https://aka.ms/PowerToysOverview_FancyZones) is a window manager that makes it easy to create complex window layouts and quickly position windows into those layouts.
<br/>
<br/>
<br/>
@@ -35,7 +34,7 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
### File Explorer Add-ons
[<img align="left" src="./doc/images/overview/PowerPreview_small.png" />](https://aka.ms/PowerToysOverview_FileExplorerAddOns) [File Explorer](https://aka.ms/PowerToysOverview_FileExplorerAddOns) add-ons will enable SVG icon rendering and Preview Pane additions for File Explorer.
[<img align="left" src="https://aka.ms/powerToysPowerPreviewImageSmall" />](https://aka.ms/PowerToysOverview_FileExplorerAddOns) [File Explorer](https://aka.ms/PowerToysOverview_FileExplorerAddOns) add-ons will enable SVG icon rendering and Preview Pane additions for File Explorer.
Preview Pane is an existing feature in the File Explorer. To enable it, you just click the View tab in the ribbon and then click "Preview Pane". PowerToys will now enable two types of files to be previewed: Markdown (.md) & SVG (.svg)
<br/>
@@ -43,7 +42,7 @@ Preview Pane is an existing feature in the File Explorer. To enable it, you jus
### Image Resizer
[<img align="left" src="./doc/images/overview/ImageResizer_small.png" />](https://aka.ms/PowerToysOverview_ImageResizer) [Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) is a Windows Shell Extension for quickly resizing images. With a simple right click from File Explorer, resize one or many images instantly. This code is based on [Brice Lambson's Image Resizer](https://github.com/bricelam/ImageResizer).
[<img align="left" src="https://aka.ms/powerToysImageResizerImageSmall" />](https://aka.ms/PowerToysOverview_ImageResizer) [Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) is a Windows Shell Extension for quickly resizing images. With a simple right click from File Explorer, resize one or many images instantly. This code is based on [Brice Lambson's Image Resizer](https://github.com/bricelam/ImageResizer).
<br/>
<br/>
<br/>
@@ -51,7 +50,7 @@ Preview Pane is an existing feature in the File Explorer. To enable it, you jus
### Keyboard Manager
[<img align="left" src="./doc/images/overview/KBM_small.png" />](https://aka.ms/PowerToysOverview_KeyboardManager) [Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) allows you to customize the keyboard to be more productive by remapping keys and creating your own keyboard shortcuts. This PowerToy requires Windows 10 1903 (build 18362) or later.
[<img align="left" src="https://aka.ms/powerToysKBMImageSmall" />](https://aka.ms/PowerToysOverview_KeyboardManager) [Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) allows you to customize the keyboard to be more productive by remapping keys and creating your own keyboard shortcuts. This PowerToy requires Windows 10 1903 (build 18362) or later.
<br/>
<br/>
<br/>
@@ -59,24 +58,31 @@ Preview Pane is an existing feature in the File Explorer. To enable it, you jus
### PowerRename
[<img align="left" src="./doc/images/overview/PowerRename_small.png" />](https://aka.ms/PowerToysOverview_PowerRename) [PowerRename](https://aka.ms/PowerToysOverview_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. This code is based on [Chris Davis's SmartRename](https://github.com/chrdavis/SmartRename).
[<img align="left" src="https://aka.ms/powerToysPowerRenameImageSmall" />](https://aka.ms/PowerToysOverview_PowerRename) [PowerRename](https://aka.ms/PowerToysOverview_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. This code is based on [Chris Davis's SmartRename](https://github.com/chrdavis/SmartRename).
<br/>
### PowerToys Run
[<img align="left" src="./doc/images/overview/PowerLauncher_small.png" />](https://aka.ms/PowerToysOverview_PowerToysRun) [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) is a new toy in PowerToys that can help you search and launch your app instantly with a simple <kbd>Alt</kbd>+<kbd>Space</kbd> and start typing! It is open source and modular for additional plugins. Window Walker is now inside too! This PowerToy requires Windows 10 1903 (build 18362) or later.
<br/>
[<img align="left" src="https://aka.ms/powerToysPowerLauncherImageSmall" />](https://aka.ms/PowerToysOverview_PowerToysRun) [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) is a new toy in PowerToys that can help you search and launch your app instantly with a simple <kbd>Alt</kbd>+<kbd>Space</kbd> and start typing! It is open source and modular for additional plugins. Window Walker is now inside too! This PowerToy requires Windows 10 1903 (build 18362) or later.
<br/>
<br/>
<br/>
### Shortcut Guide
[<img align="left" src="./doc/images/overview/ShortcutGuide_small.png" />](https://aka.ms/PowerToysOverview_ShortcutGuide) [Windows key shortcut guide](https://aka.ms/PowerToysOverview_ShortcutGuide) 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.
[<img align="left" src="https://aka.ms/powerToysShortcutGuideImageSmall" />](https://aka.ms/PowerToysOverview_ShortcutGuide) [Windows key shortcut guide](https://aka.ms/PowerToysOverview_ShortcutGuide) 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.
<br/>
<br/>
<br/>
<br/>
### Video Conference Mute (Experimental)
[<img align="left" src="https://aka.ms/powerToysVideoConferenceImageSmall" />](https://aka.ms/PowerToysOverview_VideoConference) [Video Conference Mute](https://aka.ms/PowerToysOverview_VideoConference) is a quick and easy way to do a global "mute" of both your microphone and webcam via <kbd>Win</kbd>+<kbd>N</kbd>. Just set your webcam in the target application to the PowerToys VideoConference camera.
**Note:** This is only included in the [pre-release version of PowerToys installer][github-prerelease-link]. This PowerToy requires Windows 10 1903 (build 18362) or later.
<br/>
<br/>
<br/>
## Installing and running Microsoft PowerToys
@@ -87,11 +93,11 @@ Preview Pane is an existing feature in the File Explorer. To enable it, you jus
#### 0.18 users for updating via notifications
- We adjusted how upgrading works in 0.20. In 0.19 we accounted for this upcoming change but if you are going from 0.18 to 0.20, please directly use the installer file.
- We adjusted how upgrading works in 0.20. In 0.19 we accounted for this upcoming change but if you are going from 0.18 to 0.21, please directly use the installer file.
### Via GitHub with EXE [Recommended]
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.20.1-x64.exe` to download the PowerToys installer.
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.21.1-x64.exe` to download the PowerToys installer.
This is our preferred method.
@@ -120,39 +126,83 @@ We currently support the matrix below.
## What's Happening
### July 2020 Update
### August 2020 Update
Our goals for 0.20 release cycle were to focus on adding in a few new features along with a heavy focus on stability / quality fixes. Martin Chrzan helped contribute a new utility that was in our 2021 plans, a screen wide color picker! Chris Davis also helped contribute a SVG icon support for File Explorer!
Our goals for 0.21 release cycle was to focus on stability, localization and quality of life improvements for both the development team and our end users.
Between 0.19 and 0.20 releases, we tracked down a lot of performance and memory issues with PowerToys Run as well. The most important ones got added to 0.19.1 and 0.19.2 releases. If you find something not working correctly, please make us aware.
One of the longer term goal items we have made progress on is the Out of Box experience / initial onboarding experience (OOBE) improvements.[@Niels9001](https://github.com/niels9001/) created a [wicked awesome proof of concept of what the OOBE experience could be](https://github.com/microsoft/PowerToys/issues/1285#issuecomment-679268558). We are pretty stoked about this since it handles one an important item, critical shortcut default adjustments.
In addition, we'd like to thank everyone who filed a bug, gave feedback or made a pull-request. The PowerToys team is extremely grateful to have the support of an amazing active community.
#### Highlights from August
Here are a few highlights from July
- We shipped [v0.21][github-release-link]!
- [Video conference muting first public release][vidConfOverview]
- We shipped [v0.20][github-release-link]!
- [Martin Chrzan's Color Picker](https://github.com/martinchrzan/) was added in! With a quick <kbd>Win</kbd>+<kbd>Shift</kbd>+<kbd>C</kbd>, get the color from your screen
- File Explorer - Can now render SVG icons thanks to Chris Davis
- FancyZones - you can now snap to any number of zones in FancyZones holding <kbd>Shift</kbd>+<kbd>Ctrl</kbd> while dragging a window
- PT Run - keyboard interaction improvements
- PT Run - freshly installed apps are now being detected
- PT Run - Lots of perf and bug fixes
- Keyboard manager - app level shortcuts
- Example: For Outlook, Remap <kbd>Ctrl</kbd>+<kbd>F</kbd> to <kbd>F4</kbd> and now <kbd>Ctrl</kbd>+<kbd>F</kbd> will put up the find window :)
- Keyboard manager - Now can remap key to shortcut and shortcut to key.
- Settings - Now has improved OOBE based on the work the Microsoft Garage Interns did during their hackathon
- PowerRename improvements
**PT Run:**
- Removed need for space in action keywords. This means you now can type `>ipconfig`
- Icon caches fixed and now has colored icons
- Improved font rendering via ClearType (Shout out to [@AnuthaDev](https://github.com/AnuthaDev) doing the heavy lifting here)
- Result speed improvements
- URLs are supported
- Fixed bugs including calculating bugs
For [0.21](https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F8), we are proactively working on:
**FancyZone:**
- <kbd>Win</kbd>+<kbd>Arrow key</kbd> is directional based on zone rect
- Fixed bugs
**Runner:**
- Fixed toast notifications running elevated from non-admin account
**Shortcut Guide:**
- Improved vkey catching which will fix some use cases of it not showing up
**SVG in File Explorer:**
- Embedded image tags will now render in Explorer
**Color Picker:**
- Fixed bug where it would launch via false positive keystrokes
**Accessibility:**
- Settings, PT Run and KBM undergoing improvements
**Localization:**
- Pipeline is now setup and will be doing a full E2E pass on all utilities shortly.
**Dev quality of life improvements:**
- Continued warning count reduction. This release ~80 removed
- StyleCop enabled E2E
- FxCop starting to be added in E2E
#### New experiential PowerToys utility - Video conference muting:
**Note:** This is only included in the [pre-release version of PowerToys installer][github-prerelease-link]. This PowerToy requires Windows 10 1903 (build 18362) or later.
Back in the June timeframe, we started prototyping an idea. With COVID-19, we're all multi-tasking and trying to make the best of everything and being able to quickly mute while on a conference call is critical regardless of where you are on your computer and what application has focus.
The utility will mute not just your audio but your video as well with a single keystroke. You can do audio, video both. We knew this would impact our roadmap and goals but felt extremely strong that this is the right decision. We're all multi-tasking and trying to make the best of everything and being able to quickly mute while on a conference call is critical regardless of where you are on your computer.
We know we have some issues and we have a [master tracking issue - #6246](https://github.com/microsoft/PowerToys/issues/6246). We know a certain laptops currently the video forwarding does not work and are proactively working on fixing this.
To use:
- Set your camera to the PowerToys Video driver in the target application
- <kbd>Win</kbd>+<kbd>N</kbd> to toggle both Audio and Video at the same time
- <kbd>Win</kbd>+<kbd>Shift</kbd>+<kbd>O</kbd> to toggle video
- <kbd>Win</kbd>+<kbd>Shift</kbd>+<kbd>A</kbd> to toggle microphone
For a more information, head over to the [Video conference mute overview][vidConfOverview]
### What is being planned for 0.23
For [0.23](https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F12), we are proactively working on:
- Stability
- Quality
- Localization
- FancyZones improvements
- Improve interactions with elevated windows and keeping most of the PT utilities non-elevated so we still have a 'shell' like experience
- OOBE work
### PowerToys 2020 roadmap
### PowerToys roadmap
Our roadmap for all the [goals and utilities for 2020 detailed over here in the wiki][v1].
Our [prioritized roadmap][roadmap] of features and utilites that the core team is focusing on..
## Developer Guidance
@@ -183,5 +233,7 @@ The application logs basic telemetry. Our Telemetry Data page (Coming Soon) has
[oss-CLA]: https://cla.opensource.microsoft.com
[oss-conduct-code]: CODE_OF_CONDUCT.md
[github-release-link]: https://github.com/microsoft/PowerToys/releases/
[v1]: https://github.com/microsoft/PowerToys/wiki/Version-1.0-Strategy
[github-prerelease-link]: https://github.com/microsoft/PowerToys/releases/tag/v0.22.0-Experimental
[roadmap]: https://github.com/microsoft/PowerToys/wiki/Roadmap
[privacyLink]: http://go.microsoft.com/fwlink/?LinkId=521839
[vidConfOverview]: https://aka.ms/PowerToysOverview_VideoConference

View File

@@ -121,6 +121,12 @@ When you'd like the team to take a look, (even if the work is not yet fully-comp
Once your code has been reviewed and approved by the requisite number of team members, it will be merged into the master branch. Once merged, your PR will be automatically closed.
### How can I become a collaborateur on the PowerToys team
Be a great community member. Just help out a lot and make useful additions, filing bugs/suggestions, help develop fixes and features, code reviews, and always, docs. Lets continue to make the PowerToys repository a great spot to learn and make a great set of utilities.
When the time comes, Microsoft will reach out and help make you a formal team member. Just make sure they can reach out to you :)
---
## Thank you

View File

@@ -40,7 +40,7 @@ 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.**
Contains the source code of the PowerToys runner and of all of the PowerToys modules. **This is where most of the magic happens.**
### The [`tools`](/tools) folder
@@ -80,7 +80,11 @@ modify --installpath "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\%targetFo
- 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 Installer (.MSI)
## Building the Installers
Our installer is two parts, an EXE and an MSI. The EXE contains the MSI and handles more complex install logic.
- The EXE installs all prerequisites and installs PowerToys via the MSI. Also has additional features, such as silent installation flags
- The MSI installs PowerToys.
### Prerequisites Building the Installer (.MSI)
@@ -92,6 +96,15 @@ modify --installpath "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\%targetFo
- From the `installer` folder open `PowerToysSetup.sln` in Visual Studio, in the `Solutions Configuration` drop-down menu select `Release`, from the `Build` menu choose `Build Solution`.
- The resulting `PowerToysSetup.msi` installer will be available in the `installer\PowerToysSetup\x64\Release\` folder.
### Compiling Bootstraper Installer (.EXE)
- MSI Installer needs to be built in release mode
- Build `PowerToysBootstrapper` solution (`installer\PowerToysBootstrapper\`)
#### Supported arguments for EXE installer:
Head over to the wiki to get the [full list of supported installer arguments][installerArgWiki].
## Debugging
The following configuration issue only applies if the user is a member of the Administrators group.
@@ -105,8 +118,8 @@ To run and debug PowerToys from Visual Studio when the user is a member of the A
## 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).
See the instructions on [how to install the PowerToys Module project template](/tools/project_template). <br />
Specifications for the [PowerToys settings API](/doc/devdocs/settings.md).
## Implementation details
@@ -134,7 +147,7 @@ The common lib, as the name suggests, contains code shared by multiple PowerToys
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).
The html portion of the project that is shown in the WebView is contained in [`settings-html`](/src/settings/settings-html).
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`.
@@ -164,3 +177,5 @@ This module has a setting to serve as an example for each of the currently imple
- CustomAction property
![Image of the Options](/doc/images/settings/example_settings.png)
[installerArgWiki]: https://github.com/microsoft/PowerToys/wiki/Installer-arguments-for-exe

View File

@@ -7,6 +7,6 @@
## 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.
- 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/src/codeAnalysis/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.
- 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.

23
doc/devdocs/tools.md Normal file
View File

@@ -0,0 +1,23 @@
# Tools
## [Monitor info report](tools\monitor_info_report)
A small diagnostic tool which helps identifying WinAPI bugs related to the physical monitor detection. When launched, it creates a log file like this:
```
GetSystemMetrics = 2
GetMonitorInfo OK
EnumDisplayDevices OK:
DeviceID = \\?\DISPLAY#VSCBD34#5&25664547&0&UID4355#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
DeviceKey = \Registry\Machine\System\CurrentControlSet\Control\Class\{4d36e96e-e325-11ce-bfc1-08002be10318}\0002
DeviceName = \\.\DISPLAY1\Monitor0
DeviceString = Generic PnP Monitor
GetMonitorInfo OK
EnumDisplayDevices OK:
DeviceID = \\?\DISPLAY#ENC2682#5&25664547&0&UID4357#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
DeviceKey = \Registry\Machine\System\CurrentControlSet\Control\Class\{4d36e96e-e325-11ce-bfc1-08002be10318}\0003
DeviceName = \\.\DISPLAY2\Monitor0
DeviceString = Generic PnP Monitor
EnumDisplayMonitors OK
```
and also duplicates the info to `stdout`.

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -0,0 +1,14 @@
{
"Projects": [
{
"LanguageSet": "Azure_Languages",
"LocItems": [
{
"SourceFile": "installer\\PowerToysBootstrapper\\bootstrapper\\Resources.resx",
"CopyOption": "LangIDOnName",
"OutputPath": "installer\\PowerToysBootstrapper\\bootstrapper"
}
]
}
]
}

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="DOTNET_CORE_DOWNLOAD_FAILURE" xml:space="preserve">
<value>Couldn't download .NET Core Desktop Runtime 3.1, please install it manually.</value>
</data>
<data name="DOTNET_CORE_DOWNLOAD_FAILURE_TITLE" xml:space="preserve">
<value>PowerToys installation error</value>
</data>
</root>

View File

@@ -5,13 +5,6 @@
MAINICON ICON "../../../src/runner/svgs/icon.ico"
IDR_BIN_ICON BIN "../../../src/runner/svgs/icon.ico"
STRINGTABLE
BEGIN
IDS_DOTNET_CORE_DOWNLOAD_FAILURE "Couldn't download .NET Core Desktop Runtime 3.1, please install it manually."
IDS_DOTNET_CORE_DOWNLOAD_FAILURE_TITLE "PowerToys installation error"
END
1 VERSIONINFO
FILEVERSION FILE_VERSION
PRODUCTVERSION PRODUCT_VERSION

View File

@@ -1,4 +1,5 @@
#include "pch.h"
#include "Generated Files/resource.h"
#include <common/common.h>
#include <common/notifications.h>
@@ -9,7 +10,6 @@
#include <common/appMutex.h>
#include <common/processApi.h>
#include "resource.h"
#include <runner/action_runner_utils.h>
@@ -91,7 +91,8 @@ std::unordered_set<CmdArgs> parseCmdArgs(const int nCmdArgs, LPWSTR* argList)
}
return result;
}
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
int bootstrapper()
{
using namespace localized_strings;
winrt::init_apartment();
@@ -215,7 +216,7 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
break;
}
progressParams.progress = min(0.99f, progressParams.progress + 0.001f);
progressParams.progress = std::min(0.99f, progressParams.progress + 0.001f);
notifications::update_progress_bar_toast(TOAST_TAG, progressParams);
}
} }.detach();
@@ -257,12 +258,20 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
updateProgressBar(.5f, INSTALLING_DOTNET);
}
if (installDotnet &&
!updating::dotnet_is_installed() &&
!updating::install_dotnet(cmdArgs.contains(CmdArgs::silent)) &&
!cmdArgs.contains(CmdArgs::silent))
try
{
notifications::show_toast(DOTNET_INSTALL_ERROR, TOAST_TITLE);
if (installDotnet &&
!updating::dotnet_is_installed() &&
!updating::install_dotnet(cmdArgs.contains(CmdArgs::silent)) &&
!cmdArgs.contains(CmdArgs::silent))
{
notifications::show_toast(DOTNET_INSTALL_ERROR, TOAST_TITLE);
}
}
catch (...)
{
MessageBoxW(nullptr, L".NET Core installation", L"Unknown exception encountered!", MB_OK | MB_ICONERROR);
}
updateProgressBar(.75f, INSTALLING_NEW_VERSION);
@@ -288,9 +297,32 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_NO_CONSOLE };
sei.lpFile = newPTPath->c_str();
sei.nShow = SW_SHOWNORMAL;
sei.lpParameters = UPDATE_REPORT_SUCCESS;
ShellExecuteExW(&sei);
}
return 0;
}
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
return bootstrapper();
}
catch (const std::exception& ex)
{
MessageBoxA(nullptr, ex.what(), "Unhandled stdexception encountered!", MB_OK | MB_ICONERROR);
}
catch (winrt::hresult_error const& ex)
{
winrt::hstring message = ex.message();
MessageBoxW(nullptr, message.c_str(), L"Unhandled winrt exception encountered!", MB_OK | MB_ICONERROR);
}
catch (...)
{
auto lastErrorMessage = get_last_error_message(GetLastError());
std::wstring message = lastErrorMessage ? std::move(*lastErrorMessage) : L"";
MessageBoxW(nullptr, message.c_str(), L"Unknown exception encountered!", MB_OK | MB_ICONERROR);
}
return 0;
}

View File

@@ -17,6 +17,9 @@
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)..\..\tools\build\convert-resx-to-rc.ps1 . resource.base.h resource.h bootstrapper.base.rc bootstrapper.rc 105" />
</Target>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{D194E3AA-F824-4CA9-9A58-034DD6B7D022}</ProjectGuid>
@@ -116,13 +119,13 @@
<ItemGroup>
<ClInclude Include="..\runner\updating.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="bootstrapper.rc" />
<None Include="bootstrapper.base.rc" />
<ResourceCompile Include="Generated Files/bootstrapper.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="..\runner\svgs\icon.ico" />
@@ -145,4 +148,4 @@
</PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>
</Project>

View File

@@ -1,5 +1,6 @@
#pragma once
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <shellapi.h>

View File

@@ -12,8 +12,5 @@
// Non-localizable
//////////////////////////////
#define IDS_DOTNET_CORE_DOWNLOAD_FAILURE 101
#define IDS_DOTNET_CORE_DOWNLOAD_FAILURE_TITLE 102
#define IDR_BIN_MSIINSTALLER 103
#define IDR_BIN_ICON 104

View File

@@ -421,52 +421,52 @@
<!-- Added a separate component for Per-User registry changes -->
<!-- Registry Key for Class Registration of Svg Preview Handler -->
<RegistryKey Root="HKCR" Key="CLSID\{ddee2b8a-6807-48a6-bb20-2338174ff779}">
<RegistryValue Type="string" Value="SvgPreviewHandler.SvgPreviewHandler" />
<RegistryValue Type="string" Value="Microsoft.PowerToys.PreviewHandler.Svg.SvgPreviewHandler" />
<RegistryValue Type="string" Name="DisplayName" Value="Svg Preview Handler" />
<RegistryValue Type="string" Name="AppID" Value="{CF142243-F059-45AF-8842-DBBE9783DB14}" />
<RegistryValue Type="string" Key="Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Value=""/>
<RegistryValue Type="string" Key="InprocServer32" Value="mscoree.dll" />
<RegistryValue Type="string" Key="InprocServer32" Name="Assembly" Value="SvgPreviewHandler, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32" Name="Class" Value="SvgPreviewHandler.SvgPreviewHandler" />
<RegistryValue Type="string" Key="InprocServer32" Name="Class" Value="Microsoft.PowerToys.PreviewHandler.Svg.SvgPreviewHandler" />
<RegistryValue Type="string" Key="InprocServer32" Name="RuntimeVersion" Value="v4.0.30319" />
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Both" />
<RegistryValue Type="string" Key="InprocServer32" Name="CodeBase" Value="file:///[FileExplorerPreviewInstallFolder]SvgPreviewHandler.dll" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Assembly" Value="SvgPreviewHandler, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Class" Value="SvgPreviewHandler.SvgPreviewHandler" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Class" Value="Microsoft.PowerToys.PreviewHandler.Svg.SvgPreviewHandler" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="RuntimeVersion" Value="v4.0.30319" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="CodeBase" Value="file:///[FileExplorerPreviewInstallFolder]SvgPreviewHandler.dll" />
</RegistryKey>
<!-- Registry Key for Class Registration of Svg Thumbnail Provider -->
<RegistryKey Root="HKCR" Key="CLSID\{36B27788-A8BB-4698-A756-DF9F11F64F84}">
<RegistryValue Type="string" Value="SvgThumbnailProvider.SvgThumbnailProvider" />
<RegistryValue Type="string" Value="Microsoft.PowerToys.ThumbnailHandler.Svg.SvgThumbnailProvider" />
<RegistryValue Type="string" Name="DisplayName" Value="Svg Thumbnail Provider" />
<RegistryValue Type="string" Name="AppID" Value="{CF142243-F059-45AF-8842-DBBE9783DB14}" />
<RegistryValue Type="string" Key="Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Value=""/>
<RegistryValue Type="string" Key="InprocServer32" Value="mscoree.dll" />
<RegistryValue Type="string" Key="InprocServer32" Name="Assembly" Value="SvgThumbnailProvider, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32" Name="Class" Value="SvgThumbnailProvider.SvgThumbnailProvider" />
<RegistryValue Type="string" Key="InprocServer32" Name="Class" Value="Microsoft.PowerToys.ThumbnailHandler.Svg.SvgThumbnailProvider" />
<RegistryValue Type="string" Key="InprocServer32" Name="RuntimeVersion" Value="v4.0.30319" />
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Both" />
<RegistryValue Type="string" Key="InprocServer32" Name="CodeBase" Value="file:///[FileExplorerPreviewInstallFolder]SvgThumbnailProvider.dll" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Assembly" Value="SvgThumbnailProvider, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Class" Value="SvgThumbnailProvider.SvgThumbnailProvider" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Class" Value="Microsoft.PowerToys.ThumbnailHandler.Svg.SvgThumbnailProvider" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="RuntimeVersion" Value="v4.0.30319" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="CodeBase" Value="file:///[FileExplorerPreviewInstallFolder]SvgThumbnailProvider.dll" />
</RegistryKey>
<!-- Registry Key for Class Registration of Markdown Preview Handler -->
<RegistryKey Root="HKCR" Key="CLSID\{45769bcc-e8fd-42d0-947e-02beef77a1f5}">
<RegistryValue Type="string" Value="MarkdownPreviewHandler.MarkdownPreviewHandler" />
<RegistryValue Type="string" Value="Microsoft.PowerToys.PreviewHandler.Markdown.MarkdownPreviewHandler" />
<RegistryValue Type="string" Name="DisplayName" Value="Markdown Preview Handler" />
<RegistryValue Type="string" Name="AppID" Value="{CF142243-F059-45AF-8842-DBBE9783DB14}" />
<RegistryValue Type="string" Key="Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Value="" />
<RegistryValue Type="string" Key="InprocServer32" Value="mscoree.dll" />
<RegistryValue Type="string" Key="InprocServer32" Name="Assembly" Value="MarkdownPreviewHandler, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32" Name="Class" Value="MarkdownPreviewHandler.MarkdownPreviewHandler" />
<RegistryValue Type="string" Key="InprocServer32" Name="Class" Value="Microsoft.PowerToys.PreviewHandler.Markdown.MarkdownPreviewHandler" />
<RegistryValue Type="string" Key="InprocServer32" Name="RuntimeVersion" Value="v4.0.30319" />
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Both" />
<RegistryValue Type="string" Key="InprocServer32" Name="CodeBase" Value="file:///[FileExplorerPreviewInstallFolder]MarkdownPreviewHandler.dll" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Assembly" Value="MarkdownPreviewHandler, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Class" Value="MarkdownPreviewHandler.MarkdownPreviewHandler" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Class" Value="Microsoft.PowerToys.PreviewHandler.Markdown.MarkdownPreviewHandler" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="RuntimeVersion" Value="v4.0.30319" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="CodeBase" Value="file:///[FileExplorerPreviewInstallFolder]MarkdownPreviewHandler.dll" />
</RegistryKey>
@@ -666,7 +666,7 @@
<File Source="$(var.BinX64Dir)SettingsUIRunner\Microsoft.PowerToys.Settings.UI.Runner.exe"/>
<File Source="$(var.BinX64Dir)SettingsUIRunner\Microsoft.PowerToys.Settings.UI.exe"/>
<!-- dll -->
<?foreach File in concrt140_app.dll;Microsoft.Bcl.AsyncInterfaces.dll;Microsoft.PowerToys.Settings.UI.Lib.dll;Microsoft.PowerToys.Settings.UI.Runner.dll;Microsoft.Toolkit.dll;Microsoft.Toolkit.Uwp.dll;Microsoft.Toolkit.Uwp.UI.dll;Microsoft.Toolkit.Win32.UI.XamlHost.dll;Microsoft.Toolkit.Win32.UI.XamlHost.Managed.dll;Microsoft.Toolkit.Wpf.UI.Controls.dll;Microsoft.Toolkit.Wpf.UI.XamlHost.dll;Microsoft.UI.Xaml.dll;Microsoft.Xaml.Interactions.dll;Microsoft.Xaml.Interactivity.dll;msvcp140_1_app.dll;msvcp140_2_app.dll;msvcp140_app.dll;Newtonsoft.Json.dll;PowerToysInterop.dll;System.Runtime.CompilerServices.Unsafe.dll;System.Runtime.dll;System.Text.Encodings.Web.dll;System.Text.Json.dll;vcamp140_app.dll;vccorlib140_app.dll;vcomp140_app.dll;vcruntime140_1_app.dll;vcruntime140_app.dll;Telemetry.dll;ManagedCommon.dll?>
<?foreach File in concrt140_app.dll;Microsoft.Bcl.AsyncInterfaces.dll;Microsoft.PowerToys.Settings.UI.Lib.dll;Microsoft.PowerToys.Settings.UI.Runner.dll;Microsoft.Toolkit.dll;Microsoft.Toolkit.Uwp.dll;Microsoft.Toolkit.Uwp.UI.dll;Microsoft.Toolkit.Win32.UI.XamlHost.dll;Microsoft.Toolkit.Win32.UI.XamlHost.Managed.dll;Microsoft.Toolkit.Wpf.UI.Controls.dll;Microsoft.Toolkit.Wpf.UI.XamlHost.dll;Microsoft.UI.Xaml.dll;Microsoft.Xaml.Interactions.dll;Microsoft.Xaml.Interactivity.dll;msvcp140_1_app.dll;msvcp140_2_app.dll;msvcp140_app.dll;Newtonsoft.Json.dll;PowerToysInterop.dll;System.Runtime.CompilerServices.Unsafe.dll;System.Text.Encodings.Web.dll;System.Text.Json.dll;vcamp140_app.dll;vccorlib140_app.dll;vcomp140_app.dll;vcruntime140_1_app.dll;vcruntime140_app.dll;Telemetry.dll;ManagedCommon.dll?>
<File Id="SettingsV2_$(var.File)" Source="$(var.BinX64Dir)SettingsUIRunner\$(var.File)" />
<?endforeach?>
<!-- json -->
@@ -844,7 +844,7 @@
<ComponentGroup Id="LauncherComponents">
<Component Id="launcherInstallComponent" Directory="LauncherInstallFolder" Guid="5E688DB4-C522-4268-BA54-ED1CDFFE9DB6">
<File Source="$(var.BinX64Dir)modules\Launcher\Microsoft.Launcher.dll" />
<?foreach File in concrt140_app.dll;ICSharpCode.SharpZipLib.dll;JetBrains.Annotations.dll;Mages.Core.dll;Microsoft.Search.Interop.dll;EntityFramework.SqlServer.dll;EntityFramework.dll;Mono.Cecil.dll;Mono.Cecil.Mdb.dll;Mono.Cecil.Pdb.dll;Mono.Cecil.Rocks.dll;msvcp140_1_app.dll;msvcp140_2_app.dll;msvcp140_app.dll;Newtonsoft.Json.dll;NLog.dll;NLog.Extensions.Logging.dll;Pinyin4Net.dll;PowerLauncher.deps.json;PowerLauncher.dll;PowerLauncher.exe;Microsoft.Xaml.Behaviors.dll;System.Text.Json.dll;sni.dll;System.Data.SQLite.EF6.dll;PowerLauncher.runtimeconfig.json;SQLite.Interop.dll;System.Data.OleDb.dll;System.Data.SqlClient.dll;System.Data.SQLite.dll;vcamp140_app.dll;vccorlib140_app.dll;vcomp140_app.dll;vcruntime140_1_app.dll;vcruntime140_app.dll;Wox.Core.dll;Wox.Infrastructure.dll;Wox.Plugin.dll;PowerToysInterop.dll;Telemetry.dll;PowerLauncher.Telemetry.dll;PropertyChanged.dll;Microsoft.Extensions.Configuration.Abstractions.dll;Microsoft.Extensions.Configuration.Binder.dll;Microsoft.Extensions.Configuration.dll;Microsoft.Extensions.DependencyInjection.Abstractions.dll;Microsoft.Extensions.DependencyInjection.dll;Microsoft.Extensions.Logging.Abstractions.dll;Microsoft.Extensions.Logging.dll;Microsoft.Extensions.Options.dll;Microsoft.Extensions.Primitives.dll;ControlzEx.dll;MahApps.Metro.dll;ManagedCommon.dll?>
<?foreach File in concrt140_app.dll;ICSharpCode.SharpZipLib.dll;JetBrains.Annotations.dll;Mages.Core.dll;Microsoft.Search.Interop.dll;EntityFramework.SqlServer.dll;EntityFramework.dll;Mono.Cecil.dll;Mono.Cecil.Mdb.dll;Mono.Cecil.Pdb.dll;Mono.Cecil.Rocks.dll;msvcp140_1_app.dll;msvcp140_2_app.dll;msvcp140_app.dll;Newtonsoft.Json.dll;NLog.dll;NLog.Extensions.Logging.dll;Pinyin4Net.dll;PowerLauncher.deps.json;PowerLauncher.dll;PowerLauncher.exe;Microsoft.Xaml.Behaviors.dll;System.Text.Json.dll;sni.dll;System.Data.SQLite.EF6.dll;PowerLauncher.runtimeconfig.json;SQLite.Interop.dll;System.Data.OleDb.dll;System.Data.SqlClient.dll;System.Data.SQLite.dll;vcamp140_app.dll;vccorlib140_app.dll;vcomp140_app.dll;vcruntime140_1_app.dll;vcruntime140_app.dll;Wox.Core.dll;Wox.Infrastructure.dll;Wox.Plugin.dll;PowerToysInterop.dll;Telemetry.dll;PowerLauncher.Telemetry.dll;Microsoft.Extensions.Configuration.Abstractions.dll;Microsoft.Extensions.Configuration.Binder.dll;Microsoft.Extensions.Configuration.dll;Microsoft.Extensions.DependencyInjection.Abstractions.dll;Microsoft.Extensions.DependencyInjection.dll;Microsoft.Extensions.Logging.Abstractions.dll;Microsoft.Extensions.Logging.dll;Microsoft.Extensions.Options.dll;Microsoft.Extensions.Primitives.dll;ControlzEx.dll;MahApps.Metro.dll;ManagedCommon.dll?>
<File Id="File_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\$(var.File)" />
<?endforeach?>
<File Source="$(var.BinX64Dir)SettingsUIRunner\Microsoft.PowerToys.Settings.UI.Lib.dll" />
@@ -874,20 +874,6 @@
<Component Id="calculatorImagesComponent" Directory="CalculatorImagesFolder" Guid="07EC9232-CF9A-4CDB-8D8E-E79DC75096C0">
<File Id="calculatorPluginImg_calculator_light" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Calculator\Images\calculator.light.png" />
<File Id="calculatorPluginImg_calculator_dark" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Calculator\Images\calculator.dark.png" />
</Component>
<Component Id="calculatorLanguagesComponent" Directory="CalculatorLanguagesFolder" Guid="2D8019E7-664F-4529-9FAA-83C8DACF0732">
<?foreach LanguageFile in de.xaml;en.xaml;pl.xaml;tr.xaml;zh-cn.xaml;zh-tw.xaml?>
<!--NB: Ids can't contain hyphens-->
<?if $(var.LanguageFile) = zh-cn.xaml?>
<?define IdSafeLanguage = zh_cn.xaml?>
<?elseif $(var.LanguageFile) = zh-tw.xaml?>
<?define IdSafeLanguage = zh_tw.xaml?>
<?else?>
<?define IdSafeLanguage = $(var.LanguageFile)?>
<?endif?>
<File Id="File_calc_Plugin_$(var.IdSafeLanguage)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Calculator\Languages\$(var.LanguageFile)" />
<?undef IdSafeLanguage?>
<?endforeach?>
</Component>
<Component Id="calculatorpinyindbComponent" Directory="CalculatorpinyindbFolder" Guid="D5527670-BE9A-4AA9-9D36-1249F2184B5B">
<?foreach File in pinyin_gwoyeu_mapping.xml;pinyin_mapping.xml;unicode_to_hanyu_pinyin.txt?>
@@ -906,20 +892,6 @@
<File Id="FolderPlugin_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Folder\Images\$(var.File)" />
<?endforeach?>
</Component>
<Component Id="FolderPluginLanguagesComponent" Directory="FolderPluginLanguagesFolder" Guid="6316D847-5FD2-488B-A60E-5517BF95A25C">
<?foreach LanguageFile in de.xaml;en.xaml;pl.xaml;tr.xaml;zh-cn.xaml;zh-tw.xaml?>
<!--NB: Ids can't contain hyphens-->
<?if $(var.LanguageFile) = zh-cn.xaml?>
<?define IdSafeLanguage = zh_cn.xaml?>
<?elseif $(var.LanguageFile) = zh-tw.xaml?>
<?define IdSafeLanguage = zh_tw.xaml?>
<?else?>
<?define IdSafeLanguage = $(var.LanguageFile)?>
<?endif?>
<File Id="File_Folder_Plugin_$(var.IdSafeLanguage)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Folder\Languages\$(var.LanguageFile)" />
<?undef IdSafeLanguage?>
<?endforeach?>
</Component>
<Component Id="FolderPluginpinyindbComponent" Directory="FolderPluginpinyindbFolder" Guid="233BE087-B9DC-408A-8809-593C42DE8B1B">
<?foreach File in pinyin_gwoyeu_mapping.xml;pinyin_mapping.xml;unicode_to_hanyu_pinyin.txt?>
<File Id="FolderPlugin_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Folder\pinyindb\$(var.File)" />
@@ -936,20 +908,6 @@
<?foreach File in app.dark.png;app.light.png;disable.light.png;disable.dark.png;folder.light.png;folder.dark.png;shell.light.png;shell.dark.png;user.light.png;user.dark.png?>
<File Id="Program_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Program\Images\$(var.File)" />
<?endforeach?>
</Component>
<Component Id="ProgramLanguagesComponent" Directory="ProgramLanguagesFolder" Guid="EBFF53B6-3602-4F55-8784-FC7DB29D3D62">
<?foreach LanguageFile in de.xaml;en.xaml;pl.xaml;tr.xaml;zh-cn.xaml;zh-tw.xaml?>
<!--NB: Ids can't contain hyphens-->
<?if $(var.LanguageFile) = zh-cn.xaml?>
<?define IdSafeLanguage = zh_cn.xaml?>
<?elseif $(var.LanguageFile) = zh-tw.xaml?>
<?define IdSafeLanguage = zh_tw.xaml?>
<?else?>
<?define IdSafeLanguage = $(var.LanguageFile)?>
<?endif?>
<File Id="File_Program_Plugin_$(var.IdSafeLanguage)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Program\Languages\$(var.LanguageFile)" />
<?undef IdSafeLanguage?>
<?endforeach?>
</Component>
<Component Id="ProgrampinyindbComponent" Directory="ProgrampinyindbFolder" Guid="65A488C3-C67D-45F7-9654-6DF529AEEB3F">
<?foreach File in pinyin_gwoyeu_mapping.xml;pinyin_mapping.xml;unicode_to_hanyu_pinyin.txt?>
@@ -967,20 +925,6 @@
<?foreach File in shell.light.png;shell.dark.png;user.light.png;user.dark.png?>
<File Id="Shell_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Shell\Images\$(var.File)" />
<?endforeach?>
</Component>
<Component Id="ShellLanguagesComponent" Directory="ShellLanguagesFolder" Guid="4190F789-8A66-46AA-B920-C76CB29277D7">
<?foreach LanguageFile in de.xaml;en.xaml;pl.xaml;tr.xaml;zh-cn.xaml;zh-tw.xaml?>
<!--NB: Ids can't contain hyphens-->
<?if $(var.LanguageFile) = zh-cn.xaml?>
<?define IdSafeLanguage = zh_cn.xaml?>
<?elseif $(var.LanguageFile) = zh-tw.xaml?>
<?define IdSafeLanguage = zh_tw.xaml?>
<?else?>
<?define IdSafeLanguage = $(var.LanguageFile)?>
<?endif?>
<File Id="File_Shell_Plugin_$(var.IdSafeLanguage)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Shell\Languages\$(var.LanguageFile)" />
<?undef IdSafeLanguage?>
<?endforeach?>
</Component>
<Component Id="ShellpinyindbComponent" Directory="ShellpinyindbFolder" Guid="A60742F3-2187-47F2-A5B5-300E44837DD7">
<?foreach File in pinyin_gwoyeu_mapping.xml;pinyin_mapping.xml;unicode_to_hanyu_pinyin.txt?>
@@ -999,20 +943,6 @@
<File Id="Indexer_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Indexer\Images\$(var.File)" />
<?endforeach?>
</Component>
<Component Id="IndexerLanguagesComponent" Directory="IndexerLanguagesFolder" Guid="4B5ED306-7DD5-4EA6-9DBB-CF054929182C">
<?foreach LanguageFile in de.xaml;en.xaml;ja.xaml;pl.xaml;tr.xaml;zh-cn.xaml;zh-tw.xaml?>
<!--NB: Ids can't contain hyphens-->
<?if $(var.LanguageFile) = zh-cn.xaml?>
<?define IdSafeLanguage = zh_cn.xaml?>
<?elseif $(var.LanguageFile) = zh-tw.xaml?>
<?define IdSafeLanguage = zh_tw.xaml?>
<?else?>
<?define IdSafeLanguage = $(var.LanguageFile)?>
<?endif?>
<File Id="Indexer_Plugin_$(var.IdSafeLanguage)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Indexer\Languages\$(var.LanguageFile)" />
<?undef IdSafeLanguage?>
<?endforeach?>
</Component>
<Component Id="IndexerpinyindbComponent" Directory="IndexerpinyindbFolder" Guid="48DE333A-80F8-400A-87F4-244DF0A2DB05">
<?foreach File in pinyin_gwoyeu_mapping.xml;pinyin_mapping.xml;unicode_to_hanyu_pinyin.txt?>
<File Id="IndexerPlugin_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Indexer\pinyindb\$(var.File)" />
@@ -1029,20 +959,6 @@
<File Id="UriDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Uri\Images\Uri.dark.png" />
<File Id="UriLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Uri\Images\Uri.light.png" />
</Component>
<Component Id="UriLanguagesComponent" Directory="UriLanguagesFolder" Guid="4CA9CECE-BB93-4686-A58F-35835F5C3F7D">
<?foreach LanguageFile in de.xaml;en.xaml;pl.xaml;tr.xaml;zh-cn.xaml;zh-tw.xaml?>
<!--NB: Ids can't contain hyphens-->
<?if $(var.LanguageFile) = zh-cn.xaml?>
<?define IdSafeLanguage = zh_cn.xaml?>
<?elseif $(var.LanguageFile) = zh-tw.xaml?>
<?define IdSafeLanguage = zh_tw.xaml?>
<?else?>
<?define IdSafeLanguage = $(var.LanguageFile)?>
<?endif?>
<File Id="File_Uri_Plugin_$(var.IdSafeLanguage)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Uri\Languages\$(var.LanguageFile)" />
<?undef IdSafeLanguage?>
<?endforeach?>
</Component>
<Component Id="UripinyindbComponent" Directory="UripinyindbFolder" Guid="A52A7281-CD7C-4E7D-A5A6-EA8CFCF462A2">
<?foreach File in pinyin_gwoyeu_mapping.xml;pinyin_mapping.xml;unicode_to_hanyu_pinyin.txt?>
<File Id="UriPlugin_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Uri\pinyindb\$(var.File)" />
@@ -1059,9 +975,6 @@
<File Id="WindowWalkerDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\Images\windowwalker.dark.png" />
<File Id="WindowWalkerLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\Images\windowwalker.light.png" />
</Component>
<Component Id="WindowWalkerLanguagesComponent" Directory="WindowWalkerLanguagesFolder" Guid="7D9471D9-5C0A-4BD1-9A01-BAB65DD58834">
<File Id="WindowWalkerLanguage" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\Languages\en.xaml" />
</Component>
<Component Id="WindowWalkerpinyindbComponent" Directory="WindowWalkerpinyindbFolder" Guid="02C7A758-CDD4-4E27-9EC7-2ED68DC444B0">
<?foreach File in pinyin_gwoyeu_mapping.xml;pinyin_mapping.xml;unicode_to_hanyu_pinyin.txt?>
<File Id="WindowWalkerPlugin_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\pinyindb\$(var.File)" />

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Version>0.21.0</Version>
<Version>0.23.2</Version>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,14 @@
{
"Projects": [
{
"LanguageSet": "Azure_Languages",
"LocItems": [
{
"SourceFile": "src\\runner\\Resources.resx",
"CopyOption": "LangIDOnName",
"OutputPath": "src\\runner"
}
]
}
]
}

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="DOTNET_CORE_DOWNLOAD_FAILURE" xml:space="preserve">
<value>Couldn't download .NET Core Desktop Runtime 3.1, please install it manually.</value>
</data>
<data name="DOTNET_CORE_DOWNLOAD_FAILURE_TITLE" xml:space="preserve">
<value>PowerToys installation error</value>
</data>
</root>

View File

@@ -2,12 +2,6 @@
#include "resource.h"
#include "../common/version.h"
STRINGTABLE
BEGIN
IDS_DOTNET_CORE_DOWNLOAD_FAILURE "Couldn't download .NET Core Desktop Runtime 3.1, please install it manually."
IDS_DOTNET_CORE_DOWNLOAD_FAILURE_TITLE "PowerToys installation error"
END
1 VERSIONINFO
FILEVERSION FILE_VERSION
PRODUCTVERSION PRODUCT_VERSION

View File

@@ -16,7 +16,7 @@
#include "../runner/tray_icon.h"
#include "../runner/action_runner_utils.h"
#include "resource.h"
#include "Generated Files/resource.h"
extern "C" IMAGE_DOS_HEADER __ImageBase;
@@ -190,7 +190,8 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
}
else
{
params = args[nextArg];
params += args[nextArg];
params += L' ';
nextArg++;
}
}

View File

@@ -19,6 +19,10 @@
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 . resource.base.h resource.h action_runner.base.rc action_runner.rc" />
</Target>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}</ProjectGuid>
@@ -167,7 +171,8 @@
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="action_runner.rc" />
<None Include="action_runner.base.rc" />
<ResourceCompile Include="Generated Files/action_runner.rc" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@@ -9,8 +9,3 @@
#define INTERNAL_NAME "action_runner"
#define ORIGINAL_FILENAME "action_runner.exe"
// Non-localizable
//////////////////////////////
#define IDS_DOTNET_CORE_DOWNLOAD_FAILURE 101
#define IDS_DOTNET_CORE_DOWNLOAD_FAILURE_TITLE 102

View File

@@ -1,18 +1,18 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices;
namespace ManagedCommon
{
internal static class NativeMethods
{
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, int processId);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
}
}
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices;
namespace ManagedCommon
{
internal static class NativeMethods
{
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, int processId);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
}
}

View File

@@ -1,37 +1,37 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace ManagedCommon
{
public static class RunnerHelper
{
public static void WaitForPowerToysRunner(int powerToysPID, Action act)
{
var stackTrace = new StackTrace();
var assembly = Assembly.GetCallingAssembly().GetName();
var callingMethod = stackTrace.GetFrame(1).GetMethod().Name;
PowerToysTelemetry.Log.WriteEvent(new DebugEvent() { Message = $"[{assembly}][{callingMethod}]WaitForPowerToysRunner waiting for Event powerToysPID={powerToysPID}" });
Task.Run(() =>
{
const uint INFINITE = 0xFFFFFFFF;
const uint WAIT_OBJECT_0 = 0x00000000;
const uint SYNCHRONIZE = 0x00100000;
IntPtr powerToysProcHandle = NativeMethods.OpenProcess(SYNCHRONIZE, false, powerToysPID);
if (NativeMethods.WaitForSingleObject(powerToysProcHandle, INFINITE) == WAIT_OBJECT_0)
{
PowerToysTelemetry.Log.WriteEvent(new DebugEvent() { Message = $"[{assembly}][{callingMethod}]WaitForPowerToysRunner Event Notified powerToysPID={powerToysPID}" });
act.Invoke();
}
});
}
}
}
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace ManagedCommon
{
public static class RunnerHelper
{
public static void WaitForPowerToysRunner(int powerToysPID, Action act)
{
var stackTrace = new StackTrace();
var assembly = Assembly.GetCallingAssembly().GetName();
var callingMethod = stackTrace.GetFrame(1).GetMethod().Name;
PowerToysTelemetry.Log.WriteEvent(new DebugEvent() { Message = $"[{assembly}][{callingMethod}]WaitForPowerToysRunner waiting for Event powerToysPID={powerToysPID}" });
Task.Run(() =>
{
const uint INFINITE = 0xFFFFFFFF;
const uint WAIT_OBJECT_0 = 0x00000000;
const uint SYNCHRONIZE = 0x00100000;
IntPtr powerToysProcHandle = NativeMethods.OpenProcess(SYNCHRONIZE, false, powerToysPID);
if (NativeMethods.WaitForSingleObject(powerToysProcHandle, INFINITE) == WAIT_OBJECT_0)
{
PowerToysTelemetry.Log.WriteEvent(new DebugEvent() { Message = $"[{assembly}][{callingMethod}]WaitForPowerToysRunner Event Notified powerToysPID={powerToysPID}" });
act.Invoke();
}
});
}
}
}

View File

@@ -4,6 +4,7 @@
using System.Diagnostics.Tracing;
// WARNING: THIS FILE GETS REPLACED ON THE BUILD FARM
namespace Microsoft.PowerToys.Telemetry
{
/// <summary>

View File

@@ -9,7 +9,7 @@
VersionHelper::VersionHelper(std::string str)
{
// Remove whitespaces chars and a leading 'v'
str = left_trim(trim(str), "v");
str = left_trim<char>(trim<char>(str), "v");
// Replace '.' with spaces
replace_chars(str, ".", ' ');

View File

@@ -11,12 +11,6 @@
#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "shlwapi.lib")
namespace localized_strings
{
const wchar_t LAST_ERROR_FORMAT_STRING[] = L"%s failed with error %d: %s";
const wchar_t LAST_ERROR_TITLE_STRING[] = L"Error";
}
std::optional<RECT> get_window_pos(HWND hwnd)
{
RECT window;
@@ -91,7 +85,7 @@ std::optional<std::wstring> get_last_error_message(const DWORD dw)
return message;
}
void show_last_error_message(LPCWSTR lpszFunction, DWORD dw)
void show_last_error_message(LPCWSTR lpszFunction, DWORD dw, LPCWSTR errorTitle)
{
const auto system_message = get_last_error_message(dw);
if (!system_message.has_value())
@@ -107,7 +101,7 @@ void show_last_error_message(LPCWSTR lpszFunction, DWORD dw)
lpszFunction,
dw,
system_message->c_str());
MessageBoxW(NULL, (LPCTSTR)lpDisplayBuf, localized_strings::LAST_ERROR_TITLE_STRING, MB_OK);
MessageBoxW(NULL, (LPCTSTR)lpDisplayBuf, errorTitle, MB_OK | MB_ICONERROR);
LocalFree(lpDisplayBuf);
}
}

View File

@@ -6,6 +6,13 @@
#include <memory>
#include <vector>
namespace localized_strings
{
const wchar_t LAST_ERROR_FORMAT_STRING[] = L"%s failed with error %d: %s";
const wchar_t LAST_ERROR_TITLE_STRING[] = L"Error";
}
// Gets position of given window.
std::optional<RECT> get_window_pos(HWND hwnd);
@@ -16,7 +23,7 @@ bool is_system_window(HWND hwnd, const char* class_name);
int run_message_loop(const bool until_idle = false, const std::optional<uint32_t> timeout_seconds = {});
std::optional<std::wstring> get_last_error_message(const DWORD dw);
void show_last_error_message(LPCWSTR lpszFunction, DWORD dw);
void show_last_error_message(LPCWSTR lpszFunction, DWORD dw, LPCWSTR errorTitle = localized_strings::LAST_ERROR_TITLE_STRING);
enum WindowState
{

View File

@@ -2,6 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Threading;
using interop;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -9,46 +10,73 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Microsoft.Interop.Tests
{
[TestClass]
public class InteropTests
public class InteropTests : IDisposable
{
private const string ServerSidePipe = "\\\\.\\pipe\\serverside";
private const string ClientSidePipe = "\\\\.\\pipe\\clientside";
private TwoWayPipeMessageIPCManaged clientPipe;
internal TwoWayPipeMessageIPCManaged ClientPipe { get; set; }
private bool disposedValue;
[TestInitialize]
public void Initialize()
{
clientPipe = new TwoWayPipeMessageIPCManaged(ClientSidePipe, ServerSidePipe, null);
ClientPipe = new TwoWayPipeMessageIPCManaged(ClientSidePipe, ServerSidePipe, null);
}
[TestCleanup]
public void Cleanup()
{
clientPipe.End();
ClientPipe.End();
}
[TestMethod]
public void TestSend()
{
var testString = "This string is a test\n";
var reset = new AutoResetEvent(false);
var serverPipe = new TwoWayPipeMessageIPCManaged(
ServerSidePipe,
ClientSidePipe,
(string msg) =>
using (var reset = new AutoResetEvent(false))
{
using (var serverPipe = new TwoWayPipeMessageIPCManaged(
ServerSidePipe,
ClientSidePipe,
(string msg) =>
{
Assert.AreEqual(testString, msg);
reset.Set();
}))
{
Assert.AreEqual(testString, msg);
reset.Set();
});
serverPipe.Start();
clientPipe.Start();
serverPipe.Start();
ClientPipe.Start();
clientPipe.Send(testString);
reset.WaitOne();
ClientPipe.Send(testString);
reset.WaitOne();
serverPipe.End();
serverPipe.End();
}
}
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
ClientPipe.Dispose();
}
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
// TODO: set large fields to null
disposedValue = true;
}
}
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}

View File

@@ -77,7 +77,6 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
@@ -107,6 +106,11 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers">
<Version>3.3.0</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers">
<Version>1.1.118</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@@ -4,6 +4,7 @@
#include <msclr\marshal.h>
#include <msclr\marshal_cppstd.h>
#include <common/debug_control.h>
#include <common/common.h>
using namespace interop;
using namespace System::Runtime::InteropServices;
@@ -46,7 +47,8 @@ void KeyboardHook::Start()
0);
if (hookHandle == nullptr)
{
throw std::exception("SetWindowsHookEx failed.");
DWORD errorCode = GetLastError();
show_last_error_message(L"SetWindowsHookEx", errorCode, L"PowerToys - Interop");
}
}
}

View File

@@ -127,5 +127,10 @@ public
{
public:
literal int VK_WIN_BOTH = CommonSharedConstants::VK_WIN_BOTH;
static String^ PowerLauncherSharedEvent()
{
return gcnew String(CommonSharedConstants::POWER_LAUNCHER_SHARED_EVENT);
}
};
}

View File

@@ -403,8 +403,13 @@ void notifications::show_toast_with_activations(std::wstring message,
}
}
}
notifier.Show(notification);
try
{
notifier.Show(notification);
}
catch (...)
{
}
}
void notifications::update_progress_bar_toast(std::wstring_view tag, progress_bar_params params)

View File

@@ -27,15 +27,21 @@ inline std::vector<wil::unique_process_handle> getProcessHandlesByName(const std
handleAccess |= PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ;
for (const DWORD processId : processIds)
{
wil::unique_process_handle hProcess{ OpenProcess(handleAccess, FALSE, processId) };
wchar_t name[MAX_PATH + 1];
if (!hProcess || !GetProcessImageFileNameW(hProcess.get(), name, MAX_PATH))
try
{
continue;
wil::unique_process_handle hProcess{ OpenProcess(handleAccess, FALSE, processId) };
wchar_t name[MAX_PATH + 1];
if (!hProcess || !GetProcessImageFileNameW(hProcess.get(), name, MAX_PATH))
{
continue;
}
if (processName == PathFindFileNameW(name))
{
result.push_back(std::move(hProcess));
}
}
if (processName == PathFindFileNameW(name))
catch (...)
{
result.push_back(std::move(hProcess));
}
}
return result;

View File

@@ -343,6 +343,11 @@ namespace PowerToysSettings
return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedObject(L"value");
}
json::JsonObject PowerToyValues::get_raw_json()
{
return m_json;
}
std::wstring PowerToyValues::serialize()
{
set_version();

View File

@@ -83,6 +83,7 @@ namespace PowerToysSettings
std::optional<int> get_int_value(std::wstring_view property_name);
std::optional<std::wstring> get_string_value(std::wstring_view property_name);
std::optional<json::JsonObject> get_json(std::wstring_view property_name);
json::JsonObject get_raw_json();
std::wstring serialize();
void save_to_settings_file();

View File

@@ -8,4 +8,7 @@ namespace CommonSharedConstants
// Fake key code to represent VK_WIN.
inline const DWORD VK_WIN_BOTH = 0x104;
}
// Path to the event used by PowerLauncher
const wchar_t POWER_LAUNCHER_SHARED_EVENT[] = L"Local\\PowerToysRunInvokeEvent-30f26ad7-d36d-4c0e-ab02-68bb5ff3c4ab";
}

View File

@@ -4,21 +4,39 @@
#include <string>
#include <algorithm>
constexpr inline std::string_view default_trim_arg = " \t\r\n";
inline std::string_view left_trim(std::string_view s, const std::string_view chars_to_trim = default_trim_arg)
template<typename CharT>
struct default_trim_arg
{
s.remove_prefix(std::min(s.find_first_not_of(chars_to_trim), size(s)));
};
template<>
struct default_trim_arg<char>
{
static inline constexpr std::string_view value = " \t\r\n";
};
template<>
struct default_trim_arg<wchar_t>
{
static inline constexpr std::wstring_view value = L" \t\r\n";
};
template<typename CharT>
inline std::basic_string_view<CharT> left_trim(std::basic_string_view<CharT> s, const std::basic_string_view<CharT> chars_to_trim = default_trim_arg<CharT>::value)
{
s.remove_prefix(std::min<size_t>(s.find_first_not_of(chars_to_trim), size(s)));
return s;
}
inline std::string_view right_trim(std::string_view s, const std::string_view chars_to_trim = default_trim_arg)
template<typename CharT>
inline std::basic_string_view<CharT> right_trim(std::basic_string_view<CharT> s, const std::basic_string_view<CharT> chars_to_trim = default_trim_arg<CharT>::value)
{
s.remove_suffix(std::min(size(s) - s.find_last_not_of(chars_to_trim) - 1, size(s)));
s.remove_suffix(std::min<size_t>(size(s) - s.find_last_not_of(chars_to_trim) - 1, size(s)));
return s;
}
inline std::string_view trim(std::string_view s, const std::string_view chars_to_trim = default_trim_arg)
template<typename CharT>
inline std::basic_string_view<CharT> trim(std::basic_string_view<CharT> s, const std::basic_string_view<CharT> chars_to_trim = default_trim_arg<CharT>::value)
{
return left_trim(right_trim(s, chars_to_trim), chars_to_trim);
}

View File

@@ -25,7 +25,6 @@ namespace localized_strings
const wchar_t GITHUB_NEW_VERSION_UPDATE_NOW[] = L"Update now";
const wchar_t GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART[] = L"At next launch";
const wchar_t UNINSTALLATION_SUCCESS[] = L"Previous version of PowerToys was uninstalled successfully.";
const wchar_t UNINSTALLATION_UNKNOWN_ERROR[] = L"Error: please uninstall the previous version of PowerToys manually.";
const wchar_t GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT[] = L"An update to PowerToys is available. Visit our GitHub page to update.\n";
@@ -131,11 +130,6 @@ namespace updating
std::move(toast_params));
}
void show_uninstallation_success()
{
::notifications::show_toast(localized_strings::UNINSTALLATION_SUCCESS, TOAST_TITLE);
}
void show_uninstallation_error()
{
::notifications::show_toast(localized_strings::UNINSTALLATION_UNKNOWN_ERROR, TOAST_TITLE);

View File

@@ -12,7 +12,6 @@ namespace updating
void show_visit_github(const updating::new_version_download_info& info);
void show_install_error(const updating::new_version_download_info& info);
void show_version_ready(const updating::new_version_download_info& info);
void show_uninstallation_success();
void show_uninstallation_error();
void update_download_progress(const updating::new_version_download_info& info, float progress);

View File

@@ -84,7 +84,6 @@ namespace updating
const auto uninstall_result = MsiInstallProductW(package_path.c_str(), L"REMOVE=ALL");
if (ERROR_SUCCESS == uninstall_result)
{
notifications::show_uninstallation_success();
return true;
}
else if (auto system_message = get_last_error_message(uninstall_result); system_message.has_value())
@@ -238,16 +237,17 @@ namespace updating
}
}
std::future<void> check_new_version_available()
std::future<std::wstring> check_new_version_available()
{
const auto new_version = co_await get_new_github_version_info_async();
if (!new_version)
{
updating::notifications::show_unavailable();
co_return;
co_return VersionHelper{ VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION }.toWstring();
}
updating::notifications::show_available(new_version.value());
co_return new_version->version_string;
}
std::future<std::wstring> download_update()

View File

@@ -30,7 +30,7 @@ namespace updating
std::future<void> try_autoupdate(const bool download_updates_automatically);
std::filesystem::path get_pending_updates_path();
std::future<void> check_new_version_available();
std::future<std::wstring> check_new_version_available();
std::future<std::wstring> download_update();
// non-localized

View File

@@ -4,10 +4,11 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UI.Lib
{
public class ColorPickerSettings : BasePTModuleSettings
public class ColorPickerSettings : BasePTModuleSettings, ISettingsConfig
{
public const string ModuleName = "ColorPicker";
@@ -21,7 +22,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
Name = ModuleName;
}
public virtual void Save()
public virtual void Save(ISettingsUtils settingsUtils)
{
// Save settings to file
var options = new JsonSerializerOptions
@@ -29,7 +30,18 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
WriteIndented = true,
};
SettingsUtils.SaveSettings(JsonSerializer.Serialize(this, options), ModuleName);
settingsUtils.SaveSettings(JsonSerializer.Serialize(this, options), ModuleName);
}
public string GetModuleName()
{
return Name;
}
// This can be utilized in the future if the settings.json file is to be modified/deleted.
public bool UpgradeSettingsConfiguration()
{
return false;
}
}
}

View File

@@ -3,19 +3,33 @@
// See the LICENSE file in the project root for more information.
using System.Text.Json.Serialization;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UI.Lib
{
public class FancyZonesSettings : BasePTModuleSettings
public class FancyZonesSettings : BasePTModuleSettings, ISettingsConfig
{
public const string ModuleName = "FancyZones";
public FancyZonesSettings()
{
Version = string.Empty;
Name = string.Empty;
Version = "1.0";
Name = ModuleName;
Properties = new FZConfigProperties();
}
[JsonPropertyName("properties")]
public FZConfigProperties Properties { get; set; }
public string GetModuleName()
{
return Name;
}
// This can be utilized in the future if the settings.json file is to be modified/deleted.
public bool UpgradeSettingsConfiguration()
{
return false;
}
}
}

View File

@@ -2,12 +2,15 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
using Microsoft.PowerToys.Settings.UI.Lib.Utilities;
namespace Microsoft.PowerToys.Settings.UI.Lib
{
public class GeneralSettings
public class GeneralSettings : ISettingsConfig
{
// Gets or sets a value indicating whether packaged.
[JsonPropertyName("packaged")]
@@ -82,5 +85,32 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
{
return interop.CommonManaged.GetProductVersion();
}
// This function is to implement the ISettingsConfig interface.
// This interface helps in getting the settings configurations.
public string GetModuleName()
{
// The SettingsUtils functions access general settings when the module name is an empty string.
return string.Empty;
}
public bool UpgradeSettingsConfiguration()
{
try
{
if (Helper.CompareVersions(PowertoysVersion, Helper.GetProductVersion()) < 0)
{
// Update settings
PowertoysVersion = Helper.GetProductVersion();
return true;
}
}
catch (FormatException)
{
// If there is an issue with the version number format, don't migrate settings.
}
return false;
}
}
}

View File

@@ -0,0 +1,20 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UI.Lib
{
public interface ISettingsUtils
{
T GetSettings<T>(string powertoy = "", string fileName = "settings.json")
where T : ISettingsConfig, new();
void SaveSettings(string jsonSettings, string powertoy = "", string fileName = "settings.json");
bool SettingsExists(string powertoy = "", string fileName = "settings.json");
void DeleteSettings(string powertoy = "");
}
}

View File

@@ -4,10 +4,11 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UI.Lib
{
public class ImageResizerSettings : BasePTModuleSettings
public class ImageResizerSettings : BasePTModuleSettings, ISettingsConfig
{
public const string ModuleName = "Image Resizer";
@@ -29,5 +30,16 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
};
return JsonSerializer.Serialize(this, options);
}
public string GetModuleName()
{
return Name;
}
// This can be utilized in the future if the settings.json file is to be modified/deleted.
public bool UpgradeSettingsConfiguration()
{
return false;
}
}
}

View File

@@ -141,15 +141,18 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
set
{
int newWidth = -1;
int.TryParse(value + string.Empty, out newWidth);
double newWidth = -1;
if (newWidth < 0)
if (value < 0 || double.IsNaN(value))
{
newWidth = 0;
}
else
{
newWidth = value;
}
if (_width != value)
if (_width != newWidth)
{
_width = newWidth;
OnPropertyChanged();
@@ -167,15 +170,18 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
set
{
int newHeight = -1;
int.TryParse(value + string.Empty, out newHeight);
double newHeight = -1;
if (newHeight < 0)
if (value < 0 || double.IsNaN(value))
{
newHeight = 0;
}
else
{
newHeight = value;
}
if (_height != value)
if (_height != newHeight)
{
_height = newHeight;
OnPropertyChanged();

View File

@@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Microsoft.PowerToys.Settings.UI.Lib.Interface
{
// Common interface to be implemented by all the objects which get and store settings properties.
public interface ISettingsConfig
{
string ToJsonString();
string GetModuleName();
bool UpgradeSettingsConfiguration();
}
}

View File

@@ -0,0 +1,11 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Microsoft.PowerToys.Settings.UI.Lib.Interface
{
public interface ISettingsRepository<T>
{
T SettingsConfig { get; set; }
}
}

View File

@@ -2,11 +2,13 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UI.Lib
{
public class KeyboardManagerProfile
public class KeyboardManagerProfile : ISettingsConfig
{
[JsonPropertyName("remapKeys")]
public RemapKeysDataModel RemapKeys { get; set; }
@@ -19,5 +21,21 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
RemapKeys = new RemapKeysDataModel();
RemapShortcuts = new ShortcutsKeyDataModel();
}
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
}
public string GetModuleName()
{
return KeyboardManagerSettings.ModuleName;
}
// This can be utilized in the future if the default.json file is to be modified/deleted.
public bool UpgradeSettingsConfiguration()
{
return false;
}
}
}

View File

@@ -3,11 +3,14 @@
// See the LICENSE file in the project root for more information.
using System.Text.Json.Serialization;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UI.Lib
{
public class KeyboardManagerSettings : BasePTModuleSettings
public class KeyboardManagerSettings : BasePTModuleSettings, ISettingsConfig
{
public const string ModuleName = "Keyboard Manager";
[JsonPropertyName("properties")]
public KeyboardManagerProperties Properties { get; set; }
@@ -15,14 +18,18 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
{
Properties = new KeyboardManagerProperties();
Version = "1";
Name = "_unset_";
Name = ModuleName;
}
public KeyboardManagerSettings(string ptName)
public string GetModuleName()
{
Properties = new KeyboardManagerProperties();
Version = "1";
Name = ptName;
return Name;
}
// This can be utilized in the future if the settings.json file is to be modified/deleted.
public bool UpgradeSettingsConfiguration()
{
return false;
}
}
}

View File

@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.PowerToys.Settings.UI.Lib.Utilities;
@@ -35,5 +36,10 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
{
return MapKeys(NewRemapKeys);
}
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
}
}
}

View File

@@ -4,10 +4,11 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UI.Lib
{
public class PowerLauncherSettings : BasePTModuleSettings
public class PowerLauncherSettings : BasePTModuleSettings, ISettingsConfig
{
public const string ModuleName = "PowerToys Run";
@@ -17,11 +18,11 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
public PowerLauncherSettings()
{
Properties = new PowerLauncherProperties();
Version = "1";
Version = "1.0";
Name = ModuleName;
}
public virtual void Save()
public virtual void Save(ISettingsUtils settingsUtils)
{
// Save settings to file
var options = new JsonSerializerOptions
@@ -29,7 +30,18 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
WriteIndented = true,
};
SettingsUtils.SaveSettings(JsonSerializer.Serialize(this, options), ModuleName);
settingsUtils.SaveSettings(JsonSerializer.Serialize(this, options), ModuleName);
}
public string GetModuleName()
{
return Name;
}
// This can be utilized in the future if the settings.json file is to be modified/deleted.
public bool UpgradeSettingsConfiguration()
{
return false;
}
}
}

View File

@@ -3,10 +3,11 @@
// See the LICENSE file in the project root for more information.
using System.Text.Json.Serialization;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UI.Lib
{
public class PowerPreviewSettings : BasePTModuleSettings
public class PowerPreviewSettings : BasePTModuleSettings, ISettingsConfig
{
public const string ModuleName = "File Explorer";
@@ -20,11 +21,15 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
Name = ModuleName;
}
public PowerPreviewSettings(string ptName)
public string GetModuleName()
{
Properties = new PowerPreviewProperties();
Version = "1";
Name = ptName;
return Name;
}
// This can be utilized in the future if the settings.json file is to be modified/deleted.
public bool UpgradeSettingsConfiguration()
{
return false;
}
}
}

View File

@@ -3,10 +3,11 @@
// See the LICENSE file in the project root for more information.
using System.Text.Json;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UI.Lib
{
public class PowerRenameLocalProperties
public class PowerRenameLocalProperties : ISettingsConfig
{
public PowerRenameLocalProperties()
{
@@ -51,5 +52,18 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
{
return JsonSerializer.Serialize(this);
}
// This function is required to implement the ISettingsConfig interface and obtain the settings configurations.
public string GetModuleName()
{
string moduleName = PowerRenameSettings.ModuleName;
return moduleName;
}
// This can be utilized in the future if the settings.json file is to be modified/deleted.
public bool UpgradeSettingsConfiguration()
{
return false;
}
}
}

View File

@@ -3,10 +3,11 @@
// See the LICENSE file in the project root for more information.
using System.Text.Json.Serialization;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UI.Lib
{
public class PowerRenameSettings : BasePTModuleSettings
public class PowerRenameSettings : BasePTModuleSettings, ISettingsConfig
{
public const string ModuleName = "PowerRename";
@@ -39,5 +40,16 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
Version = "1";
Name = ptName;
}
public string GetModuleName()
{
return Name;
}
// This can be utilized in the future if the power-rename-settings.json file is to be modified/deleted.
public bool UpgradeSettingsConfiguration()
{
return false;
}
}
}

View File

@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Microsoft.PowerToys.Settings.UI.Lib
@@ -16,5 +17,10 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
{
InProcessRemapKeys = new List<KeysDataModel>();
}
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
}
}
}

View File

@@ -0,0 +1,66 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UI.Lib
{
// This Singleton class is a wrapper around the settings configurations that are accessed by viewmodels.
// This class can have only one instance and therefore the settings configurations are common to all.
public class SettingsRepository<T> : ISettingsRepository<T>
where T : class, ISettingsConfig, new()
{
private static readonly object _SettingsRepoLock = new object();
private static ISettingsUtils _settingsUtils;
private static SettingsRepository<T> settingsRepository;
private T settingsConfig;
public static SettingsRepository<T> GetInstance(ISettingsUtils settingsUtils)
{
// To ensure that only one instance of Settings Repository is created in a multi-threaded environment.
lock (_SettingsRepoLock)
{
if (settingsRepository == null)
{
settingsRepository = new SettingsRepository<T>();
_settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils));
}
return settingsRepository;
}
}
// The Singleton class must have a private constructor so that it cannot be instantiated by any other object other than itself.
private SettingsRepository()
{
}
// Settings configurations shared across all viewmodels
public T SettingsConfig
{
get
{
if (settingsConfig == null)
{
T settingsItem = new T();
settingsConfig = _settingsUtils.GetSettings<T>(settingsItem.GetModuleName());
}
return settingsConfig;
}
set
{
if (value != null)
{
settingsConfig = value;
}
}
}
}
}

View File

@@ -3,24 +3,36 @@
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
using System.Text.Json;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
using Microsoft.PowerToys.Settings.UI.Lib.Utilities;
namespace Microsoft.PowerToys.Settings.UI.Lib
{
public static class SettingsUtils
public class SettingsUtils : ISettingsUtils
{
private const string DefaultFileName = "settings.json";
private const string DefaultModuleName = "";
private IIOProvider _ioProvider;
public static bool SettingsFolderExists(string powertoy)
public SettingsUtils(IIOProvider ioProvider)
{
return Directory.Exists(Path.Combine(LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"));
_ioProvider = ioProvider ?? throw new ArgumentNullException(nameof(ioProvider));
}
public static void CreateSettingsFolder(string powertoy)
private bool SettingsFolderExists(string powertoy)
{
Directory.CreateDirectory(Path.Combine(LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"));
return _ioProvider.DirectoryExists(System.IO.Path.Combine(LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"));
}
private void CreateSettingsFolder(string powertoy)
{
_ioProvider.CreateDirectory(System.IO.Path.Combine(LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"));
}
public void DeleteSettings(string powertoy = "")
{
_ioProvider.DeleteDirectory(System.IO.Path.Combine(LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"));
}
/// <summary>
@@ -31,33 +43,64 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
{
if (string.IsNullOrWhiteSpace(powertoy))
{
return Path.Combine(
return System.IO.Path.Combine(
LocalApplicationDataFolder(),
$"Microsoft\\PowerToys\\{fileName}");
}
return Path.Combine(
return System.IO.Path.Combine(
LocalApplicationDataFolder(),
$"Microsoft\\PowerToys\\{powertoy}\\{fileName}");
}
public static bool SettingsExists(string powertoy = DefaultModuleName, string fileName = DefaultFileName)
public bool SettingsExists(string powertoy = DefaultModuleName, string fileName = DefaultFileName)
{
return File.Exists(GetSettingsPath(powertoy, fileName));
return _ioProvider.FileExists(GetSettingsPath(powertoy, fileName));
}
/// <summary>
/// Get a Deserialized object of the json settings string.
/// This function creates a file in the powertoy folder if it does not exist and returns an object with default properties.
/// </summary>
/// <returns>Deserialized json settings object.</returns>
public static T GetSettings<T>(string powertoy = DefaultModuleName, string fileName = DefaultFileName)
public T GetSettings<T>(string powertoy = DefaultModuleName, string fileName = DefaultFileName)
where T : ISettingsConfig, new()
{
var jsonSettingsString = File.ReadAllText(GetSettingsPath(powertoy, fileName));
if (SettingsExists(powertoy, fileName))
{
// Given the file already exists, to deserialize the file and read it's content.
T deserializedSettings = GetFile<T>(powertoy, fileName);
// IF the file needs to be modified, to save the new configurations accordingly.
if (deserializedSettings.UpgradeSettingsConfiguration())
{
SaveSettings(deserializedSettings.ToJsonString(), powertoy, fileName);
}
return deserializedSettings;
}
else
{
// If the settings file does not exist, to create a new object with default parameters and save it to a newly created settings file.
T newSettingsItem = new T();
SaveSettings(newSettingsItem.ToJsonString(), powertoy, fileName);
return newSettingsItem;
}
}
// Given the powerToy folder name and filename to be accessed, this function deserializes and returns the file.
private T GetFile<T>(string powertoyFolderName = DefaultModuleName, string fileName = DefaultFileName)
{
// Adding Trim('\0') to overcome possible NTFS file corruption.
// Look at issue https://github.com/microsoft/PowerToys/issues/6413 you'll see the file has a large sum of \0 to fill up a 4096 byte buffer for writing to disk
// This, while not totally ideal, does work around the problem by trimming the end.
// The file itself did write the content correctly but something is off with the actual end of the file, hence the 0x00 bug
var jsonSettingsString = _ioProvider.ReadAllText(GetSettingsPath(powertoyFolderName, fileName)).Trim('\0');
return JsonSerializer.Deserialize<T>(jsonSettingsString);
}
// Save settings to a json file.
public static void SaveSettings(string jsonSettings, string powertoy = DefaultModuleName, string fileName = DefaultFileName)
public void SaveSettings(string jsonSettings, string powertoy = DefaultModuleName, string fileName = DefaultFileName)
{
try
{
@@ -68,7 +111,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
CreateSettingsFolder(powertoy);
}
File.WriteAllText(GetSettingsPath(powertoy, fileName), jsonSettings);
_ioProvider.WriteAllText(GetSettingsPath(powertoy, fileName), jsonSettings);
}
}
catch
@@ -76,7 +119,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
}
}
public static string LocalApplicationDataFolder()
private static string LocalApplicationDataFolder()
{
return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
}

View File

@@ -3,10 +3,11 @@
// See the LICENSE file in the project root for more information.
using System.Text.Json.Serialization;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UI.Lib
{
public class ShortcutGuideSettings : BasePTModuleSettings
public class ShortcutGuideSettings : BasePTModuleSettings, ISettingsConfig
{
public const string ModuleName = "Shortcut Guide";
@@ -19,5 +20,16 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
Properties = new ShortcutGuideProperties();
Version = "1.0";
}
public string GetModuleName()
{
return Name;
}
// This can be utilized in the future if the settings.json file is to be modified/deleted.
public bool UpgradeSettingsConfiguration()
{
return false;
}
}
}

View File

@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Microsoft.PowerToys.Settings.UI.Lib
@@ -20,5 +21,10 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
GlobalRemapShortcuts = new List<KeysDataModel>();
AppSpecificRemapShortcuts = new List<AppSpecificKeysDataModel>();
}
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
}
}
}

View File

@@ -39,8 +39,11 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.Utilities
ModuleAction = customAction,
};
var sendCustomAction = new SendCustomAction(moduleName);
sendCustomAction.Action = moduleCustomAction;
var sendCustomAction = new SendCustomAction(moduleName)
{
Action = moduleCustomAction,
};
return sendCustomAction.ToJsonString();
}
@@ -53,12 +56,15 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.Utilities
Directory.CreateDirectory(path);
}
var watcher = new FileSystemWatcher();
watcher.Path = path;
watcher.Filter = fileName;
watcher.NotifyFilter = NotifyFilters.LastWrite;
var watcher = new FileSystemWatcher
{
Path = path,
Filter = fileName,
NotifyFilter = NotifyFilters.LastWrite,
EnableRaisingEvents = true,
};
watcher.Changed += (o, e) => onChangedCallback();
watcher.EnableRaisingEvents = true;
return watcher;
}
@@ -71,11 +77,11 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.Utilities
[DllImport("user32.dll")]
private static extern bool AllowSetForegroundWindow(int dwProcessId);
private static interop.LayoutMapManaged layoutMap = new interop.LayoutMapManaged();
private static readonly interop.LayoutMapManaged LayoutMap = new interop.LayoutMapManaged();
public static string GetKeyName(uint key)
{
return layoutMap.GetKeyName(key);
return LayoutMap.GetKeyName(key);
}
public static string GetProductVersion()

View File

@@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Microsoft.PowerToys.Settings.UI.Lib.Utilities
{
public interface IIOProvider
{
bool FileExists(string path);
bool DirectoryExists(string path);
bool CreateDirectory(string path);
void DeleteDirectory(string path);
void WriteAllText(string path, string content);
string ReadAllText(string path);
}
}

View File

@@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.IO;
namespace Microsoft.PowerToys.Settings.UI.Lib.Utilities
{
public class SystemIOProvider : IIOProvider
{
public bool CreateDirectory(string path)
{
var directioryInfo = Directory.CreateDirectory(path);
return directioryInfo != null;
}
public void DeleteDirectory(string path)
{
Directory.Delete(path, recursive: true);
}
public bool DirectoryExists(string path)
{
return Directory.Exists(path);
}
public bool FileExists(string path)
{
return File.Exists(path);
}
public string ReadAllText(string path)
{
return File.ReadAllText(path);
}
public void WriteAllText(string path, string content)
{
File.WriteAllText(path, content);
}
}
}

View File

@@ -5,32 +5,38 @@
using System;
using System.Text.Json;
using Microsoft.PowerToys.Settings.UI.Lib.Helpers;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
public class ColorPickerViewModel : Observable
{
private GeneralSettings GeneralSettingsConfig { get; set; }
private readonly ISettingsUtils _settingsUtils;
private ColorPickerSettings _colorPickerSettings;
private bool _isEnabled;
private Func<string, int> SendConfigMSG { get; }
public ColorPickerViewModel(Func<string, int> ipcMSGCallBackFunc)
public ColorPickerViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc)
{
if (SettingsUtils.SettingsExists(ColorPickerSettings.ModuleName))
// Obtain the general PowerToy settings configurations
GeneralSettingsConfig = settingsRepository.SettingsConfig;
_settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils));
if (_settingsUtils.SettingsExists(ColorPickerSettings.ModuleName))
{
_colorPickerSettings = SettingsUtils.GetSettings<ColorPickerSettings>(ColorPickerSettings.ModuleName);
_colorPickerSettings = _settingsUtils.GetSettings<ColorPickerSettings>(ColorPickerSettings.ModuleName);
}
else
{
_colorPickerSettings = new ColorPickerSettings();
}
if (SettingsUtils.SettingsExists())
{
var generalSettings = SettingsUtils.GetSettings<GeneralSettings>();
_isEnabled = generalSettings.Enabled.ColorPicker;
}
_isEnabled = GeneralSettingsConfig.Enabled.ColorPicker;
// set the callback functions value to hangle outgoing IPC message.
SendConfigMSG = ipcMSGCallBackFunc;
@@ -50,10 +56,10 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
_isEnabled = value;
OnPropertyChanged(nameof(IsEnabled));
// grab the latest version of settings
var generalSettings = SettingsUtils.GetSettings<GeneralSettings>();
generalSettings.Enabled.ColorPicker = value;
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(generalSettings);
// Set the status of ColorPicker in the general settings
GeneralSettingsConfig.Enabled.ColorPicker = value;
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(GeneralSettingsConfig);
SendConfigMSG(outgoing.ToString());
}
}

View File

@@ -3,15 +3,19 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Drawing;
using System.Runtime.CompilerServices;
using Microsoft.PowerToys.Settings.UI.Lib.Helpers;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
using Microsoft.PowerToys.Settings.UI.Lib.ViewModels.Commands;
namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
public class FancyZonesViewModel : Observable
{
private const string ModuleName = "FancyZones";
private GeneralSettings GeneralSettingsConfig { get; set; }
private const string ModuleName = FancyZonesSettings.ModuleName;
public ButtonClickCommand LaunchEditorEventHandler { get; set; }
@@ -21,19 +25,14 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
private string settingsConfigFileFolder = string.Empty;
public FancyZonesViewModel(Func<string, int> ipcMSGCallBackFunc, string configFileSubfolder = "")
public FancyZonesViewModel(ISettingsRepository<GeneralSettings> settingsRepository, ISettingsRepository<FancyZonesSettings> moduleSettingsRepository, Func<string, int> ipcMSGCallBackFunc, string configFileSubfolder = "")
{
// To obtain the general settings configurations of PowerToys Settings.
GeneralSettingsConfig = settingsRepository.SettingsConfig;
settingsConfigFileFolder = configFileSubfolder;
try
{
Settings = SettingsUtils.GetSettings<FancyZonesSettings>(GetSettingsSubPath());
}
catch
{
Settings = new FancyZonesSettings();
SettingsUtils.SaveSettings(Settings.ToJsonString(), GetSettingsSubPath());
}
// To obtain the settings configurations of Fancy zones.
Settings = moduleSettingsRepository.SettingsConfig;
LaunchEditorEventHandler = new ButtonClickCommand(LaunchEditor);
@@ -49,6 +48,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
_restoreSize = Settings.Properties.FancyzonesRestoreSize.Value;
_useCursorPosEditorStartupScreen = Settings.Properties.UseCursorposEditorStartupscreen.Value;
_showOnAllMonitors = Settings.Properties.FancyzonesShowOnAllMonitors.Value;
_spanZonesAcrossMonitors = Settings.Properties.FancyzonesSpanZonesAcrossMonitors.Value;
_makeDraggedWindowTransparent = Settings.Properties.FancyzonesMakeDraggedWindowTransparent.Value;
_highlightOpacity = Settings.Properties.FancyzonesHighlightOpacity.Value;
_excludedApps = Settings.Properties.FancyzonesExcludedApps.Value;
@@ -66,18 +66,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
string highlightColor = Settings.Properties.FancyzonesZoneHighlightColor.Value;
_zoneHighlightColor = highlightColor != string.Empty ? highlightColor : "#0078D7";
GeneralSettings generalSettings;
try
{
generalSettings = SettingsUtils.GetSettings<GeneralSettings>(string.Empty);
}
catch
{
generalSettings = new GeneralSettings();
SettingsUtils.SaveSettings(generalSettings.ToJsonString(), string.Empty);
}
_isEnabled = generalSettings.Enabled.FancyZones;
_isEnabled = GeneralSettingsConfig.Enabled.FancyZones;
}
private bool _isEnabled;
@@ -115,9 +104,10 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
if (value != _isEnabled)
{
_isEnabled = value;
GeneralSettings generalSettings = SettingsUtils.GetSettings<GeneralSettings>(string.Empty);
generalSettings.Enabled.FancyZones = value;
OutGoingGeneralSettings snd = new OutGoingGeneralSettings(generalSettings);
// Set the status of FancyZones in the general settings configuration
GeneralSettingsConfig.Enabled.FancyZones = value;
OutGoingGeneralSettings snd = new OutGoingGeneralSettings(GeneralSettingsConfig);
SendConfigMSG(snd.ToString());
OnPropertyChanged("IsEnabled");
@@ -401,6 +391,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
set
{
value = ToRGBHex(value);
if (!value.Equals(_zoneHighlightColor))
{
_zoneHighlightColor = value;
@@ -419,6 +410,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
set
{
value = ToRGBHex(value);
if (!value.Equals(_zoneBorderColor, StringComparison.OrdinalIgnoreCase))
{
_zoneBorderColor = value;
@@ -437,6 +429,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
set
{
value = ToRGBHex(value);
if (!value.Equals(_zoneInActiveColor))
{
_zoneInActiveColor = value;
@@ -524,5 +517,19 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
SendConfigMSG(ipcMessage.ToJsonString());
}
}
private string ToRGBHex(string color)
{
try
{
int argb = int.Parse(color.Replace("#", string.Empty), System.Globalization.NumberStyles.HexNumber);
Color clr = Color.FromArgb(argb);
return "#" + clr.R.ToString("X2") + clr.G.ToString("X2") + clr.B.ToString("X2");
}
catch (Exception)
{
return "#FFFFFF";
}
}
}
}

View File

@@ -3,9 +3,9 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using Microsoft.PowerToys.Settings.UI.Lib.Helpers;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
using Microsoft.PowerToys.Settings.UI.Lib.Utilities;
using Microsoft.PowerToys.Settings.UI.Lib.ViewModels.Commands;
@@ -13,7 +13,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
public class GeneralViewModel : Observable
{
private GeneralSettings GeneralSettingsConfigs { get; set; }
private GeneralSettings GeneralSettingsConfig { get; set; }
public ButtonClickCommand CheckFoUpdatesEventHandler { get; set; }
@@ -33,32 +33,13 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
private string _settingsConfigFileFolder = string.Empty;
public GeneralViewModel(string runAsAdminText, string runAsUserText, bool isElevated, bool isAdmin, Func<string, int> updateTheme, Func<string, int> ipcMSGCallBackFunc, Func<string, int> ipcMSGRestartAsAdminMSGCallBackFunc, Func<string, int> ipcMSGCheckForUpdatesCallBackFunc, string configFileSubfolder = "")
public GeneralViewModel(ISettingsRepository<GeneralSettings> settingsRepository, string runAsAdminText, string runAsUserText, bool isElevated, bool isAdmin, Func<string, int> updateTheme, Func<string, int> ipcMSGCallBackFunc, Func<string, int> ipcMSGRestartAsAdminMSGCallBackFunc, Func<string, int> ipcMSGCheckForUpdatesCallBackFunc, string configFileSubfolder = "")
{
CheckFoUpdatesEventHandler = new ButtonClickCommand(CheckForUpdates_Click);
RestartElevatedButtonEventHandler = new ButtonClickCommand(Restart_Elevated);
try
{
GeneralSettingsConfigs = SettingsUtils.GetSettings<GeneralSettings>(string.Empty);
if (Helper.CompareVersions(GeneralSettingsConfigs.PowertoysVersion, Helper.GetProductVersion()) < 0)
{
// Update settings
GeneralSettingsConfigs.PowertoysVersion = Helper.GetProductVersion();
SettingsUtils.SaveSettings(GeneralSettingsConfigs.ToJsonString(), string.Empty);
}
}
catch (FormatException e)
{
// If there is an issue with the version number format, don't migrate settings.
Debug.WriteLine(e.Message);
}
catch
{
GeneralSettingsConfigs = new GeneralSettings();
SettingsUtils.SaveSettings(GeneralSettingsConfigs.ToJsonString(), string.Empty);
}
// To obtain the general settings configuration of PowerToys if it exists, else to create a new file and return the default configurations.
GeneralSettingsConfig = settingsRepository.SettingsConfig;
// set the callback functions value to hangle outgoing IPC message.
SendConfigMSG = ipcMSGCallBackFunc;
@@ -67,12 +48,12 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
// set the callback function value to update the UI theme.
UpdateUIThemeCallBack = updateTheme;
UpdateUIThemeCallBack(GeneralSettingsConfigs.Theme.ToLower());
UpdateUIThemeCallBack(GeneralSettingsConfig.Theme.ToLower());
// Update Settings file folder:
_settingsConfigFileFolder = configFileSubfolder;
switch (GeneralSettingsConfigs.Theme.ToLower())
switch (GeneralSettingsConfig.Theme.ToLower())
{
case "light":
_isLightThemeRadioButtonChecked = true;
@@ -85,10 +66,10 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
break;
}
_startup = GeneralSettingsConfigs.Startup;
_autoDownloadUpdates = GeneralSettingsConfigs.AutoDownloadUpdates;
_startup = GeneralSettingsConfig.Startup;
_autoDownloadUpdates = GeneralSettingsConfig.AutoDownloadUpdates;
_isElevated = isElevated;
_runElevated = GeneralSettingsConfigs.RunElevated;
_runElevated = GeneralSettingsConfig.RunElevated;
RunningAsUserDefaultText = runAsUserText;
RunningAsAdminDefaultText = runAsAdminText;
@@ -106,6 +87,8 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
private bool _isSystemThemeRadioButtonChecked = false;
private bool _autoDownloadUpdates = false;
private string _latestAvailableVersion = string.Empty;
// Gets or sets a value indicating whether packaged.
public bool Packaged
{
@@ -137,7 +120,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
if (_startup != value)
{
_startup = value;
GeneralSettingsConfigs.Startup = value;
GeneralSettingsConfig.Startup = value;
RaisePropertyChanged();
}
}
@@ -209,7 +192,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
if (_runElevated != value)
{
_runElevated = value;
GeneralSettingsConfigs.RunElevated = value;
GeneralSettingsConfig.RunElevated = value;
RaisePropertyChanged();
}
}
@@ -236,7 +219,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
if (_autoDownloadUpdates != value)
{
_autoDownloadUpdates = value;
GeneralSettingsConfigs.AutoDownloadUpdates = value;
GeneralSettingsConfig.AutoDownloadUpdates = value;
RaisePropertyChanged();
}
}
@@ -253,11 +236,11 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
if (value == true)
{
GeneralSettingsConfigs.Theme = "dark";
GeneralSettingsConfig.Theme = "dark";
_isDarkThemeRadioButtonChecked = value;
try
{
UpdateUIThemeCallBack(GeneralSettingsConfigs.Theme);
UpdateUIThemeCallBack(GeneralSettingsConfig.Theme);
}
catch
{
@@ -279,11 +262,11 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
if (value == true)
{
GeneralSettingsConfigs.Theme = "light";
GeneralSettingsConfig.Theme = "light";
_isLightThemeRadioButtonChecked = value;
try
{
UpdateUIThemeCallBack(GeneralSettingsConfigs.Theme);
UpdateUIThemeCallBack(GeneralSettingsConfig.Theme);
}
catch
{
@@ -305,11 +288,11 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
if (value == true)
{
GeneralSettingsConfigs.Theme = "system";
GeneralSettingsConfig.Theme = "system";
_isSystemThemeRadioButtonChecked = value;
try
{
UpdateUIThemeCallBack(GeneralSettingsConfigs.Theme);
UpdateUIThemeCallBack(GeneralSettingsConfig.Theme);
}
catch
{
@@ -328,12 +311,29 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
}
}
// Temp string. Appears when a user clicks "Check for updates" button and shows latest version available on the Github.
public string LatestAvailableVersion
{
get
{
return _latestAvailableVersion;
}
set
{
if (_latestAvailableVersion != value)
{
_latestAvailableVersion = value;
RaisePropertyChanged();
}
}
}
public void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
// Notify UI of property change
OnPropertyChanged(propertyName);
OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings(GeneralSettingsConfigs);
OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings(GeneralSettingsConfig);
SendConfigMSG(outsettings.ToString());
}
@@ -341,10 +341,9 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
// callback function to launch the URL to check for updates.
private void CheckForUpdates_Click()
{
GeneralSettings settings = SettingsUtils.GetSettings<GeneralSettings>(_settingsConfigFileFolder);
settings.CustomActionName = "check_for_updates";
GeneralSettingsConfig.CustomActionName = "check_for_updates";
OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings(settings);
OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings(GeneralSettingsConfig);
GeneralSettingsCustomAction customaction = new GeneralSettingsCustomAction(outsettings);
SendCheckForUpdatesConfigMSG(customaction.ToString());
@@ -352,10 +351,9 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
public void Restart_Elevated()
{
GeneralSettings settings = SettingsUtils.GetSettings<GeneralSettings>(_settingsConfigFileFolder);
settings.CustomActionName = "restart_elevation";
GeneralSettingsConfig.CustomActionName = "restart_elevation";
OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings(settings);
OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings(GeneralSettingsConfig);
GeneralSettingsCustomAction customaction = new GeneralSettingsCustomAction(outsettings);
SendRestartAsAdminConfigMSG(customaction.ToString());

View File

@@ -7,45 +7,44 @@ using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using Microsoft.PowerToys.Settings.UI.Lib.Helpers;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
public class ImageResizerViewModel : Observable
{
private GeneralSettings GeneralSettingsConfig { get; set; }
private readonly ISettingsUtils _settingsUtils;
private ImageResizerSettings Settings { get; set; }
// NOTE: Not using ImageResizerSettings.ModuleName ("Image Resizer") to be backward compatible.
private const string ModuleName = "ImageResizer";
private Func<string, int> SendConfigMSG { get; }
public ImageResizerViewModel(Func<string, int> ipcMSGCallBackFunc)
public ImageResizerViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc)
{
_settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils));
// To obtain the general settings configurations of PowerToys.
GeneralSettingsConfig = settingsRepository.SettingsConfig;
try
{
Settings = SettingsUtils.GetSettings<ImageResizerSettings>(ModuleName);
Settings = _settingsUtils.GetSettings<ImageResizerSettings>(ModuleName);
}
catch
{
Settings = new ImageResizerSettings();
SettingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
}
GeneralSettings generalSettings;
try
{
generalSettings = SettingsUtils.GetSettings<GeneralSettings>(string.Empty);
}
catch
{
generalSettings = new GeneralSettings();
SettingsUtils.SaveSettings(generalSettings.ToJsonString(), string.Empty);
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
}
// set the callback functions value to hangle outgoing IPC message.
SendConfigMSG = ipcMSGCallBackFunc;
_isEnabled = generalSettings.Enabled.ImageResizer;
_isEnabled = GeneralSettingsConfig.Enabled.ImageResizer;
_advancedSizes = Settings.Properties.ImageresizerSizes.Value;
_jpegQualityLevel = Settings.Properties.ImageresizerJpegQualityLevel.Value;
_pngInterlaceOption = Settings.Properties.ImageresizerPngInterlaceOption.Value;
@@ -83,10 +82,11 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
if (value != _isEnabled)
{
// To set the status of ImageResizer in the General PowerToys settings.
_isEnabled = value;
GeneralSettings generalSettings = SettingsUtils.GetSettings<GeneralSettings>(string.Empty);
generalSettings.Enabled.ImageResizer = value;
OutGoingGeneralSettings snd = new OutGoingGeneralSettings(generalSettings);
GeneralSettingsConfig.Enabled.ImageResizer = value;
OutGoingGeneralSettings snd = new OutGoingGeneralSettings(GeneralSettingsConfig);
SendConfigMSG(snd.ToString());
OnPropertyChanged("IsEnabled");
}
@@ -121,7 +121,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
_jpegQualityLevel = value;
Settings.Properties.ImageresizerJpegQualityLevel.Value = value;
SettingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
OnPropertyChanged("JPEGQualityLevel");
}
}
@@ -140,7 +140,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
_pngInterlaceOption = value;
Settings.Properties.ImageresizerPngInterlaceOption.Value = value;
SettingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
OnPropertyChanged("PngInterlaceOption");
}
}
@@ -159,7 +159,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
_tiffCompressOption = value;
Settings.Properties.ImageresizerTiffCompressOption.Value = value;
SettingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
OnPropertyChanged("TiffCompressOption");
}
}
@@ -178,7 +178,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
_fileName = value;
Settings.Properties.ImageresizerFileName.Value = value;
SettingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
OnPropertyChanged("FileName");
}
}
@@ -195,7 +195,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
_keepDateModified = value;
Settings.Properties.ImageresizerKeepDateModified.Value = value;
SettingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
OnPropertyChanged("KeepDateModified");
}
}
@@ -212,9 +212,9 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
if (_encoderGuidId != value)
{
_encoderGuidId = value;
SettingsUtils.SaveSettings(Settings.Properties.ImageresizerSizes.ToJsonString(), ModuleName, "sizes.json");
_settingsUtils.SaveSettings(Settings.Properties.ImageresizerSizes.ToJsonString(), ModuleName, "sizes.json");
Settings.Properties.ImageresizerFallbackEncoder.Value = GetEncoderGuid(value);
SettingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
OnPropertyChanged("Encoder");
}
}
@@ -243,9 +243,9 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
public void SavesImageSizes(ObservableCollection<ImageSize> imageSizes)
{
SettingsUtils.SaveSettings(Settings.Properties.ImageresizerSizes.ToJsonString(), ModuleName, "sizes.json");
_settingsUtils.SaveSettings(Settings.Properties.ImageresizerSizes.ToJsonString(), ModuleName, "sizes.json");
Settings.Properties.ImageresizerSizes = new ImageResizerSizes(imageSizes);
SettingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
}
public string GetEncoderGuid(int value)

View File

@@ -4,11 +4,13 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using Microsoft.PowerToys.Settings.UI.Lib.Helpers;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
using Microsoft.PowerToys.Settings.UI.Lib.Utilities;
using Microsoft.PowerToys.Settings.UI.Lib.ViewModels.Commands;
@@ -16,7 +18,11 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
public class KeyboardManagerViewModel : Observable
{
private const string PowerToyName = "Keyboard Manager";
private GeneralSettings GeneralSettingsConfig { get; set; }
private readonly ISettingsUtils _settingsUtils;
private const string PowerToyName = KeyboardManagerSettings.ModuleName;
private const string RemapKeyboardActionName = "RemapKeyboard";
private const string RemapKeyboardActionValue = "Open Remap Keyboard Window";
private const string EditShortcutActionName = "EditShortcut";
@@ -30,22 +36,25 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
private ICommand _remapKeyboardCommand;
private ICommand _editShortcutCommand;
private KeyboardManagerProfile _profile;
private GeneralSettings _generalSettings;
private Func<string, int> SendConfigMSG { get; }
private Func<List<KeysDataModel>, int> FilterRemapKeysList { get; }
public KeyboardManagerViewModel(Func<string, int> ipcMSGCallBackFunc, Func<List<KeysDataModel>, int> filterRemapKeysList)
public KeyboardManagerViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc, Func<List<KeysDataModel>, int> filterRemapKeysList)
{
GeneralSettingsConfig = settingsRepository.SettingsConfig;
// set the callback functions value to hangle outgoing IPC message.
SendConfigMSG = ipcMSGCallBackFunc;
FilterRemapKeysList = filterRemapKeysList;
if (SettingsUtils.SettingsExists(PowerToyName))
_settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils));
if (_settingsUtils.SettingsExists(PowerToyName))
{
// Todo: Be more resilient while reading and saving settings.
Settings = SettingsUtils.GetSettings<KeyboardManagerSettings>(PowerToyName);
Settings = _settingsUtils.GetSettings<KeyboardManagerSettings>(PowerToyName);
// Load profile.
if (!LoadProfile())
@@ -55,18 +64,8 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
}
else
{
Settings = new KeyboardManagerSettings(PowerToyName);
SettingsUtils.SaveSettings(Settings.ToJsonString(), PowerToyName);
}
if (SettingsUtils.SettingsExists())
{
_generalSettings = SettingsUtils.GetSettings<GeneralSettings>(string.Empty);
}
else
{
_generalSettings = new GeneralSettings();
SettingsUtils.SaveSettings(_generalSettings.ToJsonString(), string.Empty);
Settings = new KeyboardManagerSettings();
_settingsUtils.SaveSettings(Settings.ToJsonString(), PowerToyName);
}
}
@@ -74,16 +73,16 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
get
{
return _generalSettings.Enabled.KeyboardManager;
return GeneralSettingsConfig.Enabled.KeyboardManager;
}
set
{
if (_generalSettings.Enabled.KeyboardManager != value)
if (GeneralSettingsConfig.Enabled.KeyboardManager != value)
{
_generalSettings.Enabled.KeyboardManager = value;
GeneralSettingsConfig.Enabled.KeyboardManager = value;
OnPropertyChanged(nameof(Enabled));
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(_generalSettings);
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(GeneralSettingsConfig);
SendConfigMSG(outgoing.ToString());
}
@@ -173,8 +172,19 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
// update the UI element here.
try
{
_profile = SettingsUtils.GetSettings<KeyboardManagerProfile>(PowerToyName, Settings.Properties.ActiveConfiguration.Value + JsonFileType);
FilterRemapKeysList(_profile.RemapKeys.InProcessRemapKeys);
string fileName = Settings.Properties.ActiveConfiguration.Value + JsonFileType;
if (_settingsUtils.SettingsExists(PowerToyName, fileName))
{
_profile = _settingsUtils.GetSettings<KeyboardManagerProfile>(PowerToyName, fileName);
}
else
{
// The KBM process out of runner creates the default.json file if it does not exist.
success = false;
}
FilterRemapKeysList(_profile?.RemapKeys?.InProcessRemapKeys);
}
finally
{

View File

@@ -6,13 +6,17 @@ using System;
using System.Runtime.CompilerServices;
using System.Text.Json;
using Microsoft.PowerToys.Settings.UI.Lib.Helpers;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
public class PowerLauncherViewModel : Observable
{
private GeneralSettings GeneralSettingsConfig { get; set; }
private readonly ISettingsUtils _settingsUtils;
private PowerLauncherSettings settings;
private GeneralSettings generalSettings;
public delegate void SendCallback(PowerLauncherSettings settings);
@@ -20,43 +24,33 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
private Func<string, int> SendConfigMSG { get; }
public PowerLauncherViewModel(Func<string, int> ipcMSGCallBackFunc, int defaultKeyCode)
public PowerLauncherViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc, int defaultKeyCode)
{
try
_settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils));
// To obtain the general Settings configurations of PowerToys
GeneralSettingsConfig = settingsRepository.SettingsConfig;
// set the callback functions value to hangle outgoing IPC message.
SendConfigMSG = ipcMSGCallBackFunc;
callback = (PowerLauncherSettings settings) =>
{
callback = (PowerLauncherSettings settings) =>
{
// Propagate changes to Power Launcher through IPC
SendConfigMSG(
string.Format("{{ \"powertoys\": {{ \"{0}\": {1} }} }}", PowerLauncherSettings.ModuleName, JsonSerializer.Serialize(settings)));
};
if (SettingsUtils.SettingsExists(PowerLauncherSettings.ModuleName))
{
settings = SettingsUtils.GetSettings<PowerLauncherSettings>(PowerLauncherSettings.ModuleName);
}
else
{
settings = new PowerLauncherSettings();
settings.Properties.OpenPowerLauncher.Alt = true;
settings.Properties.OpenPowerLauncher.Code = defaultKeyCode;
settings.Properties.MaximumNumberOfResults = 4;
callback(settings);
}
// Propagate changes to Power Launcher through IPC
SendConfigMSG(
string.Format("{{ \"powertoys\": {{ \"{0}\": {1} }} }}", PowerLauncherSettings.ModuleName, JsonSerializer.Serialize(settings)));
};
if (SettingsUtils.SettingsExists())
{
generalSettings = SettingsUtils.GetSettings<GeneralSettings>();
}
else
{
generalSettings = new GeneralSettings();
}
// set the callback functions value to hangle outgoing IPC message.
SendConfigMSG = ipcMSGCallBackFunc;
if (_settingsUtils.SettingsExists(PowerLauncherSettings.ModuleName))
{
settings = _settingsUtils.GetSettings<PowerLauncherSettings>(PowerLauncherSettings.ModuleName);
}
catch
else
{
settings = new PowerLauncherSettings();
settings.Properties.OpenPowerLauncher.Alt = true;
settings.Properties.OpenPowerLauncher.Code = defaultKeyCode;
settings.Properties.MaximumNumberOfResults = 4;
callback(settings);
}
}
@@ -78,16 +72,16 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
get
{
return generalSettings.Enabled.PowerLauncher;
return GeneralSettingsConfig.Enabled.PowerLauncher;
}
set
{
if (generalSettings.Enabled.PowerLauncher != value)
if (GeneralSettingsConfig.Enabled.PowerLauncher != value)
{
generalSettings.Enabled.PowerLauncher = value;
GeneralSettingsConfig.Enabled.PowerLauncher = value;
OnPropertyChanged(nameof(EnablePowerLauncher));
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(generalSettings);
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(GeneralSettingsConfig);
SendConfigMSG(outgoing.ToString());
}
}

View File

@@ -5,12 +5,13 @@
using System;
using System.Runtime.CompilerServices;
using Microsoft.PowerToys.Settings.UI.Lib.Helpers;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
public class PowerPreviewViewModel : Observable
{
private const string ModuleName = "File Explorer";
private const string ModuleName = PowerPreviewSettings.ModuleName;
private PowerPreviewSettings Settings { get; set; }
@@ -18,20 +19,14 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
private string _settingsConfigFileFolder = string.Empty;
public PowerPreviewViewModel(Func<string, int> ipcMSGCallBackFunc, string configFileSubfolder = "")
public PowerPreviewViewModel(ISettingsRepository<PowerPreviewSettings> moduleSettingsRepository, Func<string, int> ipcMSGCallBackFunc, string configFileSubfolder = "")
{
// Update Settings file folder:
_settingsConfigFileFolder = configFileSubfolder;
try
{
Settings = SettingsUtils.GetSettings<PowerPreviewSettings>(GetSettingsSubPath());
}
catch
{
Settings = new PowerPreviewSettings();
SettingsUtils.SaveSettings(Settings.ToJsonString(), GetSettingsSubPath());
}
// To obtain the PowerPreview settings if it exists.
// If the file does not exist, to create a new one and return the default settings configurations.
Settings = moduleSettingsRepository.SettingsConfig;
// set the callback functions value to hangle outgoing IPC message.
SendConfigMSG = ipcMSGCallBackFunc;

View File

@@ -5,12 +5,17 @@
using System;
using System.Runtime.CompilerServices;
using Microsoft.PowerToys.Settings.UI.Lib.Helpers;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
public class PowerRenameViewModel : Observable
{
private const string ModuleName = "PowerRename";
private GeneralSettings GeneralSettingsConfig { get; set; }
private readonly ISettingsUtils _settingsUtils;
private const string ModuleName = PowerRenameSettings.ModuleName;
private string _settingsConfigFileFolder = string.Empty;
@@ -18,21 +23,24 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
private Func<string, int> SendConfigMSG { get; }
public PowerRenameViewModel(Func<string, int> ipcMSGCallBackFunc, string configFileSubfolder = "")
public PowerRenameViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc, string configFileSubfolder = "")
{
// Update Settings file folder:
_settingsConfigFileFolder = configFileSubfolder;
_settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils));
GeneralSettingsConfig = settingsRepository.SettingsConfig;
try
{
PowerRenameLocalProperties localSettings = SettingsUtils.GetSettings<PowerRenameLocalProperties>(GetSettingsSubPath(), "power-rename-settings.json");
PowerRenameLocalProperties localSettings = _settingsUtils.GetSettings<PowerRenameLocalProperties>(GetSettingsSubPath(), "power-rename-settings.json");
Settings = new PowerRenameSettings(localSettings);
}
catch
{
PowerRenameLocalProperties localSettings = new PowerRenameLocalProperties();
Settings = new PowerRenameSettings(localSettings);
SettingsUtils.SaveSettings(localSettings.ToJsonString(), GetSettingsSubPath(), "power-rename-settings.json");
_settingsUtils.SaveSettings(localSettings.ToJsonString(), GetSettingsSubPath(), "power-rename-settings.json");
}
// set the callback functions value to hangle outgoing IPC message.
@@ -43,19 +51,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
_powerRenameRestoreFlagsOnLaunch = Settings.Properties.PersistState.Value;
_powerRenameMaxDispListNumValue = Settings.Properties.MaxMRUSize.Value;
_autoComplete = Settings.Properties.MRUEnabled.Value;
GeneralSettings generalSettings;
try
{
generalSettings = SettingsUtils.GetSettings<GeneralSettings>(string.Empty);
}
catch
{
generalSettings = new GeneralSettings();
SettingsUtils.SaveSettings(generalSettings.ToJsonString(), string.Empty);
}
_powerRenameEnabled = generalSettings.Enabled.PowerRename;
_powerRenameEnabled = GeneralSettingsConfig.Enabled.PowerRename;
}
private bool _powerRenameEnabled = false;
@@ -76,9 +72,9 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
if (value != _powerRenameEnabled)
{
GeneralSettings generalSettings = SettingsUtils.GetSettings<GeneralSettings>(string.Empty);
generalSettings.Enabled.PowerRename = value;
OutGoingGeneralSettings snd = new OutGoingGeneralSettings(generalSettings);
GeneralSettingsConfig.Enabled.PowerRename = value;
OutGoingGeneralSettings snd = new OutGoingGeneralSettings(GeneralSettingsConfig);
SendConfigMSG(snd.ToString());
_powerRenameEnabled = value;

View File

@@ -5,50 +5,38 @@
using System;
using System.Runtime.CompilerServices;
using Microsoft.PowerToys.Settings.UI.Lib.Helpers;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
{
public class ShortcutGuideViewModel : Observable
{
private GeneralSettings GeneralSettingsConfig { get; set; }
private ShortcutGuideSettings Settings { get; set; }
private const string ModuleName = "Shortcut Guide";
private const string ModuleName = ShortcutGuideSettings.ModuleName;
private Func<string, int> SendConfigMSG { get; }
private string _settingsConfigFileFolder = string.Empty;
public ShortcutGuideViewModel(Func<string, int> ipcMSGCallBackFunc, string configFileSubfolder = "")
public ShortcutGuideViewModel(ISettingsRepository<GeneralSettings> settingsRepository, ISettingsRepository<ShortcutGuideSettings> moduleSettingsRepository, Func<string, int> ipcMSGCallBackFunc, string configFileSubfolder = "")
{
// Update Settings file folder:
_settingsConfigFileFolder = configFileSubfolder;
try
{
Settings = SettingsUtils.GetSettings<ShortcutGuideSettings>(GetSettingsSubPath());
}
catch
{
Settings = new ShortcutGuideSettings();
SettingsUtils.SaveSettings(Settings.ToJsonString(), GetSettingsSubPath());
}
// To obtain the general PowerToys settings.
GeneralSettingsConfig = settingsRepository.SettingsConfig;
GeneralSettings generalSettings;
try
{
generalSettings = SettingsUtils.GetSettings<GeneralSettings>(string.Empty);
}
catch
{
generalSettings = new GeneralSettings();
SettingsUtils.SaveSettings(generalSettings.ToJsonString(), string.Empty);
}
// To obtain the shortcut guide settings, if the file exists.
// If not, to create a file with the default settings and to return the default configurations.
Settings = moduleSettingsRepository.SettingsConfig;
// set the callback functions value to hangle outgoing IPC message.
SendConfigMSG = ipcMSGCallBackFunc;
_isEnabled = generalSettings.Enabled.ShortcutGuide;
_isEnabled = GeneralSettingsConfig.Enabled.ShortcutGuide;
_pressTime = Settings.Properties.PressTime.Value;
_opacity = Settings.Properties.OverlayOpacity.Value;
@@ -87,9 +75,11 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
if (value != _isEnabled)
{
_isEnabled = value;
GeneralSettings generalSettings = SettingsUtils.GetSettings<GeneralSettings>(string.Empty);
generalSettings.Enabled.ShortcutGuide = value;
OutGoingGeneralSettings snd = new OutGoingGeneralSettings(generalSettings);
// To update the status of shortcut guide in General PowerToy settings.
GeneralSettingsConfig.Enabled.ShortcutGuide = value;
OutGoingGeneralSettings snd = new OutGoingGeneralSettings(GeneralSettingsConfig);
SendConfigMSG(snd.ToString());
OnPropertyChanged("IsEnabled");
}

View File

@@ -8,7 +8,7 @@ using Microsoft.PowerLauncher.Telemetry;
using Microsoft.PowerToys.Settings.UI.Views;
using Microsoft.PowerToys.Telemetry;
using Microsoft.Toolkit.Wpf.UI.XamlHost;
using Windows.UI.Popups;
using Windows.Data.Json;
namespace Microsoft.PowerToys.Settings.UI.Runner
{
@@ -56,12 +56,31 @@ namespace Microsoft.PowerToys.Settings.UI.Runner
Program.GetTwoWayIPCManager().Send(msg);
});
// receive IPC Message
Program.IPCMessageReceivedCallback = (string msg) =>
{
if (ShellPage.ShellHandler.IPCResponseHandleList != null)
{
try
{
JsonObject json = JsonObject.Parse(msg);
foreach (Action<JsonObject> handle in ShellPage.ShellHandler.IPCResponseHandleList)
{
handle(json);
}
}
catch (Exception)
{
}
}
};
shellPage.SetElevationStatus(Program.IsElevated);
shellPage.SetIsUserAnAdmin(Program.IsUserAnAdmin);
shellPage.Refresh();
}
// If the window is open, explicity force it to be shown to solve the blank dialog issue https://github.com/microsoft/PowerToys/issues/3384
// XAML Islands: If the window is open, explicity force it to be shown to solve the blank dialog issue https://github.com/microsoft/PowerToys/issues/3384
if (isOpen)
{
Show();
@@ -71,6 +90,13 @@ namespace Microsoft.PowerToys.Settings.UI.Runner
private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
isOpen = false;
// XAML Islands: If the window is closed while minimized, exit the process. Required to avoid process not terminating issue - https://github.com/microsoft/PowerToys/issues/4430
if (WindowState == WindowState.Minimized)
{
// Run Environment.Exit on a separate task to avoid performance impact
System.Threading.Tasks.Task.Run(() => { Environment.Exit(0); });
}
}
}
}

View File

@@ -61,9 +61,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Toolkit.UI.XamlHost" Version="6.1.1" />
<PackageReference Include="Microsoft.Toolkit.Wpf.UI.Controls" Version="6.1.1" />
<PackageReference Include="Microsoft.Toolkit.Wpf.UI.XamlHost" Version="6.1.1" />
<PackageReference Include="Microsoft.Toolkit.UI.XamlHost" Version="6.1.2" />
<PackageReference Include="Microsoft.Toolkit.Wpf.UI.Controls" Version="6.1.2" />
<PackageReference Include="Microsoft.Toolkit.Wpf.UI.XamlHost" Version="6.1.2" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
@@ -27,6 +27,8 @@ namespace Microsoft.PowerToys.Settings.UI.Runner
public static int PowerToysPID { get; set; }
public static Action<string> IPCMessageReceivedCallback { get; set; }
[STAThread]
public static void Main(string[] args)
{
@@ -63,7 +65,16 @@ namespace Microsoft.PowerToys.Settings.UI.Runner
Environment.Exit(0);
});
ipcmanager = new TwoWayPipeMessageIPCManaged(args[1], args[0], null);
ipcmanager = new TwoWayPipeMessageIPCManaged(args[1], args[0], (string message) =>
{
if (IPCMessageReceivedCallback != null && message.Length > 0)
{
Application.Current.Dispatcher.BeginInvoke(new System.Action(() =>
{
IPCMessageReceivedCallback(message);
}));
}
});
ipcmanager.Start();
app.Run();
}

View File

@@ -17,9 +17,13 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="Moq" Version="4.14.5" />
<PackageReference Include="MSTest.TestAdapter" Version="2.1.2" />
<PackageReference Include="MSTest.TestFramework" Version="2.1.2" />
<PackageReference Include="coverlet.collector" Version="1.2.0" />
<PackageReference Include="coverlet.collector" Version="1.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,38 @@
using Microsoft.PowerToys.Settings.UI.Lib.Utilities;
using Moq;
using System;
using System.Collections.Generic;
using System.Text;
namespace Microsoft.PowerToys.Settings.UI.UnitTests.Mocks
{
internal static class IIOProviderMocks
{
/// <summary>
/// This method mocks an IO provider to validate tests wich required saving to a file, and then reading the contents of that file, or verifying it exists
/// </summary>
/// <returns></returns>
internal static Mock<IIOProvider> GetMockIOProviderForSaveLoadExists()
{
string savePath = string.Empty;
string saveContent = string.Empty;
var mockIOProvider = new Mock<IIOProvider>();
mockIOProvider.Setup(x => x.WriteAllText(It.IsAny<string>(), It.IsAny<string>()))
.Callback<string, string>((path, content) =>
{
savePath = path;
saveContent = content;
});
mockIOProvider.Setup(x => x.ReadAllText(It.Is<string>(x => x.Equals(savePath, StringComparison.Ordinal))))
.Returns(() => saveContent);
mockIOProvider.Setup(x => x.FileExists(It.Is<string>(x => x.Equals(savePath, StringComparison.Ordinal))))
.Returns(true);
mockIOProvider.Setup(x => x.FileExists(It.Is<string>(x => !x.Equals(savePath, StringComparison.Ordinal))))
.Returns(false);
return mockIOProvider;
}
}
}

View File

@@ -0,0 +1,21 @@
using Microsoft.PowerToys.Settings.UI.Lib;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
using Moq;
using System;
namespace Microsoft.PowerToys.Settings.UI.UnitTests.Mocks
{
internal static class ISettingsUtilsMocks
{
//Stubs out empty values for imageresizersettings and general settings as needed by the imageresizer viewmodel
internal static Mock<ISettingsUtils> GetStubSettingsUtils<T>()
where T : ISettingsConfig, new()
{
var settingsUtils = new Mock<ISettingsUtils>();
settingsUtils.Setup(x => x.GetSettings<T>(It.IsAny<string>(), It.IsAny<string>()))
.Returns(new T());
return settingsUtils;
}
}
}

View File

@@ -4,8 +4,11 @@
using System;
using Microsoft.PowerToys.Settings.UI.Lib;
using Microsoft.PowerToys.Settings.UI.Lib.Utilities;
using Microsoft.PowerToys.Settings.UI.UnitTests.Mocks;
using Microsoft.PowerToys.Settings.UnitTest;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema;
@@ -21,6 +24,13 @@ namespace CommonLibTest
[Obsolete]
public void ToJsonString_ShouldReturnValidJSONOfModel_WhenSuccessful()
{
//Mock Disk access
string saveContent = string.Empty;
string savePath = string.Empty;
var mockIOProvider = IIOProviderMocks.GetMockIOProviderForSaveLoadExists();
var settingsUtils = new SettingsUtils(mockIOProvider.Object);
// Arrange
string file_name = "test\\BasePTModuleSettingsTest";
string expectedSchemaText = @"
@@ -39,11 +49,11 @@ namespace CommonLibTest
}";
string testSettingsConfigs = new BasePTSettingsTest().ToJsonString();
SettingsUtils.SaveSettings(testSettingsConfigs, file_name);
settingsUtils.SaveSettings(testSettingsConfigs, file_name);
JsonSchema expectedSchema = JsonSchema.Parse(expectedSchemaText);
// Act
JObject actualSchema = JObject.Parse(SettingsUtils.GetSettings<BasePTSettingsTest>(file_name).ToJsonString());
JObject actualSchema = JObject.Parse(settingsUtils.GetSettings<BasePTSettingsTest>(file_name).ToJsonString());
bool valid = actualSchema.IsValid(expectedSchema);
// Assert

View File

@@ -3,15 +3,26 @@
// See the LICENSE file in the project root for more information.
using Microsoft.PowerToys.Settings.UI.Lib;
using Microsoft.PowerToys.Settings.UI.Lib.Interface;
namespace Microsoft.PowerToys.Settings.UnitTest
{
public class BasePTSettingsTest : BasePTModuleSettings
public class BasePTSettingsTest : BasePTModuleSettings, ISettingsConfig
{
public BasePTSettingsTest()
{
Name = string.Empty;
Version = string.Empty;
}
public string GetModuleName()
{
return Name;
}
public bool UpgradeSettingsConfiguration()
{
return false;
}
}
}

View File

@@ -0,0 +1,68 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.PowerToys.Settings.UI.Lib;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.PowerToys.Settings.UI.UnitTests.Mocks;
namespace CommonLibTest
{
[TestClass]
public class SettingsRepositoryTest
{
private Task<SettingsRepository<GeneralSettings>> GetSettingsRepository(ISettingsUtils settingsUtils)
{
return Task.Run(() =>
{
return SettingsRepository<GeneralSettings>.GetInstance(settingsUtils);
});
}
[TestMethod]
public void SettingsRepositoryInstanceWhenCalledMustReturnSameObject()
{
// The singleton class Settings Repository must always have a single instance
var mockSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<GeneralSettings>();
// Arrange and Act
SettingsRepository<GeneralSettings> firstInstance = SettingsRepository<GeneralSettings>.GetInstance(mockSettingsUtils.Object);
SettingsRepository<GeneralSettings> secondInstance = SettingsRepository<GeneralSettings>.GetInstance(mockSettingsUtils.Object);
// Assert
Assert.IsTrue(object.ReferenceEquals(firstInstance, secondInstance));
}
[TestMethod]
public void SettingsRepositoryInstanceMustBeTheSameAcrossThreads()
{
// Multiple tasks try to access and initialize the settings repository class, however they must all access the same settings Repository object.
// Arrange
var mockSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<GeneralSettings>();
List<Task<SettingsRepository<GeneralSettings>>> settingsRepoTasks = new List<Task<SettingsRepository<GeneralSettings>>>();
int numberOfTasks = 100;
for(int i = 0; i < numberOfTasks; i++)
{
settingsRepoTasks.Add(GetSettingsRepository(mockSettingsUtils.Object));
}
// Act
Task.WaitAll(settingsRepoTasks.ToArray());
// Assert
for(int i=0; i< numberOfTasks-1; i++)
{
Assert.IsTrue(object.ReferenceEquals(settingsRepoTasks[i].Result, settingsRepoTasks[i + 1].Result));
}
}
}
}

View File

@@ -7,45 +7,34 @@ using System.IO;
using System.Linq;
using System.Text.Json;
using Microsoft.PowerToys.Settings.UI.Lib;
using Microsoft.PowerToys.Settings.UI.Lib.Utilities;
using Microsoft.PowerToys.Settings.UI.UnitTests.Mocks;
using Microsoft.PowerToys.Settings.UnitTest;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace CommonLibTest
{
[TestClass]
public class SettingsUtilsTests
{
public SettingsUtilsTests()
{
string file_name = "\\test";
if (SettingsUtils.SettingsFolderExists(file_name))
{
DeleteFolder(file_name);
}
}
[TestCleanup]
public void Cleanup()
{
string file_name = "\\test";
if (SettingsUtils.SettingsFolderExists(file_name))
{
DeleteFolder(file_name);
}
}
[TestMethod]
public void SaveSettings_SaveSettingsToFile_WhenFilePathExists()
{
// Arrange
var mockIOProvider = IIOProviderMocks.GetMockIOProviderForSaveLoadExists();
var settingsUtils = new SettingsUtils(mockIOProvider.Object);
string file_name = "\\test";
string file_contents_correct_json_content = "{\"name\":\"powertoy module name\",\"version\":\"powertoy version\"}";
BasePTSettingsTest expected_json = JsonSerializer.Deserialize<BasePTSettingsTest>(file_contents_correct_json_content);
// Act
SettingsUtils.SaveSettings(file_contents_correct_json_content, file_name);
BasePTSettingsTest actual_json = SettingsUtils.GetSettings<BasePTSettingsTest>(file_name);
settingsUtils.SaveSettings(file_contents_correct_json_content, file_name);
BasePTSettingsTest actual_json = settingsUtils.GetSettings<BasePTSettingsTest>(file_name);
// Assert
Assert.AreEqual(expected_json.ToJsonString(), actual_json.ToJsonString());
@@ -55,19 +44,15 @@ namespace CommonLibTest
public void SaveSettings_ShouldCreateFile_WhenFilePathIsNotFound()
{
// Arrange
var mockIOProvider = IIOProviderMocks.GetMockIOProviderForSaveLoadExists();
var settingsUtils = new SettingsUtils(mockIOProvider.Object);
string file_name = "test\\Test Folder";
string file_contents_correct_json_content = "{\"name\":\"powertoy module name\",\"version\":\"powertoy version\"}";
BasePTSettingsTest expected_json = JsonSerializer.Deserialize<BasePTSettingsTest>(file_contents_correct_json_content);
// Act
if (SettingsUtils.SettingsFolderExists(file_name))
{
DeleteFolder(file_name);
}
SettingsUtils.SaveSettings(file_contents_correct_json_content, file_name);
BasePTSettingsTest actual_json = SettingsUtils.GetSettings<BasePTSettingsTest>(file_name);
settingsUtils.SaveSettings(file_contents_correct_json_content, file_name);
BasePTSettingsTest actual_json = settingsUtils.GetSettings<BasePTSettingsTest>(file_name);
// Assert
Assert.AreEqual(expected_json.ToJsonString(), actual_json.ToJsonString());
@@ -77,39 +62,23 @@ namespace CommonLibTest
public void SettingsFolderExists_ShouldReturnFalse_WhenFilePathIsNotFound()
{
// Arrange
var mockIOProvider = IIOProviderMocks.GetMockIOProviderForSaveLoadExists();
var settingsUtils = new SettingsUtils(mockIOProvider.Object);
string file_name_random = "test\\" + RandomString();
string file_name_exists = "test\\exists";
string file_contents_correct_json_content = "{\"name\":\"powertoy module name\",\"version\":\"powertoy version\"}";
// Act
bool pathNotFound = SettingsUtils.SettingsFolderExists(file_name_random);
bool pathNotFound = settingsUtils.SettingsExists(file_name_random);
SettingsUtils.SaveSettings(file_contents_correct_json_content, file_name_exists);
bool pathFound = SettingsUtils.SettingsFolderExists(file_name_exists);
settingsUtils.SaveSettings(file_contents_correct_json_content, file_name_exists);
bool pathFound = settingsUtils.SettingsExists(file_name_exists);
// Assert
Assert.IsFalse(pathNotFound);
Assert.IsTrue(pathFound);
}
[TestMethod]
public void CreateSettingsFolder_ShouldCreateFolder_WhenSuccessful()
{
// Arrange
string file_name = "test\\" + RandomString();
// Act
SettingsUtils.CreateSettingsFolder(file_name);
// Assert
Assert.IsTrue(SettingsUtils.SettingsFolderExists(file_name));
}
public void DeleteFolder(string powertoy)
{
Directory.Delete(Path.Combine(SettingsUtils.LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"), true);
}
public static string RandomString()
{
Random random = new Random();

View File

@@ -2,10 +2,6 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.IO;
using System.Text.Json;
using Microsoft.PowerToys.Settings.UI.Lib;
using Microsoft.PowerToys.Settings.UI.Lib.ViewModels;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace ViewModelTests
@@ -13,51 +9,6 @@ namespace ViewModelTests
[TestClass]
public class ColorPicker
{
private const string ModuleName = "ColorPicker";
[TestInitialize]
public void Setup()
{
var generalSettings = new GeneralSettings();
var colorPickerSettings = new ColorPickerSettings();
SettingsUtils.SaveSettings(generalSettings.ToJsonString());
SettingsUtils.SaveSettings(colorPickerSettings.ToJsonString(), colorPickerSettings.Name, ModuleName + ".json");
}
[TestCleanup]
public void CleanUp()
{
string generalSettings_file_name = string.Empty;
if (SettingsUtils.SettingsFolderExists(generalSettings_file_name))
{
DeleteFolder(generalSettings_file_name);
}
if (SettingsUtils.SettingsFolderExists(ModuleName))
{
DeleteFolder(ModuleName);
}
}
[TestMethod]
public void ColorPickerIsEnabledByDefault()
{
var viewModel = new ColorPickerViewModel(ColorPickerIsEnabledByDefault_IPC);
Assert.IsTrue(viewModel.IsEnabled);
}
public int ColorPickerIsEnabledByDefault_IPC(string msg)
{
OutGoingGeneralSettings snd = JsonSerializer.Deserialize<OutGoingGeneralSettings>(msg);
Assert.IsTrue(snd.GeneralSettings.Enabled.ColorPicker);
return 0;
}
private static void DeleteFolder(string powertoy)
{
Directory.Delete(Path.Combine(SettingsUtils.LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"), true);
}
}
}

View File

@@ -9,7 +9,9 @@ using System.Text.Json;
using CommonLibTest;
using Microsoft.PowerToys.Settings.UI.Lib;
using Microsoft.PowerToys.Settings.UI.Lib.ViewModels;
using Microsoft.PowerToys.Settings.UI.UnitTests.Mocks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace ViewModelTests
{
@@ -18,37 +20,15 @@ namespace ViewModelTests
{
public const string FancyZonesTestFolderName = "Test\\FancyZones";
private Mock<ISettingsUtils> mockGeneralSettingsUtils;
private Mock<ISettingsUtils> mockFancyZonesSettingsUtils;
[TestInitialize]
public void Setup()
public void SetUp_StubSettingUtils()
{
// initialize creation of test settings file.
GeneralSettings generalSettings = new GeneralSettings();
FZConfigProperties fZConfigProperties = new FZConfigProperties();
SettingsUtils.SaveSettings(generalSettings.ToJsonString());
SettingsUtils.SaveSettings(fZConfigProperties.ToJsonString(), FancyZonesTestFolderName);
}
[TestCleanup]
public void CleanUp()
{
// delete general settings folder created.
string generalSettings_file_name = string.Empty;
if (SettingsUtils.SettingsFolderExists(string.Empty))
{
DeleteFolder(string.Empty);
}
// delete fancy zones folder created.
if (SettingsUtils.SettingsFolderExists(FancyZonesTestFolderName))
{
DeleteFolder(FancyZonesTestFolderName);
}
}
public void DeleteFolder(string powertoy)
{
Directory.Delete(Path.Combine(SettingsUtils.LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"), true);
mockGeneralSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<GeneralSettings>();
mockFancyZonesSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<FancyZonesSettings>();
}
[TestMethod]
@@ -62,7 +42,7 @@ namespace ViewModelTests
};
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel(SendMockIPCConfigMSG, FancyZonesTestFolderName);
FancyZonesViewModel viewModel = new FancyZonesViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), SendMockIPCConfigMSG, FancyZonesTestFolderName);
Assert.IsTrue(viewModel.IsEnabled); // check if the module is enabled.
// act
@@ -81,7 +61,7 @@ namespace ViewModelTests
};
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel(SendMockIPCConfigMSG, FancyZonesTestFolderName);
FancyZonesViewModel viewModel = new FancyZonesViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), SendMockIPCConfigMSG, FancyZonesTestFolderName);
Assert.IsTrue(viewModel.ShiftDrag); // check if value was initialized to false.
// act
@@ -100,7 +80,7 @@ namespace ViewModelTests
};
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel(SendMockIPCConfigMSG, FancyZonesTestFolderName);
FancyZonesViewModel viewModel = new FancyZonesViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), SendMockIPCConfigMSG, FancyZonesTestFolderName);
Assert.IsFalse(viewModel.OverrideSnapHotkeys); // check if value was initialized to false.
// act
@@ -119,7 +99,7 @@ namespace ViewModelTests
};
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel(SendMockIPCConfigMSG, FancyZonesTestFolderName);
FancyZonesViewModel viewModel = new FancyZonesViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), SendMockIPCConfigMSG, FancyZonesTestFolderName);
Assert.IsFalse(viewModel.MoveWindowsBasedOnPosition); // check if value was initialized to false.
// act
@@ -138,7 +118,7 @@ namespace ViewModelTests
};
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel(SendMockIPCConfigMSG, FancyZonesTestFolderName);
FancyZonesViewModel viewModel = new FancyZonesViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), SendMockIPCConfigMSG, FancyZonesTestFolderName);
Assert.IsFalse(viewModel.MakeDraggedWindowsTransparent); // check if value was initialized to false.
// act
@@ -157,7 +137,7 @@ namespace ViewModelTests
};
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel(SendMockIPCConfigMSG, FancyZonesTestFolderName);
FancyZonesViewModel viewModel = new FancyZonesViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), SendMockIPCConfigMSG, FancyZonesTestFolderName);
Assert.IsFalse(viewModel.MouseSwitch); // check if value was initialized to false.
// act
@@ -176,7 +156,7 @@ namespace ViewModelTests
};
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel(SendMockIPCConfigMSG, FancyZonesTestFolderName);
FancyZonesViewModel viewModel = new FancyZonesViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), SendMockIPCConfigMSG, FancyZonesTestFolderName);
Assert.IsFalse(viewModel.DisplayChangeMoveWindows); // check if value was initialized to false.
// act
@@ -195,7 +175,7 @@ namespace ViewModelTests
};
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel(SendMockIPCConfigMSG, FancyZonesTestFolderName);
FancyZonesViewModel viewModel = new FancyZonesViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), SendMockIPCConfigMSG, FancyZonesTestFolderName);
Assert.IsFalse(viewModel.ZoneSetChangeMoveWindows); // check if value was initialized to false.
// act
@@ -214,7 +194,7 @@ namespace ViewModelTests
};
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel(SendMockIPCConfigMSG, FancyZonesTestFolderName);
FancyZonesViewModel viewModel = new FancyZonesViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), SendMockIPCConfigMSG, FancyZonesTestFolderName);
Assert.IsFalse(viewModel.AppLastZoneMoveWindows); // check if value was initialized to false.
// act
@@ -232,7 +212,7 @@ namespace ViewModelTests
};
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel(SendMockIPCConfigMSG, FancyZonesTestFolderName);
FancyZonesViewModel viewModel = new FancyZonesViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), SendMockIPCConfigMSG, FancyZonesTestFolderName);
Assert.IsFalse(viewModel.OpenWindowOnActiveMonitor); // check if value was initialized to false.
// act
@@ -251,7 +231,7 @@ namespace ViewModelTests
};
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel(SendMockIPCConfigMSG, FancyZonesTestFolderName);
FancyZonesViewModel viewModel = new FancyZonesViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), SendMockIPCConfigMSG, FancyZonesTestFolderName);
Assert.IsFalse(viewModel.RestoreSize); // check if value was initialized to false.
// act
@@ -270,7 +250,7 @@ namespace ViewModelTests
};
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel(SendMockIPCConfigMSG, FancyZonesTestFolderName);
FancyZonesViewModel viewModel = new FancyZonesViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), SendMockIPCConfigMSG, FancyZonesTestFolderName);
Assert.IsTrue(viewModel.UseCursorPosEditorStartupScreen); // check if value was initialized to false.
// act
@@ -289,7 +269,7 @@ namespace ViewModelTests
};
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel(SendMockIPCConfigMSG, FancyZonesTestFolderName);
FancyZonesViewModel viewModel = new FancyZonesViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), SendMockIPCConfigMSG, FancyZonesTestFolderName);
Assert.IsFalse(viewModel.ShowOnAllMonitors); // check if value was initialized to false.
// act
@@ -308,7 +288,7 @@ namespace ViewModelTests
};
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel(SendMockIPCConfigMSG, FancyZonesTestFolderName);
FancyZonesViewModel viewModel = new FancyZonesViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), SendMockIPCConfigMSG, FancyZonesTestFolderName);
Assert.AreEqual(ConfigDefaults.DefaultFancyZonesZoneHighlightColor, viewModel.ZoneHighlightColor);
// act
@@ -327,7 +307,7 @@ namespace ViewModelTests
};
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel(SendMockIPCConfigMSG, FancyZonesTestFolderName);
FancyZonesViewModel viewModel = new FancyZonesViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), SendMockIPCConfigMSG, FancyZonesTestFolderName);
Assert.AreEqual(ConfigDefaults.DefaultFancyzonesBorderColor, viewModel.ZoneBorderColor);
// act
@@ -346,7 +326,7 @@ namespace ViewModelTests
};
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel(SendMockIPCConfigMSG, FancyZonesTestFolderName);
FancyZonesViewModel viewModel = new FancyZonesViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), SendMockIPCConfigMSG, FancyZonesTestFolderName);
Assert.AreEqual(ConfigDefaults.DefaultFancyZonesInActiveColor, viewModel.ZoneInActiveColor);
// act
@@ -365,7 +345,7 @@ namespace ViewModelTests
};
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel(SendMockIPCConfigMSG, FancyZonesTestFolderName);
FancyZonesViewModel viewModel = new FancyZonesViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), SendMockIPCConfigMSG, FancyZonesTestFolderName);
Assert.AreEqual(string.Empty, viewModel.ExcludedApps);
// act
@@ -384,7 +364,7 @@ namespace ViewModelTests
};
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel(SendMockIPCConfigMSG, FancyZonesTestFolderName);
FancyZonesViewModel viewModel = new FancyZonesViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), SendMockIPCConfigMSG, FancyZonesTestFolderName);
Assert.AreEqual(50, viewModel.HighlightOpacity);
// act

View File

@@ -8,6 +8,9 @@ using System.Text.Json;
using Microsoft.PowerToys.Settings.UI.Lib;
using Microsoft.PowerToys.Settings.UI.Lib.ViewModels;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.PowerToys.Settings.UI.UnitTests.Mocks;
using Moq;
using NuGet.Frameworks;
namespace ViewModelTests
{
@@ -16,27 +19,12 @@ namespace ViewModelTests
{
public const string generalSettings_file_name = "Test\\GenealSettings";
private Mock<ISettingsUtils> mockGeneralSettingsUtils;
[TestInitialize]
public void Setup()
public void SetUp_StubSettingUtils()
{
// initialize creation of test settings file.
GeneralSettings generalSettings = new GeneralSettings();
SettingsUtils.SaveSettings(generalSettings.ToJsonString(), generalSettings_file_name);
}
[TestCleanup]
public void CleanUp()
{
// delete folder created.
if (SettingsUtils.SettingsFolderExists(generalSettings_file_name))
{
DeleteFolder(generalSettings_file_name);
}
}
public void DeleteFolder(string powertoy)
{
Directory.Delete(Path.Combine(SettingsUtils.LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"), true);
mockGeneralSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<GeneralSettings>();
}
[TestMethod]
@@ -47,6 +35,7 @@ namespace ViewModelTests
Func<string, int> SendRestartAdminIPCMessage = msg => { return 0; };
Func<string, int> SendCheckForUpdatesIPCMessage = msg => { return 0; };
GeneralViewModel viewModel = new GeneralViewModel(
SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
"GeneralSettings_RunningAsAdminText",
"GeneralSettings_RunningAsUserText",
false,
@@ -83,6 +72,7 @@ namespace ViewModelTests
Func<string, int> SendRestartAdminIPCMessage = msg => { return 0; };
Func<string, int> SendCheckForUpdatesIPCMessage = msg => { return 0; };
GeneralViewModel viewModel = new GeneralViewModel(
SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
"GeneralSettings_RunningAsAdminText",
"GeneralSettings_RunningAsUserText",
false,
@@ -114,6 +104,7 @@ namespace ViewModelTests
// Arrange
GeneralViewModel viewModel = new GeneralViewModel(
SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
"GeneralSettings_RunningAsAdminText",
"GeneralSettings_RunningAsUserText",
false,
@@ -146,6 +137,7 @@ namespace ViewModelTests
Func<string, int> SendRestartAdminIPCMessage = msg => { return 0; };
Func<string, int> SendCheckForUpdatesIPCMessage = msg => { return 0; };
viewModel = new GeneralViewModel(
SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
"GeneralSettings_RunningAsAdminText",
"GeneralSettings_RunningAsUserText",
false,
@@ -176,6 +168,7 @@ namespace ViewModelTests
Func<string, int> SendRestartAdminIPCMessage = msg => { return 0; };
Func<string, int> SendCheckForUpdatesIPCMessage = msg => { return 0; };
GeneralViewModel viewModel = new GeneralViewModel(
SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
"GeneralSettings_RunningAsAdminText",
"GeneralSettings_RunningAsUserText",
false,
@@ -193,6 +186,24 @@ namespace ViewModelTests
viewModel.IsDarkThemeRadioButtonChecked = true;
}
[TestMethod]
public void AllModulesAreEnabledByDefault()
{
//arrange
EnabledModules modules = new EnabledModules();
//Assert
Assert.IsTrue(modules.FancyZones);
Assert.IsTrue(modules.ImageResizer);
Assert.IsTrue(modules.FileExplorerPreview);
Assert.IsTrue(modules.ShortcutGuide);
Assert.IsTrue(modules.PowerRename);
Assert.IsTrue(modules.KeyboardManager);
Assert.IsTrue(modules.PowerLauncher);
Assert.IsTrue(modules.ColorPicker);
}
public int UpdateUIThemeMethod(string themeName)
{
return 0;

View File

@@ -7,8 +7,11 @@ using System.IO;
using System.Linq;
using System.Text.Json;
using Microsoft.PowerToys.Settings.UI.Lib;
using Microsoft.PowerToys.Settings.UI.Lib.Utilities;
using Microsoft.PowerToys.Settings.UI.Lib.ViewModels;
using Microsoft.PowerToys.Settings.UI.UnitTests.Mocks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace ViewModelTests
{
@@ -17,38 +20,15 @@ namespace ViewModelTests
{
public const string Module = "ImageResizer";
private Mock<ISettingsUtils> mockGeneralSettingsUtils;
private Mock<ISettingsUtils> mockImgResizerSettingsUtils;
[TestInitialize]
public void Setup()
public void SetUp_StubSettingUtils()
{
// initialize creation of test settings file.
// Test base path:
// C:\Users\<user name>\AppData\Local\Packages\08e1807b-8b6d-4bfa-adc4-79c64aae8e78_9abkseg265h2m\LocalState\Microsoft\PowerToys\
GeneralSettings generalSettings = new GeneralSettings();
ImageResizerSettings imageResizer = new ImageResizerSettings();
SettingsUtils.SaveSettings(generalSettings.ToJsonString());
SettingsUtils.SaveSettings(imageResizer.ToJsonString(), imageResizer.Name);
}
[TestCleanup]
public void CleanUp()
{
// delete folder created.
string generalSettings_file_name = string.Empty;
if (SettingsUtils.SettingsFolderExists(generalSettings_file_name))
{
DeleteFolder(generalSettings_file_name);
}
if (SettingsUtils.SettingsFolderExists(Module))
{
DeleteFolder(Module);
}
}
public void DeleteFolder(string powertoy)
{
Directory.Delete(Path.Combine(SettingsUtils.LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"), true);
mockGeneralSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<GeneralSettings>();
mockImgResizerSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<ImageResizerSettings>();
}
[TestMethod]
@@ -63,7 +43,7 @@ namespace ViewModelTests
};
// arrange
ImageResizerViewModel viewModel = new ImageResizerViewModel(SendMockIPCConfigMSG);
ImageResizerViewModel viewModel = new ImageResizerViewModel(mockImgResizerSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG);
// act
viewModel.IsEnabled = true;
@@ -73,14 +53,16 @@ namespace ViewModelTests
public void JPEGQualityLevel_ShouldSetValueToTen_WhenSuccessful()
{
// arrange
var mockIOProvider = IIOProviderMocks.GetMockIOProviderForSaveLoadExists();
var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object);
Func<string, int> SendMockIPCConfigMSG = msg => { return 0; };
ImageResizerViewModel viewModel = new ImageResizerViewModel(SendMockIPCConfigMSG);
ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG);
// act
viewModel.JPEGQualityLevel = 10;
// Assert
viewModel = new ImageResizerViewModel(SendMockIPCConfigMSG);
viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG);
Assert.AreEqual(10, viewModel.JPEGQualityLevel);
}
@@ -88,14 +70,16 @@ namespace ViewModelTests
public void PngInterlaceOption_ShouldSetValueToTen_WhenSuccessful()
{
// arrange
var mockIOProvider = IIOProviderMocks.GetMockIOProviderForSaveLoadExists();
var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object);
Func<string, int> SendMockIPCConfigMSG = msg => { return 0; };
ImageResizerViewModel viewModel = new ImageResizerViewModel(SendMockIPCConfigMSG);
ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG);
// act
viewModel.PngInterlaceOption = 10;
// Assert
viewModel = new ImageResizerViewModel(SendMockIPCConfigMSG);
viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG);
Assert.AreEqual(10, viewModel.PngInterlaceOption);
}
@@ -103,14 +87,16 @@ namespace ViewModelTests
public void TiffCompressOption_ShouldSetValueToTen_WhenSuccessful()
{
// arrange
var mockIOProvider = IIOProviderMocks.GetMockIOProviderForSaveLoadExists();
var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object);
Func<string, int> SendMockIPCConfigMSG = msg => { return 0; };
ImageResizerViewModel viewModel = new ImageResizerViewModel(SendMockIPCConfigMSG);
ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG);
// act
viewModel.TiffCompressOption = 10;
// Assert
viewModel = new ImageResizerViewModel(SendMockIPCConfigMSG);
viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG);
Assert.AreEqual(10, viewModel.TiffCompressOption);
}
@@ -118,15 +104,17 @@ namespace ViewModelTests
public void FileName_ShouldUpdateValue_WhenSuccessful()
{
// arrange
var mockIOProvider = IIOProviderMocks.GetMockIOProviderForSaveLoadExists();
var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object);
Func<string, int> SendMockIPCConfigMSG = msg => { return 0; };
ImageResizerViewModel viewModel = new ImageResizerViewModel(SendMockIPCConfigMSG);
ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG);
string expectedValue = "%1 (%3)";
// act
viewModel.FileName = expectedValue;
// Assert
viewModel = new ImageResizerViewModel(SendMockIPCConfigMSG);
viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG);
Assert.AreEqual(expectedValue, viewModel.FileName);
}
@@ -134,29 +122,39 @@ namespace ViewModelTests
public void KeepDateModified_ShouldUpdateValue_WhenSuccessful()
{
// arrange
var settingUtils = ISettingsUtilsMocks.GetStubSettingsUtils<ImageResizerSettings>();
var expectedSettingsString = new ImageResizerSettings() { Properties = new ImageResizerProperties() { ImageresizerKeepDateModified = new BoolProperty() { Value = true } } }.ToJsonString();
settingUtils.Setup(x => x.SaveSettings(
It.Is<string>(content => content.Equals(expectedSettingsString, StringComparison.Ordinal)),
It.Is<string>(module => module.Equals(Module, StringComparison.Ordinal)),
It.IsAny<string>()))
.Verifiable();
Func<string, int> SendMockIPCConfigMSG = msg => { return 0; };
ImageResizerViewModel viewModel = new ImageResizerViewModel(SendMockIPCConfigMSG);
ImageResizerViewModel viewModel = new ImageResizerViewModel(settingUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG);
// act
viewModel.KeepDateModified = true;
// Assert
ImageResizerSettings settings = SettingsUtils.GetSettings<ImageResizerSettings>(Module);
Assert.AreEqual(true, settings.Properties.ImageresizerKeepDateModified.Value);
settingUtils.Verify();
}
[TestMethod]
public void Encoder_ShouldUpdateValue_WhenSuccessful()
{
// arrange
var mockIOProvider = IIOProviderMocks.GetMockIOProviderForSaveLoadExists();
var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object);
Func<string, int> SendMockIPCConfigMSG = msg => { return 0; };
ImageResizerViewModel viewModel = new ImageResizerViewModel(SendMockIPCConfigMSG);
ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG);
// act
viewModel.Encoder = 3;
// Assert
viewModel = new ImageResizerViewModel(SendMockIPCConfigMSG);
viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG);
Assert.AreEqual("163bcc30-e2e9-4f0b-961d-a3e9fdb788a3", viewModel.GetEncoderGuid(viewModel.Encoder));
Assert.AreEqual(3, viewModel.Encoder);
}
@@ -165,8 +163,9 @@ namespace ViewModelTests
public void AddRow_ShouldAddEmptyImageSize_WhenSuccessful()
{
// arrange
var mockSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<ImageResizerSettings>();
Func<string, int> SendMockIPCConfigMSG = msg => { return 0; };
ImageResizerViewModel viewModel = new ImageResizerViewModel(SendMockIPCConfigMSG);
ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG);
int sizeOfOriginalArray = viewModel.Sizes.Count;
// act
@@ -180,8 +179,9 @@ namespace ViewModelTests
public void DeleteImageSize_ShouldDeleteImageSize_WhenSuccessful()
{
// arrange
var mockSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<ImageResizerSettings>();
Func<string, int> SendMockIPCConfigMSG = msg => { return 0; };
ImageResizerViewModel viewModel = new ImageResizerViewModel(SendMockIPCConfigMSG);
ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG);
int sizeOfOriginalArray = viewModel.Sizes.Count;
ImageSize deleteCandidate = viewModel.Sizes.Where<ImageSize>(x => x.Id == 0).First();

View File

@@ -13,7 +13,7 @@ namespace ViewModelTests
[TestClass]
public class KeyboardManager
{
public const string Module = "Keyboard Manager";
public const string Module = KeyboardManagerSettings.ModuleName;
[TestInitialize]
public void Setup()

View File

@@ -5,6 +5,7 @@
using Microsoft.PowerToys.Settings.UI.Lib;
using Microsoft.PowerToys.Settings.UI.Lib.ViewModels;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace ViewModelTests
{
@@ -24,13 +25,11 @@ namespace ViewModelTests
private PowerLauncherViewModel viewModel;
private PowerLauncherSettings mockSettings;
private SendCallbackMock sendCallbackMock;
[TestInitialize]
public void Initialize()
{
mockSettings = new PowerLauncherSettings();
sendCallbackMock = new SendCallbackMock();
viewModel = new PowerLauncherViewModel(
mockSettings,
new PowerLauncherViewModel.SendCallback(sendCallbackMock.OnSend));

View File

@@ -7,7 +7,9 @@ using System.IO;
using System.Text.Json;
using Microsoft.PowerToys.Settings.UI.Lib;
using Microsoft.PowerToys.Settings.UI.Lib.ViewModels;
using Microsoft.PowerToys.Settings.UI.UnitTests.Mocks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace ViewModelTests
{
@@ -16,36 +18,12 @@ namespace ViewModelTests
{
public const string Module = "Test\\File Explorer";
private Mock<ISettingsUtils> mockPowerPreviewSettingsUtils;
[TestInitialize]
public void Setup()
public void SetUp_StubSettingUtils()
{
// initialize creation of test settings file.
GeneralSettings generalSettings = new GeneralSettings();
PowerPreviewSettings powerpreview = new PowerPreviewSettings();
SettingsUtils.SaveSettings(generalSettings.ToJsonString());
SettingsUtils.SaveSettings(powerpreview.ToJsonString(), powerpreview.Name);
}
[TestCleanup]
public void CleanUp()
{
// delete folder created.
string generalSettings_file_name = string.Empty;
if (SettingsUtils.SettingsFolderExists(generalSettings_file_name))
{
DeleteFolder(generalSettings_file_name);
}
if (SettingsUtils.SettingsFolderExists(Module))
{
DeleteFolder(Module);
}
}
public void DeleteFolder(string powertoy)
{
Directory.Delete(Path.Combine(SettingsUtils.LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"), true);
mockPowerPreviewSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<PowerPreviewSettings>();
}
[TestMethod]
@@ -60,7 +38,7 @@ namespace ViewModelTests
};
// arrange
PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SendMockIPCConfigMSG, Module);
PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SettingsRepository<PowerPreviewSettings>.GetInstance(mockPowerPreviewSettingsUtils.Object), SendMockIPCConfigMSG, Module);
// act
viewModel.SVGRenderIsEnabled = true;
@@ -78,7 +56,7 @@ namespace ViewModelTests
};
// arrange
PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SendMockIPCConfigMSG, Module);
PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SettingsRepository<PowerPreviewSettings>.GetInstance(mockPowerPreviewSettingsUtils.Object), SendMockIPCConfigMSG, Module);
// act
viewModel.SVGThumbnailIsEnabled = true;
@@ -96,7 +74,7 @@ namespace ViewModelTests
};
// arrange
PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SendMockIPCConfigMSG, Module);;
PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SettingsRepository<PowerPreviewSettings>.GetInstance(mockPowerPreviewSettingsUtils.Object), SendMockIPCConfigMSG, Module); ;
// act
viewModel.MDRenderIsEnabled = true;

View File

@@ -7,34 +7,27 @@ using System.IO;
using System.Text.Json;
using Microsoft.PowerToys.Settings.UI.Lib;
using Microsoft.PowerToys.Settings.UI.Lib.ViewModels;
using Microsoft.PowerToys.Settings.UI.UnitTests.Mocks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace ViewModelTests
{
[TestClass]
public class PowerRename
{
public const string ModuleName = "PowerRename";
public const string ModuleName = PowerRenameSettings.ModuleName;
public const string generalSettings_file_name = "Test\\PowerRename";
private Mock<ISettingsUtils> mockGeneralSettingsUtils;
private Mock<ISettingsUtils> mockPowerRenamePropertiesUtils;
[TestInitialize]
public void Setup()
public void SetUp_StubSettingUtils()
{
// initialize creation of test settings file.
GeneralSettings generalSettings = new GeneralSettings();
PowerRenameSettings powerRename = new PowerRenameSettings();
SettingsUtils.SaveSettings(generalSettings.ToJsonString());
SettingsUtils.SaveSettings(powerRename.ToJsonString(), generalSettings_file_name, "power-rename-settings.json");
}
[TestCleanup]
public void CleanUp()
{
// delete folder created.
if (SettingsUtils.SettingsFolderExists(generalSettings_file_name))
{
DeleteFolder(generalSettings_file_name);
}
mockGeneralSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<GeneralSettings>();
mockPowerRenamePropertiesUtils = ISettingsUtilsMocks.GetStubSettingsUtils<PowerRenameLocalProperties>();
}
[TestMethod]
@@ -49,7 +42,7 @@ namespace ViewModelTests
};
// arrange
PowerRenameViewModel viewModel = new PowerRenameViewModel(SendMockIPCConfigMSG, generalSettings_file_name);
PowerRenameViewModel viewModel = new PowerRenameViewModel(mockPowerRenamePropertiesUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG, generalSettings_file_name);
// act
viewModel.IsEnabled = true;
@@ -67,7 +60,7 @@ namespace ViewModelTests
};
// arrange
PowerRenameViewModel viewModel = new PowerRenameViewModel(SendMockIPCConfigMSG, generalSettings_file_name);
PowerRenameViewModel viewModel = new PowerRenameViewModel(mockPowerRenamePropertiesUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG, generalSettings_file_name);
// act
viewModel.MRUEnabled = true;
@@ -77,7 +70,7 @@ namespace ViewModelTests
public void WhenIsEnabledIsOffAndMRUEnabledIsOffGlobalAndMruShouldBeOff()
{
Func<string, int> SendMockIPCConfigMSG = msg => { return 0; };
PowerRenameViewModel viewModel = new PowerRenameViewModel(SendMockIPCConfigMSG, generalSettings_file_name);
PowerRenameViewModel viewModel = new PowerRenameViewModel(mockPowerRenamePropertiesUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG, generalSettings_file_name);
viewModel.IsEnabled = false;
viewModel.MRUEnabled = false;
@@ -89,7 +82,7 @@ namespace ViewModelTests
public void WhenIsEnabledIsOffAndMRUEnabledIsOnGlobalAndMruShouldBeOff()
{
Func<string, int> SendMockIPCConfigMSG = msg => { return 0; };
PowerRenameViewModel viewModel = new PowerRenameViewModel(SendMockIPCConfigMSG, generalSettings_file_name);
PowerRenameViewModel viewModel = new PowerRenameViewModel(mockPowerRenamePropertiesUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG, generalSettings_file_name);
viewModel.IsEnabled = false;
viewModel.MRUEnabled = true;
@@ -101,7 +94,7 @@ namespace ViewModelTests
public void WhenIsEnabledIsOnAndMRUEnabledIsOffGlobalAndMruShouldBeOff()
{
Func<string, int> SendMockIPCConfigMSG = msg => { return 0; };
PowerRenameViewModel viewModel = new PowerRenameViewModel(SendMockIPCConfigMSG, generalSettings_file_name);
PowerRenameViewModel viewModel = new PowerRenameViewModel(mockPowerRenamePropertiesUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG, generalSettings_file_name);
viewModel.IsEnabled = true;
viewModel.MRUEnabled = false;
@@ -113,7 +106,7 @@ namespace ViewModelTests
public void WhenIsEnabledIsOnAndMRUEnabledIsOnGlobalAndMruShouldBeOn()
{
Func<string, int> SendMockIPCConfigMSG = msg => { return 0; };
PowerRenameViewModel viewModel = new PowerRenameViewModel(SendMockIPCConfigMSG, generalSettings_file_name);
PowerRenameViewModel viewModel = new PowerRenameViewModel(mockPowerRenamePropertiesUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG, generalSettings_file_name);
viewModel.IsEnabled = true;
viewModel.MRUEnabled = true;
@@ -133,7 +126,7 @@ namespace ViewModelTests
};
// arrange
PowerRenameViewModel viewModel = new PowerRenameViewModel(SendMockIPCConfigMSG, generalSettings_file_name);
PowerRenameViewModel viewModel = new PowerRenameViewModel(mockPowerRenamePropertiesUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG, generalSettings_file_name);
// act
viewModel.EnabledOnContextMenu = true;
@@ -151,7 +144,7 @@ namespace ViewModelTests
};
// arrange
PowerRenameViewModel viewModel = new PowerRenameViewModel(SendMockIPCConfigMSG, generalSettings_file_name);
PowerRenameViewModel viewModel = new PowerRenameViewModel(mockPowerRenamePropertiesUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG, generalSettings_file_name);
// act
viewModel.EnabledOnContextMenu = true;
@@ -169,7 +162,7 @@ namespace ViewModelTests
};
// arrange
PowerRenameViewModel viewModel = new PowerRenameViewModel(SendMockIPCConfigMSG, generalSettings_file_name);
PowerRenameViewModel viewModel = new PowerRenameViewModel(mockPowerRenamePropertiesUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG, generalSettings_file_name);
// act
viewModel.RestoreFlagsOnLaunch = true;
@@ -187,15 +180,10 @@ namespace ViewModelTests
};
// arrange
PowerRenameViewModel viewModel = new PowerRenameViewModel(SendMockIPCConfigMSG, generalSettings_file_name);
PowerRenameViewModel viewModel = new PowerRenameViewModel(mockPowerRenamePropertiesUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG, generalSettings_file_name);
// act
viewModel.MaxDispListNum = 20;
}
public void DeleteFolder(string powertoy)
{
Directory.Delete(Path.Combine(SettingsUtils.LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"), true);
}
}
}

View File

@@ -7,7 +7,9 @@ using System.IO;
using System.Text.Json;
using Microsoft.PowerToys.Settings.UI.Lib;
using Microsoft.PowerToys.Settings.UI.Lib.ViewModels;
using Microsoft.PowerToys.Settings.UI.UnitTests.Mocks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace ViewModelTests
{
@@ -16,40 +18,15 @@ namespace ViewModelTests
{
public const string ShortCutGuideTestFolderName = "Test\\ShortCutGuide";
private Mock<ISettingsUtils> mockGeneralSettingsUtils;
private Mock<ISettingsUtils> mockShortcutGuideSettingsUtils;
[TestInitialize]
public void Setup()
public void SetUp_StubSettingUtils()
{
// initialize creation of test settings file.
// Test base path:
// C:\Users\<user name>\AppData\Local\Packages\08e1807b-8b6d-4bfa-adc4-79c64aae8e78_9abkseg265h2m\LocalState\Microsoft\PowerToys\
GeneralSettings generalSettings = new GeneralSettings();
ShortcutGuideSettings shortcutGuide = new ShortcutGuideSettings();
SettingsUtils.SaveSettings(generalSettings.ToJsonString());
SettingsUtils.SaveSettings(shortcutGuide.ToJsonString(), ShortCutGuideTestFolderName);
}
[TestCleanup]
public void CleanUp()
{
// delete folder created.
// delete general settings folder.
string ShortCutGuideTestFolderName = string.Empty;
if (SettingsUtils.SettingsFolderExists(string.Empty))
{
DeleteFolder(string.Empty);
}
// delete power rename folder.
if (SettingsUtils.SettingsFolderExists(ShortCutGuideTestFolderName))
{
DeleteFolder(ShortCutGuideTestFolderName);
}
}
public void DeleteFolder(string powertoy)
{
Directory.Delete(Path.Combine(SettingsUtils.LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"), true);
mockGeneralSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<GeneralSettings>();
mockShortcutGuideSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<ShortcutGuideSettings>();
}
[TestMethod]
@@ -65,7 +42,7 @@ namespace ViewModelTests
};
// Arrange
ShortcutGuideViewModel viewModel = new ShortcutGuideViewModel(SendMockIPCConfigMSG, ShortCutGuideTestFolderName);
ShortcutGuideViewModel viewModel = new ShortcutGuideViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<ShortcutGuideSettings>.GetInstance(mockShortcutGuideSettingsUtils.Object), SendMockIPCConfigMSG, ShortCutGuideTestFolderName);
// Act
viewModel.IsEnabled = true;
@@ -84,7 +61,7 @@ namespace ViewModelTests
};
// Arrange
ShortcutGuideViewModel viewModel = new ShortcutGuideViewModel(SendMockIPCConfigMSG, ShortCutGuideTestFolderName);
ShortcutGuideViewModel viewModel = new ShortcutGuideViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<ShortcutGuideSettings>.GetInstance(mockShortcutGuideSettingsUtils.Object), SendMockIPCConfigMSG, ShortCutGuideTestFolderName);
Assert.AreEqual(1, viewModel.ThemeIndex);
// Act
@@ -104,7 +81,7 @@ namespace ViewModelTests
};
// Arrange
ShortcutGuideViewModel viewModel = new ShortcutGuideViewModel(SendMockIPCConfigMSG, ShortCutGuideTestFolderName);
ShortcutGuideViewModel viewModel = new ShortcutGuideViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<ShortcutGuideSettings>.GetInstance(mockShortcutGuideSettingsUtils.Object), SendMockIPCConfigMSG, ShortCutGuideTestFolderName);
Assert.AreEqual(900, viewModel.PressTime);
// Act
@@ -126,7 +103,7 @@ namespace ViewModelTests
};
// Arrange
ShortcutGuideViewModel viewModel = new ShortcutGuideViewModel(SendMockIPCConfigMSG, ShortCutGuideTestFolderName);
ShortcutGuideViewModel viewModel = new ShortcutGuideViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<ShortcutGuideSettings>.GetInstance(mockShortcutGuideSettingsUtils.Object), SendMockIPCConfigMSG, ShortCutGuideTestFolderName);
Assert.AreEqual(90, viewModel.OverlayOpacity);
// Act

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