diff --git a/ColorControl/AmdService.cs b/ColorControl/AmdService.cs index 31ede47..a6b5539 100644 --- a/ColorControl/AmdService.cs +++ b/ColorControl/AmdService.cs @@ -64,7 +64,7 @@ namespace ColorControl SavePresets(); } - public override bool HasDisplaysAttached() + public override bool HasDisplaysAttached(bool reinitialize = false) { try { diff --git a/ColorControl/ColorControl.csproj b/ColorControl/ColorControl.csproj index 1c5b1c5..4d1fe11 100644 --- a/ColorControl/ColorControl.csproj +++ b/ColorControl/ColorControl.csproj @@ -18,8 +18,8 @@ Maassoft Maassoft 0 - 5.3.0.0 - 5.3.0.0 + 5.4.0.0 + 5.4.0.0 false true false diff --git a/ColorControl/GraphicsService.cs b/ColorControl/GraphicsService.cs index 294c7f4..ea78a87 100644 --- a/ColorControl/GraphicsService.cs +++ b/ColorControl/GraphicsService.cs @@ -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) { diff --git a/ColorControl/LgDevice.cs b/ColorControl/LgDevice.cs index e452961..4b420b5 100644 --- a/ColorControl/LgDevice.cs +++ b/ColorControl/LgDevice.cs @@ -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 _actionsForGameBar; @@ -124,6 +126,7 @@ namespace ColorControl MacAddress = macAddress; IsCustom = isCustom; IsDummy = isDummy; + TriggersEnabled = true; AddInvokableAction("WOL", new Func, 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, bool>(TurnScreenOffAction)); AddInvokableAction("turnScreenOn", new Func, 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, 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 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 parameters) diff --git a/ColorControl/LgGameBar.Designer.cs b/ColorControl/LgGameBar.Designer.cs index a7ecd26..370d606 100644 --- a/ColorControl/LgGameBar.Designer.cs +++ b/ColorControl/LgGameBar.Designer.cs @@ -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); diff --git a/ColorControl/LgGameBar.cs b/ColorControl/LgGameBar.cs index 5eb4586..3113d24 100644 --- a/ColorControl/LgGameBar.cs +++ b/ColorControl/LgGameBar.cs @@ -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(); } diff --git a/ColorControl/LgGameBar.resx b/ColorControl/LgGameBar.resx index eb2cf17..7dbbdc6 100644 --- a/ColorControl/LgGameBar.resx +++ b/ColorControl/LgGameBar.resx @@ -1,64 +1,4 @@ - - - + diff --git a/ColorControl/LgService.cs b/ColorControl/LgService.cs index f2cfb88..b7ee9fe 100644 --- a/ColorControl/LgService.cs +++ b/ColorControl/LgService.cs @@ -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; diff --git a/ColorControl/LgServiceConfig.cs b/ColorControl/LgServiceConfig.cs index 5409866..410396d 100644 --- a/ColorControl/LgServiceConfig.cs +++ b/ColorControl/LgServiceConfig.cs @@ -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(); + GameBarTop = 100; + GameBarLeft = 100; } } } diff --git a/ColorControl/MainForm.Designer.cs b/ColorControl/MainForm.Designer.cs index f561b11..943c1fd 100644 --- a/ColorControl/MainForm.Designer.cs +++ b/ColorControl/MainForm.Designer.cs @@ -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; } } diff --git a/ColorControl/MainForm.cs b/ColorControl/MainForm.cs index 9f548d7..0c6588c 100644 --- a/ColorControl/MainForm.cs +++ b/ColorControl/MainForm.cs @@ -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. +"); + } } } \ No newline at end of file diff --git a/ColorControl/NonInvasiveKeyboardHookLibrary/KeybindStruct.cs b/ColorControl/NonInvasiveKeyboardHookLibrary/KeybindStruct.cs new file mode 100644 index 0000000..69f64a4 --- /dev/null +++ b/ColorControl/NonInvasiveKeyboardHookLibrary/KeybindStruct.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; + +namespace NonInvasiveKeyboardHookLibrary +{ + /// + /// 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. + /// + internal class KeybindStruct : IEquatable + { + public readonly int VirtualKeyCode; + public readonly List Modifiers; + public readonly Guid? Identifier; + + public KeybindStruct(IEnumerable modifiers, int virtualKeyCode, Guid? identifier = null) + { + this.VirtualKeyCode = virtualKeyCode; + this.Modifiers = new List(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; + } + } +} diff --git a/ColorControl/NonInvasiveKeyboardHookLibrary/KeyboardHookManager.cs b/ColorControl/NonInvasiveKeyboardHookLibrary/KeyboardHookManager.cs new file mode 100644 index 0000000..338c00a --- /dev/null +++ b/ColorControl/NonInvasiveKeyboardHookLibrary/KeyboardHookManager.cs @@ -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; + } + } + + /// + /// 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. + /// + public class KeyboardHookManager + { + #region Private Attributes + /// + /// Keeps track of all registered hotkeys + /// + private readonly Dictionary _registeredCallbacks; + /// + /// Keeps track of modifier keys that are held down + /// + private readonly HashSet _downModifierKeys; + /// + /// Keeps track of all keys that are held down to prevent firing callbacks + /// more than once for a single keypress + /// + private readonly HashSet _downKeys; + private readonly object _modifiersLock = new object(); + private LowLevelKeyboardProc _hook; + private bool _isStarted; + #endregion + + #region Constructors + /// + /// 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 + /// + public KeyboardHookManager() + { + this._registeredCallbacks = new Dictionary(); + this._downModifierKeys = new HashSet(); + this._downKeys = new HashSet(); + } + #endregion + + #region Public API + /// + /// 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. + /// + public void Start() + { + if (this._isStarted) return; + + this._hook = this.HookCallback; + _hookId = SetHook(this._hook); + this._isStarted = true; + } + + /// + /// Pauses the low-level keyboard hook (without unregistering the existing hotkeys) + /// + public void Stop() + { + if (this._isStarted) + { + UnhookWindowsHookEx(_hookId); + this._isStarted = false; + } + } + + /// + /// Registers a hotkey. + /// + /// The virtual key code of the hotkey + /// The callback action to invoke when this hotkey is pressed + /// Thrown when the given key is already mapped to a callback + /// /// Unique identifier of this hotkey, which can be used to remove it later + public Guid RegisterHotkey(int virtualKeyCode, Action action) + { + return this.RegisterHotkey(new ModifierKeys[0], virtualKeyCode, action); + } + + /// + /// Registers a new key combination with one or more modifiers + /// + /// Modifiers that must be held while hitting the key. Multiple modifiers can be provided using the flags bitwise OR operation + /// The virtual key code of the standard key + /// The callback action to invoke when this combination is pressed + /// Thrown when the given key combination is already mapped to a callback + /// Unique identifier of this hotkey, which can be used to remove it later + public Guid RegisterHotkey(ModifierKeys modifiers, int virtualKeyCode, Action action) + { + var allModifiers = Enum.GetValues(typeof(ModifierKeys)).Cast().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); + } + + /// + /// Registers a new key combination. + /// + /// Modifiers that must be held while hitting the key + /// The virtual key code of the standard key + /// The callback action to invoke when this combination is pressed + /// Thrown when the given key combination is already mapped to a callback + /// Unique identifier of this hotkey, which can be used to remove it later + 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; + } + + /// + /// Unregisters all hotkeys (the low-level keyboard hook continues running) + /// + public void UnregisterAll() + { + this._registeredCallbacks.Clear(); + } + + /// + /// Unregisters a specific single-key hotkey + /// + /// Virtual key code of the unregistered key + /// Thrown when the given key combination is not registered + public void UnregisterHotkey(int virtualKeyCode) + { + this.UnregisterHotkey(new ModifierKeys[0], virtualKeyCode); + } + + /// + /// Unregisters a specific key combination + /// + /// The modifiers of the combination + /// The key of the combination + /// Thrown when the given key combination is not registered + public void UnregisterHotkey(ModifierKeys[] modifiers, int virtualKeyCode) + { + var keybind = new KeybindStruct(modifiers, virtualKeyCode); + + if (!this._registeredCallbacks.Remove(keybind)) + { + throw new HotkeyNotRegisteredException(); + } + } + + /// + /// Unregisters a specific key by its unique identifier + /// + /// Keybind GUID, as returned by RegisterHotkey + 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); + } + + /// + /// Handles a keyboard event based on the KeyboardParams it receives + /// + /// KeyboardParams struct (object type to comply with QueueUserWorkItem) + 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); + + /// + /// Loads the library. + /// + /// Name of the library + /// A handle to the library + [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 +} diff --git a/ColorControl/NonInvasiveKeyboardHookLibrary/ModifierKeys.cs b/ColorControl/NonInvasiveKeyboardHookLibrary/ModifierKeys.cs new file mode 100644 index 0000000..9413bd0 --- /dev/null +++ b/ColorControl/NonInvasiveKeyboardHookLibrary/ModifierKeys.cs @@ -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; + } + } + } +} diff --git a/ColorControl/NvService.cs b/ColorControl/NvService.cs index 3e4dfea..34f48b1 100644 --- a/ColorControl/NvService.cs +++ b/ColorControl/NvService.cs @@ -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(); + } + 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; } diff --git a/ColorControl/Utils.cs b/ColorControl/Utils.cs index 7c7b30f..c5d062e 100644 --- a/ColorControl/Utils.cs +++ b/ColorControl/Utils.cs @@ -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 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 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 processes = null) { - return FindPidFromIndexedProcessName(FindIndexedProcessName(process.Id)); + var indexedProcessName = FindIndexedProcessName(process.Id, process.ProcessName, processes); + if (indexedProcessName == null) + { + return null; + } + + return FindPidFromIndexedProcessName(indexedProcessName, processes); } } } diff --git a/ColorControl/lgtv/LgTvApi.cs b/ColorControl/lgtv/LgTvApi.cs index c97c35a..32b59b8 100644 --- a/ColorControl/lgtv/LgTvApi.cs +++ b/ColorControl/lgtv/LgTvApi.cs @@ -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 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();