fix/add various LG/NVIDIA issues

This commit is contained in:
Vincent Maas committed 2022-02-05 11:53:49 +01:00
1 parent 977060e927
commit b2e7c529a0
17 files changed
+752 -147

No files matched your search

+1 -1
View File
@@ -64,7 +64,7 @@ namespace ColorControl
SavePresets();
}
public override bool HasDisplaysAttached()
public override bool HasDisplaysAttached(bool reinitialize = false)
{
try
{
+2 -2
View File
@@ -18,8 +18,8 @@
<PublisherName>Maassoft</PublisherName>
<Company>Maassoft</Company>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>5.3.0.0</ApplicationVersion>
<Version>5.3.0.0</Version>
<ApplicationVersion>5.4.0.0</ApplicationVersion>
<Version>5.4.0.0</Version>
<UseApplicationTrust>false</UseApplicationTrust>
<PublishWizardCompleted>true</PublishWizardCompleted>
<BootstrapperEnabled>false</BootstrapperEnabled>
+1 -2
View File
@@ -15,7 +15,6 @@ namespace ColorControl
public GraphicsService(string dataPath, string presetsBaseFilename) : base(dataPath, presetsBaseFilename)
{
Initialize();
}
~GraphicsService()
@@ -23,7 +22,7 @@ namespace ColorControl
Uninitialize();
}
public abstract bool HasDisplaysAttached();
public abstract bool HasDisplaysAttached(bool reinitialize = false);
protected void ToggleHDR(int delay = 1000)
{
+13 -3
View File
@@ -65,6 +65,8 @@ namespace ColorControl
public bool PowerOffOnShutdown { get; set; }
public bool PowerOffOnStandby { get; set; }
public bool PowerSwitchOnScreenSaver { get; set; }
public bool PowerOnAfterManualPowerOff { get; set; }
public bool TriggersEnabled { get; set; }
private List<string> _actionsForGameBar;
@@ -124,6 +126,7 @@ namespace ColorControl
MacAddress = macAddress;
IsCustom = isCustom;
IsDummy = isDummy;
TriggersEnabled = true;
AddInvokableAction("WOL", new Func<Dictionary<string, object>, bool>(WakeAction));
AddGenericPictureAction("backlight", minValue: 0, maxValue: 100);
@@ -131,6 +134,7 @@ namespace ColorControl
AddGenericPictureAction("contrast", minValue: 0, maxValue: 100);
AddGenericPictureAction("color", minValue: 0, maxValue: 100);
AddGenericPictureAction("pictureMode", typeof(PictureMode), title: "Picture Mode");
//AddGenericPictureAction("dynamicRange", typeof(DynamicRange), category: "dimensionInfo", title: "Dynamic Range");
AddGenericPictureAction("colorGamut", typeof(ColorGamut), title: "Color Gamut");
AddGenericPictureAction("dynamicContrast", typeof(OffToHigh), title: "Dynamic Contrast");
AddGenericPictureAction("gamma", typeof(GammaExp));
@@ -159,6 +163,7 @@ namespace ColorControl
AddGenericPictureAction("hdmiPcMode_hdmi3", typeof(FalseToTrue), category: "other");
AddGenericPictureAction("hdmiPcMode_hdmi4", typeof(FalseToTrue), category: "other");
AddGenericPictureAction("adjustingLuminance", minValue: -50, maxValue: 50);
//AddGenericPictureAction("wb20PointsGammaValue", minValue: -50, maxValue: 50);
AddInvokableAction("turnScreenOff", new Func<Dictionary<string, object>, bool>(TurnScreenOffAction));
AddInvokableAction("turnScreenOn", new Func<Dictionary<string, object>, bool>(TurnScreenOnAction));
@@ -170,6 +175,11 @@ namespace ColorControl
AddSetDeviceConfigAction("HDMI_2_icon", typeof(HdmiIcon), "HDMI 2 icon");
AddSetDeviceConfigAction("HDMI_3_icon", typeof(HdmiIcon), "HDMI 3 icon");
AddSetDeviceConfigAction("HDMI_4_icon", typeof(HdmiIcon), "HDMI 4 icon");
AddGenericPictureAction("soundMode", typeof(SoundMode), category: "sound", title: "Sound Mode");
AddGenericPictureAction("soundOutput", typeof(SoundOutput), category: "sound", title: "Sound Output");
//await ExecuteRequest("luna://com.webos.settingsservice/setSystemSettings", new { category = "network", settings = new { wolwowlOnOff = "true" } });
AddGenericPictureAction("wolwowlOnOff", typeof(FalseToTrue), category: "network", title: "Wake-On-LAN");
}
private void AddInvokableAction(string name, Func<Dictionary<string, object>, bool> function)
@@ -272,7 +282,7 @@ namespace ColorControl
await _lgTvApi.SubscribePowerState(PowerStateChanged);
await _lgTvApi.SubscribePictureSettings(PictureSettingsChanged);
//await _lgTvApi.SetDeviceConfig("PC");
//await _lgTvApi.Reboot();
//var result = await GetPictureSettings();
@@ -788,9 +798,9 @@ namespace ColorControl
internal async Task<dynamic> GetPictureSettings()
{
//var keys = new[] { "backlight", "brightness", "contrast", "color", "pictureMode", "colorGamut", "dynamicContrast", "peakBrightness", "smoothGradation", "energySaving", "motionProOLED" };
var keys = new[] { "backlight", "brightness", "contrast", "color" };
//var keys = new[] { "backlight", "brightness", "contrast", "color" };
return await _lgTvApi.GetSystemSettings("picture", keys);
return await _lgTvApi.GetSystemSettings2("picture");
}
private bool WakeAction(Dictionary<string, object> parameters)
+16 -11
View File
@@ -41,9 +41,10 @@ namespace ColorControl
//
this.flowPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.flowPanel.Location = new System.Drawing.Point(12, 41);
this.flowPanel.Location = new System.Drawing.Point(14, 47);
this.flowPanel.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.flowPanel.Name = "flowPanel";
this.flowPanel.Size = new System.Drawing.Size(231, 282);
this.flowPanel.Size = new System.Drawing.Size(270, 325);
this.flowPanel.TabIndex = 0;
this.flowPanel.MouseDown += new System.Windows.Forms.MouseEventHandler(this.RemoteControlForm_MouseDown);
this.flowPanel.MouseMove += new System.Windows.Forms.MouseEventHandler(this.flowPanel_MouseMove);
@@ -56,9 +57,10 @@ namespace ColorControl
this.btnClose.FlatAppearance.BorderSize = 0;
this.btnClose.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnClose.ForeColor = System.Drawing.Color.White;
this.btnClose.Location = new System.Drawing.Point(240, 0);
this.btnClose.Location = new System.Drawing.Point(280, 0);
this.btnClose.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.btnClose.Name = "btnClose";
this.btnClose.Size = new System.Drawing.Size(14, 23);
this.btnClose.Size = new System.Drawing.Size(16, 27);
this.btnClose.TabIndex = 1;
this.btnClose.TabStop = false;
this.btnClose.Text = "x";
@@ -69,9 +71,10 @@ namespace ColorControl
//
this.lblTvName.AutoSize = true;
this.lblTvName.ForeColor = System.Drawing.Color.White;
this.lblTvName.Location = new System.Drawing.Point(12, 0);
this.lblTvName.Location = new System.Drawing.Point(14, 0);
this.lblTvName.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lblTvName.Name = "lblTvName";
this.lblTvName.Size = new System.Drawing.Size(25, 13);
this.lblTvName.Size = new System.Drawing.Size(25, 15);
this.lblTvName.TabIndex = 0;
this.lblTvName.Text = " ";
//
@@ -84,33 +87,35 @@ namespace ColorControl
//
this.lblProcessName.AutoSize = true;
this.lblProcessName.ForeColor = System.Drawing.Color.White;
this.lblProcessName.Location = new System.Drawing.Point(12, 20);
this.lblProcessName.Location = new System.Drawing.Point(14, 23);
this.lblProcessName.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lblProcessName.Name = "lblProcessName";
this.lblProcessName.Size = new System.Drawing.Size(25, 13);
this.lblProcessName.Size = new System.Drawing.Size(25, 15);
this.lblProcessName.TabIndex = 2;
this.lblProcessName.Text = " ";
//
// LgGameBar
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.Black;
this.ClientSize = new System.Drawing.Size(255, 335);
this.ClientSize = new System.Drawing.Size(298, 387);
this.Controls.Add(this.lblProcessName);
this.Controls.Add(this.lblTvName);
this.Controls.Add(this.btnClose);
this.Controls.Add(this.flowPanel);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.KeyPreview = true;
this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "LgGameBar";
this.Opacity = 0.7D;
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.Text = "RemoteControlForm";
this.TopMost = true;
this.Activated += new System.EventHandler(this.LgGameBar_Activated);
this.Deactivate += new System.EventHandler(this.LgGameBar_Deactivate);
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.RemoteControlForm_FormClosed);
this.Load += new System.EventHandler(this.RemoteControlForm_Load);
this.Shown += new System.EventHandler(this.RemoteControlForm_Shown);
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.RemoteControlForm_KeyDown);
+6 -25
View File
@@ -178,6 +178,8 @@ namespace ColorControl
private void RemoteControlForm_Load(object sender, EventArgs e)
{
Left = _lgService.Config.GameBarLeft;
Top = _lgService.Config.GameBarTop;
}
private void ButtonClick(object sender, EventArgs e)
@@ -242,22 +244,6 @@ namespace ColorControl
ResetAutoHide();
}
private void pnlMouse_MouseEnter(object sender, EventArgs e)
{
}
private void RemoteControlForm_FormClosed(object sender, FormClosedEventArgs e)
{
}
private void pnlMouse_MouseUp(object sender, MouseEventArgs e)
{
}
private void HandleMouse(MouseEventArgs e)
{
}
private void RemoteControlForm_Shown(object sender, EventArgs e)
{
GenerateComponents();
@@ -273,22 +259,17 @@ namespace ColorControl
UpdateValues();
}
private void pnlMouse_MouseMove(object sender, MouseEventArgs e)
{
HandleMouse(e);
}
private void pnlMouse_MouseWheel(object sender, MouseEventArgs e)
{
}
private void LgGameBar_Deactivate(object sender, EventArgs e)
{
_lgService.Config.GameBarLeft = Left;
_lgService.Config.GameBarTop = Top;
Hide();
}
private void tmrHide_Tick(object sender, EventArgs e)
{
_lgService.Config.GameBarLeft = Left;
_lgService.Config.GameBarTop = Top;
Hide();
}
+1 -61
View File
@@ -1,64 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
+12 -8
View File
@@ -433,7 +433,7 @@ namespace ColorControl
state == PowerOnOffState.ScreenSaver && d.PowerSwitchOnScreenSaver);
foreach (var device in wakeDevices)
{
if (device.PoweredOffBy == LgDevice.PowerOffSource.Manually)
if (!device.PowerOnAfterManualPowerOff && device.PoweredOffBy == LgDevice.PowerOffSource.Manually)
{
Logger.Debug($"[{device.Name}]: device was manually powered off by user, not powering on");
continue;
@@ -557,8 +557,8 @@ namespace ColorControl
try
{
var applicableDevices = Devices.Where(d => d.PowerSwitchOnScreenSaver || _presets.Any(p => p.Triggers.Any(t => t.Trigger != PresetTriggerType.None) &&
((p.DeviceMacAddress == null && d == SelectedDevice) || p.DeviceMacAddress == d.MacAddress)));
var applicableDevices = Devices.Where(d => d.PowerSwitchOnScreenSaver || 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())
{
@@ -623,7 +623,7 @@ namespace ColorControl
wasConnected = true;
}
MonitorContext.Devices = connectedDevices;
MonitorContext.Devices = connectedDevices.Where(d => d.TriggersEnabled).ToList();
MonitorContext.RunningProcesses = processes;
//if (lastProcesses != null)
//{
@@ -646,7 +646,7 @@ namespace ColorControl
if (process != null)
{
var parent = process.Parent();
var parent = process.Parent(processes);
if (parent?.ProcessName.Contains("winlogon") ?? false)
{
@@ -705,7 +705,11 @@ namespace ColorControl
private async Task ExecuteProcessPresets(ProcessMonitorContext context)
{
var presets = _presets.Where(p => p.Triggers.Any(t => t.Trigger == PresetTriggerType.ProcessSwitch));
var selectedDevice = SelectedDevice;
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())
{
return;
@@ -715,7 +719,7 @@ namespace ColorControl
var (processId, isFullScreen) = Utils.GetForegroundProcessIdAndIfFullScreen();
if (processId == Process.GetCurrentProcess().Id)
if (processId == Environment.ProcessId)
{
return;
}
@@ -808,7 +812,7 @@ namespace ColorControl
if (!string.IsNullOrEmpty(device.MacAddress))
{
var presets = _presets.Where(p => !string.IsNullOrEmpty(p.DeviceMacAddress) && p.DeviceMacAddress.Equals(device.MacAddress)).ToList();
var presets = _presets.Where(p => !string.IsNullOrEmpty(p.DeviceMacAddress) && p.DeviceMacAddress.Equals(device.MacAddress, StringComparison.OrdinalIgnoreCase)).ToList();
presets.ForEach(preset =>
{
preset.DeviceMacAddress = null;
+4
View File
@@ -13,6 +13,8 @@ namespace ColorControl
public bool ShowRemoteControl { get; set; }
public bool ShowAdvancedActions { get; set; }
public string GameBarShortcut { get; set; }
public int GameBarTop { get; set; }
public int GameBarLeft { get; set; }
public LgServiceConfig()
{
@@ -20,6 +22,8 @@ namespace ColorControl
DeviceSearchKey = "[LG]";
PowerOnRetries = 10;
Devices = new List<LgDevice>();
GameBarTop = 100;
GameBarLeft = 100;
}
}
}
+26 -11
View File
@@ -104,6 +104,7 @@
this.lvAmdPresets = new System.Windows.Forms.ListView();
this.tabLG = new System.Windows.Forms.TabPage();
this.scLgController = new System.Windows.Forms.SplitContainer();
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();
@@ -981,6 +982,7 @@
//
// scLgController.Panel1
//
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);
@@ -1030,6 +1032,18 @@
this.scLgController.SplitterWidth = 5;
this.scLgController.TabIndex = 43;
//
// btnLgDeviceOptionsHelp
//
this.btnLgDeviceOptionsHelp.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnLgDeviceOptionsHelp.Location = new System.Drawing.Point(867, 70);
this.btnLgDeviceOptionsHelp.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.btnLgDeviceOptionsHelp.Name = "btnLgDeviceOptionsHelp";
this.btnLgDeviceOptionsHelp.Size = new System.Drawing.Size(22, 27);
this.btnLgDeviceOptionsHelp.TabIndex = 58;
this.btnLgDeviceOptionsHelp.Text = "?";
this.btnLgDeviceOptionsHelp.UseVisualStyleBackColor = true;
this.btnLgDeviceOptionsHelp.Click += new System.EventHandler(this.btnLgDeviceOptionsHelp_Click);
//
// lblGameBarShortcut
//
this.lblGameBarShortcut.AutoSize = true;
@@ -1278,11 +1292,11 @@
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.lvLgPresets.FullRowSelect = true;
this.lvLgPresets.Location = new System.Drawing.Point(6, 168);
this.lvLgPresets.Location = new System.Drawing.Point(6, 152);
this.lvLgPresets.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.lvLgPresets.MultiSelect = false;
this.lvLgPresets.Name = "lvLgPresets";
this.lvLgPresets.Size = new System.Drawing.Size(883, 130);
this.lvLgPresets.Size = new System.Drawing.Size(883, 146);
this.lvLgPresets.TabIndex = 8;
this.lvLgPresets.UseCompatibleStateImageBehavior = false;
this.lvLgPresets.View = System.Windows.Forms.View.Details;
@@ -1575,21 +1589,21 @@
this.clbLgPower.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.clbLgPower.CheckOnClick = true;
this.clbLgPower.ColumnWidth = 380;
this.clbLgPower.FormattingEnabled = true;
this.clbLgPower.Items.AddRange(new object[] {
"Automatically power on after startup. Requires \"Automatically start after login\" " +
"- see Options.",
"Automatically power on after resume from standby. May need some retries for wakin" +
"g TV, see Options.",
"Automatically power off on shutdown. Because this app cannot detect a restart, re" +
"starting could also trigger this. Hold down Ctrl on restart to prevent power off" +
".",
"Automatically power on after startup",
"Automatically power on after resume from standby",
"Automatically power off on shutdown",
"Automatically power off on standby",
"Automatically power off on screensaver and power on when screensaver deactivates"});
"Automatically power off/on when screensaver activates/deactivates",
"Power on even after manual power off",
"Allow triggers to be fired for this device"});
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;
this.clbLgPower.Name = "clbLgPower";
this.clbLgPower.Size = new System.Drawing.Size(883, 76);
this.clbLgPower.Size = new System.Drawing.Size(856, 76);
this.clbLgPower.TabIndex = 34;
this.clbLgPower.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(this.clbLgPower_ItemCheck);
//
@@ -2353,6 +2367,7 @@
private System.Windows.Forms.Label lblGameBarShortcut;
private System.Windows.Forms.TextBox edtLgGameBarShortcut;
private System.Windows.Forms.CheckBox chkGdiScaling;
private System.Windows.Forms.Button btnLgDeviceOptionsHelp;
}
}
+40 -4
View File
@@ -2,6 +2,7 @@
using LgTv;
using Newtonsoft.Json;
using NLog;
using NonInvasiveKeyboardHookLibrary;
using NStandard;
using NvAPIWrapper.Display;
using NvAPIWrapper.Native.Display;
@@ -59,6 +60,8 @@ namespace ColorControl
private LgGameBar _gameBarForm;
private KeyboardHookManager _keyboardHookManager;
public MainForm(AppContext appContext)
{
InitializeComponent();
@@ -72,7 +75,7 @@ namespace ColorControl
MessageForms.MainForm = this;
_nvTrayMenu = new ToolStripMenuItem("NVIDIA presets");
_amdTrayMenu = new ToolStripMenuItem("NVIDIA presets");
_amdTrayMenu = new ToolStripMenuItem("AMD presets");
_lgTrayMenu = new ToolStripMenuItem("LG presets");
_trayIcon = new NotifyIcon()
{
@@ -205,6 +208,14 @@ namespace ColorControl
{
Utils.RegisterShortcut(Handle, SHORTCUTID_GAMEBAR, _lgService.Config.GameBarShortcut);
// New shortcut manager, not working yet
//if (_keyboardHookManager == null)
//{
// _keyboardHookManager = new KeyboardHookManager();
// _keyboardHookManager.Start();
//}
//_keyboardHookManager.RegisterHotkey(NonInvasiveKeyboardHookLibrary.ModifierKeys.Control | NonInvasiveKeyboardHookLibrary.ModifierKeys.Alt, 0x47, new Action(Invoke));
edtLgGameBarShortcut.Text = _lgService.Config.GameBarShortcut;
}
}
@@ -214,6 +225,11 @@ namespace ColorControl
}
}
private void Invoke()
{
BeginInvoke(new Action(ToggleGameBar));
}
private void AfterLgServiceRefreshDevices()
{
FillLgDevices();
@@ -1464,6 +1480,8 @@ namespace ColorControl
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);
}
finally
{
@@ -1939,7 +1957,8 @@ namespace ColorControl
Connection > Mobile TV On > Turn on via Wi-Fi (Networked Standby Mode)
See Options to test this functionality."
See Options to test this functionality.
You can also activate this option by using the Expert-button and selecting Wake-On-LAN > Enabled."
);
}
@@ -1950,6 +1969,8 @@ See Options to test this functionality."
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);
_lgService.InstallEventHandlers();
}));
@@ -1978,8 +1999,6 @@ See Options to test this functionality."
private void btnLGTestPower_Click(object sender, EventArgs e)
{
//_lgService.WakeSelectedDevice();
//return;
var text =
@"The TV will now power off. Please wait for the TV to be powered off completely (relay click) and press ENTER to wake it again.
For waking up to work, you need to activate the following setting on the TV:
@@ -1987,6 +2006,8 @@ For waking up to work, you need to activate the following setting on the TV:
Connection > Mobile TV On > Turn on via Wi-Fi
It will also work over a wired connection.
You can also activate this option by using the Expert-button and selecting Wake-On-LAN > Enabled.
Do you want to continue?";
if (MessageForms.QuestionYesNo(text) == DialogResult.Yes)
@@ -2983,6 +3004,11 @@ The InStart and Software Update items are now visible under the Expert-button."
{
if (_gameBarForm == null || _gameBarForm.IsDisposed)
{
if (_lgService?.SelectedDevice == null)
{
return;
}
_gameBarForm = new LgGameBar(_lgService);
}
@@ -3054,5 +3080,15 @@ The InStart and Software Update items are now visible under the Expert-button."
ApplyDitheringOptions();
}
private void btnLgDeviceOptionsHelp_Click(object sender, EventArgs e)
{
MessageForms.InfoOk(
@"Notes:
- 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.
");
}
}
}
@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
namespace NonInvasiveKeyboardHookLibrary
{
/// <summary>
/// A struct to represent a keybind (key + modifiers)
/// When the keybind struct is compared to another keybind struct, the equality is based on the
/// modifiers and the virtual key code.
/// </summary>
internal class KeybindStruct : IEquatable<KeybindStruct>
{
public readonly int VirtualKeyCode;
public readonly List<ModifierKeys> Modifiers;
public readonly Guid? Identifier;
public KeybindStruct(IEnumerable<ModifierKeys> modifiers, int virtualKeyCode, Guid? identifier = null)
{
this.VirtualKeyCode = virtualKeyCode;
this.Modifiers = new List<ModifierKeys>(modifiers);
this.Identifier = identifier;
}
public bool Equals(KeybindStruct other)
{
if (other == null)
return false;
if (this.VirtualKeyCode != other.VirtualKeyCode)
return false;
if (this.Modifiers.Count != other.Modifiers.Count)
return false;
foreach (var modifier in this.Modifiers)
{
if (!other.Modifiers.Contains(modifier))
{
return false;
}
}
return true;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((KeybindStruct) obj);
}
public override int GetHashCode()
{
var hash = 13;
hash = (hash * 7) + VirtualKeyCode.GetHashCode();
// Sum the modifiers separately, so that their order does not affect the final hash
var modifiersHashSum = 0;
foreach (var modifier in this.Modifiers)
{
modifiersHashSum += modifier.GetHashCode();
}
hash = (hash * 7) + modifiersHashSum;
return hash;
}
}
}
@@ -0,0 +1,325 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
namespace NonInvasiveKeyboardHookLibrary
{
internal struct KeyboardParams
{
public IntPtr wParam;
public int vkCode;
public KeyboardParams(IntPtr wParam, int vkCode)
{
this.wParam = wParam;
this.vkCode = vkCode;
}
}
/// <summary>
/// A hotkey manager that uses a low-level global keyboard hook, but eventually only fires events for
/// pre-registered hotkeys, i.e. not invading a user's privacy.
/// </summary>
public class KeyboardHookManager
{
#region Private Attributes
/// <summary>
/// Keeps track of all registered hotkeys
/// </summary>
private readonly Dictionary<KeybindStruct, Action> _registeredCallbacks;
/// <summary>
/// Keeps track of modifier keys that are held down
/// </summary>
private readonly HashSet<ModifierKeys> _downModifierKeys;
/// <summary>
/// Keeps track of all keys that are held down to prevent firing callbacks
/// more than once for a single keypress
/// </summary>
private readonly HashSet<int> _downKeys;
private readonly object _modifiersLock = new object();
private LowLevelKeyboardProc _hook;
private bool _isStarted;
#endregion
#region Constructors
/// <summary>
/// Instantiates an empty keyboard hook manager.
/// It is best practice to keep a single instance per process.
/// Start() must be called to start the low-level keyboard hook manager
/// </summary>
public KeyboardHookManager()
{
this._registeredCallbacks = new Dictionary<KeybindStruct, Action>();
this._downModifierKeys = new HashSet<ModifierKeys>();
this._downKeys = new HashSet<int>();
}
#endregion
#region Public API
/// <summary>
/// Starts the low-level keyboard hook.
/// Hotkeys can be registered regardless of the low-level keyboard hook's state, but their callbacks
/// will only ever be invoked if the low-level keyboard hook is running and intercepting keys.
/// </summary>
public void Start()
{
if (this._isStarted) return;
this._hook = this.HookCallback;
_hookId = SetHook(this._hook);
this._isStarted = true;
}
/// <summary>
/// Pauses the low-level keyboard hook (without unregistering the existing hotkeys)
/// </summary>
public void Stop()
{
if (this._isStarted)
{
UnhookWindowsHookEx(_hookId);
this._isStarted = false;
}
}
/// <summary>
/// Registers a hotkey.
/// </summary>
/// <param name="virtualKeyCode">The virtual key code of the hotkey</param>
/// <param name="action">The callback action to invoke when this hotkey is pressed</param>
/// <exception cref="HotkeyAlreadyRegisteredException">Thrown when the given key is already mapped to a callback</exception>
/// /// <returns>Unique identifier of this hotkey, which can be used to remove it later</returns>
public Guid RegisterHotkey(int virtualKeyCode, Action action)
{
return this.RegisterHotkey(new ModifierKeys[0], virtualKeyCode, action);
}
/// <summary>
/// Registers a new key combination with one or more modifiers
/// </summary>
/// <param name="modifiers">Modifiers that must be held while hitting the key. Multiple modifiers can be provided using the flags bitwise OR operation</param>
/// <param name="virtualKeyCode">The virtual key code of the standard key</param>
/// <param name="action">The callback action to invoke when this combination is pressed</param>
/// <exception cref="HotkeyAlreadyRegisteredException">Thrown when the given key combination is already mapped to a callback</exception>
/// <returns>Unique identifier of this hotkey, which can be used to remove it later</returns>
public Guid RegisterHotkey(ModifierKeys modifiers, int virtualKeyCode, Action action)
{
var allModifiers = Enum.GetValues(typeof(ModifierKeys)).Cast<ModifierKeys>().ToArray();
// Get the modifiers that were chained with bitwise OR operation as an array of modifiers
var selectedModifiers = allModifiers.Where(modifier => modifiers.HasFlag(modifier)).ToArray();
return RegisterHotkey(selectedModifiers, virtualKeyCode, action);
}
/// <summary>
/// Registers a new key combination.
/// </summary>
/// <param name="modifiers">Modifiers that must be held while hitting the key</param>
/// <param name="virtualKeyCode">The virtual key code of the standard key</param>
/// <param name="action">The callback action to invoke when this combination is pressed</param>
/// <exception cref="HotkeyAlreadyRegisteredException">Thrown when the given key combination is already mapped to a callback</exception>
/// <returns>Unique identifier of this hotkey, which can be used to remove it later</returns>
public Guid RegisterHotkey(ModifierKeys[] modifiers, int virtualKeyCode, Action action)
{
var keybindIdentity = Guid.NewGuid();
var keybind = new KeybindStruct(modifiers, virtualKeyCode, keybindIdentity);
if (this._registeredCallbacks.ContainsKey(keybind))
{
throw new HotkeyAlreadyRegisteredException();
}
this._registeredCallbacks[keybind] = action;
return keybindIdentity;
}
/// <summary>
/// Unregisters all hotkeys (the low-level keyboard hook continues running)
/// </summary>
public void UnregisterAll()
{
this._registeredCallbacks.Clear();
}
/// <summary>
/// Unregisters a specific single-key hotkey
/// </summary>
/// <param name="virtualKeyCode">Virtual key code of the unregistered key</param>
/// <exception cref="HotkeyNotRegisteredException">Thrown when the given key combination is not registered</exception>
public void UnregisterHotkey(int virtualKeyCode)
{
this.UnregisterHotkey(new ModifierKeys[0], virtualKeyCode);
}
/// <summary>
/// Unregisters a specific key combination
/// </summary>
/// <param name="modifiers">The modifiers of the combination</param>
/// <param name="virtualKeyCode">The key of the combination</param>
/// <exception cref="HotkeyNotRegisteredException">Thrown when the given key combination is not registered</exception>
public void UnregisterHotkey(ModifierKeys[] modifiers, int virtualKeyCode)
{
var keybind = new KeybindStruct(modifiers, virtualKeyCode);
if (!this._registeredCallbacks.Remove(keybind))
{
throw new HotkeyNotRegisteredException();
}
}
/// <summary>
/// Unregisters a specific key by its unique identifier
/// </summary>
/// <param name="keybindIdentity">Keybind GUID, as returned by RegisterHotkey</param>
public void UnregisterHotkey(Guid keybindIdentity)
{
var keybindToRemove = this._registeredCallbacks.Keys.FirstOrDefault(keybind =>
keybind.Identifier.HasValue && keybind.Identifier.Value.Equals(keybindIdentity));
if (keybindToRemove == null || !this._registeredCallbacks.Remove(keybindToRemove))
{
throw new HotkeyNotRegisteredException();
}
}
#endregion
#region Private methods
private void HandleKeyPress(int virtualKeyCode)
{
var currentKey = new KeybindStruct(this._downModifierKeys, virtualKeyCode);
if (!this._registeredCallbacks.ContainsKey(currentKey))
{
return;
}
if (this._registeredCallbacks.TryGetValue(currentKey, out var callback))
{
callback.Invoke();
}
}
#endregion
#region Low level keyboard hook
// Source: https://blogs.msdn.microsoft.com/toub/2006/05/03/low-level-keyboard-hook-in-c/
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int WM_KEYUP = 0x0101;
private const int WM_SYSKEYDOWN = 0x0104;
private const int WM_SYSKEYUP = 0x0105;
private static IntPtr _hookId = IntPtr.Zero;
private static IntPtr SetHook(LowLevelKeyboardProc proc)
{
var userLibrary = LoadLibrary("User32");
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
userLibrary, 0);
}
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
var vkCode = Marshal.ReadInt32(lParam);
// Debug.WriteLine("Starting");
// To prevent slowing keyboard input down, we use handle keyboard inputs in a separate thread
ThreadPool.QueueUserWorkItem(this.HandleSingleKeyboardInput, new KeyboardParams(wParam, vkCode));
// Debug.WriteLine("Ending");
}
return CallNextHookEx(_hookId, nCode, wParam, lParam);
}
/// <summary>
/// Handles a keyboard event based on the KeyboardParams it receives
/// </summary>
/// <param name="keyboardParamsObj">KeyboardParams struct (object type to comply with QueueUserWorkItem)</param>
private void HandleSingleKeyboardInput(object keyboardParamsObj)
{
var keyboardParams = (KeyboardParams)keyboardParamsObj;
var wParam = keyboardParams.wParam;
var vkCode = keyboardParams.vkCode;
var modifierKey = ModifierKeysUtilities.GetModifierKeyFromCode(vkCode);
// If the keyboard event is a KeyDown event (i.e. key pressed)
if (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN)
{
// In this case, we only care about modifier keys
if (modifierKey != null)
{
lock (this._modifiersLock)
{
this._downModifierKeys.Add(modifierKey.Value);
}
}
// Trigger callbacks that are registered for this key, but only once per key press
if (!this._downKeys.Contains(vkCode))
{
this.HandleKeyPress(vkCode);
this._downKeys.Add(vkCode);
}
}
// If the keyboard event is a KeyUp event (i.e. key released)
if (wParam == (IntPtr)WM_KEYUP || wParam == (IntPtr)WM_SYSKEYUP)
{
// If the released key is a modifier key, remove it from the HashSet of modifier keys
if (modifierKey != null)
{
lock (this._modifiersLock)
{
this._downModifierKeys.Remove(modifierKey.Value);
}
}
this._downKeys.Remove(vkCode);
}
}
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
/// <summary>
/// Loads the library.
/// </summary>
/// <param name="lpFileName">Name of the library</param>
/// <returns>A handle to the library</returns>
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary(string lpFileName);
#endregion
}
#region Exceptions
public class NonInvasiveKeyboardHookException : Exception
{
}
public class HotkeyAlreadyRegisteredException : NonInvasiveKeyboardHookException
{
}
public class HotkeyNotRegisteredException : NonInvasiveKeyboardHookException
{
}
#endregion
}
@@ -0,0 +1,44 @@
using System;
namespace NonInvasiveKeyboardHookLibrary
{
[Flags]
public enum ModifierKeys
{
Alt = 1,
Control = 2,
Shift = 4,
WindowsKey = 8,
}
public static class ModifierKeysUtilities
{
public static ModifierKeys? GetModifierKeyFromCode(int keyCode)
{
switch (keyCode)
{
case 0xA0:
case 0xA1:
case 0x10:
return ModifierKeys.Shift;
case 0xA2:
case 0xA3:
case 0x11:
return ModifierKeys.Control;
case 0x12:
case 0xA4:
case 0xA5:
return ModifierKeys.Alt;
case 0x5B:
case 0x5C:
return ModifierKeys.WindowsKey;
default:
return null;
}
}
}
}
+62 -5
View File
@@ -111,6 +111,12 @@ namespace ColorControl
public Display GetCurrentDisplay()
{
if (!HasDisplaysAttached())
{
_currentDisplay = null;
return null;
}
if (_currentDisplay == null)
{
_currentDisplay = Display.GetDisplays()[0];
@@ -119,15 +125,28 @@ namespace ColorControl
return _currentDisplay;
}
public override bool HasDisplaysAttached()
public override bool HasDisplaysAttached(bool reinitialize = false)
{
if (reinitialize)
{
try
{
Initialize();
}
catch (Exception ex)
{
Logger.Error($"Could not reinitialize NVIDIA API: {ex.Message}");
return false;
}
}
try
{
return DisplayDevice.GetGDIPrimaryDisplayDevice() != null;
}
catch (Exception)
{
return false;
return reinitialize ? false : HasDisplaysAttached(true);
}
}
@@ -200,6 +219,11 @@ namespace ColorControl
if (preset.applyColorData && (ColorDataDiffers(preset.colorData) || (!newHdrEnabled && preset.applyColorData && preset.colorData.Colorimetry != ColorDataColorimetry.Auto)))
{
var display = GetCurrentDisplay();
if (display == null)
{
return false;
}
if (hdrEnabled)
{
SetHDRState(display, false);
@@ -228,6 +252,10 @@ namespace ColorControl
if (applyHdr)
{
var display = GetCurrentDisplay();
if (display == null)
{
return false;
}
var colorData = preset.applyColorData ? preset.colorData : display.DisplayDevice.CurrentColorData;
@@ -324,7 +352,13 @@ namespace ColorControl
{
var delegateValue = Marshal.GetDelegateForFunctionPointer(ptr, typeof(NvAPI_Disp_SetDitherControl)) as NvAPI_Disp_SetDitherControl;
var displayDevice = GetCurrentDisplay().DisplayDevice;
var display = GetCurrentDisplay();
if (display == null)
{
return false;
}
var displayDevice = display.DisplayDevice;
var gpuHandle = displayDevice.PhysicalGPU.Handle;
var displayId = displayDevice.DisplayId;
@@ -366,7 +400,14 @@ namespace ColorControl
{
var delegateValue = Marshal.GetDelegateForFunctionPointer(ptr, typeof(NvAPI_Disp_GetDitherControl)) as NvAPI_Disp_GetDitherControl;
var displayDevice = GetCurrentDisplay().DisplayDevice;
var display = GetCurrentDisplay();
if (display == null)
{
dither.state = -1;
return dither;
}
var displayDevice = display.DisplayDevice;
var displayId = displayDevice.DisplayId;
var result = delegateValue(displayId, ref dither);
@@ -387,6 +428,11 @@ namespace ColorControl
public bool SetRefreshRate(uint refreshRate)
{
var display = GetCurrentDisplay();
if (display == null)
{
return false;
}
var timing = display.DisplayDevice.CurrentTiming;
if (timing.Extra.RefreshRate == refreshRate)
@@ -407,6 +453,11 @@ namespace ColorControl
}
var display = GetCurrentDisplay();
if (display == null)
{
return new List<uint>();
}
var portrait = new[] { Rotate.Degree90, Rotate.Degree270 }.Contains(display.DisplayDevice.ScanOutInformation.SourceToTargetRotation);
var timing = display.DisplayDevice.CurrentTiming;
@@ -415,7 +466,13 @@ namespace ColorControl
public bool IsHDREnabled()
{
var displayDevice = GetCurrentDisplay().DisplayDevice;
var display = GetCurrentDisplay();
if (display == null)
{
return false;
}
var displayDevice = display.DisplayDevice;
var hdr = displayDevice.HDRColorData;
return hdr?.HDRMode == ColorDataHDRMode.UHDA;
}
+33 -14
View File
@@ -605,7 +605,12 @@ namespace ColorControl
var itemText = (enumValue as IConvertible).GetDescription() ?? enumValue.ToString();
var item = subMenuItem.DropDownItems.Add(itemText);
item.Tag = tag;
item.AccessibleName = enumValue.ToString();
var strValue = enumValue.ToString();
if (strValue.EndsWith("_"))
{
strValue = strValue.Substring(0, strValue.Length - 1);
}
item.AccessibleName = strValue;
item.Click += clickEvent;
}
}
@@ -898,7 +903,7 @@ namespace ColorControl
public static Process GetProcessByName(string name, bool skipCurrent = true)
{
var currentProcessId = Process.GetCurrentProcess().Id;
var currentProcessId = Environment.ProcessId;
foreach (var process in Process.GetProcesses())
{
if (process.ProcessName.Equals(name) && (!skipCurrent || process.Id != currentProcessId))
@@ -1092,34 +1097,48 @@ namespace ColorControl
public static class ProcessExtensions
{
private static string FindIndexedProcessName(int pid)
private static string FindIndexedProcessName(int pid, string processName, IEnumerable<Process> processes = null)
{
var processName = Process.GetProcessById(pid).ProcessName;
var processesByName = Process.GetProcessesByName(processName);
string processIndexdName = null;
var processesByName = processes == null ? Process.GetProcessesByName(processName) : processes.Where(p => p.ProcessName.Equals(processName, StringComparison.OrdinalIgnoreCase)).ToArray();
string processIndexedName = null;
for (var index = 0; index < processesByName.Length; index++)
{
processIndexdName = index == 0 ? processName : processName + "#" + index;
var processId = new PerformanceCounter("Process", "ID Process", processIndexdName);
processIndexedName = index == 0 ? processName : processName + "#" + index;
var processId = new PerformanceCounter("Process", "ID Process", processIndexedName);
if ((int)processId.NextValue() == pid)
{
return processIndexdName;
return processIndexedName;
}
}
return processIndexdName;
return processIndexedName;
}
private static Process FindPidFromIndexedProcessName(string indexedProcessName)
private static Process FindPidFromIndexedProcessName(string indexedProcessName, IEnumerable<Process> processes = null)
{
var parentId = new PerformanceCounter("Process", "Creating Process ID", indexedProcessName);
return Process.GetProcessById((int)parentId.NextValue());
var parentProcessId = (int)parentId.NextValue();
try
{
return processes == null ? Process.GetProcessById(parentProcessId) : processes.FirstOrDefault(p => p.Id == parentProcessId);
}
catch (Exception)
{
return null;
}
}
public static Process Parent(this Process process)
public static Process Parent(this Process process, IEnumerable<Process> processes = null)
{
return FindPidFromIndexedProcessName(FindIndexedProcessName(process.Id));
var indexedProcessName = FindIndexedProcessName(process.Id, process.ProcessName, processes);
if (indexedProcessName == null)
{
return null;
}
return FindPidFromIndexedProcessName(indexedProcessName, processes);
}
}
}
+94
View File
@@ -27,6 +27,12 @@ namespace LgTv
dolbyHdrCinema, dolbyHdrCinemaBright, dolbyHdrDarkAmazon, dolbyHdrGame, dolbyHdrStandard, dolbyHdrVivid, dolbyStandard
}
public enum DynamicRange
{
sdr, hdr, technicolorHdr, dolbyHdr,
sdrALLM, hdrALLM, technicolorHdrALLM, dolbyHdrALLM
}
public enum OffToHigh
{
off,
@@ -99,7 +105,9 @@ namespace LgTv
public enum FalseToTrue
{
[Description("Disabled")]
false_,
[Description("Enabled")]
true_
}
@@ -137,6 +145,62 @@ namespace LgTv
mobile
}
public enum SoundMode
{
[Description("AI Sound Pro")]
aiSoundPlus,
[Description("AI Sound")]
aiSound,
[Description("Standard")]
standard,
[Description("Clear Voice")]
news,
[Description("Music")]
music,
[Description("Cinema")]
movie,
[Description("Sports")]
sports,
[Description("Game Optimizer")]
game,
[Description("Pagode")]
pagode,
[Description("Serta Wego")]
sertaWego,
[Description("Brazilian Punk")]
brazilianPunk,
[Description("ASC")]
asc,
[Description("Bass Boost")]
bass,
}
public enum SoundOutput
{
[Description("TV Speaker")]
tv_speaker,
[Description("HDMI(ARC) Device")]
external_arc,
[Description("Optical Out Device")]
external_optical,
[Description("Bluetooth Device")]
bt_soundbar,
[Description("Mobile Device")]
mobile_phone,
[Description("Audio Out Device")]
lineout,
[Description("Wired Headphones")]
headphone,
[Description("Bluetooth Device + TV Speaker")]
tv_speaker_bluetooth,
[Description("Optical Out Device + TV Speaker")]
tv_external_speaker,
[Description("Wired Headphones + TV Speaker")]
tv_speaker_headphone,
[Description("WiSA Speakers")]
wisa_speaker,
}
public class LgTvApi:IDisposable
{
public bool ConnectionClosed { get => _connection?.ConnectionClosed ?? true; }
@@ -600,6 +664,19 @@ namespace LgTv
await ExecuteRequest(lunauri, @params);
}
public async Task Reboot()
{
//await ExecuteRequest("luna://com.webos.service.oledepl/setGlobalStressReduction", new { enable = true });
//var requestMessage = new RequestMessage("ssap://com.webos.service.devicereset/requestReboot", new { reason = "broadcastSystemChanged" });
//var response = await _connection.SendCommandAsync(requestMessage);
//await ExecuteRequest("luna://com.webos.settingsservice/setSystemSettings", new { category = "network", settings = new { wolwowlOnOff = "true" } });
//await ExecuteRequest("luna://com.webos.settingsservice/setSystemSettings", new { category = "general", settings = new { powerOffBySCA3SystemChanged = "true" } });
//await ExecuteRequest("luna://com.webos.service.devicereset/requestReboot", new { reason = "broadcastSystemChanged" });
}
private async Task ExecuteRequest(string lunauri, object @params)
{
var buttons = new[]
@@ -661,6 +738,23 @@ namespace LgTv
return res;
}
public async Task<dynamic> GetSystemSettings2(string category)
{
var payload = new
{
category = "dimensionInfo",
//dimension = new { input = "default", _3dStatus = "2d", dynamicRange = "sdr" },
keys = new[] { "input", "_3dStatus", "colorSystem", "dynamicRange", "gameInput" }
};
//await ExecuteRequest("luna://com.webos.settingsservice/getSystemSettings", payload);
//return null;
var requestMessage = new RequestMessage("ssap://settings/getSystemSettings", payload);
var command = _connection.SendCommandAsync(requestMessage);
var res = await command;
return res;
}
public void Close()
{
_connection.Close();