mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 11:48:06 +01:00
awake
This commit is contained in:
@@ -829,6 +829,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Workspaces.ModuleServices",
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerToys.ModuleContracts", "src\common\PowerToys.ModuleContracts\PowerToys.ModuleContracts.csproj", "{094E65D5-585E-4898-B465-97A47CD44380}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Awake.ModuleServices", "src\modules\awake\Awake.ModuleServices\Awake.ModuleServices.csproj", "{2141FF78-5F51-ED6B-E11B-C7079CCA1456}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -5255,6 +5257,22 @@ Global
|
||||
{094E65D5-585E-4898-B465-97A47CD44380}.Release|x64.Build.0 = Release|x64
|
||||
{094E65D5-585E-4898-B465-97A47CD44380}.Release|x86.ActiveCfg = Release|x64
|
||||
{094E65D5-585E-4898-B465-97A47CD44380}.Release|x86.Build.0 = Release|x64
|
||||
{2141FF78-5F51-ED6B-E11B-C7079CCA1456}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{2141FF78-5F51-ED6B-E11B-C7079CCA1456}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{2141FF78-5F51-ED6B-E11B-C7079CCA1456}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{2141FF78-5F51-ED6B-E11B-C7079CCA1456}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{2141FF78-5F51-ED6B-E11B-C7079CCA1456}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2141FF78-5F51-ED6B-E11B-C7079CCA1456}.Debug|x64.Build.0 = Debug|x64
|
||||
{2141FF78-5F51-ED6B-E11B-C7079CCA1456}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{2141FF78-5F51-ED6B-E11B-C7079CCA1456}.Debug|x86.Build.0 = Debug|x64
|
||||
{2141FF78-5F51-ED6B-E11B-C7079CCA1456}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{2141FF78-5F51-ED6B-E11B-C7079CCA1456}.Release|Any CPU.Build.0 = Release|x64
|
||||
{2141FF78-5F51-ED6B-E11B-C7079CCA1456}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{2141FF78-5F51-ED6B-E11B-C7079CCA1456}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{2141FF78-5F51-ED6B-E11B-C7079CCA1456}.Release|x64.ActiveCfg = Release|x64
|
||||
{2141FF78-5F51-ED6B-E11B-C7079CCA1456}.Release|x64.Build.0 = Release|x64
|
||||
{2141FF78-5F51-ED6B-E11B-C7079CCA1456}.Release|x86.ActiveCfg = Release|x64
|
||||
{2141FF78-5F51-ED6B-E11B-C7079CCA1456}.Release|x86.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -5588,6 +5606,7 @@ Global
|
||||
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{D52AAF95-DE88-49EA-B28A-10E382BCD4AB} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
|
||||
{094E65D5-585E-4898-B465-97A47CD44380} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{2141FF78-5F51-ED6B-E11B-C7079CCA1456} = {127F38E0-40AA-4594-B955-5616BF206882}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<!-- Look at Directory.Build.props in root for common stuff as well -->
|
||||
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\Common.Dotnet.AotCompatibility.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
<ProjectReference Include="..\..\..\common\interop\PowerToys.Interop.vcxproj" />
|
||||
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
|
||||
<ProjectReference Include="..\..\..\common\PowerToys.ModuleContracts\PowerToys.ModuleContracts.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
79
src/modules/awake/Awake.ModuleServices/AwakeService.cs
Normal file
79
src/modules/awake/Awake.ModuleServices/AwakeService.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
// 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.Diagnostics;
|
||||
using Common.UI;
|
||||
using ManagedCommon;
|
||||
using PowerToys.ModuleContracts;
|
||||
|
||||
namespace Awake.ModuleServices;
|
||||
|
||||
/// <summary>
|
||||
/// Provides CLI-based Awake control for reuse across hosts.
|
||||
/// </summary>
|
||||
public sealed class AwakeService : ModuleServiceBase, IAwakeService
|
||||
{
|
||||
public static AwakeService Instance { get; } = new();
|
||||
|
||||
public override string Key => SettingsDeepLink.SettingsWindow.Awake.ToString();
|
||||
|
||||
protected override SettingsDeepLink.SettingsWindow SettingsWindow => SettingsDeepLink.SettingsWindow.Awake;
|
||||
|
||||
public override Task<OperationResult> LaunchAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
// Default launch -> indefinite, honoring Awake's own settings for display behavior.
|
||||
return SetIndefiniteAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public Task<OperationResult> SetIndefiniteAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return InvokeCliAsync("-m indefinite");
|
||||
}
|
||||
|
||||
public Task<OperationResult> SetTimedAsync(int minutes, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (minutes <= 0)
|
||||
{
|
||||
return Task.FromResult(OperationResult.Fail("Minutes must be greater than zero."));
|
||||
}
|
||||
|
||||
return InvokeCliAsync($"-m timed -t {minutes}");
|
||||
}
|
||||
|
||||
public Task<OperationResult> SetOffAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return InvokeCliAsync("-m passive");
|
||||
}
|
||||
|
||||
private static Task<OperationResult> InvokeCliAsync(string arguments)
|
||||
{
|
||||
try
|
||||
{
|
||||
var basePath = PowerToysPathResolver.GetPowerToysInstallPath();
|
||||
if (string.IsNullOrWhiteSpace(basePath))
|
||||
{
|
||||
return Task.FromResult(OperationResult.Fail("PowerToys install path not found."));
|
||||
}
|
||||
|
||||
var exePath = Path.Combine(basePath, "PowerToys.Awake.exe");
|
||||
if (!File.Exists(exePath))
|
||||
{
|
||||
return Task.FromResult(OperationResult.Fail("Unable to locate PowerToys.Awake.exe."));
|
||||
}
|
||||
|
||||
var startInfo = new ProcessStartInfo(exePath, arguments)
|
||||
{
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
};
|
||||
|
||||
Process.Start(startInfo);
|
||||
return Task.FromResult(OperationResult.Ok());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Task.FromResult(OperationResult.Fail($"Failed to invoke Awake: {ex.Message}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/modules/awake/Awake.ModuleServices/IAwakeService.cs
Normal file
16
src/modules/awake/Awake.ModuleServices/IAwakeService.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using PowerToys.ModuleContracts;
|
||||
|
||||
namespace Awake.ModuleServices;
|
||||
|
||||
public interface IAwakeService : IModuleService
|
||||
{
|
||||
Task<OperationResult> SetIndefiniteAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
Task<OperationResult> SetTimedAsync(int minutes, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<OperationResult> SetOffAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Awake.ModuleServices;
|
||||
|
||||
namespace PowerToysExtension.Commands;
|
||||
|
||||
internal sealed partial class StartAwakeCommand : InvokableCommand
|
||||
{
|
||||
private readonly Func<Task<OperationResult>> _action;
|
||||
private readonly string? _successToast;
|
||||
|
||||
internal StartAwakeCommand(string title, Func<Task<OperationResult>> action, string? successToast = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(action);
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(title);
|
||||
|
||||
_action = action;
|
||||
_successToast = successToast;
|
||||
Name = title;
|
||||
}
|
||||
|
||||
public override CommandResult Invoke()
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = _action().GetAwaiter().GetResult();
|
||||
if (!result.Success)
|
||||
{
|
||||
return CommandResult.ShowToast(result.Error ?? "Failed to start Awake.");
|
||||
}
|
||||
|
||||
return string.IsNullOrWhiteSpace(_successToast) ? CommandResult.Hide() : CommandResult.ShowToast(_successToast);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return CommandResult.ShowToast($"Launching Awake failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// 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.CommandPalette.Extensions.Toolkit;
|
||||
using Awake.ModuleServices;
|
||||
|
||||
namespace PowerToysExtension.Commands;
|
||||
|
||||
internal sealed partial class StopAwakeCommand : InvokableCommand
|
||||
{
|
||||
internal StopAwakeCommand()
|
||||
{
|
||||
Name = "Set Awake to Off";
|
||||
}
|
||||
|
||||
public override CommandResult Invoke()
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = AwakeService.Instance.SetOffAsync().GetAwaiter().GetResult();
|
||||
if (result.Success)
|
||||
{
|
||||
return CommandResult.ShowToast("Awake switched to Off.");
|
||||
}
|
||||
|
||||
return CommandResult.ShowToast(result.Error ?? "Awake does not appear to be running.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return CommandResult.ShowToast($"Failed to switch Awake off: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Helpers;
|
||||
|
||||
namespace PowerToysExtension.Commands;
|
||||
|
||||
internal sealed partial class StartAwakeCommand : InvokableCommand
|
||||
{
|
||||
private readonly Func<string> _argumentsProvider;
|
||||
private readonly string? _successToast;
|
||||
|
||||
internal StartAwakeCommand(string title, Func<string> argumentsProvider, string? successToast = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(argumentsProvider);
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(title);
|
||||
|
||||
_argumentsProvider = argumentsProvider;
|
||||
_successToast = successToast;
|
||||
Name = title;
|
||||
}
|
||||
|
||||
public override CommandResult Invoke()
|
||||
{
|
||||
try
|
||||
{
|
||||
var executablePath = PowerToysPathResolver.TryResolveExecutable("PowerToys.Awake.exe");
|
||||
if (string.IsNullOrEmpty(executablePath))
|
||||
{
|
||||
return CommandResult.ShowToast("Unable to locate PowerToys.Awake.exe.");
|
||||
}
|
||||
|
||||
var arguments = _argumentsProvider()?.Trim() ?? string.Empty;
|
||||
|
||||
var startInfo = new ProcessStartInfo(executablePath)
|
||||
{
|
||||
UseShellExecute = string.IsNullOrWhiteSpace(arguments),
|
||||
CreateNoWindow = true,
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(arguments))
|
||||
{
|
||||
startInfo.Arguments = arguments;
|
||||
startInfo.UseShellExecute = false;
|
||||
}
|
||||
|
||||
Process.Start(startInfo);
|
||||
return string.IsNullOrWhiteSpace(_successToast) ? CommandResult.Hide() : CommandResult.ShowToast(_successToast);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return CommandResult.ShowToast($"Launching Awake failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace PowerToysExtension.Commands;
|
||||
|
||||
internal sealed partial class StopAwakeCommand : InvokableCommand
|
||||
{
|
||||
private const string AwakeWindowClass = "Awake.MessageWindow";
|
||||
private const uint WmCommand = 0x0111;
|
||||
private const int PassiveCommand = 0x0400 + 0x3;
|
||||
|
||||
internal StopAwakeCommand()
|
||||
{
|
||||
Name = "Set Awake to Off";
|
||||
}
|
||||
|
||||
public override CommandResult Invoke()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (TrySendPassiveCommand())
|
||||
{
|
||||
return CommandResult.ShowToast("Awake switched to Off.");
|
||||
}
|
||||
|
||||
return CommandResult.ShowToast("Awake does not appear to be running.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return CommandResult.ShowToast($"Failed to switch Awake off: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TrySendPassiveCommand()
|
||||
{
|
||||
var handle = IntPtr.Zero;
|
||||
var sent = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
handle = FindWindowEx(IntPtr.Zero, handle, AwakeWindowClass, null);
|
||||
if (handle == IntPtr.Zero)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (PostMessage(handle, WmCommand, new IntPtr(PassiveCommand), IntPtr.Zero))
|
||||
{
|
||||
sent = true;
|
||||
}
|
||||
}
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string? className, string? windowTitle);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using Common.UI;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using Awake.ModuleServices;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
|
||||
@@ -19,9 +20,9 @@ internal sealed class AwakeModuleCommandProvider : ModuleCommandProvider
|
||||
|
||||
var more = new List<CommandContextItem>
|
||||
{
|
||||
new CommandContextItem(new StartAwakeCommand("Awake: Keep awake indefinitely", () => "-m indefinite", "Awake set to indefinite")),
|
||||
new CommandContextItem(new StartAwakeCommand("Awake: Keep awake for 30 minutes", () => "-m timed -t 30", "Awake set for 30 minutes")),
|
||||
new CommandContextItem(new StartAwakeCommand("Awake: Keep awake for 2 hours", () => "-m timed -t 120", "Awake set for 2 hours")),
|
||||
new CommandContextItem(new StartAwakeCommand("Awake: Keep awake indefinitely", () => AwakeService.Instance.SetIndefiniteAsync(), "Awake set to indefinite")),
|
||||
new CommandContextItem(new StartAwakeCommand("Awake: Keep awake for 30 minutes", () => AwakeService.Instance.SetTimedAsync(30), "Awake set for 30 minutes")),
|
||||
new CommandContextItem(new StartAwakeCommand("Awake: Keep awake for 2 hours", () => AwakeService.Instance.SetTimedAsync(120), "Awake set for 2 hours")),
|
||||
new CommandContextItem(new StopAwakeCommand()),
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user