mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-07 11:46:30 +02:00
Updating the threading model for timed keep-awake
This commit is contained in:
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Espresso.Shell.Core
|
namespace Espresso.Shell.Core
|
||||||
{
|
{
|
||||||
@@ -22,6 +24,9 @@ namespace Espresso.Shell.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class APIHelper
|
public class APIHelper
|
||||||
{
|
{
|
||||||
|
private static CancellationTokenSource TokenSource = new CancellationTokenSource();
|
||||||
|
private static CancellationToken ThreadToken;
|
||||||
|
|
||||||
// More details about the API used: https://docs.microsoft.com/windows/win32/api/winbase/nf-winbase-setthreadexecutionstate
|
// More details about the API used: https://docs.microsoft.com/windows/win32/api/winbase/nf-winbase-setthreadexecutionstate
|
||||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||||
static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
|
static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
|
||||||
@@ -58,6 +63,7 @@ namespace Espresso.Shell.Core
|
|||||||
|
|
||||||
public static bool SetNormalKeepAwake()
|
public static bool SetNormalKeepAwake()
|
||||||
{
|
{
|
||||||
|
//TokenSource.Cancel();
|
||||||
return SetAwakeState(EXECUTION_STATE.ES_CONTINUOUS);
|
return SetAwakeState(EXECUTION_STATE.ES_CONTINUOUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,43 +79,74 @@ namespace Espresso.Shell.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool SetTimedKeepAwake(long seconds, bool keepDisplayOn = true)
|
public static void SetTimedKeepAwake(long seconds, Action<bool> callback, bool keepDisplayOn = true)
|
||||||
{
|
{
|
||||||
|
ThreadToken = TokenSource.Token;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Task.Run(() => RunTimedLoop(seconds, keepDisplayOn), ThreadToken).ContinueWith((result) => callback(result.Result));
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException e)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{nameof(OperationCanceledException)} thrown with message: {e.Message}");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
TokenSource.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool RunTimedLoop(long seconds, bool keepDisplayOn = true)
|
||||||
|
{
|
||||||
|
bool success;
|
||||||
|
|
||||||
|
// In case cancellation was already requested.
|
||||||
|
//ThreadToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
if (keepDisplayOn)
|
if (keepDisplayOn)
|
||||||
{
|
{
|
||||||
var success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
|
success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
RunTimedLoop(seconds);
|
Console.WriteLine("Timed keep-awake with display on.");
|
||||||
return true;
|
var startTime = DateTime.UtcNow;
|
||||||
|
while (DateTime.UtcNow - startTime < TimeSpan.FromSeconds(seconds))
|
||||||
|
{
|
||||||
|
if (ThreadToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
ThreadToken.ThrowIfCancellationRequested();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
|
success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
RunTimedLoop(seconds);
|
Console.WriteLine("Timed keep-awake with display off.");
|
||||||
return true;
|
var startTime = DateTime.UtcNow;
|
||||||
|
while (DateTime.UtcNow - startTime < TimeSpan.FromSeconds(seconds))
|
||||||
|
{
|
||||||
|
if (ThreadToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
ThreadToken.ThrowIfCancellationRequested();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RunTimedLoop(long seconds)
|
|
||||||
{
|
|
||||||
var startTime = DateTime.UtcNow;
|
|
||||||
while (DateTime.UtcNow - startTime < TimeSpan.FromSeconds(seconds))
|
|
||||||
{
|
|
||||||
// We do nothing.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,20 +141,20 @@ namespace Espresso.Shell
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Timed keep-awake.
|
// Timed keep-awake.
|
||||||
bool success = APIHelper.SetTimedKeepAwake(timeLimit, displayOn);
|
APIHelper.SetTimedKeepAwake(timeLimit, LogTimedKeepAwakeCompletion, displayOn);
|
||||||
if (success)
|
//if (success)
|
||||||
{
|
//{
|
||||||
Console.WriteLine($"Finished execution of timed keep-awake.");
|
// Console.WriteLine($"Finished execution of timed keep-awake.");
|
||||||
|
|
||||||
// Because the timed keep-awake execution completed, there is no reason for
|
// // Because the timed keep-awake execution completed, there is no reason for
|
||||||
// Espresso to stay alive - I will just shut down the application until it's
|
// // Espresso to stay alive - I will just shut down the application until it's
|
||||||
// launched again by the user.
|
// // launched again by the user.
|
||||||
Environment.Exit(0);
|
// Environment.Exit(0);
|
||||||
}
|
//}
|
||||||
else
|
//else
|
||||||
{
|
//{
|
||||||
Console.WriteLine("Could not set up the state to be timed keep awake.");
|
// Console.WriteLine("Could not set up the state to be timed keep awake.");
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,6 +163,8 @@ namespace Espresso.Shell
|
|||||||
|
|
||||||
private static void HandleEspressoConfigChange(object sender, FileSystemEventArgs e)
|
private static void HandleEspressoConfigChange(object sender, FileSystemEventArgs e)
|
||||||
{
|
{
|
||||||
|
Console.WriteLine("Resetting keep-awake to normal state due to settings change.");
|
||||||
|
ResetNormalPowerState();
|
||||||
Console.WriteLine("Detected a file change. Reacting...");
|
Console.WriteLine("Detected a file change. Reacting...");
|
||||||
ProcessSettings(e.FullPath);
|
ProcessSettings(e.FullPath);
|
||||||
}
|
}
|
||||||
@@ -210,22 +212,22 @@ namespace Espresso.Shell
|
|||||||
long computedTime = (settings.Properties.Hours.Value * 60 * 60) + (settings.Properties.Minutes.Value * 60);
|
long computedTime = (settings.Properties.Hours.Value * 60 * 60) + (settings.Properties.Minutes.Value * 60);
|
||||||
Console.WriteLine($"In timed keep-awake mode. Expecting to be awake for {computedTime} seconds.");
|
Console.WriteLine($"In timed keep-awake mode. Expecting to be awake for {computedTime} seconds.");
|
||||||
|
|
||||||
bool success = APIHelper.SetTimedKeepAwake(computedTime, settings.Properties.KeepDisplayOn.Value);
|
APIHelper.SetTimedKeepAwake(computedTime, LogTimedKeepAwakeCompletion, settings.Properties.KeepDisplayOn.Value);
|
||||||
if (success)
|
//if (success)
|
||||||
{
|
//{
|
||||||
Console.WriteLine($"Finished execution of timed keep-awake.");
|
// Console.WriteLine($"Finished execution of timed keep-awake.");
|
||||||
|
|
||||||
ResetNormalPowerState();
|
// ResetNormalPowerState();
|
||||||
}
|
//}
|
||||||
else
|
//else
|
||||||
{
|
//{
|
||||||
Console.WriteLine("Could not set up the state to be timed keep awake.");
|
// Console.WriteLine("Could not set up the state to be timed keep awake.");
|
||||||
}
|
//}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
ForceExit("Could not select the right mode of operation. Existing...", 1);
|
Console.WriteLine("Unknown mode of operation. Check config file.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,6 +248,11 @@ namespace Espresso.Shell
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void LogTimedKeepAwakeCompletion(bool result)
|
||||||
|
{
|
||||||
|
Console.Write($"Completed timed keep-awake successfully: {result}");
|
||||||
|
}
|
||||||
|
|
||||||
private static void ResetNormalPowerState()
|
private static void ResetNormalPowerState()
|
||||||
{
|
{
|
||||||
bool success = APIHelper.SetNormalKeepAwake();
|
bool success = APIHelper.SetNormalKeepAwake();
|
||||||
|
|||||||
Reference in New Issue
Block a user