├── .gitignore ├── LICENSE ├── MouseTester ├── MouseTester.sln └── MouseTester │ ├── Form1.Designer.cs │ ├── Form1.cs │ ├── Form1.resx │ ├── GraphicsRenderContext.cs │ ├── MouseEvent.cs │ ├── MouseLog.cs │ ├── MousePlot.Designer.cs │ ├── MousePlot.cs │ ├── MousePlot.resx │ ├── MouseTester.csproj │ ├── OxyPlot.WindowsForms.dll │ ├── OxyPlot.dll │ ├── Program.cs │ ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ ├── Settings.settings │ └── app.manifest │ ├── RawMouse.cs │ └── app.config └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | [Bb]in/ 3 | [Oo]bj/ 4 | 5 | # mstest test results 6 | TestResults 7 | 8 | ## Ignore Visual Studio temporary files, build results, and 9 | ## files generated by popular Visual Studio add-ons. 10 | 11 | # User-specific files 12 | *.suo 13 | *.user 14 | *.sln.docstates 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Rr]elease/ 19 | x64/ 20 | *_i.c 21 | *_p.c 22 | *.ilk 23 | *.meta 24 | *.obj 25 | *.pch 26 | *.pdb 27 | *.pgc 28 | *.pgd 29 | *.rsp 30 | *.sbr 31 | *.tlb 32 | *.tli 33 | *.tlh 34 | *.tmp 35 | *.log 36 | *.vspscc 37 | *.vssscc 38 | .builds 39 | 40 | # Visual C++ cache files 41 | ipch/ 42 | *.aps 43 | *.ncb 44 | *.opensdf 45 | *.sdf 46 | 47 | # Visual Studio profiler 48 | *.psess 49 | *.vsp 50 | *.vspx 51 | 52 | # Guidance Automation Toolkit 53 | *.gpState 54 | 55 | # ReSharper is a .NET coding add-in 56 | _ReSharper* 57 | 58 | # NCrunch 59 | *.ncrunch* 60 | .*crunch*.local.xml 61 | 62 | # Installshield output folder 63 | [Ee]xpress 64 | 65 | # DocProject is a documentation generator add-in 66 | DocProject/buildhelp/ 67 | DocProject/Help/*.HxT 68 | DocProject/Help/*.HxC 69 | DocProject/Help/*.hhc 70 | DocProject/Help/*.hhk 71 | DocProject/Help/*.hhp 72 | DocProject/Help/Html2 73 | DocProject/Help/html 74 | 75 | # Click-Once directory 76 | publish 77 | 78 | # Publish Web Output 79 | *.Publish.xml 80 | 81 | # NuGet Packages Directory 82 | packages 83 | 84 | # Windows Azure Build Output 85 | csx 86 | *.build.csdef 87 | 88 | # Windows Store app package directory 89 | AppPackages/ 90 | 91 | # Others 92 | [Bb]in 93 | [Oo]bj 94 | sql 95 | TestResults 96 | [Tt]est[Rr]esult* 97 | *.Cache 98 | ClientBin 99 | [Ss]tyle[Cc]op.* 100 | ~$* 101 | *.dbmdl 102 | Generated_Code #added for RIA/Silverlight projects 103 | 104 | # Backup & report files from converting an old project file to a newer 105 | # Visual Studio version. Backup files are not needed, because we have git ;-) 106 | _UpgradeReport_Files/ 107 | Backup*/ 108 | UpgradeLog*.XML 109 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 microe1 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /MouseTester/MouseTester.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30717.126 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MouseTester", "MouseTester\MouseTester.csproj", "{B0953B29-AF9B-4C37-A2EC-947E98F683B3}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|x64 = Debug|x64 12 | Debug|x86 = Debug|x86 13 | Release|Any CPU = Release|Any CPU 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {B0953B29-AF9B-4C37-A2EC-947E98F683B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {B0953B29-AF9B-4C37-A2EC-947E98F683B3}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {B0953B29-AF9B-4C37-A2EC-947E98F683B3}.Debug|x64.ActiveCfg = Debug|x64 21 | {B0953B29-AF9B-4C37-A2EC-947E98F683B3}.Debug|x64.Build.0 = Debug|x64 22 | {B0953B29-AF9B-4C37-A2EC-947E98F683B3}.Debug|x86.ActiveCfg = Debug|x86 23 | {B0953B29-AF9B-4C37-A2EC-947E98F683B3}.Debug|x86.Build.0 = Debug|x86 24 | {B0953B29-AF9B-4C37-A2EC-947E98F683B3}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {B0953B29-AF9B-4C37-A2EC-947E98F683B3}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {B0953B29-AF9B-4C37-A2EC-947E98F683B3}.Release|x64.ActiveCfg = Release|x64 27 | {B0953B29-AF9B-4C37-A2EC-947E98F683B3}.Release|x64.Build.0 = Release|x64 28 | {B0953B29-AF9B-4C37-A2EC-947E98F683B3}.Release|x86.ActiveCfg = Release|x86 29 | {B0953B29-AF9B-4C37-A2EC-947E98F683B3}.Release|x86.Build.0 = Release|x86 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {FEE93D0A-FE0A-4153-BD9B-A612BE91F7FC} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /MouseTester/MouseTester/Form1.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace MouseTester 2 | { 3 | partial class Form1 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.groupBox1 = new System.Windows.Forms.GroupBox(); 32 | this.textBoxDesc = new System.Windows.Forms.TextBox(); 33 | this.textBoxCPI = new System.Windows.Forms.TextBox(); 34 | this.groupBox2 = new System.Windows.Forms.GroupBox(); 35 | this.label1 = new System.Windows.Forms.Label(); 36 | this.buttonMeasure = new System.Windows.Forms.Button(); 37 | this.groupBox3 = new System.Windows.Forms.GroupBox(); 38 | this.buttonSave = new System.Windows.Forms.Button(); 39 | this.buttonLoad = new System.Windows.Forms.Button(); 40 | this.buttonPlot = new System.Windows.Forms.Button(); 41 | this.groupBox4 = new System.Windows.Forms.GroupBox(); 42 | this.buttonLog = new System.Windows.Forms.Button(); 43 | this.buttonCollect = new System.Windows.Forms.Button(); 44 | this.textBox1 = new System.Windows.Forms.TextBox(); 45 | this.statusStrip1 = new System.Windows.Forms.StatusStrip(); 46 | this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); 47 | this.groupBox1.SuspendLayout(); 48 | this.groupBox2.SuspendLayout(); 49 | this.groupBox3.SuspendLayout(); 50 | this.groupBox4.SuspendLayout(); 51 | this.statusStrip1.SuspendLayout(); 52 | this.SuspendLayout(); 53 | // 54 | // groupBox1 55 | // 56 | this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 57 | | System.Windows.Forms.AnchorStyles.Right))); 58 | this.groupBox1.Controls.Add(this.textBoxDesc); 59 | this.groupBox1.Location = new System.Drawing.Point(13, 13); 60 | this.groupBox1.Name = "groupBox1"; 61 | this.groupBox1.Size = new System.Drawing.Size(267, 50); 62 | this.groupBox1.TabIndex = 0; 63 | this.groupBox1.TabStop = false; 64 | this.groupBox1.Text = "Description"; 65 | // 66 | // textBoxDesc 67 | // 68 | this.textBoxDesc.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 69 | | System.Windows.Forms.AnchorStyles.Left) 70 | | System.Windows.Forms.AnchorStyles.Right))); 71 | this.textBoxDesc.Location = new System.Drawing.Point(6, 19); 72 | this.textBoxDesc.Name = "textBoxDesc"; 73 | this.textBoxDesc.Size = new System.Drawing.Size(250, 20); 74 | this.textBoxDesc.TabIndex = 0; 75 | // 76 | // textBoxCPI 77 | // 78 | this.textBoxCPI.Location = new System.Drawing.Point(88, 21); 79 | this.textBoxCPI.Name = "textBoxCPI"; 80 | this.textBoxCPI.Size = new System.Drawing.Size(100, 20); 81 | this.textBoxCPI.TabIndex = 0; 82 | this.textBoxCPI.Validated += new System.EventHandler(this.textBoxCPI_Validated); 83 | // 84 | // groupBox2 85 | // 86 | this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 87 | | System.Windows.Forms.AnchorStyles.Right))); 88 | this.groupBox2.Controls.Add(this.label1); 89 | this.groupBox2.Controls.Add(this.buttonMeasure); 90 | this.groupBox2.Controls.Add(this.textBoxCPI); 91 | this.groupBox2.Location = new System.Drawing.Point(13, 69); 92 | this.groupBox2.Name = "groupBox2"; 93 | this.groupBox2.Size = new System.Drawing.Size(267, 50); 94 | this.groupBox2.TabIndex = 1; 95 | this.groupBox2.TabStop = false; 96 | this.groupBox2.Text = "Resolution"; 97 | // 98 | // label1 99 | // 100 | this.label1.AutoSize = true; 101 | this.label1.Location = new System.Drawing.Point(194, 24); 102 | this.label1.Name = "label1"; 103 | this.label1.Size = new System.Drawing.Size(21, 13); 104 | this.label1.TabIndex = 2; 105 | this.label1.Text = "cpi"; 106 | // 107 | // buttonMeasure 108 | // 109 | this.buttonMeasure.Location = new System.Drawing.Point(6, 19); 110 | this.buttonMeasure.Name = "buttonMeasure"; 111 | this.buttonMeasure.Size = new System.Drawing.Size(75, 23); 112 | this.buttonMeasure.TabIndex = 1; 113 | this.buttonMeasure.Text = "Measure"; 114 | this.buttonMeasure.UseVisualStyleBackColor = true; 115 | this.buttonMeasure.Click += new System.EventHandler(this.buttonMeasure_Click); 116 | // 117 | // groupBox3 118 | // 119 | this.groupBox3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 120 | | System.Windows.Forms.AnchorStyles.Right))); 121 | this.groupBox3.Controls.Add(this.buttonSave); 122 | this.groupBox3.Controls.Add(this.buttonLoad); 123 | this.groupBox3.Location = new System.Drawing.Point(13, 182); 124 | this.groupBox3.Name = "groupBox3"; 125 | this.groupBox3.Size = new System.Drawing.Size(267, 50); 126 | this.groupBox3.TabIndex = 2; 127 | this.groupBox3.TabStop = false; 128 | this.groupBox3.Text = "LogFile"; 129 | // 130 | // buttonSave 131 | // 132 | this.buttonSave.Location = new System.Drawing.Point(88, 20); 133 | this.buttonSave.Name = "buttonSave"; 134 | this.buttonSave.Size = new System.Drawing.Size(75, 23); 135 | this.buttonSave.TabIndex = 1; 136 | this.buttonSave.Text = "Save"; 137 | this.buttonSave.UseVisualStyleBackColor = true; 138 | this.buttonSave.Click += new System.EventHandler(this.buttonSave_Click); 139 | // 140 | // buttonLoad 141 | // 142 | this.buttonLoad.Location = new System.Drawing.Point(7, 20); 143 | this.buttonLoad.Name = "buttonLoad"; 144 | this.buttonLoad.Size = new System.Drawing.Size(75, 23); 145 | this.buttonLoad.TabIndex = 0; 146 | this.buttonLoad.Text = "Load"; 147 | this.buttonLoad.UseVisualStyleBackColor = true; 148 | this.buttonLoad.Click += new System.EventHandler(this.buttonLoad_Click); 149 | // 150 | // buttonPlot 151 | // 152 | this.buttonPlot.Location = new System.Drawing.Point(168, 19); 153 | this.buttonPlot.Name = "buttonPlot"; 154 | this.buttonPlot.Size = new System.Drawing.Size(75, 23); 155 | this.buttonPlot.TabIndex = 2; 156 | this.buttonPlot.Text = "Plot (F3)"; 157 | this.buttonPlot.UseVisualStyleBackColor = true; 158 | this.buttonPlot.Click += new System.EventHandler(this.buttonPlot_Click); 159 | // 160 | // groupBox4 161 | // 162 | this.groupBox4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 163 | | System.Windows.Forms.AnchorStyles.Right))); 164 | this.groupBox4.Controls.Add(this.buttonLog); 165 | this.groupBox4.Controls.Add(this.buttonCollect); 166 | this.groupBox4.Controls.Add(this.buttonPlot); 167 | this.groupBox4.Location = new System.Drawing.Point(13, 126); 168 | this.groupBox4.Name = "groupBox4"; 169 | this.groupBox4.Size = new System.Drawing.Size(267, 50); 170 | this.groupBox4.TabIndex = 3; 171 | this.groupBox4.TabStop = false; 172 | this.groupBox4.Text = "MouseData"; 173 | // 174 | // buttonLog 175 | // 176 | this.buttonLog.Location = new System.Drawing.Point(87, 19); 177 | this.buttonLog.Name = "buttonLog"; 178 | this.buttonLog.Size = new System.Drawing.Size(75, 23); 179 | this.buttonLog.TabIndex = 4; 180 | this.buttonLog.Text = "Start (F1)"; 181 | this.buttonLog.UseVisualStyleBackColor = true; 182 | this.buttonLog.Click += new System.EventHandler(this.buttonLog_Click); 183 | // 184 | // buttonCollect 185 | // 186 | this.buttonCollect.Location = new System.Drawing.Point(6, 19); 187 | this.buttonCollect.Name = "buttonCollect"; 188 | this.buttonCollect.Size = new System.Drawing.Size(75, 23); 189 | this.buttonCollect.TabIndex = 3; 190 | this.buttonCollect.Text = "Collect"; 191 | this.buttonCollect.UseVisualStyleBackColor = true; 192 | this.buttonCollect.Click += new System.EventHandler(this.buttonCollect_Click); 193 | // 194 | // textBox1 195 | // 196 | this.textBox1.Location = new System.Drawing.Point(13, 239); 197 | this.textBox1.Multiline = true; 198 | this.textBox1.Name = "textBox1"; 199 | this.textBox1.ReadOnly = true; 200 | this.textBox1.Size = new System.Drawing.Size(267, 100); 201 | this.textBox1.TabIndex = 4; 202 | // 203 | // statusStrip1 204 | // 205 | this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 206 | this.toolStripStatusLabel1}); 207 | this.statusStrip1.Location = new System.Drawing.Point(0, 339); 208 | this.statusStrip1.Name = "statusStrip1"; 209 | this.statusStrip1.Size = new System.Drawing.Size(284, 22); 210 | this.statusStrip1.TabIndex = 5; 211 | this.statusStrip1.Text = "statusStrip1"; 212 | // 213 | // toolStripStatusLabel1 214 | // 215 | this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; 216 | this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); 217 | this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; 218 | // 219 | // Form1 220 | // 221 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 222 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 223 | this.ClientSize = new System.Drawing.Size(284, 361); 224 | this.Controls.Add(this.statusStrip1); 225 | this.Controls.Add(this.textBox1); 226 | this.Controls.Add(this.groupBox4); 227 | this.Controls.Add(this.groupBox3); 228 | this.Controls.Add(this.groupBox2); 229 | this.Controls.Add(this.groupBox1); 230 | this.MaximumSize = new System.Drawing.Size(300, 400); 231 | this.MinimumSize = new System.Drawing.Size(300, 400); 232 | this.Name = "Form1"; 233 | this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; 234 | this.Text = "MouseTester v1.3"; 235 | this.groupBox1.ResumeLayout(false); 236 | this.groupBox1.PerformLayout(); 237 | this.groupBox2.ResumeLayout(false); 238 | this.groupBox2.PerformLayout(); 239 | this.groupBox3.ResumeLayout(false); 240 | this.groupBox4.ResumeLayout(false); 241 | this.statusStrip1.ResumeLayout(false); 242 | this.statusStrip1.PerformLayout(); 243 | this.ResumeLayout(false); 244 | this.PerformLayout(); 245 | 246 | } 247 | 248 | #endregion 249 | 250 | private System.Windows.Forms.GroupBox groupBox1; 251 | private System.Windows.Forms.TextBox textBoxDesc; 252 | private System.Windows.Forms.TextBox textBoxCPI; 253 | private System.Windows.Forms.GroupBox groupBox2; 254 | private System.Windows.Forms.Button buttonMeasure; 255 | private System.Windows.Forms.GroupBox groupBox3; 256 | private System.Windows.Forms.Button buttonPlot; 257 | private System.Windows.Forms.Button buttonSave; 258 | private System.Windows.Forms.Button buttonLoad; 259 | private System.Windows.Forms.GroupBox groupBox4; 260 | private System.Windows.Forms.Button buttonCollect; 261 | private System.Windows.Forms.Label label1; 262 | private System.Windows.Forms.TextBox textBox1; 263 | private System.Windows.Forms.StatusStrip statusStrip1; 264 | private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; 265 | private System.Windows.Forms.Button buttonLog; 266 | 267 | 268 | } 269 | } 270 | 271 | -------------------------------------------------------------------------------- /MouseTester/MouseTester/Form1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Diagnostics; 6 | using System.Drawing; 7 | using System.Linq; 8 | using System.Runtime.InteropServices; 9 | using System.Text; 10 | using System.Threading; 11 | using System.Windows.Forms; 12 | 13 | using OxyPlot; 14 | 15 | namespace MouseTester 16 | { 17 | using OxyPlot.Series; 18 | 19 | public partial class Form1 : Form 20 | { 21 | private MouseLog mlog = new MouseLog(); 22 | enum state { idle, measure_wait, measure, collect_wait, collect, log }; 23 | private state test_state = state.idle; 24 | private long pFreq; 25 | 26 | public Form1() 27 | { 28 | InitializeComponent(); 29 | try { 30 | // Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2); // Use only the second core 31 | // Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime; // Set highest process priority 32 | // Thread.CurrentThread.Priority = ThreadPriority.Highest; // Set highest thread priority 33 | } catch (Exception ex) { 34 | Debug.WriteLine(ex.ToString()); 35 | } 36 | 37 | this.RegisterRawInputMouse(Handle); 38 | this.textBoxDesc.Text = this.mlog.Desc.ToString(); 39 | this.textBoxCPI.Text = this.mlog.Cpi.ToString(); 40 | this.textBox1.Text = "Enter the correct CPI" + 41 | "\r\n or\r\n" + 42 | "Press the Measure button" + 43 | "\r\n or\r\n" + 44 | "Press the Load button"; 45 | this.toolStripStatusLabel1.Text = ""; 46 | this.KeyPreview = true; 47 | this.KeyDown += new KeyEventHandler(Form1_KeyDown); 48 | 49 | QueryPerformanceFrequency(out pFreq); 50 | // Debug.WriteLine("PerformanceCounterFrequency: " + pFreq.ToString() + " Hz\n"); 51 | } 52 | 53 | private void Form1_KeyDown(object sender, KeyEventArgs e) 54 | { 55 | // TODO: Replace with Global Hotkey 56 | // https://social.msdn.microsoft.com/Forums/vstudio/en-US/c061954b-19bf-463b-a57d-b09c98a3fe7d/assign-global-hotkey-to-a-system-tray-application-in-c?forum=csharpgeneral 57 | 58 | if (e.KeyCode == Keys.F1) 59 | { 60 | buttonLog.PerformClick(); 61 | e.Handled = true; 62 | } 63 | if (e.KeyCode == Keys.F2) 64 | { 65 | buttonLog.PerformClick(); 66 | e.Handled = true; 67 | } 68 | else if (e.KeyCode == Keys.F3) 69 | { 70 | buttonPlot.PerformClick(); 71 | e.Handled = false; 72 | } 73 | } 74 | 75 | protected override void WndProc(ref Message m) 76 | { 77 | if (m.Msg == WM_INPUT) 78 | { 79 | #if true 80 | RAWINPUT raw = new RAWINPUT(); 81 | uint size = (uint)Marshal.SizeOf(typeof(RAWINPUT)); 82 | int outsize = GetRawInputData(m.LParam, RID_INPUT, out raw, ref size, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER))); 83 | if (outsize != -1) 84 | { 85 | if (raw.header.dwType == RIM_TYPEMOUSE) 86 | { 87 | QueryPerformanceCounter(out long pCounter); 88 | logMouseEvent(new MouseEvent(raw.data.mouse.buttonsStr.usButtonFlags, raw.data.mouse.lLastX, -(raw.data.mouse.lLastY), pCounter)); 89 | } 90 | } 91 | #else 92 | uint dwSize = 0; 93 | 94 | GetRawInputData(m.LParam, RID_INPUT, IntPtr.Zero, ref dwSize, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER))); 95 | 96 | IntPtr buffer = Marshal.AllocHGlobal((int)dwSize); 97 | try 98 | { 99 | if ((buffer != IntPtr.Zero) && 100 | (GetRawInputData(m.LParam, RID_INPUT, buffer, ref dwSize, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER))) == dwSize)) 101 | { 102 | RAWINPUT raw = (RAWINPUT)Marshal.PtrToStructure(buffer, typeof(RAWINPUT)); 103 | 104 | if (raw.header.dwType == RIM_TYPEMOUSE) 105 | { 106 | logMouseEvent(new MouseEvent(raw.data.mouse.buttonsStr.usButtonFlags, raw.data.mouse.lLastX, -(raw.data.mouse.lLastY), pCounter)); 107 | } 108 | } 109 | } 110 | finally 111 | { 112 | Marshal.FreeHGlobal(buffer); 113 | } 114 | #endif 115 | } 116 | base.WndProc(ref m); 117 | } 118 | 119 | private void logMouseEvent(MouseEvent mevent) 120 | { 121 | // Debug.WriteLine(mevent.pcounter + ", " + mevent.lastx + ", " + mevent.lasty + ", " + mevent.buttonflags); 122 | if (this.test_state == state.idle) 123 | { 124 | 125 | } 126 | else if (this.test_state == state.measure_wait) 127 | { 128 | if (mevent.buttonflags == 0x0001) 129 | { 130 | this.mlog.Add(mevent); 131 | this.toolStripStatusLabel1.Text = "Measuring"; 132 | this.test_state = state.measure; 133 | } 134 | } 135 | else if (this.test_state == state.measure) 136 | { 137 | this.mlog.Add(mevent); 138 | if (mevent.buttonflags == 0x0002) 139 | { 140 | double x = 0.0; 141 | double y = 0.0; 142 | foreach (MouseEvent e in this.mlog.Events) 143 | { 144 | x += (double)e.lastx; 145 | y += (double)e.lasty; 146 | } 147 | tsCalc(); 148 | this.mlog.Cpi = Math.Round(Math.Sqrt((x * x) + (y * y)) / (10 / 2.54)); 149 | this.textBoxCPI.Text = this.mlog.Cpi.ToString(); 150 | this.textBox1.Text = "Press the Collect or Log Start button\r\n"; 151 | this.toolStripStatusLabel1.Text = ""; 152 | this.test_state = state.idle; 153 | } 154 | } 155 | else if (this.test_state == state.collect_wait) 156 | { 157 | if (mevent.buttonflags == 0x0001) 158 | { 159 | this.mlog.Add(mevent); 160 | this.toolStripStatusLabel1.Text = "Collecting"; 161 | this.test_state = state.collect; 162 | } 163 | } 164 | else if (this.test_state == state.collect) 165 | { 166 | this.mlog.Add(mevent); 167 | if (mevent.buttonflags == 0x0002) 168 | { 169 | tsCalc(); 170 | this.textBox1.Text = "Press the plot button to view data\r\n" + 171 | " or\r\n" + 172 | "Press the save button to save log file\r\n" + 173 | "Events: " + this.mlog.Events.Count.ToString() + "\r\n" + 174 | "Sum X: " + this.mlog.deltaX().ToString() + " counts " + Math.Abs(this.mlog.deltaX() / this.mlog.Cpi * 2.54).ToString("0.0") + " cm\r\n" + 175 | "Sum Y: " + this.mlog.deltaY().ToString() + " counts " + Math.Abs(this.mlog.deltaY() / this.mlog.Cpi * 2.54).ToString("0.0") + " cm\r\n" + 176 | "Path: " + this.mlog.path().ToString("0") + " counts " + (this.mlog.path() / this.mlog.Cpi * 2.54).ToString("0.0") + " cm"; 177 | this.toolStripStatusLabel1.Text = ""; 178 | this.test_state = state.idle; 179 | } 180 | } 181 | else if (this.test_state == state.log) 182 | { 183 | this.mlog.Add(mevent); 184 | } 185 | } 186 | 187 | private void buttonMeasure_Click(object sender, EventArgs e) 188 | { 189 | if (this.test_state == state.idle) { 190 | this.textBox1.Text = "1. Press and hold the left mouse button\r\n" + 191 | "2. Move the mouse 10 cm in a straight line\r\n" + 192 | "3. Release the left mouse button\r\n"; 193 | this.toolStripStatusLabel1.Text = "Press the left mouse button"; 194 | this.mlog.Clear(); 195 | this.test_state = state.measure_wait; 196 | } 197 | } 198 | 199 | private void buttonCollect_Click(object sender, EventArgs e) 200 | { 201 | if (this.test_state == state.idle) 202 | { 203 | this.textBox1.Text = "1. Press and hold the left mouse button\r\n" + 204 | "2. Move the mouse\r\n" + 205 | "3. Release the left mouse button\r\n"; 206 | this.toolStripStatusLabel1.Text = "Press the left mouse button"; 207 | this.mlog.Clear(); 208 | this.test_state = state.collect_wait; 209 | } 210 | } 211 | 212 | private void buttonLog_Click(object sender, EventArgs e) 213 | { 214 | if (this.test_state == state.idle) 215 | { 216 | this.textBox1.Text = "1. Press the Log Stop button\r\n"; 217 | this.toolStripStatusLabel1.Text = "Logging..."; 218 | this.mlog.Clear(); 219 | this.test_state = state.log; 220 | buttonLog.Text = "Stop (F2)"; 221 | } 222 | else if (this.test_state == state.log) 223 | { 224 | tsCalc(); 225 | this.textBox1.Text = "Press the plot button to view data\r\n" + 226 | " or\r\n" + 227 | "Press the save button to save log file\r\n" + 228 | "Events: " + this.mlog.Events.Count.ToString() + "\r\n" + 229 | "Sum X: " + this.mlog.deltaX().ToString() + " counts " + Math.Abs(this.mlog.deltaX() / this.mlog.Cpi * 2.54).ToString("0.0") + " cm\r\n" + 230 | "Sum Y: " + this.mlog.deltaY().ToString() + " counts " + Math.Abs(this.mlog.deltaY() / this.mlog.Cpi * 2.54).ToString("0.0") + " cm\r\n" + 231 | "Path: " + this.mlog.path().ToString("0") + " counts " + (this.mlog.path() / this.mlog.Cpi * 2.54).ToString("0.0") + " cm"; 232 | this.toolStripStatusLabel1.Text = ""; 233 | this.test_state = state.idle; 234 | buttonLog.Text = "Start (F1)"; 235 | } 236 | } 237 | 238 | private void buttonPlot_Click(object sender, EventArgs e) 239 | { 240 | if (this.mlog.Events.Count > 0) 241 | { 242 | this.mlog.Desc = textBoxDesc.Text; 243 | MousePlot mousePlot = new MousePlot(this.mlog); 244 | mousePlot.Show(); 245 | } 246 | } 247 | 248 | private void buttonLoad_Click(object sender, EventArgs e) 249 | { 250 | OpenFileDialog openFileDialog1 = new OpenFileDialog(); 251 | openFileDialog1.Filter = "CSV Files (*.csv)|*.csv|All Files(*.*)|*.*"; 252 | openFileDialog1.FilterIndex = 1; 253 | openFileDialog1.Multiselect = false; 254 | if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK) 255 | { 256 | this.mlog.Load(openFileDialog1.FileName); 257 | } 258 | this.textBox1.Text = "Events: " + this.mlog.Events.Count.ToString() + "\r\n" + 259 | "Sum X: " + this.mlog.deltaX().ToString() + " counts " + Math.Abs(this.mlog.deltaX() / this.mlog.Cpi * 2.54).ToString("0.0") + " cm\r\n" + 260 | "Sum Y: " + this.mlog.deltaY().ToString() + " counts " + Math.Abs(this.mlog.deltaY() / this.mlog.Cpi * 2.54).ToString("0.0") + " cm\r\n" + 261 | "Path: " + this.mlog.path().ToString("0") + " counts " + (this.mlog.path() / this.mlog.Cpi * 2.54).ToString("0.0") + " cm"; 262 | this.textBoxDesc.Text = this.mlog.Desc.ToString(); 263 | this.textBoxCPI.Text = this.mlog.Cpi.ToString(); 264 | if (this.mlog.Events.Count > 0) 265 | { 266 | MousePlot mousePlot = new MousePlot(this.mlog); 267 | mousePlot.Show(); 268 | } 269 | } 270 | 271 | private void buttonSave_Click(object sender, EventArgs e) 272 | { 273 | SaveFileDialog saveFileDialog1 = new SaveFileDialog(); 274 | saveFileDialog1.Filter = "CSV Files (*.csv)|*.csv|All Files(*.*)|*.*"; 275 | saveFileDialog1.FilterIndex = 1; 276 | if (saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK) 277 | { 278 | this.mlog.Desc = textBoxDesc.Text; 279 | this.mlog.Save(saveFileDialog1.FileName); 280 | } 281 | } 282 | 283 | private void textBoxCPI_Validated(object sender, EventArgs e) 284 | { 285 | try 286 | { 287 | this.mlog.Cpi = double.Parse(this.textBoxCPI.Text); 288 | } 289 | catch //(Exception ex) 290 | { 291 | MessageBox.Show("Invalid CPI, resetting to previous value"); 292 | this.textBoxCPI.Text = this.mlog.Cpi.ToString(); 293 | } 294 | this.textBox1.Text = "Press the Collect or Log Start button\r\n"; 295 | } 296 | 297 | private void tsCalc() 298 | { 299 | long pcounter_min = this.mlog.Events[0].pcounter; 300 | foreach (MouseEvent me in this.mlog.Events) 301 | { 302 | me.ts = (me.pcounter - pcounter_min) * 1000.0 / pFreq; 303 | } 304 | } 305 | } 306 | } 307 | -------------------------------------------------------------------------------- /MouseTester/MouseTester/Form1.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | -------------------------------------------------------------------------------- /MouseTester/MouseTester/GraphicsRenderContext.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // The MIT License (MIT) 4 | // 5 | // Copyright (c) 2012 Oystein Bjorke 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a 8 | // copy of this software and associated documentation files (the 9 | // "Software"), to deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, merge, publish, 11 | // distribute, sublicense, and/or sell copies of the Software, and to 12 | // permit persons to whom the Software is furnished to do so, subject to 13 | // the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included 16 | // in all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | // 26 | // 27 | // The graphics render context. 28 | // 29 | // -------------------------------------------------------------------------------------------------------------------- 30 | namespace OxyPlot.WindowsForms 31 | { 32 | using System; 33 | using System.Collections.Generic; 34 | using System.Drawing; 35 | using System.Drawing.Drawing2D; 36 | using System.Drawing.Imaging; 37 | using System.IO; 38 | using System.Linq; 39 | 40 | using OxyPlot; 41 | 42 | /// 43 | /// The graphics render context. 44 | /// 45 | internal class GraphicsRenderContext : RenderContextBase 46 | { 47 | /// 48 | /// The font size factor. 49 | /// 50 | private const float FontsizeFactor = 0.8f; 51 | 52 | /// 53 | /// The GDI+ drawing surface. 54 | /// 55 | private Graphics g; 56 | 57 | /// 58 | /// Initializes a new instance of the class. 59 | /// 60 | public GraphicsRenderContext() 61 | { 62 | } 63 | 64 | /// 65 | /// Sets the graphics target. 66 | /// 67 | /// The graphics surface. 68 | public void SetGraphicsTarget(Graphics graphics) 69 | { 70 | this.g = graphics; 71 | this.g.CompositingMode = CompositingMode.SourceOver; 72 | this.g.CompositingQuality = CompositingQuality.HighQuality; 73 | this.g.InterpolationMode = InterpolationMode.HighQualityBicubic; 74 | this.g.PixelOffsetMode = PixelOffsetMode.HighQuality; 75 | this.g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; 76 | this.g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit; 77 | } 78 | 79 | /// 80 | /// Draws the ellipse. 81 | /// 82 | /// The rect. 83 | /// The fill. 84 | /// The stroke. 85 | /// The thickness. 86 | public override void DrawEllipse(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness) 87 | { 88 | if (fill != null) 89 | { 90 | this.g.FillEllipse( 91 | this.ToBrush(fill), (float)rect.Left, (float)rect.Top, (float)rect.Width, (float)rect.Height); 92 | } 93 | 94 | if (stroke == null || thickness <= 0) 95 | { 96 | return; 97 | } 98 | 99 | using (var pen = new Pen(this.ToColor(stroke), (float)thickness)) 100 | { 101 | this.g.SmoothingMode = SmoothingMode.HighQuality; 102 | this.g.DrawEllipse(pen, (float)rect.Left, (float)rect.Top, (float)rect.Width, (float)rect.Height); 103 | } 104 | } 105 | 106 | /// 107 | /// Draws the line. 108 | /// 109 | /// The points. 110 | /// The stroke. 111 | /// The thickness. 112 | /// The dash array. 113 | /// The line join. 114 | /// if set to true [aliased]. 115 | public override void DrawLine( 116 | IList points, 117 | OxyColor stroke, 118 | double thickness, 119 | double[] dashArray, 120 | OxyPenLineJoin lineJoin, 121 | bool aliased) 122 | { 123 | if (stroke == null || thickness <= 0 || points.Count < 2) 124 | { 125 | return; 126 | } 127 | 128 | this.g.SmoothingMode = aliased ? SmoothingMode.None : SmoothingMode.HighQuality; 129 | using (var pen = new Pen(this.ToColor(stroke), (float)thickness)) 130 | { 131 | 132 | if (dashArray != null) 133 | { 134 | pen.DashPattern = this.ToFloatArray(dashArray); 135 | } 136 | 137 | switch (lineJoin) 138 | { 139 | case OxyPenLineJoin.Round: 140 | pen.LineJoin = LineJoin.Round; 141 | break; 142 | case OxyPenLineJoin.Bevel: 143 | pen.LineJoin = LineJoin.Bevel; 144 | break; 145 | 146 | // The default LineJoin is Miter 147 | } 148 | 149 | this.g.DrawLines(pen, this.ToPoints(points)); 150 | } 151 | } 152 | 153 | /// 154 | /// Draws the polygon. 155 | /// 156 | /// The points. 157 | /// The fill. 158 | /// The stroke. 159 | /// The thickness. 160 | /// The dash array. 161 | /// The line join. 162 | /// if set to true [aliased]. 163 | public override void DrawPolygon( 164 | IList points, 165 | OxyColor fill, 166 | OxyColor stroke, 167 | double thickness, 168 | double[] dashArray, 169 | OxyPenLineJoin lineJoin, 170 | bool aliased) 171 | { 172 | if (points.Count < 2) 173 | { 174 | return; 175 | } 176 | 177 | this.g.SmoothingMode = aliased ? SmoothingMode.None : SmoothingMode.HighQuality; 178 | 179 | PointF[] pts = this.ToPoints(points); 180 | if (fill != null) 181 | { 182 | this.g.FillPolygon(this.ToBrush(fill), pts); 183 | } 184 | 185 | if (stroke != null && thickness > 0) 186 | { 187 | using (var pen = new Pen(this.ToColor(stroke), (float)thickness)) 188 | { 189 | 190 | if (dashArray != null) 191 | { 192 | pen.DashPattern = this.ToFloatArray(dashArray); 193 | } 194 | 195 | switch (lineJoin) 196 | { 197 | case OxyPenLineJoin.Round: 198 | pen.LineJoin = LineJoin.Round; 199 | break; 200 | case OxyPenLineJoin.Bevel: 201 | pen.LineJoin = LineJoin.Bevel; 202 | break; 203 | 204 | // The default LineJoin is Miter 205 | } 206 | 207 | this.g.DrawPolygon(pen, pts); 208 | } 209 | } 210 | } 211 | 212 | /// 213 | /// The draw rectangle. 214 | /// 215 | /// 216 | /// The rect. 217 | /// 218 | /// 219 | /// The fill. 220 | /// 221 | /// 222 | /// The stroke. 223 | /// 224 | /// 225 | /// The thickness. 226 | /// 227 | public override void DrawRectangle(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness) 228 | { 229 | if (fill != null) 230 | { 231 | this.g.FillRectangle( 232 | this.ToBrush(fill), (float)rect.Left, (float)rect.Top, (float)rect.Width, (float)rect.Height); 233 | } 234 | 235 | if (stroke == null || thickness <= 0) 236 | { 237 | return; 238 | } 239 | 240 | using (var pen = new Pen(this.ToColor(stroke), (float)thickness)) 241 | { 242 | this.g.DrawRectangle(pen, (float)rect.Left, (float)rect.Top, (float)rect.Width, (float)rect.Height); 243 | } 244 | } 245 | 246 | /// 247 | /// The draw text. 248 | /// 249 | /// 250 | /// The p. 251 | /// 252 | /// 253 | /// The text. 254 | /// 255 | /// 256 | /// The fill. 257 | /// 258 | /// 259 | /// The font family. 260 | /// 261 | /// 262 | /// The font size. 263 | /// 264 | /// 265 | /// The font weight. 266 | /// 267 | /// 268 | /// The rotate. 269 | /// 270 | /// 271 | /// The halign. 272 | /// 273 | /// 274 | /// The valign. 275 | /// 276 | /// 277 | /// The maximum size of the text. 278 | /// 279 | public override void DrawText( 280 | ScreenPoint p, 281 | string text, 282 | OxyColor fill, 283 | string fontFamily, 284 | double fontSize, 285 | double fontWeight, 286 | double rotate, 287 | HorizontalAlignment halign, 288 | VerticalAlignment valign, 289 | OxySize? maxSize) 290 | { 291 | var fs = FontStyle.Regular; 292 | if (fontWeight >= 700) 293 | { 294 | fs = FontStyle.Bold; 295 | } 296 | 297 | using (var font = new Font(fontFamily, (float)fontSize * FontsizeFactor, fs)) 298 | { 299 | using (var sf = new StringFormat { Alignment = StringAlignment.Near }) 300 | { 301 | var size = this.g.MeasureString(text, font); 302 | if (maxSize != null) 303 | { 304 | if (size.Width > maxSize.Value.Width) 305 | { 306 | size.Width = (float)maxSize.Value.Width; 307 | } 308 | 309 | if (size.Height > maxSize.Value.Height) 310 | { 311 | size.Height = (float)maxSize.Value.Height; 312 | } 313 | } 314 | 315 | float dx = 0; 316 | if (halign == HorizontalAlignment.Center) 317 | { 318 | dx = -size.Width / 2; 319 | } 320 | 321 | if (halign == HorizontalAlignment.Right) 322 | { 323 | dx = -size.Width; 324 | } 325 | 326 | float dy = 0; 327 | sf.LineAlignment = StringAlignment.Near; 328 | if (valign == VerticalAlignment.Middle) 329 | { 330 | dy = -size.Height / 2; 331 | } 332 | 333 | if (valign == VerticalAlignment.Bottom) 334 | { 335 | dy = -size.Height; 336 | } 337 | 338 | this.g.TranslateTransform((float)p.X, (float)p.Y); 339 | if (Math.Abs(rotate) > double.Epsilon) 340 | { 341 | this.g.RotateTransform((float)rotate); 342 | } 343 | 344 | this.g.TranslateTransform(dx, dy); 345 | 346 | var layoutRectangle = new RectangleF(0, 0, size.Width, size.Height); 347 | this.g.DrawString(text, font, this.ToBrush(fill), layoutRectangle, sf); 348 | 349 | this.g.ResetTransform(); 350 | } 351 | } 352 | } 353 | 354 | /// 355 | /// The measure text. 356 | /// 357 | /// The text. 358 | /// The font family. 359 | /// The font size. 360 | /// The font weight. 361 | /// The size of the text. 362 | public override OxySize MeasureText(string text, string fontFamily, double fontSize, double fontWeight) 363 | { 364 | if (text == null) 365 | { 366 | return OxySize.Empty; 367 | } 368 | 369 | var fs = FontStyle.Regular; 370 | if (fontWeight >= 700) 371 | { 372 | fs = FontStyle.Bold; 373 | } 374 | 375 | using (var font = new Font(fontFamily, (float)fontSize * FontsizeFactor, fs)) 376 | { 377 | var size = this.g.MeasureString(text, font); 378 | return new OxySize(size.Width, size.Height); 379 | } 380 | } 381 | 382 | /// 383 | /// Converts a fill color to a System.Drawing.Brush. 384 | /// 385 | /// 386 | /// The fill color. 387 | /// 388 | /// 389 | /// The brush. 390 | /// 391 | private Brush ToBrush(OxyColor fill) 392 | { 393 | if (fill != null) 394 | { 395 | return new SolidBrush(this.ToColor(fill)); 396 | } 397 | 398 | return null; 399 | } 400 | 401 | /// 402 | /// Converts a color to a System.Drawing.Color. 403 | /// 404 | /// 405 | /// The color. 406 | /// 407 | /// 408 | /// The System.Drawing.Color. 409 | /// 410 | private Color ToColor(OxyColor c) 411 | { 412 | return Color.FromArgb(c.A, c.R, c.G, c.B); 413 | } 414 | 415 | /// 416 | /// Converts a double array to a float array. 417 | /// 418 | /// 419 | /// The a. 420 | /// 421 | /// 422 | /// The float array. 423 | /// 424 | private float[] ToFloatArray(double[] a) 425 | { 426 | if (a == null) 427 | { 428 | return null; 429 | } 430 | 431 | var r = new float[a.Length]; 432 | for (int i = 0; i < a.Length; i++) 433 | { 434 | r[i] = (float)a[i]; 435 | } 436 | 437 | return r; 438 | } 439 | 440 | /// 441 | /// Converts a list of point to an array of PointF. 442 | /// 443 | /// 444 | /// The points. 445 | /// 446 | /// 447 | /// An array of points. 448 | /// 449 | private PointF[] ToPoints(IList points) 450 | { 451 | if (points == null) 452 | { 453 | return null; 454 | } 455 | 456 | var r = new PointF[points.Count()]; 457 | int i = 0; 458 | foreach (ScreenPoint p in points) 459 | { 460 | r[i++] = new PointF((float)p.X, (float)p.Y); 461 | } 462 | 463 | return r; 464 | } 465 | 466 | public override void CleanUp() 467 | { 468 | var imagesToRelease = imageCache.Keys.Where(i => !imagesInUse.Contains(i)); 469 | foreach (var i in imagesToRelease) 470 | { 471 | var image = this.GetImage(i); 472 | image.Dispose(); 473 | imageCache.Remove(i); 474 | } 475 | 476 | imagesInUse.Clear(); 477 | } 478 | 479 | public override OxyImageInfo GetImageInfo(OxyImage source) 480 | { 481 | var image = this.GetImage(source); 482 | return image == null ? null : new OxyImageInfo { Width = (uint)image.Width, Height = (uint)image.Height, DpiX = image.HorizontalResolution, DpiY = image.VerticalResolution }; 483 | } 484 | 485 | public override void DrawImage(OxyImage source, uint srcX, uint srcY, uint srcWidth, uint srcHeight, double x, double y, double w, double h, double opacity, bool interpolate) 486 | { 487 | var image = this.GetImage(source); 488 | if (image != null) 489 | { 490 | ImageAttributes ia = null; 491 | if (opacity < 1) 492 | { 493 | var cm = new ColorMatrix 494 | { 495 | Matrix00 = 1f, 496 | Matrix11 = 1f, 497 | Matrix22 = 1f, 498 | Matrix33 = 1f, 499 | Matrix44 = (float)opacity 500 | }; 501 | 502 | ia = new ImageAttributes(); 503 | ia.SetColorMatrix(cm, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); 504 | } 505 | 506 | g.InterpolationMode = interpolate ? InterpolationMode.HighQualityBicubic : InterpolationMode.NearestNeighbor; 507 | int sx = (int)Math.Round(x); 508 | int sy = (int)Math.Round(y); 509 | int sw = (int)Math.Round(x + w) - sx; 510 | int sh = (int)Math.Round(y + h) - sy; 511 | g.DrawImage(image, new Rectangle(sx, sy, sw, sh), srcX, srcY, srcWidth, srcHeight, GraphicsUnit.Pixel, ia); 512 | } 513 | } 514 | 515 | private HashSet imagesInUse = new HashSet(); 516 | 517 | private Dictionary imageCache = new Dictionary(); 518 | 519 | 520 | private Image GetImage(OxyImage source) 521 | { 522 | if (source == null) 523 | { 524 | return null; 525 | } 526 | 527 | if (!this.imagesInUse.Contains(source)) 528 | { 529 | this.imagesInUse.Add(source); 530 | } 531 | 532 | Image src; 533 | if (this.imageCache.TryGetValue(source, out src)) 534 | { 535 | return src; 536 | } 537 | 538 | if (source != null) 539 | { 540 | Image btm; 541 | using (var ms = new MemoryStream(source.GetData())) 542 | { 543 | btm = Image.FromStream(ms); 544 | } 545 | 546 | this.imageCache.Add(source, btm); 547 | return btm; 548 | } 549 | 550 | return null; 551 | } 552 | 553 | public override bool SetClip(OxyRect rect) 554 | { 555 | this.g.SetClip(rect.ToRect(false)); 556 | return true; 557 | } 558 | 559 | public override void ResetClip() 560 | { 561 | this.g.ResetClip(); 562 | } 563 | } 564 | } -------------------------------------------------------------------------------- /MouseTester/MouseTester/MouseEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace MouseTester 7 | { 8 | public class MouseEvent 9 | { 10 | public ushort buttonflags; 11 | public int lastx; 12 | public int lasty; 13 | public long pcounter; 14 | public double ts; 15 | 16 | public MouseEvent(ushort buttonflags, int lastx, int lasty, long pcounter) 17 | { 18 | this.buttonflags = buttonflags; 19 | this.lastx = lastx; 20 | this.lasty = lasty; 21 | this.pcounter = pcounter; 22 | this.ts = 0.0; 23 | } 24 | public MouseEvent(ushort buttonflags, int lastx, int lasty, double ts) 25 | { 26 | this.buttonflags = buttonflags; 27 | this.lastx = lastx; 28 | this.lasty = lasty; 29 | this.pcounter = 0; 30 | this.ts = ts; 31 | } 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /MouseTester/MouseTester/MouseLog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Globalization; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace MouseTester 10 | { 11 | public class MouseLog 12 | { 13 | private string desc = "MouseTester"; 14 | private double cpi = 400.0; 15 | private List events = new List(); 16 | 17 | public double Cpi 18 | { 19 | get 20 | { 21 | return this.cpi; 22 | } 23 | set 24 | { 25 | cpi = value; 26 | } 27 | } 28 | 29 | public string Desc 30 | { 31 | get 32 | { 33 | return this.desc; 34 | } 35 | set 36 | { 37 | this.desc = value; 38 | } 39 | } 40 | 41 | public List Events 42 | { 43 | get 44 | { 45 | return this.events; 46 | } 47 | } 48 | 49 | public void Add(MouseEvent e) 50 | { 51 | this.events.Add(e); 52 | } 53 | 54 | public void Clear() 55 | { 56 | this.events.Clear(); 57 | } 58 | 59 | public void Load(string fname) 60 | { 61 | this.Clear(); 62 | 63 | try 64 | { 65 | using (StreamReader sr = File.OpenText(fname)) 66 | { 67 | this.desc = sr.ReadLine(); 68 | this.cpi = double.Parse(sr.ReadLine()); 69 | string headerline = sr.ReadLine(); 70 | while (sr.Peek() > -1) 71 | { 72 | string line = sr.ReadLine(); 73 | string[] values = line.Split(','); 74 | if (values.Length == 4) 75 | { 76 | this.Add(new MouseEvent(ushort.Parse(values[3]), int.Parse(values[0]), int.Parse(values[1]), double.Parse(values[2]))); 77 | } 78 | else if (values.Length == 3) 79 | { 80 | this.Add(new MouseEvent(0, int.Parse(values[0]), int.Parse(values[1]), double.Parse(values[2]))); 81 | } 82 | } 83 | } 84 | } 85 | catch (Exception ex) 86 | { 87 | Debug.WriteLine(ex.ToString()); 88 | } 89 | } 90 | 91 | public void Save(string fname) 92 | { 93 | try 94 | { 95 | using (StreamWriter sw = File.CreateText(fname)) 96 | { 97 | sw.WriteLine(this.desc); 98 | sw.WriteLine(this.cpi.ToString()); 99 | sw.WriteLine("xCount,yCount,Time (ms),buttonflags"); 100 | foreach (MouseEvent e in this.events) 101 | { 102 | sw.WriteLine(e.lastx.ToString() + "," + e.lasty.ToString() + "," + e.ts.ToString(CultureInfo.InvariantCulture) + "," + e.buttonflags.ToString()); 103 | } 104 | } 105 | } 106 | catch (Exception ex) 107 | { 108 | Debug.WriteLine(ex.ToString()); 109 | } 110 | } 111 | 112 | public int deltaX() 113 | { 114 | return this.events.Sum(e => e.lastx); 115 | } 116 | 117 | public int deltaY() 118 | { 119 | return this.events.Sum(e => e.lasty); 120 | } 121 | 122 | public double path() 123 | { 124 | return this.events.Sum(e => Math.Sqrt((e.lastx * e.lastx) + (e.lasty * e.lasty))); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /MouseTester/MouseTester/MousePlot.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace MouseTester 2 | { 3 | partial class MousePlot 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.splitContainer1 = new System.Windows.Forms.SplitContainer(); 32 | this.plot1 = new OxyPlot.WindowsForms.Plot(); 33 | this.checkBoxStem = new System.Windows.Forms.CheckBox(); 34 | this.buttonSavePNG = new System.Windows.Forms.Button(); 35 | this.groupBox3 = new System.Windows.Forms.GroupBox(); 36 | this.numericUpDownEnd = new System.Windows.Forms.NumericUpDown(); 37 | this.groupBox2 = new System.Windows.Forms.GroupBox(); 38 | this.numericUpDownStart = new System.Windows.Forms.NumericUpDown(); 39 | this.groupBox1 = new System.Windows.Forms.GroupBox(); 40 | this.comboBoxPlotType = new System.Windows.Forms.ComboBox(); 41 | this.checkBoxLines = new System.Windows.Forms.CheckBox(); 42 | ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); 43 | this.splitContainer1.Panel1.SuspendLayout(); 44 | this.splitContainer1.Panel2.SuspendLayout(); 45 | this.splitContainer1.SuspendLayout(); 46 | this.groupBox3.SuspendLayout(); 47 | ((System.ComponentModel.ISupportInitialize)(this.numericUpDownEnd)).BeginInit(); 48 | this.groupBox2.SuspendLayout(); 49 | ((System.ComponentModel.ISupportInitialize)(this.numericUpDownStart)).BeginInit(); 50 | this.groupBox1.SuspendLayout(); 51 | this.SuspendLayout(); 52 | // 53 | // splitContainer1 54 | // 55 | this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; 56 | this.splitContainer1.Location = new System.Drawing.Point(0, 0); 57 | this.splitContainer1.Name = "splitContainer1"; 58 | this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal; 59 | // 60 | // splitContainer1.Panel1 61 | // 62 | this.splitContainer1.Panel1.Controls.Add(this.plot1); 63 | // 64 | // splitContainer1.Panel2 65 | // 66 | this.splitContainer1.Panel2.Controls.Add(this.checkBoxLines); 67 | this.splitContainer1.Panel2.Controls.Add(this.checkBoxStem); 68 | this.splitContainer1.Panel2.Controls.Add(this.buttonSavePNG); 69 | this.splitContainer1.Panel2.Controls.Add(this.groupBox3); 70 | this.splitContainer1.Panel2.Controls.Add(this.groupBox2); 71 | this.splitContainer1.Panel2.Controls.Add(this.groupBox1); 72 | this.splitContainer1.Size = new System.Drawing.Size(800, 677); 73 | this.splitContainer1.SplitterDistance = 600; 74 | this.splitContainer1.TabIndex = 0; 75 | // 76 | // plot1 77 | // 78 | this.plot1.BackColor = System.Drawing.Color.White; 79 | this.plot1.Dock = System.Windows.Forms.DockStyle.Fill; 80 | this.plot1.KeyboardPanHorizontalStep = 0.1D; 81 | this.plot1.KeyboardPanVerticalStep = 0.1D; 82 | this.plot1.Location = new System.Drawing.Point(0, 0); 83 | this.plot1.Name = "plot1"; 84 | this.plot1.PanCursor = System.Windows.Forms.Cursors.Hand; 85 | this.plot1.Size = new System.Drawing.Size(800, 600); 86 | this.plot1.TabIndex = 0; 87 | this.plot1.Text = "plot1"; 88 | this.plot1.ZoomHorizontalCursor = System.Windows.Forms.Cursors.SizeWE; 89 | this.plot1.ZoomRectangleCursor = System.Windows.Forms.Cursors.SizeNWSE; 90 | this.plot1.ZoomVerticalCursor = System.Windows.Forms.Cursors.SizeNS; 91 | // 92 | // checkBoxStem 93 | // 94 | this.checkBoxStem.AutoSize = true; 95 | this.checkBoxStem.Location = new System.Drawing.Point(510, 40); 96 | this.checkBoxStem.Name = "checkBoxStem"; 97 | this.checkBoxStem.Size = new System.Drawing.Size(50, 17); 98 | this.checkBoxStem.TabIndex = 8; 99 | this.checkBoxStem.Text = "Stem"; 100 | this.checkBoxStem.UseVisualStyleBackColor = true; 101 | // 102 | // buttonSavePNG 103 | // 104 | this.buttonSavePNG.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 105 | this.buttonSavePNG.Location = new System.Drawing.Point(713, 24); 106 | this.buttonSavePNG.Name = "buttonSavePNG"; 107 | this.buttonSavePNG.Size = new System.Drawing.Size(75, 23); 108 | this.buttonSavePNG.TabIndex = 7; 109 | this.buttonSavePNG.Text = "SavePNG"; 110 | this.buttonSavePNG.UseVisualStyleBackColor = true; 111 | this.buttonSavePNG.Click += new System.EventHandler(this.buttonSavePNG_Click); 112 | // 113 | // groupBox3 114 | // 115 | this.groupBox3.Controls.Add(this.numericUpDownEnd); 116 | this.groupBox3.Location = new System.Drawing.Point(369, 7); 117 | this.groupBox3.Name = "groupBox3"; 118 | this.groupBox3.Size = new System.Drawing.Size(135, 50); 119 | this.groupBox3.TabIndex = 6; 120 | this.groupBox3.TabStop = false; 121 | this.groupBox3.Text = "Data Point End"; 122 | // 123 | // numericUpDownEnd 124 | // 125 | this.numericUpDownEnd.Location = new System.Drawing.Point(6, 20); 126 | this.numericUpDownEnd.Name = "numericUpDownEnd"; 127 | this.numericUpDownEnd.Size = new System.Drawing.Size(120, 20); 128 | this.numericUpDownEnd.TabIndex = 2; 129 | // 130 | // groupBox2 131 | // 132 | this.groupBox2.Controls.Add(this.numericUpDownStart); 133 | this.groupBox2.Location = new System.Drawing.Point(228, 7); 134 | this.groupBox2.Name = "groupBox2"; 135 | this.groupBox2.Size = new System.Drawing.Size(135, 50); 136 | this.groupBox2.TabIndex = 5; 137 | this.groupBox2.TabStop = false; 138 | this.groupBox2.Text = "Data Point Start"; 139 | // 140 | // numericUpDownStart 141 | // 142 | this.numericUpDownStart.Location = new System.Drawing.Point(6, 20); 143 | this.numericUpDownStart.Name = "numericUpDownStart"; 144 | this.numericUpDownStart.Size = new System.Drawing.Size(120, 20); 145 | this.numericUpDownStart.TabIndex = 3; 146 | // 147 | // groupBox1 148 | // 149 | this.groupBox1.Controls.Add(this.comboBoxPlotType); 150 | this.groupBox1.Location = new System.Drawing.Point(12, 7); 151 | this.groupBox1.Name = "groupBox1"; 152 | this.groupBox1.Size = new System.Drawing.Size(210, 50); 153 | this.groupBox1.TabIndex = 4; 154 | this.groupBox1.TabStop = false; 155 | this.groupBox1.Text = "Plot Type"; 156 | // 157 | // comboBoxPlotType 158 | // 159 | this.comboBoxPlotType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 160 | this.comboBoxPlotType.FormattingEnabled = true; 161 | this.comboBoxPlotType.Items.AddRange(new object[] { 162 | "xCount vs. Time", 163 | "yCount vs. Time", 164 | "xyCount vs. Time", 165 | "Interval vs. Time", 166 | "xVelocity vs. Time", 167 | "yVelocity vs. Time", 168 | "xyVelocity vs. Time", 169 | "X vs. Y"}); 170 | this.comboBoxPlotType.Location = new System.Drawing.Point(6, 19); 171 | this.comboBoxPlotType.Name = "comboBoxPlotType"; 172 | this.comboBoxPlotType.Size = new System.Drawing.Size(200, 21); 173 | this.comboBoxPlotType.TabIndex = 1; 174 | // 175 | // checkBoxLines 176 | // 177 | this.checkBoxLines.AutoSize = true; 178 | this.checkBoxLines.Location = new System.Drawing.Point(510, 17); 179 | this.checkBoxLines.Name = "checkBoxLines"; 180 | this.checkBoxLines.Size = new System.Drawing.Size(51, 17); 181 | this.checkBoxLines.TabIndex = 9; 182 | this.checkBoxLines.Text = "Lines"; 183 | this.checkBoxLines.UseVisualStyleBackColor = true; 184 | // 185 | // MousePlot 186 | // 187 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 188 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 189 | this.ClientSize = new System.Drawing.Size(800, 677); 190 | this.Controls.Add(this.splitContainer1); 191 | this.MinimumSize = new System.Drawing.Size(808, 627); 192 | this.Name = "MousePlot"; 193 | this.Text = "MousePlot"; 194 | this.splitContainer1.Panel1.ResumeLayout(false); 195 | this.splitContainer1.Panel2.ResumeLayout(false); 196 | this.splitContainer1.Panel2.PerformLayout(); 197 | ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); 198 | this.splitContainer1.ResumeLayout(false); 199 | this.groupBox3.ResumeLayout(false); 200 | ((System.ComponentModel.ISupportInitialize)(this.numericUpDownEnd)).EndInit(); 201 | this.groupBox2.ResumeLayout(false); 202 | ((System.ComponentModel.ISupportInitialize)(this.numericUpDownStart)).EndInit(); 203 | this.groupBox1.ResumeLayout(false); 204 | this.ResumeLayout(false); 205 | 206 | } 207 | 208 | #endregion 209 | 210 | private System.Windows.Forms.SplitContainer splitContainer1; 211 | private OxyPlot.WindowsForms.Plot plot1; 212 | private System.Windows.Forms.ComboBox comboBoxPlotType; 213 | private System.Windows.Forms.NumericUpDown numericUpDownStart; 214 | private System.Windows.Forms.NumericUpDown numericUpDownEnd; 215 | private System.Windows.Forms.GroupBox groupBox3; 216 | private System.Windows.Forms.GroupBox groupBox2; 217 | private System.Windows.Forms.GroupBox groupBox1; 218 | private System.Windows.Forms.Button buttonSavePNG; 219 | private System.Windows.Forms.CheckBox checkBoxStem; 220 | private System.Windows.Forms.CheckBox checkBoxLines; 221 | } 222 | } -------------------------------------------------------------------------------- /MouseTester/MouseTester/MousePlot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using OxyPlot; 10 | 11 | namespace MouseTester 12 | { 13 | using System.Drawing; 14 | using System.Drawing.Imaging; 15 | using OxyPlot.WindowsForms; 16 | using OxyPlot.Annotations; 17 | using OxyPlot.Axes; 18 | using OxyPlot.Series; 19 | 20 | public partial class MousePlot : Form 21 | { 22 | private MouseLog mlog; 23 | private int last_start; 24 | private int last_end; 25 | double x_min; 26 | double x_max; 27 | double y_min; 28 | double y_max; 29 | private string xlabel = ""; 30 | private string ylabel = ""; 31 | 32 | public MousePlot(MouseLog Mlog) 33 | { 34 | InitializeComponent(); 35 | this.mlog = new MouseLog(); 36 | this.mlog.Desc = Mlog.Desc; 37 | this.mlog.Cpi = Mlog.Cpi; 38 | int i = 1; 39 | int x = Mlog.Events[0].lastx; 40 | int y = Mlog.Events[0].lasty; 41 | ushort buttonflags = Mlog.Events[0].buttonflags; 42 | double ts = Mlog.Events[0].ts; 43 | while (i < Mlog.Events.Count) 44 | { 45 | this.mlog.Add(new MouseEvent(buttonflags, x, y, ts)); 46 | x = Mlog.Events[i].lastx; 47 | y = Mlog.Events[i].lasty; 48 | buttonflags = Mlog.Events[i].buttonflags; 49 | ts = Mlog.Events[i].ts; 50 | i++; 51 | } 52 | this.mlog.Add(new MouseEvent(buttonflags, x, y, ts)); 53 | 54 | this.last_start = 0; 55 | this.last_end = this.mlog.Events.Count - 1; 56 | initialize_plot(); 57 | 58 | this.comboBoxPlotType.SelectedIndex = 0; 59 | this.comboBoxPlotType.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged); 60 | 61 | this.numericUpDownStart.Minimum = 0; 62 | this.numericUpDownStart.Maximum = this.mlog.Events.Count - 1; 63 | this.numericUpDownStart.Value = last_start; 64 | this.numericUpDownStart.ValueChanged += new System.EventHandler(this.numericUpDownStart_ValueChanged); 65 | 66 | this.numericUpDownEnd.Minimum = 0; 67 | this.numericUpDownEnd.Maximum = this.mlog.Events.Count - 1; 68 | this.numericUpDownEnd.Value = last_end; 69 | this.numericUpDownEnd.ValueChanged += new System.EventHandler(this.numericUpDownEnd_ValueChanged); 70 | 71 | this.checkBoxStem.Checked = false; 72 | this.checkBoxStem.CheckedChanged += new System.EventHandler(this.checkBoxStem_CheckedChanged); 73 | 74 | this.checkBoxLines.Checked = false; 75 | this.checkBoxLines.CheckedChanged += new System.EventHandler(this.checkBoxLines_CheckedChanged); 76 | 77 | refresh_plot(); 78 | } 79 | 80 | private void initialize_plot() 81 | { 82 | var pm = new PlotModel(this.mlog.Desc.ToString()) 83 | { 84 | PlotType = PlotType.Cartesian, 85 | Background = OxyColors.White, 86 | Subtitle = this.mlog.Cpi.ToString() + " cpi" 87 | }; 88 | plot1.Model = pm; 89 | } 90 | 91 | private void refresh_plot() 92 | { 93 | PlotModel pm = plot1.Model; 94 | pm.Series.Clear(); 95 | pm.Axes.Clear(); 96 | OxyColor singleLineColor = OxyColors.Green; 97 | 98 | var scatterSeries1 = new ScatterSeries 99 | { 100 | BinSize = 8, 101 | MarkerFill = OxyColors.Blue, 102 | MarkerSize = 1.5, 103 | MarkerStroke = OxyColors.Blue, 104 | MarkerStrokeThickness = 1.0, 105 | MarkerType = MarkerType.Circle 106 | }; 107 | 108 | var scatterSeries2 = new ScatterSeries 109 | { 110 | BinSize = 8, 111 | MarkerFill = OxyColors.Red, 112 | MarkerSize = 1.5, 113 | MarkerStroke = OxyColors.Red, 114 | MarkerStrokeThickness = 1.0, 115 | MarkerType = MarkerType.Circle 116 | }; 117 | 118 | var lineSeries1 = new LineSeries 119 | { 120 | Color = OxyColors.Blue, 121 | LineStyle = LineStyle.Solid, 122 | StrokeThickness = 2.0, 123 | Smooth = true 124 | }; 125 | 126 | var lineSeries2 = new LineSeries 127 | { 128 | Color = OxyColors.Red, 129 | LineStyle = LineStyle.Solid, 130 | StrokeThickness = 2.0, 131 | Smooth = true 132 | }; 133 | 134 | if (checkBoxLines.Checked) 135 | { 136 | lineSeries1.Smooth = false; 137 | lineSeries2.Smooth = false; 138 | } 139 | 140 | var stemSeries1 = new StemSeries 141 | { 142 | Color = OxyColors.Blue, 143 | StrokeThickness = 1.0, 144 | }; 145 | 146 | var stemSeries2 = new StemSeries 147 | { 148 | Color = OxyColors.Red, 149 | StrokeThickness = 1.0 150 | }; 151 | 152 | if (comboBoxPlotType.Text.Contains("xyCount")) 153 | { 154 | plot_xycounts_vs_time(scatterSeries1, scatterSeries2, stemSeries1, stemSeries2, lineSeries1, lineSeries2); 155 | pm.Series.Add(scatterSeries1); 156 | pm.Series.Add(scatterSeries2); 157 | if (!checkBoxLines.Checked) 158 | { 159 | plot_fit(scatterSeries1, lineSeries1); 160 | plot_fit(scatterSeries2, lineSeries2); 161 | } 162 | pm.Series.Add(lineSeries1); 163 | pm.Series.Add(lineSeries2); 164 | if (checkBoxStem.Checked) 165 | { 166 | pm.Series.Add(stemSeries1); 167 | pm.Series.Add(stemSeries2); 168 | } 169 | } 170 | else if (comboBoxPlotType.Text.Contains("xCount")) 171 | { 172 | plot_xcounts_vs_time(scatterSeries1, stemSeries1, lineSeries1); 173 | pm.Series.Add(scatterSeries1); 174 | if (!checkBoxLines.Checked) 175 | { 176 | plot_fit(scatterSeries1, lineSeries1); 177 | lineSeries1.Color = singleLineColor; 178 | } 179 | pm.Series.Add(lineSeries1); 180 | if (checkBoxStem.Checked) 181 | { 182 | pm.Series.Add(stemSeries1); 183 | } 184 | } 185 | else if (comboBoxPlotType.Text.Contains("yCount")) 186 | { 187 | plot_ycounts_vs_time(scatterSeries1, stemSeries1, lineSeries1); 188 | pm.Series.Add(scatterSeries1); 189 | if (!checkBoxLines.Checked) 190 | { 191 | plot_fit(scatterSeries1, lineSeries1); 192 | lineSeries1.Color = singleLineColor; 193 | } 194 | pm.Series.Add(lineSeries1); 195 | if (checkBoxStem.Checked) 196 | { 197 | pm.Series.Add(stemSeries1); 198 | } 199 | 200 | } 201 | else if (comboBoxPlotType.Text.Contains("Interval")) 202 | { 203 | plot_interval_vs_time(scatterSeries1, stemSeries1, lineSeries1); 204 | pm.Series.Add(scatterSeries1); 205 | if (!checkBoxLines.Checked) 206 | { 207 | plot_fit(scatterSeries1, lineSeries1); 208 | lineSeries1.Color = singleLineColor; 209 | } 210 | pm.Series.Add(lineSeries1); 211 | if (checkBoxStem.Checked) 212 | { 213 | pm.Series.Add(stemSeries1); 214 | } 215 | 216 | } 217 | else if (comboBoxPlotType.Text.Contains("xyVelocity")) 218 | { 219 | plot_xyvelocity_vs_time(scatterSeries1, scatterSeries2, stemSeries1, stemSeries2, lineSeries1, lineSeries2); 220 | pm.Series.Add(scatterSeries1); 221 | pm.Series.Add(scatterSeries2); 222 | if (!checkBoxLines.Checked) 223 | { 224 | plot_fit(scatterSeries1, lineSeries1); 225 | plot_fit(scatterSeries2, lineSeries2); 226 | } 227 | pm.Series.Add(lineSeries1); 228 | pm.Series.Add(lineSeries2); 229 | if (checkBoxStem.Checked) 230 | { 231 | pm.Series.Add(stemSeries1); 232 | pm.Series.Add(stemSeries2); 233 | } 234 | 235 | } 236 | else if (comboBoxPlotType.Text.Contains("xVelocity")) 237 | { 238 | plot_xvelocity_vs_time(scatterSeries1, stemSeries1, lineSeries1); 239 | pm.Series.Add(scatterSeries1); 240 | if (!checkBoxLines.Checked) 241 | { 242 | plot_fit(scatterSeries1, lineSeries1); 243 | lineSeries1.Color = singleLineColor; 244 | } 245 | pm.Series.Add(lineSeries1); 246 | if (checkBoxStem.Checked) 247 | { 248 | pm.Series.Add(stemSeries1); 249 | } 250 | } 251 | else if (comboBoxPlotType.Text.Contains("yVelocity")) 252 | { 253 | plot_yvelocity_vs_time(scatterSeries1, stemSeries1, lineSeries1); 254 | pm.Series.Add(scatterSeries1); 255 | if (!checkBoxLines.Checked) 256 | { 257 | plot_fit(scatterSeries1, lineSeries1); 258 | lineSeries1.Color = singleLineColor; 259 | } 260 | pm.Series.Add(lineSeries1); 261 | if (checkBoxStem.Checked) 262 | { 263 | pm.Series.Add(stemSeries1); 264 | } 265 | } 266 | else if (comboBoxPlotType.Text.Contains("X vs. Y")) 267 | { 268 | plot_x_vs_y(scatterSeries1, lineSeries1); 269 | pm.Series.Add(scatterSeries1); 270 | if (checkBoxLines.Checked) 271 | { 272 | pm.Series.Add(lineSeries1); 273 | lineSeries1.Color = singleLineColor; 274 | } 275 | } 276 | 277 | var linearAxis1 = new LinearAxis(); 278 | linearAxis1.AbsoluteMinimum = x_min - (x_max - x_min) / 20.0; 279 | linearAxis1.AbsoluteMaximum = x_max + (x_max - x_min) / 20.0; 280 | linearAxis1.MajorGridlineColor = OxyColor.FromArgb(40, 0, 0, 139); 281 | linearAxis1.MajorGridlineStyle = LineStyle.Solid; 282 | linearAxis1.MinorGridlineColor = OxyColor.FromArgb(20, 0, 0, 139); 283 | linearAxis1.MinorGridlineStyle = LineStyle.Solid; 284 | linearAxis1.Position = AxisPosition.Bottom; 285 | linearAxis1.Title = xlabel; 286 | pm.Axes.Add(linearAxis1); 287 | 288 | var linearAxis2 = new LinearAxis(); 289 | linearAxis2.AbsoluteMinimum = y_min - (y_max - y_min) / 20.0; 290 | linearAxis2.AbsoluteMaximum = y_max + (y_max - y_min) / 20.0; 291 | linearAxis2.MajorGridlineColor = OxyColor.FromArgb(40, 0, 0, 139); 292 | linearAxis2.MajorGridlineStyle = LineStyle.Solid; 293 | linearAxis2.MinorGridlineColor = OxyColor.FromArgb(20, 0, 0, 139); 294 | linearAxis2.MinorGridlineStyle = LineStyle.Solid; 295 | linearAxis2.Title = ylabel; 296 | pm.Axes.Add(linearAxis2); 297 | 298 | plot1.RefreshPlot(true); 299 | } 300 | 301 | private void reset_minmax() 302 | { 303 | x_min = double.MaxValue; 304 | x_max = double.MinValue; 305 | y_min = double.MaxValue; 306 | y_max = double.MinValue; 307 | } 308 | 309 | private void update_minmax(double x, double y) 310 | { 311 | if (x < x_min) 312 | { 313 | x_min = x; 314 | } 315 | if (x > x_max) 316 | { 317 | x_max = x; 318 | } 319 | if (y < y_min) 320 | { 321 | y_min = y; 322 | } 323 | if (y > y_max) 324 | { 325 | y_max = y; 326 | } 327 | } 328 | 329 | private void plot_xcounts_vs_time(ScatterSeries scatterSeries1, StemSeries stemSeries1, LineSeries lineSeries1) 330 | { 331 | xlabel = "Time (ms)"; 332 | ylabel = "xCounts"; 333 | reset_minmax(); 334 | for (int i = last_start; i <= last_end; i++) 335 | { 336 | double x = this.mlog.Events[i].ts; 337 | double y = this.mlog.Events[i].lastx; 338 | update_minmax(x, y); 339 | scatterSeries1.Points.Add(new ScatterPoint(x, y)); 340 | lineSeries1.Points.Add(new DataPoint(x, y)); 341 | stemSeries1.Points.Add(new DataPoint(x, y)); 342 | } 343 | } 344 | 345 | private void plot_ycounts_vs_time(ScatterSeries scatterSeries1, StemSeries stemSeries1, LineSeries lineSeries1) 346 | { 347 | xlabel = "Time (ms)"; 348 | ylabel = "yCounts"; 349 | reset_minmax(); 350 | for (int i = last_start; i <= last_end; i++) 351 | { 352 | double x = this.mlog.Events[i].ts; 353 | double y = this.mlog.Events[i].lasty; 354 | update_minmax(x, y); 355 | scatterSeries1.Points.Add(new ScatterPoint(x, y)); 356 | lineSeries1.Points.Add(new DataPoint(x, y)); 357 | stemSeries1.Points.Add(new DataPoint(x, y)); 358 | } 359 | } 360 | 361 | private void plot_xycounts_vs_time(ScatterSeries scatterSeries1, ScatterSeries scatterSeries2, StemSeries stemSeries1, StemSeries stemSeries2, LineSeries lineSeries1, LineSeries lineSeries2) 362 | { 363 | xlabel = "Time (ms)"; 364 | ylabel = "Counts [x = Blue, y = Red]"; 365 | reset_minmax(); 366 | for (int i = last_start; i <= last_end; i++) 367 | { 368 | double x = this.mlog.Events[i].ts; 369 | double y = this.mlog.Events[i].lastx; 370 | update_minmax(x, y); 371 | scatterSeries1.Points.Add(new ScatterPoint(x, y)); 372 | lineSeries1.Points.Add(new DataPoint(x, y)); 373 | stemSeries1.Points.Add(new DataPoint(x, y)); 374 | } 375 | 376 | for (int i = last_start; i <= last_end; i++) 377 | { 378 | double x = this.mlog.Events[i].ts; 379 | double y = this.mlog.Events[i].lasty; 380 | update_minmax(x, y); 381 | scatterSeries2.Points.Add(new ScatterPoint(x, y)); 382 | lineSeries2.Points.Add(new DataPoint(x, y)); 383 | stemSeries2.Points.Add(new DataPoint(x, y)); 384 | } 385 | } 386 | 387 | private void plot_interval_vs_time(ScatterSeries scatterSeries1, StemSeries stemSeries1, LineSeries lineSeries1) 388 | { 389 | xlabel = "Time (ms)"; 390 | ylabel = "Update Time (ms)"; 391 | reset_minmax(); 392 | for (int i = last_start; i <= last_end; i++) 393 | { 394 | double x = this.mlog.Events[i].ts; 395 | double y; 396 | if (i == 0) 397 | { 398 | y = 0.0; 399 | } 400 | else 401 | { 402 | y = this.mlog.Events[i].ts - this.mlog.Events[i - 1].ts; 403 | } 404 | update_minmax(x, y); 405 | scatterSeries1.Points.Add(new ScatterPoint(x, y)); 406 | lineSeries1.Points.Add(new DataPoint(x, y)); 407 | stemSeries1.Points.Add(new DataPoint(x, y)); 408 | } 409 | } 410 | 411 | private void plot_xvelocity_vs_time(ScatterSeries scatterSeries1, StemSeries stemSeries1, LineSeries lineSeries1) 412 | { 413 | xlabel = "Time (ms)"; 414 | ylabel = "xVelocity (m/s)"; 415 | reset_minmax(); 416 | if (this.mlog.Cpi > 0) 417 | { 418 | for (int i = last_start; i <= last_end; i++) 419 | { 420 | double x = this.mlog.Events[i].ts; 421 | double y; 422 | if (i == 0) 423 | { 424 | y = 0.0; 425 | } 426 | else 427 | { 428 | y = (this.mlog.Events[i].lastx) / (this.mlog.Events[i].ts - this.mlog.Events[i - 1].ts) / this.mlog.Cpi * 25.4; 429 | } 430 | update_minmax(x, y); 431 | scatterSeries1.Points.Add(new ScatterPoint(x, y)); 432 | lineSeries1.Points.Add(new DataPoint(x, y)); 433 | stemSeries1.Points.Add(new DataPoint(x, y)); 434 | } 435 | } 436 | else 437 | { 438 | MessageBox.Show("CPI value is invalid, please run Measure"); 439 | } 440 | } 441 | 442 | private void plot_yvelocity_vs_time(ScatterSeries scatterSeries1, StemSeries stemSeries1, LineSeries lineSeries1) 443 | { 444 | xlabel = "Time (ms)"; 445 | ylabel = "yVelocity (m/s)"; 446 | reset_minmax(); 447 | if (this.mlog.Cpi > 0) 448 | { 449 | for (int i = last_start; i <= last_end; i++) 450 | { 451 | double x = this.mlog.Events[i].ts; 452 | double y; 453 | if (i == 0) 454 | { 455 | y = 0.0; 456 | } 457 | else 458 | { 459 | y = (this.mlog.Events[i].lasty) / (this.mlog.Events[i].ts - this.mlog.Events[i - 1].ts) / this.mlog.Cpi * 25.4; 460 | } 461 | update_minmax(x, y); 462 | scatterSeries1.Points.Add(new ScatterPoint(x, y)); 463 | lineSeries1.Points.Add(new DataPoint(x, y)); 464 | stemSeries1.Points.Add(new DataPoint(x, y)); 465 | } 466 | } 467 | else 468 | { 469 | MessageBox.Show("CPI value is invalid, please run Measure"); 470 | } 471 | } 472 | 473 | private void plot_xyvelocity_vs_time(ScatterSeries scatterSeries1, ScatterSeries scatterSeries2, StemSeries stemSeries1, StemSeries stemSeries2, LineSeries lineSeries1, LineSeries lineSeries2) 474 | { 475 | xlabel = "Time (ms)"; 476 | ylabel = "Velocity (m/s) [x = Blue, y = Red]"; 477 | reset_minmax(); 478 | if (this.mlog.Cpi > 0) 479 | { 480 | for (int i = last_start; i <= last_end; i++) 481 | { 482 | double x = this.mlog.Events[i].ts; 483 | double y; 484 | if (i == 0) 485 | { 486 | y = 0.0; 487 | } 488 | else 489 | { 490 | y = (this.mlog.Events[i].lastx) / (this.mlog.Events[i].ts - this.mlog.Events[i - 1].ts) / this.mlog.Cpi * 25.4; 491 | } 492 | update_minmax(x, y); 493 | scatterSeries1.Points.Add(new ScatterPoint(x, y)); 494 | lineSeries1.Points.Add(new DataPoint(x, y)); 495 | stemSeries1.Points.Add(new DataPoint(x, y)); 496 | } 497 | 498 | for (int i = last_start; i <= last_end; i++) 499 | { 500 | double x = this.mlog.Events[i].ts; 501 | double y; 502 | if (i == 0) 503 | { 504 | y = 0.0; 505 | } 506 | else 507 | { 508 | y = (this.mlog.Events[i].lasty) / (this.mlog.Events[i].ts - this.mlog.Events[i - 1].ts) / this.mlog.Cpi * 25.4; 509 | } 510 | update_minmax(x, y); 511 | scatterSeries2.Points.Add(new ScatterPoint(x, y)); 512 | lineSeries2.Points.Add(new DataPoint(x, y)); 513 | stemSeries2.Points.Add(new DataPoint(x, y)); 514 | } 515 | } 516 | else 517 | { 518 | MessageBox.Show("CPI value is invalid, please run Measure"); 519 | } 520 | } 521 | 522 | private void plot_x_vs_y(ScatterSeries scatterSeries1, LineSeries lineSeries1) 523 | { 524 | xlabel = "xCounts"; 525 | ylabel = "yCounts"; 526 | reset_minmax(); 527 | double x = 0.0; 528 | double y = 0.0; 529 | for (int i = last_start; i <= last_end; i++) 530 | { 531 | x += this.mlog.Events[i].lastx; 532 | y += this.mlog.Events[i].lasty; 533 | update_minmax(x, x); 534 | update_minmax(y, y); 535 | scatterSeries1.Points.Add(new ScatterPoint(x, y)); 536 | lineSeries1.Points.Add(new DataPoint(x, y)); 537 | } 538 | } 539 | 540 | #if false 541 | // Window based smoothing 542 | private void plot_fit(ScatterSeries scatterSeries1, LineSeries lineSeries1) 543 | { 544 | double sum = 0.0; 545 | 546 | lineSeries1.Points.Clear(); 547 | 548 | for (int i = 0; ((i < 8) && (i < scatterSeries1.Points.Count)); i++) 549 | //for (int i = 0; ((i < 4) && (i < scatterSeries1.Points.Count)); i++) 550 | { 551 | sum = sum + scatterSeries1.Points[i].Y; 552 | } 553 | 554 | for (int i = 3; i < scatterSeries1.Points.Count - 5; i++) 555 | //for (int i = 1; i < scatterSeries1.Points.Count - 3; i++) 556 | { 557 | double x = (scatterSeries1.Points[i].X + scatterSeries1.Points[i + 1].X) / 2.0; 558 | double y = sum; 559 | lineSeries1.Points.Add(new DataPoint(x, y / 8.0)); 560 | sum = sum - scatterSeries1.Points[i - 3].Y; 561 | sum = sum + scatterSeries1.Points[i + 5].Y; 562 | //lineSeries1.Points.Add(new DataPoint(x, y / 4.0)); 563 | //sum = sum - scatterSeries1.Points[i - 1].Y; 564 | //sum = sum + scatterSeries1.Points[i + 3].Y; 565 | 566 | } 567 | } 568 | #else 569 | // Time based smoothing 570 | private void plot_fit(ScatterSeries scatterSeries1, LineSeries lineSeries1) 571 | { 572 | double hz = 125; 573 | double ms = 1000.0 / hz; 574 | lineSeries1.Points.Clear(); 575 | 576 | int ind = 0; 577 | for (double x = ms; x <= scatterSeries1.Points[scatterSeries1.Points.Count - 1].X; x += ms) 578 | { 579 | double sum = 0.0; 580 | int count = 0; 581 | while (scatterSeries1.Points[ind].X <= x) 582 | { 583 | sum += scatterSeries1.Points[ind++].Y; 584 | count++; 585 | } 586 | lineSeries1.Points.Add(new DataPoint(x - (ms / 2.0), sum / count)); 587 | } 588 | } 589 | #endif 590 | 591 | private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) 592 | { 593 | refresh_plot(); 594 | } 595 | 596 | private void numericUpDownStart_ValueChanged(object sender, EventArgs e) 597 | { 598 | if (numericUpDownStart.Value >= numericUpDownEnd.Value) 599 | { 600 | numericUpDownStart.Value = last_start; 601 | } 602 | else 603 | { 604 | last_start = (int)numericUpDownStart.Value; 605 | refresh_plot(); 606 | } 607 | } 608 | 609 | private void numericUpDownEnd_ValueChanged(object sender, EventArgs e) 610 | { 611 | if (numericUpDownEnd.Value <= numericUpDownStart.Value) 612 | { 613 | numericUpDownEnd.Value = last_end; 614 | } 615 | else 616 | { 617 | last_end = (int)numericUpDownEnd.Value; 618 | refresh_plot(); 619 | } 620 | } 621 | 622 | private void checkBoxStem_CheckedChanged(object sender, EventArgs e) 623 | { 624 | refresh_plot(); 625 | } 626 | 627 | private void checkBoxLines_CheckedChanged(object sender, EventArgs e) 628 | { 629 | refresh_plot(); 630 | } 631 | 632 | private void buttonSavePNG_Click(object sender, EventArgs e) 633 | { 634 | SaveFileDialog saveFileDialog1 = new SaveFileDialog(); 635 | saveFileDialog1.Filter = "PNG Files (*.png)|*.png"; 636 | saveFileDialog1.FilterIndex = 1; 637 | if (saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK) 638 | { 639 | MousePlot.Export(this.plot1.Model, saveFileDialog1.FileName, 800, 600); 640 | } 641 | } 642 | 643 | public static void Export(PlotModel model, string fileName, int width, int height, Brush background = null) 644 | { 645 | using (var bm = new Bitmap(width, height)) 646 | { 647 | using (Graphics g = Graphics.FromImage(bm)) 648 | { 649 | if (background != null) 650 | { 651 | g.FillRectangle(background, 0, 0, width, height); 652 | } 653 | 654 | var rc = new GraphicsRenderContext { RendersToScreen = false }; 655 | rc.SetGraphicsTarget(g); 656 | model.Update(); 657 | model.Render(rc, width, height); 658 | bm.Save(fileName, ImageFormat.Png); 659 | } 660 | } 661 | } 662 | } 663 | } 664 | -------------------------------------------------------------------------------- /MouseTester/MouseTester/MousePlot.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /MouseTester/MouseTester/MouseTester.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {B0953B29-AF9B-4C37-A2EC-947E98F683B3} 9 | WinExe 10 | Properties 11 | MouseTester 12 | MouseTester 13 | v4.6 14 | 15 | 16 | 512 17 | false 18 | publish\ 19 | true 20 | Disk 21 | false 22 | Foreground 23 | 7 24 | Days 25 | false 26 | false 27 | true 28 | 0 29 | 1.4.0.%2a 30 | false 31 | true 32 | 33 | 34 | x86 35 | true 36 | full 37 | false 38 | bin\Debug\ 39 | DEBUG;TRACE 40 | prompt 41 | 4 42 | false 43 | 44 | 45 | x86 46 | pdbonly 47 | true 48 | bin\Release\ 49 | TRACE 50 | prompt 51 | 4 52 | false 53 | 54 | 55 | Internet 56 | 57 | 58 | false 59 | 60 | 61 | Properties\app.manifest 62 | 63 | 64 | true 65 | bin\Debug\ 66 | DEBUG;TRACE 67 | full 68 | AnyCPU 69 | 7.3 70 | prompt 71 | false 72 | 73 | 74 | bin\Release\ 75 | TRACE 76 | true 77 | pdbonly 78 | AnyCPU 79 | 7.3 80 | prompt 81 | false 82 | 83 | 84 | true 85 | bin\x64\Debug\ 86 | DEBUG;TRACE 87 | full 88 | x64 89 | 7.3 90 | prompt 91 | false 92 | 93 | 94 | bin\x64\Release\ 95 | TRACE 96 | true 97 | pdbonly 98 | x64 99 | 7.3 100 | prompt 101 | false 102 | 103 | 104 | 105 | False 106 | .\OxyPlot.dll 107 | 108 | 109 | False 110 | .\OxyPlot.WindowsForms.dll 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | Form 126 | 127 | 128 | Form1.cs 129 | 130 | 131 | 132 | 133 | 134 | Form 135 | 136 | 137 | MousePlot.cs 138 | 139 | 140 | 141 | 142 | Form 143 | 144 | 145 | Form1.cs 146 | Designer 147 | 148 | 149 | MousePlot.cs 150 | 151 | 152 | ResXFileCodeGenerator 153 | Resources.Designer.cs 154 | Designer 155 | 156 | 157 | True 158 | Resources.resx 159 | True 160 | 161 | 162 | 163 | 164 | SettingsSingleFileGenerator 165 | Settings.Designer.cs 166 | 167 | 168 | True 169 | Settings.settings 170 | True 171 | 172 | 173 | 174 | 175 | False 176 | Microsoft .NET Framework 4 Client Profile %28x86 and x64%29 177 | true 178 | 179 | 180 | False 181 | .NET Framework 3.5 SP1 Client Profile 182 | false 183 | 184 | 185 | False 186 | .NET Framework 3.5 SP1 187 | false 188 | 189 | 190 | False 191 | Windows Installer 3.1 192 | true 193 | 194 | 195 | 196 | 203 | -------------------------------------------------------------------------------- /MouseTester/MouseTester/OxyPlot.WindowsForms.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microe1/MouseTester/3c747afa502b7543704d5cea4303ecc2741ec8c8/MouseTester/MouseTester/OxyPlot.WindowsForms.dll -------------------------------------------------------------------------------- /MouseTester/MouseTester/OxyPlot.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microe1/MouseTester/3c747afa502b7543704d5cea4303ecc2741ec8c8/MouseTester/MouseTester/OxyPlot.dll -------------------------------------------------------------------------------- /MouseTester/MouseTester/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Windows.Forms; 5 | 6 | namespace MouseTester 7 | { 8 | static class Program 9 | { 10 | /// 11 | /// The main entry point for the application. 12 | /// 13 | [STAThread] 14 | static void Main() 15 | { 16 | Application.EnableVisualStyles(); 17 | Application.SetCompatibleTextRenderingDefault(false); 18 | Application.Run(new Form1()); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /MouseTester/MouseTester/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MouseTester")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MouseTester")] 13 | [assembly: AssemblyCopyright("Copyright © 2021")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("057b69bb-f19d-457e-a0a7-a0bc68b8c2c4")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.4.0.0")] 36 | [assembly: AssemblyFileVersion("1.4.0.0")] 37 | -------------------------------------------------------------------------------- /MouseTester/MouseTester/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace MouseTester.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MouseTester.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /MouseTester/MouseTester/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /MouseTester/MouseTester/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace MouseTester.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.8.1.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /MouseTester/MouseTester/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MouseTester/MouseTester/Properties/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 47 | -------------------------------------------------------------------------------- /MouseTester/MouseTester/RawMouse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Diagnostics; 5 | using System.Text; 6 | using System.Runtime.InteropServices; 7 | using System.Windows.Forms; 8 | 9 | namespace MouseTester 10 | { 11 | public partial class Form1 12 | { 13 | private const int RIDEV_INPUTSINK = 0x00000100; 14 | private const int RID_INPUT = 0x10000003; 15 | private const int WM_INPUT = 0x00FF; 16 | private const int RIM_TYPEMOUSE = 0; 17 | private const int RI_MOUSE_LEFT_BUTTON_DOWN = 0x0001; 18 | private const ushort RI_MOUSE_LEFT_BUTTON_UP = 0x0002; 19 | private const int RI_MOUSE_RIGHT_BUTTON_DOWN = 0x0004; 20 | private const ushort RI_MOUSE_RIGHT_BUTTON_UP = 0x0008; 21 | 22 | [StructLayout(LayoutKind.Sequential)] 23 | internal struct RAWINPUTDEVICE 24 | { 25 | [MarshalAs(UnmanagedType.U2)] 26 | public ushort usUsagePage; 27 | [MarshalAs(UnmanagedType.U2)] 28 | public ushort usUsage; 29 | [MarshalAs(UnmanagedType.U4)] 30 | public int dwFlags; 31 | public IntPtr hwndTarget; 32 | } 33 | 34 | [StructLayout(LayoutKind.Sequential)] 35 | internal struct RAWINPUTHEADER 36 | { 37 | [MarshalAs(UnmanagedType.U4)] 38 | public int dwType; 39 | [MarshalAs(UnmanagedType.U4)] 40 | public int dwSize; 41 | public IntPtr hDevice; 42 | [MarshalAs(UnmanagedType.U4)] 43 | public int wParam; 44 | } 45 | 46 | [StructLayout(LayoutKind.Sequential)] 47 | internal struct RAWHID 48 | { 49 | [MarshalAs(UnmanagedType.U4)] 50 | public int dwSizHid; 51 | [MarshalAs(UnmanagedType.U4)] 52 | public int dwCount; 53 | } 54 | 55 | [StructLayout(LayoutKind.Sequential)] 56 | internal struct BUTTONSSTR 57 | { 58 | [MarshalAs(UnmanagedType.U2)] 59 | public ushort usButtonFlags; 60 | [MarshalAs(UnmanagedType.U2)] 61 | public ushort usButtonData; 62 | } 63 | 64 | [StructLayout(LayoutKind.Explicit)] 65 | internal struct RAWMOUSE 66 | { 67 | [MarshalAs(UnmanagedType.U2)] 68 | [FieldOffset(0)] 69 | public ushort usFlags; 70 | [MarshalAs(UnmanagedType.U4)] 71 | [FieldOffset(4)] 72 | public uint ulButtons; 73 | [FieldOffset(4)] 74 | public BUTTONSSTR buttonsStr; 75 | [MarshalAs(UnmanagedType.U4)] 76 | [FieldOffset(8)] 77 | public uint ulRawButtons; 78 | [FieldOffset(12)] 79 | public int lLastX; 80 | [FieldOffset(16)] 81 | public int lLastY; 82 | [MarshalAs(UnmanagedType.U4)] 83 | [FieldOffset(20)] 84 | public uint ulExtraInformation; 85 | } 86 | 87 | [StructLayout(LayoutKind.Sequential)] 88 | internal struct RAWKEYBOARD 89 | { 90 | [MarshalAs(UnmanagedType.U2)] 91 | public ushort MakeCode; 92 | [MarshalAs(UnmanagedType.U2)] 93 | public ushort Flags; 94 | [MarshalAs(UnmanagedType.U2)] 95 | public ushort Reserved; 96 | [MarshalAs(UnmanagedType.U2)] 97 | public ushort VKey; 98 | [MarshalAs(UnmanagedType.U4)] 99 | public uint Message; 100 | [MarshalAs(UnmanagedType.U4)] 101 | public uint ExtraInformation; 102 | } 103 | 104 | [StructLayout(LayoutKind.Sequential)] 105 | internal struct RAWINPUT 106 | { 107 | public RAWINPUTHEADER header; 108 | public Union data; 109 | [StructLayout(LayoutKind.Explicit)] 110 | public struct Union 111 | { 112 | [FieldOffset(0)] 113 | public RAWMOUSE mouse; 114 | [FieldOffset(0)] 115 | public RAWKEYBOARD keyboard; 116 | [FieldOffset(0)] 117 | public RAWHID hid; 118 | } 119 | } 120 | 121 | [DllImport("user32.dll")] 122 | extern static bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevices, 123 | uint uiNumDevices, 124 | uint cbSize); 125 | 126 | [DllImport("User32.dll")] 127 | extern static int GetRawInputData(IntPtr hRawInput, 128 | uint uiCommand, 129 | out RAWINPUT pData, //IntPtr pData, 130 | ref uint pcbSize, 131 | uint cbSizeHeader); 132 | 133 | public void RegisterRawInputMouse(IntPtr hwnd) 134 | { 135 | RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[1]; 136 | rid[0].usUsagePage = 1; 137 | rid[0].usUsage = 2; 138 | rid[0].dwFlags = RIDEV_INPUTSINK; 139 | rid[0].hwndTarget = hwnd; 140 | 141 | if (!RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(rid[0]))) 142 | { 143 | Debug.WriteLine("RegisterRawInputDevices() Failed"); 144 | } 145 | } 146 | 147 | [DllImport("Kernel32.dll")] 148 | private static extern bool QueryPerformanceCounter(out long lpPerformanceCount); 149 | 150 | [DllImport("Kernel32.dll")] 151 | private static extern bool QueryPerformanceFrequency(out long lpFrequency); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /MouseTester/MouseTester/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MouseTester 2 | =========== 3 | --------------------------------------------------------------------------------