From 43a4660cc5873f13799d1758f1e4c441d7c5d8f7 Mon Sep 17 00:00:00 2001 From: Vincent Maas Date: Mon, 11 Jan 2021 19:43:53 +0100 Subject: [PATCH] add some buttons to control LG TV (volume/mute) add preliminary remote control form --- ColorControl/ColorControl.csproj | 11 +- ColorControl/GraphicsService.cs | 12 +++ ColorControl/LgService.cs | 78 ++++++++++++++ ColorControl/MainForm.Designer.cs | 13 +++ ColorControl/MainForm.cs | 9 +- ColorControl/NvService.cs | 5 + ColorControl/Properties/AssemblyInfo.cs | 6 +- ColorControl/RemoteControlForm.Designer.cs | 101 +++++++++++++++++ ColorControl/RemoteControlForm.cs | 66 ++++++++++++ ColorControl/RemoteControlForm.resx | 120 +++++++++++++++++++++ ColorControl/lgtv/LgWebOsMouseService.cs | 11 +- 11 files changed, 424 insertions(+), 8 deletions(-) create mode 100644 ColorControl/RemoteControlForm.Designer.cs create mode 100644 ColorControl/RemoteControlForm.cs create mode 100644 ColorControl/RemoteControlForm.resx diff --git a/ColorControl/ColorControl.csproj b/ColorControl/ColorControl.csproj index 16abca2..9693913 100644 --- a/ColorControl/ColorControl.csproj +++ b/ColorControl/ColorControl.csproj @@ -27,7 +27,7 @@ ColorControl Maassoft 0 - 1.3.6.0 + 1.4.0.0 false true true @@ -175,6 +175,12 @@ + + Form + + + RemoteControlForm.cs + @@ -223,6 +229,9 @@ True Resources.resx + + RemoteControlForm.cs + PreserveNewest diff --git a/ColorControl/GraphicsService.cs b/ColorControl/GraphicsService.cs index 0c73b12..14dd8ce 100644 --- a/ColorControl/GraphicsService.cs +++ b/ColorControl/GraphicsService.cs @@ -48,6 +48,18 @@ namespace ColorControl } } + protected void OpenDisplaySettings(int delay = 1000) + { + Process.Start("ms-settings:display"); + Thread.Sleep(delay); + + var process = Process.GetProcessesByName("SystemSettings").FirstOrDefault(); + if (process != null) + { + System.Windows.Forms.SendKeys.SendWait("%{F4}"); + } + } + protected bool SetRefreshRateInternal(string displayName, uint refreshRate, bool portrait, int horizontal, int vertical) { uint i = 0; diff --git a/ColorControl/LgService.cs b/ColorControl/LgService.cs index 50c9cb2..cae96a6 100644 --- a/ColorControl/LgService.cs +++ b/ColorControl/LgService.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Runtime; using System.Threading; using System.Threading.Tasks; +using System.Web.Script.Serialization; using System.Windows.Forms; using Windows.Data.Json; @@ -41,12 +42,16 @@ namespace ColorControl private bool _allowPowerOn; private bool _justWokeUp; private PnpDev _selectedDevice; + private string _rcButtonsFilename; + private List _remoteControlButtons; + private JavaScriptSerializer _JsonDeserializer = new JavaScriptSerializer(); public LgService(string dataDir, bool allowPowerOn) { _dataDir = dataDir; _allowPowerOn = allowPowerOn; LoadConfig(); + LoadRemoteControlButtons(); foreach (var screen in Screen.AllScreens) { @@ -63,6 +68,7 @@ namespace ColorControl ~LgService() { SaveConfig(); + SaveRemoteControlButtons(); } private void LoadConfig() @@ -78,12 +84,84 @@ namespace ColorControl } } + private void LoadRemoteControlButtons() + { + var defaultButtons = GenerateDefaultRemoteControlButtons(); + + _rcButtonsFilename = Path.Combine(_dataDir, "LgRemoteControlButtons.json"); + if (File.Exists(_rcButtonsFilename)) + { + var json = File.ReadAllText(_rcButtonsFilename); + + _remoteControlButtons = _JsonDeserializer.Deserialize>(json); + + var missingButtons = defaultButtons.Where(b => !_remoteControlButtons.Any(x => x.name.Equals(b.name))); + _remoteControlButtons.AddRange(missingButtons); + } + else + { + _remoteControlButtons = defaultButtons; + } + } + + public List GetRemoteControlButtons() + { + return _remoteControlButtons; + } + + private List GenerateDefaultRemoteControlButtons() + { + var list = new List(); + + for (var i = 1; i < 11; i++) + { + var button = i < 10 ? i : 0; + list.Add(GeneratePreset(button.ToString())); + } + + list.Add(GeneratePreset("Settings", appId: "com.palm.app.settings")); + + list.Add(GeneratePreset("Vol +", step: "VOLUMEUP")); + list.Add(GeneratePreset("Vol -", step: "VOLUMEDOWN")); + list.Add(GeneratePreset("Mute", step: "MUTE")); + + list.Add(GeneratePreset("Up", step: "UP")); + list.Add(GeneratePreset("Down", step: "DOWN")); + list.Add(GeneratePreset("Left", step: "LEFT")); + list.Add(GeneratePreset("Right", step: "RIGHT")); + + list.Add(GeneratePreset("Enter", step: "ENTER")); + list.Add(GeneratePreset("Exit", step: "EXIT")); + + return list; + } + + private LgPreset GeneratePreset(string name, string step = null, string appId = null) + { + var preset = new LgPreset(); + + preset.name = name; + preset.appId = appId; + if (appId == null) + { + preset.steps.Add(step == null ? name : step); + } + + return preset; + } + public void SaveConfig() { var json = JsonConvert.SerializeObject(Config); File.WriteAllText(_configFilename, json); } + public void SaveRemoteControlButtons() + { + var json = JsonConvert.SerializeObject(_remoteControlButtons); + File.WriteAllText(_rcButtonsFilename, json); + } + public async Task RefreshDevices(bool connect = true) { var devices = await Utils.GetPnpDevices(Config.DeviceSearchKey); diff --git a/ColorControl/MainForm.Designer.cs b/ColorControl/MainForm.Designer.cs index 19ca421..707f398 100644 --- a/ColorControl/MainForm.Designer.cs +++ b/ColorControl/MainForm.Designer.cs @@ -71,6 +71,7 @@ this.tabAMD = new System.Windows.Forms.TabPage(); this.lblErrorAMD = new System.Windows.Forms.Label(); this.tabLG = new System.Windows.Forms.TabPage(); + this.btnLGRemoteControl = new System.Windows.Forms.Button(); this.btnLgDeviceFilterRefresh = new System.Windows.Forms.Button(); this.clbLgPower = new System.Windows.Forms.CheckedListBox(); this.btnLgAddButton = new System.Windows.Forms.Button(); @@ -550,6 +551,7 @@ // // tabLG // + this.tabLG.Controls.Add(this.btnLGRemoteControl); this.tabLG.Controls.Add(this.btnLgDeviceFilterRefresh); this.tabLG.Controls.Add(this.clbLgPower); this.tabLG.Controls.Add(this.btnLgAddButton); @@ -581,6 +583,16 @@ this.tabLG.Text = "LG controller"; this.tabLG.UseVisualStyleBackColor = true; // + // btnLGRemoteControl + // + this.btnLGRemoteControl.Location = new System.Drawing.Point(675, 5); + this.btnLGRemoteControl.Name = "btnLGRemoteControl"; + this.btnLGRemoteControl.Size = new System.Drawing.Size(95, 23); + this.btnLGRemoteControl.TabIndex = 36; + this.btnLGRemoteControl.Text = "Remote Control"; + this.btnLGRemoteControl.UseVisualStyleBackColor = true; + this.btnLGRemoteControl.Click += new System.EventHandler(this.btnLGRemoteControl_Click); + // // btnLgDeviceFilterRefresh // this.btnLgDeviceFilterRefresh.Location = new System.Drawing.Point(594, 5); @@ -1426,6 +1438,7 @@ private System.Windows.Forms.ToolStripMenuItem spatialDynamic2x2ToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem spatialStatic2x2ToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem temporalToolStripMenuItem; + private System.Windows.Forms.Button btnLGRemoteControl; } } diff --git a/ColorControl/MainForm.cs b/ColorControl/MainForm.cs index 17ba10b..ae2873f 100644 --- a/ColorControl/MainForm.cs +++ b/ColorControl/MainForm.cs @@ -19,7 +19,6 @@ using System.Reflection; // 1. Import the InteropServices type using System.Runtime.InteropServices; using System.Security.Principal; -using System.Threading; using System.Threading.Tasks; using System.Web.Script.Serialization; using System.Windows.Forms; @@ -1736,6 +1735,7 @@ namespace ColorControl { _lgService.SelectedDevice = (PnpDev)cbxLgDevices.SelectedItem; } + btnLGRemoteControl.Enabled = _lgService.SelectedDevice != null; } private void WarningOk(string text) @@ -1997,5 +1997,12 @@ Do you want to continue?"; AddOrUpdateItem(); } + + private void btnLGRemoteControl_Click(object sender, EventArgs e) + { + var buttons = _lgService.GetRemoteControlButtons(); + var remoteControlForm = new RemoteControlForm(_lgService, buttons); + remoteControlForm.Show(); + } } } \ No newline at end of file diff --git a/ColorControl/NvService.cs b/ColorControl/NvService.cs index aa006be..4d1a11b 100644 --- a/ColorControl/NvService.cs +++ b/ColorControl/NvService.cs @@ -178,6 +178,11 @@ namespace ColorControl { ToggleHDR(); } + else if (enabled) + { + // Currectly there seems to be a bug that after enabling HDR via NVAPI, some settings are only applied upon opening the Display Settings... + OpenDisplaySettings(); + } } public void SetDithering(bool enabled, uint bits = 1, uint mode = 4, NvPreset preset = null) diff --git a/ColorControl/Properties/AssemblyInfo.cs b/ColorControl/Properties/AssemblyInfo.cs index 8be8584..fa56faa 100644 --- a/ColorControl/Properties/AssemblyInfo.cs +++ b/ColorControl/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Maassoft")] [assembly: AssemblyProduct("ColorControl")] -[assembly: AssemblyCopyright("Copyright © Maassoft 2020")] +[assembly: AssemblyCopyright("Copyright © Maassoft 2021")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.3.6.0")] -[assembly: AssemblyFileVersion("1.3.6.0")] +[assembly: AssemblyVersion("1.4.0.0")] +[assembly: AssemblyFileVersion("1.4.0.0")] diff --git a/ColorControl/RemoteControlForm.Designer.cs b/ColorControl/RemoteControlForm.Designer.cs new file mode 100644 index 0000000..d9428f7 --- /dev/null +++ b/ColorControl/RemoteControlForm.Designer.cs @@ -0,0 +1,101 @@ + +namespace ColorControl +{ + partial class RemoteControlForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.flowPanel = new System.Windows.Forms.FlowLayoutPanel(); + this.btnClose = new System.Windows.Forms.Button(); + this.lblUC = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // flowPanel + // + this.flowPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.flowPanel.Location = new System.Drawing.Point(12, 16); + this.flowPanel.Name = "flowPanel"; + this.flowPanel.Size = new System.Drawing.Size(326, 349); + this.flowPanel.TabIndex = 0; + this.flowPanel.MouseDown += new System.Windows.Forms.MouseEventHandler(this.RemoteControlForm_MouseDown); + // + // btnClose + // + this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnClose.FlatAppearance.BorderColor = System.Drawing.Color.DarkGray; + 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(335, 0); + this.btnClose.Name = "btnClose"; + this.btnClose.Size = new System.Drawing.Size(14, 23); + this.btnClose.TabIndex = 1; + this.btnClose.Text = "x"; + this.btnClose.UseVisualStyleBackColor = true; + this.btnClose.Click += new System.EventHandler(this.btnClose_Click); + // + // lblUC + // + this.lblUC.AutoSize = true; + this.lblUC.ForeColor = System.Drawing.Color.Maroon; + this.lblUC.Location = new System.Drawing.Point(130, 0); + this.lblUC.Name = "lblUC"; + this.lblUC.Size = new System.Drawing.Size(100, 13); + this.lblUC.TabIndex = 0; + this.lblUC.Text = "Under construction!"; + // + // RemoteControlForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Black; + this.ClientSize = new System.Drawing.Size(350, 377); + this.Controls.Add(this.lblUC); + this.Controls.Add(this.btnClose); + this.Controls.Add(this.flowPanel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "RemoteControlForm"; + this.Opacity = 0.8D; + this.Text = "RemoteControlForm"; + this.Load += new System.EventHandler(this.RemoteControlForm_Load); + this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.RemoteControlForm_MouseDown); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.FlowLayoutPanel flowPanel; + private System.Windows.Forms.Button btnClose; + private System.Windows.Forms.Label lblUC; + } +} \ No newline at end of file diff --git a/ColorControl/RemoteControlForm.cs b/ColorControl/RemoteControlForm.cs new file mode 100644 index 0000000..5d97a2c --- /dev/null +++ b/ColorControl/RemoteControlForm.cs @@ -0,0 +1,66 @@ +using NWin32; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace ColorControl +{ + partial class RemoteControlForm : Form + { + private LgService _lgService; + private List _buttons; + + public RemoteControlForm(LgService lgService, List buttons) + { + _lgService = lgService; + _buttons = buttons; + + InitializeComponent(); + } + + private void RemoteControlForm_Load(object sender, EventArgs e) + { + foreach (var preset in _buttons) + { + var button = new Button(); + button.ForeColor = Color.White; + button.FlatStyle = FlatStyle.Flat; + button.FlatAppearance.BorderColor = Color.DarkGray; + button.FlatAppearance.MouseOverBackColor = Color.DarkGray; + button.Text = preset.name; + button.Click += ButtonClick; + button.Tag = preset; + + button.Parent = flowPanel; + } + } + + private void ButtonClick(object sender, EventArgs e) + { + var preset = (LgPreset)(sender as Button).Tag; + + _lgService.ApplyPreset(preset); + } + + private void btnClose_Click(object sender, EventArgs e) + { + Close(); + } + + private void RemoteControlForm_MouseDown(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + NativeMethods.ReleaseCapture(); + var intPtr = new UIntPtr(2); + NativeMethods.SendMessageW(Handle, NativeConstants.WM_NCLBUTTONDOWN, intPtr, IntPtr.Zero); + } + } + } +} diff --git a/ColorControl/RemoteControlForm.resx b/ColorControl/RemoteControlForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/ColorControl/RemoteControlForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/ColorControl/lgtv/LgWebOsMouseService.cs b/ColorControl/lgtv/LgWebOsMouseService.cs index 69384d7..5d3d692 100644 --- a/ColorControl/lgtv/LgWebOsMouseService.cs +++ b/ColorControl/lgtv/LgWebOsMouseService.cs @@ -1,5 +1,4 @@ -using NStandard; -using System; +using System; using System.Threading.Tasks; namespace LgTv @@ -28,7 +27,13 @@ namespace LgTv _8, _9, _0, - POWER + POWER, + VOLUMEUP, + VOLUMEDOWN, + MUTE, + MENU, + CC, + DASH } public class LgWebOsMouseService : IDisposable