diff --git a/LICENSE b/LICENSE index 63218ce..3afd917 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018 Nielk1 +Copyright (c) 2018 John Klein Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/VSCView.sln b/VSCView.sln new file mode 100644 index 0000000..859fad9 --- /dev/null +++ b/VSCView.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26730.16 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSCView", "VSCView\VSCView.csproj", "{E513702D-EF79-4766-AD9D-C2382BD0CEAD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E513702D-EF79-4766-AD9D-C2382BD0CEAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E513702D-EF79-4766-AD9D-C2382BD0CEAD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E513702D-EF79-4766-AD9D-C2382BD0CEAD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E513702D-EF79-4766-AD9D-C2382BD0CEAD}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DC3B117E-47DB-4553-8101-4ECBC70B1A48} + EndGlobalSection +EndGlobal diff --git a/VSCView/About.Designer.cs b/VSCView/About.Designer.cs new file mode 100644 index 0000000..48083e2 --- /dev/null +++ b/VSCView/About.Designer.cs @@ -0,0 +1,334 @@ +namespace VSCView +{ + partial class About + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + 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() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(About)); + this.okButton = new System.Windows.Forms.Button(); + this.logoPictureBox = new System.Windows.Forms.PictureBox(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.labelProductName = new System.Windows.Forms.Label(); + this.labelVersion = new System.Windows.Forms.Label(); + this.textBoxDescription = new System.Windows.Forms.TextBox(); + this.labelCompanyName = new System.Windows.Forms.Label(); + this.labelCopyright = new System.Windows.Forms.Label(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabPage1 = new System.Windows.Forms.TabPage(); + this.tabPage2 = new System.Windows.Forms.TabPage(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.tabPage3 = new System.Windows.Forms.TabPage(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.tabPage4 = new System.Windows.Forms.TabPage(); + this.textBox3 = new System.Windows.Forms.TextBox(); + ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.tabControl1.SuspendLayout(); + this.tabPage1.SuspendLayout(); + this.tabPage2.SuspendLayout(); + this.tabPage3.SuspendLayout(); + this.tabPage4.SuspendLayout(); + this.SuspendLayout(); + // + // okButton + // + this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.okButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.okButton.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(54)))), ((int)(((byte)(54)))), ((int)(((byte)(54))))); + this.okButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.okButton.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(204)))), ((int)(((byte)(204)))), ((int)(((byte)(204))))); + this.okButton.Location = new System.Drawing.Point(12, 146); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(128, 31); + this.okButton.TabIndex = 32; + this.okButton.Text = "&OK"; + // + // logoPictureBox + // + this.logoPictureBox.Image = global::VSCView.Properties.Resources.Nielk1_eyes_128; + this.logoPictureBox.Location = new System.Drawing.Point(12, 12); + this.logoPictureBox.Name = "logoPictureBox"; + this.logoPictureBox.Size = new System.Drawing.Size(128, 128); + this.logoPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.logoPictureBox.TabIndex = 31; + this.logoPictureBox.TabStop = false; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Controls.Add(this.labelProductName, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.labelVersion, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.textBoxDescription, 0, 4); + this.tableLayoutPanel1.Controls.Add(this.labelCompanyName, 0, 3); + this.tableLayoutPanel1.Controls.Add(this.labelCopyright, 0, 2); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 5; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.Size = new System.Drawing.Size(572, 136); + this.tableLayoutPanel1.TabIndex = 33; + // + // labelProductName + // + this.labelProductName.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelProductName.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(204)))), ((int)(((byte)(204)))), ((int)(((byte)(204))))); + this.labelProductName.Location = new System.Drawing.Point(0, 0); + this.labelProductName.Margin = new System.Windows.Forms.Padding(0); + this.labelProductName.MaximumSize = new System.Drawing.Size(0, 17); + this.labelProductName.Name = "labelProductName"; + this.labelProductName.Size = new System.Drawing.Size(572, 17); + this.labelProductName.TabIndex = 19; + this.labelProductName.Text = "Product Name"; + this.labelProductName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // labelVersion + // + this.labelVersion.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelVersion.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(204)))), ((int)(((byte)(204)))), ((int)(((byte)(204))))); + this.labelVersion.Location = new System.Drawing.Point(0, 20); + this.labelVersion.Margin = new System.Windows.Forms.Padding(0); + this.labelVersion.MaximumSize = new System.Drawing.Size(0, 17); + this.labelVersion.Name = "labelVersion"; + this.labelVersion.Size = new System.Drawing.Size(572, 17); + this.labelVersion.TabIndex = 0; + this.labelVersion.Text = "Version"; + this.labelVersion.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // textBoxDescription + // + this.textBoxDescription.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(22)))), ((int)(((byte)(22)))), ((int)(((byte)(22))))); + this.textBoxDescription.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.textBoxDescription.Dock = System.Windows.Forms.DockStyle.Fill; + this.textBoxDescription.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(204)))), ((int)(((byte)(204)))), ((int)(((byte)(204))))); + this.textBoxDescription.Location = new System.Drawing.Point(0, 80); + this.textBoxDescription.Margin = new System.Windows.Forms.Padding(0); + this.textBoxDescription.Multiline = true; + this.textBoxDescription.Name = "textBoxDescription"; + this.textBoxDescription.ReadOnly = true; + this.textBoxDescription.ScrollBars = System.Windows.Forms.ScrollBars.Both; + this.textBoxDescription.Size = new System.Drawing.Size(572, 56); + this.textBoxDescription.TabIndex = 23; + this.textBoxDescription.TabStop = false; + this.textBoxDescription.Text = "Description"; + // + // labelCompanyName + // + this.labelCompanyName.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCompanyName.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(204)))), ((int)(((byte)(204)))), ((int)(((byte)(204))))); + this.labelCompanyName.Location = new System.Drawing.Point(0, 60); + this.labelCompanyName.Margin = new System.Windows.Forms.Padding(0); + this.labelCompanyName.MaximumSize = new System.Drawing.Size(0, 17); + this.labelCompanyName.Name = "labelCompanyName"; + this.labelCompanyName.Size = new System.Drawing.Size(572, 17); + this.labelCompanyName.TabIndex = 22; + this.labelCompanyName.Text = "Company Name"; + this.labelCompanyName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // labelCopyright + // + this.labelCopyright.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCopyright.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(204)))), ((int)(((byte)(204)))), ((int)(((byte)(204))))); + this.labelCopyright.Location = new System.Drawing.Point(0, 40); + this.labelCopyright.Margin = new System.Windows.Forms.Padding(0); + this.labelCopyright.MaximumSize = new System.Drawing.Size(0, 17); + this.labelCopyright.Name = "labelCopyright"; + this.labelCopyright.Size = new System.Drawing.Size(572, 17); + this.labelCopyright.TabIndex = 21; + this.labelCopyright.Text = "Copyright"; + this.labelCopyright.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // tabControl1 + // + this.tabControl1.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.tabControl1.Appearance = System.Windows.Forms.TabAppearance.FlatButtons; + this.tabControl1.Controls.Add(this.tabPage1); + this.tabControl1.Controls.Add(this.tabPage2); + this.tabControl1.Controls.Add(this.tabPage3); + this.tabControl1.Controls.Add(this.tabPage4); + this.tabControl1.Location = new System.Drawing.Point(146, 12); + this.tabControl1.Multiline = true; + this.tabControl1.Name = "tabControl1"; + this.tabControl1.Padding = new System.Drawing.Point(0, 0); + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(580, 165); + this.tabControl1.TabIndex = 35; + // + // tabPage1 + // + this.tabPage1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(37)))), ((int)(((byte)(37)))), ((int)(((byte)(37))))); + this.tabPage1.Controls.Add(this.tableLayoutPanel1); + this.tabPage1.Location = new System.Drawing.Point(4, 25); + this.tabPage1.Margin = new System.Windows.Forms.Padding(0); + this.tabPage1.Name = "tabPage1"; + this.tabPage1.Size = new System.Drawing.Size(572, 136); + this.tabPage1.TabIndex = 0; + this.tabPage1.Text = "VSCView"; + // + // tabPage2 + // + this.tabPage2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(37)))), ((int)(((byte)(37)))), ((int)(((byte)(37))))); + this.tabPage2.Controls.Add(this.textBox1); + this.tabPage2.Location = new System.Drawing.Point(4, 25); + this.tabPage2.Margin = new System.Windows.Forms.Padding(0); + this.tabPage2.Name = "tabPage2"; + this.tabPage2.Size = new System.Drawing.Size(422, 136); + this.tabPage2.TabIndex = 1; + this.tabPage2.Text = "VSCView License"; + // + // textBox1 + // + this.textBox1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(22)))), ((int)(((byte)(22)))), ((int)(((byte)(22))))); + this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.textBox1.Dock = System.Windows.Forms.DockStyle.Fill; + this.textBox1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(204)))), ((int)(((byte)(204)))), ((int)(((byte)(204))))); + this.textBox1.Location = new System.Drawing.Point(0, 0); + this.textBox1.Margin = new System.Windows.Forms.Padding(0); + this.textBox1.Multiline = true; + this.textBox1.Name = "textBox1"; + this.textBox1.ReadOnly = true; + this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Both; + this.textBox1.Size = new System.Drawing.Size(422, 136); + this.textBox1.TabIndex = 35; + this.textBox1.TabStop = false; + this.textBox1.Text = resources.GetString("textBox1.Text"); + // + // tabPage3 + // + this.tabPage3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(37)))), ((int)(((byte)(37)))), ((int)(((byte)(37))))); + this.tabPage3.Controls.Add(this.textBox2); + this.tabPage3.Location = new System.Drawing.Point(4, 25); + this.tabPage3.Margin = new System.Windows.Forms.Padding(0); + this.tabPage3.Name = "tabPage3"; + this.tabPage3.Size = new System.Drawing.Size(422, 136); + this.tabPage3.TabIndex = 2; + this.tabPage3.Text = "HidLibrary License"; + // + // textBox2 + // + this.textBox2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(22)))), ((int)(((byte)(22)))), ((int)(((byte)(22))))); + this.textBox2.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.textBox2.Dock = System.Windows.Forms.DockStyle.Fill; + this.textBox2.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(204)))), ((int)(((byte)(204)))), ((int)(((byte)(204))))); + this.textBox2.Location = new System.Drawing.Point(0, 0); + this.textBox2.Margin = new System.Windows.Forms.Padding(0); + this.textBox2.Multiline = true; + this.textBox2.Name = "textBox2"; + this.textBox2.ReadOnly = true; + this.textBox2.ScrollBars = System.Windows.Forms.ScrollBars.Both; + this.textBox2.Size = new System.Drawing.Size(422, 136); + this.textBox2.TabIndex = 36; + this.textBox2.TabStop = false; + this.textBox2.Text = resources.GetString("textBox2.Text"); + // + // tabPage4 + // + this.tabPage4.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(37)))), ((int)(((byte)(37)))), ((int)(((byte)(37))))); + this.tabPage4.Controls.Add(this.textBox3); + this.tabPage4.Location = new System.Drawing.Point(4, 25); + this.tabPage4.Margin = new System.Windows.Forms.Padding(0); + this.tabPage4.Name = "tabPage4"; + this.tabPage4.Size = new System.Drawing.Size(422, 136); + this.tabPage4.TabIndex = 3; + this.tabPage4.Text = "Newtonsoft.Json License"; + // + // textBox3 + // + this.textBox3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(22)))), ((int)(((byte)(22)))), ((int)(((byte)(22))))); + this.textBox3.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.textBox3.Dock = System.Windows.Forms.DockStyle.Fill; + this.textBox3.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(204)))), ((int)(((byte)(204)))), ((int)(((byte)(204))))); + this.textBox3.Location = new System.Drawing.Point(0, 0); + this.textBox3.Margin = new System.Windows.Forms.Padding(0); + this.textBox3.Multiline = true; + this.textBox3.Name = "textBox3"; + this.textBox3.ReadOnly = true; + this.textBox3.ScrollBars = System.Windows.Forms.ScrollBars.Both; + this.textBox3.Size = new System.Drawing.Size(422, 136); + this.textBox3.TabIndex = 37; + this.textBox3.TabStop = false; + this.textBox3.Text = resources.GetString("textBox3.Text"); + // + // About + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(37)))), ((int)(((byte)(37)))), ((int)(((byte)(37))))); + this.ClientSize = new System.Drawing.Size(738, 188); + this.Controls.Add(this.tabControl1); + this.Controls.Add(this.logoPictureBox); + this.Controls.Add(this.okButton); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "About"; + this.Padding = new System.Windows.Forms.Padding(9); + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "About"; + ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.tabControl1.ResumeLayout(false); + this.tabPage1.ResumeLayout(false); + this.tabPage2.ResumeLayout(false); + this.tabPage2.PerformLayout(); + this.tabPage3.ResumeLayout(false); + this.tabPage3.PerformLayout(); + this.tabPage4.ResumeLayout(false); + this.tabPage4.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button okButton; + private System.Windows.Forms.PictureBox logoPictureBox; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label labelProductName; + private System.Windows.Forms.Label labelVersion; + private System.Windows.Forms.TextBox textBoxDescription; + private System.Windows.Forms.Label labelCompanyName; + private System.Windows.Forms.Label labelCopyright; + private System.Windows.Forms.TabControl tabControl1; + private System.Windows.Forms.TabPage tabPage1; + private System.Windows.Forms.TabPage tabPage2; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.TabPage tabPage3; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.TabPage tabPage4; + private System.Windows.Forms.TextBox textBox3; + } +} diff --git a/VSCView/About.cs b/VSCView/About.cs new file mode 100644 index 0000000..720e4d8 --- /dev/null +++ b/VSCView/About.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace VSCView +{ + partial class About : Form + { + public About() + { + InitializeComponent(); + this.Text = String.Format("About {0}", AssemblyTitle); + this.labelProductName.Text = AssemblyProduct; + this.labelVersion.Text = String.Format("Version {0}", AssemblyVersion); + this.labelCopyright.Text = AssemblyCopyright; + this.labelCompanyName.Text = AssemblyCompany; + this.textBoxDescription.Text = AssemblyDescription; + } + + #region Assembly Attribute Accessors + + public string AssemblyTitle + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false); + if (attributes.Length > 0) + { + AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0]; + if (titleAttribute.Title != "") + { + return titleAttribute.Title; + } + } + return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase); + } + } + + public string AssemblyVersion + { + get + { + return Assembly.GetExecutingAssembly().GetName().Version.ToString(); + } + } + + public string AssemblyDescription + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyDescriptionAttribute)attributes[0]).Description; + } + } + + public string AssemblyProduct + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyProductAttribute)attributes[0]).Product; + } + } + + public string AssemblyCopyright + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyCopyrightAttribute)attributes[0]).Copyright; + } + } + + public string AssemblyCompany + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyCompanyAttribute)attributes[0]).Company; + } + } + #endregion + } +} diff --git a/VSCView/About.resx b/VSCView/About.resx new file mode 100644 index 0000000..a7bc4a0 --- /dev/null +++ b/VSCView/About.resx @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + MIT License + +Copyright (c) 2018 John Klein + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + Copyright (c) 2010 Ultraviolet Catastrophe + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + The MIT License (MIT) + +Copyright (c) 2007 James Newton-King + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + \ No newline at end of file diff --git a/VSCView/App.config b/VSCView/App.config new file mode 100644 index 0000000..b50c74f --- /dev/null +++ b/VSCView/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/VSCView/MainForm.Designer.cs b/VSCView/MainForm.Designer.cs new file mode 100644 index 0000000..a6c878e --- /dev/null +++ b/VSCView/MainForm.Designer.cs @@ -0,0 +1,194 @@ +namespace VSCView +{ + partial class MainForm + { + /// + /// 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.components = new System.ComponentModel.Container(); + this.tmrPaint = new System.Windows.Forms.Timer(this.components); + this.cmsMain = new System.Windows.Forms.ContextMenuStrip(this.components); + this.tsmiTheme = new System.Windows.Forms.ToolStripMenuItem(); + this.tsmiController = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.tsmiReloadThemes = new System.Windows.Forms.ToolStripMenuItem(); + this.tsmiReloadControllers = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); + this.tsmiAbout = new System.Windows.Forms.ToolStripMenuItem(); + this.tsmiExit = new System.Windows.Forms.ToolStripMenuItem(); + this.lblHint1 = new System.Windows.Forms.Label(); + this.lblHint2 = new System.Windows.Forms.Label(); + this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); + this.tsmiSetBackgroundColor = new System.Windows.Forms.ToolStripMenuItem(); + this.colorDialog1 = new System.Windows.Forms.ColorDialog(); + this.cmsMain.SuspendLayout(); + this.SuspendLayout(); + // + // tmrPaint + // + this.tmrPaint.Enabled = true; + this.tmrPaint.Interval = 15; + this.tmrPaint.Tick += new System.EventHandler(this.tmrPaint_Tick); + // + // cmsMain + // + this.cmsMain.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.tsmiTheme, + this.tsmiController, + this.toolStripSeparator1, + this.tsmiReloadThemes, + this.tsmiReloadControllers, + this.toolStripSeparator2, + this.tsmiSetBackgroundColor, + this.tsmiAbout, + this.toolStripSeparator3, + this.tsmiExit}); + this.cmsMain.Name = "cmsMain"; + this.cmsMain.Size = new System.Drawing.Size(190, 176); + // + // tsmiTheme + // + this.tsmiTheme.Name = "tsmiTheme"; + this.tsmiTheme.Size = new System.Drawing.Size(189, 22); + this.tsmiTheme.Text = "&Theme"; + // + // tsmiController + // + this.tsmiController.Name = "tsmiController"; + this.tsmiController.Size = new System.Drawing.Size(189, 22); + this.tsmiController.Text = "&Controller"; + // + // toolStripSeparator1 + // + this.toolStripSeparator1.Name = "toolStripSeparator1"; + this.toolStripSeparator1.Size = new System.Drawing.Size(186, 6); + // + // tsmiReloadThemes + // + this.tsmiReloadThemes.Name = "tsmiReloadThemes"; + this.tsmiReloadThemes.Size = new System.Drawing.Size(189, 22); + this.tsmiReloadThemes.Text = "Reload Themes"; + this.tsmiReloadThemes.Click += new System.EventHandler(this.tsmiReloadThemes_Click); + // + // tsmiReloadControllers + // + this.tsmiReloadControllers.Name = "tsmiReloadControllers"; + this.tsmiReloadControllers.Size = new System.Drawing.Size(189, 22); + this.tsmiReloadControllers.Text = "Reload Controllers"; + this.tsmiReloadControllers.Click += new System.EventHandler(this.tsmiReloadControllers_Click); + // + // toolStripSeparator2 + // + this.toolStripSeparator2.Name = "toolStripSeparator2"; + this.toolStripSeparator2.Size = new System.Drawing.Size(186, 6); + // + // tsmiAbout + // + this.tsmiAbout.Name = "tsmiAbout"; + this.tsmiAbout.Size = new System.Drawing.Size(189, 22); + this.tsmiAbout.Text = "&About"; + this.tsmiAbout.Click += new System.EventHandler(this.tsmiAbout_Click); + // + // tsmiExit + // + this.tsmiExit.Name = "tsmiExit"; + this.tsmiExit.Size = new System.Drawing.Size(189, 22); + this.tsmiExit.Text = "E&xit"; + this.tsmiExit.Click += new System.EventHandler(this.tsmiExit_Click); + // + // lblHint1 + // + this.lblHint1.AutoSize = true; + this.lblHint1.Location = new System.Drawing.Point(87, 77); + this.lblHint1.Name = "lblHint1"; + this.lblHint1.Size = new System.Drawing.Size(142, 13); + this.lblHint1.TabIndex = 1; + this.lblHint1.Text = "Right Click for Context Menu"; + // + // lblHint2 + // + this.lblHint2.AutoSize = true; + this.lblHint2.Location = new System.Drawing.Point(87, 109); + this.lblHint2.Name = "lblHint2"; + this.lblHint2.Size = new System.Drawing.Size(119, 13); + this.lblHint2.TabIndex = 2; + this.lblHint2.Text = "Click and Drag to Move"; + // + // toolStripSeparator3 + // + this.toolStripSeparator3.Name = "toolStripSeparator3"; + this.toolStripSeparator3.Size = new System.Drawing.Size(186, 6); + // + // tsmiSetBackgroundColor + // + this.tsmiSetBackgroundColor.Name = "tsmiSetBackgroundColor"; + this.tsmiSetBackgroundColor.Size = new System.Drawing.Size(189, 22); + this.tsmiSetBackgroundColor.Text = "Set Background Color"; + this.tsmiSetBackgroundColor.Click += new System.EventHandler(this.tsmiSetBackgroundColor_Click); + // + // colorDialog1 + // + this.colorDialog1.Color = System.Drawing.Color.Lime; + // + // MainForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Lime; + this.ClientSize = new System.Drawing.Size(314, 264); + this.ContextMenuStrip = this.cmsMain; + this.Controls.Add(this.lblHint2); + this.Controls.Add(this.lblHint1); + this.DoubleBuffered = true; + this.Name = "MainForm"; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.Text = "VSCView"; + this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.MainForm_MouseDown); + this.cmsMain.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Timer tmrPaint; + private System.Windows.Forms.ContextMenuStrip cmsMain; + private System.Windows.Forms.ToolStripMenuItem tsmiTheme; + private System.Windows.Forms.ToolStripMenuItem tsmiController; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; + private System.Windows.Forms.ToolStripMenuItem tsmiExit; + private System.Windows.Forms.ToolStripMenuItem tsmiReloadThemes; + private System.Windows.Forms.ToolStripMenuItem tsmiReloadControllers; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; + private System.Windows.Forms.ToolStripMenuItem tsmiAbout; + private System.Windows.Forms.Label lblHint1; + private System.Windows.Forms.Label lblHint2; + private System.Windows.Forms.ToolStripMenuItem tsmiSetBackgroundColor; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; + private System.Windows.Forms.ColorDialog colorDialog1; + } +} \ No newline at end of file diff --git a/VSCView/MainForm.cs b/VSCView/MainForm.cs new file mode 100644 index 0000000..362a8d8 --- /dev/null +++ b/VSCView/MainForm.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace VSCView +{ + public partial class MainForm : Form + { + //SteamController[] Controllers; + //SteamController.SteamControllerState State; + + ControllerData ControllerData; + SteamController ActiveController; + + //short AngularVelocityXMax = 5000; + //short AngularVelocityYMax = 5000; + //short AngularVelocityZMax = 5000; + + UI ui; + + public MainForm() + { + this.FormBorderStyle = FormBorderStyle.None; + InitializeComponent(); + + ControllerData = new ControllerData(); + //ActiveController.SetController(Controllers[0]); + + //ui = new UI(ActiveController, "default",); + + //this.Width = ui.Width; + //this.Height = ui.Height; + + //Controllers = SteamController.GetControllers(); + //ActiveController.SetController(Controllers[0]); + //if (Controllers.Length > 0) Controllers[0].StateUpdated += (object sender, SteamController.SteamControllerState e) => MainForm_StateUpdated(sender, e, 0); + //if (Controllers.Length > 1) Controllers[1].StateUpdated += (object sender, SteamController.SteamControllerState e) => MainForm_StateUpdated(sender, e, 1); + //if (Controllers.Length > 2) Controllers[2].StateUpdated += (object sender, SteamController.SteamControllerState e) => MainForm_StateUpdated(sender, e, 2); + //if (Controllers.Length > 3) Controllers[3].StateUpdated += (object sender, SteamController.SteamControllerState e) => MainForm_StateUpdated(sender, e, 3); + + LoadThemes(); + LoadControllers(); + } + + private void LoadThemes() + { + tsmiTheme.DropDownItems.Clear(); + + if (!Directory.Exists("themes")) Directory.CreateDirectory("themes"); + string[] themeParents = Directory.GetDirectories("themes"); + + foreach (string themeParent in themeParents) + { + string ThemeName = Path.GetFileName(themeParent); + + string[] themeFiles = Directory.GetFiles(themeParent, "*.json", SearchOption.TopDirectoryOnly); + foreach (string themeFile in themeFiles) + { + string ThemeFileName = Path.GetFileNameWithoutExtension(themeFile); + + string DisplayName = ThemeName + "/" + ThemeFileName; + + ToolStripItem itm = tsmiTheme.DropDownItems.Add(DisplayName, null, LoadTheme); + } + } + } + + private void LoadControllers() + { + tsmiController.DropDownItems.Clear(); + + SteamController[] Controllers = SteamController.GetControllers(); + + foreach (SteamController controller in Controllers) + { + ToolStripItem itm = tsmiController.DropDownItems.Add(controller.GetDevicePath(), null, LoadController); + itm.Tag = controller; + } + } + + private void LoadController(object sender, EventArgs e) + { + if (ActiveController != null) + { + ActiveController.DeInitalize(); + } + + ToolStripItem item = (ToolStripItem)sender; + ActiveController = (SteamController)item.Tag; + + ControllerData.SetController(ActiveController); + ActiveController.Initalize(); + } + + private void LoadTheme(object sender, EventArgs e) + { + lblHint1.Hide(); + lblHint2.Hide(); + + ToolStripItem item = (ToolStripItem)sender; + string displayText = item.Text; + + string[] displayTextParts = displayText.Split(new string[] { "/" }, 2, StringSplitOptions.None); + + string skinJson = File.ReadAllText(Path.Combine("themes", displayTextParts[0], displayTextParts[1] + @".json")); + + ui = new UI(ControllerData, displayTextParts[0], skinJson); + this.Width = ui.Width; + this.Height = ui.Height; + } + + #region Drag Anywhere + public const int WM_NCLBUTTONDOWN = 0xA1; + public const int HT_CAPTION = 0x2; + + [System.Runtime.InteropServices.DllImportAttribute("user32.dll")] + public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); + [System.Runtime.InteropServices.DllImportAttribute("user32.dll")] + public static extern bool ReleaseCapture(); + + private void MainForm_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + ReleaseCapture(); + SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0); + } + } + #endregion Drag Anywhere + + protected override void OnPaint(PaintEventArgs e) + { + //DateTime now = DateTime.UtcNow; + + // Call the OnPaint method of the base class. + base.OnPaint(e); + + ui?.Paint(e.Graphics); + + //Console.WriteLine((DateTime.UtcNow - now).TotalMilliseconds); + } + + private void tmrPaint_Tick(object sender, EventArgs e) + { + this.Invalidate(); // we can invalidate specific zones + this.Update(); + } + + private void tsmiExit_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void tsmiReloadThemes_Click(object sender, EventArgs e) + { + LoadThemes(); + } + + private void tsmiReloadControllers_Click(object sender, EventArgs e) + { + LoadControllers(); + } + + private void tsmiAbout_Click(object sender, EventArgs e) + { + new About().ShowDialog(); + } + + private void tsmiSetBackgroundColor_Click(object sender, EventArgs e) + { + if(colorDialog1.ShowDialog() == DialogResult.OK) + { + this.BackColor = colorDialog1.Color; + } + } + } +} diff --git a/VSCView/MainForm.resx b/VSCView/MainForm.resx new file mode 100644 index 0000000..411f443 --- /dev/null +++ b/VSCView/MainForm.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + 17, 17 + + + 115, 17 + + + 215, 17 + + \ No newline at end of file diff --git a/VSCView/OSD.cs b/VSCView/OSD.cs new file mode 100644 index 0000000..e2f738c --- /dev/null +++ b/VSCView/OSD.cs @@ -0,0 +1,946 @@ +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace VSCView +{ + public class UI + { + public int Height { get; private set; } + public int Width { get; private set; } + + private UI_ImageCache cache; + private ControllerData data; + private List Items; + + public UI(ControllerData data, string themePath, string json) + { + JObject themeData = JObject.Parse(json); + Initalize(data, themePath, themeData); + } + + public UI(ControllerData data, string themePath, JObject themeData) + { + Initalize(data, themePath, themeData); + } + + private void Initalize(ControllerData data, string themePath, JObject themeData) + { + this.data = data; + cache = new UI_ImageCache(themePath); + Items = new List(); + + Height = themeData["height"]?.Value() ?? 100; + Width = themeData["width"]?.Value() ?? 100; + + themeData["children"]?.ToList().ForEach(child => + { + string uiType = child["type"]?.Value() ?? ""; + + switch (uiType) + { + case "": + Items.Add(new UI_Item(data, cache, themePath, (JObject)child)); + break; + case "image": + Items.Add(new UI_GraphicalItem(data, cache, themePath, (JObject)child)); + break; + case "showhide": + Items.Add(new UL_ShowHide(data, cache, themePath, (JObject)child)); + break; + case "slider": + Items.Add(new UL_Slider(data, cache, themePath, (JObject)child)); + break; + case "trailpad": + Items.Add(new UL_TrailPad(data, cache, themePath, (JObject)child)); + break; + case "pbar": + Items.Add(new UL_PBar(data, cache, themePath, (JObject)child)); + break; + case "basic3d1": + Items.Add(new UL_Basic3D1(data, cache, themePath, (JObject)child)); + break; + default: + throw new Exception("Unknown UI Widget Type"); + } + }); + } + + public void Paint(Graphics graphics) + { + foreach(UI_Item item in Items) + { + item.Paint(graphics); + } + } + } + + public class ControllerData + { + SteamController ActiveController; + + public bool GetBasicControl(string inputName) + { + if (ActiveController == null) return false; + + inputName = inputName.ToLowerInvariant(); + + SteamController.SteamControllerState state = ActiveController.GetState(); + + switch (inputName) + { + case "a": + return state.Buttons.A; + case "b": + return state.Buttons.B; + case "x": + return state.Buttons.X; + case "y": + return state.Buttons.Y; + + case "leftbumper": + case "lb": + return state.Buttons.LeftBumper; + case "lefttrigger": + case "lt": + return state.Buttons.LeftTrigger; + + case "rightbumper": + case "rb": + return state.Buttons.RightBumper; + case "righttrigger": + case "rt": + return state.Buttons.RightTrigger; + + case "leftgrip": + case "lg": + return state.Buttons.LeftGrip; + case "rightgrip": + case "rg": + return state.Buttons.RightGrip; + + case "start": + return state.Buttons.Start; + case "steam": + return state.Buttons.Steam; + case "select": + return state.Buttons.Select; + + case "down": + return state.Buttons.Down; + case "left": + return state.Buttons.Left; + case "right": + return state.Buttons.Right; + case "up": + return state.Buttons.Up; + + case "stickclick": + case "sc": + return state.Buttons.StickClick; + case "leftpadtouch": + case "lpt": + return state.Buttons.LeftPadTouch; + case "leftpadclick": + case "lpc": + return state.Buttons.LeftPadClick; + case "rightpadtouch": + case "rpt": + return state.Buttons.RightPadTouch; + case "rightpadclick": + case "rpc": + return state.Buttons.RightPadClick; + default: + return false; + } + } + + public Int32 GetAnalogControl(string inputName) + { + if (ActiveController == null) return 0; + + inputName = inputName.ToLowerInvariant(); + + SteamController.SteamControllerState state = ActiveController.GetState(); + + switch (inputName) + { + case "leftpadx": return state.LeftPadX; + case "leftpady": return state.LeftPadY; + + case "rightpadx": return state.RightPadX; + case "rightpady": return state.RightPadY; + + case "leftstickx": return state.LeftStickX; + case "leftsticky": return state.LeftStickY; + + case "lefttrigger": return state.LeftTrigger; + case "righttrigger": return state.RightTrigger; + + case "angularvelocityx": return state.AngularVelocityX; + case "angularvelocityy": return state.AngularVelocityY; + case "angularvelocityz": return state.AngularVelocityZ; + + // consider orientation data here, but it's a quaternion so that's complicated + + default: return 0; + } + } + + public SteamController.SteamControllerState GetState() + { + if (ActiveController == null) return null; + return ActiveController.GetState(); + } + + public void SetController(SteamController ActiveController) + { + this.ActiveController = ActiveController; + } + } + + public class UI_ImageCache : IDisposable + { + private string themePath; + private Dictionary cache; + + public UI_ImageCache(string themePath) + { + this.themePath = themePath; + this.cache = new Dictionary(); + } + + private bool disposed = false; + ~UI_ImageCache() + { + Dispose(false); + } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + protected virtual void Dispose(bool disposing) + { + if (disposed) + return; + + if (disposing) + { + // Free any other managed objects here. + // + foreach(var key in cache.Keys) + { + cache[key].Dispose(); + cache[key] = null; + } + } + + // Free any unmanaged objects here. + // + cache = null; + disposed = true; + } + + public Image GetImage(string Key, Func ImageLoader) + { + lock(cache) + { + if (cache.ContainsKey(Key)) return cache[Key]; + cache[Key] = ImageLoader(); + return cache[Key]; + } + } + + public Image LoadImage(string name) + { + // load the image for the active theme + string ImagePath = Path.Combine("themes", themePath, name); + + // this will throw an exception if the file or path doesn't exist + return Image.FromFile(ImagePath); + } + + public static Image SetImageOpacity(Image image, float opacity) + { + try + { + //create a Bitmap the size of the image provided + Bitmap bmp = new Bitmap(image.Width, image.Height); + + //create a graphics object from the image + using (Graphics gfx = Graphics.FromImage(bmp)) + { + + //create a color matrix object + ColorMatrix matrix = new ColorMatrix(); + + //set the opacity + matrix.Matrix33 = opacity; + + //create image attributes + ImageAttributes attributes = new ImageAttributes(); + + //set the color(opacity) of the image + attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); + + //now draw the image + gfx.DrawImage(image, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes); + + bmp.SetResolution(image.HorizontalResolution, image.VerticalResolution); + } + return bmp; + } + catch (Exception ex) + { + return null; + } + } + + } + + public class UI_Item + { + public float X { get; private set; } + public float Y { get; private set; } + public float Rot { get; private set; } + + private UI_ImageCache cache; + private List Items; + + //public UI_Item(UI_ImageCache cache, string themePath, string json) + //{ + // JObject themeData = JObject.Parse(json); + // Initalize(cache, themePath, themeData); + //} + + public UI_Item(ControllerData data, UI_ImageCache cache, string themePath, JObject themeData) + { + Initalize(data, cache, themePath, themeData); + } + + protected virtual void Initalize(ControllerData data, UI_ImageCache cache, string themePath, JObject themeData) + { + this.cache = cache; + Items = new List(); + + X = themeData["x"]?.Value() ?? 0; + Y = themeData["y"]?.Value() ?? 0; + Rot = themeData["rot"]?.Value() ?? 0; + + themeData["children"]?.ToList().ForEach(child => + { + string uiType = child["type"]?.Value() ?? ""; + + switch (uiType) + { + case "": + Items.Add(new UI_Item(data, cache, themePath, (JObject)child)); + break; + case "image": + Items.Add(new UI_GraphicalItem(data, cache, themePath, (JObject)child)); + break; + case "showhide": + Items.Add(new UL_ShowHide(data, cache, themePath, (JObject)child)); + break; + case "slider": + Items.Add(new UL_Slider(data, cache, themePath, (JObject)child)); + break; + case "trailpad": + Items.Add(new UL_TrailPad(data, cache, themePath, (JObject)child)); + break; + case "pbar": + Items.Add(new UL_PBar(data, cache, themePath, (JObject)child)); + break; + case "basic3d1": + Items.Add(new UL_Basic3D1(data, cache, themePath, (JObject)child)); + break; + default: + throw new Exception("Unknown UI Widget Type"); + } + }); + } + + public virtual void Paint(Graphics graphics) + { + Matrix preserve = graphics.Transform; + graphics.TranslateTransform(X, Y); + graphics.RotateTransform(Rot); + + foreach (UI_Item item in Items) + { + item.Paint(graphics); + } + + graphics.Transform = preserve; + } + } + + public class UI_GraphicalItem : UI_Item + { + public UI_GraphicalItem(ControllerData data, UI_ImageCache cache, string themePath, JObject themeData) : base(data, cache, themePath, themeData) + { + } + + public float Height { get; private set; } + public float Width { get; private set; } + public bool DrawFromCenter { get; private set; } + + protected Image DisplayImage; + + protected override void Initalize(ControllerData data, UI_ImageCache cache, string themePath, JObject themeData) + { + base.Initalize(data, cache, themePath, themeData); + + Height = themeData["height"]?.Value() ?? 0; + Width = themeData["width"]?.Value() ?? 0; + DrawFromCenter = themeData["center"]?.Value() ?? false; + + string imageName = themeData["image"]?.Value(); + + if (!string.IsNullOrWhiteSpace(imageName)) + { + DisplayImage = cache.LoadImage(imageName); + } + } + + public override void Paint(Graphics graphics) + { + Matrix preserve = graphics.Transform; + if (DrawFromCenter) + graphics.TranslateTransform(-Width / 2, -Height / 2); + + if (DisplayImage != null) + { + if(DisplayImage != null) + graphics.DrawImage(DisplayImage, X, Y, Width, Height); + } + + graphics.Transform = preserve; + + //if (DrawFromCenter) + // graphics.TranslateTransform(X, Y); + + base.Paint(graphics); + + //graphics.Transform = preserve; + } + } + + public class UL_ShowHide : UI_Item + { + public UL_ShowHide(ControllerData data, UI_ImageCache cache, string themePath, JObject themeData) : base(data, cache, themePath, themeData) + { + } + + private ControllerData data; + private string InputName; + + private bool output; + + protected override void Initalize(ControllerData data, UI_ImageCache cache, string themePath, JObject themeData) + { + base.Initalize(data, cache, themePath, themeData); + this.data = data; + + output = true; + + InputName = themeData["inputName"]?.Value(); + output = !(themeData["invert"]?.Value() ?? false); + } + + public override void Paint(Graphics graphics) + { + Matrix preserve = graphics.Transform; + + if (string.IsNullOrWhiteSpace(InputName)) + { + if (output) base.Paint(graphics); + } + else if (data.GetBasicControl(InputName)) + { + if (output) base.Paint(graphics); + } + else + { + if (!output) base.Paint(graphics); + } + } + } + + public class UL_Slider : UI_Item + { + public UL_Slider(ControllerData data, UI_ImageCache cache, string themePath, JObject themeData) : base(data, cache, themePath, themeData) + { + } + + private ControllerData data; + protected string AxisNameX; + protected string AxisNameY; + protected float ScaleFactorX; + protected float ScaleFactorY; + + protected override void Initalize(ControllerData data, UI_ImageCache cache, string themePath, JObject themeData) + { + base.Initalize(data, cache, themePath, themeData); + this.data = data; + + AxisNameX = themeData["axisNameX"]?.Value(); + AxisNameY = themeData["axisNameY"]?.Value(); + + ScaleFactorX = themeData["scaleFactorX"]?.Value() ?? 0; + ScaleFactorY = themeData["scaleFactorY"]?.Value() ?? 0; + } + + public override void Paint(Graphics graphics) + { + Matrix preserve = graphics.Transform; + + float AnalogX = string.IsNullOrWhiteSpace(AxisNameX) ? 0 : (data.GetAnalogControl(AxisNameX) * ScaleFactorX); + float AnalogY = string.IsNullOrWhiteSpace(AxisNameY) ? 0 : (data.GetAnalogControl(AxisNameY) * ScaleFactorY); + + graphics.TranslateTransform(AnalogX, -AnalogY); + + base.Paint(graphics); + + graphics.Transform = preserve; + } + } + + public class UL_TrailPad : UL_Slider + { + public UL_TrailPad(ControllerData data, UI_ImageCache cache, string themePath, JObject themeData) : base(data, cache, themePath, themeData) + { + } + + private ControllerData data; + private Image[] ImagePadDecay; + private List PadPosHistory; + private string InputName; + + protected override void Initalize(ControllerData data, UI_ImageCache cache, string themePath, JObject themeData) + { + base.Initalize(data, cache, themePath, themeData); + this.data = data; + + PadPosHistory = new List(); + + InputName = themeData["inputName"]?.Value(); + string imageName = themeData["image"]?.Value(); + int TrailLength = themeData["length"]?.Value()??0; + + if (!string.IsNullOrWhiteSpace(imageName) && TrailLength > 0) + { + Image ImagePadDecayBase = cache.LoadImage(imageName); + ImagePadDecay = new Image[TrailLength]; + for (int x = 0; x < ImagePadDecay.Length; x++) + { + float percent = ((x + 1) * 1.0f / ImagePadDecay.Length); + + ImagePadDecay[x] = cache.GetImage($"{imageName}:{percent}", () => { return UI_ImageCache.SetImageOpacity(ImagePadDecayBase, percent * 0.15f); }); + } + } + else + { + ImagePadDecay = new Image[0]; + } + } + + public override void Paint(Graphics graphics) + { + Matrix preserve = graphics.Transform; + graphics.TranslateTransform(X, Y); + + bool ControlHot = data.GetBasicControl(InputName); + + PointF? prevCord = null; + for (int pointfade = 0; pointfade < PadPosHistory.Count && pointfade < ImagePadDecay.Length; pointfade++) + { + PointF? cord = PadPosHistory[pointfade]; + if (cord.HasValue) + { + float SubPointWidth = ImagePadDecay[pointfade].Width; + float SubPointHeight = ImagePadDecay[pointfade].Height; + + float ratio = (pointfade * 1.0f / ImagePadDecay.Length); + ratio = ratio * 0.5f + 0.5f; + SubPointWidth *= ratio; + SubPointHeight *= ratio; + + graphics.DrawImage(ImagePadDecay[pointfade], cord.Value.X - (SubPointWidth / 2.0f), cord.Value.Y - (SubPointHeight / 2.0f), SubPointWidth, SubPointHeight); + if (prevCord.HasValue) + { + // draw extra dots between points we've seen + double xVector = cord.Value.X - prevCord.Value.X; + double yVector = cord.Value.Y - prevCord.Value.Y; + + double distance = Math.Sqrt(xVector * xVector + yVector * yVector); + double subdist = distance * 0.5f; + + if ((int)subdist > 0) + { + double distBetweenDots = distance / subdist; + float SubPoint2Width = ImagePadDecay[pointfade - 1].Width; + float SubPoint2Height = ImagePadDecay[pointfade - 1].Height; + + //float ratio = (pointfade * 1.0f / ImagePadDecay.Length); + SubPoint2Width *= ratio; + SubPoint2Height *= ratio; + + for (int subDistPlot = 0; subDistPlot < subdist; subDistPlot++) + { + PointF betweenPoint = new PointF( + (float)(prevCord.Value.X + xVector * subDistPlot / subdist), + (float)(prevCord.Value.Y + yVector * subDistPlot / subdist)); + + //Matrix preserve2 = graphics.Transform; + //graphics.TranslateTransform(X, Y); + graphics.DrawImage(ImagePadDecay[pointfade - 1], betweenPoint.X - (SubPoint2Width / 2.0f), betweenPoint.Y - (SubPoint2Height / 2.0f), SubPoint2Width, SubPoint2Height); + //graphics.Transform = preserve2; + } + } + } + } + prevCord = cord; + } + + + if (PadPosHistory.Count >= ImagePadDecay.Length && PadPosHistory.Count > 0) PadPosHistory.RemoveAt(0); + + float AnalogX = string.IsNullOrWhiteSpace(AxisNameX) ? 0 : (data.GetAnalogControl(AxisNameX) * ScaleFactorX); + float AnalogY = string.IsNullOrWhiteSpace(AxisNameY) ? 0 : (data.GetAnalogControl(AxisNameY) * ScaleFactorY); + + if (string.IsNullOrWhiteSpace(InputName) || data.GetBasicControl(InputName)) + { + PointF cord = new PointF(AnalogX,-AnalogY); + PadPosHistory.Add(cord); + } + else + { + PadPosHistory.Add(null); + } + + graphics.Transform = preserve; + + base.Paint(graphics); + } + } + + public class UL_PBar : UI_Item + { + public UL_PBar(ControllerData data, UI_ImageCache cache, string themePath, JObject themeData) : base(data, cache, themePath, themeData) + { + } + + private ControllerData data; + protected string AxisName; + protected string Direction; + protected int Min; + protected int Max; + protected float Width; + protected float Height; + protected Color Foreground; + protected Color Background; + + protected override void Initalize(ControllerData data, UI_ImageCache cache, string themePath, JObject themeData) + { + base.Initalize(data, cache, themePath, themeData); + this.data = data; + + Background = Color.White; + Foreground = Color.Black ; + + AxisName = themeData["axisName"]?.Value(); + Direction = themeData["direction"]?.Value(); + + Min = themeData["min"]?.Value() ?? 0; + Max = themeData["max"]?.Value() ?? 0; + Width = themeData["width"]?.Value() ?? 0; + Height = themeData["height"]?.Value() ?? 0; + + string ForegroundCode = themeData["foreground"]?.Value(); + string BackgroundCode = themeData["background"]?.Value(); + + try + { + Foreground = Color.FromArgb(int.Parse(ForegroundCode, System.Globalization.NumberStyles.HexNumber)); + } + catch { } + try + { + Background = Color.FromArgb(int.Parse(BackgroundCode, System.Globalization.NumberStyles.HexNumber)); + } + catch { } + } + + public override void Paint(Graphics graphics) + { + Matrix preserve = graphics.Transform; + + float Analog = string.IsNullOrWhiteSpace(AxisName) ? 0 : (data.GetAnalogControl(AxisName)); + Analog = Math.Max(Math.Min((Analog - Min) / (Max - Min), 1.0f), 0.0f); + + graphics.TranslateTransform(X, Y); + graphics.TranslateTransform(-Width / 2, -Height / 2); + + switch (Direction) + { + case "up": + graphics.FillRectangle(new SolidBrush(Background), 0, Height - (Height * Analog), Width, Height * Analog); + break; + case "down": + graphics.FillRectangle(new SolidBrush(Background), 0, 0, Width, Height * Analog); + break; + case "left": + graphics.FillRectangle(new SolidBrush(Background), Width - (Width * Analog), 0, Width * Analog, Height); + break; + default: + graphics.FillRectangle(new SolidBrush(Background), 0, 0, Width * Analog, Height); + break; + } + + graphics.DrawRectangle(new Pen(Foreground, 2), 0, 0, Width, Height); + + graphics.Transform = preserve; + + base.Paint(graphics); + } + } + + public class UL_Basic3D1 : UI_Item + { + public UL_Basic3D1(ControllerData data, UI_ImageCache cache, string themePath, JObject themeData) : base(data, cache, themePath, themeData) + { + } + + private ControllerData data; + private UI_ImageCache cache; + protected string DisplayType; + protected Image DisplayImage; + protected Image ShadowL; + protected Image ShadowR; + protected Image ShadowU; + protected Image ShadowD; + protected float Width; + protected float Height; + + float TiltTranslateX; + float TiltTranslateY; + + string ShadowLName; + string ShadowRName; + string ShadowUName; + string ShadowDName; + + protected override void Initalize(ControllerData data, UI_ImageCache cache, string themePath, JObject themeData) + { + base.Initalize(data, cache, themePath, themeData); + this.data = data; + this.cache = cache; + + DisplayType = themeData["mode"]?.Value(); + string ImageName = themeData["image"]?.Value(); + ShadowLName = themeData["shadowl"]?.Value(); + ShadowRName = themeData["shadowr"]?.Value(); + ShadowUName = themeData["shadowu"]?.Value(); + ShadowDName = themeData["shadowd"]?.Value(); + + if (!string.IsNullOrWhiteSpace(ImageName)) + DisplayImage = cache.LoadImage(ImageName); + + if (!string.IsNullOrWhiteSpace(ShadowLName)) + ShadowL = cache.LoadImage(ShadowLName); + + if (!string.IsNullOrWhiteSpace(ShadowRName)) + ShadowR = cache.LoadImage(ShadowRName); + + if (!string.IsNullOrWhiteSpace(ShadowUName)) + ShadowU = cache.LoadImage(ShadowUName); + + if (!string.IsNullOrWhiteSpace(ShadowDName)) + ShadowD = cache.LoadImage(ShadowDName); + + Width = themeData["width"]?.Value() ?? 0; + Height = themeData["height"]?.Value() ?? 0; + + TiltTranslateX = themeData["tilttranslatex"]?.Value() ?? 0; + TiltTranslateY = themeData["tilttranslatey"]?.Value() ?? 0; + } + + public override void Paint(Graphics graphics) + { + Matrix preserve = graphics.Transform; + + graphics.TranslateTransform(X, Y); + //graphics.TranslateTransform(-Width / 2, -Height / 2); + + switch (DisplayType) + { + case "accel": + { + SteamController.SteamControllerState State = data.GetState(); + + if (State != null) + { + float TiltFactorX = State.AngularVelocityX * 0.0001f; + float TiltFactorY = State.AngularVelocityY * 0.0001f; + float rotationAngle = (State.AngularVelocityZ * 0.0001f) * -90; + float transformX = 1.0f - Math.Abs(TiltFactorY * 0.5f); + float transformY = 1.0f - Math.Abs(TiltFactorX * 0.5f); + + Draw3dAs3d(cache, graphics, DisplayImage, ShadowLName, ShadowL, ShadowRName, ShadowR, ShadowUName, ShadowU, ShadowDName, ShadowD, transformX, transformY, rotationAngle, TiltFactorX, TiltFactorY, Width, Height, TiltTranslateX, TiltTranslateY); + + graphics.ResetTransform(); + } + } + break; + case "gyro": + { + SteamController.SteamControllerState State = data.GetState(); + + if (State != null) + { + double qw = (State.OrientationW * 1.0f / 32736); + double qx = (State.OrientationX * 1.0f / 32736); + double qy = (State.OrientationY * 1.0f / 32736); + double qz = (State.OrientationZ * 1.0f / 32736); + + double pitch; + double roll; + double yaw; + + ToEulerAngles(qw, qy, qz, qx, out pitch, out roll, out yaw); + + { + double Yaw = (yaw * 2.0f / Math.PI); + double Roll = -(roll * 2.0f / Math.PI); + double Pitch = (pitch * 2.0f / Math.PI); + + if (double.IsNaN(Yaw)) Yaw = 0; + if (double.IsNaN(Roll)) Roll = 0; + if (double.IsNaN(Pitch)) Pitch = 0; + + int SignY = -Math.Sign((2 * mod(Math.Floor((Roll - 1) * 0.5f) + 1, 2)) - 1); + float TiltFactorX = (float)((2 * Math.Abs(mod((Pitch - 1) * 0.5f, 2) - 1)) - 1); + float TiltFactorY = (float)((2 * Math.Abs(mod((Roll - 1) * 0.5f, 2) - 1)) - 1); + float rotationAngle = (float)(Yaw * -90.0f); + float transformX = SignY * Math.Max(1.0f - Math.Abs(TiltFactorY), 0.15f); + float transformY = Math.Max(1.0f - Math.Abs(TiltFactorX), 0.15f); + + //Console.WriteLine($"{TiltFactorY}\t{Roll}\t{(2 * mod(Math.Floor((Roll - 1) * 0.5f) + 1, 2)) - 1}"); + + Draw3dAs3d(cache, graphics, DisplayImage, ShadowLName, ShadowL, ShadowRName, ShadowR, ShadowUName, ShadowU, ShadowDName, ShadowD, transformX, transformY, rotationAngle, TiltFactorX, TiltFactorY, Width, Height, TiltTranslateX, TiltTranslateY); + + graphics.ResetTransform(); + } + } + } + break; + default: + break; + } + + graphics.Transform = preserve; + + base.Paint(graphics); + } + + public static void ToEulerAngles(double QuaternionW, double QuaternionX, double QuaternionY, double QuaternionZ, out double Pitch, out double Roll, out double Yaw) + { + // Store the Euler angles in radians + //Vector3 pitchYawRoll = new Vector3(); + + double sqw = QuaternionW * QuaternionW; + double sqx = QuaternionX * QuaternionX; + double sqy = QuaternionY * QuaternionY; + double sqz = QuaternionZ * QuaternionZ; + + // If quaternion is normalised the unit is one, otherwise it is the correction factor + double unit = sqx + sqy + sqz + sqw; + double test = QuaternionX * QuaternionY + QuaternionZ * QuaternionW; + + if (test > 0.4999f * unit) // 0.4999f OR 0.5f - EPSILON + { + // Singularity at north pole + Yaw = 2f * Math.Atan2(QuaternionX, QuaternionW); // Yaw + Pitch = Math.PI * 0.5f; // Pitch + Roll = 0f; // Roll + return; + } + else if (test < -0.4999f * unit) // -0.4999f OR -0.5f + EPSILON + { + // Singularity at south pole + Yaw = -2f * Math.Atan2(QuaternionX, QuaternionW); // Yaw + Pitch = -Math.PI * 0.5f; // Pitch + Roll = 0f; // Roll + return; + } + else + { + Yaw = Math.Atan2(2f * QuaternionY * QuaternionW - 2f * QuaternionX * QuaternionZ, sqx - sqy - sqz + sqw); // Yaw + Pitch = Math.Asin(2f * test / unit); // Pitch + Roll = Math.Atan2(2f * QuaternionX * QuaternionW - 2f * QuaternionY * QuaternionZ, -sqx + sqy - sqz + sqw); // Roll + } + } + + double mod(double x, double m) + { + return (x % m + m) % m; + } + + private void Draw3dAs3d( + UI_ImageCache cache, Graphics g, + Image image, string ImageGyroLName, Image ImageGyroL, string ImageGyroRName, Image ImageGyroR, string ImageGyroUName, Image ImageGyroU, string ImageGyroDName, Image ImageGyroD, + float transformX, float transformY, + float rotationAngle, + float TiltFactorX, float TiltFactorY, + float Width, float Height, + float TiltTranslateX, float TiltTranslateY) + { + // fix flip + if (TiltFactorX < -1) TiltFactorX = 2.0f + TiltFactorX; + if (TiltFactorX > 1) TiltFactorX = 2.0f - TiltFactorX; + if (TiltFactorY < -1) TiltFactorY = 2.0f + TiltFactorY; + if (TiltFactorY > 1) TiltFactorY = 2.0f - TiltFactorY; + + PointF location = new PointF((TiltFactorY * -TiltTranslateX) - (Width / 2), (TiltFactorX * TiltTranslateY) - (Height / 2)); + + g.RotateTransform(rotationAngle); + g.ScaleTransform(transformX, transformY); + + g.DrawImage(image, location.X, location.Y, Width, Height); + + if (Math.Abs(TiltFactorX) > 0) + { + if (Math.Sign(TiltFactorX) > 0) { + float percent = TiltFactorX * 2;// * 0.15f; + g.DrawImage(cache.GetImage($"{ImageGyroDName}:{percent}", () => { return UI_ImageCache.SetImageOpacity(ImageGyroD, percent); }), location.X, location.Y, Width, Height); + } + if (Math.Sign(TiltFactorX) < 0) { + float percent = -TiltFactorX * 2;// * 0.15f; + g.DrawImage(cache.GetImage($"{ImageGyroUName}:{percent}", () => { return UI_ImageCache.SetImageOpacity(ImageGyroU, percent); }), location.X, location.Y, Width, Height); + } + } + + if (Math.Abs(TiltFactorY) > 0) + { + if (Math.Sign(TiltFactorY) > 0) { + float percent = TiltFactorY * 2;// * 0.15f; + g.DrawImage(cache.GetImage($"{ImageGyroLName}:{percent}", () => { return UI_ImageCache.SetImageOpacity(ImageGyroL, percent); }), location.X, location.Y, Width, Height); + } + if (Math.Sign(TiltFactorY) < 0) { + float percent = -TiltFactorY * 2;// * 0.15f; + g.DrawImage(cache.GetImage($"{ImageGyroRName}:{percent}", () => { return UI_ImageCache.SetImageOpacity(ImageGyroR, percent); }), location.X, location.Y, Width, Height); + } + } + } + + } +} diff --git a/VSCView/ProcForm.Designer.cs b/VSCView/ProcForm.Designer.cs new file mode 100644 index 0000000..c5c4879 --- /dev/null +++ b/VSCView/ProcForm.Designer.cs @@ -0,0 +1,124 @@ +namespace VSCView +{ + partial class ProcForm + { + /// + /// 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.txtTemp1 = new System.Windows.Forms.TextBox(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.txtTemp2 = new System.Windows.Forms.TextBox(); + this.txtTemp3 = new System.Windows.Forms.TextBox(); + this.txtTemp4 = new System.Windows.Forms.TextBox(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // txtTemp1 + // + this.txtTemp1.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtTemp1.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtTemp1.Location = new System.Drawing.Point(3, 3); + this.txtTemp1.Multiline = true; + this.txtTemp1.Name = "txtTemp1"; + this.txtTemp1.ReadOnly = true; + this.txtTemp1.Size = new System.Drawing.Size(229, 647); + this.txtTemp1.TabIndex = 0; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 4; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel1.Controls.Add(this.txtTemp4, 3, 0); + this.tableLayoutPanel1.Controls.Add(this.txtTemp3, 2, 0); + this.tableLayoutPanel1.Controls.Add(this.txtTemp2, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.txtTemp1, 0, 0); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 1; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.Size = new System.Drawing.Size(940, 637); + this.tableLayoutPanel1.TabIndex = 1; + // + // txtTemp2 + // + this.txtTemp2.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtTemp2.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtTemp2.Location = new System.Drawing.Point(238, 3); + this.txtTemp2.Multiline = true; + this.txtTemp2.Name = "txtTemp2"; + this.txtTemp2.ReadOnly = true; + this.txtTemp2.Size = new System.Drawing.Size(229, 647); + this.txtTemp2.TabIndex = 1; + // + // txtTemp3 + // + this.txtTemp3.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtTemp3.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtTemp3.Location = new System.Drawing.Point(473, 3); + this.txtTemp3.Multiline = true; + this.txtTemp3.Name = "txtTemp3"; + this.txtTemp3.ReadOnly = true; + this.txtTemp3.Size = new System.Drawing.Size(229, 647); + this.txtTemp3.TabIndex = 2; + // + // txtTemp4 + // + this.txtTemp4.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtTemp4.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtTemp4.Location = new System.Drawing.Point(708, 3); + this.txtTemp4.Multiline = true; + this.txtTemp4.Name = "txtTemp4"; + this.txtTemp4.ReadOnly = true; + this.txtTemp4.Size = new System.Drawing.Size(229, 647); + this.txtTemp4.TabIndex = 3; + // + // MainForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(940, 637); + this.Controls.Add(this.tableLayoutPanel1); + this.Name = "MainForm"; + this.Text = "MainForm"; + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TextBox txtTemp1; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.TextBox txtTemp4; + private System.Windows.Forms.TextBox txtTemp3; + private System.Windows.Forms.TextBox txtTemp2; + } +} \ No newline at end of file diff --git a/VSCView/ProcForm.cs b/VSCView/ProcForm.cs new file mode 100644 index 0000000..c42bd56 --- /dev/null +++ b/VSCView/ProcForm.cs @@ -0,0 +1,109 @@ +using HidLibrary; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace VSCView +{ + public partial class ProcForm : Form + { + SteamController[] Controllers; + TextBox[] txtTemp; + + public ProcForm() + { + InitializeComponent(); + + SetDoubleBuffered(txtTemp1); + SetDoubleBuffered(txtTemp2); + SetDoubleBuffered(txtTemp3); + SetDoubleBuffered(txtTemp4); + txtTemp = new TextBox[] { txtTemp1, txtTemp2, txtTemp3, txtTemp4 }; ; + + Controllers = SteamController.GetControllers(); + + //Controllers[0].StateUpdated += MainForm_StateUpdated; + if (Controllers.Length > 0) Controllers[0].StateUpdated += (object sender, SteamController.SteamControllerState e) => MainForm_StateUpdated(sender, e, 0); + if (Controllers.Length > 1) Controllers[1].StateUpdated += (object sender, SteamController.SteamControllerState e) => MainForm_StateUpdated(sender, e, 1); + if (Controllers.Length > 2) Controllers[2].StateUpdated += (object sender, SteamController.SteamControllerState e) => MainForm_StateUpdated(sender, e, 2); + if (Controllers.Length > 3) Controllers[3].StateUpdated += (object sender, SteamController.SteamControllerState e) => MainForm_StateUpdated(sender, e, 3); + } + + public static void SetDoubleBuffered(System.Windows.Forms.Control c) + { + //Taxes: Remote Desktop Connection and painting + //http://blogs.msdn.com/oldnewthing/archive/2006/01/03/508694.aspx + if (System.Windows.Forms.SystemInformation.TerminalServerSession) + return; + + System.Reflection.PropertyInfo aProp = + typeof(System.Windows.Forms.Control).GetProperty( + "DoubleBuffered", + System.Reflection.BindingFlags.NonPublic | + System.Reflection.BindingFlags.Instance); + + aProp.SetValue(c, true, null); + } + + private void MainForm_StateUpdated(object sender, SteamController.SteamControllerState e, int index) + { + txtTemp1.Invoke((MethodInvoker)delegate + { + // Running on the UI thread + txtTemp[index].Text = + $"Buttons.A = {e.Buttons.A}\r\n" + + $"Buttons.B = {e.Buttons.B}\r\n" + + $"Buttons.X = {e.Buttons.X}\r\n" + + $"Buttons.Y = {e.Buttons.Y}\r\n" + + "\r\n" + + $"Buttons.LeftBumper = {e.Buttons.LeftBumper}\r\n" + + $"Buttons.LeftTrigger = {e.Buttons.LeftTrigger}\r\n" + + $"Buttons.LeftGrip = {e.Buttons.LeftGrip}\r\n" + + "\r\n" + + $"Buttons.RightBumper = {e.Buttons.RightBumper}\r\n" + + $"Buttons.RightTrigger = {e.Buttons.RightTrigger}\r\n" + + $"Buttons.RightGrip = {e.Buttons.RightGrip}\r\n" + + "\r\n" + + $"Buttons.CenterRight = {e.Buttons.Start}\r\n" + + $"Buttons.Center = {e.Buttons.Steam}\r\n" + + $"Buttons.CenterLeft = {e.Buttons.Select}\r\n" + + "\r\n" + + $"Buttons.Up = {e.Buttons.Up}\r\n" + + $"Buttons.Down = {e.Buttons.Down}\r\n" + + $"Buttons.Left = {e.Buttons.Left}\r\n" + + $"Buttons.Right = {e.Buttons.Right}\r\n" + + "\r\n" + + $"Buttons.ThumbStick = {e.Buttons.StickClick}\r\n" + + $"Buttons.LeftPadTouch = {e.Buttons.LeftPadTouch}\r\n" + + $"Buttons.LeftPadPress = {e.Buttons.LeftPadClick}\r\n" + + $"Buttons.RightPadTouch = {e.Buttons.RightPadTouch}\r\n" + + $"Buttons.RightPadPress = {e.Buttons.RightPadClick}\r\n" + + "\r\n" + + $"LeftTrigger = {e.LeftTrigger}\r\n" + + $"RightTrigger = {e.RightTrigger}\r\n" + + "\r\n" + + $"LeftStickX = {e.LeftStickX}\r\n" + + $"LeftStickY = {e.LeftStickY}\r\n" + + $"LeftPadX = {e.LeftPadX}\r\n" + + $"LeftPadY = {e.LeftPadY}\r\n" + + $"RightPadX = {e.RightPadX}\r\n" + + $"RightPadY = {e.RightPadY}\r\n" + + "\r\n" + + $"AngularVelocityX = {e.AngularVelocityX}\r\n" + + $"AngularVelocityY = {e.AngularVelocityY}\r\n" + + $"AngularVelocityZ = {e.AngularVelocityZ}\r\n" + + $"OrientationW = {e.OrientationW}\r\n" + + $"OrientationX = {e.OrientationX}\r\n" + + $"OrientationY = {e.OrientationY}\r\n" + + $"OrientationZ = {e.OrientationZ}\r\n"; + }); + } + } +} diff --git a/VSCView/ProcForm.resx b/VSCView/ProcForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/VSCView/ProcForm.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/VSCView/Program.cs b/VSCView/Program.cs new file mode 100644 index 0000000..fc81073 --- /dev/null +++ b/VSCView/Program.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace VSCView +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main(string[] args) + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + if (args.Length == 0 || args[0] == @"-1") + { + Application.Run(new MainForm()); + } + else if (args[0] == @"-2") + { + Application.Run(new ProcForm()); + } + else if (args[0] == @"-3") + { + Application.Run(new RawForm()); + } + else + { + Application.Run(new MainForm()); + } + } + } +} diff --git a/VSCView/Properties/AssemblyInfo.cs b/VSCView/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9091b58 --- /dev/null +++ b/VSCView/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("VSCView")] +[assembly: AssemblyDescription("This application allows the viewing of raw Steam Controller input for use in on screen displays for videos and streams.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Nielk1")] +[assembly: AssemblyProduct("VSCView")] +[assembly: AssemblyCopyright("John Klein © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("e513702d-ef79-4766-ad9d-c2382bd0cead")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// 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("0.2.0.3")] +[assembly: AssemblyFileVersion("0.2.0.3")] diff --git a/VSCView/Properties/Resources.Designer.cs b/VSCView/Properties/Resources.Designer.cs new file mode 100644 index 0000000..0531561 --- /dev/null +++ b/VSCView/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace VSCView.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("VSCView.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Nielk1_eyes_128 { + get { + object obj = ResourceManager.GetObject("Nielk1_eyes_128", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/VSCView/Properties/Resources.resx b/VSCView/Properties/Resources.resx new file mode 100644 index 0000000..ee6e547 --- /dev/null +++ b/VSCView/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + ..\Resources\Nielk1_eyes_128.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/VSCView/Properties/Settings.Designer.cs b/VSCView/Properties/Settings.Designer.cs new file mode 100644 index 0000000..6531372 --- /dev/null +++ b/VSCView/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace VSCView.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/VSCView/Properties/Settings.settings b/VSCView/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/VSCView/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/VSCView/RawForm.Designer.cs b/VSCView/RawForm.Designer.cs new file mode 100644 index 0000000..b43c0dd --- /dev/null +++ b/VSCView/RawForm.Designer.cs @@ -0,0 +1,128 @@ +namespace VSCView +{ + partial class RawForm + { + /// + /// 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() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(RawForm)); + this.txtUpdate = new System.Windows.Forms.TextBox(); + this.txtDevicePath = new System.Windows.Forms.TextBox(); + this.txtDescription = new System.Windows.Forms.TextBox(); + this.txtBattery = new System.Windows.Forms.TextBox(); + this.txtConnection = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // txtUpdate + // + this.txtUpdate.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtUpdate.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtUpdate.Location = new System.Drawing.Point(12, 60); + this.txtUpdate.Multiline = true; + this.txtUpdate.Name = "txtUpdate"; + this.txtUpdate.ReadOnly = true; + this.txtUpdate.Size = new System.Drawing.Size(738, 840); + this.txtUpdate.TabIndex = 0; + this.txtUpdate.Text = resources.GetString("txtUpdate.Text"); + // + // txtDevicePath + // + this.txtDevicePath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtDevicePath.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtDevicePath.Location = new System.Drawing.Point(12, 8); + this.txtDevicePath.Name = "txtDevicePath"; + this.txtDevicePath.ReadOnly = true; + this.txtDevicePath.Size = new System.Drawing.Size(738, 20); + this.txtDevicePath.TabIndex = 1; + // + // txtDescription + // + this.txtDescription.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtDescription.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtDescription.Location = new System.Drawing.Point(12, 34); + this.txtDescription.Name = "txtDescription"; + this.txtDescription.ReadOnly = true; + this.txtDescription.Size = new System.Drawing.Size(738, 20); + this.txtDescription.TabIndex = 2; + // + // txtBattery + // + this.txtBattery.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtBattery.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtBattery.Location = new System.Drawing.Point(12, 1024); + this.txtBattery.Multiline = true; + this.txtBattery.Name = "txtBattery"; + this.txtBattery.ReadOnly = true; + this.txtBattery.Size = new System.Drawing.Size(738, 166); + this.txtBattery.TabIndex = 3; + this.txtBattery.Text = "00\r\n00\r\n00\r\n00\r\n00\r\n00\r\n00\r\n00\r\n00\r\n00\r\n00\r\n00"; + // + // txtConnection + // + this.txtConnection.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtConnection.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtConnection.Location = new System.Drawing.Point(12, 906); + this.txtConnection.Multiline = true; + this.txtConnection.Name = "txtConnection"; + this.txtConnection.ReadOnly = true; + this.txtConnection.Size = new System.Drawing.Size(738, 112); + this.txtConnection.TabIndex = 4; + this.txtConnection.Text = "00\r\n00\r\n00\r\n00\r\n00\r\n00\r\n00\r\n00"; + // + // RawForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoScroll = true; + this.ClientSize = new System.Drawing.Size(811, 298); + this.Controls.Add(this.txtConnection); + this.Controls.Add(this.txtBattery); + this.Controls.Add(this.txtDescription); + this.Controls.Add(this.txtDevicePath); + this.Controls.Add(this.txtUpdate); + this.Name = "RawForm"; + this.Text = "Form1"; + this.Load += new System.EventHandler(this.Form1_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox txtUpdate; + private System.Windows.Forms.TextBox txtDevicePath; + private System.Windows.Forms.TextBox txtDescription; + private System.Windows.Forms.TextBox txtBattery; + private System.Windows.Forms.TextBox txtConnection; + } +} + diff --git a/VSCView/RawForm.cs b/VSCView/RawForm.cs new file mode 100644 index 0000000..d018b3c --- /dev/null +++ b/VSCView/RawForm.cs @@ -0,0 +1,405 @@ +using HidLibrary; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace VSCView +{ + public partial class RawForm : Form + { + private const int VendorId = 10462; + private static int ProductIdWireless = 4418; + private static int ProductIdWired = 1102; + private static bool _attached; + + //private Int16 MaxVal = 0; + + public RawForm() + { + InitializeComponent(); + SetDoubleBuffered(txtUpdate); + } + + public static void SetDoubleBuffered(System.Windows.Forms.Control c) + { + //Taxes: Remote Desktop Connection and painting + //http://blogs.msdn.com/oldnewthing/archive/2006/01/03/508694.aspx + if (System.Windows.Forms.SystemInformation.TerminalServerSession) + return; + + System.Reflection.PropertyInfo aProp = + typeof(System.Windows.Forms.Control).GetProperty( + "DoubleBuffered", + System.Reflection.BindingFlags.NonPublic | + System.Reflection.BindingFlags.Instance); + + aProp.SetValue(c, true, null); + } + + private void Form1_Load(object sender, EventArgs e) + { + GetHidDevice(); + } + + private void GetHidDevice() + { + List _devices = HidDevices.Enumerate(VendorId, ProductIdWireless, ProductIdWired).ToList(); + + foreach(HidDevice _device in _devices) + { + if (_device != null) + { + // found + + // \\?\hid#vid_28de&pid_1142&mi_00&col01#8&d70e632&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} HID Keyboard Device + // \\?\hid#vid_28de&pid_1142&mi_00&col02#8&d70e632&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030} HID-compliant mouse + // \\?\hid#vid_28de&pid_1142&mi_01#8&314823f4&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} HID-compliant device + // \\?\hid#vid_28de&pid_1142&mi_02#8&198497af&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} HID-compliant device + // \\?\hid#vid_28de&pid_1142&mi_03#8&1c10b6a&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} HID-compliant device + // \\?\hid#vid_28de&pid_1142&mi_04#8&279758bf&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} HID-compliant device + + int index = -1; + Match m = Regex.Match(_device.DevicePath, "&mi_([0-9]{2})"); + if (!m.Success) continue; + index = int.Parse(m.Groups[1].Value) - 1; + if (index < 0) continue; + + _device.OpenDevice(); + //_device.OpenDevice(DeviceMode.NonOverlapped, DeviceMode.NonOverlapped, ShareMode.ShareRead); + + Console.WriteLine(_device.DevicePath + "\t" + _device.Description); + + byte[] featureData; + _device.ReadFeatureData(out featureData); + byte[] manufacturer; + _device.ReadManufacturer(out manufacturer); + byte[] productData; + _device.ReadProduct(out productData); + byte[] serialNumber; + _device.ReadSerialNumber(out serialNumber); + + _device.Inserted += () => DeviceAttachedHandler(_device); + _device.Removed += () => DeviceRemovedHandler(_device); + + _device.MonitorDeviceEvents = true; + + _device.ReadReport((_data) => OnReport(_device, _data)); + //_device.Read((_data) => OnRead(_device, _data)); + } + else + { + // not found + } + } + } + + /*private static void OnRead(HidDevice _device, HidDeviceData data) + { + if (_attached == false) { return; } + + //if (data.Data.Length >= 4) + { + var message = MessageFactory.CreateMessage(ProductId, data.Data); + } + + _device.Read((_data) => OnRead(_device, _data)); + }*/ + + private void OnReport(HidDevice _device, HidReport report) + { + if (_attached == false) { return; } + + //if (report.Data.Length == 64) + { + txtDevicePath.Invoke((MethodInvoker)delegate + { + // Running on the UI thread + txtDevicePath.Text = _device.DevicePath; + }); + + txtDescription.Invoke((MethodInvoker)delegate + { + // Running on the UI thread + txtDescription.Text = _device.Description; + }); + + byte EventType = report.Data[2]; + + string[] NiceOutputText = BitConverter.ToString(report.Data).Split('-'); + + switch (EventType) + { + case 0x00: + { + + } + //_device.ReadReport((data) => OnReport(_device, data)); + break; + + case 0x01: + { + NiceOutputText[0] += " -------- Always 01?"; + NiceOutputText[1] += " -------- Always 00?"; + NiceOutputText[2] += " -------- Event Type"; + NiceOutputText[3] += " -------- 3C?"; + + NiceOutputText[4] += " -------- Packet Index: " + BitConverter.ToUInt32(report.Data, 4); + NiceOutputText[5] += " ^^^^^^^^"; + NiceOutputText[6] += " ^^^^^^^^"; + NiceOutputText[7] += " ^^^^^^^^"; + + NiceOutputText[8] += " " + Convert.ToString(report.Data[8], 2).PadLeft(8, '0'); + NiceOutputText[8] += (report.Data[8] & 128) == 128 ? " ↓A↓" : " ↑A↑"; + NiceOutputText[8] += (report.Data[8] & 64) == 64 ? " ↓X↓" : " ↑X↑"; + NiceOutputText[8] += (report.Data[8] & 32) == 32 ? " ↓B↓" : " ↑B↑"; + NiceOutputText[8] += (report.Data[8] & 16) == 16 ? " ↓Y↓" : " ↑Y↑"; + NiceOutputText[8] += (report.Data[8] & 8) == 8 ? " ↓LB↓" : " ↑LB↑"; + NiceOutputText[8] += (report.Data[8] & 4) == 4 ? " ↓RB↓" : " ↑RB↑"; + NiceOutputText[8] += (report.Data[8] & 2) == 2 ? " ↓LT↓" : " ↑LT↑"; + NiceOutputText[8] += (report.Data[8] & 1) == 1 ? " ↓RT↓" : " ↑RT↑"; + + NiceOutputText[9] += " " + Convert.ToString(report.Data[9], 2).PadLeft(8, '0'); + NiceOutputText[9] += (report.Data[9] & 128) == 128 ? " ↓L-Grip↓" : " ↑L-Grip↑"; + NiceOutputText[9] += (report.Data[9] & 64) == 64 ? " ↓SteamR↓" : " ↑SteamR↑"; + NiceOutputText[9] += (report.Data[9] & 32) == 32 ? " ↓Steam↓" : " ↑Steam↑"; + NiceOutputText[9] += (report.Data[9] & 16) == 16 ? " ↓SteamL↓" : " ↑SteamL↑"; + NiceOutputText[9] += (report.Data[9] & 8) == 8 ? " ↓Down↓" : " ↑Down↑"; + NiceOutputText[9] += (report.Data[9] & 4) == 4 ? " ↓Left↓" : " ↑Left↑"; + NiceOutputText[9] += (report.Data[9] & 2) == 2 ? " ↓Right↓" : " ↑Right↑"; + NiceOutputText[9] += (report.Data[9] & 1) == 1 ? " ↓Up↓" : " ↑Up↑"; + + bool LeftAnalogMultiplexMode = (report.Data[10] & 128) == 128; + bool LeftPadTouch = (report.Data[10] & 8) == 8; + + NiceOutputText[10] += " " + Convert.ToString(report.Data[10], 2).PadLeft(8, '0'); + NiceOutputText[10] += LeftAnalogMultiplexMode ? " !MULTIPLEX!" : " "; + NiceOutputText[10] += (report.Data[10] & 64) == 64 ? " ↓ThumbStick↓" : " ↑ThumbStick↑"; + NiceOutputText[10] += (report.Data[10] & 32) == 32 ? " ↓-↓" : " ↑-↑"; + NiceOutputText[10] += (report.Data[10] & 16) == 16 ? " ↓R-Pad Touch↓" : " ↑R-Pad Touch↑"; + NiceOutputText[10] += LeftPadTouch ? " ↓L-Pad Touch↓" : " ↑L-Pad Touch↑"; + NiceOutputText[10] += (report.Data[10] & 4) == 4 ? " ↓R-Pad Press↓" : " ↑R-Pad Press↑"; + NiceOutputText[10] += (report.Data[10] & 2) == 2 ? " ↓?ThumbStick OR L-Pad Press?↓" : " ↑?ThumbStick OR L-Pad Press?↑"; + NiceOutputText[10] += (report.Data[10] & 1) == 1 ? " ↓R-Grip↓" : " ↑R-Grip↑"; + + NiceOutputText[11] += " -------- LT: " + report.Data[11].ToString().PadLeft(3); + NiceOutputText[12] += " -------- RT: " + report.Data[12].ToString().PadLeft(3); + + string LeftPadX = " "; + string LeftPadY = " "; + string LeftStickX = string.Empty; + string LeftStickY = string.Empty; + + if (LeftAnalogMultiplexMode) + { + if (LeftPadTouch) + { + LeftPadX = BitConverter.ToInt16(report.Data, 16).ToString().PadLeft(6); + LeftPadY = BitConverter.ToInt16(report.Data, 18).ToString().PadLeft(6); + } + else + { + LeftStickX = BitConverter.ToInt16(report.Data, 16).ToString().PadLeft(6); + LeftStickY = BitConverter.ToInt16(report.Data, 18).ToString().PadLeft(6); + } + } + else if (LeftPadTouch) + { + LeftPadX = BitConverter.ToInt16(report.Data, 16).ToString().PadLeft(6); + LeftPadY = BitConverter.ToInt16(report.Data, 18).ToString().PadLeft(6); + } + else + { + LeftStickX = BitConverter.ToInt16(report.Data, 16).ToString().PadLeft(6); + LeftStickY = BitConverter.ToInt16(report.Data, 18).ToString().PadLeft(6); + } + + NiceOutputText[16] += " -------- Left Pad X: " + LeftPadX + " ThumbStick X: " + LeftStickX; + NiceOutputText[17] += " ^^^^^^^^"; + NiceOutputText[18] += " -------- Left Pad Y: " + LeftPadY + " ThumbStick Y: " + LeftStickY; + NiceOutputText[19] += " ^^^^^^^^"; + + NiceOutputText[20] += " -------- Right Pad X: " + BitConverter.ToInt16(report.Data, 20); + NiceOutputText[21] += " ^^^^^^^^"; + NiceOutputText[22] += " -------- Right Pad Y: " + BitConverter.ToInt16(report.Data, 22); + NiceOutputText[23] += " ^^^^^^^^"; + + //NiceOutputText[28] += " -------- Acceleration X: " + BitConverter.ToInt16(report.Data, 28); + //NiceOutputText[29] += " ^^^^^^^^"; + //NiceOutputText[30] += " -------- Acceleration Y: " + BitConverter.ToInt16(report.Data, 30); + //NiceOutputText[31] += " ^^^^^^^^"; + //NiceOutputText[32] += " -------- Acceleration Z: " + BitConverter.ToInt16(report.Data, 32); + //NiceOutputText[33] += " ^^^^^^^^"; + NiceOutputText[34] += " -------- AngularVelocity X: " + BitConverter.ToInt16(report.Data, 34); + NiceOutputText[35] += " ^^^^^^^^"; + NiceOutputText[36] += " -------- AngularVelocity Y: " + BitConverter.ToInt16(report.Data, 36); + NiceOutputText[37] += " ^^^^^^^^"; + NiceOutputText[38] += " -------- AngularVelocity Z: " + BitConverter.ToInt16(report.Data, 38); + NiceOutputText[39] += " ^^^^^^^^"; + + float qw = (BitConverter.ToInt16(report.Data, 40) * 1.0f / 32736); + float qx = (BitConverter.ToInt16(report.Data, 42) * 1.0f / 32736); + float qy = (BitConverter.ToInt16(report.Data, 44) * 1.0f / 32736); + float qz = (BitConverter.ToInt16(report.Data, 46) * 1.0f / 32736); + + double roll; + double pitch; + double yaw; + + // roll (x-axis rotation) + double sinr = +2.0 * (qw * qx + qy * qz); + double cosr = +1.0 - 2.0 * (qx * qx + qy * qy); + roll = Math.Atan2(sinr, cosr); + + // pitch (y-axis rotation) + double sinp = +2.0 * (qw * qy - qz * qx); + if (Math.Abs(sinp) >= 1) + pitch = Math.Abs(Math.PI / 2) * Math.Sign(sinp); // use 90 degrees if out of range + else + pitch = Math.Asin(sinp); + + // yaw (z-axis rotation) + double siny = +2.0 * (qw * qz + qx * qy); + double cosy = +1.0 - 2.0 * (qy * qy + qz * qz); + yaw = Math.Atan2(siny, cosy); + + Console.WriteLine($"{(roll / 2 / Math.PI).ToString("0.###")},{(pitch / 2 / Math.PI).ToString("0.###")},{(yaw / 2 / Math.PI).ToString("0.###")}"); + + NiceOutputText[40] += " -------- Orientation W: " + BitConverter.ToInt16(report.Data, 40) + " " + (BitConverter.ToInt16(report.Data, 40) * 1.0f / 32736).ToString("0.###"); + NiceOutputText[41] += " ^^^^^^^^"; + NiceOutputText[42] += " -------- Orientation X: " + BitConverter.ToInt16(report.Data, 42) + " " + (BitConverter.ToInt16(report.Data, 42) * 1.0f / 32736).ToString("0.###"); + NiceOutputText[43] += " ^^^^^^^^"; + NiceOutputText[44] += " -------- Orientation Y: " + BitConverter.ToInt16(report.Data, 44) + " " + (BitConverter.ToInt16(report.Data, 44) * 1.0f / 32736).ToString("0.###"); + NiceOutputText[45] += " ^^^^^^^^"; + NiceOutputText[46] += " -------- Orientation Z: " + BitConverter.ToInt16(report.Data, 46) + " " + (BitConverter.ToInt16(report.Data, 46) * 1.0f / 32736).ToString("0.###"); + NiceOutputText[47] += " ^^^^^^^^"; + + /*MaxVal = Math.Max( + Math.Max( + Math.Abs(BitConverter.ToInt16(report.Data, 40)), + Math.Max( + Math.Abs(BitConverter.ToInt16(report.Data, 42)), + Math.Max( + Math.Abs(BitConverter.ToInt16(report.Data, 44)), + Math.Abs(BitConverter.ToInt16(report.Data, 46)) + ) + ) + ), MaxVal); + + Console.WriteLine(MaxVal);*/ + + txtUpdate.Invoke((MethodInvoker)delegate + { + // Running on the UI thread + txtUpdate.Text = string.Join("\r\n", NiceOutputText); + }); + } + //_device.ReadReport((data) => OnReport(_device, data)); + _device.ReadReport((data) => OnReport(_device, data)); + break; + + case 0x03: + { + NiceOutputText[0] += " -------- Always 01?"; + NiceOutputText[1] += " -------- Always 00?"; + NiceOutputText[2] += " -------- Event Type"; + NiceOutputText[3] += " -------- 01?"; + + // Connection detail. 0x01 for disconnect, 0x02 for connect, 0x03 for pairing request. + NiceOutputText[4] += " -------- Connection Detail: " + report.Data[4]; + + if (report.Data[4] == 0x01) + { + byte[] tmpBytes = new byte[4]; + tmpBytes[1] = report.Data[5]; + tmpBytes[2] = report.Data[6]; + tmpBytes[3] = report.Data[7]; + + NiceOutputText[5] += " -------- Packet Index: " + BitConverter.ToUInt32(tmpBytes, 0); + NiceOutputText[6] += " ^^^^^^^^"; + NiceOutputText[7] += " ^^^^^^^^"; + } + + // only works if controller is configured to send this data + + // millivolts + NiceOutputText[8] += " -------- Battery Voltage: " + BitConverter.ToUInt16(report.Data, 8); + NiceOutputText[9] += " ^^^^^^^^"; + + NiceOutputText[10] += " -------- Unknown, stuck at 100%: " + BitConverter.ToUInt16(report.Data, 10); + NiceOutputText[11] += " ^^^^^^^^"; + + txtConnection.Invoke((MethodInvoker)delegate + { + // Running on the UI thread + txtConnection.Text = string.Join("\r\n", NiceOutputText); + }); + } + _device.ReadReport((data) => OnReport(_device, data)); + break; + + case 0x04: + { + NiceOutputText[0] += " -------- Always 01?"; + NiceOutputText[1] += " -------- Always 00?"; + NiceOutputText[2] += " -------- Event Type"; + NiceOutputText[3] += " -------- 0B?"; + + NiceOutputText[4] += " -------- Packet Index: " + BitConverter.ToUInt32(report.Data, 4); + NiceOutputText[5] += " ^^^^^^^^"; + NiceOutputText[6] += " ^^^^^^^^"; + NiceOutputText[7] += " ^^^^^^^^"; + + // only works if controller is configured to send this data + + // millivolts + NiceOutputText[8] += " -------- Battery Voltage: " + BitConverter.ToUInt16(report.Data, 8); + NiceOutputText[9] += " ^^^^^^^^"; + + NiceOutputText[10] += " -------- Unknown, stuck at 100%: " + BitConverter.ToUInt16(report.Data, 10); + NiceOutputText[11] += " ^^^^^^^^"; + + txtBattery.Invoke((MethodInvoker)delegate + { + // Running on the UI thread + txtBattery.Text = string.Join("\r\n", NiceOutputText); + }); + } + _device.ReadReport((data) => OnReport(_device, data)); + break; + + default: + { + Console.WriteLine("Unknown Packet Type " + EventType); + } + _device.ReadReport((data) => OnReport(_device, data)); + break; + } + + //var message = MessageFactory.CreateMessage(ProductId, report.Data); + + //_device.ReadReport((data) => OnReport(_device, data)); + } + } + + private void DeviceAttachedHandler(HidDevice _device) + { + _attached = true; + Console.WriteLine("Gamepad attached."); + _device.ReadReport((_data) => OnReport(_device, _data)); + //_device.Read((_data) => OnRead(_device, _data)); + } + + private void DeviceRemovedHandler(HidDevice _device) + { + _attached = false; + Console.WriteLine("Gamepad removed."); + } + } +} diff --git a/VSCView/RawForm.resx b/VSCView/RawForm.resx new file mode 100644 index 0000000..07855bc --- /dev/null +++ b/VSCView/RawForm.resx @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + 00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 + + \ No newline at end of file diff --git a/VSCView/Resources/Nielk1_eyes_128.png b/VSCView/Resources/Nielk1_eyes_128.png new file mode 100644 index 0000000..746ece5 Binary files /dev/null and b/VSCView/Resources/Nielk1_eyes_128.png differ diff --git a/VSCView/SteamController.cs b/VSCView/SteamController.cs new file mode 100644 index 0000000..f95062b --- /dev/null +++ b/VSCView/SteamController.cs @@ -0,0 +1,441 @@ +using HidLibrary; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; + +namespace VSCView +{ + public class SteamController + { + private const int VendorId = 0x28DE; // 10462 + private const int ProductIdWireless = 0x1142; // 4418; + private const int ProductIdWired = 0x1102; // 4354 + + private bool _attached = false; + private HidDevice _device; + + public enum VSCEventType + { + CONTROL_UPDATE = 0x01, + CONNECTION_DETAIL = 0x03, + BATTERY_UPDATE = 0x04, + } + + public enum ConnectionState + { + DISCONNECT = 0x01, + CONNECT = 0x02, + PAIRING = 0x03, + } + + public class SteamControllerButtons : ICloneable + { + public bool A { get; set; } + public bool B { get; set; } + public bool X { get; set; } + public bool Y { get; set; } + + public bool LeftBumper { get; set; } + public bool LeftTrigger { get; set; } + + public bool RightBumper { get; set; } + public bool RightTrigger { get; set; } + + public bool LeftGrip { get; set; } + public bool RightGrip { get; set; } + + public bool Start { get; set; } + public bool Steam { get; set; } + public bool Select { get; set; } + + public bool Down { get; set; } + public bool Left { get; set; } + public bool Right { get; set; } + public bool Up { get; set; } + + public bool StickClick { get; set; } + public bool LeftPadTouch { get; set; } + public bool LeftPadClick { get; set; } + public bool RightPadTouch { get; set; } + public bool RightPadClick { get; set; } + + public object Clone() + { + SteamControllerButtons buttons = new SteamControllerButtons(); + + buttons.A = A; + buttons.B = B; + buttons.X = X; + buttons.Y = Y; + + buttons.LeftBumper = LeftBumper; + buttons.LeftTrigger = LeftTrigger; + + buttons.RightBumper = RightBumper; + buttons.RightTrigger = RightTrigger; + + buttons.LeftGrip = LeftGrip; + buttons.RightGrip = RightGrip; + + buttons.Start = Start; + buttons.Steam = Steam; + buttons.Select = Select; + + buttons.Down = Down; + buttons.Left = Left; + buttons.Right = Right; + buttons.Up = Up; + + buttons.StickClick = StickClick; + buttons.LeftPadTouch = LeftPadTouch; + buttons.LeftPadClick = LeftPadClick; + buttons.RightPadTouch = RightPadTouch; + buttons.RightPadClick = RightPadClick; + + return buttons; + } + } + + public class SteamControllerState + { + public SteamControllerButtons Buttons; + + public byte LeftTrigger { get; set; } + public byte RightTrigger { get; set; } + + public Int32 LeftStickX { get; set; } + public Int32 LeftStickY { get; set; } + public Int32 LeftPadX { get; set; } + public Int32 LeftPadY { get; set; } + public Int32 RightPadX { get; set; } + public Int32 RightPadY { get; set; } + + public Int16 AngularVelocityX { get; set; } + public Int16 AngularVelocityY { get; set; } + public Int16 AngularVelocityZ { get; set; } + public Int16 OrientationW { get; set; } + public Int16 OrientationX { get; set; } + public Int16 OrientationY { get; set; } + public Int16 OrientationZ { get; set; } + } + + SteamControllerButtons Buttons { get; set; } + + byte LeftTrigger { get; set; } + byte RightTrigger { get; set; } + + Int32 LeftStickX { get; set; } + Int32 LeftStickY { get; set; } + Int32 LeftPadX { get; set; } + Int32 LeftPadY { get; set; } + Int32 RightPadX { get; set; } + Int32 RightPadY { get; set; } + + Int16 AngularVelocityX { get; set; } + Int16 AngularVelocityY { get; set; } + Int16 AngularVelocityZ { get; set; } + Int16 OrientationW { get; set; } + Int16 OrientationX { get; set; } + Int16 OrientationY { get; set; } + Int16 OrientationZ { get; set; } + + bool Initalized; + + public delegate void StateUpdatedEventHandler(object sender, SteamControllerState e); + public event StateUpdatedEventHandler StateUpdated; + protected virtual void OnStateUpdated(SteamControllerState e) + { + StateUpdated?.Invoke(this, e); + } + + object controllerStateLock = new object(); + + public SteamController(HidDevice device) + { + Buttons = new SteamControllerButtons(); + + _device = device; + + Initalized = false; + } + + public void Initalize() + { + if (Initalized) return; + + //_device.OpenDevice(); + + _device.Inserted += DeviceAttachedHandler; + _device.Removed += DeviceRemovedHandler; + + _device.MonitorDeviceEvents = true; + + _device.ReadReport(OnReport); + + Initalized = true; + } + + public void DeInitalize() + { + if (!Initalized) return; + + _device.Inserted -= DeviceAttachedHandler; + _device.Removed -= DeviceRemovedHandler; + + _device.MonitorDeviceEvents = false; + + Initalized = false; + } + + public string GetDevicePath() + { + return _device.DevicePath; + } + + public SteamControllerState GetState() + { + lock (controllerStateLock) + { + SteamControllerState state = new SteamControllerState(); + state.Buttons = (SteamControllerButtons)Buttons.Clone(); + + state.LeftTrigger = LeftTrigger; + state.RightTrigger = RightTrigger; + + state.LeftStickX = LeftStickX; + state.LeftStickY = LeftStickY; + state.LeftPadX = LeftPadX; + state.LeftPadY = LeftPadY; + state.RightPadX = RightPadX; + state.RightPadY = RightPadY; + + state.AngularVelocityX = AngularVelocityX; + state.AngularVelocityY = AngularVelocityY; + state.AngularVelocityZ = AngularVelocityZ; + state.OrientationW = OrientationW; + state.OrientationX = OrientationX; + state.OrientationY = OrientationY; + state.OrientationZ = OrientationZ; + + return state; + } + } + + public static SteamController[] GetControllers() + { + List _devices = HidDevices.Enumerate(VendorId, ProductIdWireless, ProductIdWired).ToList(); + //Dictionary HidDeviceList = new Dictionary(); + + List HidDeviceList = new List(); + + // we should never have holes, this entire dictionary is just because I don't know if I can trust the order I get the HID devices + foreach (HidDevice _device in _devices) + { + if (_device != null) + { + int index = -1; + Match m = Regex.Match(_device.DevicePath, "&mi_([0-9]{2})"); + if (!m.Success) continue; + index = int.Parse(m.Groups[1].Value) - 1; + if (index < 0) continue; + + //HidDeviceList.Add(index, _device); + HidDeviceList.Add(_device); + } + } + + //SteamController[] Controllers = new SteamController[HidDeviceList.Count]; + //for (int idx = 0; idx < HidDeviceList.Count; idx++) + //{ + // if (!HidDeviceList.ContainsKey(idx)) continue; + // + // Controllers[idx] = new SteamController(HidDeviceList[idx]); + //} + // + //return Controllers; + + return HidDeviceList.Select(dr => new SteamController(dr)).ToArray(); + } + + private void OnReport(HidReport report) + { + if (!Initalized) return; + + lock (controllerStateLock) + { + //SteamControllerState OldState = GetState(); + + if (_attached == false) { return; } + + byte Unknown1 = report.Data[0]; // always 0x01? + byte Unknown2 = report.Data[1]; // always 0x00? + VSCEventType EventType = (VSCEventType)report.Data[2]; + + switch (EventType) + { + case 0: // not sure what this is but wired controllers do it + break; + case VSCEventType.CONTROL_UPDATE: + { + //report.Data[3] // 0x3C? + + UInt32 PacketIndex = BitConverter.ToUInt32(report.Data, 4); + + Buttons.A = (report.Data[8] & 128) == 128; + Buttons.X = (report.Data[8] & 64) == 64; + Buttons.B = (report.Data[8] & 32) == 32; + Buttons.Y = (report.Data[8] & 16) == 16; + Buttons.LeftBumper = (report.Data[8] & 8) == 8; + Buttons.RightBumper = (report.Data[8] & 4) == 4; + Buttons.LeftTrigger = (report.Data[8] & 2) == 2; + Buttons.RightTrigger = (report.Data[8] & 1) == 1; + + Buttons.LeftGrip = (report.Data[9] & 128) == 128; + Buttons.Start = (report.Data[9] & 64) == 64; + Buttons.Steam = (report.Data[9] & 32) == 32; + Buttons.Select = (report.Data[9] & 16) == 16; + + Buttons.Down = (report.Data[9] & 8) == 8; + Buttons.Left = (report.Data[9] & 4) == 4; + Buttons.Right = (report.Data[9] & 2) == 2; + Buttons.Up = (report.Data[9] & 1) == 1; + + bool LeftAnalogMultiplexMode = (report.Data[10] & 128) == 128; + Buttons.StickClick = (report.Data[10] & 64) == 64; + bool Unknown = (report.Data[10] & 32) == 32; // what is this? + Buttons.RightPadTouch = (report.Data[10] & 16) == 16; + bool LeftPadTouch = (report.Data[10] & 8) == 8; + Buttons.RightPadClick = (report.Data[10] & 4) == 4; + bool ThumbOrLeftPadPress = (report.Data[10] & 2) == 2; // what is this even for? + Buttons.RightGrip = (report.Data[10] & 1) == 1; + + LeftTrigger = report.Data[11]; + RightTrigger = report.Data[12]; + + if (LeftAnalogMultiplexMode) + { + if (LeftPadTouch) + { + Buttons.LeftPadTouch = true; + Buttons.LeftPadClick = ThumbOrLeftPadPress; + LeftPadX = BitConverter.ToInt16(report.Data, 16); + LeftPadY = BitConverter.ToInt16(report.Data, 18); + } + else + { + LeftStickX = BitConverter.ToInt16(report.Data, 16); + LeftStickY = BitConverter.ToInt16(report.Data, 18); + } + } + else + { + if (LeftPadTouch) + { + Buttons.LeftPadTouch = true; + LeftPadX = BitConverter.ToInt16(report.Data, 16); + LeftPadY = BitConverter.ToInt16(report.Data, 18); + } + else + { + Buttons.LeftPadTouch = false; + LeftStickX = BitConverter.ToInt16(report.Data, 16); + LeftStickY = BitConverter.ToInt16(report.Data, 18); + LeftPadX = 0; + LeftPadY = 0; + } + + Buttons.LeftPadClick = ThumbOrLeftPadPress && !Buttons.StickClick; + } + + RightPadX = BitConverter.ToInt16(report.Data, 20); + RightPadY = BitConverter.ToInt16(report.Data, 22); + + /* + //NiceOutputText[28] += " -------- Acceleration X: " + BitConverter.ToInt16(report.Data, 28); + //NiceOutputText[29] += " ^^^^^^^^"; + //NiceOutputText[30] += " -------- Acceleration Y: " + BitConverter.ToInt16(report.Data, 30); + //NiceOutputText[31] += " ^^^^^^^^"; + //NiceOutputText[32] += " -------- Acceleration Z: " + BitConverter.ToInt16(report.Data, 32); + //NiceOutputText[33] += " ^^^^^^^^"; + */ + AngularVelocityX = BitConverter.ToInt16(report.Data, 34); + AngularVelocityY = BitConverter.ToInt16(report.Data, 36); + AngularVelocityZ = BitConverter.ToInt16(report.Data, 38); + OrientationW = BitConverter.ToInt16(report.Data, 40); + OrientationX = BitConverter.ToInt16(report.Data, 42); + OrientationY = BitConverter.ToInt16(report.Data, 44); + OrientationZ = BitConverter.ToInt16(report.Data, 46); + } + break; + + case VSCEventType.CONNECTION_DETAIL: + { + //report.Data[3] // 0x01? + + // Connection detail. 0x01 for disconnect, 0x02 for connect, 0x03 for pairing request. + ConnectionState ConnectionStateV = (ConnectionState)report.Data[4]; + + if (report.Data[4] == 0x01) + { + byte[] tmpBytes = new byte[4]; + tmpBytes[1] = report.Data[5]; + tmpBytes[2] = report.Data[6]; + tmpBytes[3] = report.Data[7]; + + //BitConverter.ToUInt32(tmpBytes, 0); // Timestamp + } + } + break; + + case VSCEventType.BATTERY_UPDATE: + { + //report.Data[3] // 0x0B? + + UInt32 PacketIndex = BitConverter.ToUInt32(report.Data, 4); + + // only works if controller is configured to send this data + + // millivolts + UInt16 BatteryVoltage = BitConverter.ToUInt16(report.Data, 8); + //BitConverter.ToUInt16(report.Data, 10); // UNKNOWN, stuck at 100 + } + break; + + default: + { + Console.WriteLine("Unknown Packet Type " + EventType); + } + break; + } + + SteamControllerState NewState = GetState(); + OnStateUpdated(NewState); + + _device.ReadReport(OnReport); + } + } + + private void DeviceAttachedHandler() + { + lock (controllerStateLock) + { + _attached = true; + Console.WriteLine("VSC Address Attached"); + _device.ReadReport(OnReport); + } + } + + private void DeviceRemovedHandler() + { + lock (controllerStateLock) + { + _attached = false; + Console.WriteLine("VSC Address Removed"); + } + } + } +} diff --git a/VSCView/VSCView.csproj b/VSCView/VSCView.csproj new file mode 100644 index 0000000..04da5d8 --- /dev/null +++ b/VSCView/VSCView.csproj @@ -0,0 +1,181 @@ + + + + + Debug + AnyCPU + {E513702D-EF79-4766-AD9D-C2382BD0CEAD} + WinExe + VSCView + VSCView + v4.6.2 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + true + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\hidlibrary.3.2.46.0\lib\HidLibrary.dll + + + ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + + + + + + + + + + + + + + + + Form + + + About.cs + + + Form + + + MainForm.cs + + + + Form + + + ProcForm.cs + + + + Form + + + RawForm.cs + + + + + About.cs + + + MainForm.cs + + + RawForm.cs + + + ProcForm.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + PreserveNewest + + + PreserveNewest + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + \ No newline at end of file diff --git a/VSCView/licenses/HidLibrary.txt b/VSCView/licenses/HidLibrary.txt new file mode 100644 index 0000000..7d5d651 --- /dev/null +++ b/VSCView/licenses/HidLibrary.txt @@ -0,0 +1,18 @@ +Copyright (c) 2010 Ultraviolet Catastrophe + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/VSCView/licenses/Newtonsoft.Json.txt b/VSCView/licenses/Newtonsoft.Json.txt new file mode 100644 index 0000000..0fecee7 --- /dev/null +++ b/VSCView/licenses/Newtonsoft.Json.txt @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2007 James Newton-King + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/VSCView/licenses/VCSView.txt b/VSCView/licenses/VCSView.txt new file mode 100644 index 0000000..3afd917 --- /dev/null +++ b/VSCView/licenses/VCSView.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 John Klein + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/VSCView/packages.config b/VSCView/packages.config new file mode 100644 index 0000000..2726fbe --- /dev/null +++ b/VSCView/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/VSCView/themes/default/all.json b/VSCView/themes/default/all.json new file mode 100644 index 0000000..5df4044 --- /dev/null +++ b/VSCView/themes/default/all.json @@ -0,0 +1,160 @@ +{ + "width": 629, + "height": 774, + "children": [ + { + "type":"image", + "image":"base.png", + "x":314.5, + "y":302.5, + "width":629, + "height":605, + "center":true, + "children": [ + { + "x":74, + "y":67, + "children": [ + { "type":"showhide", "inputName":"a", "invert":false, "children": [ { "type":"image", "image":"btn-face.png", "x": 0, "y": 35, "width":36, "height":36, "center":true } ] }, + { "type":"showhide", "inputName":"b", "invert":false, "children": [ { "type":"image", "image":"btn-face.png", "x": 35, "y": 0, "width":36, "height":36, "center":true } ] }, + { "type":"showhide", "inputName":"x", "invert":false, "children": [ { "type":"image", "image":"btn-face.png", "x":-35, "y": 0, "width":36, "height":36, "center":true } ] }, + { "type":"showhide", "inputName":"y", "invert":false, "children": [ { "type":"image", "image":"btn-face.png", "x": 0, "y":-35, "width":36, "height":36, "center":true } ] } + ] + }, + + { "type":"showhide", "inputName":"stickclick", "invert":false, "children": [ { "type":"image", "image":"btn-stick.png", "x": -73, "y": 67, "width":105, "height":105, "center":true } ] }, + { + "type":"slider", + "x": -72, + "y": 67, + "axisNameX":"leftstickx", + "axisNameY":"leftsticky", + "scaleFactorX": 0.0005, + "scaleFactorY": 0.0005, + "children": [ + { "type":"image", "image":"stick.png", "x": 0, "y": 0, "width":69, "height":70, "center":true } + ] + }, + { + "x":0, + "y":-29, + "children": [ + { "type":"showhide", "inputName":"steam" , "invert":false, "children": [ { "type":"image", "image":"btn-home.png", "x": 0, "y": -8, "width":51, "height":51, "center":true } ] }, + { "type":"showhide", "inputName":"start" , "invert":false, "children": [ { "type":"image", "image":"btn-sub.png" , "x": 52, "y": 0, "width":38, "height":22, "center":true } ] }, + { "type":"showhide", "inputName":"select", "invert":false, "children": [ { "type":"image", "image":"btn-sub.png" , "x": -52, "y": 0, "width":38, "height":22, "center":true } ] } + ] + }, + { + "x":0, + "y":-235, + "children": [ + { "type":"showhide", "inputName":"lg", "invert":false, "children": [ { "type":"image", "image":"btn-trigger.png" , "x": -75, "y": 0, "width":50, "height":50, "center":true } ] }, + { "type":"showhide", "inputName":"lt", "invert":false, "children": [ { "type":"image", "image":"btn-trigger.png" , "x": -163, "y": 48, "width":50, "height":50, "center":true } ] }, + { "type":"showhide", "inputName":"lb", "invert":false, "children": [ { "type":"image", "image":"btn-trigger.png" , "x": -163, "y": -28, "width":50, "height":50, "center":true } ] }, + { "type":"showhide", "inputName":"rg", "invert":false, "children": [ { "type":"image", "image":"btn-trigger.png" , "x": 75, "y": 0, "width":50, "height":50, "center":true } ] }, + { "type":"showhide", "inputName":"rt", "invert":false, "children": [ { "type":"image", "image":"btn-trigger.png" , "x": 163, "y": 48, "width":50, "height":50, "center":true } ] }, + { "type":"showhide", "inputName":"rb", "invert":false, "children": [ { "type":"image", "image":"btn-trigger.png" , "x": 163, "y": -28, "width":50, "height":50, "center":true } ] } + ] + }, + + { "type":"showhide", "inputName":"rightpadclick", "invert":false, "children": [ { "type":"image", "image":"btn-haptic.png", "x": 171, "y": -23, "width":156, "height":160, "center":true } ] }, + { + "x": 171, + "y": -23, + "rot":-15, + "children": [ + { + "type":"trailpad", + "inputName":"rightpadtouch", + "x": 0, + "y": 0, + "axisNameX":"rightpadx", + "axisNameY":"rightpady", + "scaleFactorX": 0.0022, + "scaleFactorY": 0.0022, + "image":"padheat.png", + "length":60, + "width":36, + "height":36, + "children": [ + { "type":"showhide", "inputName":"rightpadtouch", "invert":false, "children": [ { "type":"image", "image":"btn-face.png", "x": 0, "y": 0, "width":36, "height":36, "center":true } ] } + ] + } + ] + }, + + { "type":"showhide", "inputName":"leftpadclick" , "invert":false, "children": [ { "type":"image", "image":"btn-haptic.png", "x": -171, "y": -23, "width":156, "height":160, "center":true } ] }, + { + "x": -171, + "y": -23, + "rot": 15, + "children": [ + { + "type":"trailpad", + "inputName":"leftpadtouch", + "x": 0, + "y": 0, + "axisNameX":"leftpadx", + "axisNameY":"leftpady", + "scaleFactorX": 0.0022, + "scaleFactorY": 0.0022, + "image":"padheat.png", + "length":60, + "width":36, + "height":36, + "children": [ + { "type":"showhide", "inputName":"leftpadtouch", "invert":false, "children": [ { "type":"image", "image":"btn-face.png", "x": 0, "y": 0, "width":36, "height":36, "center":true } ] } + ] + } + ] + }, + + { + "x":0, + "y":-170, + "children": [ + { "type":"pbar", "axisName":"lefttrigger" , "background":"ff007894", "foreground":"ff00d2f8", "x": -65, "y": 0, "width":120, "height":15, "min":0, "max":255, "direction": "right" }, + { "type":"pbar", "axisName":"righttrigger", "background":"ff007894", "foreground":"ff00d2f8", "x": 65, "y": 0, "width":120, "height":15, "min":0, "max":255, "direction": "left" } + ] + }, + + { + "x":0, + "y":370, + "children": [ + { + "type":"basic3d1", + "x": 165, + "y": 0, + "width":103, + "height":77, + "mode": "accel", + "image":"gyro.png", + "shadowl":"gyro_l.png", + "shadowr":"gyro_r.png", + "shadowu":"gyro_u.png", + "shadowd":"gyro_d.png", + "tilttranslatex":55, + "tilttranslatey":40 + }, + { + "type":"basic3d1", + "x": -165, + "y": 0, + "width":103, + "height":77, + "mode": "gyro", + "image":"gyro.png", + "shadowl":"gyro_l.png", + "shadowr":"gyro_r.png", + "shadowu":"gyro_u.png", + "shadowd":"gyro_d.png", + "tilttranslatex":55, + "tilttranslatey":40 + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/VSCView/themes/default/base.png b/VSCView/themes/default/base.png new file mode 100644 index 0000000..7de0a62 Binary files /dev/null and b/VSCView/themes/default/base.png differ diff --git a/VSCView/themes/default/btn-face.png b/VSCView/themes/default/btn-face.png new file mode 100644 index 0000000..9d87693 Binary files /dev/null and b/VSCView/themes/default/btn-face.png differ diff --git a/VSCView/themes/default/btn-haptic.png b/VSCView/themes/default/btn-haptic.png new file mode 100644 index 0000000..62c6fd3 Binary files /dev/null and b/VSCView/themes/default/btn-haptic.png differ diff --git a/VSCView/themes/default/btn-home.png b/VSCView/themes/default/btn-home.png new file mode 100644 index 0000000..28ae679 Binary files /dev/null and b/VSCView/themes/default/btn-home.png differ diff --git a/VSCView/themes/default/btn-stick.png b/VSCView/themes/default/btn-stick.png new file mode 100644 index 0000000..2999fa7 Binary files /dev/null and b/VSCView/themes/default/btn-stick.png differ diff --git a/VSCView/themes/default/btn-sub.png b/VSCView/themes/default/btn-sub.png new file mode 100644 index 0000000..8ac314d Binary files /dev/null and b/VSCView/themes/default/btn-sub.png differ diff --git a/VSCView/themes/default/btn-trigger.png b/VSCView/themes/default/btn-trigger.png new file mode 100644 index 0000000..25e7ad1 Binary files /dev/null and b/VSCView/themes/default/btn-trigger.png differ diff --git a/VSCView/themes/default/gyro.png b/VSCView/themes/default/gyro.png new file mode 100644 index 0000000..f29dece Binary files /dev/null and b/VSCView/themes/default/gyro.png differ diff --git a/VSCView/themes/default/gyro_d.png b/VSCView/themes/default/gyro_d.png new file mode 100644 index 0000000..cc61b82 Binary files /dev/null and b/VSCView/themes/default/gyro_d.png differ diff --git a/VSCView/themes/default/gyro_l.png b/VSCView/themes/default/gyro_l.png new file mode 100644 index 0000000..a449329 Binary files /dev/null and b/VSCView/themes/default/gyro_l.png differ diff --git a/VSCView/themes/default/gyro_r.png b/VSCView/themes/default/gyro_r.png new file mode 100644 index 0000000..4b9a01e Binary files /dev/null and b/VSCView/themes/default/gyro_r.png differ diff --git a/VSCView/themes/default/gyro_u.png b/VSCView/themes/default/gyro_u.png new file mode 100644 index 0000000..6a0082f Binary files /dev/null and b/VSCView/themes/default/gyro_u.png differ diff --git a/VSCView/themes/default/nogyro.json b/VSCView/themes/default/nogyro.json new file mode 100644 index 0000000..7a1c909 --- /dev/null +++ b/VSCView/themes/default/nogyro.json @@ -0,0 +1,123 @@ +{ + "width": 629, + "height": 605, + "children": [ + { + "type":"image", + "image":"base.png", + "x":314.5, + "y":302.5, + "width":629, + "height":605, + "center":true, + "children": [ + { + "x":74, + "y":67, + "children": [ + { "type":"showhide", "inputName":"a", "invert":false, "children": [ { "type":"image", "image":"btn-face.png", "x": 0, "y": 35, "width":36, "height":36, "center":true } ] }, + { "type":"showhide", "inputName":"b", "invert":false, "children": [ { "type":"image", "image":"btn-face.png", "x": 35, "y": 0, "width":36, "height":36, "center":true } ] }, + { "type":"showhide", "inputName":"x", "invert":false, "children": [ { "type":"image", "image":"btn-face.png", "x":-35, "y": 0, "width":36, "height":36, "center":true } ] }, + { "type":"showhide", "inputName":"y", "invert":false, "children": [ { "type":"image", "image":"btn-face.png", "x": 0, "y":-35, "width":36, "height":36, "center":true } ] } + ] + }, + + { "type":"showhide", "inputName":"stickclick", "invert":false, "children": [ { "type":"image", "image":"btn-stick.png", "x": -73, "y": 67, "width":105, "height":105, "center":true } ] }, + { + "type":"slider", + "x": -72, + "y": 67, + "axisNameX":"leftstickx", + "axisNameY":"leftsticky", + "scaleFactorX": 0.0005, + "scaleFactorY": 0.0005, + "children": [ + { "type":"image", "image":"stick.png", "x": 0, "y": 0, "width":69, "height":70, "center":true } + ] + }, + { + "x":0, + "y":-29, + "children": [ + { "type":"showhide", "inputName":"steam" , "invert":false, "children": [ { "type":"image", "image":"btn-home.png", "x": 0, "y": -8, "width":51, "height":51, "center":true } ] }, + { "type":"showhide", "inputName":"start" , "invert":false, "children": [ { "type":"image", "image":"btn-sub.png" , "x": 52, "y": 0, "width":38, "height":22, "center":true } ] }, + { "type":"showhide", "inputName":"select", "invert":false, "children": [ { "type":"image", "image":"btn-sub.png" , "x": -52, "y": 0, "width":38, "height":22, "center":true } ] } + ] + }, + { + "x":0, + "y":-235, + "children": [ + { "type":"showhide", "inputName":"lg", "invert":false, "children": [ { "type":"image", "image":"btn-trigger.png" , "x": -75, "y": 0, "width":50, "height":50, "center":true } ] }, + { "type":"showhide", "inputName":"lt", "invert":false, "children": [ { "type":"image", "image":"btn-trigger.png" , "x": -163, "y": 48, "width":50, "height":50, "center":true } ] }, + { "type":"showhide", "inputName":"lb", "invert":false, "children": [ { "type":"image", "image":"btn-trigger.png" , "x": -163, "y": -28, "width":50, "height":50, "center":true } ] }, + { "type":"showhide", "inputName":"rg", "invert":false, "children": [ { "type":"image", "image":"btn-trigger.png" , "x": 75, "y": 0, "width":50, "height":50, "center":true } ] }, + { "type":"showhide", "inputName":"rt", "invert":false, "children": [ { "type":"image", "image":"btn-trigger.png" , "x": 163, "y": 48, "width":50, "height":50, "center":true } ] }, + { "type":"showhide", "inputName":"rb", "invert":false, "children": [ { "type":"image", "image":"btn-trigger.png" , "x": 163, "y": -28, "width":50, "height":50, "center":true } ] } + ] + }, + + { "type":"showhide", "inputName":"rightpadclick", "invert":false, "children": [ { "type":"image", "image":"btn-haptic.png", "x": 171, "y": -23, "width":156, "height":160, "center":true } ] }, + { + "x": 171, + "y": -23, + "rot":-15, + "children": [ + { + "type":"trailpad", + "inputName":"rightpadtouch", + "x": 0, + "y": 0, + "axisNameX":"rightpadx", + "axisNameY":"rightpady", + "scaleFactorX": 0.0022, + "scaleFactorY": 0.0022, + "image":"padheat.png", + "length":60, + "width":36, + "height":36, + "children": [ + { "type":"showhide", "inputName":"rightpadtouch", "invert":false, "children": [ { "type":"image", "image":"btn-face.png", "x": 0, "y": 0, "width":36, "height":36, "center":true } ] } + ] + } + ] + }, + + { "type":"showhide", "inputName":"leftpadclick" , "invert":false, "children": [ { "type":"image", "image":"btn-haptic.png", "x": -171, "y": -23, "width":156, "height":160, "center":true } ] }, + { + "x": -171, + "y": -23, + "rot": 15, + "children": [ + { + "type":"trailpad", + "inputName":"leftpadtouch", + "x": 0, + "y": 0, + "axisNameX":"leftpadx", + "axisNameY":"leftpady", + "scaleFactorX": 0.0022, + "scaleFactorY": 0.0022, + "image":"padheat.png", + "length":60, + "width":36, + "height":36, + "children": [ + { "type":"showhide", "inputName":"leftpadtouch", "invert":false, "children": [ { "type":"image", "image":"btn-face.png", "x": 0, "y": 0, "width":36, "height":36, "center":true } ] } + ] + } + ] + }, + + { + "x":0, + "y":-170, + "children": [ + { "type":"pbar", "axisName":"lefttrigger" , "background":"ff007894", "foreground":"ff00d2f8", "x": -65, "y": 0, "width":120, "height":15, "min":0, "max":255, "direction": "right" }, + { "type":"pbar", "axisName":"righttrigger", "background":"ff007894", "foreground":"ff00d2f8", "x": 65, "y": 0, "width":120, "height":15, "min":0, "max":255, "direction": "left" } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/VSCView/themes/default/padheat.png b/VSCView/themes/default/padheat.png new file mode 100644 index 0000000..492086e Binary files /dev/null and b/VSCView/themes/default/padheat.png differ diff --git a/VSCView/themes/default/stick.png b/VSCView/themes/default/stick.png new file mode 100644 index 0000000..454c72d Binary files /dev/null and b/VSCView/themes/default/stick.png differ