diff --git a/ColorControl/ColorControl.csproj b/ColorControl/ColorControl.csproj index 403a92c..d71a006 100644 --- a/ColorControl/ColorControl.csproj +++ b/ColorControl/ColorControl.csproj @@ -18,8 +18,8 @@ Maassoft Maassoft 0 - 9.8.2.0 - 9.8.2.0 + 9.8.2.1 + 9.8.2.1 false true false diff --git a/ColorControl/MainForm.cs b/ColorControl/MainForm.cs index 3187676..4a460d7 100644 --- a/ColorControl/MainForm.cs +++ b/ColorControl/MainForm.cs @@ -1,13 +1,13 @@ using ColorControl.Forms; using ColorControl.Services.AMD; using ColorControl.Services.Common; -using ColorControl.Services.EventDispatcher; using ColorControl.Services.GameLauncher; using ColorControl.Services.LG; using ColorControl.Services.NVIDIA; using ColorControl.Services.Samsung; using ColorControl.Shared.Common; using ColorControl.Shared.Contracts; +using ColorControl.Shared.EventDispatcher; using ColorControl.Shared.Forms; using ColorControl.Shared.Native; using ColorControl.Shared.Services; diff --git a/ColorControl/Program.cs b/ColorControl/Program.cs index fc84fbb..6590a95 100644 --- a/ColorControl/Program.cs +++ b/ColorControl/Program.cs @@ -1,12 +1,12 @@ using ColorControl.Forms; using ColorControl.Services.Common; -using ColorControl.Services.EventDispatcher; using ColorControl.Services.GameLauncher; using ColorControl.Services.LG; using ColorControl.Services.NVIDIA; using ColorControl.Services.Samsung; using ColorControl.Shared.Common; using ColorControl.Shared.Contracts; +using ColorControl.Shared.EventDispatcher; using ColorControl.Shared.Native; using ColorControl.Shared.Services; using ColorControl.Svc; @@ -73,11 +73,6 @@ namespace ColorControl return; } - var host = CreateHostBuilder().Build(); - ServiceProvider = host.Services; - - var mutexId = $"Global\\{typeof(MainForm).GUID}"; - var currentDomain = AppDomain.CurrentDomain; // Handler for unhandled exceptions. currentDomain.UnhandledException += GlobalUnhandledExceptionHandler; @@ -86,16 +81,24 @@ namespace ColorControl LoadConfig(); + if (Config.UseGdiScaling) + { + var result = Application.SetHighDpiMode(HighDpiMode.DpiUnawareGdiScaled); + + Logger.Debug($"Result of setting SetHighDpiMode: {result}"); + } + + var host = CreateHostBuilder().Build(); + ServiceProvider = host.Services; + + var mutexId = $"Global\\{typeof(MainForm).GUID}"; + var appContextProvider = ServiceProvider.GetRequiredService(); var startUpParams = StartUpParams.Parse(args); AppContext = new GlobalContext(Config, startUpParams, DataDir, _loggingRule, mutexId); appContextProvider.SetAppContext(AppContext); - if (Config.UseGdiScaling) - { - Application.SetHighDpiMode(HighDpiMode.DpiUnawareGdiScaled); - } var existingProcess = Utils.GetProcessByName("ColorControl"); diff --git a/ColorControl/Services/Common/PresetBase.cs b/ColorControl/Services/Common/PresetBase.cs index fa47a87..2de771a 100644 --- a/ColorControl/Services/Common/PresetBase.cs +++ b/ColorControl/Services/Common/PresetBase.cs @@ -1,6 +1,6 @@ -using ColorControl.Services.EventDispatcher; -using ColorControl.Shared.Common; +using ColorControl.Shared.Common; using ColorControl.Shared.Contracts; +using ColorControl.Shared.EventDispatcher; using NStandard; using System; using System.Collections.Generic; diff --git a/ColorControl/Services/Common/ServiceBase.cs b/ColorControl/Services/Common/ServiceBase.cs index d790320..073ce6a 100644 --- a/ColorControl/Services/Common/ServiceBase.cs +++ b/ColorControl/Services/Common/ServiceBase.cs @@ -1,4 +1,4 @@ -using ColorControl.Services.EventDispatcher; +using ColorControl.Shared.EventDispatcher; using ColorControl.Shared.Native; using ColorControl.Shared.Services; using Newtonsoft.Json; diff --git a/ColorControl/Services/EventDispatcher/EventExtensions.cs b/ColorControl/Services/EventDispatcher/EventExtensions.cs deleted file mode 100644 index 071da6d..0000000 --- a/ColorControl/Services/EventDispatcher/EventExtensions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace ColorControl.Services.EventDispatcher -{ - public static class EventExtensions - { - public delegate Task AsyncEventHandler(object sender, TEventArgs e, CancellationToken token); - - public static Task InvokeAsync(this AsyncEventHandler func, object sender, TArgs e) - { - return func == null ? Task.CompletedTask - : Task.WhenAll(func.GetInvocationList().Cast>().Select(f => f(sender, e, CancellationToken.None))); - } - } -} diff --git a/ColorControl/Services/EventDispatcher/PowerEventDispatcher.cs b/ColorControl/Services/EventDispatcher/PowerEventDispatcher.cs deleted file mode 100644 index 11ca589..0000000 --- a/ColorControl/Services/EventDispatcher/PowerEventDispatcher.cs +++ /dev/null @@ -1,117 +0,0 @@ -using Microsoft.Win32; -using NWin32; -using System; -using System.Threading.Tasks; - -namespace ColorControl.Services.EventDispatcher -{ - public enum PowerOnOffState - { - None = 0, - StartUp = 1, - Resume = 2, - ScreenSaver = 3, - ShutDown = 4, - StandBy = 5, - MonitorOff = 6, - MonitorOn = 7 - } - - internal enum WindowsMonitorPowerSetting - { - Off = 0, - On = 1, - Dimmed = 2 - } - - public class PowerStateChangedEventArgs : EventArgs - { - public PowerOnOffState State { get; private set; } - - public PowerStateChangedEventArgs(PowerOnOffState state) - { - State = state; - } - } - - public class PowerEventDispatcher : EventDispatcher - { - public const string Event_Suspend = "Suspend"; - public const string Event_Resume = "Resume"; - public const string Event_Startup = "Startup"; - public const string Event_Shutdown = "Shutdown"; - public const string Event_MonitorOff = "MonitorOff"; - public const string Event_MonitorOn = "MonitorOn"; - - private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); - - public PowerEventDispatcher() - { - SystemEvents.PowerModeChanged += OnPowerModeChanged; - } - - public void SendEvent(string eventName) - { - var state = eventName switch - { - Event_Shutdown => PowerOnOffState.ShutDown, - Event_Startup => PowerOnOffState.StartUp, - Event_MonitorOff => PowerOnOffState.MonitorOff, - Event_MonitorOn => PowerOnOffState.MonitorOn, - _ => PowerOnOffState.None - }; - - if (state == PowerOnOffState.None) - { - return; - } - - if (state == PowerOnOffState.ShutDown) - { - DispatchEventWithExecutionState(Event_Shutdown, PowerOnOffState.ShutDown); - return; - } - - DispatchEvent(eventName, new PowerStateChangedEventArgs(state)); - } - - public async Task SendEventAsync(string eventName) - { - var state = eventName switch - { - Event_Startup => PowerOnOffState.StartUp, - _ => PowerOnOffState.None - }; - - await DispatchEventAsync(eventName, new PowerStateChangedEventArgs(state)); - } - - private async void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e) - { - if (e.Mode == PowerModes.Suspend) - { - DispatchEventWithExecutionState(Event_Suspend, PowerOnOffState.StandBy); - } - else if (e.Mode == PowerModes.Resume) - { - await DispatchEventAsync(Event_Resume, new PowerStateChangedEventArgs(PowerOnOffState.Resume)); - DispatchEvent(Event_Resume, new PowerStateChangedEventArgs(PowerOnOffState.Resume)); - } - } - - private void DispatchEventWithExecutionState(string eventName, PowerOnOffState powerState) - { - var error = NativeMethods.SetThreadExecutionState(NativeConstants.ES_CONTINUOUS | NativeConstants.ES_SYSTEM_REQUIRED | NativeConstants.ES_AWAYMODE_REQUIRED); - try - { - Logger.Debug($"SetThreadExecutionState: {error}, Thread#: {Environment.CurrentManagedThreadId}"); - DispatchEvent(eventName, new PowerStateChangedEventArgs(powerState)); - } - finally - { - var error2 = NativeMethods.SetThreadExecutionState(NativeConstants.ES_CONTINUOUS); - Logger.Debug($"SetThreadExecutionState (reset): {error2}, Thread#: {Environment.CurrentManagedThreadId}"); - } - } - } -} diff --git a/ColorControl/Services/EventDispatcher/ProcessEventDispatcher.cs b/ColorControl/Services/EventDispatcher/ProcessEventDispatcher.cs deleted file mode 100644 index 4ffc2b5..0000000 --- a/ColorControl/Services/EventDispatcher/ProcessEventDispatcher.cs +++ /dev/null @@ -1,141 +0,0 @@ -using ColorControl.Shared.Common; -using ColorControl.Shared.Forms; -using ColorControl.Shared.Services; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Management; -using System.Threading.Tasks; - -namespace ColorControl.Services.EventDispatcher -{ - public enum ScreenSaverTransitionState - { - None = 0, - Started = 1, - Running = 2, - Stopped = 3 - } - - public class ProcessChangedEventArgs : EventArgs - { - public IList StartedProcesses { get; set; } - public IList StoppedProcesses { get; set; } - public IList RunningProcesses { get; set; } - public bool IsNotificationDisabled { get; set; } - public Process ForegroundProcess { get; set; } - public bool ForegroundProcessIsFullScreen { get; set; } - public string LastFullScreenProcessName = string.Empty; - public bool StoppedFullScreen { get; set; } - public bool IsScreenSaverActive { get; set; } - public ScreenSaverTransitionState ScreenSaverTransitionState { get; set; } - } - - - public class ProcessEventDispatcher : EventDispatcher - { - public const string Event_ProcessChanged = "ProcessChanged"; - public bool IsRunning { get; set; } - public ProcessChangedEventArgs MonitorContext { get; private set; } - - protected static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); - - private AppContextProvider _appContextProvider { get; } - - public ProcessEventDispatcher(AppContextProvider appContextProvider) - { - _appContextProvider = appContextProvider; - - IsRunning = true; - - //Task.Run(async () => await CheckProcesses()); - - var _ = CheckProcesses(); - } - - private async Task CheckProcesses() - { - await Task.Delay(2000); - - //var startWatch = new ManagementEventWatcher("SELECT * FROM Win32_ProcessStartTrace"); - //startWatch.EventArrived += startWatch_EventArrived; - //startWatch.Start(); - - MonitorContext ??= new ProcessChangedEventArgs(); - - while (IsRunning) - { - await Task.Delay(_appContextProvider.GetAppContext().Config.ProcessMonitorPollingInterval); - - if (!HasHandlers(Event_ProcessChanged)) - { - continue; - } - - try - { - FillContext(MonitorContext); - - // Ignore if own process has the foreground - if (MonitorContext.ForegroundProcess?.Id == Environment.ProcessId) - { - continue; - } - - await DispatchEventAsync(Event_ProcessChanged, MonitorContext); - DispatchEvent(Event_ProcessChanged, MonitorContext); - } - catch (Exception ex) - { - Logger.Error("CheckProcesses: " + ex.ToLogString()); - } - } - } - - private void FillContext(ProcessChangedEventArgs context) - { - var processes = Process.GetProcesses(); - - context.StartedProcesses = processes.Where(p => context.RunningProcesses?.Any(rp => rp.Id == p.Id) == false).ToList(); - context.StoppedProcesses = context.RunningProcesses?.Where(p => processes.Any(rp => rp.Id == p.Id) == false).ToList(); - context.RunningProcesses = processes; - - context.IsNotificationDisabled = FormUtils.IsNotificationDisabled(); - - var (processId, isFullScreen) = FormUtils.GetForegroundProcessIdAndIfFullScreen(); - - if (processId > 0) - { - var process = context.RunningProcesses.FirstOrDefault(p => p.Id == processId); - - var screenSaverActive = process?.ProcessName?.Contains(".scr") == true; - - context.IsScreenSaverActive = screenSaverActive; - context.ScreenSaverTransitionState = screenSaverActive ? - context.ScreenSaverTransitionState == ScreenSaverTransitionState.None ? ScreenSaverTransitionState.Started : ScreenSaverTransitionState.Running : - context.ScreenSaverTransitionState == ScreenSaverTransitionState.Running ? ScreenSaverTransitionState.Stopped : ScreenSaverTransitionState.None; - context.ForegroundProcess = process; - context.ForegroundProcessIsFullScreen = isFullScreen; - - if (isFullScreen) - { - context.LastFullScreenProcessName = context.ForegroundProcess.ProcessName; - //Logger.Debug($"Foreground fullscreen app detected: {context.ForegroundProcess.ProcessName}"); - } - } - else - { - context.StoppedFullScreen = context.ForegroundProcessIsFullScreen; - context.ForegroundProcess = null; - context.ForegroundProcessIsFullScreen = false; - context.LastFullScreenProcessName = string.Empty; - } - } - - private void startWatch_EventArrived(object sender, EventArrivedEventArgs e) - { - //Logger.Debug("Process started: " + e.NewEvent.Properties["ProcessName"].Value); - } - } -} diff --git a/ColorControl/Services/EventDispatcher/SessionSwitchDispatcher.cs b/ColorControl/Services/EventDispatcher/SessionSwitchDispatcher.cs deleted file mode 100644 index 413ae9b..0000000 --- a/ColorControl/Services/EventDispatcher/SessionSwitchDispatcher.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Microsoft.Win32; - -namespace ColorControl.Services.EventDispatcher -{ - public class SessionSwitchDispatcher : EventDispatcher - { - public const string Event_SessionSwitch = "SessionSwitch"; - - private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); - - public bool UserLocalSession { get; private set; } = true; - public SessionSwitchReason LastSessionSwitchReason { get; private set; } = 0; - - public SessionSwitchDispatcher() - { - SystemEvents.SessionSwitch += SessionSwitchHandler; - } - - public void SessionSwitchHandler(object sender, SessionSwitchEventArgs evt) - { - if (evt.Reason == SessionSwitchReason.ConsoleDisconnect) - { - Logger.Debug("Detected a disconnect from the console"); - UserLocalSession = false; - - DispatchEvent(Event_SessionSwitch, evt); - } - else if (evt.Reason == SessionSwitchReason.ConsoleConnect) - { - Logger.Debug("Detected a connect to the console"); - if (!UserLocalSession) - { - Logger.Debug("Session state switched to local"); - UserLocalSession = true; - DispatchEvent(Event_SessionSwitch, evt); - } - } - LastSessionSwitchReason = evt.Reason; - } - } -} diff --git a/ColorControl/Services/GameLauncher/GameService.cs b/ColorControl/Services/GameLauncher/GameService.cs index 21ba132..79490f9 100644 --- a/ColorControl/Services/GameLauncher/GameService.cs +++ b/ColorControl/Services/GameLauncher/GameService.cs @@ -1,6 +1,6 @@ using ColorControl.Services.Common; -using ColorControl.Services.EventDispatcher; using ColorControl.Shared.Common; +using ColorControl.Shared.EventDispatcher; using ColorControl.Shared.Services; using Newtonsoft.Json; using System; diff --git a/ColorControl/Services/LG/LgPanel.cs b/ColorControl/Services/LG/LgPanel.cs index 51125c2..ee45323 100644 --- a/ColorControl/Services/LG/LgPanel.cs +++ b/ColorControl/Services/LG/LgPanel.cs @@ -1,9 +1,9 @@ using ColorControl.Services.AMD; using ColorControl.Services.Common; -using ColorControl.Services.EventDispatcher; using ColorControl.Services.NVIDIA; using ColorControl.Shared.Common; using ColorControl.Shared.Contracts; +using ColorControl.Shared.EventDispatcher; using ColorControl.Shared.Forms; using ColorControl.Shared.Native; using LgTv; diff --git a/ColorControl/Services/LG/LgService.cs b/ColorControl/Services/LG/LgService.cs index a79214e..86897b0 100644 --- a/ColorControl/Services/LG/LgService.cs +++ b/ColorControl/Services/LG/LgService.cs @@ -1,7 +1,7 @@ using ColorControl.Services.Common; -using ColorControl.Services.EventDispatcher; using ColorControl.Shared.Common; using ColorControl.Shared.Contracts; +using ColorControl.Shared.EventDispatcher; using ColorControl.Shared.Native; using ColorControl.Shared.Services; using LgTv; diff --git a/ColorControl/Services/NVIDIA/NvService.cs b/ColorControl/Services/NVIDIA/NvService.cs index 8b56f7d..69b41d4 100644 --- a/ColorControl/Services/NVIDIA/NvService.cs +++ b/ColorControl/Services/NVIDIA/NvService.cs @@ -1,8 +1,8 @@ using ColorControl.Services.Common; -using ColorControl.Services.EventDispatcher; using ColorControl.Shared.Common; using ColorControl.Shared.Contracts; using ColorControl.Shared.Contracts.NVIDIA; +using ColorControl.Shared.EventDispatcher; using ColorControl.Shared.Forms; using ColorControl.Shared.Native; using ColorControl.Shared.Services; diff --git a/ColorControl/Services/Samsung/SamsungPanel.cs b/ColorControl/Services/Samsung/SamsungPanel.cs index cdf90f2..4a102e3 100644 --- a/ColorControl/Services/Samsung/SamsungPanel.cs +++ b/ColorControl/Services/Samsung/SamsungPanel.cs @@ -1,9 +1,9 @@ using ColorControl.Services.AMD; using ColorControl.Services.Common; -using ColorControl.Services.EventDispatcher; using ColorControl.Services.NVIDIA; using ColorControl.Shared.Common; using ColorControl.Shared.Contracts; +using ColorControl.Shared.EventDispatcher; using ColorControl.Shared.Forms; using ColorControl.Shared.Native; using NLog; diff --git a/ColorControl/Services/Samsung/SamsungService.cs b/ColorControl/Services/Samsung/SamsungService.cs index a048360..cb71848 100644 --- a/ColorControl/Services/Samsung/SamsungService.cs +++ b/ColorControl/Services/Samsung/SamsungService.cs @@ -1,6 +1,6 @@ using ColorControl.Services.Common; -using ColorControl.Services.EventDispatcher; using ColorControl.Shared.Common; +using ColorControl.Shared.EventDispatcher; using ColorControl.Shared.Native; using ColorControl.Shared.Services; using Microsoft.Extensions.DependencyInjection; diff --git a/ColorControl/Svc/ColorControlBackgroundService.cs b/ColorControl/Svc/ColorControlBackgroundService.cs index 4bb9998..c24324b 100644 --- a/ColorControl/Svc/ColorControlBackgroundService.cs +++ b/ColorControl/Svc/ColorControlBackgroundService.cs @@ -1,7 +1,7 @@ -using ColorControl.Services.EventDispatcher; -using ColorControl.Services.LG; +using ColorControl.Services.LG; using ColorControl.Shared.Common; using ColorControl.Shared.Contracts; +using ColorControl.Shared.EventDispatcher; using ColorControl.Shared.Services; using Microsoft.Extensions.Hosting; using Newtonsoft.Json; diff --git a/ColorControl/Services/EventDispatcher/EventDispatcher.cs b/Shared/EventDispatcher/EventDispatcher.cs similarity index 89% rename from ColorControl/Services/EventDispatcher/EventDispatcher.cs rename to Shared/EventDispatcher/EventDispatcher.cs index 08fae03..b4f3e9c 100644 --- a/ColorControl/Services/EventDispatcher/EventDispatcher.cs +++ b/Shared/EventDispatcher/EventDispatcher.cs @@ -1,9 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using static ColorControl.Services.EventDispatcher.EventExtensions; +using static ColorControl.Shared.EventDispatcher.EventExtensions; -namespace ColorControl.Services.EventDispatcher; +namespace ColorControl.Shared.EventDispatcher; public class EventDispatcher where T : EventArgs { diff --git a/Shared/EventDispatcher/EventExtensions.cs b/Shared/EventDispatcher/EventExtensions.cs new file mode 100644 index 0000000..e345850 --- /dev/null +++ b/Shared/EventDispatcher/EventExtensions.cs @@ -0,0 +1,12 @@ +namespace ColorControl.Shared.EventDispatcher; + +public static class EventExtensions +{ + public delegate Task AsyncEventHandler(object sender, TEventArgs e, CancellationToken token); + + public static Task InvokeAsync(this AsyncEventHandler func, object sender, TArgs e) + { + return func == null ? Task.CompletedTask + : Task.WhenAll(func.GetInvocationList().Cast>().Select(f => f(sender, e, CancellationToken.None))); + } +} diff --git a/Shared/EventDispatcher/PowerEventDispatcher.cs b/Shared/EventDispatcher/PowerEventDispatcher.cs new file mode 100644 index 0000000..4a077fe --- /dev/null +++ b/Shared/EventDispatcher/PowerEventDispatcher.cs @@ -0,0 +1,114 @@ +using Microsoft.Win32; +using NWin32; + +namespace ColorControl.Shared.EventDispatcher; + +public enum PowerOnOffState +{ + None = 0, + StartUp = 1, + Resume = 2, + ScreenSaver = 3, + ShutDown = 4, + StandBy = 5, + MonitorOff = 6, + MonitorOn = 7 +} + +public enum WindowsMonitorPowerSetting +{ + Off = 0, + On = 1, + Dimmed = 2 +} + +public class PowerStateChangedEventArgs : EventArgs +{ + public PowerOnOffState State { get; private set; } + + public PowerStateChangedEventArgs(PowerOnOffState state) + { + State = state; + } +} + +public class PowerEventDispatcher : EventDispatcher +{ + public const string Event_Suspend = "Suspend"; + public const string Event_Resume = "Resume"; + public const string Event_Startup = "Startup"; + public const string Event_Shutdown = "Shutdown"; + public const string Event_MonitorOff = "MonitorOff"; + public const string Event_MonitorOn = "MonitorOn"; + + private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); + + public PowerEventDispatcher() + { + SystemEvents.PowerModeChanged += OnPowerModeChanged; + } + + public void SendEvent(string eventName) + { + var state = eventName switch + { + Event_Shutdown => PowerOnOffState.ShutDown, + Event_Startup => PowerOnOffState.StartUp, + Event_MonitorOff => PowerOnOffState.MonitorOff, + Event_MonitorOn => PowerOnOffState.MonitorOn, + _ => PowerOnOffState.None + }; + + if (state == PowerOnOffState.None) + { + return; + } + + if (state == PowerOnOffState.ShutDown) + { + DispatchEventWithExecutionState(Event_Shutdown, PowerOnOffState.ShutDown); + return; + } + + DispatchEvent(eventName, new PowerStateChangedEventArgs(state)); + } + + public async Task SendEventAsync(string eventName) + { + var state = eventName switch + { + Event_Startup => PowerOnOffState.StartUp, + _ => PowerOnOffState.None + }; + + await DispatchEventAsync(eventName, new PowerStateChangedEventArgs(state)); + } + + private async void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e) + { + if (e.Mode == PowerModes.Suspend) + { + DispatchEventWithExecutionState(Event_Suspend, PowerOnOffState.StandBy); + } + else if (e.Mode == PowerModes.Resume) + { + await DispatchEventAsync(Event_Resume, new PowerStateChangedEventArgs(PowerOnOffState.Resume)); + DispatchEvent(Event_Resume, new PowerStateChangedEventArgs(PowerOnOffState.Resume)); + } + } + + private void DispatchEventWithExecutionState(string eventName, PowerOnOffState powerState) + { + var error = NativeMethods.SetThreadExecutionState(NativeConstants.ES_CONTINUOUS | NativeConstants.ES_SYSTEM_REQUIRED | NativeConstants.ES_AWAYMODE_REQUIRED); + try + { + Logger.Debug($"SetThreadExecutionState: {error}, Thread#: {Environment.CurrentManagedThreadId}"); + DispatchEvent(eventName, new PowerStateChangedEventArgs(powerState)); + } + finally + { + var error2 = NativeMethods.SetThreadExecutionState(NativeConstants.ES_CONTINUOUS); + Logger.Debug($"SetThreadExecutionState (reset): {error2}, Thread#: {Environment.CurrentManagedThreadId}"); + } + } +} diff --git a/Shared/EventDispatcher/ProcessEventDispatcher.cs b/Shared/EventDispatcher/ProcessEventDispatcher.cs new file mode 100644 index 0000000..bea6d5b --- /dev/null +++ b/Shared/EventDispatcher/ProcessEventDispatcher.cs @@ -0,0 +1,136 @@ +using ColorControl.Shared.Common; +using ColorControl.Shared.Forms; +using ColorControl.Shared.Services; +using System.Diagnostics; +using System.Management; + +namespace ColorControl.Shared.EventDispatcher; + +public enum ScreenSaverTransitionState +{ + None = 0, + Started = 1, + Running = 2, + Stopped = 3 +} + +public class ProcessChangedEventArgs : EventArgs +{ + public IList StartedProcesses { get; set; } + public IList StoppedProcesses { get; set; } + public IList RunningProcesses { get; set; } + public bool IsNotificationDisabled { get; set; } + public Process ForegroundProcess { get; set; } + public bool ForegroundProcessIsFullScreen { get; set; } + public string LastFullScreenProcessName = string.Empty; + public bool StoppedFullScreen { get; set; } + public bool IsScreenSaverActive { get; set; } + public ScreenSaverTransitionState ScreenSaverTransitionState { get; set; } +} + + +public class ProcessEventDispatcher : EventDispatcher +{ + public const string Event_ProcessChanged = "ProcessChanged"; + public bool IsRunning { get; set; } + public ProcessChangedEventArgs MonitorContext { get; private set; } + + protected static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); + + private AppContextProvider _appContextProvider { get; } + + public ProcessEventDispatcher(AppContextProvider appContextProvider) + { + _appContextProvider = appContextProvider; + + IsRunning = true; + + //Task.Run(async () => await CheckProcesses()); + + var _ = CheckProcesses(); + } + + private async Task CheckProcesses() + { + await Task.Delay(2000); + + //var startWatch = new ManagementEventWatcher("SELECT * FROM Win32_ProcessStartTrace"); + //startWatch.EventArrived += startWatch_EventArrived; + //startWatch.Start(); + + MonitorContext ??= new ProcessChangedEventArgs(); + + while (IsRunning) + { + await Task.Delay(_appContextProvider.GetAppContext().Config.ProcessMonitorPollingInterval); + + if (!HasHandlers(Event_ProcessChanged)) + { + continue; + } + + try + { + FillContext(MonitorContext); + + // Ignore if own process has the foreground + if (MonitorContext.ForegroundProcess?.Id == Environment.ProcessId) + { + continue; + } + + await DispatchEventAsync(Event_ProcessChanged, MonitorContext); + DispatchEvent(Event_ProcessChanged, MonitorContext); + } + catch (Exception ex) + { + Logger.Error("CheckProcesses: " + ex.ToLogString()); + } + } + } + + private void FillContext(ProcessChangedEventArgs context) + { + var processes = Process.GetProcesses(); + + context.StartedProcesses = processes.Where(p => context.RunningProcesses?.Any(rp => rp.Id == p.Id) == false).ToList(); + context.StoppedProcesses = context.RunningProcesses?.Where(p => processes.Any(rp => rp.Id == p.Id) == false).ToList(); + context.RunningProcesses = processes; + + context.IsNotificationDisabled = FormUtils.IsNotificationDisabled(); + + var (processId, isFullScreen) = FormUtils.GetForegroundProcessIdAndIfFullScreen(); + + if (processId > 0) + { + var process = context.RunningProcesses.FirstOrDefault(p => p.Id == processId); + + var screenSaverActive = process?.ProcessName?.Contains(".scr") == true; + + context.IsScreenSaverActive = screenSaverActive; + context.ScreenSaverTransitionState = screenSaverActive ? + context.ScreenSaverTransitionState == ScreenSaverTransitionState.None ? ScreenSaverTransitionState.Started : ScreenSaverTransitionState.Running : + context.ScreenSaverTransitionState == ScreenSaverTransitionState.Running ? ScreenSaverTransitionState.Stopped : ScreenSaverTransitionState.None; + context.ForegroundProcess = process; + context.ForegroundProcessIsFullScreen = isFullScreen; + + if (isFullScreen) + { + context.LastFullScreenProcessName = context.ForegroundProcess.ProcessName; + //Logger.Debug($"Foreground fullscreen app detected: {context.ForegroundProcess.ProcessName}"); + } + } + else + { + context.StoppedFullScreen = context.ForegroundProcessIsFullScreen; + context.ForegroundProcess = null; + context.ForegroundProcessIsFullScreen = false; + context.LastFullScreenProcessName = string.Empty; + } + } + + private void startWatch_EventArrived(object sender, EventArrivedEventArgs e) + { + //Logger.Debug("Process started: " + e.NewEvent.Properties["ProcessName"].Value); + } +} diff --git a/Shared/EventDispatcher/SessionSwitchDispatcher.cs b/Shared/EventDispatcher/SessionSwitchDispatcher.cs new file mode 100644 index 0000000..0beaf06 --- /dev/null +++ b/Shared/EventDispatcher/SessionSwitchDispatcher.cs @@ -0,0 +1,40 @@ +using Microsoft.Win32; + +namespace ColorControl.Shared.EventDispatcher; + +public class SessionSwitchDispatcher : EventDispatcher +{ + public const string Event_SessionSwitch = "SessionSwitch"; + + private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); + + public bool UserLocalSession { get; private set; } = true; + public SessionSwitchReason LastSessionSwitchReason { get; private set; } = 0; + + public SessionSwitchDispatcher() + { + SystemEvents.SessionSwitch += SessionSwitchHandler; + } + + public void SessionSwitchHandler(object sender, SessionSwitchEventArgs evt) + { + if (evt.Reason == SessionSwitchReason.ConsoleDisconnect) + { + Logger.Debug("Detected a disconnect from the console"); + UserLocalSession = false; + + DispatchEvent(Event_SessionSwitch, evt); + } + else if (evt.Reason == SessionSwitchReason.ConsoleConnect) + { + Logger.Debug("Detected a connect to the console"); + if (!UserLocalSession) + { + Logger.Debug("Session state switched to local"); + UserLocalSession = true; + DispatchEvent(Event_SessionSwitch, evt); + } + } + LastSessionSwitchReason = evt.Reason; + } +}