Disable sleep idle timeout when audio is playing via SetThreadExecutionState.
This commit is contained in:
@@ -102,5 +102,6 @@
|
||||
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
|
||||
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
|
||||
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,6 +1,9 @@
|
||||
using Harmonia.Core.Player;
|
||||
using Harmonia.WinUI.Session;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Harmonia.WinUI;
|
||||
|
||||
@@ -8,16 +11,23 @@ public sealed partial class MainWindow : Window
|
||||
{
|
||||
private const string ApplicationTitle = "Harmonia";
|
||||
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
private static partial EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
|
||||
|
||||
private readonly ISessionService _sessionService;
|
||||
private readonly ISessionTracker _sessionTracker;
|
||||
private readonly IAudioPlayer _audioPlayer;
|
||||
|
||||
private bool _isSaved;
|
||||
|
||||
public MainWindow(ISessionService sessionService, ISessionTracker sessionTracker)
|
||||
public MainWindow(ISessionService sessionService, ISessionTracker sessionTracker, IAudioPlayer audioPlayer)
|
||||
{
|
||||
_sessionService = sessionService;
|
||||
_sessionTracker = sessionTracker;
|
||||
|
||||
_audioPlayer = audioPlayer;
|
||||
_audioPlayer.PropertyChanged += OnAudioPlayerPropertyChanged;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeTitleBar();
|
||||
InitializeWindowState();
|
||||
@@ -54,6 +64,8 @@ public sealed partial class MainWindow : Window
|
||||
|
||||
private async void OnMainWindowClosed(object sender, WindowEventArgs args)
|
||||
{
|
||||
EnableSleepIdleTimeout();
|
||||
|
||||
if (_isSaved)
|
||||
return;
|
||||
|
||||
@@ -65,4 +77,53 @@ public sealed partial class MainWindow : Window
|
||||
_isSaved = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void OnAudioPlayerPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
case nameof(_audioPlayer.State):
|
||||
OnAudioPlayerStateChanged(sender, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAudioPlayerStateChanged(object? sender, EventArgs e)
|
||||
{
|
||||
// SetThreadExecutionState is per-thread, so always marshal to the UI thread to
|
||||
// guarantee the ES_CONTINUOUS flags are set and cleared on the same thread.
|
||||
DispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
switch (_audioPlayer.State)
|
||||
{
|
||||
case Core.Engine.AudioPlaybackState.Playing:
|
||||
DisableSleepIdleTimeout();
|
||||
break;
|
||||
default:
|
||||
EnableSleepIdleTimeout();
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void EnableSleepIdleTimeout()
|
||||
{
|
||||
// Clear EXECUTION_STATE flags to allow the system to idle to sleep normally.
|
||||
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS);
|
||||
}
|
||||
|
||||
private static void DisableSleepIdleTimeout()
|
||||
{
|
||||
// Prevent the system sleep idle time-out while still allowing the display to sleep.
|
||||
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS | EXECUTION_STATE.ES_SYSTEM_REQUIRED);
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum EXECUTION_STATE : uint
|
||||
{
|
||||
ES_CONTINUOUS = 0x80000000,
|
||||
ES_SYSTEM_REQUIRED = 0x00000001,
|
||||
ES_DISPLAY_REQUIRED = 0x00000002,
|
||||
ES_AWAYMODE_REQUIRED = 0x00000040
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user