Merge branch 'master' into master
This commit is contained in:
commit
803522ac7a
10
.github/actions/spell-check/expect.txt
vendored
10
.github/actions/spell-check/expect.txt
vendored
|
@ -87,6 +87,7 @@ args
|
|||
argv
|
||||
Arial
|
||||
arik
|
||||
arity
|
||||
arjunbalgovind
|
||||
ARPINSTALLLOCATION
|
||||
ARPPRODUCTICON
|
||||
|
@ -123,6 +124,7 @@ Autorun
|
|||
AUTOSIZECOLUMNS
|
||||
autoupdate
|
||||
AValid
|
||||
AWAYMODE
|
||||
azurecr
|
||||
azurewebsites
|
||||
backend
|
||||
|
@ -1077,6 +1079,8 @@ localport
|
|||
localtime
|
||||
LOCATIONCHANGE
|
||||
Lockyour
|
||||
logconsole
|
||||
logfile
|
||||
LOGFONT
|
||||
LOGMSG
|
||||
logon
|
||||
|
@ -1191,6 +1195,7 @@ mimetype
|
|||
Minimizeallwindows
|
||||
MINIMIZEBOX
|
||||
miniz
|
||||
minlevel
|
||||
MINMAXINFO
|
||||
Miracast
|
||||
MJPG
|
||||
|
@ -1410,6 +1415,7 @@ otating
|
|||
OUTOFCONTEXT
|
||||
OUTOFMEMORY
|
||||
Outptr
|
||||
outputtype
|
||||
outro
|
||||
outsettings
|
||||
OVERLAPPEDWINDOW
|
||||
|
@ -1982,6 +1988,7 @@ toggleswitch
|
|||
toolbar
|
||||
Toolchain
|
||||
toolset
|
||||
toolstrip
|
||||
tooltip
|
||||
toolwindow
|
||||
TOPDOWNDIB
|
||||
|
@ -2188,6 +2195,8 @@ windowsx
|
|||
windowwalker
|
||||
winerror
|
||||
WINEVENT
|
||||
winexe
|
||||
winforms
|
||||
winfx
|
||||
winget
|
||||
Winhook
|
||||
|
@ -2275,6 +2284,7 @@ XOffset
|
|||
xpath
|
||||
XResource
|
||||
xsd
|
||||
xsi
|
||||
XSmall
|
||||
XStr
|
||||
XToolset
|
||||
|
|
|
@ -324,6 +324,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEditorLibrar
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEditorTest", "src\modules\keyboardmanager\KeyboardManagerEditorTest\KeyboardManagerEditorTest.vcxproj", "{62173D9A-6724-4C00-A1C8-FB646480A9EC}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "espresso", "espresso", "{127F38E0-40AA-4594-B955-5616BF206882}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EspressoModuleInterface", "src\modules\espresso\EspressoModuleInterface\EspressoModuleInterface.vcxproj", "{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Espresso", "src\modules\espresso\Espresso\Espresso.csproj", "{D940E07F-532C-4FF3-883F-790DA014F19A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
|
@ -660,6 +666,14 @@ Global
|
|||
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Debug|x64.Build.0 = Debug|x64
|
||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Release|x64.ActiveCfg = Release|x64
|
||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Release|x64.Build.0 = Release|x64
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x64.Build.0 = Debug|x64
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x64.ActiveCfg = Release|x64
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x64.Build.0 = Release|x64
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x64.Build.0 = Debug|x64
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x64.ActiveCfg = Release|x64
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -759,6 +773,9 @@ Global
|
|||
{8DF78B53-200E-451F-9328-01EB907193AE} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
|
||||
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
|
||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
|
||||
{127F38E0-40AA-4594-B955-5616BF206882} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A} = {127F38E0-40AA-4594-B955-5616BF206882}
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A} = {127F38E0-40AA-4594-B955-5616BF206882}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
|
BIN
doc/images/icons/Espresso.png
Normal file
BIN
doc/images/icons/Espresso.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -2,12 +2,14 @@
|
|||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
|
||||
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" >
|
||||
|
||||
<!-- Names of folders and projects -->
|
||||
<?define FancyZonesProjectName="FancyZones"?>
|
||||
<?define ImageResizerProjectName="ImageResizer"?>
|
||||
<?define KeyboardManagerProjectName="KeyboardManager"?>
|
||||
<?define PowerRenameProjectName="PowerRename"?>
|
||||
<?define ShortcutGuideProjectName="ShortcutGuide"?>
|
||||
<?define ColorPickerProjectName="ColorPicker"?>
|
||||
<?define EspressoProjectName="Espresso"?>
|
||||
|
||||
<?define RepoDir="$(var.ProjectDir)..\..\" ?>
|
||||
<?define BinX64Dir="$(var.RepoDir)x64\$(var.Configuration)\" ?>
|
||||
|
@ -212,16 +214,26 @@
|
|||
<Directory Id="ShortcutGuideInstallFolder" Name="$(var.ShortcutGuideProjectName)"/>
|
||||
<Directory Id="FileExplorerPreviewInstallFolder" Name="FileExplorerPreview" />
|
||||
<Directory Id="FancyZonesInstallFolder" Name="$(var.FancyZonesProjectName)" />
|
||||
<Directory Id="EspressoInstallFolder" Name="$(var.EspressoProjectName)" />
|
||||
|
||||
<!-- KBM -->
|
||||
<Directory Id="KeyboardManagerInstallFolder" Name="$(var.KeyboardManagerProjectName)">
|
||||
<Directory Id="KeyboardManagerEditorInstallFolder" Name="KeyboardManagerEditor" />
|
||||
<Directory Id="KeyboardManagerEngineInstallFolder" Name="KeyboardManagerEngine" />
|
||||
</Directory>
|
||||
|
||||
<!-- Color Picker -->
|
||||
<Directory Id="ColorPickerInstallFolder" Name="$(var.ColorPickerProjectName)">
|
||||
<Directory Id="ColorPickerResourcesFolder" Name="Resources"/>
|
||||
</Directory>
|
||||
|
||||
<!-- Launcher -->
|
||||
<Directory Id="LauncherInstallFolder" Name="launcher">
|
||||
<Directory Id="AssetsFolder" Name="Assets" />
|
||||
<Directory Id="LauncherImagesFolder" Name="Images" />
|
||||
<Directory Id="LauncherPropertiesFolder" Name="Properties" />
|
||||
|
||||
<!-- Plugins -->
|
||||
<Directory Id="LauncherPluginsFolder" Name="Plugins">
|
||||
<Directory Id="CalculatorPluginFolder" Name="Calculator">
|
||||
<Directory Id="CalculatorImagesFolder" Name="Images" />
|
||||
|
@ -266,9 +278,10 @@
|
|||
<Directory Id="SystemImagesFolder" Name="Images" />
|
||||
</Directory>
|
||||
</Directory>
|
||||
<Directory Id="LauncherPropertiesFolder" Name="Properties" />
|
||||
</Directory>
|
||||
</Directory>
|
||||
|
||||
<!-- Settings -->
|
||||
<Directory Id="SettingsV2InstallFolder" Name="Settings">
|
||||
<Directory Id="SettingsV2ViewsInstallFolder" Name="Views"/>
|
||||
<Directory Id="SettingsV2StylesInstallFolder" Name="Styles"/>
|
||||
|
@ -355,6 +368,7 @@
|
|||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- Shortcut guide files -->
|
||||
<DirectoryRef Id="SvgsInstallFolder" FileSource="$(var.BinX64Dir)svgs\">
|
||||
<Component Id="PowerToysSvgs" Guid="7C4D4EED-9338-423D-992C-DCE02F3E2D35" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)svgs\0.svg" />
|
||||
|
@ -372,6 +386,8 @@
|
|||
<File Source="$(var.BinX64Dir)svgs\overlay_portrait.svg" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- FancyZone -->
|
||||
<DirectoryRef Id="FancyZonesInstallFolder" FileSource="$(var.BinX64Dir)modules\">
|
||||
<Component Id="Module_FancyZones" Guid="C6B5272E-6ED4-4B80-B0E7-2FF0355D8CF4" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.FancyZonesProjectName)\fancyzones.dll" KeyPath="yes" />
|
||||
|
@ -477,6 +493,7 @@
|
|||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- Image Resizer -->
|
||||
<DirectoryRef Id="ImageResizerInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.ImageResizerProjectName)">
|
||||
<Component Id="Module_ImageResizer" Guid="96E63289-759C-4A73-A56B-EE7429932F72" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.ImageResizerProjectName)\ImageResizer.exe" />
|
||||
|
@ -506,6 +523,7 @@
|
|||
<RegistryValue Value="[ImageResizerInstallFolder]ImageResizerExt.dll" Type="string" />
|
||||
<RegistryValue Name="ThreadingModel" Value="Apartment" Type="string" />
|
||||
</RegistryKey>
|
||||
|
||||
<!-- Registry Key for the drag and drop handler -->
|
||||
<RegistryValue Root="HKCR"
|
||||
Key="Directory\ShellEx\DragDropHandlers\ImageResizer"
|
||||
|
@ -567,6 +585,7 @@
|
|||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- PowerRename -->
|
||||
<DirectoryRef Id="PowerRenameInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)">
|
||||
<Component Id="Module_PowerRename" Guid="E4401D08-27FE-4F96-BA17-0C61FD79E684" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\PowerRenameExt.dll" KeyPath="yes" />
|
||||
|
@ -582,30 +601,35 @@
|
|||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- Shortcut guide -->
|
||||
<DirectoryRef Id="ShortcutGuideInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.ShortcutGuideProjectName)\">
|
||||
<Component Id="Module_ShortcutGuide" Guid="CBD0AC09-91D3-428E-B2B3-05745ADF3473" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.ShortcutGuideProjectName)\$(var.ShortcutGuideProjectName).dll" KeyPath="yes" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- KBM -->
|
||||
<DirectoryRef Id="KeyboardManagerInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.KeyboardManagerProjectName)\">
|
||||
<Component Id="Module_KeyboardManager" Guid="9279BD82-786F-4F0B-8E49-DB484EE34C9B" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.KeyboardManagerProjectName)\KeyboardManager.dll" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- KBM Editor -->
|
||||
<DirectoryRef Id="KeyboardManagerEditorInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.KeyboardManagerProjectName)\KeyboardManagerEditor">
|
||||
<Component Id="Module_KeyboardManager_Editor" Guid="1240F1B8-17FE-4D68-B9AF-91882B0B1933" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.KeyboardManagerProjectName)\KeyboardManagerEditor\PowerToys.KeyboardManagerEditor.exe" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- KBM Engine -->
|
||||
<DirectoryRef Id="KeyboardManagerEngineInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.KeyboardManagerProjectName)\KeyboardManagerEngine">
|
||||
<Component Id="Module_KeyboardManager_Engine" Guid="14DBAA38-B98D-431F-9439-8EDE1C0670DB" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.KeyboardManagerProjectName)\KeyboardManagerEngine\PowerToys.KeyboardManagerEngine.exe" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- Color Picker -->
|
||||
<DirectoryRef Id="ColorPickerInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.ColorPickerProjectName)">
|
||||
<Component Id="Module_ColorPicker" Guid="8A52A69E-37B2-4BEA-9D73-77763066052F" Win64="yes">
|
||||
<?foreach File in ColorPicker.dll;System.IO.Abstractions.dll;ColorPickerUI.exe;ColorPickerUI.dll;ColorPickerUI.deps.json;ColorPickerUI.runtimeconfig.json;Microsoft.PowerToys.Settings.UI.Lib.dll;PowerToysInterop.dll;System.Text.Json.dll;ManagedTelemetry.dll;ManagedCommon.dll;ControlzEx.dll;Microsoft.Xaml.Behaviors.dll;ModernWpf.Controls.dll;ModernWpf.dll;System.ComponentModel.Composition.dll;Microsoft.PowerToys.Common.UI.dll;System.Runtime.CompilerServices.Unsafe.dll;System.Text.Encodings.Web.dll?>
|
||||
|
@ -614,6 +638,7 @@
|
|||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- Color Picker Resources -->
|
||||
<DirectoryRef Id="ColorPickerResourcesFolder" FileSource="$(var.BinX64Dir)modules\$(var.ColorPickerProjectName)\Resources">
|
||||
<Component Id="Module_ColorPicker_Resources" Guid="7544BD0F-1DB6-4C53-89D3-ADAD472FDCC1">
|
||||
<?foreach File in colorPicker.cur;icon.ico?>
|
||||
|
@ -621,6 +646,27 @@
|
|||
<?endforeach?>
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- Espresso -->
|
||||
<DirectoryRef Id="EspressoInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.EspressoProjectName)">
|
||||
<Component Id="Module_Espresso" Guid="F26F5780-5B38-43B2-BC21-8406ED6E2071" Win64="yes">
|
||||
<!--
|
||||
EspressoModuleInterface.exp;
|
||||
EspressoModuleInterface.lib;
|
||||
EspressoModuleInterface.pdb;
|
||||
ManagedCommon.pdb;
|
||||
ManagedTelemetry.pdb;
|
||||
Microsoft.PowerToys.Settings.UI.Lib.pdb;
|
||||
PowerToys.Espresso.pdb;
|
||||
PowerToys.Espresso.runtimeconfig.dev.json;
|
||||
PowerToysInterop.pdb;
|
||||
System.Reactive.xml;
|
||||
-->
|
||||
<?foreach File in EspressoModuleInterface.dll;ManagedCommon.dll;ManagedTelemetry.dll;Microsoft.PowerToys.Settings.UI.Lib.dll;Microsoft.Win32.Registry.dll;Microsoft.Win32.SystemEvents.dll;NLog.config;NLog.dll;PowerToys.Espresso.deps.json;PowerToys.Espresso.dll;PowerToys.Espresso.exe;PowerToys.Espresso.runtimeconfig.json;PowerToysInterop.dll;System.CommandLine.dll;System.Configuration.ConfigurationManager.dll;System.Drawing.Common.dll;System.IO.Abstractions.dll;System.Reactive.dll;System.Runtime.Caching.dll;System.Runtime.CompilerServices.Unsafe.dll;System.Security.AccessControl.dll;System.Security.Cryptography.ProtectedData.dll;System.Security.Permissions.dll;System.Security.Principal.Windows.dll;System.Text.Encodings.Web.dll;System.Text.Json.dll;System.Windows.Extensions.dll?>
|
||||
<File Id="EspressoFile_$(var.File)" Source="$(var.BinX64Dir)modules\$(var.EspressoProjectName)\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<DirectoryRef Id="FileExplorerPreviewInstallFolder" FileSource="$(var.RepoDir)\modules\FileExplorerPreview\">
|
||||
<Component Id="Module_PowerPreview" Guid="FF1700D5-1B07-4E07-9A62-4D206645EEA9" Win64="yes">
|
||||
|
@ -800,6 +846,7 @@
|
|||
<ComponentRef Id="Module_KeyboardManager_Engine" />
|
||||
<ComponentRef Id="Module_ColorPicker" />
|
||||
<ComponentRef Id="Module_ColorPicker_Resources"/>
|
||||
<ComponentRef Id ="Module_Espresso"/>
|
||||
<ComponentRef Id="SettingsV2" />
|
||||
<ComponentRef Id="SettingsV2Assets" />
|
||||
<ComponentRef Id="SettingsV2AssetsModules" />
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace PTSettingsHelper
|
|||
{
|
||||
constexpr inline const wchar_t* log_settings_filename = L"log_settings.json";
|
||||
|
||||
std::wstring get_module_save_file_location(std::wstring_view powertoy_key);
|
||||
std::wstring get_module_save_folder_location(std::wstring_view powertoy_name);
|
||||
std::wstring get_root_save_folder_location();
|
||||
|
||||
|
|
245
src/modules/espresso/Espresso/Core/APIHelper.cs
Normal file
245
src/modules/espresso/Espresso/Core/APIHelper.cs
Normal file
|
@ -0,0 +1,245 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Win32;
|
||||
using NLog;
|
||||
|
||||
namespace Espresso.Shell.Core
|
||||
{
|
||||
[Flags]
|
||||
public enum EXECUTION_STATE : uint
|
||||
{
|
||||
ES_AWAYMODE_REQUIRED = 0x00000040,
|
||||
ES_CONTINUOUS = 0x80000000,
|
||||
ES_DISPLAY_REQUIRED = 0x00000002,
|
||||
ES_SYSTEM_REQUIRED = 0x00000001,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper class that allows talking to Win32 APIs without having to rely on PInvoke in other parts
|
||||
/// of the codebase.
|
||||
/// </summary>
|
||||
public class APIHelper
|
||||
{
|
||||
private const string BuildRegistryLocation = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion";
|
||||
public const int StdOutputHandle = -11;
|
||||
public const int StdInputHandle = -10;
|
||||
public const int StdErrorHandle = -12;
|
||||
public const uint GenericWrite = 0x40000000;
|
||||
public const uint GenericRead = 0x80000000;
|
||||
|
||||
private static readonly Logger _log;
|
||||
private static CancellationTokenSource _tokenSource;
|
||||
private static CancellationToken _threadToken;
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool AllocConsole();
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern IntPtr CreateFile(
|
||||
[MarshalAs(UnmanagedType.LPTStr)] string filename,
|
||||
[MarshalAs(UnmanagedType.U4)] uint access,
|
||||
[MarshalAs(UnmanagedType.U4)] FileShare share,
|
||||
IntPtr securityAttributes,
|
||||
[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
|
||||
[MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes,
|
||||
IntPtr templateFile);
|
||||
|
||||
static APIHelper()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_tokenSource = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
public static void AllocateConsole()
|
||||
{
|
||||
AllocConsole();
|
||||
|
||||
var outputFilePointer = CreateFile("CONOUT$", GenericRead | GenericWrite, FileShare.Write, IntPtr.Zero, FileMode.OpenOrCreate, 0, IntPtr.Zero);
|
||||
|
||||
SetStdHandle(StdOutputHandle, outputFilePointer);
|
||||
Console.SetOut(new StreamWriter(Console.OpenStandardOutput(), Console.OutputEncoding) { AutoFlush = true });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the computer awake state using the native Win32 SetThreadExecutionState API. This
|
||||
/// function is just a nice-to-have wrapper that helps avoid tracking the success or failure of
|
||||
/// the call.
|
||||
/// </summary>
|
||||
/// <param name="state">Single or multiple EXECUTION_STATE entries.</param>
|
||||
/// <returns>true if successful, false if failed</returns>
|
||||
private static bool SetAwakeState(EXECUTION_STATE state)
|
||||
{
|
||||
try
|
||||
{
|
||||
var stateResult = SetThreadExecutionState(state);
|
||||
return stateResult != 0;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetIndefiniteKeepAwake(Action<bool> callback, Action failureCallback, bool keepDisplayOn = true)
|
||||
{
|
||||
_tokenSource = new CancellationTokenSource();
|
||||
_threadToken = _tokenSource.Token;
|
||||
|
||||
Task.Run(() => RunIndefiniteLoop(keepDisplayOn), _threadToken)
|
||||
.ContinueWith((result) => callback(result.Result), TaskContinuationOptions.OnlyOnRanToCompletion)
|
||||
.ContinueWith((result) => failureCallback, TaskContinuationOptions.NotOnRanToCompletion);
|
||||
}
|
||||
|
||||
public static void SetTimedKeepAwake(uint seconds, Action<bool> callback, Action failureCallback, bool keepDisplayOn = true)
|
||||
{
|
||||
_tokenSource = new CancellationTokenSource();
|
||||
_threadToken = _tokenSource.Token;
|
||||
|
||||
Task.Run(() => RunTimedLoop(seconds, keepDisplayOn), _threadToken)
|
||||
.ContinueWith((result) => callback(result.Result), TaskContinuationOptions.OnlyOnRanToCompletion)
|
||||
.ContinueWith((result) => failureCallback, TaskContinuationOptions.NotOnRanToCompletion);
|
||||
}
|
||||
|
||||
private static bool RunIndefiniteLoop(bool keepDisplayOn = true)
|
||||
{
|
||||
bool success;
|
||||
if (keepDisplayOn)
|
||||
{
|
||||
success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
_log.Info("Initiated indefinite keep awake in background thread.");
|
||||
while (true)
|
||||
{
|
||||
if (_threadToken.IsCancellationRequested)
|
||||
{
|
||||
_threadToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_log.Info("Could not successfully set up indefinite keep awake.");
|
||||
return success;
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
// Task was clearly cancelled.
|
||||
_log.Info($"Background thread termination. Message: {ex.Message}");
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool RunTimedLoop(uint seconds, bool keepDisplayOn = true)
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
// In case cancellation was already requested.
|
||||
_threadToken.ThrowIfCancellationRequested();
|
||||
try
|
||||
{
|
||||
if (keepDisplayOn)
|
||||
{
|
||||
success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
|
||||
if (success)
|
||||
{
|
||||
_log.Info("Timed keep-awake with display on.");
|
||||
var startTime = DateTime.UtcNow;
|
||||
while (DateTime.UtcNow - startTime < TimeSpan.FromSeconds(Math.Abs(seconds)))
|
||||
{
|
||||
if (_threadToken.IsCancellationRequested)
|
||||
{
|
||||
_threadToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
else
|
||||
{
|
||||
_log.Info("Could not set up timed keep-awake with display on.");
|
||||
return success;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
|
||||
if (success)
|
||||
{
|
||||
_log.Info("Timed keep-awake with display off.");
|
||||
var startTime = DateTime.UtcNow;
|
||||
while (DateTime.UtcNow - startTime < TimeSpan.FromSeconds(Math.Abs(seconds)))
|
||||
{
|
||||
if (_threadToken.IsCancellationRequested)
|
||||
{
|
||||
_threadToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
else
|
||||
{
|
||||
_log.Info("Could not set up timed keep-awake with display off.");
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
// Task was clearly cancelled.
|
||||
_log.Info($"Background thread termination. Message: {ex.Message}");
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetOperatingSystemBuild()
|
||||
{
|
||||
try
|
||||
{
|
||||
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
|
||||
RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(BuildRegistryLocation);
|
||||
#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type.
|
||||
|
||||
if (registryKey != null)
|
||||
{
|
||||
var versionString = $"{registryKey.GetValue("ProductName")} {registryKey.GetValue("DisplayVersion")} {registryKey.GetValue("BuildLabEx")}";
|
||||
return versionString;
|
||||
}
|
||||
else
|
||||
{
|
||||
_log.Debug("Registry key acquisition for OS failed.");
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Debug($"Could not get registry key for the build number. Error: {ex.Message}");
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
226
src/modules/espresso/Espresso/Core/TrayHelper.cs
Normal file
226
src/modules/espresso/Espresso/Core/TrayHelper.cs
Normal file
|
@ -0,0 +1,226 @@
|
|||
// 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.Drawing;
|
||||
using System.Text.Json;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
|
||||
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||
#pragma warning disable CS8603 // Possible null reference return.
|
||||
|
||||
namespace Espresso.Shell.Core
|
||||
{
|
||||
internal static class TrayHelper
|
||||
{
|
||||
private static NotifyIcon? trayIcon;
|
||||
|
||||
private static NotifyIcon TrayIcon { get => trayIcon; set => trayIcon = value; }
|
||||
|
||||
private static SettingsUtils? moduleSettings;
|
||||
|
||||
private static SettingsUtils ModuleSettings { get => moduleSettings; set => moduleSettings = value; }
|
||||
|
||||
static TrayHelper()
|
||||
{
|
||||
TrayIcon = new NotifyIcon();
|
||||
ModuleSettings = new SettingsUtils();
|
||||
}
|
||||
|
||||
public static void InitializeTray(string text, Icon icon, ContextMenuStrip? contextMenu = null)
|
||||
{
|
||||
System.Threading.Tasks.Task.Factory.StartNew(
|
||||
(tray) =>
|
||||
{
|
||||
((NotifyIcon?)tray).Text = text;
|
||||
((NotifyIcon?)tray).Icon = icon;
|
||||
((NotifyIcon?)tray).ContextMenuStrip = contextMenu;
|
||||
((NotifyIcon?)tray).Visible = true;
|
||||
|
||||
Application.Run();
|
||||
}, TrayIcon);
|
||||
}
|
||||
|
||||
internal static void SetTray(string text, EspressoSettings settings)
|
||||
{
|
||||
SetTray(
|
||||
text,
|
||||
settings.Properties.KeepDisplayOn,
|
||||
settings.Properties.Mode,
|
||||
IndefiniteKeepAwakeCallback(text),
|
||||
TimedKeepAwakeCallback(text),
|
||||
KeepDisplayOnCallback(text),
|
||||
ExitCallback());
|
||||
}
|
||||
|
||||
private static Action ExitCallback()
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
Environment.Exit(0);
|
||||
};
|
||||
}
|
||||
|
||||
private static Action KeepDisplayOnCallback(string moduleName)
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
// Just changing the display mode.
|
||||
var currentSettings = ModuleSettings.GetSettings<EspressoSettings>(moduleName);
|
||||
currentSettings.Properties.KeepDisplayOn = !currentSettings.Properties.KeepDisplayOn;
|
||||
|
||||
ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), moduleName);
|
||||
};
|
||||
}
|
||||
|
||||
private static Action<uint, uint> TimedKeepAwakeCallback(string moduleName)
|
||||
{
|
||||
return (hours, minutes) =>
|
||||
{
|
||||
// Set timed keep awake.
|
||||
var currentSettings = ModuleSettings.GetSettings<EspressoSettings>(moduleName);
|
||||
currentSettings.Properties.Mode = EspressoMode.TIMED;
|
||||
currentSettings.Properties.Hours = hours;
|
||||
currentSettings.Properties.Minutes = minutes;
|
||||
|
||||
ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), moduleName);
|
||||
};
|
||||
}
|
||||
|
||||
private static Action IndefiniteKeepAwakeCallback(string moduleName)
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
// Set indefinite keep awake.
|
||||
var currentSettings = ModuleSettings.GetSettings<EspressoSettings>(moduleName);
|
||||
currentSettings.Properties.Mode = EspressoMode.INDEFINITE;
|
||||
|
||||
ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), moduleName);
|
||||
};
|
||||
}
|
||||
|
||||
public static void SetTray(string text, bool keepDisplayOn, EspressoMode mode, Action indefiniteKeepAwakeCallback, Action<uint, uint> timedKeepAwakeCallback, Action keepDisplayOnCallback, Action exitCallback)
|
||||
{
|
||||
var contextMenuStrip = new ContextMenuStrip();
|
||||
|
||||
// Main toolstrip.
|
||||
var operationContextMenu = new ToolStripMenuItem
|
||||
{
|
||||
Text = "Mode",
|
||||
};
|
||||
|
||||
// Indefinite keep-awake menu item.
|
||||
var indefiniteMenuItem = new ToolStripMenuItem
|
||||
{
|
||||
Text = "Keep awake indefinitely",
|
||||
};
|
||||
|
||||
if (mode == EspressoMode.INDEFINITE)
|
||||
{
|
||||
indefiniteMenuItem.Checked = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
indefiniteMenuItem.Checked = false;
|
||||
}
|
||||
|
||||
indefiniteMenuItem.Click += (e, s) =>
|
||||
{
|
||||
// User opted to set the mode to indefinite, so we need to write new settings.
|
||||
indefiniteKeepAwakeCallback();
|
||||
};
|
||||
|
||||
var displayOnMenuItem = new ToolStripMenuItem
|
||||
{
|
||||
Text = "Keep display on",
|
||||
};
|
||||
if (keepDisplayOn)
|
||||
{
|
||||
displayOnMenuItem.Checked = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
displayOnMenuItem.Checked = false;
|
||||
}
|
||||
|
||||
displayOnMenuItem.Click += (e, s) =>
|
||||
{
|
||||
// User opted to set the display mode directly.
|
||||
keepDisplayOnCallback();
|
||||
};
|
||||
|
||||
// Timed keep-awake menu item
|
||||
var timedMenuItem = new ToolStripMenuItem
|
||||
{
|
||||
Text = "Keep awake temporarily",
|
||||
};
|
||||
if (mode == EspressoMode.TIMED)
|
||||
{
|
||||
timedMenuItem.Checked = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
timedMenuItem.Checked = false;
|
||||
}
|
||||
|
||||
var halfHourMenuItem = new ToolStripMenuItem
|
||||
{
|
||||
Text = "30 minutes",
|
||||
};
|
||||
halfHourMenuItem.Click += (e, s) =>
|
||||
{
|
||||
// User is setting the keep-awake to 30 minutes.
|
||||
timedKeepAwakeCallback(0, 30);
|
||||
};
|
||||
|
||||
var oneHourMenuItem = new ToolStripMenuItem
|
||||
{
|
||||
Text = "1 hour",
|
||||
};
|
||||
oneHourMenuItem.Click += (e, s) =>
|
||||
{
|
||||
// User is setting the keep-awake to 1 hour.
|
||||
timedKeepAwakeCallback(1, 0);
|
||||
};
|
||||
|
||||
var twoHoursMenuItem = new ToolStripMenuItem
|
||||
{
|
||||
Text = "2 hours",
|
||||
};
|
||||
twoHoursMenuItem.Click += (e, s) =>
|
||||
{
|
||||
// User is setting the keep-awake to 2 hours.
|
||||
timedKeepAwakeCallback(2, 0);
|
||||
};
|
||||
|
||||
// Exit menu item.
|
||||
var exitContextMenu = new ToolStripMenuItem
|
||||
{
|
||||
Text = "Exit",
|
||||
};
|
||||
exitContextMenu.Click += (e, s) =>
|
||||
{
|
||||
// User is setting the keep-awake to 2 hours.
|
||||
exitCallback();
|
||||
};
|
||||
|
||||
timedMenuItem.DropDownItems.Add(halfHourMenuItem);
|
||||
timedMenuItem.DropDownItems.Add(oneHourMenuItem);
|
||||
timedMenuItem.DropDownItems.Add(twoHoursMenuItem);
|
||||
|
||||
operationContextMenu.DropDownItems.Add(indefiniteMenuItem);
|
||||
operationContextMenu.DropDownItems.Add(timedMenuItem);
|
||||
operationContextMenu.DropDownItems.Add(new ToolStripSeparator());
|
||||
operationContextMenu.DropDownItems.Add(displayOnMenuItem);
|
||||
|
||||
contextMenuStrip.Items.Add(operationContextMenu);
|
||||
contextMenuStrip.Items.Add(new ToolStripSeparator());
|
||||
contextMenuStrip.Items.Add(exitContextMenu);
|
||||
|
||||
TrayIcon.Text = text;
|
||||
TrayIcon.ContextMenuStrip = contextMenuStrip;
|
||||
}
|
||||
}
|
||||
}
|
87
src/modules/espresso/Espresso/Espresso.csproj
Normal file
87
src/modules/espresso/Espresso/Espresso.csproj
Normal file
|
@ -0,0 +1,87 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\Version.props" />
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\modules\Espresso</OutputPath>
|
||||
<Nullable>enable</Nullable>
|
||||
<Platforms>x64</Platforms>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<!--Per documentation: https://docs.microsoft.com/dotnet/core/compatibility/windows-forms/5.0/automatically-infer-winexe-output-type#outputtype-set-to-winexe-for-wpf-and-winforms-apps -->
|
||||
<DisableWinExeOutputInference>true</DisableWinExeOutputInference>
|
||||
<AssemblyName>PowerToys.Espresso</AssemblyName>
|
||||
<Version>$(Version).0</Version>
|
||||
<ApplicationIcon>Images\Espresso.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Optimize>false</Optimize>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<DefineConstants>TRACE;RELEASE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Images\Espresso.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||
<PackageReference Include="NLog" Version="4.7.9" />
|
||||
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20071.2" />
|
||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||
<PackageReference Include="System.Runtime.Caching" Version="6.0.0-preview.1.21102.12" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
<ProjectReference Include="..\..\..\settings-ui\Microsoft.PowerToys.Settings.UI.Library\Microsoft.PowerToys.Settings.UI.Library.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Program.cs">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="NLog.config">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\..\codeAnalysis\GlobalSuppressions.cs">
|
||||
<Link>GlobalSuppressions.cs</Link>
|
||||
</Compile>
|
||||
<AdditionalFiles Include="..\..\..\codeAnalysis\StyleCop.json">
|
||||
<Link>StyleCop.json</Link>
|
||||
</AdditionalFiles>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="StyleCop.Analyzers">
|
||||
<Version>1.1.118</Version>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Images\Espresso.ico" />
|
||||
</ItemGroup>
|
||||
</Project>
|
BIN
src/modules/espresso/Espresso/Images/Espresso.ico
Normal file
BIN
src/modules/espresso/Espresso/Images/Espresso.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
14
src/modules/espresso/Espresso/NLog.config
Normal file
14
src/modules/espresso/Espresso/NLog.config
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<targets async="true">
|
||||
<target name="logfile" xsi:type="File" fileName="espresso.log" layout="[${longdate} ${level:uppercase=true} ${logger}] ${message}" />
|
||||
<target name="logconsole" xsi:type="Console" layout="[${longdate} ${level:uppercase=true}] ${message}" />
|
||||
</targets>
|
||||
|
||||
<rules>
|
||||
<logger name="*" minlevel="Info" writeTo="logconsole" />
|
||||
<logger name="*" minlevel="Debug" writeTo="logfile" />
|
||||
</rules>
|
||||
</nlog>
|
294
src/modules/espresso/Espresso/Program.cs
Normal file
294
src/modules/espresso/Espresso/Program.cs
Normal file
|
@ -0,0 +1,294 @@
|
|||
// 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.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reactive.Concurrency;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using Espresso.Shell.Core;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using NLog;
|
||||
|
||||
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||
#pragma warning disable CS8603 // Possible null reference return.
|
||||
|
||||
namespace Espresso.Shell
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
private static Mutex? _mutex = null;
|
||||
private const string AppName = "Espresso";
|
||||
private static FileSystemWatcher? _watcher = null;
|
||||
private static SettingsUtils? _settingsUtils = null;
|
||||
|
||||
public static Mutex LockMutex { get => _mutex; set => _mutex = value; }
|
||||
|
||||
private static Logger? _log;
|
||||
|
||||
private static int Main(string[] args)
|
||||
{
|
||||
bool instantiated;
|
||||
LockMutex = new Mutex(true, AppName, out instantiated);
|
||||
|
||||
if (!instantiated)
|
||||
{
|
||||
ForceExit(AppName + " is already running! Exiting the application.", 1);
|
||||
}
|
||||
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_settingsUtils = new SettingsUtils();
|
||||
|
||||
_log.Info("Launching Espresso...");
|
||||
_log.Info(FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion);
|
||||
_log.Debug($"OS: {Environment.OSVersion}");
|
||||
_log.Debug($"OS Build: {APIHelper.GetOperatingSystemBuild()}");
|
||||
|
||||
var configOption = new Option<bool>(
|
||||
aliases: new[] { "--use-pt-config", "-c" },
|
||||
getDefaultValue: () => false,
|
||||
description: "Specifies whether Espresso will be using the PowerToys configuration file for managing the state.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => false)
|
||||
{
|
||||
Arity = ArgumentArity.ZeroOrOne,
|
||||
},
|
||||
};
|
||||
|
||||
configOption.Required = false;
|
||||
|
||||
var displayOption = new Option<bool>(
|
||||
aliases: new[] { "--display-on", "-d" },
|
||||
getDefaultValue: () => true,
|
||||
description: "Determines whether the display should be kept awake.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => false)
|
||||
{
|
||||
Arity = ArgumentArity.ZeroOrOne,
|
||||
},
|
||||
};
|
||||
|
||||
displayOption.Required = false;
|
||||
|
||||
var timeOption = new Option<uint>(
|
||||
aliases: new[] { "--time-limit", "-t" },
|
||||
getDefaultValue: () => 0,
|
||||
description: "Determines the interval, in seconds, during which the computer is kept awake.")
|
||||
{
|
||||
Argument = new Argument<uint>(() => 0)
|
||||
{
|
||||
Arity = ArgumentArity.ExactlyOne,
|
||||
},
|
||||
};
|
||||
|
||||
timeOption.Required = false;
|
||||
|
||||
var pidOption = new Option<int>(
|
||||
aliases: new[] { "--pid", "-p" },
|
||||
getDefaultValue: () => 0,
|
||||
description: "Bind the execution of Espresso to another process.")
|
||||
{
|
||||
Argument = new Argument<int>(() => 0)
|
||||
{
|
||||
Arity = ArgumentArity.ZeroOrOne,
|
||||
},
|
||||
};
|
||||
|
||||
pidOption.Required = false;
|
||||
|
||||
var rootCommand = new RootCommand
|
||||
{
|
||||
configOption,
|
||||
displayOption,
|
||||
timeOption,
|
||||
pidOption,
|
||||
};
|
||||
|
||||
rootCommand.Description = AppName;
|
||||
|
||||
rootCommand.Handler = CommandHandler.Create<bool, bool, uint, int>(HandleCommandLineArguments);
|
||||
|
||||
return rootCommand.InvokeAsync(args).Result;
|
||||
}
|
||||
|
||||
private static void ForceExit(string message, int exitCode)
|
||||
{
|
||||
_log.Debug(message);
|
||||
_log.Info(message);
|
||||
Console.ReadKey();
|
||||
Environment.Exit(exitCode);
|
||||
}
|
||||
|
||||
private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, uint timeLimit, int pid)
|
||||
{
|
||||
if (pid == 0)
|
||||
{
|
||||
APIHelper.AllocateConsole();
|
||||
}
|
||||
|
||||
_log.Info($"The value for --use-pt-config is: {usePtConfig}");
|
||||
_log.Info($"The value for --display-on is: {displayOn}");
|
||||
_log.Info($"The value for --time-limit is: {timeLimit}");
|
||||
_log.Info($"The value for --pid is: {pid}");
|
||||
|
||||
if (usePtConfig)
|
||||
{
|
||||
#pragma warning disable CS8604 // Possible null reference argument.
|
||||
TrayHelper.InitializeTray(AppName, new Icon(Application.GetResourceStream(new Uri("/Images/Espresso.ico", UriKind.Relative)).Stream));
|
||||
#pragma warning restore CS8604 // Possible null reference argument.
|
||||
|
||||
// Configuration file is used, therefore we disregard any other command-line parameter
|
||||
// and instead watch for changes in the file.
|
||||
try
|
||||
{
|
||||
var settingsPath = _settingsUtils.GetSettingsFilePath(AppName);
|
||||
_log.Info($"Reading configuration file: {settingsPath}");
|
||||
|
||||
_watcher = new FileSystemWatcher
|
||||
{
|
||||
Path = Path.GetDirectoryName(settingsPath),
|
||||
EnableRaisingEvents = true,
|
||||
NotifyFilter = NotifyFilters.LastWrite,
|
||||
Filter = Path.GetFileName(settingsPath),
|
||||
};
|
||||
|
||||
Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
|
||||
h => _watcher.Changed += h,
|
||||
h => _watcher.Changed -= h)
|
||||
.SubscribeOn(TaskPoolScheduler.Default)
|
||||
.Select(e => e.EventArgs)
|
||||
.Throttle(TimeSpan.FromMilliseconds(25))
|
||||
.Subscribe(HandleEspressoConfigChange);
|
||||
|
||||
// Initially the file might not be updated, so we need to start processing
|
||||
// settings right away.
|
||||
ProcessSettings();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorString = $"There was a problem with the configuration file. Make sure it exists.\n{ex.Message}";
|
||||
_log.Info(errorString);
|
||||
_log.Debug(errorString);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var mode = timeLimit <= 0 ? EspressoMode.INDEFINITE : EspressoMode.TIMED;
|
||||
|
||||
if (mode == EspressoMode.INDEFINITE)
|
||||
{
|
||||
SetupIndefiniteKeepAwake(displayOn);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupTimedKeepAwake(timeLimit, displayOn);
|
||||
}
|
||||
}
|
||||
|
||||
var exitSignal = new ManualResetEvent(false);
|
||||
if (pid != 0)
|
||||
{
|
||||
RunnerHelper.WaitForPowerToysRunner(pid, () =>
|
||||
{
|
||||
exitSignal.Set();
|
||||
Environment.Exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
exitSignal.WaitOne();
|
||||
}
|
||||
|
||||
private static void SetupIndefiniteKeepAwake(bool displayOn)
|
||||
{
|
||||
// Indefinite keep awake.
|
||||
APIHelper.SetIndefiniteKeepAwake(LogCompletedKeepAwakeThread, LogUnexpectedOrCancelledKeepAwakeThreadCompletion, displayOn);
|
||||
}
|
||||
|
||||
private static void HandleEspressoConfigChange(FileSystemEventArgs fileEvent)
|
||||
{
|
||||
_log.Info("Detected a settings file change. Updating configuration...");
|
||||
_log.Info("Resetting keep-awake to normal state due to settings change.");
|
||||
ProcessSettings();
|
||||
}
|
||||
|
||||
private static void ProcessSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
EspressoSettings settings = _settingsUtils.GetSettings<EspressoSettings>(AppName);
|
||||
|
||||
if (settings != null)
|
||||
{
|
||||
switch (settings.Properties.Mode)
|
||||
{
|
||||
case EspressoMode.INDEFINITE:
|
||||
{
|
||||
// Indefinite keep awake.
|
||||
SetupIndefiniteKeepAwake(settings.Properties.KeepDisplayOn);
|
||||
break;
|
||||
}
|
||||
|
||||
case EspressoMode.TIMED:
|
||||
{
|
||||
// Timed keep-awake.
|
||||
uint computedTime = (settings.Properties.Hours * 60 * 60) + (settings.Properties.Minutes * 60);
|
||||
SetupTimedKeepAwake(computedTime, settings.Properties.KeepDisplayOn);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
var errorMessage = "Unknown mode of operation. Check config file.";
|
||||
_log.Info(errorMessage);
|
||||
_log.Debug(errorMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TrayHelper.SetTray(AppName, settings);
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorMessage = "Settings are null.";
|
||||
_log.Info(errorMessage);
|
||||
_log.Debug(errorMessage);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorMessage = $"There was a problem reading the configuration file. Error: {ex.Message}";
|
||||
_log.Info(errorMessage);
|
||||
_log.Debug(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetupTimedKeepAwake(uint time, bool displayOn)
|
||||
{
|
||||
_log.Info($"Timed keep-awake. Expected runtime: {time} seconds with display on setting set to {displayOn}.");
|
||||
|
||||
APIHelper.SetTimedKeepAwake(time, LogCompletedKeepAwakeThread, LogUnexpectedOrCancelledKeepAwakeThreadCompletion, displayOn);
|
||||
}
|
||||
|
||||
private static void LogUnexpectedOrCancelledKeepAwakeThreadCompletion()
|
||||
{
|
||||
var errorMessage = "The keep-awake thread was terminated early.";
|
||||
_log.Info(errorMessage);
|
||||
_log.Debug(errorMessage);
|
||||
}
|
||||
|
||||
private static void LogCompletedKeepAwakeThread(bool result)
|
||||
{
|
||||
_log.Info($"Exited keep-awake thread successfully: {result}");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#include <string>
|
||||
|
||||
namespace EspressoConstants
|
||||
{
|
||||
// Name of the powertoy module.
|
||||
inline const std::wstring ModuleKey = L"Espresso";
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United States) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// String Table
|
||||
//
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_ESPRESSO_NAME "Espresso"
|
||||
END
|
||||
|
||||
#endif // English (United States) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{5e7360a8-d048-4ed3-8f09-0bfd64c5529a}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>Espresso</RootNamespace>
|
||||
<ProjectName>EspressoModuleInterface</ProjectName>
|
||||
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\Espresso\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="EspressoConstants.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SetttingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="EspressoModuleInterface.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="trace.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="EspressoConstants.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{e8ef1c4e-cc50-4ce5-b00d-4e3ac5c1a7db}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{fbd9cdd2-e7d5-4417-9b52-25e345ae9562}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Generated Files">
|
||||
<UniqueIdentifier>{c2a23a2b-5846-440f-b29e-eea748dba12d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{77f1702b-da7f-4ff6-90a3-19db515cf963}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="EspressoModuleInterface.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
226
src/modules/espresso/EspressoModuleInterface/dllmain.cpp
Normal file
226
src/modules/espresso/EspressoModuleInterface/dllmain.cpp
Normal file
|
@ -0,0 +1,226 @@
|
|||
#include "pch.h"
|
||||
#include <interface/powertoy_module_interface.h>
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include <common/interop/shared_constants.h>
|
||||
#include "trace.h"
|
||||
#include "resource.h"
|
||||
#include "EspressoConstants.h"
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
|
||||
#include <common/utils/elevation.h>
|
||||
#include <common/utils/process_path.h>
|
||||
#include <common/utils/resources.h>
|
||||
#include <common/utils/os-detect.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
Trace::RegisterProvider();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
Trace::UnregisterProvider();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// The PowerToy name that will be shown in the settings.
|
||||
const static wchar_t* MODULE_NAME = L"Espresso";
|
||||
// Add a description that will we shown in the module settings page.
|
||||
const static wchar_t* MODULE_DESC = L"<no description>";
|
||||
|
||||
// These are the properties shown in the Settings page.
|
||||
struct ModuleSettings
|
||||
{
|
||||
|
||||
} g_settings;
|
||||
|
||||
// Implement the PowerToy Module Interface and all the required methods.
|
||||
class Espresso : public PowertoyModuleIface
|
||||
{
|
||||
std::wstring app_name;
|
||||
//contains the non localized key of the powertoy
|
||||
std::wstring app_key;
|
||||
|
||||
private:
|
||||
// The PowerToy state.
|
||||
bool m_enabled = false;
|
||||
|
||||
HANDLE m_hProcess;
|
||||
|
||||
HANDLE send_telemetry_event;
|
||||
|
||||
// Handle to event used to invoke Espresso
|
||||
HANDLE m_hInvokeEvent;
|
||||
|
||||
// Load initial settings from the persisted values.
|
||||
void init_settings();
|
||||
|
||||
bool is_process_running()
|
||||
{
|
||||
return WaitForSingleObject(m_hProcess, 0) == WAIT_TIMEOUT;
|
||||
}
|
||||
|
||||
void launch_process()
|
||||
{
|
||||
Logger::trace(L"Launching Espresso process");
|
||||
unsigned long powertoys_pid = GetCurrentProcessId();
|
||||
|
||||
std::wstring executable_args = L"--use-pt-config --pid " + std::to_wstring(powertoys_pid);
|
||||
Logger::trace(L"Espresso launching with parameters: " + executable_args);
|
||||
|
||||
SHELLEXECUTEINFOW sei{ sizeof(sei) };
|
||||
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
|
||||
sei.lpFile = L"modules\\Espresso\\PowerToys.Espresso.exe";
|
||||
sei.nShow = SW_SHOWNORMAL;
|
||||
sei.lpParameters = executable_args.data();
|
||||
if (!ShellExecuteExW(&sei))
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
std::wstring message = L"Espresso failed to start with error = ";
|
||||
message += std::to_wstring(error);
|
||||
Logger::error(message);
|
||||
}
|
||||
|
||||
m_hProcess = sei.hProcess;
|
||||
}
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
Espresso()
|
||||
{
|
||||
app_name = GET_RESOURCE_STRING(IDS_ESPRESSO_NAME);
|
||||
app_key = EspressoConstants::ModuleKey;
|
||||
|
||||
std::filesystem::path logFilePath(PTSettingsHelper::get_module_save_folder_location(this->app_key));
|
||||
Logger::init(LogSettings::launcherLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
|
||||
Logger::info("Launcher object is constructing");
|
||||
init_settings();
|
||||
};
|
||||
|
||||
// Destroy the powertoy and free memory
|
||||
virtual void destroy() override
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
// Return the display name of the powertoy, this will be cached by the runner
|
||||
virtual const wchar_t* get_name() override
|
||||
{
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
// Return JSON with the configuration options.
|
||||
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
|
||||
{
|
||||
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||
|
||||
// Create a Settings object.
|
||||
PowerToysSettings::Settings settings(hinstance, get_name());
|
||||
settings.set_description(MODULE_DESC);
|
||||
|
||||
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||
}
|
||||
|
||||
// Return the non localized key of the powertoy, this will be cached by the runner
|
||||
virtual const wchar_t* get_key() override
|
||||
{
|
||||
return app_key.c_str();
|
||||
}
|
||||
|
||||
// Signal from the Settings editor to call a custom action.
|
||||
// This can be used to spawn more complex editors.
|
||||
virtual void call_custom_action(const wchar_t* action) override
|
||||
{
|
||||
static UINT custom_action_num_calls = 0;
|
||||
try
|
||||
{
|
||||
// Parse the action values, including name.
|
||||
PowerToysSettings::CustomActionObject action_object =
|
||||
PowerToysSettings::CustomActionObject::from_json_string(action);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
// Improper JSON.
|
||||
}
|
||||
}
|
||||
|
||||
// Called by the runner to pass the updated settings values as a serialized JSON.
|
||||
virtual void set_config(const wchar_t* config) override
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse the input JSON string.
|
||||
PowerToysSettings::PowerToyValues values =
|
||||
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
||||
|
||||
// If you don't need to do any custom processing of the settings, proceed
|
||||
// to persists the values calling:
|
||||
values.save_to_settings_file();
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
// Improper JSON.
|
||||
}
|
||||
}
|
||||
|
||||
virtual void enable()
|
||||
{
|
||||
ResetEvent(send_telemetry_event);
|
||||
ResetEvent(m_hInvokeEvent);
|
||||
launch_process();
|
||||
m_enabled = true;
|
||||
};
|
||||
|
||||
virtual void disable()
|
||||
{
|
||||
if (m_enabled)
|
||||
{
|
||||
ResetEvent(send_telemetry_event);
|
||||
ResetEvent(m_hInvokeEvent);
|
||||
TerminateProcess(m_hProcess, 1);
|
||||
}
|
||||
|
||||
m_enabled = false;
|
||||
}
|
||||
|
||||
// Returns if the powertoys is enabled
|
||||
virtual bool is_enabled() override
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
};
|
||||
|
||||
// Load the settings file.
|
||||
void Espresso::init_settings()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Load and parse the settings file for this PowerToy.
|
||||
PowerToysSettings::PowerToyValues settings =
|
||||
PowerToysSettings::PowerToyValues::load_from_settings_file(get_key());
|
||||
}
|
||||
catch (std::exception ex)
|
||||
{
|
||||
Logger::warn(L"An exception occurred while loading the settings file");
|
||||
// Error while loading from the settings file. Let default values stay as they are.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
{
|
||||
return new Espresso();
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" />
|
||||
</packages>
|
1
src/modules/espresso/EspressoModuleInterface/pch.cpp
Normal file
1
src/modules/espresso/EspressoModuleInterface/pch.cpp
Normal file
|
@ -0,0 +1 @@
|
|||
#include "pch.h"
|
7
src/modules/espresso/EspressoModuleInterface/pch.h
Normal file
7
src/modules/espresso/EspressoModuleInterface/pch.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <ProjectTelemetry.h>
|
||||
#include <shellapi.h>
|
||||
#include <Shlwapi.h>
|
16
src/modules/espresso/EspressoModuleInterface/resource.h
Normal file
16
src/modules/espresso/EspressoModuleInterface/resource.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by Espresso.rc
|
||||
//
|
||||
#define IDS_ESPRESSO_NAME 101
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
19
src/modules/espresso/EspressoModuleInterface/trace.cpp
Normal file
19
src/modules/espresso/EspressoModuleInterface/trace.cpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#include "pch.h"
|
||||
#include "trace.h"
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
g_hProvider,
|
||||
"Microsoft.PowerToys",
|
||||
// {38e8889b-9731-53f5-e901-e8a7c1753074}
|
||||
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
|
||||
TraceLoggingOptionProjectTelemetry());
|
||||
|
||||
void Trace::RegisterProvider()
|
||||
{
|
||||
TraceLoggingRegister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::UnregisterProvider()
|
||||
{
|
||||
TraceLoggingUnregister(g_hProvider);
|
||||
}
|
8
src/modules/espresso/EspressoModuleInterface/trace.h
Normal file
8
src/modules/espresso/EspressoModuleInterface/trace.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
class Trace
|
||||
{
|
||||
public:
|
||||
static void RegisterProvider();
|
||||
static void UnregisterProvider();
|
||||
};
|
|
@ -148,7 +148,7 @@ int runner(bool isProcessElevated, bool openSettings, bool openOobe)
|
|||
chdir_current_executable();
|
||||
// Load Powertoys DLLs
|
||||
|
||||
const std::array<std::wstring_view, 8> knownModules = {
|
||||
const std::array<std::wstring_view, 9> knownModules = {
|
||||
L"modules/FancyZones/fancyzones.dll",
|
||||
L"modules/FileExplorerPreview/powerpreview.dll",
|
||||
L"modules/ImageResizer/ImageResizerExt.dll",
|
||||
|
@ -157,6 +157,7 @@ int runner(bool isProcessElevated, bool openSettings, bool openOobe)
|
|||
L"modules/PowerRename/PowerRenameExt.dll",
|
||||
L"modules/ShortcutGuide/ShortcutGuide.dll",
|
||||
L"modules/ColorPicker/ColorPicker.dll",
|
||||
L"modules/Espresso/EspressoModuleInterface.dll",
|
||||
};
|
||||
|
||||
for (const auto& moduleSubdir : knownModules)
|
||||
|
|
|
@ -143,6 +143,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||
}
|
||||
}
|
||||
|
||||
private bool espresso = true;
|
||||
|
||||
[JsonPropertyName("Espresso")]
|
||||
public bool Espresso
|
||||
{
|
||||
get => espresso;
|
||||
set
|
||||
{
|
||||
if (espresso != value)
|
||||
{
|
||||
LogTelemetryEvent(value);
|
||||
espresso = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string ToJsonString()
|
||||
{
|
||||
return JsonSerializer.Serialize(this);
|
||||
|
|
|
@ -0,0 +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.Text.Json.Serialization;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class EspressoProperties
|
||||
{
|
||||
public EspressoProperties()
|
||||
{
|
||||
KeepDisplayOn = false;
|
||||
Mode = EspressoMode.INDEFINITE;
|
||||
Hours = 0;
|
||||
Minutes = 0;
|
||||
}
|
||||
|
||||
[JsonPropertyName("espresso_keep_display_on")]
|
||||
public bool KeepDisplayOn { get; set; }
|
||||
|
||||
[JsonPropertyName("espresso_mode")]
|
||||
public EspressoMode Mode { get; set; }
|
||||
|
||||
[JsonPropertyName("espresso_hours")]
|
||||
public uint Hours { get; set; }
|
||||
|
||||
[JsonPropertyName("espresso_minutes")]
|
||||
public uint Minutes { get; set; }
|
||||
}
|
||||
|
||||
public enum EspressoMode
|
||||
{
|
||||
INDEFINITE = 0,
|
||||
TIMED = 1,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// 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.Text.Json.Serialization;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class EspressoSettings : BasePTModuleSettings, ISettingsConfig
|
||||
{
|
||||
public const string ModuleName = "Espresso";
|
||||
public const string ModuleVersion = "1.0.0";
|
||||
|
||||
public EspressoSettings()
|
||||
{
|
||||
Name = ModuleName;
|
||||
Version = ModuleVersion;
|
||||
Properties = new EspressoProperties();
|
||||
}
|
||||
|
||||
[JsonPropertyName("properties")]
|
||||
public EspressoProperties Properties { get; set; }
|
||||
|
||||
public string GetModuleName()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
public bool UpgradeSettingsConfiguration()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,5 +19,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||
bool SettingsExists(string powertoy = "", string fileName = "settings.json");
|
||||
|
||||
void DeleteSettings(string powertoy = "");
|
||||
|
||||
string GetSettingsFilePath(string powertoy = "", string fileName = "settings.json");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
|
|
@ -135,5 +135,11 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the file path to the settings file, that is exposed from the local ISettingsPath instance.
|
||||
public string GetSettingsFilePath(string powertoy = "", string fileName = "settings.json")
|
||||
{
|
||||
return _settingsPath.GetSettingsPath(powertoy, fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
// 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.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class SndEspressoSettings
|
||||
{
|
||||
[JsonPropertyName("Espresso")]
|
||||
public EspressoSettings Settings { get; set; }
|
||||
|
||||
public SndEspressoSettings()
|
||||
{
|
||||
}
|
||||
|
||||
public SndEspressoSettings(EspressoSettings settings)
|
||||
{
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
public string ToJsonString()
|
||||
{
|
||||
return JsonSerializer.Serialize(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
// 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.CompilerServices;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
{
|
||||
public class EspressoViewModel : Observable
|
||||
{
|
||||
private GeneralSettings GeneralSettingsConfig { get; set; }
|
||||
|
||||
private EspressoSettings Settings { get; set; }
|
||||
|
||||
private Func<string, int> SendConfigMSG { get; }
|
||||
|
||||
public EspressoViewModel(ISettingsRepository<GeneralSettings> settingsRepository, ISettingsRepository<EspressoSettings> moduleSettingsRepository, Func<string, int> ipcMSGCallBackFunc)
|
||||
{
|
||||
// To obtain the general settings configurations of PowerToys Settings.
|
||||
if (settingsRepository == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(settingsRepository));
|
||||
}
|
||||
|
||||
GeneralSettingsConfig = settingsRepository.SettingsConfig;
|
||||
|
||||
// To obtain the settings configurations of Fancy zones.
|
||||
if (moduleSettingsRepository == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(moduleSettingsRepository));
|
||||
}
|
||||
|
||||
Settings = moduleSettingsRepository.SettingsConfig;
|
||||
|
||||
_isEnabled = GeneralSettingsConfig.Enabled.Espresso;
|
||||
_keepDisplayOn = Settings.Properties.KeepDisplayOn;
|
||||
_mode = Settings.Properties.Mode;
|
||||
_hours = Settings.Properties.Hours;
|
||||
_minutes = Settings.Properties.Minutes;
|
||||
|
||||
// set the callback functions value to hangle outgoing IPC message.
|
||||
SendConfigMSG = ipcMSGCallBackFunc;
|
||||
}
|
||||
|
||||
public bool IsEnabled
|
||||
{
|
||||
get => _isEnabled;
|
||||
set
|
||||
{
|
||||
if (_isEnabled != value)
|
||||
{
|
||||
_isEnabled = value;
|
||||
|
||||
GeneralSettingsConfig.Enabled.Espresso = value;
|
||||
|
||||
var outgoing = new OutGoingGeneralSettings(GeneralSettingsConfig);
|
||||
SendConfigMSG(outgoing.ToString());
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public EspressoMode Mode
|
||||
{
|
||||
get => _mode;
|
||||
set
|
||||
{
|
||||
if (_mode != value)
|
||||
{
|
||||
_mode = value;
|
||||
OnPropertyChanged(nameof(Mode));
|
||||
|
||||
Settings.Properties.Mode = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool KeepDisplayOn
|
||||
{
|
||||
get => _keepDisplayOn;
|
||||
set
|
||||
{
|
||||
if (_keepDisplayOn != value)
|
||||
{
|
||||
_keepDisplayOn = value;
|
||||
OnPropertyChanged(nameof(KeepDisplayOn));
|
||||
|
||||
Settings.Properties.KeepDisplayOn = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public uint Hours
|
||||
{
|
||||
get => _hours;
|
||||
set
|
||||
{
|
||||
if (_hours != value)
|
||||
{
|
||||
_hours = value;
|
||||
OnPropertyChanged(nameof(Hours));
|
||||
|
||||
Settings.Properties.Hours = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public uint Minutes
|
||||
{
|
||||
get => _minutes;
|
||||
set
|
||||
{
|
||||
if (_minutes != value)
|
||||
{
|
||||
_minutes = value;
|
||||
OnPropertyChanged(nameof(Minutes));
|
||||
|
||||
Settings.Properties.Minutes = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
OnPropertyChanged(propertyName);
|
||||
if (SendConfigMSG != null)
|
||||
{
|
||||
SndEspressoSettings outsettings = new SndEspressoSettings(Settings);
|
||||
SndModuleSettings<SndEspressoSettings> ipcMessage = new SndModuleSettings<SndEspressoSettings>(outsettings);
|
||||
|
||||
var targetMessage = ipcMessage.ToJsonString();
|
||||
SendConfigMSG(targetMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isEnabled;
|
||||
private uint _hours;
|
||||
private uint _minutes;
|
||||
private bool _keepDisplayOn;
|
||||
private EspressoMode _mode;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
|
@ -9,6 +9,9 @@
|
|||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutputPath>..\..\..\x64\Debug\SettingsTests\</OutputPath>
|
||||
<DebugType>full</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 3 KiB |
|
@ -0,0 +1,44 @@
|
|||
// 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.Library;
|
||||
using Windows.UI.Xaml.Data;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Converters
|
||||
{
|
||||
public sealed class EspressoModeToBoolConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (targetType != typeof(bool))
|
||||
{
|
||||
throw new InvalidOperationException("The target type needs to be a boolean.");
|
||||
}
|
||||
|
||||
switch ((EspressoMode)value)
|
||||
{
|
||||
case EspressoMode.INDEFINITE:
|
||||
return true;
|
||||
case EspressoMode.TIMED:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
switch ((bool)value)
|
||||
{
|
||||
case true:
|
||||
return EspressoMode.INDEFINITE;
|
||||
case false:
|
||||
return EspressoMode.TIMED;
|
||||
}
|
||||
|
||||
return EspressoMode.INDEFINITE;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
// 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.Library;
|
||||
using Windows.UI.Xaml.Data;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Converters
|
||||
{
|
||||
public sealed class EspressoModeToReverseBoolConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (targetType != typeof(bool))
|
||||
{
|
||||
throw new InvalidOperationException("The target type needs to be a boolean.");
|
||||
}
|
||||
|
||||
switch ((EspressoMode)value)
|
||||
{
|
||||
case EspressoMode.INDEFINITE:
|
||||
return false;
|
||||
case EspressoMode.TIMED:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
switch ((bool)value)
|
||||
{
|
||||
case false:
|
||||
return EspressoMode.INDEFINITE;
|
||||
case true:
|
||||
return EspressoMode.TIMED;
|
||||
}
|
||||
|
||||
return EspressoMode.INDEFINITE;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -105,6 +105,8 @@
|
|||
<Compile Include="Controls\ShortcutVisualControl.xaml.cs">
|
||||
<DependentUpon>ShortcutVisualControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Converters\EspressoModeToBoolConverter.cs" />
|
||||
<Compile Include="Converters\EspressoModeToReverseBoolConverter.cs" />
|
||||
<Compile Include="Converters\ModuleEnabledToForegroundConverter.cs" />
|
||||
<Compile Include="Generated Files\AssemblyInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
|
@ -121,6 +123,9 @@
|
|||
<Compile Include="OOBE\Enums\PowerToysModulesEnum.cs" />
|
||||
<Compile Include="OOBE\ViewModel\OobeShellViewModel.cs" />
|
||||
<Compile Include="OOBE\ViewModel\OobePowerToysModule.cs" />
|
||||
<Compile Include="OOBE\Views\OobeEspresso.xaml.cs">
|
||||
<DependentUpon>OobeEspresso.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="OOBE\Views\OobeColorPicker.xaml.cs">
|
||||
<DependentUpon>OobeColorPicker.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -158,6 +163,9 @@
|
|||
<Compile Include="Services\NavigationService.cs" />
|
||||
<Compile Include="ViewModels\Commands\ButtonClickCommand.cs" />
|
||||
<Compile Include="ViewModels\ShellViewModel.cs" />
|
||||
<Compile Include="Views\EspressoPage.xaml.cs">
|
||||
<DependentUpon>EspressoPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\ColorPickerPage.xaml.cs">
|
||||
<DependentUpon>ColorPickerPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -197,6 +205,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Assets\FluentIcons\FluentIconsColorPicker.png" />
|
||||
<Content Include="Assets\FluentIcons\FluentIconsEspresso.png" />
|
||||
<Content Include="Assets\FluentIcons\FluentIconsFancyZones.png" />
|
||||
<Content Include="Assets\FluentIcons\FluentIconsFileExplorerPreview.png" />
|
||||
<Content Include="Assets\FluentIcons\FluentIconsImageResizer.png" />
|
||||
|
@ -275,7 +284,7 @@
|
|||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PRIResource Include="Strings\*\Resources.resw" />
|
||||
<PRIResource Include="Strings\en-us\Resources.resw" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Include="Controls\HotkeySettingsControl.xaml">
|
||||
|
@ -294,6 +303,10 @@
|
|||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="OOBE\Views\OobeEspresso.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="OOBE\Views\OobeColorPicker.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
@ -366,6 +379,10 @@
|
|||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Views\EspressoPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Views\ColorPickerPage.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Enums
|
|||
{
|
||||
Overview = 0,
|
||||
ColorPicker,
|
||||
Espresso,
|
||||
FancyZones,
|
||||
FileExplorer,
|
||||
ImageResizer,
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
<Page x:Class="Microsoft.PowerToys.Settings.UI.OOBE.Views.OobeEspresso"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.OOBE.Views"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="280" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Image Stretch="UniformToFill"
|
||||
Source="{x:Bind ViewModel.PreviewImageSource}" />
|
||||
|
||||
<ScrollViewer Grid.Row="1"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Orientation="Vertical"
|
||||
Margin="{StaticResource OobePageContentMargin}"
|
||||
VerticalAlignment="Top">
|
||||
|
||||
<TextBlock Text="{x:Bind ViewModel.ModuleName}"
|
||||
AutomationProperties.HeadingLevel="Level2"
|
||||
Style="{StaticResource PageTitleStyle}" />
|
||||
|
||||
<TextBlock TextWrapping="Wrap"
|
||||
Margin="0,4,0,0"
|
||||
Text="{x:Bind ViewModel.Description}" />
|
||||
|
||||
<HyperlinkButton NavigateUri="{x:Bind ViewModel.Link}" Margin="0,0,0,4">
|
||||
<TextBlock>
|
||||
<Run x:Uid="Oobe_LearnMore" />
|
||||
<Run Text="{x:Bind ViewModel.ModuleName}" />
|
||||
</TextBlock>
|
||||
</HyperlinkButton>
|
||||
|
||||
<TextBlock x:Uid="Oobe_HowToUse"
|
||||
AutomationProperties.HeadingLevel="Level3"
|
||||
Style="{StaticResource OobeSubtitleStyle}" />
|
||||
|
||||
<controls:ShortcutTextControl x:Uid="Oobe_Espresso_HowToUse" />
|
||||
|
||||
<TextBlock x:Uid="Oobe_TipsAndTricks"
|
||||
AutomationProperties.HeadingLevel="Level3"
|
||||
Style="{StaticResource OobeSubtitleStyle}"/>
|
||||
|
||||
<controls:ShortcutTextControl x:Uid="Oobe_Espresso_TipsAndTricks" />
|
||||
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Spacing="4"
|
||||
Margin="0,32,0,0">
|
||||
<Button Click="SettingsLaunchButton_Click"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=SettingsLabel}">
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Spacing="8">
|
||||
<TextBlock Text=""
|
||||
Margin="0,3,0,0"
|
||||
FontFamily="Segoe MDL2 Assets" />
|
||||
<TextBlock x:Uid="OOBE_Settings" Name="SettingsLabel" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Page>
|
|
@ -0,0 +1,48 @@
|
|||
// 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.Threading;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.Enums;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel;
|
||||
using Microsoft.PowerToys.Settings.UI.Views;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class OobeEspresso : Page
|
||||
{
|
||||
public OobePowerToysModule ViewModel { get; set; }
|
||||
|
||||
public OobeEspresso()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModulesEnum.Espresso]);
|
||||
DataContext = ViewModel;
|
||||
}
|
||||
|
||||
private void SettingsLaunchButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
if (OobeShellPage.OpenMainWindowCallback != null)
|
||||
{
|
||||
OobeShellPage.OpenMainWindowCallback(typeof(EspressoPage));
|
||||
}
|
||||
|
||||
ViewModel.LogOpeningSettingsEvent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogClosingModuleEvent();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -88,6 +88,18 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
|||
Description = loader.GetString("Oobe_ColorPicker_Description"),
|
||||
Link = "https://aka.ms/PowerToysOverview_ColorPicker",
|
||||
});
|
||||
Modules.Insert((int)PowerToysModulesEnum.Espresso, new OobePowerToysModule()
|
||||
{
|
||||
ModuleName = loader.GetString("Oobe_Espresso"),
|
||||
Tag = "Espresso",
|
||||
IsNew = false,
|
||||
Icon = "\uEC32",
|
||||
Image = "ms-appx:///Assets/Modules/Espresso.png",
|
||||
FluentIcon = "ms-appx:///Assets/FluentIcons/FluentIconsEspresso.png",
|
||||
PreviewImageSource = "ms-appx:///Assets/Modules/OOBE/FancyZones.gif",
|
||||
Description = loader.GetString("Oobe_Espresso_Description"),
|
||||
Link = "https://aka.ms/PowerToysOverview_Espresso",
|
||||
});
|
||||
Modules.Insert((int)PowerToysModulesEnum.FancyZones, new OobePowerToysModule()
|
||||
{
|
||||
ModuleName = loader.GetString("Oobe_FancyZones"),
|
||||
|
@ -211,6 +223,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
|||
{
|
||||
case "Overview": NavigationFrame.Navigate(typeof(OobeOverview)); break;
|
||||
case "ColorPicker": NavigationFrame.Navigate(typeof(OobeColorPicker)); break;
|
||||
case "Espresso": NavigationFrame.Navigate(typeof(OobeEspresso)); break;
|
||||
case "FancyZones": NavigationFrame.Navigate(typeof(OobeFancyZones)); break;
|
||||
case "Run": NavigationFrame.Navigate(typeof(OobeRun)); break;
|
||||
case "ImageResizer": NavigationFrame.Navigate(typeof(OobeImageResizer)); break;
|
||||
|
|
|
@ -121,6 +121,10 @@
|
|||
<value>General</value>
|
||||
<comment>Navigation view item name for General</comment>
|
||||
</data>
|
||||
<data name="Shell_Espresso.Content" xml:space="preserve">
|
||||
<value>Espresso</value>
|
||||
<comment>Product name: Navigation view item name for Espresso</comment>
|
||||
</data>
|
||||
<data name="Shell_PowerLauncher.Content" xml:space="preserve">
|
||||
<value>PowerToys Run</value>
|
||||
<comment>Product name: Navigation view item name for PowerToys Run</comment>
|
||||
|
@ -905,6 +909,10 @@
|
|||
<value>https://aka.ms/PowerToysOverview_ColorPicker</value>
|
||||
<comment>URL. Do not loc</comment>
|
||||
</data>
|
||||
<data name="Espresso_ImageHyperlinkToDocs.NavigateUri" xml:space="preserve">
|
||||
<value>https://aka.ms/PowerToysOverview_Espresso</value>
|
||||
<comment>URL. Do not loc</comment>
|
||||
</data>
|
||||
<data name="FancyZones_ImageHyperlinkToDocs.NavigateUri" xml:space="preserve">
|
||||
<value>https://aka.ms/PowerToysOverview_FancyZones</value>
|
||||
<comment>URL. Do not loc</comment>
|
||||
|
@ -1161,38 +1169,60 @@ From there, simply click on a Markdown file or SVG icon in the File Explorer and
|
|||
<data name="SettingsWindow_Title" xml:space="preserve">
|
||||
<value>PowerToys Settings</value>
|
||||
</data>
|
||||
<data name="Run_PositionAppearance_GroupSettings.Text" xml:space="preserve">
|
||||
<value>Position & appearance</value>
|
||||
<data name="About_Espresso.Text" xml:space="preserve">
|
||||
<value>About Espresso</value>
|
||||
</data>
|
||||
<data name="Run_PositionHeader.Text" xml:space="preserve">
|
||||
<value>Show PowerToys Run on</value>
|
||||
<comment>as in Show PowerToys Run on primary monitor</comment>
|
||||
<data name="Espresso_Description.Text" xml:space="preserve">
|
||||
<value>A convenient way to keep your computer awake on-demand.</value>
|
||||
</data>
|
||||
<data name="Run_Radio_Position_Cursor.Content" xml:space="preserve">
|
||||
<value>Monitor with mouse cursor</value>
|
||||
<data name="Espresso_EnableEspresso.Header" xml:space="preserve">
|
||||
<value>Enable Espresso</value>
|
||||
</data>
|
||||
<data name="Run_Radio_Position_Focus.Content" xml:space="preserve">
|
||||
<value>Monitor with focused window</value>
|
||||
<data name="Espresso_IndefiniteKeepAwakeContent.Text" xml:space="preserve">
|
||||
<value>Keep awake indefinitely</value>
|
||||
</data>
|
||||
<data name="Run_Radio_Position_Primary_Monitor.Content" xml:space="preserve">
|
||||
<value>Primary monitor</value>
|
||||
<data name="Espresso_TemporaryKeepAwakeContent.Text" xml:space="preserve">
|
||||
<value>Keep awake temporarily</value>
|
||||
</data>
|
||||
<data name="Run_PluginsLoading.Text" xml:space="preserve">
|
||||
<value>Plugins are loading...</value>
|
||||
<data name="Espresso_IndefiniteKeepAwakeDescription.Text" xml:space="preserve">
|
||||
<value>Keeps the computer awake until the setting is disabled.</value>
|
||||
</data>
|
||||
<data name="ColorPicker_ButtonDown.AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Move the color down</value>
|
||||
<data name="Espresso_TemporaryKeepAwakeDescription.Text" xml:space="preserve">
|
||||
<value>Keeps the computer awake until the set time elapses.</value>
|
||||
</data>
|
||||
<data name="ColorPicker_ButtonUp.AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Move the color up</value>
|
||||
<data name="Espresso_EnableDisplayKeepAwake.Content" xml:space="preserve">
|
||||
<value>Keep screen on</value>
|
||||
</data>
|
||||
<data name="FancyZones_FlashZonesOnQuickSwitch.Content" xml:space="preserve">
|
||||
<value>Flash zones when switching layout</value>
|
||||
<data name="Espresso_Mode.Text" xml:space="preserve">
|
||||
<value>Mode</value>
|
||||
</data>
|
||||
<data name="FancyZones_QuickLayoutSwitch.Content" xml:space="preserve">
|
||||
<value>Enable quick layout switch</value>
|
||||
<data name="Espresso_Behavior_GroupSettings.Text" xml:space="preserve">
|
||||
<value>Behavior</value>
|
||||
</data>
|
||||
<data name="FancyZones_QuickLayoutSwitch_GroupSettings.Text" xml:space="preserve">
|
||||
<value>Quick layout switch</value>
|
||||
<data name="Espresso_TemporaryKeepAwake_Hours.Header" xml:space="preserve">
|
||||
<value>Hours</value>
|
||||
</data>
|
||||
</root>
|
||||
<data name="Espresso_TemporaryKeepAwake_Minutes.Header" xml:space="preserve">
|
||||
<value>Minutes</value>
|
||||
</data>
|
||||
<data name="Espresso_ModuleAttributionLabel.Text" xml:space="preserve">
|
||||
<value>Den Delimarsky's Espresso</value>
|
||||
</data>
|
||||
<data name="Espresso_ModuleAttributionHyperlink.NavigateUri" xml:space="preserve">
|
||||
<value>https://espresso.den.dev</value>
|
||||
<comment>URL. Do not loc</comment>
|
||||
</data>
|
||||
<data name="Oobe_Espresso" xml:space="preserve">
|
||||
<value>Espresso</value>
|
||||
<comment>Module name, do not loc</comment>
|
||||
</data>
|
||||
<data name="Oobe_Espresso_Description" xml:space="preserve">
|
||||
<value>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</value>
|
||||
</data>
|
||||
<data name="Oobe_Espresso_HowToUse.Text" xml:space="preserve">
|
||||
<value>Open PowerToys Settings and {turn on Espresso}</value>
|
||||
</data>
|
||||
<data name="Oobe_Espresso_TipsAndTricks.Text" xml:space="preserve">
|
||||
<value>You can always change modes quickly by clicking the {Espresso icon in the system tray}</value>
|
||||
</data>
|
||||
</root>
|
|
@ -0,0 +1,188 @@
|
|||
<Page
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.EspressoPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Views"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:c="using:Microsoft.PowerToys.Settings.UI.Converters"
|
||||
xmlns:Custom="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:Color="using:Microsoft.PowerToys.Settings.UI.Library.ViewModels" xmlns:Interactivity="using:Microsoft.Xaml.Interactivity" xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="400"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
||||
AutomationProperties.LandmarkType="Main">
|
||||
|
||||
<Page.Resources>
|
||||
<c:EspressoModeToBoolConverter x:Key="EspressoModeToBoolConverter" />
|
||||
<c:EspressoModeToReverseBoolConverter x:Key="EspressoModeToReverseBoolConverter" />
|
||||
</Page.Resources>
|
||||
|
||||
<Grid RowSpacing="{StaticResource DefaultRowSpacing}">
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="LayoutVisualStates">
|
||||
<VisualState x:Name="WideLayout">
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowWidth="{StaticResource WideLayoutMinWidth}" />
|
||||
</VisualState.StateTriggers>
|
||||
</VisualState>
|
||||
<VisualState x:Name="SmallLayout">
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowWidth="{StaticResource SmallLayoutMinWidth}" />
|
||||
<AdaptiveTrigger MinWindowWidth="0" />
|
||||
</VisualState.StateTriggers>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="SidePanel.(Grid.Column)" Value="0" />
|
||||
<Setter Target="SidePanel.Width" Value="Auto" />
|
||||
<Setter Target="ColorPickerView.(Grid.Row)" Value="1" />
|
||||
<Setter Target="ColorPickerView.Margin" Value="0" />
|
||||
<Setter Target="LinksPanel.(RelativePanel.RightOf)" Value="AboutImage" />
|
||||
<Setter Target="LinksPanel.(RelativePanel.AlignTopWith)" Value="AboutImage" />
|
||||
<Setter Target="AboutImage.Margin" Value="0,12,12,0" />
|
||||
<Setter Target="AboutTitle.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Orientation="Vertical"
|
||||
x:Name="EspressoView"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="0,0,48,0"
|
||||
MaxWidth="{StaticResource MaxContentWidth}">
|
||||
<ToggleSwitch x:Uid="Espresso_EnableEspresso" IsOn="{Binding IsEnabled, Mode=TwoWay}" />
|
||||
<!--IsOn="{x:Bind Mode=TwoWay, Path=ViewModel.EnablePowerLauncher}"/>-->
|
||||
|
||||
<!--<TextBlock x:Uid="Shortcuts"
|
||||
Style="{StaticResource SettingsGroupTitleStyle}"
|
||||
Foreground="{x:Bind Mode=OneWay, Path=ViewModel.EnablePowerLauncher, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>-->
|
||||
|
||||
<TextBlock x:Uid="Espresso_Behavior_GroupSettings"
|
||||
Style="{StaticResource SettingsGroupTitleStyle}"/>
|
||||
|
||||
<CheckBox x:Uid="Espresso_EnableDisplayKeepAwake"
|
||||
IsEnabled="{Binding IsEnabled}"
|
||||
IsChecked="{Binding KeepDisplayOn, Mode=TwoWay}"
|
||||
Margin="{StaticResource XSmallTopMargin}" />
|
||||
|
||||
<TextBlock x:Uid="Espresso_Mode"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
x:Name="ModeTitleLabel"
|
||||
Foreground="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}" />
|
||||
|
||||
<StackPanel AutomationProperties.LabeledBy="{Binding ElementName=ModeTitleLabel}"
|
||||
Margin="0,-4,0,0">
|
||||
<RadioButton x:Uid="Espresso_IndefiniteKeepAwake"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
IsEnabled="{Binding IsEnabled}"
|
||||
IsChecked="{Binding Mode, Mode=TwoWay, Converter={StaticResource EspressoModeToBoolConverter}}">
|
||||
<RadioButton.Content>
|
||||
<TextBlock TextWrapping="WrapWholeWords" LineHeight="20">
|
||||
<Run x:Uid="Espresso_IndefiniteKeepAwakeContent"/>
|
||||
<LineBreak/>
|
||||
<Run Foreground="{ThemeResource SystemBaseMediumColor}"
|
||||
x:Uid="Espresso_IndefiniteKeepAwakeDescription"/>
|
||||
</TextBlock>
|
||||
</RadioButton.Content>
|
||||
</RadioButton>
|
||||
<RadioButton x:Uid="Espresso_TemporaryKeepAwake"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
IsEnabled="{Binding IsEnabled}"
|
||||
IsChecked="{Binding Mode, Mode=TwoWay, Converter={StaticResource EspressoModeToReverseBoolConverter}}">
|
||||
<RadioButton.Content>
|
||||
<TextBlock TextWrapping="WrapWholeWords" LineHeight="20">
|
||||
<Run x:Uid="Espresso_TemporaryKeepAwakeContent"/>
|
||||
<LineBreak/>
|
||||
<Run Foreground="{ThemeResource SystemBaseMediumColor}"
|
||||
x:Uid="Espresso_TemporaryKeepAwakeDescription"/>
|
||||
</TextBlock>
|
||||
</RadioButton.Content>
|
||||
</RadioButton>
|
||||
|
||||
<StackPanel Margin="28,8,0,0" Orientation="Horizontal">
|
||||
<muxc:NumberBox x:Uid="Espresso_TemporaryKeepAwake_Hours"
|
||||
Value="{Binding Hours, Mode=TwoWay}"
|
||||
Minimum="0"
|
||||
SpinButtonPlacementMode="Compact"
|
||||
HorizontalAlignment="Left"
|
||||
MinWidth="90"
|
||||
IsEnabled="{Binding Mode, Converter={StaticResource EspressoModeToReverseBoolConverter}}"
|
||||
SmallChange="1"
|
||||
LargeChange="5"/>
|
||||
<muxc:NumberBox x:Uid="Espresso_TemporaryKeepAwake_Minutes"
|
||||
Value="{Binding Minutes, Mode=TwoWay}"
|
||||
Minimum="1"
|
||||
SpinButtonPlacementMode="Compact"
|
||||
Margin="8,0,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
MinWidth="90"
|
||||
IsEnabled="{Binding Mode, Converter={StaticResource EspressoModeToReverseBoolConverter}}"
|
||||
SmallChange="1"
|
||||
LargeChange="5"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
<!--Foreground="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"-->
|
||||
</StackPanel>
|
||||
|
||||
<RelativePanel x:Name="SidePanel"
|
||||
HorizontalAlignment="Left"
|
||||
Width="{StaticResource SidePanelWidth}"
|
||||
Grid.Column="1">
|
||||
<StackPanel x:Name="DescriptionPanel">
|
||||
<TextBlock x:Uid="About_Espresso"
|
||||
x:Name="AboutTitle"
|
||||
Grid.ColumnSpan="2"
|
||||
Style="{StaticResource SettingsGroupTitleStyle}"
|
||||
Margin="{StaticResource XSmallBottomMargin}"/>
|
||||
<TextBlock x:Uid="Espresso_Description"
|
||||
TextWrapping="Wrap"
|
||||
Grid.Row="1" />
|
||||
</StackPanel>
|
||||
|
||||
<Border x:Name="AboutImage"
|
||||
CornerRadius="4"
|
||||
Grid.Row="2"
|
||||
MaxWidth="240"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="{StaticResource SmallTopBottomMargin}"
|
||||
RelativePanel.Below="DescriptionPanel">
|
||||
<HyperlinkButton x:Uid="Espresso_ImageHyperlinkToDocs">
|
||||
<Image x:Uid="Espresso_Image" Source="ms-appx:///Assets/Modules/ColorPicker.png" />
|
||||
</HyperlinkButton>
|
||||
</Border>
|
||||
<StackPanel x:Name="LinksPanel"
|
||||
Margin="0,1,0,0"
|
||||
RelativePanel.Below="AboutImage"
|
||||
Orientation="Vertical" >
|
||||
<HyperlinkButton x:Uid="Espresso_ImageHyperlinkToDocs">
|
||||
<TextBlock x:Uid="Module_overview" />
|
||||
</HyperlinkButton>
|
||||
<HyperlinkButton NavigateUri="https://aka.ms/powerToysGiveFeedback">
|
||||
<TextBlock x:Uid="Give_Feedback" />
|
||||
</HyperlinkButton>
|
||||
|
||||
<TextBlock
|
||||
x:Uid="AttributionTitle"
|
||||
Style="{StaticResource SettingsGroupTitleStyle}" />
|
||||
|
||||
<HyperlinkButton Margin="0,-3,0,0"
|
||||
x:Uid="Espresso_ModuleAttributionHyperlink">
|
||||
<TextBlock x:Uid="Espresso_ModuleAttributionLabel"
|
||||
TextWrapping="Wrap" />
|
||||
</HyperlinkButton>
|
||||
</StackPanel>
|
||||
</RelativePanel>
|
||||
</Grid>
|
||||
</Page>
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.ViewModels;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class EspressoPage : Page
|
||||
{
|
||||
private EspressoViewModel ViewModel { get; set; }
|
||||
|
||||
public EspressoPage()
|
||||
{
|
||||
var settingsUtils = new SettingsUtils();
|
||||
ViewModel = new EspressoViewModel(SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), SettingsRepository<EspressoSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage);
|
||||
DataContext = ViewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -41,7 +41,13 @@
|
|||
<FontIcon Glyph=""/>
|
||||
</winui:NavigationViewItem.Icon>
|
||||
</winui:NavigationViewItem>
|
||||
|
||||
|
||||
<winui:NavigationViewItem x:Uid="Shell_Espresso" helpers:NavHelper.NavigateTo="views:EspressoPage" AutomationProperties.HeadingLevel="Level1">
|
||||
<winui:NavigationViewItem.Icon>
|
||||
<FontIcon Glyph=""/>
|
||||
</winui:NavigationViewItem.Icon>
|
||||
</winui:NavigationViewItem>
|
||||
|
||||
<winui:NavigationViewItem x:Uid="Shell_FancyZones" helpers:NavHelper.NavigateTo="views:FancyZonesPage" AutomationProperties.HeadingLevel="Level1">
|
||||
<winui:NavigationViewItem.Icon>
|
||||
<PathIcon Data="M45,48H25.5V45H45V25.5H25.5v-3H45V3H25.5V0H48V48ZM22.5,48H3V45H22.5V3H3V0H25.5V48ZM0,48V0H3V48Z"/>
|
||||
|
|
|
@ -34,6 +34,9 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutputPath>..\..\..\$(Platform)\$(Configuration)\Settings</OutputPath>
|
||||
<Optimize>false</Optimize>
|
||||
<DebugType>full</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
|
Loading…
Reference in a new issue