fix LG device settings not saving, upgrade to .NET 7

This commit is contained in:
Vincent Maas committed 2023-04-15 10:37:08 +02:00
1 parent 6318d37247
commit 52fd635fda
20 files changed
+1164 -967

No files matched your search

+10 -10
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<LangVersion>10.0</LangVersion>
<TargetFramework>net6.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<OutputType>WinExe</OutputType>
<IsWebBootstrapper>false</IsWebBootstrapper>
<PublishUrl>publish\</PublishUrl>
@@ -19,8 +19,8 @@
<PublisherName>Maassoft</PublisherName>
<Company>Maassoft</Company>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>9.0.0.0</ApplicationVersion>
<Version>9.0.0.0</Version>
<ApplicationVersion>9.1.0.0</ApplicationVersion>
<Version>9.1.0.0</Version>
<UseApplicationTrust>false</UseApplicationTrust>
<PublishWizardCompleted>true</PublishWizardCompleted>
<BootstrapperEnabled>false</BootstrapperEnabled>
@@ -89,17 +89,17 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.1" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NLog" Version="5.0.4" />
<PackageReference Include="NStandard" Version="0.15.2" />
<PackageReference Include="NWin32" Version="1.2.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NLog" Version="5.1.2" />
<PackageReference Include="NStandard" Version="0.24.0" />
<PackageReference Include="NWin32" Version="1.2.6" />
<PackageReference Include="System.Management" Version="7.0.0" />
<PackageReference Include="TaskScheduler" Version="2.10.1" />
<PackageReference Include="Vanara.PInvoke.IpHlpApi" Version="3.4.9" />
<PackageReference Include="Vanara.PInvoke.IpHlpApi" Version="3.4.13" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Nspector\Nspector.csproj" />
+2 -2
View File
@@ -296,7 +296,7 @@ The best and suggested method to provide this is via a Windows Service. Only whe
return key != null && key.GetValue(null).ToString().Contains("--disable-lcd-text");
}
internal static bool InstallChromeFix(bool install)
internal static bool InstallChromeFix(bool install, string applicationDataFolder)
{
var argument = "--disable-lcd-text";
@@ -312,7 +312,7 @@ The best and suggested method to provide this is via a Windows Service. Only whe
key.SetValue(null, value);
}
var roamingFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var roamingFolder = applicationDataFolder ?? Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
UpdateShortcut(Path.Combine(roamingFolder, @"Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\Google Chrome.lnk"), argument, !install);
UpdateShortcut(Path.Combine(roamingFolder, @"Microsoft\Internet Explorer\Quick Launch\Google Chrome.lnk"), argument, !install);
+8 -6
View File
@@ -45,12 +45,14 @@ namespace ColorControl.Forms
public static void SetNotifyIconText(NotifyIcon ni, string text)
{
text = text.Substring(0, Math.Min(text.Length, 127));
Type t = typeof(NotifyIcon);
BindingFlags hidden = BindingFlags.NonPublic | BindingFlags.Instance;
t.GetField("text", hidden).SetValue(ni, text);
if ((bool)t.GetField("added", hidden).GetValue(ni))
t.GetMethod("UpdateIcon", hidden).Invoke(ni, new object[] { true });
ni.Text = text;
//text = text.Substring(0, Math.Min(text.Length, 127));
//Type t = typeof(NotifyIcon);
//BindingFlags hidden = BindingFlags.NonPublic | BindingFlags.Instance;
//t.GetField("text", hidden).SetValue(ni, text);
//if ((bool)t.GetField("added", hidden).GetValue(ni))
// t.GetMethod("UpdateIcon", hidden).Invoke(ni, new object[] { true });
}
public static ToolStripMenuItem BuildDropDownMenuEx(ToolStripItemCollection items, string parentName, string name, Type enumType, EventHandler clickEvent, object tag = null, int min = 0, int max = 0, bool noSubItems = false)
+16 -17
View File
@@ -140,7 +140,6 @@ namespace ColorControl
InitInfo();
UpdateServiceInfo();
UserSessionInfo.Install();
_screenStateNotify = WinApi.RegisterPowerSettingNotification(Handle, ref Utils.GUID_CONSOLE_DISPLAY_STATE, 0);
//Scale(new SizeF(1.25F, 1.25F));
@@ -320,9 +319,7 @@ namespace ColorControl
{
try
{
var appContextProvider = Program.ServiceProvider.GetRequiredService<AppContextProvider>();
_lgService = new LgService(appContextProvider, StartUpParams.RunningFromScheduledTask);
_lgService = Program.ServiceProvider.GetRequiredService<LgService>();
_lgPanel = new LgPanel(_lgService, _nvService, _amdService, _trayIcon, Handle);
_lgPanel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
@@ -562,20 +559,24 @@ namespace ColorControl
{
//Logger.Debug($"WM_SYSCOMMAND: {m.WParam.ToInt32()}");
if (m.WParam.ToInt32() == NativeConstants.SC_MONITORPOWER)
{
//if (m.WParam.ToInt32() == NativeConstants.SC_MONITORPOWER)
//{
}
//}
}
else if (m.Msg == NativeConstants.WM_POWERBROADCAST)
{
//Logger.Debug($"WM_POWERBROADCAST: {m.WParam.ToInt32()}");
if (m.WParam.ToInt32() == WinApi.PBT_POWERSETTINGCHANGE)
{
var ps = Marshal.PtrToStructure<WinApi.POWERBROADCAST_SETTING>(m.LParam);
Logger.Debug($"PBT_POWERSETTINGCHANGE: {ps.Data}");
var power = (LgService.WindowsPowerSetting)ps.Data;
_lgService?.PowerSettingChanged((LgService.WindowsPowerSetting)ps.Data);
Logger.Debug($"PBT_POWERSETTINGCHANGE: {power}");
_lgService?.PowerSettingChanged(power);
}
}
@@ -1398,14 +1399,12 @@ Currently ColorControl is {(Utils.IsAdministrator() ? "" : "not ")}running as ad
if (_initialized)
{
_config.FixChromeFonts = chkFixChromeFonts.Checked;
if (chkFixChromeFonts.Checked)
{
Utils.ExecuteElevated(StartUpParams.ActivateChromeFontFixParam);
}
else
{
Utils.ExecuteElevated(StartUpParams.DeactivateChromeFontFixParam);
}
var param = chkFixChromeFonts.Checked ? StartUpParams.ActivateChromeFontFixParam : StartUpParams.DeactivateChromeFontFixParam;
var folder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
Utils.ExecuteElevated($"{param} {folder}");
}
}
+6 -1
View File
@@ -2,6 +2,7 @@
using ColorControl.Forms;
using ColorControl.Services.AMD;
using ColorControl.Services.Common;
using ColorControl.Services.EventDispatcher;
using ColorControl.Services.LG;
using ColorControl.Services.NVIDIA;
using ColorControl.Svc;
@@ -207,7 +208,7 @@ namespace ColorControl
{
if (startUpParams.ActivateChromeFontFix || startUpParams.DeactivateChromeFontFix)
{
Utils.InstallChromeFix(startUpParams.ActivateChromeFontFix);
Utils.InstallChromeFix(startUpParams.ActivateChromeFontFix, startUpParams.ChromeFontFixApplicationDataFolder);
return true;
}
if (startUpParams.EnableAutoStart || startUpParams.DisableAutoStart)
@@ -353,6 +354,9 @@ namespace ColorControl
{
//services.AddSingleton<NvService>();
services.RegisterSharedServices();
services.AddSingleton<LgService>();
services.AddSingleton<PowerEventDispatcher>();
services.AddSingleton<ProcessEventDispatcher>();
});
}
private static async Task RunService(string[] args)
@@ -377,6 +381,7 @@ namespace ColorControl
private static void RegisterSharedServices(this IServiceCollection services)
{
services.AddSingleton<AppContextProvider>();
services.AddSingleton<SessionSwitchDispatcher>();
}
public static int EnumThreadWindows(IntPtr handle, IntPtr param)
@@ -87,8 +87,9 @@ namespace ColorControl.Services.Common
DEVMODEA devMode;
while (NativeMethods.EnumDisplaySettingsA(displayName, i, out devMode))
{
if ((!portrait && devMode.dmPelsWidth == horizontal && devMode.dmPelsHeight == vertical) ||
(portrait && devMode.dmPelsWidth == vertical && devMode.dmPelsHeight == horizontal))
if (((!portrait && devMode.dmPelsWidth == horizontal && devMode.dmPelsHeight == vertical) ||
(portrait && devMode.dmPelsWidth == vertical && devMode.dmPelsHeight == horizontal)) &&
!list.Contains(devMode.dmDisplayFrequency))
{
list.Add(devMode.dmDisplayFrequency);
}
@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using static ColorControl.Services.EventDispatcher.EventExtensions;
namespace ColorControl.Services.EventDispatcher;
public class EventDispatcher<T> where T : EventArgs
{
private Dictionary<string, EventHandler<T>> eventHandlers = new Dictionary<string, EventHandler<T>>();
private Dictionary<string, AsyncEventHandler<T>> asyncEventHandlers = new Dictionary<string, AsyncEventHandler<T>>();
public void RegisterEventHandler(string eventName, EventHandler<T> eventHandler)
{
if (!eventHandlers.ContainsKey(eventName))
{
eventHandlers.Add(eventName, eventHandler);
}
}
public void RegisterAsyncEventHandler(string eventName, AsyncEventHandler<T> eventHandler)
{
if (!asyncEventHandlers.ContainsKey(eventName))
{
asyncEventHandlers.Add(eventName, eventHandler);
}
}
public void UnregisterEventHandler(string eventName)
{
eventHandlers.Remove(eventName);
}
public void DispatchEvent(string eventName, T eventArgs)
{
if (eventHandlers.ContainsKey(eventName))
{
eventHandlers[eventName]?.Invoke(this, eventArgs);
}
}
public async Task DispatchEventAsync(string eventName, T eventArgs)
{
if (asyncEventHandlers.ContainsKey(eventName))
{
await asyncEventHandlers[eventName]?.InvokeAsync(this, eventArgs);
}
}
protected bool HasHandlers(string eventName)
{
return eventHandlers.ContainsKey(eventName) || asyncEventHandlers.ContainsKey(eventName);
}
}
@@ -0,0 +1,17 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace ColorControl.Services.EventDispatcher
{
public static class EventExtensions
{
public delegate Task AsyncEventHandler<TEventArgs>(object sender, TEventArgs e, CancellationToken token);
public static Task InvokeAsync<TArgs>(this AsyncEventHandler<TArgs> func, object sender, TArgs e)
{
return func == null ? Task.CompletedTask
: Task.WhenAll(func.GetInvocationList().Cast<AsyncEventHandler<TArgs>>().Select(f => f(sender, e, CancellationToken.None)));
}
}
}
@@ -0,0 +1,27 @@
using Microsoft.Win32;
namespace ColorControl.Services.EventDispatcher
{
public class PowerEventDispatcher : EventDispatcher<PowerModeChangedEventArgs>
{
public const string Event_Suspend = "Suspend";
public const string Event_Resume = "Resume";
public PowerEventDispatcher()
{
SystemEvents.PowerModeChanged += OnPowerModeChanged;
}
private void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
if (e.Mode == PowerModes.Suspend)
{
DispatchEvent(Event_Suspend, e);
}
else if (e.Mode == PowerModes.Resume)
{
DispatchEvent(Event_Resume, e);
}
}
}
}
@@ -0,0 +1,119 @@
using ColorControl.Common;
using ColorControl.Forms;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Management;
using System.Threading.Tasks;
namespace ColorControl.Services.EventDispatcher
{
public class ProcessChangedEventArgs : EventArgs
{
public IList<Process> StartedProcesses { get; set; }
public IList<Process> StoppedProcesses { get; set; }
public IList<Process> 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 class ProcessEventDispatcher : EventDispatcher<ProcessChangedEventArgs>
{
public const string Event_ProcessChanged = "ProcessChanged";
public bool IsRunning { get; set; }
protected static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
private ProcessChangedEventArgs MonitorContext { get; set; }
public ProcessEventDispatcher()
{
IsRunning = true;
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();
//Process[] lastProcesses = null;
while (IsRunning)
{
await Task.Delay(1000);
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);
}
catch (Exception ex)
{
Logger.Error("CheckProcesses: " + ex.ToLogString());
}
}
}
private void FillContext(ProcessChangedEventArgs context)
{
var processes = Process.GetProcesses();
context.RunningProcesses = processes;
context.IsNotificationDisabled = FormUtils.IsNotificationDisabled();
var (processId, isFullScreen) = FormUtils.GetForegroundProcessIdAndIfFullScreen();
if (processId > 0)
{
var process = context.RunningProcesses.FirstOrDefault(p => p.Id == processId);
context.IsScreenSaverActive = process?.ProcessName?.Contains(".scr") == true;
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);
}
}
}
@@ -1,29 +1,29 @@
using Microsoft.Win32;
namespace ColorControl
namespace ColorControl.Services.EventDispatcher
{
static class UserSessionInfo
public class SessionSwitchDispatcher : EventDispatcher<SessionSwitchEventArgs>
{
public const string Event_SessionSwitch = "SessionSwitch";
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
public static bool UserLocalSession { get; private set; } = true;
public static SessionSwitchReason LastSessionSwitchReason { get; private set; } = 0;
public bool UserLocalSession { get; private set; } = true;
public SessionSwitchReason LastSessionSwitchReason { get; private set; } = 0;
public delegate void UserSessionSwitchHandler(bool toLocal);
public static event UserSessionSwitchHandler UserSessionSwitch;
public static void Install()
public SessionSwitchDispatcher()
{
SystemEvents.SessionSwitch += SessionSwitchHandler;
}
public static void SessionSwitchHandler(object sender, SessionSwitchEventArgs evt)
public void SessionSwitchHandler(object sender, SessionSwitchEventArgs evt)
{
if (evt.Reason == SessionSwitchReason.ConsoleDisconnect)
{
Logger.Debug("Detected a disconnect from the console");
UserLocalSession = false;
UserSessionSwitch(false);
DispatchEvent(Event_SessionSwitch, evt);
}
else if (evt.Reason == SessionSwitchReason.ConsoleConnect)
{
@@ -32,7 +32,7 @@ namespace ColorControl
{
Logger.Debug("Session state switched to local");
UserLocalSession = true;
UserSessionSwitch(true);
DispatchEvent(Event_SessionSwitch, evt);
}
}
LastSessionSwitchReason = evt.Reason;
+30 -1
View File
@@ -61,7 +61,8 @@ namespace ColorControl.Services.LG
Series2019,
Series2020,
Series2021,
Series2022
Series2022,
Series2023
}
protected static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
@@ -80,6 +81,7 @@ namespace ColorControl.Services.LG
public bool PowerOffOnShutdown { get; set; }
public bool PowerOffOnStandby { get; set; }
public bool PowerOffOnScreenSaver { get; set; }
public int ScreenSaverMinimalDuration { get; set; }
public bool PowerOnAfterScreenSaver { get; set; }
public bool PowerOnAfterManualPowerOff { get; set; }
public bool PowerOnByWindows { get; set; }
@@ -143,6 +145,9 @@ namespace ColorControl.Services.LG
public event EventHandler PictureSettingsChangedEvent;
public event EventHandler PowerStateChangedEvent;
[JsonIgnore]
private Timer _powerOffTimer;
[JsonConstructor]
public LgDevice(string name, string ipAddress, string macAddress, bool isCustom = true, bool isDummy = false)
{
@@ -256,6 +261,11 @@ namespace ColorControl.Services.LG
AddGenericPictureAction("wolwowlOnOff", typeof(FalseToTrue), category: "network", title: "Wake-On-LAN");
}
~LgDevice()
{
_powerOffTimer?.Dispose();
}
private void AddInvokableAction(string name, Func<Dictionary<string, object>, bool> function)
{
var action = new InvokableAction
@@ -430,6 +440,7 @@ namespace ColorControl.Services.LG
'X' => ModelYear.Series2020,
'1' => ModelYear.Series2021,
'2' => ModelYear.Series2022,
'3' => ModelYear.Series2023,
_ => ModelYear.None
};
@@ -1083,5 +1094,23 @@ namespace ColorControl.Services.LG
}
}
}
internal void ClearPowerOffTask()
{
_powerOffTimer?.Dispose();
}
internal void PowerOffIn(int seconds)
{
_powerOffTimer = new Timer(PowerOffByTimer);
_powerOffTimer.Change(TimeSpan.FromSeconds(seconds), TimeSpan.FromSeconds(seconds));
}
private void PowerOffByTimer(object state)
{
_powerOffTimer?.Dispose();
var _ = PowerOff(true);
}
}
}
File diff suppressed because it is too large. Load diff
+28 -10
View File
@@ -32,7 +32,6 @@ namespace ColorControl.Services.LG
private NotifyIcon _trayIcon;
private string _lgTabMessage;
private bool _initialized = false;
private bool _disableEvents = false;
private LgGameBar _gameBarForm;
@@ -74,7 +73,6 @@ namespace ColorControl.Services.LG
public void Init()
{
_lgService.RefreshDevices(afterStartUp: true).ContinueWith((_) => BeginInvoke(() => AfterLgServiceRefreshDevices()));
_lgService.InstallEventHandlers();
}
@@ -290,11 +288,6 @@ namespace ColorControl.Services.LG
edtLgPresetIncludedProcesses.Text,
edtLgPresetExcludedProcesses.Text);
if (triggerType != PresetTriggerType.None)
{
_lgService.InstallEventHandlers();
}
var shortcutChanged = !shortcut.Equals(preset.shortcut);
if (shortcutChanged)
{
@@ -665,7 +658,7 @@ namespace ColorControl.Services.LG
private void clbLgPower_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (!_initialized || _disableEvents)
if (_disableEvents)
{
return;
}
@@ -702,8 +695,6 @@ You can also activate this option by using the Expert-button and selecting Wake-
device.PowerOnByWindows = clbLgPower.GetItemChecked(9);
device.UseSecureConnection = clbLgPower.GetItemChecked(10);
_lgService.InstallEventHandlers();
if (e.Index == 10)
{
_lgService.RefreshDevices().ContinueWith((_) => BeginInvoke(() => FillLgDevices()));
@@ -1279,5 +1270,32 @@ The InStart, EzAdjust and Software Update items are now visible under the Expert
}
}
private void clbLgPower_SelectedIndexChanged(object sender, EventArgs e)
{
btnLgDeviceOptionsSettings.Enabled = clbLgPower.SelectedIndex == 4;
}
private void btnLgDeviceOptionsSettings_Click(object sender, EventArgs e)
{
var device = _lgService.SelectedDevice;
var selectedItem = clbLgPower.SelectedItem;
var durationField = new MessageForms.FieldDefinition
{
Label = "Enter the minimal duration the screen saver must be running (in seconds)",
FieldType = MessageForms.FieldType.Numeric,
MinValue = 0,
MaxValue = 3600,
Value = device.ScreenSaverMinimalDuration
};
if (!MessageForms.ShowDialog($"Settings - {selectedItem}", new[] { durationField }).Any())
{
return;
}
device.ScreenSaverMinimalDuration = durationField.ValueAsInt;
}
}
}
+189 -261
View File
@@ -1,6 +1,6 @@
using ColorControl.Common;
using ColorControl.Forms;
using ColorControl.Services.Common;
using ColorControl.Services.EventDispatcher;
using ColorControl.Svc;
using LgTv;
using Microsoft.Extensions.DependencyInjection;
@@ -12,7 +12,6 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
@@ -77,6 +76,9 @@ namespace ColorControl.Services.LG
private string _configFilename;
private bool _allowPowerOn;
private readonly PowerEventDispatcher _powerEventDispatcher;
private readonly SessionSwitchDispatcher _sessionSwitchDispatcher;
private readonly ProcessEventDispatcher _processEventDispatcher;
private LgDevice _selectedDevice;
private string _rcButtonsFilename;
private List<LgPreset> _remoteControlButtons;
@@ -84,15 +86,15 @@ namespace ColorControl.Services.LG
private bool _poweredOffByScreenSaver;
private int _poweredOffByScreenSaverProcessId;
private Task _monitorTask;
private int _monitorTaskCounter;
private LgPreset _lastTriggeredPreset;
private RestartDetector _restartDetector;
public LgService(AppContextProvider appContextProvider, bool allowPowerOn) : base(appContextProvider)
public LgService(AppContextProvider appContextProvider, PowerEventDispatcher powerEventDispatcher, SessionSwitchDispatcher sessionSwitchDispatcher, ProcessEventDispatcher processEventDispatcher) : base(appContextProvider)
{
_allowPowerOn = allowPowerOn;
_allowPowerOn = appContextProvider.GetAppContext().StartUpParams.RunningFromScheduledTask;
_powerEventDispatcher = powerEventDispatcher;
_sessionSwitchDispatcher = sessionSwitchDispatcher;
_processEventDispatcher = processEventDispatcher;
LgPreset.LgApps = _lgApps;
_restartDetector = new RestartDetector();
@@ -111,9 +113,8 @@ namespace ColorControl.Services.LG
{
try
{
var appContextProvider = Program.ServiceProvider.GetRequiredService<AppContextProvider>();
var lgService = Program.ServiceProvider.GetRequiredService<LgService>();
var lgService = new LgService(appContextProvider, true);
await lgService.RefreshDevices(afterStartUp: true);
var result = await lgService.ApplyPreset(presetName);
@@ -442,32 +443,35 @@ namespace ColorControl.Services.LG
public void InstallEventHandlers()
{
SystemEvents.PowerModeChanged -= PowerModeChanged;
SystemEvents.PowerModeChanged += PowerModeChanged;
_powerEventDispatcher.RegisterEventHandler(PowerEventDispatcher.Event_Suspend, PowerModeChanged);
_powerEventDispatcher.RegisterEventHandler(PowerEventDispatcher.Event_Resume, PowerModeChanged);
//SystemEvents.SessionEnded -= SessionEnded;
//SystemEvents.SessionEnded += SessionEnded;
UserSessionInfo.UserSessionSwitch -= SessionSwitched;
UserSessionInfo.UserSessionSwitch += SessionSwitched;
_sessionSwitchDispatcher.RegisterEventHandler(SessionSwitchDispatcher.Event_SessionSwitch, SessionSwitched);
MonitorProcesses();
_processEventDispatcher.RegisterAsyncEventHandler(ProcessEventDispatcher.Event_ProcessChanged, ProcessChanged);
}
private void SessionSwitched(bool toLocal)
private void SessionSwitched(object sender, SessionSwitchEventArgs e)
{
if (toLocal)
if (_sessionSwitchDispatcher.UserLocalSession)
{
if (_poweredOffByScreenSaver)
{
Logger.Debug("User switched to local and screen was powered off due to screensaver: waking up");
_poweredOffByScreenSaver = false;
_poweredOffByScreenSaverProcessId = 0;
WakeAfterStartupOrResume();
}
else
{
Logger.Debug("User switched to local but screen was not powered off by screensaver: NOT waking up");
}
return;
}
if (_poweredOffByScreenSaver)
{
Logger.Debug("User switched to local and screen was powered off due to screensaver: waking up");
_poweredOffByScreenSaver = false;
_poweredOffByScreenSaverProcessId = 0;
WakeAfterStartupOrResume();
}
else
{
Logger.Debug("User switched to local but screen was not powered off by screensaver: NOT waking up");
}
}
@@ -479,6 +483,8 @@ namespace ColorControl.Services.LG
if (powerOn)
{
Devices.ForEach(d => d.ClearPowerOffTask());
WakeAfterStartupOrResume(PowerOnOffState.Resume);
return;
}
@@ -516,199 +522,101 @@ namespace ColorControl.Services.LG
}
}
private void MonitorProcesses()
public async Task ProcessChanged(object sender, ProcessChangedEventArgs args, CancellationToken token)
{
var enableMonitoring = ShouldMonitorProcesses();
if (enableMonitoring && _monitorTask == null)
try
{
_monitorTask = CheckProcesses();
}
else if (!enableMonitoring && _monitorTask != null)
{
_monitorTask = null;
}
}
var wasConnected = Devices.Any(d => (d.PowerOffOnScreenSaver || d.PowerOnAfterScreenSaver) && d.IsConnected());
public bool ShouldMonitorProcesses()
{
return Devices.Any(d => d.PowerOffOnScreenSaver || d.PowerOnAfterScreenSaver) || _presets.Any(p => p.Triggers.Any(t => t.Trigger != PresetTriggerType.None));
}
var applicableDevices = Devices.Where(d => d.PowerOffOnScreenSaver || d.PowerOnAfterScreenSaver || d.TriggersEnabled && _presets.Any(p => p.Triggers.Any(t => t.Trigger != PresetTriggerType.None) &&
((string.IsNullOrEmpty(p.DeviceMacAddress) && d == SelectedDevice) || p.DeviceMacAddress.Equals(d.MacAddress, StringComparison.OrdinalIgnoreCase))));
public async Task CheckProcesses()
{
var wasConnected = Devices.Any(d => (d.PowerOffOnScreenSaver || d.PowerOnAfterScreenSaver) && d.IsConnected());
_monitorTaskCounter++;
var validCounter = _monitorTaskCounter;
var lastProcessId = 0;
await Task.Delay(2000);
//var startWatch = new ManagementEventWatcher("SELECT * FROM Win32_ProcessStartTrace");
//startWatch.EventArrived += startWatch_EventArrived;
//startWatch.Start();
MonitorContext ??= new ProcessMonitorContext();
//Process[] lastProcesses = null;
while (validCounter == _monitorTaskCounter)
{
await Task.Delay(_poweredOffByScreenSaver ? 500 : 1000);
try
if (!applicableDevices.Any())
{
var applicableDevices = Devices.Where(d => d.PowerOffOnScreenSaver || d.PowerOnAfterScreenSaver || d.TriggersEnabled && _presets.Any(p => p.Triggers.Any(t => t.Trigger != PresetTriggerType.None) &&
((string.IsNullOrEmpty(p.DeviceMacAddress) && d == SelectedDevice) || p.DeviceMacAddress.Equals(d.MacAddress, StringComparison.OrdinalIgnoreCase))));
if (!applicableDevices.Any())
{
continue;
}
if (_poweredOffByScreenSaver && !UserSessionInfo.UserLocalSession)
{
continue;
}
var processes = Process.GetProcesses();
if (_poweredOffByScreenSaver)
{
if (processes.Any(p => p.Id == _poweredOffByScreenSaverProcessId))
{
continue;
}
Logger.Debug("Screensaver stopped, waking");
_poweredOffByScreenSaver = false;
_poweredOffByScreenSaverProcessId = 0;
lastProcessId = 0;
WakeAfterStartupOrResume(PowerOnOffState.ScreenSaver);
continue;
}
var connectedDevices = applicableDevices.Where(d => d.IsConnected()).ToList();
if (!connectedDevices.Any())
{
if (wasConnected)
{
Logger.Debug("Process monitor: TV(s) where connected, but not any longer");
wasConnected = false;
continue;
}
else
{
var devices = applicableDevices.ToList();
foreach (var device in devices)
{
Logger.Debug($"Process monitor: test connection with {device.Name}...");
var test = await device.TestConnection();
Logger.Debug("Process monitor: test connection result: " + test);
}
connectedDevices = applicableDevices.Where(d => d.IsConnected()).ToList();
if (!connectedDevices.Any())
{
continue;
}
}
}
if (!wasConnected)
{
Logger.Debug("Process monitor: TV(s) where not connected, but connection has now been established");
wasConnected = true;
}
if (connectedDevices.Any(d => d.PowerOffOnScreenSaver || d.PowerOnAfterScreenSaver))
{
lastProcessId = await HandleScreenSaverProcessAsync(lastProcessId, processes, connectedDevices);
}
MonitorContext.Devices = connectedDevices.Where(d => d.TriggersEnabled).ToList();
MonitorContext.RunningProcesses = processes;
await ExecuteProcessPresets(MonitorContext);
return;
}
catch (Exception ex)
if (_poweredOffByScreenSaver && !_sessionSwitchDispatcher.UserLocalSession)
{
Logger.Error("CheckProcesses: " + ex.ToLogString());
return;
}
var processes = args.RunningProcesses;
if (_poweredOffByScreenSaver)
{
if (processes.Any(p => p.Id == _poweredOffByScreenSaverProcessId))
{
return;
}
Logger.Debug("Screensaver stopped, waking");
_poweredOffByScreenSaver = false;
_poweredOffByScreenSaverProcessId = 0;
WakeAfterStartupOrResume(PowerOnOffState.ScreenSaver);
return;
}
var connectedDevices = applicableDevices.Where(d => d.IsConnected()).ToList();
if (!connectedDevices.Any())
{
if (wasConnected)
{
Logger.Debug("Process monitor: TV(s) where connected, but not any longer");
wasConnected = false;
return;
}
else
{
var devices = applicableDevices.ToList();
foreach (var device in devices)
{
Logger.Debug($"Process monitor: test connection with {device.Name}...");
var test = await device.TestConnection();
Logger.Debug("Process monitor: test connection result: " + test);
}
connectedDevices = applicableDevices.Where(d => d.IsConnected()).ToList();
if (!connectedDevices.Any())
{
return;
}
}
}
if (!wasConnected)
{
Logger.Debug("Process monitor: TV(s) where not connected, but connection has now been established");
wasConnected = true;
}
if (connectedDevices.Any(d => d.PowerOffOnScreenSaver || d.PowerOnAfterScreenSaver))
{
await HandleScreenSaverProcessAsync(processes, connectedDevices);
}
await ExecuteProcessPresets(args, connectedDevices);
}
catch (Exception ex)
{
Logger.Error("ProcessChanged: " + ex.ToLogString());
}
}
private void startWatch_EventArrived(object sender, EventArrivedEventArgs e)
private async Task ExecuteProcessPresets(ProcessChangedEventArgs context, IList<LgDevice> connectedDevices)
{
//Logger.Debug("Process started: " + e.NewEvent.Properties["ProcessName"].Value);
}
var triggerDevices = connectedDevices.Where(d => d.TriggersEnabled).ToList();
private async Task<int> HandleScreenSaverProcessAsync(int lastProcessId, Process[] processes, List<LgDevice> connectedDevices)
{
var process = processes.FirstOrDefault(p => p.ProcessName.ToLowerInvariant().EndsWith(".scr"));
if (process == null)
if (context.IsScreenSaverActive)
{
return 0;
return;
}
var parent = process.Parent(processes);
if (parent?.ProcessName.Contains("winlogon") ?? false)
{
Logger.Debug($"Screensaver started: {process.ProcessName}, parent: {parent.ProcessName}");
try
{
foreach (var device in connectedDevices.Where(d => d.PowerOffOnScreenSaver))
{
Logger.Debug($"Screensaver check: test connection with {device.Name}...");
var test = await device.TestConnection();
Logger.Debug("Screensaver check: test connection result: " + test);
if (!test)
{
continue;
}
Logger.Debug($"Screensaver check: powering off tv {device.Name} because of screensaver");
try
{
_poweredOffByScreenSaver = await device.PowerOff(true).WaitAsync(TimeSpan.FromSeconds(5));
}
catch (TimeoutException)
{
// Assume powering off was successful
_poweredOffByScreenSaver = true;
Logger.Error($"Screensaver check: timeout exception while powering off (probably connection closed)");
}
catch (Exception pex)
{
// Assume powering off was successful
_poweredOffByScreenSaver = true;
Logger.Error($"Screensaver check: exception while powering off (probably connection closed): " + pex.Message);
}
Logger.Debug($"Screensaver check: powered off tv {device.Name}");
}
_poweredOffByScreenSaverProcessId = process.Id;
lastProcessId = 0;
}
catch (Exception e)
{
Logger.Error($"Screensaver check: can't power off: " + e.ToLogString());
}
}
else if (process.Id != lastProcessId)
{
Logger.Debug($"Screensaver started: {process.ProcessName}, but invalid parent: {parent?.ProcessName ?? "no parent"}");
lastProcessId = process.Id;
}
return lastProcessId;
}
private async Task ExecuteProcessPresets(ProcessMonitorContext context)
{
var selectedDevice = SelectedDevice;
var presets = _presets.Where(p => p.Triggers.Any(t => t.Trigger == PresetTriggerType.ProcessSwitch) &&
@@ -719,33 +627,6 @@ namespace ColorControl.Services.LG
return;
}
context.IsNotificationDisabled = FormUtils.IsNotificationDisabled();
var (processId, isFullScreen) = FormUtils.GetForegroundProcessIdAndIfFullScreen();
if (processId == Environment.ProcessId)
{
return;
}
if (processId > 0)
{
var process = context.RunningProcesses.FirstOrDefault(p => p.Id == processId);
if (process?.ProcessName?.Contains(".scr") ?? false)
{
return;
}
context.ForegroundProcess = process;
context.ForegroundProcessIsFullScreen = isFullScreen;
}
else
{
context.ForegroundProcess = null;
context.ForegroundProcessIsFullScreen = false;
}
var changedProcesses = new List<Process>();
if (context.ForegroundProcess != null)
{
@@ -754,23 +635,14 @@ namespace ColorControl.Services.LG
if (context.ForegroundProcess != null && context.ForegroundProcessIsFullScreen)
{
if (!context.LastFullScreenProcessName.Equals(context.ForegroundProcess.ProcessName))
{
context.LastFullScreenProcessName = context.ForegroundProcess.ProcessName;
//Logger.Debug($"Foreground fullscreen app detected: {context.ForegroundProcess.ProcessName}");
}
presets = presets.Where(p => p.Triggers.Any(t => t.Conditions.HasFlag(PresetConditionType.FullScreen)));
context.WasFullScreen = true;
}
else if (context.WasFullScreen)
else if (context.StoppedFullScreen)
{
presets = presets.Where(p => p.Triggers.Any(t => !t.Conditions.HasFlag(PresetConditionType.FullScreen)));
context.WasFullScreen = false;
context.LastFullScreenProcessName = string.Empty;
}
var isHDRActive = context.Devices.Any(d => d.IsUsingHDRPictureMode());
var isHDRActive = triggerDevices.Any(d => d.IsUsingHDRPictureMode());
var isGsyncActive = LgDevice.ExternalServiceHandler("GsyncEnabled", new[] { "" });
@@ -784,27 +656,11 @@ namespace ColorControl.Services.LG
IsNotificationDisabled = context.IsNotificationDisabled
};
var toApplyPresets = new List<LgPreset>();
foreach (var preset in presets)
{
if (preset.Triggers.Any(t => t.TriggerActive(triggerContext)))
{
toApplyPresets.Add(preset);
}
}
var toApplyPresets = presets.Where(p => p.Triggers.Any(t => t.TriggerActive(triggerContext))).ToList();
if (toApplyPresets.Any())
{
LgPreset toApplyPreset;
if (toApplyPresets.Count > 1)
{
toApplyPreset = toApplyPresets.FirstOrDefault(p => p.Triggers.Any(t => !t.IncludedProcesses.Contains("*")));
toApplyPreset = toApplyPreset != null ? toApplyPreset : toApplyPresets.First();
}
else
{
toApplyPreset = toApplyPresets.First();
}
var toApplyPreset = toApplyPresets.FirstOrDefault(p => toApplyPresets.Count == 1 || p.Triggers.Any(t => !t.IncludedProcesses.Contains("*"))) ?? toApplyPresets.First();
if (_lastTriggeredPreset != toApplyPreset)
{
@@ -815,6 +671,78 @@ namespace ColorControl.Services.LG
}
}
private async Task HandleScreenSaverProcessAsync(IList<Process> processes, List<LgDevice> connectedDevices)
{
var process = processes.FirstOrDefault(p => p.ProcessName.ToLowerInvariant().EndsWith(".scr"));
var powerOffDevices = connectedDevices.Where(d => d.PowerOffOnScreenSaver).ToList();
if (process == null)
{
powerOffDevices.ForEach(d => d.ClearPowerOffTask());
return;
}
var parent = process.Parent(processes);
// Ignore manually started screen savers
if (parent?.ProcessName.Contains("winlogon") != true)
{
return;
}
Logger.Debug($"Screensaver started: {process.ProcessName}, parent: {parent.ProcessName}");
try
{
foreach (var device in powerOffDevices)
{
Logger.Debug($"Screensaver check: test connection with {device.Name}...");
var test = await device.TestConnection();
Logger.Debug("Screensaver check: test connection result: " + test);
if (!test)
{
continue;
}
if (device.ScreenSaverMinimalDuration > 0)
{
_poweredOffByScreenSaver = true;
device.PowerOffIn(device.ScreenSaverMinimalDuration);
continue;
}
Logger.Debug($"Screensaver check: powering off tv {device.Name} because of screensaver");
try
{
_poweredOffByScreenSaver = await device.PowerOff(true).WaitAsync(TimeSpan.FromSeconds(5));
}
catch (TimeoutException)
{
// Assume powering off was successful
_poweredOffByScreenSaver = true;
Logger.Error($"Screensaver check: timeout exception while powering off (probably connection closed)");
}
catch (Exception pex)
{
// Assume powering off was successful
_poweredOffByScreenSaver = true;
Logger.Error($"Screensaver check: exception while powering off (probably connection closed): " + pex.Message);
}
Logger.Debug($"Screensaver check: powered off tv {device.Name}");
}
_poweredOffByScreenSaverProcessId = process.Id;
}
catch (Exception e)
{
Logger.Error($"Screensaver check: can't power off: " + e.ToLogString());
}
}
internal void AddCustomDevice(LgDevice device)
{
Devices.Add(device);
@@ -929,7 +857,7 @@ namespace ColorControl.Services.LG
return;
}
if (checkUserSession && !UserSessionInfo.UserLocalSession)
if (checkUserSession && !_sessionSwitchDispatcher.UserLocalSession)
{
Logger.Debug($"WakeAfterStartupOrResume: not waking because session info indicates no local session");
return;
+1 -2
View File
@@ -1,7 +1,6 @@
using ColorControl.Common;
using ColorControl.Forms;
using ColorControl.Native;
using NLog;
using nspector;
using nspector.Common;
using nspector.Common.Meta;
@@ -24,7 +23,7 @@ namespace ColorControl.Services.NVIDIA
{
public static readonly int SHORTCUTID_NVQA = -200;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
//private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private Config _config;
private NvService _nvService;
+9
View File
@@ -28,6 +28,7 @@ namespace ColorControl
public bool RunningFromScheduledTask { get; private set; }
public bool ActivateChromeFontFix { get; private set; }
public bool DeactivateChromeFontFix { get; private set; }
public string ChromeFontFixApplicationDataFolder { get; private set; }
public bool ExecuteHelp { get; private set; }
public bool ExecuteNvidiaPreset { get; private set; }
public string NvidiaPresetIdOrName { get; private set; }
@@ -63,6 +64,12 @@ namespace ColorControl
{
switch (parseNameParam)
{
case ActivateChromeFontFixParam:
case DeactivateChromeFontFixParam:
{
settings.ChromeFontFixApplicationDataFolder = arg;
break;
}
case ExecuteNvidiaPresetParam:
{
settings.NvidiaPresetIdOrName = arg;
@@ -132,11 +139,13 @@ namespace ColorControl
case ActivateChromeFontFixParam:
{
settings.ActivateChromeFontFix = true;
parseNameParam = ActivateChromeFontFixParam;
break;
}
case DeactivateChromeFontFixParam:
{
settings.DeactivateChromeFontFix = true;
parseNameParam = DeactivateChromeFontFixParam;
break;
}
case ExecuteHelpParam:
@@ -1,4 +1,5 @@
using ColorControl.Common;
using ColorControl.Services.EventDispatcher;
using ColorControl.Services.LG;
using ColorControl.Services.NVIDIA;
using Microsoft.Extensions.Hosting;
@@ -18,8 +19,14 @@ namespace ColorControl.Svc
public sealed class ColorControlBackgroundService : BackgroundService
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly SessionSwitchDispatcher _sessionSwitchDispatcher;
private static string LgConfigFile = "LgConfig.json";
public ColorControlBackgroundService(SessionSwitchDispatcher sessionSwitchDispatcher)
{
_sessionSwitchDispatcher = sessionSwitchDispatcher;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
@@ -207,7 +214,7 @@ namespace ColorControl.Svc
private async Task WakeDevicesAsync()
{
if (!UserSessionInfo.UserLocalSession)
if (!_sessionSwitchDispatcher.UserLocalSession)
{
return;
}
+2 -2
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<UseWindowsForms>true</UseWindowsForms>
<Nullable>enable</Nullable>
@@ -10,7 +10,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Resources.Extensions" Version="6.0.0" />
<PackageReference Include="System.Resources.Extensions" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
+2 -2
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-windows10.0.20348.0</TargetFramework>
<Version>0.8.1.101</Version>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<Version>0.8.1.102</Version>
<Company>falahati.net</Company>
<Description>NvAPIWrapper is a .Net wrapper for NVIDIA public API</Description>
<Authors>Soroush Falahati</Authors>