├── .github
├── dependabot.yml
└── workflows
│ └── release.yml
├── .gitignore
├── LICENSE
├── MouseTester
├── MouseTester.sln
└── MouseTester
│ ├── FodyWeavers.xml
│ ├── FodyWeavers.xsd
│ ├── 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
│ └── packages.config
└── README.md
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 |
3 | updates:
4 | - package-ecosystem: "github-actions"
5 | directory: "/"
6 | schedule:
7 | interval: "weekly"
8 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Create release
2 | run-name: Create release
3 |
4 | on:
5 | workflow_dispatch:
6 | inputs:
7 | version:
8 | description: "Version of the program to build. This will be used for the tag and release name."
9 | required: true
10 |
11 | pre-release:
12 | description: "Pre-release"
13 | required: true
14 | default: false
15 | type: boolean
16 |
17 | permissions:
18 | contents: write
19 |
20 | jobs:
21 | build:
22 | runs-on: windows-latest
23 |
24 | steps:
25 | - name: Checkout repository
26 | uses: actions/checkout@v4
27 |
28 | - name: Set up MSVC environment
29 | uses: microsoft/setup-msbuild@v2
30 |
31 | - name: Install packages
32 | run: nuget restore .\MouseTester\MouseTester.sln
33 |
34 | - name: Build executable
35 | run: |
36 | MSBuild.exe .\MouseTester\MouseTester.sln -p:Configuration=Release -p:Platform=x64
37 |
38 | - name: Create release
39 | uses: ncipollo/release-action@v1
40 | with:
41 | tag: MouseTester_v${{ inputs.version }}
42 | name: MouseTester_v${{ inputs.version }}
43 | prerelease: ${{ inputs.pre-release }}
44 | artifacts: ./MouseTester/MouseTester/bin/x64/Release/MouseTester.exe
45 | generateReleaseNotes: true
46 |
--------------------------------------------------------------------------------
/.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 | /MouseTester/.vs
110 |
--------------------------------------------------------------------------------
/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/FodyWeavers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/MouseTester/MouseTester/FodyWeavers.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks
13 |
14 |
15 |
16 |
17 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.
18 |
19 |
20 |
21 |
22 | A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks
23 |
24 |
25 |
26 |
27 | A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.
28 |
29 |
30 |
31 |
32 | A list of unmanaged 32 bit assembly names to include, delimited with line breaks.
33 |
34 |
35 |
36 |
37 | A list of unmanaged 64 bit assembly names to include, delimited with line breaks.
38 |
39 |
40 |
41 |
42 | The order of preloaded assemblies, delimited with line breaks.
43 |
44 |
45 |
46 |
47 |
48 | This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.
49 |
50 |
51 |
52 |
53 | Controls if .pdbs for reference assemblies are also embedded.
54 |
55 |
56 |
57 |
58 | Controls if runtime assemblies are also embedded.
59 |
60 |
61 |
62 |
63 | Controls whether the runtime assemblies are embedded with their full path or only with their assembly name.
64 |
65 |
66 |
67 |
68 | Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.
69 |
70 |
71 |
72 |
73 | As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.
74 |
75 |
76 |
77 |
78 | Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.
79 |
80 |
81 |
82 |
83 | Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.
84 |
85 |
86 |
87 |
88 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |
89 |
90 |
91 |
92 |
93 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.
94 |
95 |
96 |
97 |
98 | A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with |
99 |
100 |
101 |
102 |
103 | A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with |.
104 |
105 |
106 |
107 |
108 | A list of unmanaged 32 bit assembly names to include, delimited with |.
109 |
110 |
111 |
112 |
113 | A list of unmanaged 64 bit assembly names to include, delimited with |.
114 |
115 |
116 |
117 |
118 | The order of preloaded assemblies, delimited with |.
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 | 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
127 |
128 |
129 |
130 |
131 | A comma-separated list of error codes that can be safely ignored in assembly verification.
132 |
133 |
134 |
135 |
136 | 'false' to turn off automatic generation of the XML Schema file.
137 |
138 |
139 |
140 |
141 |
--------------------------------------------------------------------------------
/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.Controls.Add(this.textBoxDesc);
57 | this.groupBox1.Location = new System.Drawing.Point(13, 13);
58 | this.groupBox1.Name = "groupBox1";
59 | this.groupBox1.Size = new System.Drawing.Size(267, 50);
60 | this.groupBox1.TabIndex = 0;
61 | this.groupBox1.TabStop = false;
62 | this.groupBox1.Text = "Description";
63 | //
64 | // textBoxDesc
65 | //
66 | this.textBoxDesc.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
67 | | System.Windows.Forms.AnchorStyles.Left)
68 | | System.Windows.Forms.AnchorStyles.Right)));
69 | this.textBoxDesc.Location = new System.Drawing.Point(6, 19);
70 | this.textBoxDesc.Name = "textBoxDesc";
71 | this.textBoxDesc.Size = new System.Drawing.Size(250, 20);
72 | this.textBoxDesc.TabIndex = 0;
73 | //
74 | // textBoxCPI
75 | //
76 | this.textBoxCPI.Location = new System.Drawing.Point(88, 21);
77 | this.textBoxCPI.Name = "textBoxCPI";
78 | this.textBoxCPI.Size = new System.Drawing.Size(100, 20);
79 | this.textBoxCPI.TabIndex = 0;
80 | this.textBoxCPI.Validated += new System.EventHandler(this.textBoxCPI_Validated);
81 | //
82 | // groupBox2
83 | //
84 | this.groupBox2.Controls.Add(this.label1);
85 | this.groupBox2.Controls.Add(this.buttonMeasure);
86 | this.groupBox2.Controls.Add(this.textBoxCPI);
87 | this.groupBox2.Location = new System.Drawing.Point(13, 69);
88 | this.groupBox2.Name = "groupBox2";
89 | this.groupBox2.Size = new System.Drawing.Size(267, 50);
90 | this.groupBox2.TabIndex = 1;
91 | this.groupBox2.TabStop = false;
92 | this.groupBox2.Text = "Resolution";
93 | //
94 | // label1
95 | //
96 | this.label1.AutoSize = true;
97 | this.label1.Location = new System.Drawing.Point(194, 24);
98 | this.label1.Name = "label1";
99 | this.label1.Size = new System.Drawing.Size(21, 13);
100 | this.label1.TabIndex = 2;
101 | this.label1.Text = "cpi";
102 | //
103 | // buttonMeasure
104 | //
105 | this.buttonMeasure.Location = new System.Drawing.Point(6, 19);
106 | this.buttonMeasure.Name = "buttonMeasure";
107 | this.buttonMeasure.Size = new System.Drawing.Size(75, 23);
108 | this.buttonMeasure.TabIndex = 1;
109 | this.buttonMeasure.Text = "Measure";
110 | this.buttonMeasure.UseVisualStyleBackColor = true;
111 | this.buttonMeasure.Click += new System.EventHandler(this.buttonMeasure_Click);
112 | //
113 | // groupBox3
114 | //
115 | this.groupBox3.Controls.Add(this.buttonSave);
116 | this.groupBox3.Controls.Add(this.buttonLoad);
117 | this.groupBox3.Location = new System.Drawing.Point(13, 182);
118 | this.groupBox3.Name = "groupBox3";
119 | this.groupBox3.Size = new System.Drawing.Size(267, 50);
120 | this.groupBox3.TabIndex = 2;
121 | this.groupBox3.TabStop = false;
122 | this.groupBox3.Text = "LogFile";
123 | //
124 | // buttonSave
125 | //
126 | this.buttonSave.Location = new System.Drawing.Point(88, 20);
127 | this.buttonSave.Name = "buttonSave";
128 | this.buttonSave.Size = new System.Drawing.Size(75, 23);
129 | this.buttonSave.TabIndex = 1;
130 | this.buttonSave.Text = "Save";
131 | this.buttonSave.UseVisualStyleBackColor = true;
132 | this.buttonSave.Click += new System.EventHandler(this.buttonSave_Click);
133 | //
134 | // buttonLoad
135 | //
136 | this.buttonLoad.Location = new System.Drawing.Point(7, 20);
137 | this.buttonLoad.Name = "buttonLoad";
138 | this.buttonLoad.Size = new System.Drawing.Size(75, 23);
139 | this.buttonLoad.TabIndex = 0;
140 | this.buttonLoad.Text = "Load";
141 | this.buttonLoad.UseVisualStyleBackColor = true;
142 | this.buttonLoad.Click += new System.EventHandler(this.buttonLoad_Click);
143 | //
144 | // buttonPlot
145 | //
146 | this.buttonPlot.Location = new System.Drawing.Point(168, 19);
147 | this.buttonPlot.Name = "buttonPlot";
148 | this.buttonPlot.Size = new System.Drawing.Size(75, 23);
149 | this.buttonPlot.TabIndex = 2;
150 | this.buttonPlot.Text = "Plot (F3)";
151 | this.buttonPlot.UseVisualStyleBackColor = true;
152 | this.buttonPlot.Click += new System.EventHandler(this.buttonPlot_Click);
153 | //
154 | // groupBox4
155 | //
156 | this.groupBox4.Controls.Add(this.buttonLog);
157 | this.groupBox4.Controls.Add(this.buttonCollect);
158 | this.groupBox4.Controls.Add(this.buttonPlot);
159 | this.groupBox4.Location = new System.Drawing.Point(13, 126);
160 | this.groupBox4.Name = "groupBox4";
161 | this.groupBox4.Size = new System.Drawing.Size(267, 50);
162 | this.groupBox4.TabIndex = 3;
163 | this.groupBox4.TabStop = false;
164 | this.groupBox4.Text = "MouseData";
165 | //
166 | // buttonLog
167 | //
168 | this.buttonLog.Location = new System.Drawing.Point(87, 19);
169 | this.buttonLog.Name = "buttonLog";
170 | this.buttonLog.Size = new System.Drawing.Size(75, 23);
171 | this.buttonLog.TabIndex = 4;
172 | this.buttonLog.Text = "Start (F1)";
173 | this.buttonLog.UseVisualStyleBackColor = true;
174 | this.buttonLog.Click += new System.EventHandler(this.buttonLog_Click);
175 | //
176 | // buttonCollect
177 | //
178 | this.buttonCollect.Location = new System.Drawing.Point(6, 19);
179 | this.buttonCollect.Name = "buttonCollect";
180 | this.buttonCollect.Size = new System.Drawing.Size(75, 23);
181 | this.buttonCollect.TabIndex = 3;
182 | this.buttonCollect.Text = "Collect";
183 | this.buttonCollect.UseVisualStyleBackColor = true;
184 | this.buttonCollect.Click += new System.EventHandler(this.buttonCollect_Click);
185 | //
186 | // textBox1
187 | //
188 | this.textBox1.Location = new System.Drawing.Point(13, 239);
189 | this.textBox1.Multiline = true;
190 | this.textBox1.Name = "textBox1";
191 | this.textBox1.ReadOnly = true;
192 | this.textBox1.Size = new System.Drawing.Size(267, 100);
193 | this.textBox1.TabIndex = 4;
194 | //
195 | // statusStrip1
196 | //
197 | this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
198 | this.toolStripStatusLabel1});
199 | this.statusStrip1.Location = new System.Drawing.Point(0, 339);
200 | this.statusStrip1.Name = "statusStrip1";
201 | this.statusStrip1.Size = new System.Drawing.Size(294, 22);
202 | this.statusStrip1.TabIndex = 5;
203 | this.statusStrip1.Text = "statusStrip1";
204 | //
205 | // toolStripStatusLabel1
206 | //
207 | this.toolStripStatusLabel1.Name = "toolStripStatusLabel1";
208 | this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17);
209 | this.toolStripStatusLabel1.Text = "toolStripStatusLabel1";
210 | //
211 | // Form1
212 | //
213 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
214 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
215 | this.ClientSize = new System.Drawing.Size(294, 361);
216 | this.Controls.Add(this.statusStrip1);
217 | this.Controls.Add(this.textBox1);
218 | this.Controls.Add(this.groupBox4);
219 | this.Controls.Add(this.groupBox3);
220 | this.Controls.Add(this.groupBox2);
221 | this.Controls.Add(this.groupBox1);
222 | this.MaximizeBox = false;
223 | this.MaximumSize = new System.Drawing.Size(310, 400);
224 | this.MinimumSize = new System.Drawing.Size(300, 400);
225 | this.Name = "Form1";
226 | this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
227 | this.groupBox1.ResumeLayout(false);
228 | this.groupBox1.PerformLayout();
229 | this.groupBox2.ResumeLayout(false);
230 | this.groupBox2.PerformLayout();
231 | this.groupBox3.ResumeLayout(false);
232 | this.groupBox4.ResumeLayout(false);
233 | this.statusStrip1.ResumeLayout(false);
234 | this.statusStrip1.PerformLayout();
235 | this.ResumeLayout(false);
236 | this.PerformLayout();
237 |
238 | }
239 |
240 | #endregion
241 |
242 | private System.Windows.Forms.GroupBox groupBox1;
243 | private System.Windows.Forms.TextBox textBoxDesc;
244 | private System.Windows.Forms.TextBox textBoxCPI;
245 | private System.Windows.Forms.GroupBox groupBox2;
246 | private System.Windows.Forms.Button buttonMeasure;
247 | private System.Windows.Forms.GroupBox groupBox3;
248 | private System.Windows.Forms.Button buttonPlot;
249 | private System.Windows.Forms.Button buttonSave;
250 | private System.Windows.Forms.Button buttonLoad;
251 | private System.Windows.Forms.GroupBox groupBox4;
252 | private System.Windows.Forms.Button buttonCollect;
253 | private System.Windows.Forms.Label label1;
254 | private System.Windows.Forms.TextBox textBox1;
255 | private System.Windows.Forms.StatusStrip statusStrip1;
256 | private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1;
257 | private System.Windows.Forms.Button buttonLog;
258 |
259 |
260 | }
261 | }
262 |
263 |
--------------------------------------------------------------------------------
/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 |
30 | this.Text = $"MouseTester v{Program.version}";
31 |
32 | try {
33 | // Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2); // Use only the second core
34 | // Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime; // Set highest process priority
35 | // Thread.CurrentThread.Priority = ThreadPriority.Highest; // Set highest thread priority
36 | } catch (Exception ex) {
37 | Debug.WriteLine(ex.ToString());
38 | }
39 |
40 | this.RegisterRawInputMouse(Handle);
41 | this.textBoxDesc.Text = this.mlog.Desc.ToString();
42 | this.textBoxCPI.Text = this.mlog.Cpi.ToString();
43 | this.textBox1.Text = "Enter the correct CPI" +
44 | "\r\n or\r\n" +
45 | "Press the Measure button" +
46 | "\r\n or\r\n" +
47 | "Press the Load button";
48 | this.toolStripStatusLabel1.Text = "";
49 | this.KeyPreview = true;
50 | this.KeyDown += new KeyEventHandler(Form1_KeyDown);
51 |
52 | QueryPerformanceFrequency(out pFreq);
53 | // Debug.WriteLine("PerformanceCounterFrequency: " + pFreq.ToString() + " Hz\n");
54 | }
55 |
56 | private void Form1_KeyDown(object sender, KeyEventArgs e)
57 | {
58 | // TODO: Replace with Global Hotkey
59 | // 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
60 |
61 | if (e.KeyCode == Keys.F1)
62 | {
63 | buttonLog.PerformClick();
64 | e.Handled = true;
65 | }
66 | if (e.KeyCode == Keys.F2)
67 | {
68 | buttonLog.PerformClick();
69 | e.Handled = true;
70 | }
71 | else if (e.KeyCode == Keys.F3)
72 | {
73 | buttonPlot.PerformClick();
74 | e.Handled = false;
75 | }
76 | }
77 |
78 | protected override void WndProc(ref Message m)
79 | {
80 | QueryPerformanceCounter(out long pCounter);
81 | if (m.Msg == WM_INPUT)
82 | {
83 | RAWINPUT raw = new RAWINPUT();
84 | uint size = (uint)Marshal.SizeOf(typeof(RAWINPUT));
85 | int outsize = GetRawInputData(m.LParam, RID_INPUT, out raw, ref size, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER)));
86 | if (outsize != -1)
87 | {
88 | if (raw.header.dwType == RIM_TYPEMOUSE)
89 | {
90 | logMouseEvent(new MouseEvent(raw.data.mouse.buttonsStr.usButtonFlags, raw.data.mouse.lLastX, -(raw.data.mouse.lLastY), pCounter));
91 | }
92 | }
93 | }
94 | base.WndProc(ref m);
95 | }
96 |
97 | private void logMouseEvent(MouseEvent mevent)
98 | {
99 | // Debug.WriteLine(mevent.pcounter + ", " + mevent.lastx + ", " + mevent.lasty + ", " + mevent.buttonflags);
100 | if (this.test_state == state.idle)
101 | {
102 |
103 | }
104 | else if (this.test_state == state.measure_wait)
105 | {
106 | if (mevent.buttonflags == 0x0001)
107 | {
108 | this.mlog.Add(mevent);
109 | this.toolStripStatusLabel1.Text = "Measuring";
110 | this.test_state = state.measure;
111 | }
112 | }
113 | else if (this.test_state == state.measure)
114 | {
115 | this.mlog.Add(mevent);
116 | if (mevent.buttonflags == 0x0002)
117 | {
118 | double x = 0.0;
119 | double y = 0.0;
120 | foreach (MouseEvent e in this.mlog.Events)
121 | {
122 | x += (double)e.lastx;
123 | y += (double)e.lasty;
124 | }
125 | tsCalc();
126 | this.mlog.Cpi = Math.Round(Math.Sqrt((x * x) + (y * y)) / (10 / 2.54));
127 | this.textBoxCPI.Text = this.mlog.Cpi.ToString();
128 | this.textBox1.Text = "Press the Collect or Log Start button\r\n";
129 | this.toolStripStatusLabel1.Text = "";
130 | this.test_state = state.idle;
131 | }
132 | }
133 | else if (this.test_state == state.collect_wait)
134 | {
135 | if (mevent.buttonflags == 0x0001)
136 | {
137 | this.mlog.Add(mevent);
138 | this.toolStripStatusLabel1.Text = "Collecting";
139 | this.test_state = state.collect;
140 | }
141 | }
142 | else if (this.test_state == state.collect)
143 | {
144 | this.mlog.Add(mevent);
145 | if (mevent.buttonflags == 0x0002)
146 | {
147 | tsCalc();
148 | this.textBox1.Text = "Press the plot button to view data\r\n" +
149 | " or\r\n" +
150 | "Press the save button to save log file\r\n" +
151 | "Events: " + this.mlog.Events.Count.ToString() + "\r\n" +
152 | "Sum X: " + this.mlog.deltaX().ToString() + " counts " + Math.Abs(this.mlog.deltaX() / this.mlog.Cpi * 2.54).ToString("0.0") + " cm\r\n" +
153 | "Sum Y: " + this.mlog.deltaY().ToString() + " counts " + Math.Abs(this.mlog.deltaY() / this.mlog.Cpi * 2.54).ToString("0.0") + " cm\r\n" +
154 | "Path: " + this.mlog.path().ToString("0") + " counts " + (this.mlog.path() / this.mlog.Cpi * 2.54).ToString("0.0") + " cm";
155 | this.toolStripStatusLabel1.Text = "";
156 | this.test_state = state.idle;
157 | }
158 | }
159 | else if (this.test_state == state.log)
160 | {
161 | this.mlog.Add(mevent);
162 | }
163 | }
164 |
165 | private void buttonMeasure_Click(object sender, EventArgs e)
166 | {
167 | if (this.test_state == state.idle) {
168 | this.textBox1.Text = "1. Press and hold the left mouse button\r\n" +
169 | "2. Move the mouse 10 cm in a straight line\r\n" +
170 | "3. Release the left mouse button\r\n";
171 | this.toolStripStatusLabel1.Text = "Press the left mouse button";
172 | this.mlog.Clear();
173 | this.test_state = state.measure_wait;
174 | }
175 | }
176 |
177 | private void buttonCollect_Click(object sender, EventArgs e)
178 | {
179 | if (this.test_state == state.idle)
180 | {
181 | this.textBox1.Text = "1. Press and hold the left mouse button\r\n" +
182 | "2. Move the mouse\r\n" +
183 | "3. Release the left mouse button\r\n";
184 | this.toolStripStatusLabel1.Text = "Press the left mouse button";
185 | this.mlog.Clear();
186 | this.test_state = state.collect_wait;
187 | }
188 | }
189 |
190 | private void buttonLog_Click(object sender, EventArgs e)
191 | {
192 | if (this.test_state == state.idle)
193 | {
194 | this.textBox1.Text = "1. Press the Log Stop button\r\n";
195 | this.toolStripStatusLabel1.Text = "Logging...";
196 | this.mlog.Clear();
197 | this.test_state = state.log;
198 | buttonLog.Text = "Stop (F2)";
199 | }
200 | else if (this.test_state == state.log)
201 | {
202 | tsCalc();
203 | this.textBox1.Text = "Press the plot button to view data\r\n" +
204 | " or\r\n" +
205 | "Press the save button to save log file\r\n" +
206 | "Events: " + this.mlog.Events.Count.ToString() + "\r\n" +
207 | "Sum X: " + this.mlog.deltaX().ToString() + " counts " + Math.Abs(this.mlog.deltaX() / this.mlog.Cpi * 2.54).ToString("0.0") + " cm\r\n" +
208 | "Sum Y: " + this.mlog.deltaY().ToString() + " counts " + Math.Abs(this.mlog.deltaY() / this.mlog.Cpi * 2.54).ToString("0.0") + " cm\r\n" +
209 | "Path: " + this.mlog.path().ToString("0") + " counts " + (this.mlog.path() / this.mlog.Cpi * 2.54).ToString("0.0") + " cm";
210 | this.toolStripStatusLabel1.Text = "";
211 | this.test_state = state.idle;
212 | buttonLog.Text = "Start (F1)";
213 | }
214 | }
215 |
216 | private void buttonPlot_Click(object sender, EventArgs e)
217 | {
218 | if (this.mlog.Events.Count > 0 && this.test_state != state.log && this.test_state != state.collect_wait)
219 | {
220 | this.mlog.Desc = textBoxDesc.Text;
221 | MousePlot mousePlot = new MousePlot(this.mlog);
222 | mousePlot.Show();
223 | }
224 | }
225 |
226 | private void buttonLoad_Click(object sender, EventArgs e)
227 | {
228 | OpenFileDialog openFileDialog1 = new OpenFileDialog();
229 | openFileDialog1.Filter = "CSV Files (*.csv)|*.csv|All Files(*.*)|*.*";
230 | openFileDialog1.FilterIndex = 1;
231 | openFileDialog1.Multiselect = false;
232 | if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
233 | {
234 | this.mlog.Load(openFileDialog1.FileName);
235 | }
236 | this.textBox1.Text = "Events: " + this.mlog.Events.Count.ToString() + "\r\n" +
237 | "Sum X: " + this.mlog.deltaX().ToString() + " counts " + Math.Abs(this.mlog.deltaX() / this.mlog.Cpi * 2.54).ToString("0.0") + " cm\r\n" +
238 | "Sum Y: " + this.mlog.deltaY().ToString() + " counts " + Math.Abs(this.mlog.deltaY() / this.mlog.Cpi * 2.54).ToString("0.0") + " cm\r\n" +
239 | "Path: " + this.mlog.path().ToString("0") + " counts " + (this.mlog.path() / this.mlog.Cpi * 2.54).ToString("0.0") + " cm";
240 | this.textBoxDesc.Text = this.mlog.Desc.ToString();
241 | this.textBoxCPI.Text = this.mlog.Cpi.ToString();
242 | if (this.mlog.Events.Count > 0)
243 | {
244 | MousePlot mousePlot = new MousePlot(this.mlog);
245 | mousePlot.Show();
246 | }
247 | }
248 |
249 | private void buttonSave_Click(object sender, EventArgs e)
250 | {
251 | SaveFileDialog saveFileDialog1 = new SaveFileDialog();
252 | saveFileDialog1.Filter = "CSV Files (*.csv)|*.csv|All Files(*.*)|*.*";
253 | saveFileDialog1.FilterIndex = 1;
254 | if (saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
255 | {
256 | this.mlog.Desc = textBoxDesc.Text;
257 | this.mlog.Save(saveFileDialog1.FileName);
258 | }
259 | }
260 |
261 | private void textBoxCPI_Validated(object sender, EventArgs e)
262 | {
263 | try
264 | {
265 | this.mlog.Cpi = double.Parse(this.textBoxCPI.Text);
266 | }
267 | catch //(Exception ex)
268 | {
269 | MessageBox.Show("Invalid CPI, resetting to previous value");
270 | this.textBoxCPI.Text = this.mlog.Cpi.ToString();
271 | }
272 | this.textBox1.Text = "Press the Collect or Log Start button\r\n";
273 | }
274 |
275 | private void tsCalc()
276 | {
277 | long pcounter_min = this.mlog.Events[0].pcounter;
278 | foreach (MouseEvent me in this.mlog.Events)
279 | {
280 | me.ts = (me.pcounter - pcounter_min) * 1000.0 / pFreq;
281 | }
282 | }
283 | }
284 | }
285 |
--------------------------------------------------------------------------------
/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.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
34 | this.statisticsGroupBox = new System.Windows.Forms.GroupBox();
35 | this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
36 | this.label4 = new System.Windows.Forms.Label();
37 | this.label2 = new System.Windows.Forms.Label();
38 | this.maxInterval = new System.Windows.Forms.Label();
39 | this.avgInterval = new System.Windows.Forms.Label();
40 | this.label11 = new System.Windows.Forms.Label();
41 | this.label12 = new System.Windows.Forms.Label();
42 | this.rangeInterval = new System.Windows.Forms.Label();
43 | this.medianInterval = new System.Windows.Forms.Label();
44 | this.label14 = new System.Windows.Forms.Label();
45 | this.label13 = new System.Windows.Forms.Label();
46 | this.minInterval = new System.Windows.Forms.Label();
47 | this.stdevInterval = new System.Windows.Forms.Label();
48 | this.firstPercentileMetricLabel = new System.Windows.Forms.Label();
49 | this.secondPercentileMetricLabel = new System.Windows.Forms.Label();
50 | this.firstPercentileInterval = new System.Windows.Forms.Label();
51 | this.secondPercentileInterval = new System.Windows.Forms.Label();
52 | this.groupBox1 = new System.Windows.Forms.GroupBox();
53 | this.comboBoxPlotType = new System.Windows.Forms.ComboBox();
54 | this.groupBox2 = new System.Windows.Forms.GroupBox();
55 | this.numericUpDownStart = new System.Windows.Forms.NumericUpDown();
56 | this.groupBox3 = new System.Windows.Forms.GroupBox();
57 | this.numericUpDownEnd = new System.Windows.Forms.NumericUpDown();
58 | this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
59 | this.checkBoxLines = new System.Windows.Forms.CheckBox();
60 | this.checkBoxStem = new System.Windows.Forms.CheckBox();
61 | this.buttonSavePNG = new System.Windows.Forms.Button();
62 | ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
63 | this.splitContainer1.Panel1.SuspendLayout();
64 | this.splitContainer1.Panel2.SuspendLayout();
65 | this.splitContainer1.SuspendLayout();
66 | this.tableLayoutPanel1.SuspendLayout();
67 | this.statisticsGroupBox.SuspendLayout();
68 | this.tableLayoutPanel3.SuspendLayout();
69 | this.groupBox1.SuspendLayout();
70 | this.groupBox2.SuspendLayout();
71 | ((System.ComponentModel.ISupportInitialize)(this.numericUpDownStart)).BeginInit();
72 | this.groupBox3.SuspendLayout();
73 | ((System.ComponentModel.ISupportInitialize)(this.numericUpDownEnd)).BeginInit();
74 | this.tableLayoutPanel2.SuspendLayout();
75 | this.SuspendLayout();
76 | //
77 | // splitContainer1
78 | //
79 | this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
80 | this.splitContainer1.Location = new System.Drawing.Point(0, 0);
81 | this.splitContainer1.Name = "splitContainer1";
82 | this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal;
83 | //
84 | // splitContainer1.Panel1
85 | //
86 | this.splitContainer1.Panel1.Controls.Add(this.plot1);
87 | //
88 | // splitContainer1.Panel2
89 | //
90 | this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1);
91 | this.splitContainer1.Size = new System.Drawing.Size(1299, 791);
92 | this.splitContainer1.SplitterDistance = 699;
93 | this.splitContainer1.TabIndex = 0;
94 | //
95 | // plot1
96 | //
97 | this.plot1.BackColor = System.Drawing.Color.White;
98 | this.plot1.Dock = System.Windows.Forms.DockStyle.Fill;
99 | this.plot1.KeyboardPanHorizontalStep = 0.1D;
100 | this.plot1.KeyboardPanVerticalStep = 0.1D;
101 | this.plot1.Location = new System.Drawing.Point(0, 0);
102 | this.plot1.Name = "plot1";
103 | this.plot1.PanCursor = System.Windows.Forms.Cursors.Hand;
104 | this.plot1.Size = new System.Drawing.Size(1299, 699);
105 | this.plot1.TabIndex = 0;
106 | this.plot1.Text = "plot1";
107 | this.plot1.ZoomHorizontalCursor = System.Windows.Forms.Cursors.SizeWE;
108 | this.plot1.ZoomRectangleCursor = System.Windows.Forms.Cursors.SizeNWSE;
109 | this.plot1.ZoomVerticalCursor = System.Windows.Forms.Cursors.SizeNS;
110 | //
111 | // tableLayoutPanel1
112 | //
113 | this.tableLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
114 | | System.Windows.Forms.AnchorStyles.Left)
115 | | System.Windows.Forms.AnchorStyles.Right)));
116 | this.tableLayoutPanel1.ColumnCount = 7;
117 | this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
118 | this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
119 | this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
120 | this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
121 | this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
122 | this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
123 | this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
124 | this.tableLayoutPanel1.Controls.Add(this.statisticsGroupBox, 3, 0);
125 | this.tableLayoutPanel1.Controls.Add(this.groupBox1, 0, 0);
126 | this.tableLayoutPanel1.Controls.Add(this.groupBox2, 1, 0);
127 | this.tableLayoutPanel1.Controls.Add(this.groupBox3, 2, 0);
128 | this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 5, 0);
129 | this.tableLayoutPanel1.Controls.Add(this.buttonSavePNG, 6, 0);
130 | this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 3);
131 | this.tableLayoutPanel1.Name = "tableLayoutPanel1";
132 | this.tableLayoutPanel1.RowCount = 1;
133 | this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
134 | this.tableLayoutPanel1.Size = new System.Drawing.Size(1293, 73);
135 | this.tableLayoutPanel1.TabIndex = 1;
136 | //
137 | // statisticsGroupBox
138 | //
139 | this.statisticsGroupBox.AutoSize = true;
140 | this.statisticsGroupBox.Controls.Add(this.tableLayoutPanel3);
141 | this.statisticsGroupBox.Location = new System.Drawing.Point(501, 3);
142 | this.statisticsGroupBox.Name = "statisticsGroupBox";
143 | this.statisticsGroupBox.Padding = new System.Windows.Forms.Padding(0, 0, 5, 0);
144 | this.statisticsGroupBox.Size = new System.Drawing.Size(337, 71);
145 | this.statisticsGroupBox.TabIndex = 6;
146 | this.statisticsGroupBox.TabStop = false;
147 | this.statisticsGroupBox.Text = "Statistics";
148 | //
149 | // tableLayoutPanel3
150 | //
151 | this.tableLayoutPanel3.AutoSize = true;
152 | this.tableLayoutPanel3.ColumnCount = 8;
153 | this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
154 | this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
155 | this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
156 | this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
157 | this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
158 | this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
159 | this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
160 | this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
161 | this.tableLayoutPanel3.Controls.Add(this.label4, 0, 1);
162 | this.tableLayoutPanel3.Controls.Add(this.label2, 0, 0);
163 | this.tableLayoutPanel3.Controls.Add(this.maxInterval, 1, 0);
164 | this.tableLayoutPanel3.Controls.Add(this.avgInterval, 1, 1);
165 | this.tableLayoutPanel3.Controls.Add(this.label11, 2, 0);
166 | this.tableLayoutPanel3.Controls.Add(this.label12, 2, 1);
167 | this.tableLayoutPanel3.Controls.Add(this.rangeInterval, 5, 0);
168 | this.tableLayoutPanel3.Controls.Add(this.medianInterval, 5, 1);
169 | this.tableLayoutPanel3.Controls.Add(this.label14, 4, 1);
170 | this.tableLayoutPanel3.Controls.Add(this.label13, 4, 0);
171 | this.tableLayoutPanel3.Controls.Add(this.minInterval, 3, 0);
172 | this.tableLayoutPanel3.Controls.Add(this.stdevInterval, 3, 1);
173 | this.tableLayoutPanel3.Controls.Add(this.firstPercentileMetricLabel, 6, 0);
174 | this.tableLayoutPanel3.Controls.Add(this.secondPercentileMetricLabel, 6, 1);
175 | this.tableLayoutPanel3.Controls.Add(this.firstPercentileInterval, 7, 0);
176 | this.tableLayoutPanel3.Controls.Add(this.secondPercentileInterval, 7, 1);
177 | this.tableLayoutPanel3.Location = new System.Drawing.Point(6, 17);
178 | this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(0);
179 | this.tableLayoutPanel3.Name = "tableLayoutPanel3";
180 | this.tableLayoutPanel3.Padding = new System.Windows.Forms.Padding(0, 2, 0, 0);
181 | this.tableLayoutPanel3.RowCount = 2;
182 | this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
183 | this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
184 | this.tableLayoutPanel3.Size = new System.Drawing.Size(326, 41);
185 | this.tableLayoutPanel3.TabIndex = 1;
186 | //
187 | // label4
188 | //
189 | this.label4.AutoSize = true;
190 | this.label4.Location = new System.Drawing.Point(0, 25);
191 | this.label4.Margin = new System.Windows.Forms.Padding(0);
192 | this.label4.Name = "label4";
193 | this.label4.Size = new System.Drawing.Size(50, 13);
194 | this.label4.TabIndex = 3;
195 | this.label4.Text = "Average:";
196 | //
197 | // label2
198 | //
199 | this.label2.AutoSize = true;
200 | this.label2.Location = new System.Drawing.Point(0, 2);
201 | this.label2.Margin = new System.Windows.Forms.Padding(0, 0, 0, 10);
202 | this.label2.Name = "label2";
203 | this.label2.Size = new System.Drawing.Size(54, 13);
204 | this.label2.TabIndex = 1;
205 | this.label2.Text = "Maximum:";
206 | //
207 | // maxInterval
208 | //
209 | this.maxInterval.AutoSize = true;
210 | this.maxInterval.Location = new System.Drawing.Point(54, 2);
211 | this.maxInterval.Margin = new System.Windows.Forms.Padding(0, 0, 10, 0);
212 | this.maxInterval.Name = "maxInterval";
213 | this.maxInterval.Size = new System.Drawing.Size(13, 13);
214 | this.maxInterval.TabIndex = 4;
215 | this.maxInterval.Text = "0";
216 | //
217 | // avgInterval
218 | //
219 | this.avgInterval.AutoSize = true;
220 | this.avgInterval.Location = new System.Drawing.Point(54, 25);
221 | this.avgInterval.Margin = new System.Windows.Forms.Padding(0, 0, 10, 0);
222 | this.avgInterval.Name = "avgInterval";
223 | this.avgInterval.Size = new System.Drawing.Size(13, 13);
224 | this.avgInterval.TabIndex = 5;
225 | this.avgInterval.Text = "0";
226 | //
227 | // label11
228 | //
229 | this.label11.AutoSize = true;
230 | this.label11.Location = new System.Drawing.Point(77, 2);
231 | this.label11.Margin = new System.Windows.Forms.Padding(0);
232 | this.label11.Name = "label11";
233 | this.label11.Size = new System.Drawing.Size(51, 13);
234 | this.label11.TabIndex = 6;
235 | this.label11.Text = "Minimum:";
236 | //
237 | // label12
238 | //
239 | this.label12.AutoSize = true;
240 | this.label12.Location = new System.Drawing.Point(77, 25);
241 | this.label12.Margin = new System.Windows.Forms.Padding(0);
242 | this.label12.Name = "label12";
243 | this.label12.Size = new System.Drawing.Size(46, 13);
244 | this.label12.TabIndex = 7;
245 | this.label12.Text = "STDEV:";
246 | //
247 | // rangeInterval
248 | //
249 | this.rangeInterval.AutoSize = true;
250 | this.rangeInterval.Location = new System.Drawing.Point(196, 2);
251 | this.rangeInterval.Margin = new System.Windows.Forms.Padding(0, 0, 10, 0);
252 | this.rangeInterval.Name = "rangeInterval";
253 | this.rangeInterval.Size = new System.Drawing.Size(13, 13);
254 | this.rangeInterval.TabIndex = 12;
255 | this.rangeInterval.Text = "0";
256 | //
257 | // medianInterval
258 | //
259 | this.medianInterval.AutoSize = true;
260 | this.medianInterval.Location = new System.Drawing.Point(196, 25);
261 | this.medianInterval.Margin = new System.Windows.Forms.Padding(0, 0, 10, 0);
262 | this.medianInterval.Name = "medianInterval";
263 | this.medianInterval.Size = new System.Drawing.Size(13, 13);
264 | this.medianInterval.TabIndex = 13;
265 | this.medianInterval.Text = "0";
266 | //
267 | // label14
268 | //
269 | this.label14.AutoSize = true;
270 | this.label14.Location = new System.Drawing.Point(151, 25);
271 | this.label14.Margin = new System.Windows.Forms.Padding(0);
272 | this.label14.Name = "label14";
273 | this.label14.Size = new System.Drawing.Size(45, 13);
274 | this.label14.TabIndex = 11;
275 | this.label14.Text = "Median:";
276 | //
277 | // label13
278 | //
279 | this.label13.AutoSize = true;
280 | this.label13.Location = new System.Drawing.Point(151, 2);
281 | this.label13.Margin = new System.Windows.Forms.Padding(0);
282 | this.label13.Name = "label13";
283 | this.label13.Size = new System.Drawing.Size(42, 13);
284 | this.label13.TabIndex = 9;
285 | this.label13.Text = "Range:";
286 | //
287 | // minInterval
288 | //
289 | this.minInterval.AutoSize = true;
290 | this.minInterval.Location = new System.Drawing.Point(128, 2);
291 | this.minInterval.Margin = new System.Windows.Forms.Padding(0, 0, 10, 0);
292 | this.minInterval.Name = "minInterval";
293 | this.minInterval.Size = new System.Drawing.Size(13, 13);
294 | this.minInterval.TabIndex = 14;
295 | this.minInterval.Text = "0";
296 | //
297 | // stdevInterval
298 | //
299 | this.stdevInterval.AutoSize = true;
300 | this.stdevInterval.Location = new System.Drawing.Point(128, 25);
301 | this.stdevInterval.Margin = new System.Windows.Forms.Padding(0, 0, 10, 0);
302 | this.stdevInterval.Name = "stdevInterval";
303 | this.stdevInterval.Size = new System.Drawing.Size(13, 13);
304 | this.stdevInterval.TabIndex = 15;
305 | this.stdevInterval.Text = "0";
306 | //
307 | // firstPercentileMetricLabel
308 | //
309 | this.firstPercentileMetricLabel.AutoSize = true;
310 | this.firstPercentileMetricLabel.Location = new System.Drawing.Point(219, 2);
311 | this.firstPercentileMetricLabel.Margin = new System.Windows.Forms.Padding(0);
312 | this.firstPercentileMetricLabel.Name = "firstPercentileMetricLabel";
313 | this.firstPercentileMetricLabel.Size = new System.Drawing.Size(72, 13);
314 | this.firstPercentileMetricLabel.TabIndex = 16;
315 | this.firstPercentileMetricLabel.Text = "99 Percentile:";
316 | //
317 | // secondPercentileMetricLabel
318 | //
319 | this.secondPercentileMetricLabel.AutoSize = true;
320 | this.secondPercentileMetricLabel.Location = new System.Drawing.Point(219, 25);
321 | this.secondPercentileMetricLabel.Margin = new System.Windows.Forms.Padding(0);
322 | this.secondPercentileMetricLabel.Name = "secondPercentileMetricLabel";
323 | this.secondPercentileMetricLabel.Size = new System.Drawing.Size(81, 13);
324 | this.secondPercentileMetricLabel.TabIndex = 17;
325 | this.secondPercentileMetricLabel.Text = "99.9 Percentile:";
326 | //
327 | // firstPercentileInterval
328 | //
329 | this.firstPercentileInterval.AutoSize = true;
330 | this.firstPercentileInterval.Location = new System.Drawing.Point(300, 2);
331 | this.firstPercentileInterval.Margin = new System.Windows.Forms.Padding(0, 0, 10, 0);
332 | this.firstPercentileInterval.Name = "firstPercentileInterval";
333 | this.firstPercentileInterval.Size = new System.Drawing.Size(13, 13);
334 | this.firstPercentileInterval.TabIndex = 18;
335 | this.firstPercentileInterval.Text = "0";
336 | //
337 | // secondPercentileInterval
338 | //
339 | this.secondPercentileInterval.AutoSize = true;
340 | this.secondPercentileInterval.Location = new System.Drawing.Point(300, 25);
341 | this.secondPercentileInterval.Margin = new System.Windows.Forms.Padding(0, 0, 10, 0);
342 | this.secondPercentileInterval.Name = "secondPercentileInterval";
343 | this.secondPercentileInterval.Size = new System.Drawing.Size(13, 13);
344 | this.secondPercentileInterval.TabIndex = 19;
345 | this.secondPercentileInterval.Text = "0";
346 | //
347 | // groupBox1
348 | //
349 | this.groupBox1.Controls.Add(this.comboBoxPlotType);
350 | this.groupBox1.Location = new System.Drawing.Point(3, 3);
351 | this.groupBox1.Name = "groupBox1";
352 | this.groupBox1.Size = new System.Drawing.Size(210, 71);
353 | this.groupBox1.TabIndex = 4;
354 | this.groupBox1.TabStop = false;
355 | this.groupBox1.Text = "Plot Type";
356 | //
357 | // comboBoxPlotType
358 | //
359 | this.comboBoxPlotType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
360 | this.comboBoxPlotType.FormattingEnabled = true;
361 | this.comboBoxPlotType.Items.AddRange(new object[] {
362 | "xCount vs. Time",
363 | "yCount vs. Time",
364 | "xyCount vs. Time",
365 | "Interval vs. Time",
366 | "Frequency vs. Time",
367 | "xVelocity vs. Time",
368 | "yVelocity vs. Time",
369 | "xyVelocity vs. Time",
370 | "X vs. Y"});
371 | this.comboBoxPlotType.Location = new System.Drawing.Point(6, 30);
372 | this.comboBoxPlotType.Name = "comboBoxPlotType";
373 | this.comboBoxPlotType.Size = new System.Drawing.Size(200, 21);
374 | this.comboBoxPlotType.TabIndex = 1;
375 | //
376 | // groupBox2
377 | //
378 | this.groupBox2.Controls.Add(this.numericUpDownStart);
379 | this.groupBox2.Location = new System.Drawing.Point(219, 3);
380 | this.groupBox2.Name = "groupBox2";
381 | this.groupBox2.Size = new System.Drawing.Size(135, 71);
382 | this.groupBox2.TabIndex = 5;
383 | this.groupBox2.TabStop = false;
384 | this.groupBox2.Text = "Time Start (ms)";
385 | //
386 | // numericUpDownStart
387 | //
388 | this.numericUpDownStart.Location = new System.Drawing.Point(6, 30);
389 | this.numericUpDownStart.Name = "numericUpDownStart";
390 | this.numericUpDownStart.Size = new System.Drawing.Size(120, 20);
391 | this.numericUpDownStart.TabIndex = 3;
392 | //
393 | // groupBox3
394 | //
395 | this.groupBox3.Controls.Add(this.numericUpDownEnd);
396 | this.groupBox3.Location = new System.Drawing.Point(360, 3);
397 | this.groupBox3.Name = "groupBox3";
398 | this.groupBox3.Size = new System.Drawing.Size(135, 71);
399 | this.groupBox3.TabIndex = 6;
400 | this.groupBox3.TabStop = false;
401 | this.groupBox3.Text = "Time End (ms)";
402 | //
403 | // numericUpDownEnd
404 | //
405 | this.numericUpDownEnd.Location = new System.Drawing.Point(6, 30);
406 | this.numericUpDownEnd.Name = "numericUpDownEnd";
407 | this.numericUpDownEnd.Size = new System.Drawing.Size(120, 20);
408 | this.numericUpDownEnd.TabIndex = 2;
409 | //
410 | // tableLayoutPanel2
411 | //
412 | this.tableLayoutPanel2.ColumnCount = 1;
413 | this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
414 | this.tableLayoutPanel2.Controls.Add(this.checkBoxLines, 0, 0);
415 | this.tableLayoutPanel2.Controls.Add(this.checkBoxStem, 0, 1);
416 | this.tableLayoutPanel2.Location = new System.Drawing.Point(844, 3);
417 | this.tableLayoutPanel2.Name = "tableLayoutPanel2";
418 | this.tableLayoutPanel2.RowCount = 2;
419 | this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
420 | this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
421 | this.tableLayoutPanel2.Size = new System.Drawing.Size(66, 63);
422 | this.tableLayoutPanel2.TabIndex = 7;
423 | //
424 | // checkBoxLines
425 | //
426 | this.checkBoxLines.AutoSize = true;
427 | this.checkBoxLines.Location = new System.Drawing.Point(3, 15);
428 | this.checkBoxLines.Margin = new System.Windows.Forms.Padding(3, 15, 3, 3);
429 | this.checkBoxLines.Name = "checkBoxLines";
430 | this.checkBoxLines.Size = new System.Drawing.Size(51, 17);
431 | this.checkBoxLines.TabIndex = 9;
432 | this.checkBoxLines.Text = "Lines";
433 | this.checkBoxLines.UseVisualStyleBackColor = true;
434 | //
435 | // checkBoxStem
436 | //
437 | this.checkBoxStem.AutoSize = true;
438 | this.checkBoxStem.Location = new System.Drawing.Point(3, 38);
439 | this.checkBoxStem.Name = "checkBoxStem";
440 | this.checkBoxStem.Size = new System.Drawing.Size(50, 17);
441 | this.checkBoxStem.TabIndex = 8;
442 | this.checkBoxStem.Text = "Stem";
443 | this.checkBoxStem.UseVisualStyleBackColor = true;
444 | //
445 | // buttonSavePNG
446 | //
447 | this.buttonSavePNG.Anchor = System.Windows.Forms.AnchorStyles.Right;
448 | this.buttonSavePNG.Location = new System.Drawing.Point(1209, 27);
449 | this.buttonSavePNG.Margin = new System.Windows.Forms.Padding(3, 3, 9, 3);
450 | this.buttonSavePNG.Name = "buttonSavePNG";
451 | this.buttonSavePNG.Size = new System.Drawing.Size(75, 23);
452 | this.buttonSavePNG.TabIndex = 7;
453 | this.buttonSavePNG.Text = "SavePNG";
454 | this.buttonSavePNG.UseVisualStyleBackColor = true;
455 | this.buttonSavePNG.Click += new System.EventHandler(this.buttonSavePNG_Click);
456 | //
457 | // MousePlot
458 | //
459 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
460 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
461 | this.AutoSize = true;
462 | this.ClientSize = new System.Drawing.Size(1299, 791);
463 | this.Controls.Add(this.splitContainer1);
464 | this.MinimumSize = new System.Drawing.Size(1315, 830);
465 | this.Name = "MousePlot";
466 | this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
467 | this.splitContainer1.Panel1.ResumeLayout(false);
468 | this.splitContainer1.Panel2.ResumeLayout(false);
469 | ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
470 | this.splitContainer1.ResumeLayout(false);
471 | this.tableLayoutPanel1.ResumeLayout(false);
472 | this.tableLayoutPanel1.PerformLayout();
473 | this.statisticsGroupBox.ResumeLayout(false);
474 | this.statisticsGroupBox.PerformLayout();
475 | this.tableLayoutPanel3.ResumeLayout(false);
476 | this.tableLayoutPanel3.PerformLayout();
477 | this.groupBox1.ResumeLayout(false);
478 | this.groupBox2.ResumeLayout(false);
479 | ((System.ComponentModel.ISupportInitialize)(this.numericUpDownStart)).EndInit();
480 | this.groupBox3.ResumeLayout(false);
481 | ((System.ComponentModel.ISupportInitialize)(this.numericUpDownEnd)).EndInit();
482 | this.tableLayoutPanel2.ResumeLayout(false);
483 | this.tableLayoutPanel2.PerformLayout();
484 | this.ResumeLayout(false);
485 |
486 | }
487 |
488 | #endregion
489 |
490 | private System.Windows.Forms.SplitContainer splitContainer1;
491 | private OxyPlot.WindowsForms.Plot plot1;
492 | private System.Windows.Forms.ComboBox comboBoxPlotType;
493 | private System.Windows.Forms.NumericUpDown numericUpDownStart;
494 | private System.Windows.Forms.NumericUpDown numericUpDownEnd;
495 | private System.Windows.Forms.GroupBox groupBox3;
496 | private System.Windows.Forms.GroupBox groupBox2;
497 | private System.Windows.Forms.GroupBox groupBox1;
498 | private System.Windows.Forms.Button buttonSavePNG;
499 | private System.Windows.Forms.CheckBox checkBoxStem;
500 | private System.Windows.Forms.CheckBox checkBoxLines;
501 | private System.Windows.Forms.GroupBox statisticsGroupBox;
502 | private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
503 | private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
504 | private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
505 | private System.Windows.Forms.Label label4;
506 | private System.Windows.Forms.Label label2;
507 | private System.Windows.Forms.Label maxInterval;
508 | private System.Windows.Forms.Label avgInterval;
509 | private System.Windows.Forms.Label label11;
510 | private System.Windows.Forms.Label label12;
511 | private System.Windows.Forms.Label rangeInterval;
512 | private System.Windows.Forms.Label medianInterval;
513 | private System.Windows.Forms.Label label14;
514 | private System.Windows.Forms.Label label13;
515 | private System.Windows.Forms.Label minInterval;
516 | private System.Windows.Forms.Label stdevInterval;
517 | private System.Windows.Forms.Label firstPercentileMetricLabel;
518 | private System.Windows.Forms.Label secondPercentileMetricLabel;
519 | private System.Windows.Forms.Label firstPercentileInterval;
520 | private System.Windows.Forms.Label secondPercentileInterval;
521 | }
522 | }
--------------------------------------------------------------------------------
/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 double last_start_time;
25 | private int last_end;
26 | private double last_end_time;
27 | double x_min;
28 | double x_max;
29 | double y_min;
30 | double y_max;
31 | private string xlabel = "";
32 | private string ylabel = "";
33 |
34 | public MousePlot(MouseLog Mlog)
35 | {
36 | this.Text = $"MousePlot v{Program.version}";
37 | InitializeComponent();
38 | this.mlog = new MouseLog();
39 | this.mlog.Desc = Mlog.Desc;
40 | this.mlog.Cpi = Mlog.Cpi;
41 | int i = 1;
42 | int x = Mlog.Events[0].lastx;
43 | int y = Mlog.Events[0].lasty;
44 | ushort buttonflags = Mlog.Events[0].buttonflags;
45 | double ts = Mlog.Events[0].ts;
46 | while (i < Mlog.Events.Count)
47 | {
48 | this.mlog.Add(new MouseEvent(buttonflags, x, y, ts));
49 | x = Mlog.Events[i].lastx;
50 | y = Mlog.Events[i].lasty;
51 | buttonflags = Mlog.Events[i].buttonflags;
52 | ts = Mlog.Events[i].ts;
53 | i++;
54 | }
55 | this.mlog.Add(new MouseEvent(buttonflags, x, y, ts));
56 |
57 | this.last_end = mlog.Events.Count - 1;
58 | this.last_end_time = Mlog.Events[this.last_end].ts;
59 |
60 | this.last_start_time = mlog.Events[last_end].ts > 100 ? 100 : 0;
61 | initialize_plot();
62 |
63 | this.comboBoxPlotType.SelectedIndex = 0;
64 | this.comboBoxPlotType.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged);
65 |
66 | this.numericUpDownStart.Minimum = 0;
67 | this.numericUpDownStart.Maximum = (decimal)last_end_time;
68 | this.numericUpDownStart.Value = (decimal)last_start_time;
69 | this.numericUpDownStart.DecimalPlaces = 3;
70 | this.numericUpDownStart.Increment = 10;
71 | this.numericUpDownStart.ValueChanged += new System.EventHandler(this.numericUpDownStart_ValueChanged);
72 |
73 | this.numericUpDownEnd.Minimum = 0;
74 | this.numericUpDownEnd.Maximum = (decimal)last_end_time;
75 | this.numericUpDownEnd.Value = (decimal)last_end_time;
76 | this.numericUpDownEnd.DecimalPlaces = 3;
77 | this.numericUpDownEnd.Increment = 10;
78 | this.numericUpDownEnd.ValueChanged += new System.EventHandler(this.numericUpDownEnd_ValueChanged);
79 |
80 | this.checkBoxStem.Checked = false;
81 | this.checkBoxStem.CheckedChanged += new System.EventHandler(this.checkBoxStem_CheckedChanged);
82 |
83 | this.checkBoxLines.Checked = false;
84 | this.checkBoxLines.CheckedChanged += new System.EventHandler(this.checkBoxLines_CheckedChanged);
85 |
86 | // open MousePlot to "Interval vs. Time" selection
87 | comboBoxPlotType.SelectedItem = "Interval vs. Time";
88 |
89 | refresh_plot();
90 | }
91 |
92 | private void initialize_plot()
93 | {
94 | var pm = new PlotModel(this.mlog.Desc.ToString())
95 | {
96 | PlotType = PlotType.Cartesian,
97 | Background = OxyColors.White,
98 | Subtitle = this.mlog.Cpi.ToString() + " cpi"
99 | };
100 | plot1.Model = pm;
101 | }
102 |
103 | private void refresh_plot()
104 | {
105 | for (int j = 0; j < mlog.Events.Count; j++) {
106 | double currentTimeStamp = mlog.Events[j].ts;
107 |
108 | if (currentTimeStamp >= last_start_time) {
109 | last_start = j;
110 | last_start_time = currentTimeStamp;
111 | numericUpDownStart.Value = (decimal)currentTimeStamp;
112 | break;
113 | }
114 | }
115 |
116 | for (int j = mlog.Events.Count - 1; j >= 0; j--) {
117 | double currentTimeStamp = mlog.Events[j].ts;
118 |
119 | if (currentTimeStamp <= last_end_time) {
120 | last_end = j;
121 | last_end_time = currentTimeStamp;
122 | numericUpDownEnd.Value = (decimal)currentTimeStamp;
123 | break;
124 | }
125 | }
126 |
127 | PlotModel pm = plot1.Model;
128 | pm.Series.Clear();
129 | pm.Axes.Clear();
130 | OxyColor singleLineColor = OxyColors.Green;
131 |
132 | var scatterSeries1 = new ScatterSeries
133 | {
134 | BinSize = 8,
135 | MarkerFill = OxyColors.Blue,
136 | MarkerSize = 1.5,
137 | MarkerStroke = OxyColors.Blue,
138 | MarkerStrokeThickness = 1.0,
139 | MarkerType = MarkerType.Circle
140 | };
141 |
142 | var scatterSeries2 = new ScatterSeries
143 | {
144 | BinSize = 8,
145 | MarkerFill = OxyColors.Red,
146 | MarkerSize = 1.5,
147 | MarkerStroke = OxyColors.Red,
148 | MarkerStrokeThickness = 1.0,
149 | MarkerType = MarkerType.Circle
150 | };
151 |
152 | var lineSeries1 = new LineSeries
153 | {
154 | Color = OxyColors.Blue,
155 | LineStyle = LineStyle.Solid,
156 | StrokeThickness = 2.0,
157 | Smooth = true
158 | };
159 |
160 | var lineSeries2 = new LineSeries
161 | {
162 | Color = OxyColors.Red,
163 | LineStyle = LineStyle.Solid,
164 | StrokeThickness = 2.0,
165 | Smooth = true
166 | };
167 |
168 | if (checkBoxLines.Checked)
169 | {
170 | lineSeries1.Smooth = false;
171 | lineSeries2.Smooth = false;
172 | }
173 |
174 | var stemSeries1 = new StemSeries
175 | {
176 | Color = OxyColors.Blue,
177 | StrokeThickness = 1.0,
178 | };
179 |
180 | var stemSeries2 = new StemSeries
181 | {
182 | Color = OxyColors.Red,
183 | StrokeThickness = 1.0
184 | };
185 |
186 | // Only display statistics when "Interval" or "Frequency" is selected
187 | statisticsGroupBox.Visible = comboBoxPlotType.Text.Contains("Interval") || comboBoxPlotType.Text.Contains("Frequency");
188 |
189 | if (comboBoxPlotType.Text.Contains("xyCount"))
190 | {
191 | plot_xycounts_vs_time(scatterSeries1, scatterSeries2, stemSeries1, stemSeries2, lineSeries1, lineSeries2);
192 | pm.Series.Add(scatterSeries1);
193 | pm.Series.Add(scatterSeries2);
194 | if (!checkBoxLines.Checked)
195 | {
196 | plot_fit(scatterSeries1, lineSeries1);
197 | plot_fit(scatterSeries2, lineSeries2);
198 | }
199 | pm.Series.Add(lineSeries1);
200 | pm.Series.Add(lineSeries2);
201 | if (checkBoxStem.Checked)
202 | {
203 | pm.Series.Add(stemSeries1);
204 | pm.Series.Add(stemSeries2);
205 | }
206 | }
207 | else if (comboBoxPlotType.Text.Contains("xCount"))
208 | {
209 | plot_xcounts_vs_time(scatterSeries1, stemSeries1, lineSeries1);
210 | pm.Series.Add(scatterSeries1);
211 | if (!checkBoxLines.Checked)
212 | {
213 | plot_fit(scatterSeries1, lineSeries1);
214 | lineSeries1.Color = singleLineColor;
215 | }
216 | pm.Series.Add(lineSeries1);
217 | if (checkBoxStem.Checked)
218 | {
219 | pm.Series.Add(stemSeries1);
220 | }
221 | }
222 | else if (comboBoxPlotType.Text.Contains("yCount"))
223 | {
224 | plot_ycounts_vs_time(scatterSeries1, stemSeries1, lineSeries1);
225 | pm.Series.Add(scatterSeries1);
226 | if (!checkBoxLines.Checked)
227 | {
228 | plot_fit(scatterSeries1, lineSeries1);
229 | lineSeries1.Color = singleLineColor;
230 | }
231 | pm.Series.Add(lineSeries1);
232 | if (checkBoxStem.Checked)
233 | {
234 | pm.Series.Add(stemSeries1);
235 | }
236 |
237 | }
238 | else if (comboBoxPlotType.Text.Contains("Interval") || comboBoxPlotType.Text.Contains("Frequency"))
239 | {
240 | plot_interval_vs_time(scatterSeries1, stemSeries1, lineSeries1, comboBoxPlotType.Text.Contains("Interval"), (value) => comboBoxPlotType.Text.Contains("Interval") ? value : 1000 / value);
241 | pm.Series.Add(scatterSeries1);
242 | if (!checkBoxLines.Checked)
243 | {
244 | plot_fit(scatterSeries1, lineSeries1);
245 | lineSeries1.Color = singleLineColor;
246 | }
247 | pm.Series.Add(lineSeries1);
248 | if (checkBoxStem.Checked)
249 | {
250 | pm.Series.Add(stemSeries1);
251 | }
252 |
253 | }
254 | else if (comboBoxPlotType.Text.Contains("xyVelocity"))
255 | {
256 | plot_xyvelocity_vs_time(scatterSeries1, scatterSeries2, stemSeries1, stemSeries2, lineSeries1, lineSeries2);
257 | pm.Series.Add(scatterSeries1);
258 | pm.Series.Add(scatterSeries2);
259 | if (!checkBoxLines.Checked)
260 | {
261 | plot_fit(scatterSeries1, lineSeries1);
262 | plot_fit(scatterSeries2, lineSeries2);
263 | }
264 | pm.Series.Add(lineSeries1);
265 | pm.Series.Add(lineSeries2);
266 | if (checkBoxStem.Checked)
267 | {
268 | pm.Series.Add(stemSeries1);
269 | pm.Series.Add(stemSeries2);
270 | }
271 |
272 | }
273 | else if (comboBoxPlotType.Text.Contains("xVelocity"))
274 | {
275 | plot_xvelocity_vs_time(scatterSeries1, stemSeries1, lineSeries1);
276 | pm.Series.Add(scatterSeries1);
277 | if (!checkBoxLines.Checked)
278 | {
279 | plot_fit(scatterSeries1, lineSeries1);
280 | lineSeries1.Color = singleLineColor;
281 | }
282 | pm.Series.Add(lineSeries1);
283 | if (checkBoxStem.Checked)
284 | {
285 | pm.Series.Add(stemSeries1);
286 | }
287 | }
288 | else if (comboBoxPlotType.Text.Contains("yVelocity"))
289 | {
290 | plot_yvelocity_vs_time(scatterSeries1, stemSeries1, lineSeries1);
291 | pm.Series.Add(scatterSeries1);
292 | if (!checkBoxLines.Checked)
293 | {
294 | plot_fit(scatterSeries1, lineSeries1);
295 | lineSeries1.Color = singleLineColor;
296 | }
297 | pm.Series.Add(lineSeries1);
298 | if (checkBoxStem.Checked)
299 | {
300 | pm.Series.Add(stemSeries1);
301 | }
302 | }
303 | else if (comboBoxPlotType.Text.Contains("X vs. Y"))
304 | {
305 | plot_x_vs_y(scatterSeries1, lineSeries1);
306 | pm.Series.Add(scatterSeries1);
307 | if (checkBoxLines.Checked)
308 | {
309 | pm.Series.Add(lineSeries1);
310 | lineSeries1.Color = singleLineColor;
311 | }
312 | }
313 |
314 | var linearAxis1 = new LinearAxis();
315 | linearAxis1.AbsoluteMinimum = x_min - (x_max - x_min) / 20.0;
316 | linearAxis1.AbsoluteMaximum = x_max + (x_max - x_min) / 20.0;
317 | linearAxis1.MajorGridlineColor = OxyColor.FromArgb(40, 0, 0, 139);
318 | linearAxis1.MajorGridlineStyle = LineStyle.Solid;
319 | linearAxis1.MinorGridlineColor = OxyColor.FromArgb(20, 0, 0, 139);
320 | linearAxis1.MinorGridlineStyle = LineStyle.Solid;
321 | linearAxis1.Position = AxisPosition.Bottom;
322 | linearAxis1.Title = xlabel;
323 | pm.Axes.Add(linearAxis1);
324 |
325 | var linearAxis2 = new LinearAxis();
326 | linearAxis2.AbsoluteMinimum = y_min - (y_max - y_min) / 20.0;
327 | linearAxis2.AbsoluteMaximum = y_max + (y_max - y_min) / 20.0;
328 | linearAxis2.MajorGridlineColor = OxyColor.FromArgb(40, 0, 0, 139);
329 | linearAxis2.MajorGridlineStyle = LineStyle.Solid;
330 | linearAxis2.MinorGridlineColor = OxyColor.FromArgb(20, 0, 0, 139);
331 | linearAxis2.MinorGridlineStyle = LineStyle.Solid;
332 | linearAxis2.Title = ylabel;
333 | pm.Axes.Add(linearAxis2);
334 |
335 | plot1.RefreshPlot(true);
336 | }
337 |
338 | private void reset_minmax()
339 | {
340 | x_min = double.MaxValue;
341 | x_max = double.MinValue;
342 | y_min = double.MaxValue;
343 | y_max = double.MinValue;
344 | }
345 |
346 | private void update_minmax(double x, double y)
347 | {
348 | if (x < x_min)
349 | {
350 | x_min = x;
351 | }
352 | if (x > x_max)
353 | {
354 | x_max = x;
355 | }
356 | if (y < y_min)
357 | {
358 | y_min = y;
359 | }
360 | if (y > y_max)
361 | {
362 | y_max = y;
363 | }
364 | }
365 |
366 | private void plot_xcounts_vs_time(ScatterSeries scatterSeries1, StemSeries stemSeries1, LineSeries lineSeries1)
367 | {
368 | xlabel = "Time (ms)";
369 | ylabel = "xCounts";
370 | reset_minmax();
371 | for (int i = last_start; i <= last_end; i++)
372 | {
373 | double x = this.mlog.Events[i].ts;
374 | double y = this.mlog.Events[i].lastx;
375 | update_minmax(x, y);
376 | scatterSeries1.Points.Add(new ScatterPoint(x, y));
377 | lineSeries1.Points.Add(new DataPoint(x, y));
378 | stemSeries1.Points.Add(new DataPoint(x, y));
379 | }
380 | }
381 |
382 | private void plot_ycounts_vs_time(ScatterSeries scatterSeries1, StemSeries stemSeries1, LineSeries lineSeries1)
383 | {
384 | xlabel = "Time (ms)";
385 | ylabel = "yCounts";
386 | reset_minmax();
387 | for (int i = last_start; i <= last_end; i++)
388 | {
389 | double x = this.mlog.Events[i].ts;
390 | double y = this.mlog.Events[i].lasty;
391 | update_minmax(x, y);
392 | scatterSeries1.Points.Add(new ScatterPoint(x, y));
393 | lineSeries1.Points.Add(new DataPoint(x, y));
394 | stemSeries1.Points.Add(new DataPoint(x, y));
395 | }
396 | }
397 |
398 | private void plot_xycounts_vs_time(ScatterSeries scatterSeries1, ScatterSeries scatterSeries2, StemSeries stemSeries1, StemSeries stemSeries2, LineSeries lineSeries1, LineSeries lineSeries2)
399 | {
400 | xlabel = "Time (ms)";
401 | ylabel = "Counts [x = Blue, y = Red]";
402 | reset_minmax();
403 | for (int i = last_start; i <= last_end; i++)
404 | {
405 | double x = this.mlog.Events[i].ts;
406 | double y = this.mlog.Events[i].lastx;
407 | update_minmax(x, y);
408 | scatterSeries1.Points.Add(new ScatterPoint(x, y));
409 | lineSeries1.Points.Add(new DataPoint(x, y));
410 | stemSeries1.Points.Add(new DataPoint(x, y));
411 | }
412 |
413 | for (int i = last_start; i <= last_end; i++)
414 | {
415 | double x = this.mlog.Events[i].ts;
416 | double y = this.mlog.Events[i].lasty;
417 | update_minmax(x, y);
418 | scatterSeries2.Points.Add(new ScatterPoint(x, y));
419 | lineSeries2.Points.Add(new DataPoint(x, y));
420 | stemSeries2.Points.Add(new DataPoint(x, y));
421 | }
422 | }
423 |
424 | private void plot_interval_vs_time(ScatterSeries scatterSeries1, StemSeries stemSeries1, LineSeries lineSeries1, bool isInterval, Func transformFunction)
425 | {
426 | xlabel = "Time (ms)";
427 |
428 | double firstPercentileMetric;
429 | double secondPercentileMetric;
430 |
431 | if (isInterval) {
432 | ylabel = "Update Time (ms)";
433 | firstPercentileMetric = 99;
434 | firstPercentileMetricLabel.Text = "99 Percentile:";
435 | secondPercentileMetric = 99.9;
436 | secondPercentileMetricLabel.Text = "99.9 Percentile:";
437 | } else {
438 | ylabel = "Frequency (Hz)";
439 | firstPercentileMetric = 1;
440 | firstPercentileMetricLabel.Text = "1 Percentile:";
441 | secondPercentileMetric = 0.1;
442 | secondPercentileMetricLabel.Text = "0.1 Percentile:";
443 | }
444 |
445 | List intervals = new List();
446 | reset_minmax();
447 | for (int i = last_start; i <= last_end; i++)
448 | {
449 | double x = this.mlog.Events[i].ts;
450 | double y;
451 | if (i == 0)
452 | {
453 | y = 0.0;
454 | }
455 | else
456 | {
457 | y = this.mlog.Events[i].ts - this.mlog.Events[i - 1].ts;
458 | }
459 | intervals.Add(y);
460 | update_minmax(x, transformFunction(y));
461 | scatterSeries1.Points.Add(new ScatterPoint(x, transformFunction(y)));
462 | lineSeries1.Points.Add(new DataPoint(x, transformFunction(y)));
463 | stemSeries1.Points.Add(new DataPoint(x, transformFunction(y)));
464 | }
465 |
466 | // Calculate statistics
467 |
468 | List intervals_descending = intervals.OrderByDescending(x => x).ToList();
469 | List intervals_ascending = intervals.OrderBy(x => x).ToList();
470 |
471 | double sum = intervals_descending.Sum();
472 | int count = intervals_descending.Count();
473 | double average = transformFunction(sum / count);
474 | double squared_deviations = 0.0;
475 | int middle_index = count / 2;
476 | int last_index = count - 1;
477 | double range = intervals_descending[0] - intervals_descending[last_index];
478 |
479 | foreach (double interval in intervals)
480 | {
481 | squared_deviations += Math.Pow(transformFunction(interval) - average, 2);
482 | }
483 | double maximumValue = transformFunction(isInterval ? intervals_descending[0] : intervals_descending[last_index]);
484 | double minimumValue = transformFunction(isInterval ? intervals_descending[last_index] : intervals_descending[0]);
485 |
486 | maxInterval.Text = $"{maximumValue:0.0000####}";
487 | minInterval.Text = $"{minimumValue:0.0000####}";
488 | avgInterval.Text = $"{average:0.0000####}";
489 | stdevInterval.Text = $"{Math.Sqrt(squared_deviations / (last_index)):0.0000####}";
490 | rangeInterval.Text = $"{maximumValue - minimumValue:0.0000####}";
491 | medianInterval.Text = $"{(transformFunction(count % 2 == 1 ? intervals_descending[middle_index] : (intervals_descending[middle_index - 1] + intervals_descending[middle_index]) / 2)):0.0000####}";
492 |
493 | List percentiles_list = isInterval ? intervals_ascending : intervals_descending;
494 |
495 | firstPercentileInterval.Text = $"{transformFunction(percentiles_list[(int) Math.Ceiling(firstPercentileMetric / 100 * count) - 1]):0.0000####}";
496 | secondPercentileInterval.Text = $"{transformFunction(percentiles_list[(int)Math.Ceiling(secondPercentileMetric / 100 * count) - 1]):0.0000####}";
497 | }
498 |
499 | private void plot_xvelocity_vs_time(ScatterSeries scatterSeries1, StemSeries stemSeries1, LineSeries lineSeries1)
500 | {
501 | xlabel = "Time (ms)";
502 | ylabel = "xVelocity (m/s)";
503 | reset_minmax();
504 | if (this.mlog.Cpi > 0)
505 | {
506 | for (int i = last_start; i <= last_end; i++)
507 | {
508 | double x = this.mlog.Events[i].ts;
509 | double y;
510 | if (i == 0)
511 | {
512 | y = 0.0;
513 | }
514 | else
515 | {
516 | y = (this.mlog.Events[i].lastx) / (this.mlog.Events[i].ts - this.mlog.Events[i - 1].ts) / this.mlog.Cpi * 25.4;
517 | }
518 | update_minmax(x, y);
519 | scatterSeries1.Points.Add(new ScatterPoint(x, y));
520 | lineSeries1.Points.Add(new DataPoint(x, y));
521 | stemSeries1.Points.Add(new DataPoint(x, y));
522 | }
523 | }
524 | else
525 | {
526 | MessageBox.Show("CPI value is invalid, please run Measure");
527 | }
528 | }
529 |
530 | private void plot_yvelocity_vs_time(ScatterSeries scatterSeries1, StemSeries stemSeries1, LineSeries lineSeries1)
531 | {
532 | xlabel = "Time (ms)";
533 | ylabel = "yVelocity (m/s)";
534 | reset_minmax();
535 | if (this.mlog.Cpi > 0)
536 | {
537 | for (int i = last_start; i <= last_end; i++)
538 | {
539 | double x = this.mlog.Events[i].ts;
540 | double y;
541 | if (i == 0)
542 | {
543 | y = 0.0;
544 | }
545 | else
546 | {
547 | y = (this.mlog.Events[i].lasty) / (this.mlog.Events[i].ts - this.mlog.Events[i - 1].ts) / this.mlog.Cpi * 25.4;
548 | }
549 | update_minmax(x, y);
550 | scatterSeries1.Points.Add(new ScatterPoint(x, y));
551 | lineSeries1.Points.Add(new DataPoint(x, y));
552 | stemSeries1.Points.Add(new DataPoint(x, y));
553 | }
554 | }
555 | else
556 | {
557 | MessageBox.Show("CPI value is invalid, please run Measure");
558 | }
559 | }
560 |
561 | private void plot_xyvelocity_vs_time(ScatterSeries scatterSeries1, ScatterSeries scatterSeries2, StemSeries stemSeries1, StemSeries stemSeries2, LineSeries lineSeries1, LineSeries lineSeries2)
562 | {
563 | xlabel = "Time (ms)";
564 | ylabel = "Velocity (m/s) [x = Blue, y = Red]";
565 | reset_minmax();
566 | if (this.mlog.Cpi > 0)
567 | {
568 | for (int i = last_start; i <= last_end; i++)
569 | {
570 | double x = this.mlog.Events[i].ts;
571 | double y;
572 | if (i == 0)
573 | {
574 | y = 0.0;
575 | }
576 | else
577 | {
578 | y = (this.mlog.Events[i].lastx) / (this.mlog.Events[i].ts - this.mlog.Events[i - 1].ts) / this.mlog.Cpi * 25.4;
579 | }
580 | update_minmax(x, y);
581 | scatterSeries1.Points.Add(new ScatterPoint(x, y));
582 | lineSeries1.Points.Add(new DataPoint(x, y));
583 | stemSeries1.Points.Add(new DataPoint(x, y));
584 | }
585 |
586 | for (int i = last_start; i <= last_end; i++)
587 | {
588 | double x = this.mlog.Events[i].ts;
589 | double y;
590 | if (i == 0)
591 | {
592 | y = 0.0;
593 | }
594 | else
595 | {
596 | y = (this.mlog.Events[i].lasty) / (this.mlog.Events[i].ts - this.mlog.Events[i - 1].ts) / this.mlog.Cpi * 25.4;
597 | }
598 | update_minmax(x, y);
599 | scatterSeries2.Points.Add(new ScatterPoint(x, y));
600 | lineSeries2.Points.Add(new DataPoint(x, y));
601 | stemSeries2.Points.Add(new DataPoint(x, y));
602 | }
603 | }
604 | else
605 | {
606 | MessageBox.Show("CPI value is invalid, please run Measure");
607 | }
608 | }
609 |
610 | private void plot_x_vs_y(ScatterSeries scatterSeries1, LineSeries lineSeries1)
611 | {
612 | xlabel = "xCounts";
613 | ylabel = "yCounts";
614 | reset_minmax();
615 | double x = 0.0;
616 | double y = 0.0;
617 | for (int i = last_start; i <= last_end; i++)
618 | {
619 | x += this.mlog.Events[i].lastx;
620 | y += this.mlog.Events[i].lasty;
621 | update_minmax(x, x);
622 | update_minmax(y, y);
623 | scatterSeries1.Points.Add(new ScatterPoint(x, y));
624 | lineSeries1.Points.Add(new DataPoint(x, y));
625 | }
626 | }
627 |
628 | #if false
629 | // Window based smoothing
630 | private void plot_fit(ScatterSeries scatterSeries1, LineSeries lineSeries1)
631 | {
632 | double sum = 0.0;
633 |
634 | lineSeries1.Points.Clear();
635 |
636 | for (int i = 0; ((i < 8) && (i < scatterSeries1.Points.Count)); i++)
637 | //for (int i = 0; ((i < 4) && (i < scatterSeries1.Points.Count)); i++)
638 | {
639 | sum = sum + scatterSeries1.Points[i].Y;
640 | }
641 |
642 | for (int i = 3; i < scatterSeries1.Points.Count - 5; i++)
643 | //for (int i = 1; i < scatterSeries1.Points.Count - 3; i++)
644 | {
645 | double x = (scatterSeries1.Points[i].X + scatterSeries1.Points[i + 1].X) / 2.0;
646 | double y = sum;
647 | lineSeries1.Points.Add(new DataPoint(x, y / 8.0));
648 | sum = sum - scatterSeries1.Points[i - 3].Y;
649 | sum = sum + scatterSeries1.Points[i + 5].Y;
650 | //lineSeries1.Points.Add(new DataPoint(x, y / 4.0));
651 | //sum = sum - scatterSeries1.Points[i - 1].Y;
652 | //sum = sum + scatterSeries1.Points[i + 3].Y;
653 |
654 | }
655 | }
656 | #else
657 | // Time based smoothing
658 | private void plot_fit(ScatterSeries scatterSeries1, LineSeries lineSeries1)
659 | {
660 | double hz = 125;
661 | double ms = 1000.0 / hz;
662 | lineSeries1.Points.Clear();
663 |
664 | int ind = 0;
665 | for (double x = ms; x <= scatterSeries1.Points[scatterSeries1.Points.Count - 1].X; x += ms)
666 | {
667 | double sum = 0.0;
668 | int count = 0;
669 | while (scatterSeries1.Points[ind].X <= x)
670 | {
671 | sum += scatterSeries1.Points[ind++].Y;
672 | count++;
673 | }
674 | lineSeries1.Points.Add(new DataPoint(x - (ms / 2.0), sum / count));
675 | }
676 | }
677 | #endif
678 |
679 | private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
680 | {
681 | refresh_plot();
682 | }
683 |
684 | private void numericUpDownStart_ValueChanged(object sender, EventArgs e)
685 | {
686 | if (numericUpDownStart.Value >= numericUpDownEnd.Value)
687 | {
688 | numericUpDownStart.Value = (decimal)last_start_time;
689 | }
690 | else
691 | {
692 | last_start_time = (double)numericUpDownStart.Value;
693 | refresh_plot();
694 | }
695 | }
696 |
697 | private void numericUpDownEnd_ValueChanged(object sender, EventArgs e)
698 | {
699 | if (numericUpDownEnd.Value <= numericUpDownStart.Value)
700 | {
701 | numericUpDownEnd.Value = (decimal)last_end_time;
702 | }
703 | else
704 | {
705 | last_end_time = (double)numericUpDownEnd.Value;
706 | refresh_plot();
707 | }
708 | }
709 |
710 | private void checkBoxStem_CheckedChanged(object sender, EventArgs e)
711 | {
712 | refresh_plot();
713 | }
714 |
715 | private void checkBoxLines_CheckedChanged(object sender, EventArgs e)
716 | {
717 | refresh_plot();
718 | }
719 |
720 | private void buttonSavePNG_Click(object sender, EventArgs e)
721 | {
722 | SaveFileDialog saveFileDialog1 = new SaveFileDialog();
723 | saveFileDialog1.Filter = "PNG Files (*.png)|*.png";
724 | saveFileDialog1.FilterIndex = 1;
725 | if (saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
726 | {
727 | Bitmap bitmap = new Bitmap(splitContainer1.Width, splitContainer1.Height);
728 |
729 | using (Graphics graphics = Graphics.FromImage(bitmap)) {
730 | graphics.Clear(Color.White);
731 | splitContainer1.DrawToBitmap(bitmap, new Rectangle(0, 0, splitContainer1.Width, splitContainer1.Height));
732 | }
733 |
734 | bitmap.Save(saveFileDialog1.FileName, ImageFormat.Png);
735 | }
736 | }
737 | }
738 | }
739 |
--------------------------------------------------------------------------------
/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 |
5 | Debug
6 | x86
7 | 8.0.30703
8 | 2.0
9 | {B0953B29-AF9B-4C37-A2EC-947E98F683B3}
10 | WinExe
11 | Properties
12 | MouseTester
13 | MouseTester
14 | v4.8
15 |
16 |
17 | 512
18 | false
19 | publish\
20 | true
21 | Disk
22 | false
23 | Foreground
24 | 7
25 | Days
26 | false
27 | false
28 | true
29 | 0
30 | 1.6.1.%2a
31 | false
32 | true
33 |
34 |
35 |
36 |
37 | x86
38 | true
39 | full
40 | false
41 | bin\Debug\
42 | DEBUG;TRACE
43 | prompt
44 | 4
45 | false
46 |
47 |
48 | x86
49 | pdbonly
50 | true
51 | bin\Release\
52 | TRACE
53 | prompt
54 | 4
55 | false
56 |
57 |
58 | Internet
59 |
60 |
61 | false
62 |
63 |
64 | Properties\app.manifest
65 |
66 |
67 | true
68 | bin\Debug\
69 | DEBUG;TRACE
70 | full
71 | AnyCPU
72 | 7.3
73 | prompt
74 | false
75 |
76 |
77 | bin\Release\
78 | TRACE
79 | true
80 | pdbonly
81 | AnyCPU
82 | 7.3
83 | prompt
84 | false
85 |
86 |
87 | true
88 | bin\x64\Debug\
89 | DEBUG;TRACE
90 | full
91 | x64
92 | 7.3
93 | prompt
94 | false
95 |
96 |
97 | bin\x64\Release\
98 | TRACE
99 | true
100 | pdbonly
101 | x64
102 | 7.3
103 | prompt
104 | false
105 |
106 |
107 |
108 |
109 |
110 |
111 | ..\packages\Costura.Fody.5.7.0\lib\netstandard1.0\Costura.dll
112 |
113 |
114 | ..\packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll
115 | True
116 | True
117 |
118 |
119 | False
120 | .\OxyPlot.dll
121 |
122 |
123 | False
124 | .\OxyPlot.WindowsForms.dll
125 |
126 |
127 | ..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.dll
128 |
129 |
130 | ..\packages\System.AppContext.4.3.0\lib\net463\System.AppContext.dll
131 | True
132 | True
133 |
134 |
135 | ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
136 |
137 |
138 |
139 | ..\packages\System.Console.4.3.1\lib\net46\System.Console.dll
140 | True
141 | True
142 |
143 |
144 |
145 | ..\packages\System.Diagnostics.DiagnosticSource.8.0.1\lib\net462\System.Diagnostics.DiagnosticSource.dll
146 |
147 |
148 | ..\packages\System.Diagnostics.Tracing.4.3.0\lib\net462\System.Diagnostics.Tracing.dll
149 | True
150 | True
151 |
152 |
153 | ..\packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll
154 | True
155 | True
156 |
157 |
158 | ..\packages\System.IO.4.3.0\lib\net462\System.IO.dll
159 | True
160 | True
161 |
162 |
163 | ..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll
164 | True
165 | True
166 |
167 |
168 |
169 | ..\packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll
170 | True
171 | True
172 |
173 |
174 | ..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll
175 | True
176 | True
177 |
178 |
179 | ..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll
180 | True
181 | True
182 |
183 |
184 | ..\packages\System.Linq.4.3.0\lib\net463\System.Linq.dll
185 | True
186 | True
187 |
188 |
189 | ..\packages\System.Linq.Expressions.4.3.0\lib\net463\System.Linq.Expressions.dll
190 | True
191 | True
192 |
193 |
194 | ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll
195 |
196 |
197 | ..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll
198 | True
199 | True
200 |
201 |
202 | ..\packages\System.Net.Sockets.4.3.0\lib\net46\System.Net.Sockets.dll
203 | True
204 | True
205 |
206 |
207 |
208 | ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
209 |
210 |
211 | ..\packages\System.Reflection.4.3.0\lib\net462\System.Reflection.dll
212 | True
213 | True
214 |
215 |
216 | ..\packages\System.Runtime.4.3.1\lib\net462\System.Runtime.dll
217 | True
218 | True
219 |
220 |
221 | ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
222 |
223 |
224 | ..\packages\System.Runtime.Extensions.4.3.1\lib\net462\System.Runtime.Extensions.dll
225 | True
226 | True
227 |
228 |
229 | ..\packages\System.Runtime.InteropServices.4.3.0\lib\net463\System.Runtime.InteropServices.dll
230 | True
231 | True
232 |
233 |
234 | ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
235 | True
236 | True
237 |
238 |
239 | ..\packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net463\System.Security.Cryptography.Algorithms.dll
240 | True
241 | True
242 |
243 |
244 | ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll
245 | True
246 | True
247 |
248 |
249 | ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll
250 | True
251 | True
252 |
253 |
254 | ..\packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll
255 | True
256 | True
257 |
258 |
259 | ..\packages/System.Text.RegularExpressions.4.3.1/lib/net463/System.Text.RegularExpressions.dll
260 | True
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 | ..\packages\System.Xml.ReaderWriter.4.3.1\lib\net46\System.Xml.ReaderWriter.dll
272 | True
273 | True
274 |
275 |
276 |
277 |
278 | Form
279 |
280 |
281 | Form1.cs
282 |
283 |
284 |
285 |
286 |
287 | Form
288 |
289 |
290 | MousePlot.cs
291 |
292 |
293 |
294 |
295 | Form
296 |
297 |
298 | Form1.cs
299 | Designer
300 |
301 |
302 | MousePlot.cs
303 |
304 |
305 | ResXFileCodeGenerator
306 | Resources.Designer.cs
307 | Designer
308 |
309 |
310 | True
311 | Resources.resx
312 | True
313 |
314 |
315 |
316 |
317 |
318 | SettingsSingleFileGenerator
319 | Settings.Designer.cs
320 |
321 |
322 | True
323 | Settings.settings
324 | True
325 |
326 |
327 |
328 |
329 | False
330 | Microsoft .NET Framework 4 Client Profile %28x86 and x64%29
331 | true
332 |
333 |
334 | False
335 | .NET Framework 3.5 SP1 Client Profile
336 | false
337 |
338 |
339 | False
340 | .NET Framework 3.5 SP1
341 | false
342 |
343 |
344 | False
345 | Windows Installer 3.1
346 | true
347 |
348 |
349 |
350 |
351 |
352 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
369 |
--------------------------------------------------------------------------------
/MouseTester/MouseTester/OxyPlot.WindowsForms.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valleyofdoom/MouseTester/daa5b90896d6e26ccedb30bcf2aa8f97c46c731d/MouseTester/MouseTester/OxyPlot.WindowsForms.dll
--------------------------------------------------------------------------------
/MouseTester/MouseTester/OxyPlot.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valleyofdoom/MouseTester/daa5b90896d6e26ccedb30bcf2aa8f97c46c731d/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 | public static string version = "1.7.2";
11 |
12 | ///
13 | /// The main entry point for the application.
14 | ///
15 | [STAThread]
16 | static void Main()
17 | {
18 | Application.EnableVisualStyles();
19 | Application.SetCompatibleTextRenderingDefault(false);
20 | Application.Run(new Form1());
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/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.7.2.0")]
36 | [assembly: AssemblyFileVersion("1.7.2.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", "17.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", "17.6.0.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 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/MouseTester/MouseTester/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | MouseTester
2 |
3 | [](https://github.com/valleyofdoom/MouseTester/releases)
4 |
--------------------------------------------------------------------------------