mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 18:57:19 +02:00
Espresso (#11303)
* Update README.md * Espresso (#11245) * Revert "Merge branch 'microsoft:master' into master" This reverts commitb080908712, reversing changes made to8463c95a43. * Fix conversion of settings in the UX * Update terminology * Updating logging configuration * Set up how tray and setting configuration works * Adding hero images * Fix how binding works * Update OOBE string * Fix spelling error * fixing dep to include espresso, adding in yml * Update API components and fix display keep-awake bug * Adding words that the spell check is yelling about * tweak wsx * Change default setting for Espresso Co-authored-by: Niels Laute <niels9001@hotmail.com> Co-authored-by: crutkas <crutkas@microsoft.com> * Update Product.wxs * Update Shortcut.cpp * Update with more logging (#11332) * Revert "Merge branch 'microsoft:master' into master" This reverts commitb080908712, reversing changes made to8463c95a43. * Fix conversion of settings in the UX * Update terminology * Updating logging configuration * Set up how tray and setting configuration works * Adding hero images * Fix how binding works * Update OOBE string * Fix spelling error * fixing dep to include espresso, adding in yml * Update API components and fix display keep-awake bug * Adding words that the spell check is yelling about * tweak wsx * Change default setting for Espresso * Adding some extra logging * Update Shortcut.cpp Co-authored-by: Niels Laute <niels9001@hotmail.com> Co-authored-by: crutkas <crutkas@microsoft.com> * Fix minor issue in the module branch (#11340) * Revert "Merge branch 'microsoft:master' into master" This reverts commitb080908712, reversing changes made to8463c95a43. * Fix conversion of settings in the UX * Update terminology * Updating logging configuration * Set up how tray and setting configuration works * Adding hero images * Fix how binding works * Update OOBE string * Fix spelling error * fixing dep to include espresso, adding in yml * Update API components and fix display keep-awake bug * Adding words that the spell check is yelling about * tweak wsx * Change default setting for Espresso * Adding some extra logging * Update Shortcut.cpp * Fix log location coming from the runner * More chatty logging for console allocation * Installer config to add the missing assets Co-authored-by: Niels Laute <niels9001@hotmail.com> Co-authored-by: crutkas <crutkas@microsoft.com> * Update Product.wxs * Update Program.cs * fixing typo * removing a unneeded removal * [Espresso] More minor tweaks to logging (#11341) * Revert "Merge branch 'microsoft:master' into master" This reverts commitb080908712, reversing changes made to8463c95a43. * Fix conversion of settings in the UX * Update terminology * Updating logging configuration * Set up how tray and setting configuration works * Adding hero images * Fix how binding works * Update OOBE string * Fix spelling error * fixing dep to include espresso, adding in yml * Update API components and fix display keep-awake bug * Adding words that the spell check is yelling about * tweak wsx * Change default setting for Espresso * Adding some extra logging * Update Shortcut.cpp * Fix log location coming from the runner * More chatty logging for console allocation * Installer config to add the missing assets * Remove unused handle codes * Update log file name for the Espresso C++ code. * Update the project configuration to fix build issue Co-authored-by: Niels Laute <niels9001@hotmail.com> Co-authored-by: crutkas <crutkas@microsoft.com> * Update patterns.txt * Fix binding issues (#11368) * Revert "Merge branch 'microsoft:master' into master" This reverts commitb080908712, reversing changes made to8463c95a43. * Fix conversion of settings in the UX * Update terminology * Updating logging configuration * Set up how tray and setting configuration works * Adding hero images * Fix how binding works * Update OOBE string * Fix spelling error * fixing dep to include espresso, adding in yml * Update API components and fix display keep-awake bug * Adding words that the spell check is yelling about * tweak wsx * Change default setting for Espresso * Adding some extra logging * Update Shortcut.cpp * Fix log location coming from the runner * More chatty logging for console allocation * Installer config to add the missing assets * Remove unused handle codes * Update log file name for the Espresso C++ code. * Update the project configuration to fix build issue * Fix binding issue with the time settings Co-authored-by: Niels Laute <niels9001@hotmail.com> Co-authored-by: crutkas <crutkas@microsoft.com> * Introduce the off mode and fix binding issues (#11385) * Revert "Merge branch 'microsoft:master' into master" This reverts commitb080908712, reversing changes made to8463c95a43. * Fix conversion of settings in the UX * Update terminology * Updating logging configuration * Set up how tray and setting configuration works * Adding hero images * Fix how binding works * Update OOBE string * Fix spelling error * fixing dep to include espresso, adding in yml * Update API components and fix display keep-awake bug * Adding words that the spell check is yelling about * tweak wsx * Change default setting for Espresso * Adding some extra logging * Update Shortcut.cpp * Fix log location coming from the runner * More chatty logging for console allocation * Installer config to add the missing assets * Remove unused handle codes * Update log file name for the Espresso C++ code. * Update the project configuration to fix build issue * Fix binding issue with the time settings * Proper Espresso behavior for binding * Fix settings UI Co-authored-by: Niels Laute <niels9001@hotmail.com> Co-authored-by: crutkas <crutkas@microsoft.com> * Update with missing strings. (#11386) * Revert "Merge branch 'microsoft:master' into master" This reverts commitb080908712, reversing changes made to8463c95a43. * Fix conversion of settings in the UX * Update terminology * Updating logging configuration * Set up how tray and setting configuration works * Adding hero images * Fix how binding works * Update OOBE string * Fix spelling error * fixing dep to include espresso, adding in yml * Update API components and fix display keep-awake bug * Adding words that the spell check is yelling about * tweak wsx * Change default setting for Espresso * Adding some extra logging * Update Shortcut.cpp * Fix log location coming from the runner * More chatty logging for console allocation * Installer config to add the missing assets * Remove unused handle codes * Update log file name for the Espresso C++ code. * Update the project configuration to fix build issue * Fix binding issue with the time settings * Proper Espresso behavior for binding * Fix settings UI * Re-add missing strings Co-authored-by: Niels Laute <niels9001@hotmail.com> Co-authored-by: crutkas <crutkas@microsoft.com> * Fix whitespace issue (#11387) * Revert "Merge branch 'microsoft:master' into master" This reverts commitb080908712, reversing changes made to8463c95a43. * Fix conversion of settings in the UX * Update terminology * Updating logging configuration * Set up how tray and setting configuration works * Adding hero images * Fix how binding works * Update OOBE string * Fix spelling error * fixing dep to include espresso, adding in yml * Update API components and fix display keep-awake bug * Adding words that the spell check is yelling about * tweak wsx * Change default setting for Espresso * Adding some extra logging * Update Shortcut.cpp * Fix log location coming from the runner * More chatty logging for console allocation * Installer config to add the missing assets * Remove unused handle codes * Update log file name for the Espresso C++ code. * Update the project configuration to fix build issue * Fix binding issue with the time settings * Proper Espresso behavior for binding * Fix settings UI * Re-add missing strings * Fix whitespace issue Co-authored-by: Niels Laute <niels9001@hotmail.com> Co-authored-by: crutkas <crutkas@microsoft.com> * Fix default (#11388) * Revert "Merge branch 'microsoft:master' into master" This reverts commitb080908712, reversing changes made to8463c95a43. * Fix conversion of settings in the UX * Update terminology * Updating logging configuration * Set up how tray and setting configuration works * Adding hero images * Fix how binding works * Update OOBE string * Fix spelling error * fixing dep to include espresso, adding in yml * Update API components and fix display keep-awake bug * Adding words that the spell check is yelling about * tweak wsx * Change default setting for Espresso * Adding some extra logging * Update Shortcut.cpp * Fix log location coming from the runner * More chatty logging for console allocation * Installer config to add the missing assets * Remove unused handle codes * Update log file name for the Espresso C++ code. * Update the project configuration to fix build issue * Fix binding issue with the time settings * Proper Espresso behavior for binding * Fix settings UI * Re-add missing strings * Fix whitespace issue * Fix the default mode of operation Co-authored-by: Niels Laute <niels9001@hotmail.com> Co-authored-by: crutkas <crutkas@microsoft.com> * Update Microsoft.PowerToys.Settings.UI.csproj * Localization improvements * Replaced a computer with your pc * Updated Espresso imagery * Fixed inconsistent string * Margin fix and updated images * Removed unused code Co-authored-by: Den Delimarsky <1389609+dend@users.noreply.github.com> Co-authored-by: Niels Laute <niels9001@hotmail.com> Co-authored-by: crutkas <crutkas@microsoft.com> Co-authored-by: Enrico Giordani <enrico.giordani@gmail.com>
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ struct LogSettings
|
||||
inline const static std::wstring actionRunnerLogPath = L"RunnerLogs\\action-runner-log.txt";
|
||||
inline const static std::string launcherLoggerName = "launcher";
|
||||
inline const static std::wstring launcherLogPath = L"LogsModuleInterface\\launcher-log.txt";
|
||||
inline const static std::wstring espressoLogPath = L"Logs\\espresso-log.txt";
|
||||
inline const static std::string fancyZonesLoggerName = "fancyzones";
|
||||
inline const static std::wstring fancyZonesLogPath = L"fancyzones-log.txt";
|
||||
inline const static std::wstring fancyZonesOldLogPath = L"FancyZonesLogs\\"; // needed to clean up old logs
|
||||
|
||||
280
src/modules/espresso/Espresso/Core/APIHelper.cs
Normal file
280
src/modules/espresso/Espresso/Core/APIHelper.cs
Normal file
@@ -0,0 +1,280 @@
|
||||
// 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";
|
||||
private const int StdOutputHandle = -11;
|
||||
private const uint GenericWrite = 0x40000000;
|
||||
private const uint GenericRead = 0x80000000;
|
||||
|
||||
private static readonly Logger _log;
|
||||
private static CancellationTokenSource _tokenSource;
|
||||
private static CancellationToken _threadToken;
|
||||
|
||||
private static Task? _runnerThread;
|
||||
|
||||
[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)]
|
||||
private static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern uint GetCurrentThreadId();
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private 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()
|
||||
{
|
||||
_log.Debug("Bootstrapping the console allocation routine.");
|
||||
AllocConsole();
|
||||
_log.Debug($"Console allocation result: {Marshal.GetLastWin32Error()}");
|
||||
|
||||
var outputFilePointer = CreateFile("CONOUT$", GenericRead | GenericWrite, FileShare.Write, IntPtr.Zero, FileMode.OpenOrCreate, 0, IntPtr.Zero);
|
||||
_log.Debug($"CONOUT creation result: {Marshal.GetLastWin32Error()}");
|
||||
|
||||
SetStdHandle(StdOutputHandle, outputFilePointer);
|
||||
_log.Debug($"SetStdHandle result: {Marshal.GetLastWin32Error()}");
|
||||
|
||||
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 = false)
|
||||
{
|
||||
_tokenSource.Cancel();
|
||||
|
||||
try
|
||||
{
|
||||
if (_runnerThread != null && !_runnerThread.IsCanceled)
|
||||
{
|
||||
_runnerThread.Wait(_threadToken);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_log.Info("Confirmed background thread cancellation when setting indefinite keep awake.");
|
||||
}
|
||||
|
||||
_tokenSource = new CancellationTokenSource();
|
||||
_threadToken = _tokenSource.Token;
|
||||
|
||||
_runnerThread = Task.Run(() => RunIndefiniteLoop(keepDisplayOn), _threadToken)
|
||||
.ContinueWith((result) => callback(result.Result), TaskContinuationOptions.OnlyOnRanToCompletion)
|
||||
.ContinueWith((result) => failureCallback, TaskContinuationOptions.NotOnRanToCompletion);
|
||||
}
|
||||
|
||||
public static void SetNoKeepAwake()
|
||||
{
|
||||
_tokenSource.Cancel();
|
||||
|
||||
try
|
||||
{
|
||||
if (_runnerThread != null && !_runnerThread.IsCanceled)
|
||||
{
|
||||
_runnerThread.Wait(_threadToken);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_log.Info("Confirmed background thread cancellation when setting passive keep awake.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetTimedKeepAwake(uint seconds, Action<bool> callback, Action failureCallback, bool keepDisplayOn = true)
|
||||
{
|
||||
_tokenSource.Cancel();
|
||||
|
||||
try
|
||||
{
|
||||
if (_runnerThread != null && !_runnerThread.IsCanceled)
|
||||
{
|
||||
_runnerThread.Wait(_threadToken);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_log.Info("Confirmed background thread cancellation when setting indefinite keep awake.");
|
||||
}
|
||||
|
||||
_tokenSource = new CancellationTokenSource();
|
||||
_threadToken = _tokenSource.Token;
|
||||
|
||||
_runnerThread = Task.Run(() => RunTimedLoop(seconds, keepDisplayOn), _threadToken)
|
||||
.ContinueWith((result) => callback(result.Result), TaskContinuationOptions.OnlyOnRanToCompletion)
|
||||
.ContinueWith((result) => failureCallback, TaskContinuationOptions.NotOnRanToCompletion);
|
||||
}
|
||||
|
||||
private static bool RunIndefiniteLoop(bool keepDisplayOn = false)
|
||||
{
|
||||
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: {GetCurrentThreadId()}. Screen on: {keepDisplayOn}");
|
||||
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: {GetCurrentThreadId()}. 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);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
_log.Info($"Initiated temporary keep awake in background thread: {GetCurrentThreadId()}. Screen on: {keepDisplayOn}");
|
||||
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;
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
// Task was clearly cancelled.
|
||||
_log.Info($"Background thread termination: {GetCurrentThreadId()}. 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.Info("Registry key acquisition for OS failed.");
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Info($"Could not get registry key for the build number. Error: {ex.Message}");
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
297
src/modules/espresso/Espresso/Core/TrayHelper.cs
Normal file
297
src/modules/espresso/Espresso/Core/TrayHelper.cs
Normal file
@@ -0,0 +1,297 @@
|
||||
// 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.IO;
|
||||
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,
|
||||
PassiveKeepAwakeCallback(text),
|
||||
IndefiniteKeepAwakeCallback(text),
|
||||
TimedKeepAwakeCallback(text),
|
||||
KeepDisplayOnCallback(text),
|
||||
ExitCallback());
|
||||
}
|
||||
|
||||
private static Action ExitCallback()
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
Environment.Exit(0);
|
||||
};
|
||||
}
|
||||
|
||||
private static Action KeepDisplayOnCallback(string moduleName)
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
EspressoSettings currentSettings;
|
||||
|
||||
try
|
||||
{
|
||||
currentSettings = ModuleSettings.GetSettings<EspressoSettings>(moduleName);
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
currentSettings = new EspressoSettings();
|
||||
}
|
||||
|
||||
currentSettings.Properties.KeepDisplayOn = !currentSettings.Properties.KeepDisplayOn;
|
||||
|
||||
ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), moduleName);
|
||||
};
|
||||
}
|
||||
|
||||
private static Action<uint, uint> TimedKeepAwakeCallback(string moduleName)
|
||||
{
|
||||
return (hours, minutes) =>
|
||||
{
|
||||
EspressoSettings currentSettings;
|
||||
|
||||
try
|
||||
{
|
||||
currentSettings = ModuleSettings.GetSettings<EspressoSettings>(moduleName);
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
currentSettings = new EspressoSettings();
|
||||
}
|
||||
|
||||
currentSettings.Properties.Mode = EspressoMode.TIMED;
|
||||
currentSettings.Properties.Hours = hours;
|
||||
currentSettings.Properties.Minutes = minutes;
|
||||
|
||||
ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), moduleName);
|
||||
};
|
||||
}
|
||||
|
||||
private static Action PassiveKeepAwakeCallback(string moduleName)
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
EspressoSettings currentSettings;
|
||||
|
||||
try
|
||||
{
|
||||
currentSettings = ModuleSettings.GetSettings<EspressoSettings>(moduleName);
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
currentSettings = new EspressoSettings();
|
||||
}
|
||||
|
||||
currentSettings.Properties.Mode = EspressoMode.PASSIVE;
|
||||
|
||||
ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), moduleName);
|
||||
};
|
||||
}
|
||||
|
||||
private static Action IndefiniteKeepAwakeCallback(string moduleName)
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
EspressoSettings currentSettings;
|
||||
|
||||
try
|
||||
{
|
||||
currentSettings = ModuleSettings.GetSettings<EspressoSettings>(moduleName);
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
currentSettings = new EspressoSettings();
|
||||
}
|
||||
|
||||
currentSettings.Properties.Mode = EspressoMode.INDEFINITE;
|
||||
|
||||
ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), moduleName);
|
||||
};
|
||||
}
|
||||
|
||||
public static void SetTray(string text, bool keepDisplayOn, EspressoMode mode, Action passiveKeepAwakeCallback, Action indefiniteKeepAwakeCallback, Action<uint, uint> timedKeepAwakeCallback, Action keepDisplayOnCallback, Action exitCallback)
|
||||
{
|
||||
var contextMenuStrip = new ContextMenuStrip();
|
||||
|
||||
// Main toolstrip.
|
||||
var operationContextMenu = new ToolStripMenuItem
|
||||
{
|
||||
Text = "Mode",
|
||||
};
|
||||
|
||||
// No keep-awake menu item.
|
||||
var passiveMenuItem = new ToolStripMenuItem
|
||||
{
|
||||
Text = "Off (Passive)",
|
||||
};
|
||||
|
||||
if (mode == EspressoMode.PASSIVE)
|
||||
{
|
||||
passiveMenuItem.Checked = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
passiveMenuItem.Checked = false;
|
||||
}
|
||||
|
||||
passiveMenuItem.Click += (e, s) =>
|
||||
{
|
||||
// User opted to set the mode to indefinite, so we need to write new settings.
|
||||
passiveKeepAwakeCallback();
|
||||
};
|
||||
|
||||
// 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 screen 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(passiveMenuItem);
|
||||
operationContextMenu.DropDownItems.Add(indefiniteMenuItem);
|
||||
operationContextMenu.DropDownItems.Add(timedMenuItem);
|
||||
|
||||
contextMenuStrip.Items.Add(operationContextMenu);
|
||||
contextMenuStrip.Items.Add(displayOnMenuItem);
|
||||
contextMenuStrip.Items.Add(new ToolStripSeparator());
|
||||
contextMenuStrip.Items.Add(exitContextMenu);
|
||||
|
||||
TrayIcon.Text = text;
|
||||
TrayIcon.ContextMenuStrip = contextMenuStrip;
|
||||
}
|
||||
}
|
||||
}
|
||||
83
src/modules/espresso/Espresso/Espresso.csproj
Normal file
83
src/modules/espresso/Espresso/Espresso.csproj
Normal file
@@ -0,0 +1,83 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
<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>
|
||||
<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 |
22
src/modules/espresso/Espresso/NLog.config
Normal file
22
src/modules/espresso/Espresso/NLog.config
Normal file
@@ -0,0 +1,22 @@
|
||||
<?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">
|
||||
|
||||
<variable name="espressoversion" value="0.0.1" />
|
||||
|
||||
<targets async="true">
|
||||
<target name="logfile"
|
||||
xsi:type="File"
|
||||
fileName="${specialfolder:folder=LocalApplicationData}/Microsoft/PowerToys/Espresso/Logs/${var:espressoversion}/log_${date:format=yyyy-MM-dd_HH}_DBG.txt"
|
||||
layout="[${longdate} ${level:uppercase=true} ${logger}] ${message}"
|
||||
archiveEvery="Day"
|
||||
archiveNumbering="Rolling"
|
||||
maxArchiveFiles="30"/>
|
||||
<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>
|
||||
320
src/modules/espresso/Espresso/Program.cs
Normal file
320
src/modules/espresso/Espresso/Program.cs
Normal file
@@ -0,0 +1,320 @@
|
||||
// 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.Info($"OS: {Environment.OSVersion}");
|
||||
_log.Info($"OS Build: {APIHelper.GetOperatingSystemBuild()}");
|
||||
|
||||
_log.Info("Parsing parameters...");
|
||||
|
||||
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);
|
||||
|
||||
_log.Info("Parameter setup complete. Proceeding to the rest of the app initiation...");
|
||||
|
||||
return rootCommand.InvokeAsync(args).Result;
|
||||
}
|
||||
|
||||
private static void ForceExit(string message, int exitCode)
|
||||
{
|
||||
_log.Info(message);
|
||||
Console.ReadKey();
|
||||
Environment.Exit(exitCode);
|
||||
}
|
||||
|
||||
private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, uint timeLimit, int pid)
|
||||
{
|
||||
if (pid == 0)
|
||||
{
|
||||
_log.Info("No PID specified. Allocating console...");
|
||||
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)
|
||||
{
|
||||
// Configuration file is used, therefore we disregard any other command-line parameter
|
||||
// and instead watch for changes in the file.
|
||||
try
|
||||
{
|
||||
#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.
|
||||
|
||||
var settingsPath = _settingsUtils.GetSettingsFilePath(AppName);
|
||||
_log.Info($"Reading configuration file: {settingsPath}");
|
||||
|
||||
_watcher = new FileSystemWatcher
|
||||
{
|
||||
Path = Path.GetDirectoryName(settingsPath),
|
||||
EnableRaisingEvents = true,
|
||||
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.CreationTime,
|
||||
Filter = Path.GetFileName(settingsPath),
|
||||
};
|
||||
|
||||
var changedObservable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
|
||||
h => _watcher.Changed += h,
|
||||
h => _watcher.Changed -= h);
|
||||
|
||||
var createdObservable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
|
||||
cre => _watcher.Created += cre,
|
||||
cre => _watcher.Created -= cre);
|
||||
|
||||
var mergedObservable = Observable.Merge(changedObservable, createdObservable);
|
||||
|
||||
mergedObservable.Throttle(TimeSpan.FromMilliseconds(25))
|
||||
.SubscribeOn(TaskPoolScheduler.Default)
|
||||
.Select(e => e.EventArgs)
|
||||
.Subscribe(HandleEspressoConfigChange);
|
||||
|
||||
TrayHelper.SetTray(AppName, new EspressoSettings());
|
||||
|
||||
// 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.PASSIVE:
|
||||
{
|
||||
SetupNoKeepAwake();
|
||||
break;
|
||||
}
|
||||
|
||||
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.GetType()} {ex.Message}";
|
||||
_log.Info(errorMessage);
|
||||
_log.Debug(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetupNoKeepAwake()
|
||||
{
|
||||
_log.Info($"Operating in passive mode (computer's standard power plan). No custom keep awake settings enabled.");
|
||||
|
||||
APIHelper.SetNoKeepAwake();
|
||||
}
|
||||
|
||||
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>
|
||||
181
src/modules/espresso/EspressoModuleInterface/dllmain.cpp
Normal file
181
src/modules/espresso/EspressoModuleInterface/dllmain.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
#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>";
|
||||
|
||||
// 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;
|
||||
|
||||
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));
|
||||
logFilePath.append(LogSettings::espressoLogPath);
|
||||
Logger::init(LogSettings::launcherLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
|
||||
Logger::info("Launcher object is constructing");
|
||||
};
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
};
|
||||
|
||||
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();
|
||||
};
|
||||
@@ -149,7 +149,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",
|
||||
@@ -158,6 +158,7 @@ int runner(bool isProcessElevated, bool openSettings, bool openOobe)
|
||||
L"modules/PowerRename/PowerRenameExt.dll",
|
||||
L"modules/ShortcutGuide/ShortcutGuideModuleInterface/ShortcutGuideModuleInterface.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;
|
||||
|
||||
[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,38 @@
|
||||
// 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.PASSIVE;
|
||||
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
|
||||
{
|
||||
PASSIVE = 0,
|
||||
INDEFINITE = 1,
|
||||
TIMED = 2,
|
||||
}
|
||||
}
|
||||
@@ -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 = "0.0.1";
|
||||
|
||||
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,157 @@
|
||||
// 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;
|
||||
OnPropertyChanged(nameof(IsEnabled));
|
||||
OnPropertyChanged(nameof(IsTimeConfigurationEnabled));
|
||||
|
||||
var outgoing = new OutGoingGeneralSettings(GeneralSettingsConfig);
|
||||
SendConfigMSG(outgoing.ToString());
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsTimeConfigurationEnabled
|
||||
{
|
||||
get => _mode == EspressoMode.TIMED && _isEnabled;
|
||||
}
|
||||
|
||||
public EspressoMode Mode
|
||||
{
|
||||
get => _mode;
|
||||
set
|
||||
{
|
||||
if (_mode != value)
|
||||
{
|
||||
_mode = value;
|
||||
OnPropertyChanged(nameof(Mode));
|
||||
OnPropertyChanged(nameof(IsTimeConfigurationEnabled));
|
||||
|
||||
Settings.Properties.Mode = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool KeepDisplayOn
|
||||
{
|
||||
get => _keepDisplayOn;
|
||||
set
|
||||
{
|
||||
if (_keepDisplayOn != value)
|
||||
{
|
||||
_keepDisplayOn = value;
|
||||
OnPropertyChanged(nameof(KeepDisplayOn));
|
||||
|
||||
Settings.Properties.KeepDisplayOn = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 246 KiB |
@@ -0,0 +1,41 @@
|
||||
// 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.");
|
||||
}
|
||||
|
||||
if (parameter == null)
|
||||
{
|
||||
throw new NullReferenceException("Parameter cannot be null for the Espresso mode to bool converter.");
|
||||
}
|
||||
|
||||
var expectedMode = (EspressoMode)Enum.Parse(typeof(EspressoMode), parameter.ToString());
|
||||
var currentMode = (EspressoMode)value;
|
||||
|
||||
return currentMode.Equals(expectedMode);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (parameter == null)
|
||||
{
|
||||
throw new NullReferenceException("Parameter cannot be null for the Espresso mode to bool converter.");
|
||||
}
|
||||
|
||||
return (EspressoMode)Enum.Parse(typeof(EspressoMode), parameter.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,6 +105,7 @@
|
||||
<Compile Include="Controls\ShortcutVisualControl.xaml.cs">
|
||||
<DependentUpon>ShortcutVisualControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Converters\EspressoModeToBoolConverter.cs" />
|
||||
<Compile Include="Converters\ModuleEnabledToForegroundConverter.cs" />
|
||||
<Compile Include="Converters\UpdatingStateCannotDownloadToVisibilityConverter.cs" />
|
||||
<Compile Include="Converters\UpdatingStateReadyToDownloadToVisibilityConverter.cs" />
|
||||
@@ -125,6 +126,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>
|
||||
@@ -162,6 +166,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>
|
||||
@@ -201,6 +208,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" />
|
||||
@@ -212,10 +220,12 @@
|
||||
<Content Include="Assets\FluentIcons\FluentIconsVideoConferenceMute.png" />
|
||||
<Content Include="Assets\Logo.scale-200.png" />
|
||||
<Content Include="Assets\Modules\ColorPicker.png" />
|
||||
<Content Include="Assets\Modules\Espresso.png" />
|
||||
<Content Include="Assets\Modules\FancyZones.png" />
|
||||
<Content Include="Assets\Modules\ImageResizer.png" />
|
||||
<Content Include="Assets\Modules\KBM.png" />
|
||||
<Content Include="Assets\Modules\OOBE\ColorPicker.gif" />
|
||||
<Content Include="Assets\Modules\OOBE\Espresso.png" />
|
||||
<Content Include="Assets\Modules\OOBE\FancyZones.gif" />
|
||||
<Content Include="Assets\Modules\OOBE\FileExplorer.png" />
|
||||
<Content Include="Assets\Modules\OOBE\ImageResizer.gif" />
|
||||
@@ -298,6 +308,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>
|
||||
@@ -370,6 +384,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>
|
||||
@@ -448,4 +466,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,6 +81,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/Espresso.png",
|
||||
Description = loader.GetString("Oobe_Espresso_Description"),
|
||||
Link = "https://aka.ms/PowerToysOverview_Espresso",
|
||||
});
|
||||
Modules.Insert((int)PowerToysModulesEnum.FancyZones, new OobePowerToysModule()
|
||||
{
|
||||
ModuleName = loader.GetString("Oobe_FancyZones"),
|
||||
@@ -204,6 +216,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>
|
||||
@@ -480,6 +484,10 @@
|
||||
<data name="ShortcutGuide_Description.Text" xml:space="preserve">
|
||||
<value>Shows a help overlay with Windows shortcuts when the Windows key is pressed.</value>
|
||||
</data>
|
||||
<data name="ShortcutGuide_PressTime.Header" xml:space="preserve">
|
||||
<value>Press duration before showing (ms)</value>
|
||||
<comment>pressing a key in milliseconds</comment>
|
||||
</data>
|
||||
<data name="ShortcutGuide_Appearance_Behavior.Text" xml:space="preserve">
|
||||
<value>Appearance & behavior</value>
|
||||
</data>
|
||||
@@ -904,6 +912,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>
|
||||
@@ -988,6 +1000,43 @@
|
||||
<data name="Run_PluginUseDescription.Text" xml:space="preserve">
|
||||
<value>You can include or remove each plugin from the global results, change the direct activation phrase and configure additional options.</value>
|
||||
</data>
|
||||
<data name="Run_PositionAppearance_GroupSettings.Text" xml:space="preserve">
|
||||
<value>Position & appearance</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>
|
||||
<data name="Run_Radio_Position_Cursor.Content" xml:space="preserve">
|
||||
<value>Monitor with mouse cursor</value>
|
||||
</data>
|
||||
<data name="Run_Radio_Position_Focus.Content" xml:space="preserve">
|
||||
<value>Monitor with focused window</value>
|
||||
</data>
|
||||
<data name="Run_Radio_Position_Primary_Monitor.Content" xml:space="preserve">
|
||||
<value>Primary monitor</value>
|
||||
</data>
|
||||
<data name="Run_PluginsLoading.Text" xml:space="preserve">
|
||||
<value>Plugins are loading...</value>
|
||||
</data>
|
||||
<data name="ColorPicker_ButtonDown.AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Move the color down</value>
|
||||
</data>
|
||||
<data name="ColorPicker_ButtonUp.AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Move the color up</value>
|
||||
</data>
|
||||
<data name="FancyZones_FlashZonesOnQuickSwitch.Content" xml:space="preserve">
|
||||
<value>Flash zones when switching layout</value>
|
||||
</data>
|
||||
<data name="FancyZones_QuickLayoutSwitch.Content" xml:space="preserve">
|
||||
<value>Enable quick layout switch</value>
|
||||
</data>
|
||||
<data name="FancyZones_QuickLayoutSwitch_GroupSettings.Text" xml:space="preserve">
|
||||
<value>Quick layout switch</value>
|
||||
</data>
|
||||
<data name="ShortcutGuide_OpenShortcutGuide.Header" xml:space="preserve">
|
||||
<value>Open Shortcut Guide</value>
|
||||
</data>
|
||||
<data name="Oobe_GetStarted.Text" xml:space="preserve">
|
||||
<value>Let's get started!</value>
|
||||
</data>
|
||||
@@ -1096,7 +1145,7 @@ From there, simply click on a Markdown file or SVG icon in the File Explorer and
|
||||
<value>PowerToys Run supports various action keys to funnel search queries for a specific subset of results. Typing {<} searches for running processes only, {?} will search only for file, or {.} for installed applications! See PowerToys documentation for the complete set of 'Action Keys' available.</value>
|
||||
</data>
|
||||
<data name="Oobe_ShortcutGuide_HowToLaunch.Text" xml:space="preserve">
|
||||
<value>{Shift} + {Win} + {/} to open Shortcut Guide, press it again to close or press {Esc}.</value>
|
||||
<value>{Win} + {?} to open Shortcut Guide, press it again to close or press {Esc}. You can also launch it by holding the {Win} key for one second!</value>
|
||||
</data>
|
||||
<data name="Oobe_TipsAndTricks.Text" xml:space="preserve">
|
||||
<value>Tips & tricks</value>
|
||||
@@ -1160,42 +1209,67 @@ 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 PC 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_NoKeepAwakeContent.Text" xml:space="preserve">
|
||||
<value>Off (Passive)</value>
|
||||
</data>
|
||||
<data name="Run_Radio_Position_Primary_Monitor.Content" xml:space="preserve">
|
||||
<value>Primary monitor</value>
|
||||
<data name="Espresso_IndefiniteKeepAwakeContent.Text" xml:space="preserve">
|
||||
<value>Keep awake indefinitely</value>
|
||||
</data>
|
||||
<data name="Run_PluginsLoading.Text" xml:space="preserve">
|
||||
<value>Plugins are loading...</value>
|
||||
<data name="Espresso_TemporaryKeepAwakeContent.Text" xml:space="preserve">
|
||||
<value>Keep awake temporarily</value>
|
||||
</data>
|
||||
<data name="ColorPicker_ButtonDown.AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Move the color down</value>
|
||||
<data name="Espresso_NoKeepAwakeDescription.Text" xml:space="preserve">
|
||||
<value>Your PC operates according to its current power plan</value>
|
||||
</data>
|
||||
<data name="ColorPicker_ButtonUp.AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Move the color up</value>
|
||||
<data name="Espresso_IndefiniteKeepAwakeDescription.Text" xml:space="preserve">
|
||||
<value>Keeps your PC awake until the setting is disabled</value>
|
||||
</data>
|
||||
<data name="FancyZones_FlashZonesOnQuickSwitch.Content" xml:space="preserve">
|
||||
<value>Flash zones when switching layout</value>
|
||||
<data name="Espresso_TemporaryKeepAwakeDescription.Text" xml:space="preserve">
|
||||
<value>Keeps your PC awake until the set time elapses</value>
|
||||
</data>
|
||||
<data name="FancyZones_QuickLayoutSwitch.Content" xml:space="preserve">
|
||||
<value>Enable quick layout switch</value>
|
||||
<data name="Espresso_EnableDisplayKeepAwake.Content" xml:space="preserve">
|
||||
<value>Keep screen on</value>
|
||||
</data>
|
||||
<data name="FancyZones_QuickLayoutSwitch_GroupSettings.Text" xml:space="preserve">
|
||||
<value>Quick layout switch</value>
|
||||
<data name="Espresso_Mode.Text" xml:space="preserve">
|
||||
<value>Mode</value>
|
||||
</data>
|
||||
<data name="ShortcutGuide_OpenShortcutGuide.Header" xml:space="preserve">
|
||||
<value>Open Shortcut Guide</value>
|
||||
<data name="Espresso_Behavior_GroupSettings.Text" xml:space="preserve">
|
||||
<value>Behavior</value>
|
||||
</data>
|
||||
<data name="Espresso_TemporaryKeepAwake_Hours.Header" xml:space="preserve">
|
||||
<value>Hours</value>
|
||||
</data>
|
||||
<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>Espresso is a Windows tool designed to keep your PC awake on-demand without having to manage its power settings. This behavior can be helpful when running time-consuming tasks while ensuring that your PC does not go to sleep or turn off its screens.</value>
|
||||
</data>
|
||||
<data name="Oobe_Espresso_HowToUse.Text" xml:space="preserve">
|
||||
<value>Open {PowerToys Settings} and enable Espresso</value>
|
||||
</data>
|
||||
<data name="Oobe_Espresso_TipsAndTricks.Text" xml:space="preserve">
|
||||
<value>You can always change modes quickly by {right-clicking the Espresso icon} in the system tray.</value>
|
||||
</data>
|
||||
<data name="General_FailedToDownloadTheNewVersion.Text" xml:space="preserve">
|
||||
<value>An error occurred trying to update to</value>
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
<Page
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.EspressoPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:c="using:Microsoft.PowerToys.Settings.UI.Converters"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="400"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
||||
AutomationProperties.LandmarkType="Main">
|
||||
|
||||
<Page.Resources>
|
||||
<c:EspressoModeToBoolConverter x:Key="EspressoModeToBoolConverter" />
|
||||
</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="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="{x:Bind ViewModel.IsEnabled, Mode=TwoWay}" />
|
||||
|
||||
<TextBlock x:Uid="Espresso_Behavior_GroupSettings"
|
||||
Foreground="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"
|
||||
Style="{StaticResource SettingsGroupTitleStyle}"/>
|
||||
|
||||
<CheckBox x:Uid="Espresso_EnableDisplayKeepAwake"
|
||||
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"
|
||||
IsChecked="{x:Bind ViewModel.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,-8,0,0">
|
||||
<RadioButton x:Uid="Espresso_NoKeepAwake"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"
|
||||
IsChecked="{x:Bind Path=ViewModel.Mode, Mode=TwoWay, Converter={StaticResource EspressoModeToBoolConverter}, ConverterParameter=0}">
|
||||
<RadioButton.Content>
|
||||
<TextBlock TextWrapping="WrapWholeWords" LineHeight="20">
|
||||
<Run x:Uid="Espresso_NoKeepAwakeContent"/>
|
||||
<LineBreak/>
|
||||
<Run Foreground="{ThemeResource SystemBaseMediumColor}"
|
||||
x:Uid="Espresso_NoKeepAwakeDescription"/>
|
||||
</TextBlock>
|
||||
</RadioButton.Content>
|
||||
</RadioButton>
|
||||
<RadioButton x:Uid="Espresso_IndefiniteKeepAwake"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"
|
||||
IsChecked="{x:Bind Path=ViewModel.Mode, Mode=TwoWay, Converter={StaticResource EspressoModeToBoolConverter}, ConverterParameter=1}">
|
||||
<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="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"
|
||||
IsChecked="{x:Bind Path=ViewModel.Mode, Mode=TwoWay, Converter={StaticResource EspressoModeToBoolConverter}, ConverterParameter=2}">
|
||||
<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="{x:Bind ViewModel.Hours, Mode=TwoWay}"
|
||||
Minimum="0"
|
||||
SpinButtonPlacementMode="Compact"
|
||||
HorizontalAlignment="Left"
|
||||
MinWidth="90"
|
||||
IsEnabled="{x:Bind ViewModel.IsTimeConfigurationEnabled, Mode=OneWay}"
|
||||
SmallChange="1"
|
||||
LargeChange="5"/>
|
||||
<muxc:NumberBox x:Uid="Espresso_TemporaryKeepAwake_Minutes"
|
||||
Value="{x:Bind ViewModel.Minutes, Mode=TwoWay}"
|
||||
Minimum="0"
|
||||
SpinButtonPlacementMode="Compact"
|
||||
Margin="8,0,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
IsEnabled="{x:Bind ViewModel.IsTimeConfigurationEnabled, Mode=OneWay}"
|
||||
MinWidth="90"
|
||||
SmallChange="1"
|
||||
LargeChange="5"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</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/Espresso.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'">
|
||||
|
||||
Reference in New Issue
Block a user