Compare commits

...
1 Commits
8 changed files with 452 additions and 268 deletions

No files matched your search

+2 -2
View File
@@ -18,8 +18,8 @@
<PublisherName>Maassoft</PublisherName>
<Company>Maassoft</Company>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>5.6.0.0</ApplicationVersion>
<Version>5.6.0.0</Version>
<ApplicationVersion>5.7.0.0</ApplicationVersion>
<Version>5.7.0.0</Version>
<UseApplicationTrust>false</UseApplicationTrust>
<PublishWizardCompleted>true</PublishWizardCompleted>
<BootstrapperEnabled>false</BootstrapperEnabled>
+40 -13
View File
@@ -53,7 +53,7 @@ namespace ColorControl
public static Func<string, string[], bool> ExternalServiceHandler;
public static List<string> DefaultActionsOnGameBar = new() { "backlight", "contrast", "brightness", "color" };
public string Name { get; private set; }
public string Name { get; private set; }
public string IpAddress { get; private set; }
public string MacAddress { get; private set; }
public bool IsCustom { get; private set; }
@@ -66,7 +66,9 @@ namespace ColorControl
public bool PowerOffOnStandby { get; set; }
public bool PowerSwitchOnScreenSaver { get; set; }
public bool PowerOnAfterManualPowerOff { get; set; }
public bool PowerByWindows { get; set; }
public bool TriggersEnabled { get; set; }
public int HDMIPortNumber { get; set; }
private List<string> _actionsForGameBar;
@@ -113,6 +115,9 @@ namespace ColorControl
[JsonIgnore]
public LgDevicePictureSettings PictureSettings { get; private set; }
[JsonIgnore]
public string CurrentAppId { get; private set; }
public event EventHandler PictureSettingsChangedEvent;
public event EventHandler PowerStateChangedEvent;
@@ -284,6 +289,7 @@ namespace ColorControl
//await _lgTvApi.SubscribeVolume(VolumeChanged);
await _lgTvApi.SubscribePowerState(PowerStateChanged);
await _lgTvApi.SubscribePictureSettings(PictureSettingsChanged);
await _lgTvApi.SubscribeForegroundApp(ForegroundAppChanged);
//await _lgTvApi.Reboot();
@@ -323,7 +329,7 @@ namespace ColorControl
{
var settings = payload.settings;
Logger.Debug($"PictureSettingsChanged: {JsonConvert.SerializeObject(settings)}");
Logger.Debug($"[{Name}] PictureSettingsChanged: {JsonConvert.SerializeObject(settings)}");
if (settings.backlight != null)
{
@@ -385,6 +391,18 @@ namespace ColorControl
return true;
}
public bool ForegroundAppChanged(dynamic payload)
{
Logger.Debug($"[{Name}] ForegroundAppChanged: {JsonConvert.SerializeObject(payload)}");
if (payload.appId != null)
{
CurrentAppId = payload.appId;
}
return true;
}
public bool IsConnected()
{
return !_lgTvApi?.ConnectionClosed ?? false;
@@ -586,6 +604,11 @@ namespace ColorControl
public async Task<IEnumerable<LgApp>> GetApps(bool force = false)
{
if (!force)
{
await Task.Delay(5000);
}
if (!await Connected(force))
{
Logger.Debug("Cannot refresh apps: no connection could be made");
@@ -595,17 +618,30 @@ namespace ColorControl
return await _lgTvApi.GetApps(force);
}
internal async Task<bool> PowerOff()
internal async Task<bool> PowerOff(bool checkHdmi = false)
{
if (!await Connected(true) || CurrentState != PowerState.Active)
{
return false;
}
if (checkHdmi && CurrentAppId != null && HDMIPortNumber != 0 && !CurrentAppId.EndsWith($".hdmi{HDMIPortNumber}", StringComparison.InvariantCulture))
{
Logger.Debug($"[{Name}] PowerOff is ignored because current app {CurrentAppId} does not match configured HDMI port {HDMIPortNumber}");
return true;
}
PoweredOffViaApp = true;
_poweredOffViaAppDateTime = DateTimeOffset.Now;
await _lgTvApi.TurnOff();
try
{
await _lgTvApi.TurnOff().WaitAsync(TimeSpan.FromSeconds(2));
}
catch (TimeoutException ex)
{
Logger.Debug($"Timeout when turning off tv: {ex.Message}");
}
return true;
}
@@ -702,15 +738,6 @@ namespace ColorControl
}
}
if (result)
{
var resumeScript = Path.Combine(Program.DataDir, "ResumeScript.bat");
if (File.Exists(resumeScript))
{
Utils.StartProcess(resumeScript, hidden: true);
}
}
return result;
}
+223 -140
View File
@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
@@ -23,6 +24,13 @@ namespace ColorControl
StandBy = 5
}
internal enum WindowsPowerSetting
{
Off = 0,
On = 1,
Dimmed = 2
}
internal class ProcessMonitorContext
{
public List<LgDevice> Devices { get; set; }
@@ -66,6 +74,7 @@ namespace ColorControl
private Task _monitorTask;
private int _monitorTaskCounter;
private LgPreset _lastTriggeredPreset;
private RestartDetector _restartDetector;
public LgService(string dataPath, bool allowPowerOn) : base(dataPath, "LgPresets.json")
{
@@ -73,6 +82,8 @@ namespace ColorControl
LgPreset.LgApps = _lgApps;
_restartDetector = new RestartDetector();
LoadConfig();
LoadPresets();
LoadRemoteControlButtons();
@@ -140,21 +151,25 @@ namespace ColorControl
presets = JsonConvert.DeserializeObject<List<LgPreset>>(json);
}
return presets;
}
private void LoadConfig()
{
_configFilename = Path.Combine(_dataPath, "LgConfig.json");
if (File.Exists(_configFilename))
try
{
Config = JsonConvert.DeserializeObject<LgServiceConfig>(File.ReadAllText(_configFilename));
if (File.Exists(_configFilename))
{
Config = JsonConvert.DeserializeObject<LgServiceConfig>(File.ReadAllText(_configFilename));
}
}
else
catch (Exception ex)
{
Config = new LgServiceConfig();
Logger.Error($"LoadConfig: {ex.Message}");
}
Config ??= new LgServiceConfig();
LgPreset.LgDevices = Config.Devices;
}
@@ -289,7 +304,7 @@ namespace ColorControl
Devices.RemoveAll(d => !d.IsCustom && !autoIpAddresses.Contains(d.IpAddress));
var newAutoDevices = autoDevices.Where(ad => !Devices.Any(d => d.IpAddress.Equals(ad.IpAddress)));
var newAutoDevices = autoDevices.Where(ad => ad.IpAddress != null && !Devices.Any(d => d.IpAddress != null && d.IpAddress.Equals(ad.IpAddress)));
Devices.AddRange(newAutoDevices);
if (Devices.Any())
@@ -404,22 +419,6 @@ namespace ColorControl
return await SelectedDevice?.PowerOff();
}
internal Task PowerOffOnShutdownOrResume(PowerOnOffState state = PowerOnOffState.ShutDown)
{
var devices = Devices.Where(d => state == PowerOnOffState.ShutDown && d.PowerOffOnShutdown ||
state == PowerOnOffState.StandBy && d.PowerOffOnStandby);
var tasks = new List<Task>();
foreach (var device in devices)
{
var task = device.PowerOff();
tasks.Add(task);
}
return Task.WhenAll(tasks.ToArray());
}
internal bool WakeSelectedDevice()
{
return SelectedDevice?.Wake() ?? false;
@@ -427,26 +426,11 @@ namespace ColorControl
internal void WakeAfterStartupOrResume(PowerOnOffState state = PowerOnOffState.StartUp, bool checkUserSession = true)
{
if (checkUserSession && !UserSessionInfo.UserLocalSession)
{
Logger.Debug($"WakeAfterStartupOrResume: not waking because session info indicates no local session");
return;
}
var wakeDevices = Devices.Where(d => state == PowerOnOffState.StartUp && d.PowerOnAfterStartup ||
state == PowerOnOffState.Resume && d.PowerOnAfterResume ||
var wakeDevices = Devices.Where(d => state == PowerOnOffState.StartUp && d.PowerOnAfterStartup ||
state == PowerOnOffState.Resume && d.PowerOnAfterResume ||
state == PowerOnOffState.ScreenSaver && d.PowerSwitchOnScreenSaver);
foreach (var device in wakeDevices)
{
if (!device.PowerOnAfterManualPowerOff && device.PoweredOffBy == LgDevice.PowerOffSource.Manually)
{
Logger.Debug($"[{device.Name}]: device was manually powered off by user, not powering on");
continue;
}
device.DisposeConnection();
var _ = device.WakeAndConnectWithRetries(Config.PowerOnRetries);
}
PowerOnDevices(wakeDevices, state, checkUserSession);
}
public void InstallEventHandlers()
@@ -492,27 +476,8 @@ namespace ColorControl
return;
}
if (Devices.Any(d => d.PowerOffOnStandby))
{
NativeMethods.SetThreadExecutionState(NativeConstants.ES_CONTINUOUS | NativeConstants.ES_SYSTEM_REQUIRED | NativeConstants.ES_AWAYMODE_REQUIRED);
try
{
var standByScript = Path.Combine(Program.DataDir, "StandByScript.bat");
if (File.Exists(standByScript))
{
Utils.StartProcess(standByScript, hidden: true);
}
Logger.Debug("Powering off tv...");
var task = PowerOffOnShutdownOrResume(PowerOnOffState.StandBy);
Utils.WaitForTask(task);
Logger.Debug("Done powering off tv");
}
finally
{
NativeMethods.SetThreadExecutionState(NativeConstants.ES_CONTINUOUS);
}
}
var devices = Devices.Where(d => d.PowerOffOnStandby);
PowerOffDevices(devices, PowerOnOffState.StandBy);
}
private void SessionEnded(object sender, SessionEndedEventArgs e)
@@ -644,84 +609,15 @@ namespace ColorControl
wasConnected = true;
}
if (connectedDevices.Any(d => d.PowerSwitchOnScreenSaver))
{
lastProcessId = await HandleScreenSaverProcessAsync(lastProcessId, processes, connectedDevices);
}
MonitorContext.Devices = connectedDevices.Where(d => d.TriggersEnabled).ToList();
MonitorContext.RunningProcesses = processes;
//if (lastProcesses != null)
//{
// monitorContext.StartedProcesses = processes.Where(p => !lastProcesses.Any(lp => lp.Id == p.Id)).ToArray();
// monitorContext.StoppedProcesses = lastProcesses.Where(lp => !processes.Any(p => p.Id == lp.Id)).ToArray();
//}
//else
//{
// monitorContext.StartedProcesses = null;
// monitorContext.StoppedProcesses = null;
//}
//if (monitorContext.StartedProcesses?.Any() ?? false)
//{
// Logger.Debug("Started processes: " + string.Join(", ", monitorContext.StartedProcesses.Select(p => p.ProcessName)));
//}
//lastProcesses = processes;
var process = processes.FirstOrDefault(p => p.ProcessName.ToLowerInvariant().EndsWith(".scr"));
if (process != null)
{
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)
{
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().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;
}
}
else
{
await ExecuteProcessPresets(MonitorContext);
}
await ExecuteProcessPresets(MonitorContext);
}
catch (Exception ex)
{
@@ -730,12 +626,75 @@ namespace ColorControl
}
}
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)
{
return 0;
}
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)
{
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().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) &&
((string.IsNullOrEmpty(p.DeviceMacAddress) && selectedDevice?.TriggersEnabled == true)
var presets = _presets.Where(p => p.Triggers.Any(t => t.Trigger == PresetTriggerType.ProcessSwitch) &&
((string.IsNullOrEmpty(p.DeviceMacAddress) && selectedDevice?.TriggersEnabled == true)
|| Devices.Any(d => d.TriggersEnabled && p.DeviceMacAddress.Equals(d.MacAddress, StringComparison.OrdinalIgnoreCase))));
if (!presets.Any())
{
@@ -753,7 +712,14 @@ namespace ColorControl
if (processId > 0)
{
context.ForegroundProcess = context.RunningProcesses.FirstOrDefault(p => p.Id == processId);
var process = context.RunningProcesses.FirstOrDefault(p => p.Id == processId);
if (process?.ProcessName?.Contains(".scr") ?? false)
{
return;
}
context.ForegroundProcess = process;
context.ForegroundProcessIsFullScreen = isFullScreen;
}
else
@@ -851,5 +817,122 @@ namespace ColorControl
SelectedDevice = Devices.Any() ? Devices.First() : null;
}
}
public void PowerSettingChanged(WindowsPowerSetting setting)
{
var devices = Devices.Where(d => d.PowerByWindows).ToList();
if (setting == WindowsPowerSetting.Off)
{
PowerOffDevices(devices, PowerOnOffState.StandBy);
}
else if (setting == WindowsPowerSetting.On)
{
PowerOnDevices(devices);
}
}
public void PowerOffDevices(IEnumerable<LgDevice> devices, PowerOnOffState state = PowerOnOffState.ShutDown)
{
if (!devices.Any())
{
return;
}
if (NativeMethods.GetAsyncKeyState(NativeConstants.VK_CONTROL) < 0 || NativeMethods.GetAsyncKeyState(NativeConstants.VK_RCONTROL) < 0)
{
Logger.Debug("Not powering off because CONTROL-key is down");
return;
}
NativeMethods.SetThreadExecutionState(NativeConstants.ES_CONTINUOUS | NativeConstants.ES_SYSTEM_REQUIRED | NativeConstants.ES_AWAYMODE_REQUIRED);
try
{
if (state == PowerOnOffState.ShutDown)
{
var sleep = Config.ShutdownDelay;
Logger.Debug($"PowerOffDevices: Waiting for {sleep} milliseconds...");
while (sleep > 0 && _restartDetector?.PowerOffDetected == false)
{
Thread.Sleep(100);
if (_restartDetector != null && (_restartDetector.RestartDetected || _restartDetector.IsRebootInProgress()))
{
Logger.Debug("Not powering off because of a restart");
return;
}
sleep -= 100;
}
}
else if (state == PowerOnOffState.StandBy)
{
var standByScript = Path.Combine(Program.DataDir, "StandByScript.bat");
if (File.Exists(standByScript))
{
Utils.StartProcess(standByScript, hidden: true);
}
}
Logger.Debug("Powering off tv(s)...");
var tasks = new List<Task>();
foreach (var device in devices)
{
var task = device.PowerOff(true);
tasks.Add(task);
}
var waitTask = Task.WhenAll(tasks.ToArray());
Utils.WaitForTask(waitTask);
Logger.Debug("Done powering off tv(s)");
}
finally
{
NativeMethods.SetThreadExecutionState(NativeConstants.ES_CONTINUOUS);
}
}
public void PowerOnDevices(IEnumerable<LgDevice> devices, PowerOnOffState state = PowerOnOffState.StartUp, bool checkUserSession = true)
{
if (!devices.Any())
{
return;
}
if (checkUserSession && !UserSessionInfo.UserLocalSession)
{
Logger.Debug($"WakeAfterStartupOrResume: not waking because session info indicates no local session");
return;
}
var resumeScript = Path.Combine(Program.DataDir, "ResumeScript.bat");
var tasks = new List<Task>();
foreach (var device in devices)
{
if (!device.PowerOnAfterManualPowerOff && device.PoweredOffBy == LgDevice.PowerOffSource.Manually)
{
Logger.Debug($"[{device.Name}]: device was manually powered off by user, not powering on");
continue;
}
device.DisposeConnection();
var task = device.WakeAndConnectWithRetries(Config.PowerOnRetries);
tasks.Add(task);
}
if (File.Exists(resumeScript))
{
var waitTask = Task.WhenAll(tasks.ToArray());
Utils.WaitForTask(waitTask);
Utils.StartProcess(resumeScript, hidden: true);
}
}
}
}
}
+88 -54
View File
@@ -104,9 +104,11 @@
this.lvAmdPresets = new System.Windows.Forms.ListView();
this.tabLG = new System.Windows.Forms.TabPage();
this.scLgController = new System.Windows.Forms.SplitContainer();
this.cbxLgPcHdmiPort = new System.Windows.Forms.ComboBox();
this.lblLgPcHdmiPort = new System.Windows.Forms.Label();
this.edtLgPresetDescription = new System.Windows.Forms.TextBox();
this.lblLgPresetDescription = new System.Windows.Forms.Label();
this.btnLgDeviceOptionsHelp = new System.Windows.Forms.Button();
this.lblGameBarShortcut = new System.Windows.Forms.Label();
this.edtLgGameBarShortcut = new System.Windows.Forms.TextBox();
this.btnLgGameBar = new System.Windows.Forms.Button();
this.btnLgPresetEditTriggerConditions = new System.Windows.Forms.Button();
this.edtLgPresetTriggerConditions = new System.Windows.Forms.TextBox();
@@ -172,6 +174,8 @@
this.lblFixChromeFontsDescription = new System.Windows.Forms.Label();
this.chkFixChromeFonts = new System.Windows.Forms.CheckBox();
this.grpLGOptions = new System.Windows.Forms.GroupBox();
this.lblGameBarShortcut = new System.Windows.Forms.Label();
this.edtLgGameBarShortcut = new System.Windows.Forms.TextBox();
this.lblLgOptionShutdownDelayHelp = new System.Windows.Forms.Label();
this.edtLgOptionShutdownDelay = new System.Windows.Forms.NumericUpDown();
this.lblLgOptionShutdownDelay = new System.Windows.Forms.Label();
@@ -201,8 +205,6 @@
this.lbPlugins = new System.Windows.Forms.ListBox();
this.label7 = new System.Windows.Forms.Label();
this.lblInfo = new System.Windows.Forms.Label();
this.edtLgPresetDescription = new System.Windows.Forms.TextBox();
this.lblLgPresetDescription = new System.Windows.Forms.Label();
this.tcMain.SuspendLayout();
this.tabNVIDIA.SuspendLayout();
this.mnuNvPresets.SuspendLayout();
@@ -988,11 +990,11 @@
//
// scLgController.Panel1
//
this.scLgController.Panel1.Controls.Add(this.cbxLgPcHdmiPort);
this.scLgController.Panel1.Controls.Add(this.lblLgPcHdmiPort);
this.scLgController.Panel1.Controls.Add(this.edtLgPresetDescription);
this.scLgController.Panel1.Controls.Add(this.lblLgPresetDescription);
this.scLgController.Panel1.Controls.Add(this.btnLgDeviceOptionsHelp);
this.scLgController.Panel1.Controls.Add(this.lblGameBarShortcut);
this.scLgController.Panel1.Controls.Add(this.edtLgGameBarShortcut);
this.scLgController.Panel1.Controls.Add(this.btnLgGameBar);
this.scLgController.Panel1.Controls.Add(this.btnLgPresetEditTriggerConditions);
this.scLgController.Panel1.Controls.Add(this.edtLgPresetTriggerConditions);
@@ -1040,6 +1042,56 @@
this.scLgController.SplitterWidth = 5;
this.scLgController.TabIndex = 43;
//
// cbxLgPcHdmiPort
//
this.cbxLgPcHdmiPort.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cbxLgPcHdmiPort.FormattingEnabled = true;
this.cbxLgPcHdmiPort.Items.AddRange(new object[] {
"None",
"HDMI1",
"HDMI2",
"HDMI3",
"HDMI4"});
this.cbxLgPcHdmiPort.Location = new System.Drawing.Point(667, 42);
this.cbxLgPcHdmiPort.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.cbxLgPcHdmiPort.Name = "cbxLgPcHdmiPort";
this.cbxLgPcHdmiPort.Size = new System.Drawing.Size(86, 23);
this.cbxLgPcHdmiPort.TabIndex = 62;
this.cbxLgPcHdmiPort.SelectedIndexChanged += new System.EventHandler(this.cbxLgPcHdmiPort_SelectedIndexChanged);
//
// lblLgPcHdmiPort
//
this.lblLgPcHdmiPort.AutoSize = true;
this.lblLgPcHdmiPort.Location = new System.Drawing.Point(577, 45);
this.lblLgPcHdmiPort.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lblLgPcHdmiPort.Name = "lblLgPcHdmiPort";
this.lblLgPcHdmiPort.Size = new System.Drawing.Size(84, 15);
this.lblLgPcHdmiPort.TabIndex = 61;
this.lblLgPcHdmiPort.Text = "PC HDMI port:";
//
// edtLgPresetDescription
//
this.edtLgPresetDescription.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.edtLgPresetDescription.Enabled = false;
this.edtLgPresetDescription.Location = new System.Drawing.Point(100, 469);
this.edtLgPresetDescription.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.edtLgPresetDescription.Multiline = true;
this.edtLgPresetDescription.Name = "edtLgPresetDescription";
this.edtLgPresetDescription.Size = new System.Drawing.Size(694, 43);
this.edtLgPresetDescription.TabIndex = 60;
//
// lblLgPresetDescription
//
this.lblLgPresetDescription.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.lblLgPresetDescription.AutoSize = true;
this.lblLgPresetDescription.Location = new System.Drawing.Point(6, 474);
this.lblLgPresetDescription.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lblLgPresetDescription.Name = "lblLgPresetDescription";
this.lblLgPresetDescription.Size = new System.Drawing.Size(70, 15);
this.lblLgPresetDescription.TabIndex = 59;
this.lblLgPresetDescription.Text = "Description:";
//
// btnLgDeviceOptionsHelp
//
this.btnLgDeviceOptionsHelp.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
@@ -1052,28 +1104,6 @@
this.btnLgDeviceOptionsHelp.UseVisualStyleBackColor = true;
this.btnLgDeviceOptionsHelp.Click += new System.EventHandler(this.btnLgDeviceOptionsHelp_Click);
//
// lblGameBarShortcut
//
this.lblGameBarShortcut.AutoSize = true;
this.lblGameBarShortcut.Location = new System.Drawing.Point(597, 45);
this.lblGameBarShortcut.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lblGameBarShortcut.Name = "lblGameBarShortcut";
this.lblGameBarShortcut.Size = new System.Drawing.Size(55, 15);
this.lblGameBarShortcut.TabIndex = 57;
this.lblGameBarShortcut.Text = "Shortcut:";
//
// edtLgGameBarShortcut
//
this.edtLgGameBarShortcut.Location = new System.Drawing.Point(667, 42);
this.edtLgGameBarShortcut.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.edtLgGameBarShortcut.Name = "edtLgGameBarShortcut";
this.edtLgGameBarShortcut.ReadOnly = true;
this.edtLgGameBarShortcut.Size = new System.Drawing.Size(128, 23);
this.edtLgGameBarShortcut.TabIndex = 56;
this.edtLgGameBarShortcut.TextChanged += new System.EventHandler(this.edtLgGameBarShortcut_TextChanged);
this.edtLgGameBarShortcut.KeyDown += new System.Windows.Forms.KeyEventHandler(this.edtLgGameBarShortcut_KeyDown);
this.edtLgGameBarShortcut.KeyUp += new System.Windows.Forms.KeyEventHandler(this.edtLgGameBarShortcut_KeyUp);
//
// btnLgGameBar
//
this.btnLgGameBar.Location = new System.Drawing.Point(478, 40);
@@ -1606,7 +1636,8 @@
"Automatically power off on standby",
"Automatically power off/on when screensaver activates/deactivates",
"Power on even after manual power off",
"Allow triggers to be fired for this device"});
"Allow triggers to be fired for this device",
"Use Windows power settings"});
this.clbLgPower.Location = new System.Drawing.Point(6, 70);
this.clbLgPower.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.clbLgPower.MultiColumn = true;
@@ -1805,6 +1836,8 @@
//
// grpLGOptions
//
this.grpLGOptions.Controls.Add(this.lblGameBarShortcut);
this.grpLGOptions.Controls.Add(this.edtLgGameBarShortcut);
this.grpLGOptions.Controls.Add(this.lblLgOptionShutdownDelayHelp);
this.grpLGOptions.Controls.Add(this.edtLgOptionShutdownDelay);
this.grpLGOptions.Controls.Add(this.lblLgOptionShutdownDelay);
@@ -1822,6 +1855,28 @@
this.grpLGOptions.TabStop = false;
this.grpLGOptions.Text = "LG controller";
//
// lblGameBarShortcut
//
this.lblGameBarShortcut.AutoSize = true;
this.lblGameBarShortcut.Location = new System.Drawing.Point(201, 127);
this.lblGameBarShortcut.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lblGameBarShortcut.Name = "lblGameBarShortcut";
this.lblGameBarShortcut.Size = new System.Drawing.Size(108, 15);
this.lblGameBarShortcut.TabIndex = 59;
this.lblGameBarShortcut.Text = "Game Bar shortcut:";
//
// edtLgGameBarShortcut
//
this.edtLgGameBarShortcut.Location = new System.Drawing.Point(307, 121);
this.edtLgGameBarShortcut.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.edtLgGameBarShortcut.Name = "edtLgGameBarShortcut";
this.edtLgGameBarShortcut.ReadOnly = true;
this.edtLgGameBarShortcut.Size = new System.Drawing.Size(128, 23);
this.edtLgGameBarShortcut.TabIndex = 58;
this.edtLgGameBarShortcut.TextChanged += new System.EventHandler(this.edtLgGameBarShortcut_TextChanged);
this.edtLgGameBarShortcut.KeyDown += new System.Windows.Forms.KeyEventHandler(this.edtLgGameBarShortcut_KeyDown);
this.edtLgGameBarShortcut.KeyUp += new System.Windows.Forms.KeyEventHandler(this.edtLgGameBarShortcut_KeyUp);
//
// lblLgOptionShutdownDelayHelp
//
this.lblLgOptionShutdownDelayHelp.AutoSize = true;
@@ -2192,29 +2247,6 @@
this.lblInfo.TabIndex = 1;
this.lblInfo.Text = "Info";
//
// edtLgPresetDescription
//
this.edtLgPresetDescription.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.edtLgPresetDescription.Enabled = false;
this.edtLgPresetDescription.Location = new System.Drawing.Point(100, 469);
this.edtLgPresetDescription.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.edtLgPresetDescription.Multiline = true;
this.edtLgPresetDescription.Name = "edtLgPresetDescription";
this.edtLgPresetDescription.Size = new System.Drawing.Size(694, 43);
this.edtLgPresetDescription.TabIndex = 60;
//
// lblLgPresetDescription
//
this.lblLgPresetDescription.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.lblLgPresetDescription.AutoSize = true;
this.lblLgPresetDescription.Location = new System.Drawing.Point(6, 474);
this.lblLgPresetDescription.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lblLgPresetDescription.Name = "lblLgPresetDescription";
this.lblLgPresetDescription.Size = new System.Drawing.Size(70, 15);
this.lblLgPresetDescription.TabIndex = 59;
this.lblLgPresetDescription.Text = "Description:";
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
@@ -2440,8 +2472,6 @@
private System.Windows.Forms.CheckBox chkCheckForUpdates;
private System.Windows.Forms.CheckBox chkLgShowAdvancedActions;
private System.Windows.Forms.Button btnLgGameBar;
private System.Windows.Forms.Label lblGameBarShortcut;
private System.Windows.Forms.TextBox edtLgGameBarShortcut;
private System.Windows.Forms.CheckBox chkGdiScaling;
private System.Windows.Forms.Button btnLgDeviceOptionsHelp;
private System.Windows.Forms.Label lblLgOptionShutdownDelayHelp;
@@ -2449,6 +2479,10 @@
private System.Windows.Forms.Label lblLgOptionShutdownDelay;
private System.Windows.Forms.TextBox edtLgPresetDescription;
private System.Windows.Forms.Label lblLgPresetDescription;
private System.Windows.Forms.Label lblGameBarShortcut;
private System.Windows.Forms.TextBox edtLgGameBarShortcut;
private System.Windows.Forms.ComboBox cbxLgPcHdmiPort;
private System.Windows.Forms.Label lblLgPcHdmiPort;
}
}
+67 -54
View File
@@ -15,8 +15,8 @@ using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
@@ -42,7 +42,6 @@ namespace ColorControl
private bool _disableEvents = false;
private Config _config;
private bool _setVisibleCalled = false;
private RestartDetector _restartDetector;
private LgService _lgService;
@@ -63,6 +62,7 @@ namespace ColorControl
private LgGameBar _gameBarForm;
private KeyboardHookManager _keyboardHookManager;
private IntPtr _screenStateNotify;
public MainForm(AppContext appContext)
{
@@ -121,8 +121,7 @@ namespace ColorControl
InitInfo();
UserSessionInfo.Install();
_restartDetector = new RestartDetector();
_screenStateNotify = Utils.RegisterPowerSettingNotification(Handle, ref Utils.GUID_CONSOLE_DISPLAY_STATE, 0);
//Scale(new SizeF(1.25F, 1.25F));
@@ -183,7 +182,7 @@ namespace ColorControl
try
{
_lgService = new LgService(_dataDir, StartUpParams.RunningFromScheduledTask);
_lgService.RefreshDevices(afterStartUp: true).ContinueWith((_) => BeginInvoke(new Action(AfterLgServiceRefreshDevices)));
_lgService.RefreshDevices(afterStartUp: true).ContinueWith((_) => BeginInvoke(() => AfterLgServiceRefreshDevices()));
FillLgPresets();
@@ -232,7 +231,7 @@ namespace ColorControl
private void Invoke()
{
BeginInvoke(new Action(ToggleGameBar));
BeginInvoke(() => ToggleGameBar());
}
private void AfterLgServiceRefreshDevices()
@@ -479,46 +478,13 @@ namespace ColorControl
GlobalSave();
if (SystemShutdown && _lgService.Devices.Any(d => d.PowerOffOnShutdown))
if (SystemShutdown && _lgService != null)
{
Logger.Debug($"MainForm_FormClosing: SystemShutdown");
if (NativeMethods.GetAsyncKeyState(NativeConstants.VK_CONTROL) < 0 || NativeMethods.GetAsyncKeyState(NativeConstants.VK_RCONTROL) < 0)
{
Logger.Debug("Not powering off because CONTROL-key is down");
return;
}
var devices = _lgService.Devices.Where(d => d.PowerOffOnShutdown);
var sleep = _lgService.Config.ShutdownDelay;
Logger.Debug($"MainForm_FormClosing: Waiting for {sleep} milliseconds...");
NativeMethods.SetThreadExecutionState(NativeConstants.ES_CONTINUOUS | NativeConstants.ES_SYSTEM_REQUIRED | NativeConstants.ES_AWAYMODE_REQUIRED);
try
{
while (sleep > 0 && _restartDetector?.PowerOffDetected == false)
{
Thread.Sleep(100);
if (_restartDetector != null && (_restartDetector.RestartDetected || _restartDetector.IsRebootInProgress()))
{
Logger.Debug("Not powering off because of a restart");
return;
}
sleep -= 100;
}
Logger.Debug("Powering off tv...");
var task = _lgService.PowerOffOnShutdownOrResume();
Utils.WaitForTask(task);
Logger.Debug("Done powering off tv");
//ExecPowerOffPreset(true);
}
finally
{
NativeMethods.SetThreadExecutionState(NativeConstants.ES_CONTINUOUS);
}
_lgService.PowerOffDevices(devices);
}
}
@@ -626,6 +592,26 @@ namespace ColorControl
Logger.Debug("WM_BRINGTOFRONT message received, opening form");
OpenForm(this, EventArgs.Empty);
}
else if (m.Msg == NativeConstants.WM_SYSCOMMAND)
{
//Logger.Debug($"WM_SYSCOMMAND: {m.WParam.ToInt32()}");
if (m.WParam.ToInt32() == NativeConstants.SC_MONITORPOWER)
{
}
}
else if (m.Msg == NativeConstants.WM_POWERBROADCAST)
{
if (m.WParam.ToInt32() == Utils.PBT_POWERSETTINGCHANGE)
{
var ps = Marshal.PtrToStructure<Utils.POWERBROADCAST_SETTING>(m.LParam);
Logger.Debug($"PBT_POWERSETTINGCHANGE: {ps.Data}");
_lgService?.PowerSettingChanged((LgService.WindowsPowerSetting)ps.Data);
}
}
base.WndProc(ref m);
}
@@ -668,6 +654,12 @@ namespace ColorControl
{
// Hide tray icon, otherwise it will remain shown until user mouses over it
_trayIcon.Visible = false;
if (_screenStateNotify != IntPtr.Zero)
{
Utils.UnregisterPowerSettingNotification(_screenStateNotify);
_screenStateNotify = IntPtr.Zero;
}
}
private void MainForm_Resize(object sender, EventArgs e)
@@ -781,7 +773,7 @@ namespace ColorControl
if (_lgService == null)
{
ShowControls(tabLG, false, lblLgError);
lblLgError.Text = "Error while initializing the LG-controller. You either don't have a LG TV or it is disabled.";
lblLgError.Text = "Error while initializing the LG-controller. You either don't have a LG TV, it is disabled or a configuration file is corrupt.";
lblLgError.Visible = true;
}
@@ -1404,6 +1396,11 @@ namespace ColorControl
private void InitLgTab()
{
if (_lgService == null)
{
return;
}
if (scLgController.Panel2.Controls.Count == 0)
{
var rcPanel = new RemoteControlPanel(_lgService, _lgService.GetRemoteControlButtons());
@@ -1501,7 +1498,7 @@ namespace ColorControl
if (cbxLgApps.Items.Count == 0 && device != null)
{
_lgService.RefreshApps().ContinueWith((task) => BeginInvoke(new Action(FillLgApps)));
_lgService.RefreshApps().ContinueWith((task) => BeginInvoke(() => FillLgApps(false)));
}
btnLgDeviceConvertToCustom.Enabled = devices.Any();
@@ -1526,6 +1523,7 @@ namespace ColorControl
clbLgPower.SetItemChecked(4, device?.PowerSwitchOnScreenSaver ?? false);
clbLgPower.SetItemChecked(5, device?.PowerOnAfterManualPowerOff ?? false);
clbLgPower.SetItemChecked(6, device?.TriggersEnabled ?? true);
clbLgPower.SetItemChecked(7, device?.PowerByWindows ?? false);
}
finally
{
@@ -1533,10 +1531,10 @@ namespace ColorControl
}
}
private void FillLgApps()
private void FillLgApps(bool forced)
{
var lgApps = _lgService?.GetApps();
if (lgApps == null || !lgApps.Any())
if (forced && (lgApps == null || !lgApps.Any()))
{
MessageForms.WarningOk("Could not refresh the apps. Check the log for details.");
return;
@@ -1769,7 +1767,7 @@ namespace ColorControl
return;
}
var applyTask = _lgService.ApplyPreset(preset, reconnect).ContinueWith((task) => BeginInvoke(new Action<Task<bool>>(LgPresetApplied), new[] { task }));
var applyTask = _lgService.ApplyPreset(preset, reconnect).ContinueWith((task) => BeginInvoke(() => LgPresetApplied(task)));
if (wait)
{
Utils.WaitForTask(applyTask);
@@ -1807,18 +1805,21 @@ namespace ColorControl
private void btnLgRefreshApps_Click(object sender, EventArgs e)
{
_lgService.RefreshApps(true).ContinueWith((task) => BeginInvoke(new Action(FillLgApps)));
_lgService.RefreshApps(true).ContinueWith((task) => BeginInvoke(() => FillLgApps(true)));
}
private void cbxLgDevices_SelectedIndexChanged(object sender, EventArgs e)
{
cbxLgPcHdmiPort.Enabled = cbxLgDevices.SelectedIndex > -1;
if (cbxLgDevices.SelectedIndex == -1)
{
_lgService.SelectedDevice = null;
cbxLgPcHdmiPort.SelectedIndex = 0;
}
else
{
_lgService.SelectedDevice = (LgDevice)cbxLgDevices.SelectedItem;
cbxLgPcHdmiPort.SelectedIndex = _lgService.SelectedDevice.HDMIPortNumber;
}
chkLgRemoteControlShow.Enabled = _lgService.SelectedDevice != null;
btnLgRemoveDevice.Enabled = _lgService.SelectedDevice != null && _lgService.SelectedDevice.IsCustom;
@@ -2006,7 +2007,7 @@ You can also activate this option by using the Expert-button and selecting Wake-
);
}
BeginInvoke(new Action(() =>
BeginInvoke(() =>
{
device.PowerOnAfterStartup = clbLgPower.GetItemChecked(0);
device.PowerOnAfterResume = clbLgPower.GetItemChecked(1);
@@ -2015,9 +2016,10 @@ You can also activate this option by using the Expert-button and selecting Wake-
device.PowerSwitchOnScreenSaver = clbLgPower.GetItemChecked(4);
device.PowerOnAfterManualPowerOff = clbLgPower.GetItemChecked(5);
device.TriggersEnabled = clbLgPower.GetItemChecked(6);
device.PowerByWindows = clbLgPower.GetItemChecked(7);
_lgService.InstallEventHandlers();
}));
});
}
private void edtLgPowerOnAfterResumeDelay_ValueChanged(object sender, EventArgs e)
@@ -2123,7 +2125,7 @@ Do you want to continue?";
private void RefreshLgDevices()
{
_lgService.RefreshDevices(false).ContinueWith((task) => BeginInvoke(new Action(FillLgDevices)));
_lgService.RefreshDevices(false).ContinueWith((task) => BeginInvoke(() => FillLgDevices()));
}
private void FillGradient()
@@ -2211,7 +2213,7 @@ Do you want to continue?";
private void InitHandleCheckForUpdates(dynamic latest)
{
BeginInvoke(new Action<dynamic>(HandleCheckForUpdates), new[] { latest });
BeginInvoke(() => HandleCheckForUpdates(latest));
}
private void HandleCheckForUpdates(dynamic latest)
@@ -2267,7 +2269,7 @@ Do you want to continue?";
Task.Run(async () =>
{
await Task.Delay(2000);
BeginInvoke(new Action(() => ApplyNvPresetOnStartup(attempts)));
BeginInvoke(() => ApplyNvPresetOnStartup(attempts));
});
}
}
@@ -2303,7 +2305,7 @@ Do you want to continue?";
Task.Run(async () =>
{
await Task.Delay(2000);
BeginInvoke(new Action(() => ApplyAmdPresetOnStartup(attempts)));
BeginInvoke(() => ApplyAmdPresetOnStartup(attempts));
});
}
}
@@ -3131,6 +3133,7 @@ The InStart and Software Update items are now visible under the Expert-button."
- power on after startup requires ""Automatically start after login"" - see Options
- power on after resume from standby may need some retries for waking TV - see Options
- power off on shutdown: because this app cannot detect a restart, restarting could also trigger this. Hold down Ctrl on restart to prevent power off.
- Use Windows power settings: powering on/off of TV will follow Windows settings. If activated, it's better to disable all other power options except power off on shutdown.
");
}
@@ -3138,5 +3141,15 @@ The InStart and Software Update items are now visible under the Expert-button."
{
_lgService.Config.ShutdownDelay = (int)edtLgOptionShutdownDelay.Value;
}
private void cbxLgPcHdmiPort_SelectedIndexChanged(object sender, EventArgs e)
{
if (_lgService?.SelectedDevice == null)
{
return;
}
_lgService.SelectedDevice.HDMIPortNumber = cbxLgPcHdmiPort.SelectedIndex;
}
}
}
+9 -5
View File
@@ -118,15 +118,19 @@ namespace ColorControl
{
ConfigFilename = Path.Combine(DataDir, "Settings.json");
if (File.Exists(ConfigFilename))
try
{
var data = File.ReadAllText(ConfigFilename);
Config = JsonConvert.DeserializeObject<Config>(data);
if (File.Exists(ConfigFilename))
{
var data = File.ReadAllText(ConfigFilename);
Config = JsonConvert.DeserializeObject<Config>(data);
}
}
else
catch (Exception ex)
{
Config = new Config();
Logger.Error($"LoadConfig: {ex.Message}");
}
Config ??= new Config();
}
private static bool HandleStartupParams(StartUpParams startUpParams, Process existingProcess)
+16
View File
@@ -53,6 +53,14 @@ namespace ColorControl
UserNotificationState.QUNS_PRESENTATION_MODE,
};
[StructLayout(LayoutKind.Sequential, Pack = 4)]
internal struct POWERBROADCAST_SETTING
{
public Guid PowerSetting;
public uint DataLength;
public byte Data;
}
public const int WM_BRINGTOFRONT = NativeConstants.WM_USER + 1;
public const int ENUM_CURRENT_SETTINGS = -1;
@@ -60,6 +68,8 @@ namespace ColorControl
public static string PKEY_PNPX_IpAddress = "{656a3bb3-ecc0-43fd-8477-4ae0404a96cd} 12297";
public static string PKEY_PNPX_PhysicalAddress = "{656a3bb3-ecc0-43fd-8477-4ae0404a96cd} 12294";
public static Guid GUID_CONSOLE_DISPLAY_STATE = Guid.Parse("6FE69556-704A-47A0-8F24-C28D936FDA47");
public static int PBT_POWERSETTINGCHANGE = 32787;
public delegate void PCREATE_PROCESS_NOTIFY_ROUTINE(IntPtr ParentId, IntPtr ProcessId, bool Create);
@@ -96,6 +106,12 @@ namespace ColorControl
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
[DllImport(@"User32", SetLastError = true)]
public static extern IntPtr RegisterPowerSettingNotification(IntPtr hRecipient, ref Guid PowerSettingGuid, Int32 Flags);
[DllImport("User32.dll", SetLastError = true)]
public static extern bool UnregisterPowerSettingNotification(IntPtr hWnd);
//[DllImport("Wtsapi32.dll")]
//public extern static bool WTSRegisterSessionNotification(IntPtr hWnd, uint dwFlags);
+7
View File
@@ -491,6 +491,13 @@ namespace LgTv
await _connection.SubscribeAsync(requestMessage, callback);
}
public async Task SubscribeForegroundApp(Func<dynamic, bool> callback, dynamic payload = null)
{
var requestMessage = new RequestMessage("ssap://com.webos.applicationManager/getForegroundAppInfo", null, "subscribe");
await _connection.SubscribeAsync(requestMessage, callback);
}
public async Task SubscribePictureSettings(Func<dynamic, bool> callback, dynamic payload = null)
{
if (payload == null)