diff --git a/ColorControl/ColorControl.csproj b/ColorControl/ColorControl.csproj
index 332c52e..4c2ad31 100644
--- a/ColorControl/ColorControl.csproj
+++ b/ColorControl/ColorControl.csproj
@@ -19,8 +19,8 @@
Maassoft
Maassoft
0
- 8.0.0.0
- 8.0.0.0
+ 8.1.0.0
+ 8.1.0.0
false
true
false
diff --git a/ColorControl/Common/Utils.cs b/ColorControl/Common/Utils.cs
index 481a9e7..61de190 100644
--- a/ColorControl/Common/Utils.cs
+++ b/ColorControl/Common/Utils.cs
@@ -426,6 +426,12 @@ public static async Task> GetPnpDevices(string deviceName)
public static T WaitForTask(Task task)
{
+ if (ConsoleOpened)
+ {
+ task.Wait();
+ return task.Result;
+ }
+
while (task != null && (task.Status < TaskStatus.WaitingForChildrenToComplete))
{
Thread.Sleep(10);
@@ -436,6 +442,12 @@ public static T WaitForTask(Task task)
public static void WaitForTask(System.Threading.Tasks.Task task)
{
+ if (ConsoleOpened)
+ {
+ task.Wait();
+ return;
+ }
+
while (task != null && (task.Status < TaskStatus.WaitingForChildrenToComplete))
{
Thread.Sleep(10);
@@ -733,7 +745,7 @@ public static Process GetProcessByName(string name, bool skipCurrent = true)
return null;
}
- public static void StartProcess(string fileName, string arguments = null, bool hidden = false, bool wait = false, bool setWorkingDir = false, bool elevate = false, uint affinityMask = 0, uint priorityClass = 0)
+ public static Process StartProcess(string fileName, string arguments = null, bool hidden = false, bool wait = false, bool setWorkingDir = false, bool elevate = false, uint affinityMask = 0, uint priorityClass = 0)
{
var process = Process.Start(new ProcessStartInfo(fileName, arguments)
{
@@ -757,6 +769,8 @@ public static void StartProcess(string fileName, string arguments = null, bool h
{
process.WaitForExit();
}
+
+ return process;
}
internal static void SetProcessAffinity(int processId, uint affinityMask)
diff --git a/ColorControl/Forms/ListViewColumnSorter.cs b/ColorControl/Forms/ListViewColumnSorter.cs
index 854c4f2..93887b8 100644
--- a/ColorControl/Forms/ListViewColumnSorter.cs
+++ b/ColorControl/Forms/ListViewColumnSorter.cs
@@ -64,7 +64,9 @@ public int Compare(object x, object y)
else
{
// Compare the two items
- compareResult = ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text, listviewY.SubItems[ColumnToSort].Text);
+ var subItemTextX = listviewX.SubItems.Count > ColumnToSort ? listviewX.SubItems[ColumnToSort].Text : string.Empty;
+ var subItemTextY = listviewY.SubItems.Count > ColumnToSort ? listviewY.SubItems[ColumnToSort].Text : string.Empty;
+ compareResult = ObjectCompare.Compare(subItemTextX, subItemTextY);
}
// Calculate correct return value based on object comparison
diff --git a/ColorControl/Forms/MessageForms.cs b/ColorControl/Forms/MessageForms.cs
index f4dc00a..cfbdca5 100644
--- a/ColorControl/Forms/MessageForms.cs
+++ b/ColorControl/Forms/MessageForms.cs
@@ -198,7 +198,7 @@ public static List ShowDialog(string caption, IEnumerable().ToArray());
+ cbxGameStepType.SelectedIndex = 0;
+ }
}
private void InitLgTab()
@@ -1769,7 +1782,8 @@ private void InitOptionsTab()
ElevationMethod.None => rbElevationNone.Checked = true,
ElevationMethod.RunAsAdmin => rbElevationAdmin.Checked = true,
ElevationMethod.UseService => rbElevationService.Checked = true,
- ElevationMethod.UseElevatedProcess => rbElevationProcess.Checked = true
+ ElevationMethod.UseElevatedProcess => rbElevationProcess.Checked = true,
+ _ => false
};
}
finally
@@ -1865,10 +1879,12 @@ private void SetLgDevicePowerOptions()
clbLgPower.SetItemChecked(1, device?.PowerOnAfterResume ?? false);
clbLgPower.SetItemChecked(2, device?.PowerOffOnShutdown ?? false);
clbLgPower.SetItemChecked(3, device?.PowerOffOnStandby ?? false);
- clbLgPower.SetItemChecked(4, device?.PowerSwitchOnScreenSaver ?? false);
- clbLgPower.SetItemChecked(5, device?.PowerOnAfterManualPowerOff ?? false);
- clbLgPower.SetItemChecked(6, device?.TriggersEnabled ?? true);
- clbLgPower.SetItemChecked(7, device?.PowerByWindows ?? false);
+ clbLgPower.SetItemChecked(4, device?.PowerOffOnScreenSaver ?? false);
+ clbLgPower.SetItemChecked(5, device?.PowerOnAfterScreenSaver ?? false);
+ clbLgPower.SetItemChecked(6, device?.PowerOnAfterManualPowerOff ?? false);
+ clbLgPower.SetItemChecked(7, device?.TriggersEnabled ?? true);
+ clbLgPower.SetItemChecked(8, device?.PowerOffByWindows ?? false);
+ clbLgPower.SetItemChecked(8, device?.PowerOnByWindows ?? false);
}
finally
{
@@ -2388,7 +2404,7 @@ private void clbLgPower_ItemCheck(object sender, ItemCheckEventArgs e)
return;
}
- if (e.Index is 0 or 1 or 4 or 7 && !(device.PowerOnAfterResume || device.PowerOnAfterStartup || device.PowerSwitchOnScreenSaver || device.PowerByWindows))
+ if (e.Index is 0 or 1 or 4 or 7 && !(device.PowerOnAfterResume || device.PowerOnAfterStartup || device.PowerOnAfterScreenSaver || device.PowerOnByWindows))
{
MessageForms.InfoOk(
@"Be sure to activate the following setting on the TV, or the app will not be able to wake the TV:
@@ -2406,10 +2422,12 @@ See Options to test this functionality.
device.PowerOnAfterResume = clbLgPower.GetItemChecked(1);
device.PowerOffOnShutdown = clbLgPower.GetItemChecked(2);
device.PowerOffOnStandby = clbLgPower.GetItemChecked(3);
- device.PowerSwitchOnScreenSaver = clbLgPower.GetItemChecked(4);
- device.PowerOnAfterManualPowerOff = clbLgPower.GetItemChecked(5);
- device.TriggersEnabled = clbLgPower.GetItemChecked(6);
- device.PowerByWindows = clbLgPower.GetItemChecked(7);
+ device.PowerOffOnScreenSaver = clbLgPower.GetItemChecked(4);
+ device.PowerOnAfterScreenSaver = clbLgPower.GetItemChecked(5);
+ device.PowerOnAfterManualPowerOff = clbLgPower.GetItemChecked(6);
+ device.TriggersEnabled = clbLgPower.GetItemChecked(7);
+ device.PowerOffByWindows = clbLgPower.GetItemChecked(8);
+ device.PowerOnByWindows = clbLgPower.GetItemChecked(9);
_lgService.InstallEventHandlers();
});
@@ -3166,16 +3184,7 @@ private void mnuLgButtons_Opening(object sender, CancelEventArgs e)
var device = _lgService.GetPresetDevice(preset);
- var actions = device?.GetInvokableActions();
- foreach (var action in actions.Where(a => a.Function != null))
- {
- var text = action.Title ?? action.Name;
-
- var item = mnuLgActions.DropDownItems.Add(text);
- item.Tag = action;
- item.Click += miLgAddAction_Click;
- }
-
+ BuildLgActionMenu(device, mnuLgActions.DropDownItems, mnuLgActions.Name, miLgAddAction_Click);
BuildServicePresetsMenu(mnuLgNvPresets, _nvService, "NVIDIA", miLgAddNvPreset_Click);
BuildServicePresetsMenu(mnuLgAmdPresets, _amdService, "AMD", miLgAddAmdPreset_Click);
}
@@ -3232,40 +3241,51 @@ private void mnuLgExpert_Opening(object sender, CancelEventArgs e)
var device = _lgService.SelectedDevice;
var eligibleModels = new[] { "B9", "C9", "E9", "W9", "C2", "G2" };
+ var eligibleModelsEnable = new[] { "B9", "C9", "E9", "W9" };
- var visible = device?.ModelName != null ? eligibleModels.Any(m => device.ModelName.Contains(m)) : false;
+ var visible = eligibleModels.Any(m => device?.ModelName?.Contains(m) == true);
+ var enableVisible = eligibleModelsEnable.Any(m => device?.ModelName?.Contains(m) == true);
mnuLgOLEDMotionPro.Visible = visible;
+ miLgEnableMotionPro.Visible = enableVisible;
miLgExpertSeparator1.Visible = visible;
- // Does not work yet, getting a "401 no permissions" error
- //var task = device?.GetPictureSettings();
- //var settings = Utils.WaitForTask(task);
+ BuildLgActionMenu(device, mnuLgExpert.Items, mnuLgExpert.Name, btnLgExpertColorGamut_Click, _lgService.Config.ShowAdvancedActions, true);
+ }
+ private void BuildLgActionMenu(LgDevice device, ToolStripItemCollection parent, string parentName, EventHandler clickEvent, bool showAdvanced = false, bool showGameBar = false)
+ {
if (device == null)
{
return;
}
- var actions = device.GetInvokableActions(_lgService.Config.ShowAdvancedActions);
+ var actions = device.GetInvokableActions(showAdvanced);
var gameBarActions = device.GetInvokableActionsForGameBar();
var activatedGameBarActions = device.GetActionsForGameBar();
const string gameBarName = "miGameBar";
- var expertActions = actions.Where(a => !a.Name.Contains("uhd", StringComparison.OrdinalIgnoreCase) &&
- !a.Name.Contains("gameOpt", StringComparison.OrdinalIgnoreCase) &&
- !a.Name.Contains("hdmiPc", StringComparison.OrdinalIgnoreCase) &&
- (a.EnumType != null || a.MaxValue > a.MinValue)).ToList();
+ var expertActions = actions.Where(a => a.EnumType != null || a.MaxValue > a.MinValue).ToList();
var categories = expertActions.Select(a => a.Category ?? "misc").Where(c => !string.IsNullOrEmpty(c)).Distinct();
foreach (var category in categories)
{
- var catMenuItem = FormUtils.BuildDropDownMenuEx(mnuLgExpert.Items, mnuLgExpert.Name, Utils.FirstCharUpperCase(category), null, null, category);
+ var catMenuItem = FormUtils.BuildDropDownMenuEx(parent, parentName, Utils.FirstCharUpperCase(category), null, null, category);
foreach (var action in expertActions.Where(a => (a.Category ?? "misc") == category))
{
- var menu = FormUtils.BuildDropDownMenuEx(catMenuItem.DropDownItems, catMenuItem.Name, action.Title, action.EnumType, btnLgExpertColorGamut_Click, action, (int)action.MinValue, (int)action.MaxValue, action.NumberOfValues > 1);
+ if (!showGameBar)
+ {
+ var text = action.Title ?? action.Name;
+
+ var item = catMenuItem.DropDownItems.Add(text);
+ item.Tag = action;
+ item.Click += clickEvent;
+ continue;
+ }
+
+ var menu = FormUtils.BuildDropDownMenuEx(catMenuItem.DropDownItems, catMenuItem.Name, action.Title, action.EnumType, clickEvent, action, (int)action.MinValue, (int)action.MaxValue, action.NumberOfValues > 1);
if (!gameBarActions.Contains(action))
{
@@ -3289,16 +3309,16 @@ private void mnuLgExpert_Opening(object sender, CancelEventArgs e)
}
}
- if (!_lgService.Config.ShowAdvancedActions)
+ if (!showAdvanced)
{
return;
}
var presetActions = actions.Where(a => a.Preset != null);
- if (presetActions.Any() && mnuLgExpert.Items.Find("miLgExpertActionsSeparator", false).Length == 0)
+ if (presetActions.Any() && parent.Find("miLgExpertActionsSeparator", false).Length == 0)
{
- mnuLgExpert.Items.Add(new ToolStripSeparator
+ parent.Add(new ToolStripSeparator
{
Name = "miLgExpertActionsSeparator"
});
@@ -3306,7 +3326,7 @@ private void mnuLgExpert_Opening(object sender, CancelEventArgs e)
foreach (var presetAction in presetActions)
{
- var menu = FormUtils.BuildDropDownMenuEx(mnuLgExpert.Items, mnuLgExpert.Name, presetAction.Name, null, btnLgExpertPresetAction_Click, presetAction.Preset);
+ var menu = FormUtils.BuildDropDownMenuEx(parent, parentName, presetAction.Name, null, btnLgExpertPresetAction_Click, presetAction.Preset);
}
}
@@ -3709,7 +3729,7 @@ private void lvGamePresets_SelectedIndexChanged(object sender, EventArgs _)
edtGameParameters.Text = preset.Parameters;
chkGameRunAsAdmin.Checked = preset.RunAsAdministrator;
chkGameQuickAccess.Checked = preset.ShowInQuickAccess;
- edtGamePrelaunchSteps.Text = string.Join(", ", preset.PreLaunchSteps);
+ ShowGameSteps();
}
else
{
@@ -3768,6 +3788,11 @@ private void AddGamePreset(FileInfo file)
}
private void btnGameSave_Click(object sender, EventArgs e)
+ {
+ SaveGamePreset();
+ }
+
+ private void SaveGamePreset()
{
var shortcut = string.Empty;
if (!Utils.ValidateShortcut(shortcut))
@@ -3801,7 +3826,15 @@ private void btnGameSave_Click(object sender, EventArgs e)
var text = edtGamePrelaunchSteps.Text;
- Utils.ParseWords(preset.PreLaunchSteps, text);
+ var stepsList = (GameStepType)cbxGameStepType.SelectedIndex switch
+ {
+ GameStepType.PreLaunch => preset.PreLaunchSteps,
+ GameStepType.PostLaunch => preset.PostLaunchSteps,
+ GameStepType.Finalize => preset.FinalizeSteps,
+ _ => throw new InvalidOperationException("Invalid game step type")
+ };
+
+ Utils.ParseWords(stepsList, text);
AddOrUpdateItemGame();
@@ -4320,5 +4353,38 @@ private void cbxLogType_SelectedIndexChanged(object sender, EventArgs e)
{
LoadLog();
}
+
+ private void cbxGameStepType_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ ShowGameSteps();
+ }
+
+ private void ShowGameSteps()
+ {
+ var preset = GetSelectedGamePreset();
+
+ if (preset == null)
+ {
+ return;
+ }
+
+ switch ((GameStepType)cbxGameStepType.SelectedIndex)
+ {
+ case GameStepType.PreLaunch:
+ edtGamePrelaunchSteps.Text = string.Join(", ", preset.PreLaunchSteps);
+ break;
+ case GameStepType.PostLaunch:
+ edtGamePrelaunchSteps.Text = string.Join(", ", preset.PostLaunchSteps);
+ break;
+ case GameStepType.Finalize:
+ edtGamePrelaunchSteps.Text = string.Join(", ", preset.FinalizeSteps);
+ break;
+ }
+ }
+
+ private void edtGamePrelaunchSteps_Leave(object sender, EventArgs e)
+ {
+ SaveGamePreset();
+ }
}
}
\ No newline at end of file
diff --git a/ColorControl/Services/GameLauncher/GamePreset.cs b/ColorControl/Services/GameLauncher/GamePreset.cs
index bf9e66f..6a95b2b 100644
--- a/ColorControl/Services/GameLauncher/GamePreset.cs
+++ b/ColorControl/Services/GameLauncher/GamePreset.cs
@@ -1,9 +1,20 @@
using ColorControl.Services.Common;
using NWin32;
using System.Collections.Generic;
+using System.ComponentModel;
namespace ColorControl.Services.GameLauncher
{
+ public enum GameStepType
+ {
+ [Description("Pre-launch steps")]
+ PreLaunch = 0,
+ [Description("Post-launch steps")]
+ PostLaunch = 1,
+ [Description("Finalize steps")]
+ Finalize = 2,
+ }
+
public enum GamePriorityClass
{
Idle = NativeConstants.IDLE_PRIORITY_CLASS,
@@ -21,6 +32,7 @@ class GamePreset : PresetBase
public bool RunAsAdministrator { get; set; }
public List PreLaunchSteps { get; set; }
public List PostLaunchSteps { get; set; }
+ public List FinalizeSteps { get; set; }
public uint ProcessAffinityMask { get; set; }
public uint ProcessPriorityClass { get; set; }
@@ -28,6 +40,7 @@ public GamePreset() : base()
{
PreLaunchSteps = new List();
PostLaunchSteps = new List();
+ FinalizeSteps = new List();
}
public GamePreset(GamePreset preset) : this()
@@ -40,6 +53,7 @@ public GamePreset(GamePreset preset) : this()
RunAsAdministrator = preset.RunAsAdministrator;
PreLaunchSteps.AddRange(preset.PreLaunchSteps);
PostLaunchSteps.AddRange(preset.PostLaunchSteps);
+ FinalizeSteps.AddRange(preset.FinalizeSteps);
}
public GamePreset Clone()
@@ -53,7 +67,7 @@ public GamePreset Clone()
public static string[] GetColumnNames()
{
- return new[] { "Name|160", "File/URI|400", "Parameters|200", "Pre-launch steps|300" };
+ return new[] { "Name|160", "File/URI|400", "Parameters|200", "Pre-launch steps|300", "Post-launch steps|300", "Finalize steps|300" };
}
public override List GetDisplayValues(Config config = null)
@@ -66,6 +80,7 @@ public override List GetDisplayValues(Config config = null)
values.Add(string.Join(", ", PreLaunchSteps));
values.Add(string.Join(", ", PostLaunchSteps));
+ values.Add(string.Join(", ", FinalizeSteps));
return values;
}
diff --git a/ColorControl/Services/GameLauncher/GameService.cs b/ColorControl/Services/GameLauncher/GameService.cs
index 3551b8a..57ed3e2 100644
--- a/ColorControl/Services/GameLauncher/GameService.cs
+++ b/ColorControl/Services/GameLauncher/GameService.cs
@@ -2,6 +2,8 @@
using ColorControl.Services.Common;
using System;
using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
using System.Threading.Tasks;
namespace ColorControl.Services.GameLauncher
@@ -79,7 +81,44 @@ public bool ApplyPreset(GamePreset preset, AppContext appContext)
{
var result = true;
- foreach (var step in preset.PreLaunchSteps)
+ ExecuteSteps(preset.PreLaunchSteps);
+
+ Process process = null;
+
+ if (!string.IsNullOrEmpty(preset.Path))
+ {
+ process = Utils.StartProcess(preset.Path, preset.Parameters, setWorkingDir: true, elevate: preset.RunAsAdministrator, affinityMask: preset.ProcessAffinityMask, priorityClass: preset.ProcessPriorityClass);
+ }
+
+ ExecuteSteps(preset.PostLaunchSteps);
+
+ if (process != null && preset.FinalizeSteps?.Any() == true)
+ {
+ var _ = ExecuteFinalizationStepsAsync(process, preset.FinalizeSteps);
+ }
+
+ _lastAppliedPreset = preset;
+
+ PresetApplied();
+
+ return result;
+ }
+
+ private async Task ExecuteFinalizationStepsAsync(Process process, List finalizeSteps)
+ {
+ await process.WaitForExitAsync();
+
+ ExecuteSteps(finalizeSteps);
+ }
+
+ private void ExecuteSteps(List steps)
+ {
+ if (steps?.Any() != true)
+ {
+ return;
+ }
+
+ foreach (var step in steps)
{
var keySpec = step.Split(':');
@@ -120,17 +159,6 @@ public bool ApplyPreset(GamePreset preset, AppContext appContext)
}
}
-
- if (!string.IsNullOrEmpty(preset.Path))
- {
- Utils.StartProcess(preset.Path, preset.Parameters, setWorkingDir: true, elevate: preset.RunAsAdministrator, affinityMask: preset.ProcessAffinityMask, priorityClass: preset.ProcessPriorityClass);
- }
-
- _lastAppliedPreset = preset;
-
- PresetApplied();
-
- return result;
}
}
}
diff --git a/ColorControl/Services/LG/LgDevice.cs b/ColorControl/Services/LG/LgDevice.cs
index 79e0130..65b5566 100644
--- a/ColorControl/Services/LG/LgDevice.cs
+++ b/ColorControl/Services/LG/LgDevice.cs
@@ -24,6 +24,8 @@ public class InvokableAction
public int NumberOfValues { get; set; }
public LgPreset Preset { get; set; }
public bool Advanced { get; set; }
+ public ModelYear FromModelYear { get; set; } = ModelYear.None;
+ public ModelYear ToModelYear { get; set; } = ModelYear.None;
}
public class LgDevicePictureSettings
@@ -51,6 +53,17 @@ public enum PowerOffSource
Manually
}
+ public enum ModelYear
+ {
+ None = 0,
+ SeriesPre2018,
+ Series2018,
+ Series2019,
+ Series2020,
+ Series2021,
+ Series2022
+ }
+
protected static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
public static Func ExternalServiceHandler;
public static List DefaultActionsOnGameBar = new() { "backlight", "contrast", "brightness", "color" };
@@ -66,9 +79,11 @@ public enum PowerOffSource
public bool PowerOnAfterResume { get; set; }
public bool PowerOffOnShutdown { get; set; }
public bool PowerOffOnStandby { get; set; }
- public bool PowerSwitchOnScreenSaver { get; set; }
+ public bool PowerOffOnScreenSaver { get; set; }
+ public bool PowerOnAfterScreenSaver { get; set; }
public bool PowerOnAfterManualPowerOff { get; set; }
- public bool PowerByWindows { get; set; }
+ public bool PowerOnByWindows { get; set; }
+ public bool PowerOffByWindows { get; set; }
public bool TriggersEnabled { get; set; }
public int HDMIPortNumber { get; set; }
@@ -114,6 +129,8 @@ public List ActionsOnGameBar
[JsonIgnore]
public string ModelName { get; private set; }
+ [JsonIgnore]
+ public ModelYear Year { get; private set; }
[JsonIgnore]
public LgDevicePictureSettings PictureSettings { get; private set; }
@@ -153,8 +170,8 @@ public LgDevice(string name, string ipAddress, string macAddress, bool isCustom
AddGenericPictureAction("eyeComfortMode", typeof(OffToOn), title: "Eye Comfort Mode");
//AddGenericPictureAction("dynamicColor", typeof(OffToAuto));
//AddGenericPictureAction("superResolution", typeof(OffToAuto));
- AddGenericPictureAction("peakBrightness", typeof(OffToHigh), title: "Peak Brightness");
- AddGenericPictureAction("smoothGradation", typeof(OffToAuto), title: "Smooth Gradation");
+ AddGenericPictureAction("peakBrightness", typeof(OffToHigh), title: "Peak Brightness", fromModelYear: ModelYear.Series2019);
+ AddGenericPictureAction("smoothGradation", typeof(OffToAuto), title: "Smooth Gradation", fromModelYear: ModelYear.Series2019);
AddGenericPictureAction("energySaving", typeof(EnergySaving), title: "Energy Saving");
AddGenericPictureAction("hdrDynamicToneMapping", typeof(DynamicTonemapping), title: "HDR Dynamic Tone Mapping");
AddGenericPictureAction("blackLevel", typeof(BlackLevel), title: "HDMI Black Level");
@@ -170,7 +187,7 @@ public LgDevice(string name, string ipAddress, string macAddress, bool isCustom
AddGenericPictureAction("truMotionMode", typeof(TruMotionMode), title: "TruMotion");
AddGenericPictureAction("truMotionJudder", minValue: 0, maxValue: 10, title: "TruMotion Judder");
AddGenericPictureAction("truMotionBlur", minValue: 0, maxValue: 10, title: "TruMotion Blur");
- AddGenericPictureAction("motionProOLED", typeof(OffToHigh), title: "OLED Motion Pro");
+ AddGenericPictureAction("motionProOLED", typeof(OffToHigh), title: "OLED Motion Pro", fromModelYear: ModelYear.Series2019);
AddGenericPictureAction("motionPro", typeof(OffToOn), title: "Motion Pro");
AddGenericPictureAction("uhdDeepColorHDMI1", typeof(OffToOn), category: "other");
AddGenericPictureAction("uhdDeepColorHDMI2", typeof(OffToOn), category: "other");
@@ -180,7 +197,10 @@ public LgDevice(string name, string ipAddress, string macAddress, bool isCustom
AddGenericPictureAction("gameOptimizationHDMI2", typeof(OffToOn), category: "other");
AddGenericPictureAction("gameOptimizationHDMI3", typeof(OffToOn), category: "other");
AddGenericPictureAction("gameOptimizationHDMI4", typeof(OffToOn), category: "other");
- //AddGenericPictureAction("freesyncOLEDHDMI4", typeof(OffToOn), category: "other");
+ AddGenericPictureAction("freesyncOLEDHDMI1", typeof(OffToOn), category: "other", fromModelYear: ModelYear.Series2020);
+ AddGenericPictureAction("freesyncOLEDHDMI2", typeof(OffToOn), category: "other", fromModelYear: ModelYear.Series2020);
+ AddGenericPictureAction("freesyncOLEDHDMI3", typeof(OffToOn), category: "other", fromModelYear: ModelYear.Series2020);
+ AddGenericPictureAction("freesyncOLEDHDMI4", typeof(OffToOn), category: "other", fromModelYear: ModelYear.Series2020);
//AddGenericPictureAction("freesyncSupport", typeof(OffToOn), category: "other");
AddGenericPictureAction("hdmiPcMode_hdmi1", typeof(FalseToTrue), category: "other");
AddGenericPictureAction("hdmiPcMode_hdmi2", typeof(FalseToTrue), category: "other");
@@ -236,7 +256,7 @@ private void AddInternalPresetAction(LgPreset preset)
_invokableActions.Add(action);
}
- private void AddGenericPictureAction(string name, Type type = null, decimal minValue = 0, decimal maxValue = 0, string category = "picture", string title = null, int numberOfValues = 1)
+ private void AddGenericPictureAction(string name, Type type = null, decimal minValue = 0, decimal maxValue = 0, string category = "picture", string title = null, int numberOfValues = 1, ModelYear fromModelYear = ModelYear.None)
{
var action = new InvokableAction
{
@@ -247,7 +267,8 @@ private void AddGenericPictureAction(string name, Type type = null, decimal minV
MaxValue = maxValue,
NumberOfValues = numberOfValues,
Category = category,
- Title = title == null ? Utils.FirstCharUpperCase(name) : title
+ Title = title == null ? Utils.FirstCharUpperCase(name) : title,
+ FromModelYear = fromModelYear
};
_invokableActions.Add(action);
@@ -318,12 +339,13 @@ public async Task Connect(int retries = 3)
//Test();
//_lgTvApi.Test3();
- if (_lgTvApi != null)
+ if (_lgTvApi != null && !Utils.ConsoleOpened)
{
var info = await _lgTvApi.GetSystemInfo("modelName");
if (info != null)
{
ModelName = info.modelName;
+ SetModelYear();
}
//await _lgTvApi.SubscribeVolume(VolumeChanged);
@@ -360,6 +382,38 @@ public async Task Connect(int retries = 3)
}
}
+ private void SetModelYear()
+ {
+ if (ModelName == null || ModelName.Contains("OLED") != true)
+ {
+ Year = ModelYear.None;
+ return;
+ }
+
+ var normalized = ModelName.Replace("OLED", "").Replace(" ", "");
+
+ if (normalized.Length > 3)
+ {
+ normalized = normalized.Substring(3);
+ }
+
+ var suffix = normalized.First();
+
+ Year = suffix switch
+ {
+ '6' => ModelYear.SeriesPre2018,
+ '7' => ModelYear.SeriesPre2018,
+ '8' => ModelYear.Series2018,
+ '9' => ModelYear.Series2019,
+ 'X' => ModelYear.Series2020,
+ '1' => ModelYear.Series2021,
+ '2' => ModelYear.Series2022,
+ _ => ModelYear.None
+ };
+
+ _invokableActions = _invokableActions.Where(a => Year == ModelYear.None || a.FromModelYear == ModelYear.None || Year >= a.FromModelYear).ToList();
+ }
+
public bool VolumeChanged(dynamic payload)
{
return true;
@@ -798,7 +852,7 @@ internal async Task WakeAndConnectWithRetries(int retries = 5)
public List GetInvokableActions(bool includedAdvanced = false)
{
- return includedAdvanced ? _invokableActions : _invokableActions.Where(a => !a.Advanced).ToList();
+ return _invokableActions.Where(a => includedAdvanced || !a.Advanced).ToList();
}
public List GetInvokableActionsForGameBar()
diff --git a/ColorControl/Services/LG/LgService.cs b/ColorControl/Services/LG/LgService.cs
index f977831..1da42a6 100644
--- a/ColorControl/Services/LG/LgService.cs
+++ b/ColorControl/Services/LG/LgService.cs
@@ -420,7 +420,7 @@ internal void WakeAfterStartupOrResume(PowerOnOffState state = PowerOnOffState.S
{
var wakeDevices = Devices.Where(d => state == PowerOnOffState.StartUp && d.PowerOnAfterStartup ||
state == PowerOnOffState.Resume && d.PowerOnAfterResume ||
- state == PowerOnOffState.ScreenSaver && d.PowerSwitchOnScreenSaver);
+ state == PowerOnOffState.ScreenSaver && d.PowerOnAfterScreenSaver);
PowerOnDevices(wakeDevices, state, checkUserSession);
}
@@ -514,12 +514,12 @@ private void MonitorProcesses()
public bool ShouldMonitorProcesses()
{
- return Devices.Any(d => d.PowerSwitchOnScreenSaver) || _presets.Any(p => p.Triggers.Any(t => t.Trigger != PresetTriggerType.None));
+ return Devices.Any(d => d.PowerOffOnScreenSaver || d.PowerOnAfterScreenSaver) || _presets.Any(p => p.Triggers.Any(t => t.Trigger != PresetTriggerType.None));
}
public async Task CheckProcesses()
{
- var wasConnected = Devices.Any(d => d.PowerSwitchOnScreenSaver && d.IsConnected());
+ var wasConnected = Devices.Any(d => (d.PowerOffOnScreenSaver || d.PowerOnAfterScreenSaver) && d.IsConnected());
_monitorTaskCounter++;
var validCounter = _monitorTaskCounter;
var lastProcessId = 0;
@@ -535,7 +535,7 @@ public async Task CheckProcesses()
try
{
- var applicableDevices = Devices.Where(d => d.PowerSwitchOnScreenSaver || d.TriggersEnabled && _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))));
if (!applicableDevices.Any())
@@ -601,7 +601,7 @@ public async Task CheckProcesses()
wasConnected = true;
}
- if (connectedDevices.Any(d => d.PowerSwitchOnScreenSaver))
+ if (connectedDevices.Any(d => d.PowerOffOnScreenSaver || d.PowerOnAfterScreenSaver))
{
lastProcessId = await HandleScreenSaverProcessAsync(lastProcessId, processes, connectedDevices);
}
@@ -634,7 +634,7 @@ private async Task HandleScreenSaverProcessAsync(int lastProcessId, Process
Logger.Debug($"Screensaver started: {process.ProcessName}, parent: {parent.ProcessName}");
try
{
- foreach (var device in connectedDevices)
+ foreach (var device in connectedDevices.Where(d => d.PowerOffOnScreenSaver))
{
Logger.Debug($"Screensaver check: test connection with {device.Name}...");
var test = await device.TestConnection();
@@ -815,14 +815,15 @@ internal void RemoveCustomDevice(LgDevice device)
public void PowerSettingChanged(WindowsPowerSetting setting)
{
- var devices = Devices.Where(d => d.PowerByWindows).ToList();
if (setting == WindowsPowerSetting.Off)
{
+ var devices = Devices.Where(d => d.PowerOffByWindows).ToList();
PowerOffDevices(devices, PowerOnOffState.StandBy);
}
else if (setting == WindowsPowerSetting.On)
{
+ var devices = Devices.Where(d => d.PowerOnByWindows).ToList();
PowerOnDevices(devices);
}
}
diff --git a/ColorControl/Svc/ColorControlBackgroundService.cs b/ColorControl/Svc/ColorControlBackgroundService.cs
index d3607d4..a8ac8d0 100644
--- a/ColorControl/Svc/ColorControlBackgroundService.cs
+++ b/ColorControl/Svc/ColorControlBackgroundService.cs
@@ -63,7 +63,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
}
catch (Exception ex)
{
- Logger.Error($"While handling message: {message}");
+ Logger.Error(ex, $"Error while handling message: {message}");
var result = SvcResultMessage.FromResult(false, ex.Message);
var resultJson = JsonConvert.SerializeObject(result);
@@ -104,7 +104,8 @@ private SvcResultMessage HandleMessage(string json)
SvcMessageType.SetLgConfig => HandleSetLgConfigMessage(message),
SvcMessageType.GetLog => HandleGetLogMessage(message),
SvcMessageType.ClearLog => HandleClearLogMessage(message),
- SvcMessageType.ExecuteRpc => HandleExecuteRpcCommand(message)
+ SvcMessageType.ExecuteRpc => HandleExecuteRpcCommand(message),
+ _ => SvcResultMessage.FromResult(false, "Unexpected message type")
};
return result;
diff --git a/ColorControl/lgtv/LgTvConnection.cs b/ColorControl/lgtv/LgTvConnection.cs
index 052637e..5c83b19 100644
--- a/ColorControl/lgtv/LgTvConnection.cs
+++ b/ColorControl/lgtv/LgTvConnection.cs
@@ -1,14 +1,13 @@
-using System;
+using ColorControl.Common;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Newtonsoft.Json.Serialization;
+using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
-using Newtonsoft.Json;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
-using Newtonsoft.Json.Serialization;
-using Newtonsoft.Json.Linq;
-using ColorControl;
-using ColorControl.Common;
namespace LgTv
{
@@ -19,7 +18,7 @@ public SendMessageException(string message, Exception e) : base(message, e)
}
}
-
+
public class LgTvApiCore : IDisposable
{
public bool ConnectionClosed { get; private set; }
@@ -58,30 +57,6 @@ public async Task Connect(Uri uri, bool ignoreReceiver = false)
{
return false;
}
-
- //using (var cancellationTokenSource = new CancellationTokenSource(5000))
- //{
- // var connectTask = _connection.ConnectAsync(uri).AsTask(cancellationTokenSource.Token);
- // var result = await connectTask.ContinueWith((antecedent) =>
- // {
- // if (antecedent.Status == TaskStatus.RanToCompletion)
- // {
- // // connectTask ran to completion, so we know that the MessageWebSocket is connected.
- // // Add additional code here to use the MessageWebSocket.
- // IsConnected?.Invoke(true);
-
- // _messageWriter = new DataWriter(_connection.OutputStream);
- // return true;
- // }
- // else
- // {
- // // connectTask timed out, or faulted.
- // return false;
- // }
- // });
-
- // return result;
- //}
}
catch (Exception e)
{
@@ -145,9 +120,8 @@ private async Task SendCommandAsync(string id, string message)
{
throw new Exception("Connection closed");
}
- var result = await taskSource.Task.ConfigureAwait(false);
- return result;
+ return await taskSource.Task;
}
catch (Exception e)
{