├── .gitignore
├── DeadzoneForm.cs
├── GPDInput.inl
├── GPViGEm.inl
├── GPWii.inl
├── GPWinMM.inl
├── GPXInput.inl
├── GamepadPhoenix.cs
├── GamepadPhoenix.csproj
├── GamepadPhoenix.ico
├── GamepadPhoenix.sln
├── GamepadPhoenix32.vcxproj
├── GamepadPhoenix64.vcxproj
├── GamepadPhoenixDLL.cpp
├── GamepadPhoenixDLL.rc
├── LICENSE
├── MainForm.cs
├── PresetsForm.cs
├── README.md
├── Resources.Designer.cs
├── Resources.resx
├── app.config
├── gfx
├── A.png
├── B.png
├── BG.png
├── Circle.png
├── DPAD-Black.png
├── DPAD.png
├── DPADDown.png
├── DPADLeft.png
├── DPADRight.png
├── DPADUp.png
├── Glow.png
├── GlowAssign.png
├── GlowHover.png
├── GlowPress.png
├── L1.png
├── L2.png
├── LEDOff.png
├── LEDOn.png
├── LICENSE
├── R1.png
├── R2.png
├── Select.png
├── Start.png
├── Stick.png
├── StickDown.png
├── StickLeft.png
├── StickPress.png
├── StickRight.png
├── StickUp.png
├── X.png
└── Y.png
└── minhook.inl
/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | Debug/
3 | Release/
4 | .vs/
5 | *.suo
6 | *.user
7 | *.aps
8 |
--------------------------------------------------------------------------------
/DeadzoneForm.cs:
--------------------------------------------------------------------------------
1 | /* Gamepad Phoenix
2 | * Copyright (c) 2021-2023 Bernhard Schelling
3 | *
4 | * Gamepad Phoenix is free software: you can redistribute it and/or modify it under the terms
5 | * of the GNU General Public License as published by the Free Software Found-
6 | * ation, either version 3 of the License, or (at your option) any later version.
7 | *
8 | * Gamepad Phoenix is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 | * PURPOSE. See the GNU General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU General Public License along with Gamepad Phoenix.
13 | * If not, see .
14 | */
15 |
16 | using System;
17 | using System.Drawing;
18 | using System.Windows.Forms;
19 |
20 | namespace GamepadPhoenix
21 | {
22 | public class DeadzoneForm : Form
23 | {
24 | public DeadzoneForm()
25 | {
26 | InitializeComponent();
27 | }
28 |
29 | internal Timer timer;
30 | internal DeadzoneControl deadzoneControl;
31 | private Label label1;
32 | private Label label2;
33 | private Label label3;
34 | private Label label4;
35 | private Label label5;
36 | private Label label6;
37 | internal TrackBar trkLeftDeadzone;
38 | internal TrackBar trkLeftLimit;
39 | internal TrackBar trkLeftAnti;
40 | internal TrackBar trkLeftSens;
41 | internal TrackBar trkLeftShiftH;
42 | internal TrackBar trkLeftShiftV;
43 | internal TrackBar trkRightDeadzone;
44 | internal TrackBar trkRightLimit;
45 | internal TrackBar trkRightAnti;
46 | internal TrackBar trkRightSens;
47 | internal TrackBar trkRightShiftH;
48 | internal TrackBar trkRightShiftV;
49 | private Label label7;
50 | private Label label8;
51 | private Label label9;
52 | private Label label10;
53 | private Label label11;
54 | private Label label12;
55 | internal NumericUpDown numLeftDeadzone;
56 | internal NumericUpDown numLeftLimit;
57 | internal NumericUpDown numLeftAnti;
58 | internal NumericUpDown numLeftSens;
59 | internal NumericUpDown numLeftShiftH;
60 | internal NumericUpDown numLeftShiftV;
61 | internal NumericUpDown numRightShiftV;
62 | internal NumericUpDown numRightShiftH;
63 | internal NumericUpDown numRightSens;
64 | internal NumericUpDown numRightAnti;
65 | internal NumericUpDown numRightLimit;
66 | internal NumericUpDown numRightDeadzone;
67 | internal Button btnOK;
68 | internal Button btnReset;
69 |
70 | ///
71 | /// Required designer variable.
72 | ///
73 | private System.ComponentModel.IContainer components = null;
74 |
75 | ///
76 | /// Clean up any resources being used.
77 | ///
78 | /// true if managed resources should be disposed; otherwise, false.
79 | protected override void Dispose(bool disposing)
80 | {
81 | if (disposing && (components != null))
82 | {
83 | components.Dispose();
84 | }
85 | base.Dispose(disposing);
86 | }
87 |
88 | #region Windows Form Designer generated code
89 |
90 | ///
91 | /// Required method for Designer support - do not modify
92 | /// the contents of this method with the code editor.
93 | ///
94 | private void InitializeComponent()
95 | {
96 | this.components = new System.ComponentModel.Container();
97 | this.timer = new System.Windows.Forms.Timer(this.components);
98 | this.label1 = new System.Windows.Forms.Label();
99 | this.label2 = new System.Windows.Forms.Label();
100 | this.label3 = new System.Windows.Forms.Label();
101 | this.label4 = new System.Windows.Forms.Label();
102 | this.label5 = new System.Windows.Forms.Label();
103 | this.label6 = new System.Windows.Forms.Label();
104 | this.trkLeftDeadzone = new System.Windows.Forms.TrackBar();
105 | this.trkLeftLimit = new System.Windows.Forms.TrackBar();
106 | this.trkLeftAnti = new System.Windows.Forms.TrackBar();
107 | this.trkLeftSens = new System.Windows.Forms.TrackBar();
108 | this.trkLeftShiftH = new System.Windows.Forms.TrackBar();
109 | this.trkLeftShiftV = new System.Windows.Forms.TrackBar();
110 | this.trkRightShiftV = new System.Windows.Forms.TrackBar();
111 | this.trkRightShiftH = new System.Windows.Forms.TrackBar();
112 | this.trkRightSens = new System.Windows.Forms.TrackBar();
113 | this.trkRightAnti = new System.Windows.Forms.TrackBar();
114 | this.trkRightLimit = new System.Windows.Forms.TrackBar();
115 | this.label7 = new System.Windows.Forms.Label();
116 | this.label8 = new System.Windows.Forms.Label();
117 | this.label9 = new System.Windows.Forms.Label();
118 | this.label10 = new System.Windows.Forms.Label();
119 | this.label11 = new System.Windows.Forms.Label();
120 | this.label12 = new System.Windows.Forms.Label();
121 | this.trkRightDeadzone = new System.Windows.Forms.TrackBar();
122 | this.numLeftDeadzone = new System.Windows.Forms.NumericUpDown();
123 | this.numLeftLimit = new System.Windows.Forms.NumericUpDown();
124 | this.numLeftAnti = new System.Windows.Forms.NumericUpDown();
125 | this.numLeftSens = new System.Windows.Forms.NumericUpDown();
126 | this.numLeftShiftH = new System.Windows.Forms.NumericUpDown();
127 | this.numLeftShiftV = new System.Windows.Forms.NumericUpDown();
128 | this.numRightShiftV = new System.Windows.Forms.NumericUpDown();
129 | this.numRightShiftH = new System.Windows.Forms.NumericUpDown();
130 | this.numRightSens = new System.Windows.Forms.NumericUpDown();
131 | this.numRightAnti = new System.Windows.Forms.NumericUpDown();
132 | this.numRightLimit = new System.Windows.Forms.NumericUpDown();
133 | this.numRightDeadzone = new System.Windows.Forms.NumericUpDown();
134 | this.btnOK = new System.Windows.Forms.Button();
135 | this.btnReset = new System.Windows.Forms.Button();
136 | this.deadzoneControl = new GamepadPhoenix.DeadzoneControl();
137 | ((System.ComponentModel.ISupportInitialize)(this.trkLeftDeadzone)).BeginInit();
138 | ((System.ComponentModel.ISupportInitialize)(this.trkLeftLimit)).BeginInit();
139 | ((System.ComponentModel.ISupportInitialize)(this.trkLeftAnti)).BeginInit();
140 | ((System.ComponentModel.ISupportInitialize)(this.trkLeftSens)).BeginInit();
141 | ((System.ComponentModel.ISupportInitialize)(this.trkLeftShiftH)).BeginInit();
142 | ((System.ComponentModel.ISupportInitialize)(this.trkLeftShiftV)).BeginInit();
143 | ((System.ComponentModel.ISupportInitialize)(this.trkRightShiftV)).BeginInit();
144 | ((System.ComponentModel.ISupportInitialize)(this.trkRightShiftH)).BeginInit();
145 | ((System.ComponentModel.ISupportInitialize)(this.trkRightSens)).BeginInit();
146 | ((System.ComponentModel.ISupportInitialize)(this.trkRightAnti)).BeginInit();
147 | ((System.ComponentModel.ISupportInitialize)(this.trkRightLimit)).BeginInit();
148 | ((System.ComponentModel.ISupportInitialize)(this.trkRightDeadzone)).BeginInit();
149 | ((System.ComponentModel.ISupportInitialize)(this.numLeftDeadzone)).BeginInit();
150 | ((System.ComponentModel.ISupportInitialize)(this.numLeftLimit)).BeginInit();
151 | ((System.ComponentModel.ISupportInitialize)(this.numLeftAnti)).BeginInit();
152 | ((System.ComponentModel.ISupportInitialize)(this.numLeftSens)).BeginInit();
153 | ((System.ComponentModel.ISupportInitialize)(this.numLeftShiftH)).BeginInit();
154 | ((System.ComponentModel.ISupportInitialize)(this.numLeftShiftV)).BeginInit();
155 | ((System.ComponentModel.ISupportInitialize)(this.numRightShiftV)).BeginInit();
156 | ((System.ComponentModel.ISupportInitialize)(this.numRightShiftH)).BeginInit();
157 | ((System.ComponentModel.ISupportInitialize)(this.numRightSens)).BeginInit();
158 | ((System.ComponentModel.ISupportInitialize)(this.numRightAnti)).BeginInit();
159 | ((System.ComponentModel.ISupportInitialize)(this.numRightLimit)).BeginInit();
160 | ((System.ComponentModel.ISupportInitialize)(this.numRightDeadzone)).BeginInit();
161 | this.SuspendLayout();
162 | //
163 | // timer
164 | //
165 | this.timer.Enabled = true;
166 | this.timer.Interval = 20;
167 | //
168 | // label1
169 | //
170 | this.label1.AutoSize = true;
171 | this.label1.Location = new System.Drawing.Point(12, 195);
172 | this.label1.Name = "label1";
173 | this.label1.Size = new System.Drawing.Size(56, 13);
174 | this.label1.TabIndex = 2;
175 | this.label1.Text = "Deadzone";
176 | //
177 | // label2
178 | //
179 | this.label2.AutoSize = true;
180 | this.label2.Location = new System.Drawing.Point(12, 221);
181 | this.label2.Name = "label2";
182 | this.label2.Size = new System.Drawing.Size(51, 13);
183 | this.label2.TabIndex = 5;
184 | this.label2.Text = "Max Limit";
185 | //
186 | // label3
187 | //
188 | this.label3.AutoSize = true;
189 | this.label3.Location = new System.Drawing.Point(12, 247);
190 | this.label3.Name = "label3";
191 | this.label3.Size = new System.Drawing.Size(77, 13);
192 | this.label3.TabIndex = 8;
193 | this.label3.Text = "Anti-Deadzone";
194 | //
195 | // label4
196 | //
197 | this.label4.AutoSize = true;
198 | this.label4.Location = new System.Drawing.Point(12, 273);
199 | this.label4.Name = "label4";
200 | this.label4.Size = new System.Drawing.Size(54, 13);
201 | this.label4.TabIndex = 11;
202 | this.label4.Text = "Sensitivity";
203 | //
204 | // label5
205 | //
206 | this.label5.AutoSize = true;
207 | this.label5.Location = new System.Drawing.Point(12, 299);
208 | this.label5.Name = "label5";
209 | this.label5.Size = new System.Drawing.Size(78, 13);
210 | this.label5.TabIndex = 14;
211 | this.label5.Text = "Shift Horizontal";
212 | //
213 | // label6
214 | //
215 | this.label6.AutoSize = true;
216 | this.label6.Location = new System.Drawing.Point(12, 325);
217 | this.label6.Name = "label6";
218 | this.label6.Size = new System.Drawing.Size(63, 13);
219 | this.label6.TabIndex = 17;
220 | this.label6.Text = "ShiftVertical";
221 | //
222 | // trkLeftDeadzone
223 | //
224 | this.trkLeftDeadzone.AutoSize = false;
225 | this.trkLeftDeadzone.Location = new System.Drawing.Point(99, 190);
226 | this.trkLeftDeadzone.Maximum = 100;
227 | this.trkLeftDeadzone.Name = "trkLeftDeadzone";
228 | this.trkLeftDeadzone.Size = new System.Drawing.Size(200, 26);
229 | this.trkLeftDeadzone.TabIndex = 3;
230 | this.trkLeftDeadzone.TickFrequency = 5;
231 | //
232 | // trkLeftLimit
233 | //
234 | this.trkLeftLimit.AutoSize = false;
235 | this.trkLeftLimit.Location = new System.Drawing.Point(99, 216);
236 | this.trkLeftLimit.Maximum = 100;
237 | this.trkLeftLimit.Name = "trkLeftLimit";
238 | this.trkLeftLimit.Size = new System.Drawing.Size(200, 26);
239 | this.trkLeftLimit.TabIndex = 6;
240 | this.trkLeftLimit.TickFrequency = 5;
241 | //
242 | // trkLeftAnti
243 | //
244 | this.trkLeftAnti.AutoSize = false;
245 | this.trkLeftAnti.Location = new System.Drawing.Point(99, 242);
246 | this.trkLeftAnti.Maximum = 100;
247 | this.trkLeftAnti.Name = "trkLeftAnti";
248 | this.trkLeftAnti.Size = new System.Drawing.Size(200, 26);
249 | this.trkLeftAnti.TabIndex = 9;
250 | this.trkLeftAnti.TickFrequency = 5;
251 | //
252 | // trkLeftSens
253 | //
254 | this.trkLeftSens.AutoSize = false;
255 | this.trkLeftSens.Location = new System.Drawing.Point(99, 268);
256 | this.trkLeftSens.Maximum = 100;
257 | this.trkLeftSens.Minimum = -100;
258 | this.trkLeftSens.Name = "trkLeftSens";
259 | this.trkLeftSens.Size = new System.Drawing.Size(200, 26);
260 | this.trkLeftSens.TabIndex = 12;
261 | this.trkLeftSens.TickFrequency = 5;
262 | //
263 | // trkLeftShiftH
264 | //
265 | this.trkLeftShiftH.AutoSize = false;
266 | this.trkLeftShiftH.Location = new System.Drawing.Point(99, 294);
267 | this.trkLeftShiftH.Maximum = 100;
268 | this.trkLeftShiftH.Minimum = -100;
269 | this.trkLeftShiftH.Name = "trkLeftShiftH";
270 | this.trkLeftShiftH.Size = new System.Drawing.Size(200, 26);
271 | this.trkLeftShiftH.TabIndex = 15;
272 | this.trkLeftShiftH.TickFrequency = 5;
273 | //
274 | // trkLeftShiftV
275 | //
276 | this.trkLeftShiftV.AutoSize = false;
277 | this.trkLeftShiftV.Location = new System.Drawing.Point(99, 320);
278 | this.trkLeftShiftV.Maximum = 100;
279 | this.trkLeftShiftV.Minimum = -100;
280 | this.trkLeftShiftV.Name = "trkLeftShiftV";
281 | this.trkLeftShiftV.Size = new System.Drawing.Size(200, 26);
282 | this.trkLeftShiftV.TabIndex = 18;
283 | this.trkLeftShiftV.TickFrequency = 5;
284 | //
285 | // trkRightShiftV
286 | //
287 | this.trkRightShiftV.AutoSize = false;
288 | this.trkRightShiftV.Location = new System.Drawing.Point(452, 320);
289 | this.trkRightShiftV.Maximum = 100;
290 | this.trkRightShiftV.Minimum = -100;
291 | this.trkRightShiftV.Name = "trkRightShiftV";
292 | this.trkRightShiftV.Size = new System.Drawing.Size(200, 26);
293 | this.trkRightShiftV.TabIndex = 36;
294 | this.trkRightShiftV.TickFrequency = 5;
295 | //
296 | // trkRightShiftH
297 | //
298 | this.trkRightShiftH.AutoSize = false;
299 | this.trkRightShiftH.Location = new System.Drawing.Point(452, 294);
300 | this.trkRightShiftH.Maximum = 100;
301 | this.trkRightShiftH.Minimum = -100;
302 | this.trkRightShiftH.Name = "trkRightShiftH";
303 | this.trkRightShiftH.Size = new System.Drawing.Size(200, 26);
304 | this.trkRightShiftH.TabIndex = 33;
305 | this.trkRightShiftH.TickFrequency = 5;
306 | //
307 | // trkRightSens
308 | //
309 | this.trkRightSens.AutoSize = false;
310 | this.trkRightSens.Location = new System.Drawing.Point(452, 268);
311 | this.trkRightSens.Maximum = 100;
312 | this.trkRightSens.Minimum = -100;
313 | this.trkRightSens.Name = "trkRightSens";
314 | this.trkRightSens.Size = new System.Drawing.Size(200, 26);
315 | this.trkRightSens.TabIndex = 30;
316 | this.trkRightSens.TickFrequency = 5;
317 | //
318 | // trkRightAnti
319 | //
320 | this.trkRightAnti.AutoSize = false;
321 | this.trkRightAnti.Location = new System.Drawing.Point(452, 242);
322 | this.trkRightAnti.Maximum = 100;
323 | this.trkRightAnti.Name = "trkRightAnti";
324 | this.trkRightAnti.Size = new System.Drawing.Size(200, 26);
325 | this.trkRightAnti.TabIndex = 27;
326 | this.trkRightAnti.TickFrequency = 5;
327 | //
328 | // trkRightLimit
329 | //
330 | this.trkRightLimit.AutoSize = false;
331 | this.trkRightLimit.Location = new System.Drawing.Point(452, 216);
332 | this.trkRightLimit.Maximum = 100;
333 | this.trkRightLimit.Name = "trkRightLimit";
334 | this.trkRightLimit.Size = new System.Drawing.Size(200, 26);
335 | this.trkRightLimit.TabIndex = 24;
336 | this.trkRightLimit.TickFrequency = 5;
337 | //
338 | // label7
339 | //
340 | this.label7.AutoSize = true;
341 | this.label7.Location = new System.Drawing.Point(365, 325);
342 | this.label7.Name = "label7";
343 | this.label7.Size = new System.Drawing.Size(63, 13);
344 | this.label7.TabIndex = 35;
345 | this.label7.Text = "ShiftVertical";
346 | //
347 | // label8
348 | //
349 | this.label8.AutoSize = true;
350 | this.label8.Location = new System.Drawing.Point(365, 299);
351 | this.label8.Name = "label8";
352 | this.label8.Size = new System.Drawing.Size(78, 13);
353 | this.label8.TabIndex = 32;
354 | this.label8.Text = "Shift Horizontal";
355 | //
356 | // label9
357 | //
358 | this.label9.AutoSize = true;
359 | this.label9.Location = new System.Drawing.Point(365, 273);
360 | this.label9.Name = "label9";
361 | this.label9.Size = new System.Drawing.Size(54, 13);
362 | this.label9.TabIndex = 29;
363 | this.label9.Text = "Sensitivity";
364 | //
365 | // label10
366 | //
367 | this.label10.AutoSize = true;
368 | this.label10.Location = new System.Drawing.Point(365, 247);
369 | this.label10.Name = "label10";
370 | this.label10.Size = new System.Drawing.Size(77, 13);
371 | this.label10.TabIndex = 26;
372 | this.label10.Text = "Anti-Deadzone";
373 | //
374 | // label11
375 | //
376 | this.label11.AutoSize = true;
377 | this.label11.Location = new System.Drawing.Point(365, 221);
378 | this.label11.Name = "label11";
379 | this.label11.Size = new System.Drawing.Size(51, 13);
380 | this.label11.TabIndex = 23;
381 | this.label11.Text = "Max Limit";
382 | //
383 | // label12
384 | //
385 | this.label12.AutoSize = true;
386 | this.label12.Location = new System.Drawing.Point(365, 195);
387 | this.label12.Name = "label12";
388 | this.label12.Size = new System.Drawing.Size(56, 13);
389 | this.label12.TabIndex = 20;
390 | this.label12.Text = "Deadzone";
391 | //
392 | // trkRightDeadzone
393 | //
394 | this.trkRightDeadzone.AutoSize = false;
395 | this.trkRightDeadzone.Location = new System.Drawing.Point(452, 190);
396 | this.trkRightDeadzone.Maximum = 100;
397 | this.trkRightDeadzone.Name = "trkRightDeadzone";
398 | this.trkRightDeadzone.Size = new System.Drawing.Size(200, 26);
399 | this.trkRightDeadzone.TabIndex = 21;
400 | this.trkRightDeadzone.TickFrequency = 5;
401 | //
402 | // numLeftDeadzone
403 | //
404 | this.numLeftDeadzone.Location = new System.Drawing.Point(300, 192);
405 | this.numLeftDeadzone.Name = "numLeftDeadzone";
406 | this.numLeftDeadzone.Size = new System.Drawing.Size(42, 20);
407 | this.numLeftDeadzone.TabIndex = 4;
408 | //
409 | // numLeftLimit
410 | //
411 | this.numLeftLimit.Location = new System.Drawing.Point(300, 218);
412 | this.numLeftLimit.Name = "numLeftLimit";
413 | this.numLeftLimit.Size = new System.Drawing.Size(42, 20);
414 | this.numLeftLimit.TabIndex = 7;
415 | //
416 | // numLeftAnti
417 | //
418 | this.numLeftAnti.Location = new System.Drawing.Point(300, 244);
419 | this.numLeftAnti.Name = "numLeftAnti";
420 | this.numLeftAnti.Size = new System.Drawing.Size(42, 20);
421 | this.numLeftAnti.TabIndex = 10;
422 | //
423 | // numLeftSens
424 | //
425 | this.numLeftSens.Location = new System.Drawing.Point(300, 270);
426 | this.numLeftSens.Minimum = new decimal(new int[] {
427 | 100,
428 | 0,
429 | 0,
430 | -2147483648});
431 | this.numLeftSens.Name = "numLeftSens";
432 | this.numLeftSens.Size = new System.Drawing.Size(42, 20);
433 | this.numLeftSens.TabIndex = 13;
434 | //
435 | // numLeftShiftH
436 | //
437 | this.numLeftShiftH.Location = new System.Drawing.Point(300, 296);
438 | this.numLeftShiftH.Minimum = new decimal(new int[] {
439 | 100,
440 | 0,
441 | 0,
442 | -2147483648});
443 | this.numLeftShiftH.Name = "numLeftShiftH";
444 | this.numLeftShiftH.Size = new System.Drawing.Size(42, 20);
445 | this.numLeftShiftH.TabIndex = 16;
446 | //
447 | // numLeftShiftV
448 | //
449 | this.numLeftShiftV.Location = new System.Drawing.Point(300, 322);
450 | this.numLeftShiftV.Minimum = new decimal(new int[] {
451 | 100,
452 | 0,
453 | 0,
454 | -2147483648});
455 | this.numLeftShiftV.Name = "numLeftShiftV";
456 | this.numLeftShiftV.Size = new System.Drawing.Size(42, 20);
457 | this.numLeftShiftV.TabIndex = 19;
458 | //
459 | // numRightShiftV
460 | //
461 | this.numRightShiftV.Location = new System.Drawing.Point(655, 322);
462 | this.numRightShiftV.Minimum = new decimal(new int[] {
463 | 100,
464 | 0,
465 | 0,
466 | -2147483648});
467 | this.numRightShiftV.Name = "numRightShiftV";
468 | this.numRightShiftV.Size = new System.Drawing.Size(42, 20);
469 | this.numRightShiftV.TabIndex = 37;
470 | //
471 | // numRightShiftH
472 | //
473 | this.numRightShiftH.Location = new System.Drawing.Point(655, 296);
474 | this.numRightShiftH.Minimum = new decimal(new int[] {
475 | 100,
476 | 0,
477 | 0,
478 | -2147483648});
479 | this.numRightShiftH.Name = "numRightShiftH";
480 | this.numRightShiftH.Size = new System.Drawing.Size(42, 20);
481 | this.numRightShiftH.TabIndex = 34;
482 | //
483 | // numRightSens
484 | //
485 | this.numRightSens.Location = new System.Drawing.Point(655, 270);
486 | this.numRightSens.Minimum = new decimal(new int[] {
487 | 100,
488 | 0,
489 | 0,
490 | -2147483648});
491 | this.numRightSens.Name = "numRightSens";
492 | this.numRightSens.Size = new System.Drawing.Size(42, 20);
493 | this.numRightSens.TabIndex = 31;
494 | //
495 | // numRightAnti
496 | //
497 | this.numRightAnti.Location = new System.Drawing.Point(655, 244);
498 | this.numRightAnti.Name = "numRightAnti";
499 | this.numRightAnti.Size = new System.Drawing.Size(42, 20);
500 | this.numRightAnti.TabIndex = 28;
501 | //
502 | // numRightLimit
503 | //
504 | this.numRightLimit.Location = new System.Drawing.Point(655, 218);
505 | this.numRightLimit.Name = "numRightLimit";
506 | this.numRightLimit.Size = new System.Drawing.Size(42, 20);
507 | this.numRightLimit.TabIndex = 25;
508 | //
509 | // numRightDeadzone
510 | //
511 | this.numRightDeadzone.Location = new System.Drawing.Point(655, 192);
512 | this.numRightDeadzone.Name = "numRightDeadzone";
513 | this.numRightDeadzone.Size = new System.Drawing.Size(42, 20);
514 | this.numRightDeadzone.TabIndex = 22;
515 | //
516 | // btnOK
517 | //
518 | this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
519 | this.btnOK.Location = new System.Drawing.Point(564, 552);
520 | this.btnOK.Name = "btnOK";
521 | this.btnOK.Size = new System.Drawing.Size(132, 23);
522 | this.btnOK.TabIndex = 39;
523 | this.btnOK.Text = "OK";
524 | this.btnOK.UseVisualStyleBackColor = true;
525 | //
526 | // btnReset
527 | //
528 | this.btnReset.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
529 | this.btnReset.Location = new System.Drawing.Point(6, 552);
530 | this.btnReset.Name = "btnReset";
531 | this.btnReset.Size = new System.Drawing.Size(132, 23);
532 | this.btnReset.TabIndex = 38;
533 | this.btnReset.Text = "Reset All Settings";
534 | this.btnReset.UseVisualStyleBackColor = true;
535 | //
536 | // deadzoneControl
537 | //
538 | this.deadzoneControl.Dock = System.Windows.Forms.DockStyle.Fill;
539 | this.deadzoneControl.Location = new System.Drawing.Point(0, 0);
540 | this.deadzoneControl.Name = "deadzoneControl";
541 | this.deadzoneControl.Size = new System.Drawing.Size(702, 581);
542 | this.deadzoneControl.TabIndex = 1;
543 | this.deadzoneControl.Text = "deazoneControl1";
544 | //
545 | // DeadzoneForm
546 | //
547 | this.AcceptButton = this.btnOK;
548 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
549 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
550 | this.ClientSize = new System.Drawing.Size(702, 581);
551 | this.Controls.Add(this.btnReset);
552 | this.Controls.Add(this.btnOK);
553 | this.Controls.Add(this.numRightShiftV);
554 | this.Controls.Add(this.numRightShiftH);
555 | this.Controls.Add(this.numRightSens);
556 | this.Controls.Add(this.numRightAnti);
557 | this.Controls.Add(this.numRightLimit);
558 | this.Controls.Add(this.numRightDeadzone);
559 | this.Controls.Add(this.numLeftShiftV);
560 | this.Controls.Add(this.numLeftShiftH);
561 | this.Controls.Add(this.numLeftSens);
562 | this.Controls.Add(this.numLeftAnti);
563 | this.Controls.Add(this.numLeftLimit);
564 | this.Controls.Add(this.numLeftDeadzone);
565 | this.Controls.Add(this.trkRightShiftV);
566 | this.Controls.Add(this.trkRightShiftH);
567 | this.Controls.Add(this.trkRightSens);
568 | this.Controls.Add(this.trkRightAnti);
569 | this.Controls.Add(this.trkRightLimit);
570 | this.Controls.Add(this.label7);
571 | this.Controls.Add(this.label8);
572 | this.Controls.Add(this.label9);
573 | this.Controls.Add(this.label10);
574 | this.Controls.Add(this.label11);
575 | this.Controls.Add(this.label12);
576 | this.Controls.Add(this.trkRightDeadzone);
577 | this.Controls.Add(this.trkLeftShiftV);
578 | this.Controls.Add(this.trkLeftShiftH);
579 | this.Controls.Add(this.trkLeftSens);
580 | this.Controls.Add(this.trkLeftAnti);
581 | this.Controls.Add(this.trkLeftLimit);
582 | this.Controls.Add(this.trkLeftDeadzone);
583 | this.Controls.Add(this.label6);
584 | this.Controls.Add(this.label5);
585 | this.Controls.Add(this.label4);
586 | this.Controls.Add(this.label3);
587 | this.Controls.Add(this.label2);
588 | this.Controls.Add(this.label1);
589 | this.Controls.Add(this.deadzoneControl);
590 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
591 | this.MaximizeBox = false;
592 | this.MinimizeBox = false;
593 | this.Name = "DeadzoneForm";
594 | this.ShowIcon = false;
595 | this.ShowInTaskbar = false;
596 | this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
597 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
598 | this.Text = "Analog Stick Deadzone Settings";
599 | ((System.ComponentModel.ISupportInitialize)(this.trkLeftDeadzone)).EndInit();
600 | ((System.ComponentModel.ISupportInitialize)(this.trkLeftLimit)).EndInit();
601 | ((System.ComponentModel.ISupportInitialize)(this.trkLeftAnti)).EndInit();
602 | ((System.ComponentModel.ISupportInitialize)(this.trkLeftSens)).EndInit();
603 | ((System.ComponentModel.ISupportInitialize)(this.trkLeftShiftH)).EndInit();
604 | ((System.ComponentModel.ISupportInitialize)(this.trkLeftShiftV)).EndInit();
605 | ((System.ComponentModel.ISupportInitialize)(this.trkRightShiftV)).EndInit();
606 | ((System.ComponentModel.ISupportInitialize)(this.trkRightShiftH)).EndInit();
607 | ((System.ComponentModel.ISupportInitialize)(this.trkRightSens)).EndInit();
608 | ((System.ComponentModel.ISupportInitialize)(this.trkRightAnti)).EndInit();
609 | ((System.ComponentModel.ISupportInitialize)(this.trkRightLimit)).EndInit();
610 | ((System.ComponentModel.ISupportInitialize)(this.trkRightDeadzone)).EndInit();
611 | ((System.ComponentModel.ISupportInitialize)(this.numLeftDeadzone)).EndInit();
612 | ((System.ComponentModel.ISupportInitialize)(this.numLeftLimit)).EndInit();
613 | ((System.ComponentModel.ISupportInitialize)(this.numLeftAnti)).EndInit();
614 | ((System.ComponentModel.ISupportInitialize)(this.numLeftSens)).EndInit();
615 | ((System.ComponentModel.ISupportInitialize)(this.numLeftShiftH)).EndInit();
616 | ((System.ComponentModel.ISupportInitialize)(this.numLeftShiftV)).EndInit();
617 | ((System.ComponentModel.ISupportInitialize)(this.numRightShiftV)).EndInit();
618 | ((System.ComponentModel.ISupportInitialize)(this.numRightShiftH)).EndInit();
619 | ((System.ComponentModel.ISupportInitialize)(this.numRightSens)).EndInit();
620 | ((System.ComponentModel.ISupportInitialize)(this.numRightAnti)).EndInit();
621 | ((System.ComponentModel.ISupportInitialize)(this.numRightLimit)).EndInit();
622 | ((System.ComponentModel.ISupportInitialize)(this.numRightDeadzone)).EndInit();
623 | this.ResumeLayout(false);
624 | this.PerformLayout();
625 |
626 | }
627 | #endregion
628 | }
629 |
630 | internal class DeadzoneControl : PadControl
631 | {
632 | protected override void OnPaint(PaintEventArgs e)
633 | {
634 | if (gb == null) { base.OnPaint(e); return; }
635 | GUI.RenderDeadzones(gb.Graphics);
636 | gb.Render(e.Graphics);
637 | }
638 | }
639 | }
640 |
--------------------------------------------------------------------------------
/GPViGEm.inl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/GPViGEm.inl
--------------------------------------------------------------------------------
/GPWii.inl:
--------------------------------------------------------------------------------
1 | /* Gamepad Phoenix
2 | * Copyright (c) 2021-2023 Bernhard Schelling
3 | *
4 | * Gamepad Phoenix is free software: you can redistribute it and/or modify it under the terms
5 | * of the GNU General Public License as published by the Free Software Found-
6 | * ation, either version 3 of the License, or (at your option) any later version.
7 | *
8 | * Gamepad Phoenix is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 | * PURPOSE. See the GNU General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU General Public License along with Gamepad Phoenix.
13 | * If not, see .
14 | */
15 |
16 | int WINAPI UIWii(const wchar_t* hidPath, BOOL on, int LEDs = 0)
17 | {
18 | #pragma GPLINKER_DLL_EXPORT
19 | typedef BOOL (WINAPI *HidD_SetOutputReportFN)(HANDLE HidDeviceObject, const void* lpReportBuffer, unsigned int ReportBufferLength);
20 | static HidD_SetOutputReportFN pHidD_SetOutputReport;
21 | if (!pHidD_SetOutputReport)
22 | {
23 | HMODULE hHidDLL = LoadLibraryA("hid.dll");
24 | pHidD_SetOutputReport = (HidD_SetOutputReportFN)(hHidDLL == INVALID_HANDLE_VALUE ? NULL : fpGetProcAddress(hHidDLL, "HidD_SetOutputReport"));
25 | }
26 |
27 | struct Wii
28 | {
29 | enum
30 | {
31 | REPORT_LENGTH = 22,
32 | MAX_READ_LENGTH = 32,
33 |
34 | InputReport_Status = 0x20, /// Status report
35 | InputReport_ReadData = 0x21, /// Read data from memory location
36 | InputReport_OutputReportAck = 0x22, /// Register write complete
37 | InputReport_Buttons = 0x30, /// Button data only
38 | InputReport_ButtonsAccel = 0x31, /// Button and accelerometer data
39 | InputReport_IRAccel = 0x33, /// IR sensor and accelerometer data
40 | InputReport_ButtonsExtension = 0x34, /// Button and extension controller data
41 | InputReport_ExtensionAccel = 0x35, /// Extension and accelerometer data
42 | InputReport_IRExtensionAccel = 0x37, /// IR sensor, extension controller and accelerometer data
43 |
44 | OutputReport_LEDs = 0x11,
45 | OutputReport_Type = 0x12,
46 | OutputReport_IR = 0x13,
47 | OutputReport_Status = 0x15,
48 | OutputReport_WriteMemory = 0x16,
49 | OutputReport_ReadMemory = 0x17,
50 | OutputReport_IR2 = 0x1a,
51 |
52 | LEDState_Extension = 0x02,
53 | LEDStateShift_LEDs = 4, // LED 1 ~ 4 is 0x10, 0x20, 0x40, 0x80
54 |
55 | WiiButtons1_Left = 0x01,
56 | WiiButtons1_Right = 0x02,
57 | WiiButtons1_Down = 0x04,
58 | WiiButtons1_Up = 0x08,
59 | WiiButtons1_Plus = 0x10,
60 | WiiButtons2_Two = 0x01,
61 | WiiButtons2_One = 0x02,
62 | WiiButtons2_B = 0x04,
63 | WiiButtons2_A = 0x08,
64 | WiiButtons2_Minus = 0x10,
65 | WiiButtons2_Home = 0x80,
66 |
67 | ExtButtons_Nunchuk_C = 0x02,
68 | ExtButtons_Nunchuk_Z = 0x01,
69 | ExtButtons1_Classic_R = 0x02,
70 | ExtButtons1_Classic_Plus = 0x04,
71 | ExtButtons1_Classic_Home = 0x08,
72 | ExtButtons1_Classic_Minus = 0x10,
73 | ExtButtons1_Classic_L = 0x20,
74 | ExtButtons1_Classic_Down = 0x40,
75 | ExtButtons1_Classic_Right = 0x80,
76 | ExtButtons2_Classic_Up = 0x01,
77 | ExtButtons2_Classic_Left = 0x02,
78 | ExtButtons2_Classic_ZR = 0x04,
79 | ExtButtons2_Classic_X = 0x08,
80 | ExtButtons2_Classic_A = 0x10,
81 | ExtButtons2_Classic_Y = 0x20,
82 | ExtButtons2_Classic_B = 0x40,
83 | ExtButtons2_Classic_ZL = 0x80,
84 | ExtButtons3_Pro_RStick = 0x01,
85 | ExtButtons3_Pro_LStick = 0x02,
86 | ExtButtons3_Pro_charging = 0x04,
87 | ExtButtons3_Pro_usbConnected = 0x08,
88 |
89 | REGISTER_IR = 0x04b00030,
90 | REGISTER_IR_SENSITIVITY_1 = 0x04b00000,
91 | REGISTER_IR_SENSITIVITY_2 = 0x04b0001a,
92 | REGISTER_IR_MODE = 0x04b00033,
93 |
94 | REGISTER_EXTENSION_INIT_1 = 0x04a400f0,
95 | REGISTER_EXTENSION_INIT_2 = 0x04a400fb,
96 | REGISTER_EXTENSION_TYPE = 0x04a400fa,
97 | REGISTER_EXTENSION_CALIBRATION = 0x04a40020,
98 |
99 | ExtensionType_None = 0x00000000, // Wiimote, no extension
100 | ExtensionType_BalanceBoard = 0x00A40402, // Balance Board
101 | ExtensionType_ClassicController = 0x00A40101, // Wiimote + Classic Controller
102 | ExtensionType_ClassicControllerPro = 0x01A40101, // Wiimote + Classic Controller Pro
103 | ExtensionType_Nunchuk = 0x00A40000, // Wiimote + Nunchuk
104 | ExtensionType_NunchukB = 0xFFA40000, // Wiimote + Nunchuk (type 2)
105 | ExtensionType_ProController = 0x00A40120, // Wii U Pro Controller
106 | ExtensionType_MotionPlus = 0x00A40405, // Wiimote + Motion Plus
107 | ExtensionType_MotionPlusNunchuk = 0x00A40505, // Wiimote + Motion Plus + Nunchuk passthrough
108 | ExtensionType_MotionPlusCC = 0x00A40705, // Wiimote + Motion Plus + Classic Controller passthrough
109 | ExtensionType_Guitar = 0x00A40103,
110 | ExtensionType_Drums = 0x01A40103,
111 | ExtensionType_TaikoDrum = 0x00A40111,
112 | ExtensionType_TurnTable = 0x03A40103,
113 | ExtensionType_DrawTablet = 0xFFA40013,
114 | ExtensionType_FalseState = 0x01000000, // Seen when reconnecting to a Pro Controller
115 | ExtensionType_PartiallyInserted = 0xFFFFFFFF,
116 | };
117 |
118 | bool AbortRead;
119 | unsigned int DevNum, HidPathHash;
120 | HANDLE h, hThread;
121 | unsigned char BatteryRaw, LEDState, LEDRequest;
122 | unsigned int ExtensionType;
123 |
124 | struct { unsigned char WiiButtons1, WiiButtons2, ExtXL, ExtYL, ExtXR, ExtYR, ExtTL, ExtTR, ExtButtons1, ExtButtons2, ExtButtons3; } State, StatePrev;
125 |
126 | struct StickCal
127 | {
128 | unsigned char Max, Min, Mid;
129 | unsigned short GetUp(unsigned char v) { if (v > Max) Max = v; return (v > Mid ? (v - Mid) * 0xFFFF / (Max - Mid) : 0); }
130 | unsigned short GetDn(unsigned char v) { if (v < Min) Min = v; return (v < Mid ? (Mid - v) * 0xFFFF / (Mid - Min) : 0); }
131 | };
132 | struct { StickCal XL, YL, XR, YR, TL, TR; } ExtCal;
133 |
134 | void RequestLEDs(int LEDs) { LEDRequest = (unsigned char)LEDs; SetLEDs(0); }
135 | void SetLEDs(int LEDs) { LEDState = (unsigned char)((LEDState & ~(0xF<>LEDStateShift_LEDs); }
137 |
138 | unsigned char GetRumbleBit() { return 0x00; }
139 |
140 | void Run()
141 | {
142 | if (!LEDState && !LEDRequest)
143 | {
144 | WriteReport(OutputReport_Status);
145 | ReadUntil(InputReport_Status);
146 | //WriteReport(OutputReport_IR);WriteReport(OutputReport_IR2);
147 | if (!GetLEDs()) LEDRequest = (unsigned char)(1 << (DevNum % 4));
148 | }
149 | if (LEDRequest)
150 | {
151 | if (!WriteReport(OutputReport_LEDs, (unsigned char)(LEDRequest<> 24),
173 | (unsigned char)((address & 0x00ff0000) >> 16),
174 | (unsigned char)((address & 0x0000ff00) >> 8),
175 | (unsigned char)(address & 0x000000ff),
176 | (unsigned char)((size & 0xff00) >> 8),
177 | (unsigned char)(size & 0xff));
178 | ReadUntil(InputReport_ReadData, (address & 0xffff), size, readBuf);
179 | }
180 |
181 | void WriteData(int address, unsigned char write0)
182 | {
183 | GPASSERT(6 + 1 <= REPORT_LENGTH);
184 | WriteReport(OutputReport_WriteMemory,
185 | (unsigned char)((address & 0xff000000) >> 24),
186 | (unsigned char)((address & 0x00ff0000) >> 16),
187 | (unsigned char)((address & 0x0000ff00) >> 8),
188 | (unsigned char)(address & 0x000000ff),
189 | 1, write0);
190 | ReadUntil(InputReport_OutputReportAck);
191 | }
192 |
193 | void ParseButtons(unsigned char* buf)
194 | {
195 | State.WiiButtons1 = buf[1];
196 | State.WiiButtons2 = buf[2];
197 | }
198 |
199 | void ParseExtension(const unsigned char* data)
200 | {
201 | switch (ExtensionType)
202 | {
203 | case ExtensionType_ClassicController:
204 | case ExtensionType_ClassicControllerPro:
205 | State.ExtXL = (unsigned char)(data[0] & 0x3f);
206 | State.ExtYL = (unsigned char)(data[1] & 0x3f);
207 | State.ExtXR = (unsigned char)((data[2] >> 7) | (data[1] & 0xc0) >> 5 | (data[0] & 0xc0) >> 3);
208 | State.ExtYR = (unsigned char)(data[2] & 0x1f);
209 | State.ExtTL = (unsigned char)(((data[2] & 0x60) >> 2) | (data[3] >> 5));
210 | State.ExtTR = (unsigned char)(data[3] & 0x1f);
211 | State.ExtButtons1 = data[4];
212 | State.ExtButtons2 = data[5];
213 | State.ExtButtons3 = 0xFF;
214 | break;
215 | case ExtensionType_Nunchuk:
216 | case ExtensionType_NunchukB:
217 | State.ExtXL = data[0];
218 | State.ExtYL = data[1];
219 | State.ExtButtons1 = (data[5] & ExtButtons_Nunchuk_C ? 0xFF : ~ExtButtons1_Classic_L);
220 | State.ExtButtons2 = (data[5] & ExtButtons_Nunchuk_Z ? 0xFF : ~ExtButtons2_Classic_ZL);
221 | State.ExtButtons3 = 0xFF;
222 | break;
223 | case ExtensionType_ProController:
224 | State.ExtButtons1 = data[8];
225 | State.ExtButtons2 = data[9];
226 | State.ExtButtons3 = data[10];
227 | { int v = ((data[1] << 8) | data[0]); State.ExtXL = ((v < 1023 ? 1023 : (v > 3071 ? 3071 : v)) - 1023) * 0xFF / 2048; }
228 | { int v = ((data[5] << 8) | data[4]); State.ExtYL = ((v < 1023 ? 1023 : (v > 3071 ? 3071 : v)) - 1023) * 0xFF / 2048; }
229 | { int v = ((data[3] << 8) | data[2]); State.ExtXR = ((v < 1023 ? 1023 : (v > 3071 ? 3071 : v)) - 1023) * 0xFF / 2048; }
230 | { int v = ((data[7] << 8) | data[6]); State.ExtYR = ((v < 1023 ? 1023 : (v > 3071 ? 3071 : v)) - 1023) * 0xFF / 2048; }
231 | break;
232 | }
233 | }
234 |
235 | void ReadUntil(unsigned char waitForType, int readAddress = 0, int readSize = 0, unsigned char* readBuf = NULL)
236 | {
237 | while (!AbortRead && h)
238 | {
239 | unsigned char buf[REPORT_LENGTH];
240 | if (!ReadFile(h, buf, REPORT_LENGTH, NULL, NULL))
241 | {
242 | CloseHandle(h);
243 | h = NULL;
244 | WriteLog("Wii - Read failed\n");
245 | return;
246 | }
247 | //WriteLog("ReadReport - %s\n", GetReportName(buf[0]));
248 | switch (buf[0])
249 | {
250 | case InputReport_Status: //= 0x20, /// Status report
251 | {
252 | ParseButtons(buf);
253 | BatteryRaw = buf[6];
254 | //mWiimoteState.Battery = (((100.0f * 48.0f * (float)((int)buff[6] / 48.0f))) / 192.0f);
255 |
256 | bool hadExtension = !!(LEDState & LEDState_Extension), haveExtension = !!(buf[3] & LEDState_Extension);
257 | if (hadExtension != haveExtension)
258 | {
259 | memset(&ExtCal, 0, sizeof(ExtCal));
260 | ExtensionType = ExtensionType_None;
261 | if (haveExtension)
262 | {
263 | unsigned char extBuf[16];
264 | WriteData(REGISTER_EXTENSION_INIT_1, 0x55);
265 | WriteData(REGISTER_EXTENSION_INIT_2, 0x00);
266 | ReadData(REGISTER_EXTENSION_TYPE, 6, extBuf);
267 | switch (((unsigned int)extBuf[0] << 24) | ((unsigned int)extBuf[2] << 16) | ((unsigned int)extBuf[4]) << 8 | extBuf[5])
268 | {
269 | case ExtensionType_ClassicController:
270 | case ExtensionType_ClassicControllerPro:
271 | ExtensionType = ExtensionType_ClassicController;
272 | ReadData(REGISTER_EXTENSION_CALIBRATION, 16, extBuf);
273 | #if 0
274 | ExtCal.XL.Max = ((extBuf[ 0] >> 2) > 0 ? (extBuf[ 0] >> 2) : 63-5);
275 | ExtCal.XL.Min = ((extBuf[ 1] >> 2) > 0 ? (extBuf[ 1] >> 2) : 0+5);
276 | ExtCal.XL.Mid = ((extBuf[ 2] >> 2) > 0 ? (extBuf[ 2] >> 2) : 31);
277 | ExtCal.YL.Max = ((extBuf[ 3] >> 2) > 0 ? (extBuf[ 3] >> 2) : 63-5);
278 | ExtCal.YL.Min = ((extBuf[ 4] >> 2) > 0 ? (extBuf[ 4] >> 2) : 0+5);
279 | ExtCal.YL.Mid = ((extBuf[ 5] >> 2) > 0 ? (extBuf[ 5] >> 2) : 31);
280 | ExtCal.XR.Max = ((extBuf[ 6] >> 3) > 0 ? (extBuf[ 6] >> 3) : 31-3);
281 | ExtCal.XR.Min = ((extBuf[ 7] >> 3) > 0 ? (extBuf[ 7] >> 3) : 0+3);
282 | ExtCal.XR.Mid = ((extBuf[ 8] >> 3) > 0 ? (extBuf[ 8] >> 3) : 15);
283 | ExtCal.YR.Max = ((extBuf[ 9] >> 3) > 0 ? (extBuf[ 9] >> 3) : 31-3);
284 | ExtCal.YR.Min = ((extBuf[10] >> 3) > 0 ? (extBuf[10] >> 3) : 0+3);
285 | ExtCal.YR.Mid = ((extBuf[11] >> 3) > 0 ? (extBuf[11] >> 3) : 15);
286 | #else
287 | ExtCal.XL.Max = ((extBuf[ 0] >> 2) > 0 ? (extBuf[ 0] >> 2) : 63);
288 | ExtCal.XL.Min = ((extBuf[ 1] >> 2) > 0 ? (extBuf[ 1] >> 2) : 0);
289 | ExtCal.XL.Mid = ((extBuf[ 2] >> 2) > 0 ? (extBuf[ 2] >> 2) : 31);
290 | ExtCal.YL.Max = ((extBuf[ 3] >> 2) > 0 ? (extBuf[ 3] >> 2) : 63);
291 | ExtCal.YL.Min = ((extBuf[ 4] >> 2) > 0 ? (extBuf[ 4] >> 2) : 0);
292 | ExtCal.YL.Mid = ((extBuf[ 5] >> 2) > 0 ? (extBuf[ 5] >> 2) : 31);
293 | ExtCal.XR.Max = ((extBuf[ 6] >> 3) > 0 ? (extBuf[ 6] >> 3) : 31);
294 | ExtCal.XR.Min = ((extBuf[ 7] >> 3) > 0 ? (extBuf[ 7] >> 3) : 0);
295 | ExtCal.XR.Mid = ((extBuf[ 8] >> 3) > 0 ? (extBuf[ 8] >> 3) : 15);
296 | ExtCal.YR.Max = ((extBuf[ 9] >> 3) > 0 ? (extBuf[ 9] >> 3) : 31);
297 | ExtCal.YR.Min = ((extBuf[10] >> 3) > 0 ? (extBuf[10] >> 3) : 0);
298 | ExtCal.YR.Mid = ((extBuf[11] >> 3) > 0 ? (extBuf[11] >> 3) : 15);
299 | #endif
300 | ExtCal.TL.Mid = 0; //(extBuf[12] >> 3) is apparently incorrect
301 | ExtCal.TL.Max = 31; //(extBuf[14] >> 3) is apparently incorrect
302 | ExtCal.TL.Mid = 0; //(extBuf[13] >> 3) is apparently incorrect
303 | ExtCal.TL.Max = 31; //(extBuf[15] >> 3) is apparently incorrect
304 | break;
305 | case ExtensionType_Nunchuk:
306 | case ExtensionType_NunchukB:
307 | ExtensionType = ExtensionType_Nunchuk;
308 | ReadData(REGISTER_EXTENSION_CALIBRATION, 16, extBuf);
309 | ExtCal.XL.Max = extBuf[8];
310 | ExtCal.XL.Min = extBuf[9];
311 | ExtCal.XL.Mid = extBuf[10];
312 | ExtCal.YL.Max = extBuf[11];
313 | ExtCal.YL.Min = extBuf[12];
314 | ExtCal.YL.Mid = extBuf[13];
315 | break;
316 | case ExtensionType_ProController:
317 | ExtensionType = ExtensionType_ProController;
318 | ExtCal.XL.Max = ExtCal.YL.Max = ExtCal.XR.Max = ExtCal.YR.Max = 255;
319 | ExtCal.XL.Min = ExtCal.YL.Min = ExtCal.XR.Min = ExtCal.YR.Min = 0;
320 | ExtCal.XL.Mid = ExtCal.YL.Mid = ExtCal.XR.Mid = ExtCal.YR.Mid = 127;
321 | break;
322 | }
323 | }
324 | }
325 | State.ExtXL = ExtCal.XL.Mid;
326 | State.ExtYL = ExtCal.YL.Mid;
327 | State.ExtXR = ExtCal.XR.Mid;
328 | State.ExtYR = ExtCal.YR.Mid;
329 | State.ExtTL = ExtCal.TL.Mid;
330 | State.ExtTR = ExtCal.TR.Mid;
331 | State.ExtButtons1 = State.ExtButtons2 = State.ExtButtons3 = 0xFF;
332 | StatePrev = State;
333 | WriteReport(OutputReport_Type, 0x00, (ExtensionType == ExtensionType_None ? InputReport_Buttons : InputReport_ButtonsExtension)); //0x04 = continuous data, 0x00 only changing data
334 | LEDState = buf[3];
335 | if (waitForType == InputReport_Status) return;
336 | break;
337 | }
338 | case InputReport_ReadData: //= 0x21, /// Read data from memory location
339 | {
340 | ParseButtons(buf);
341 | GPASSERT(!(buf[3] & 0x08)); //Error reading data from Wiimote: Bytes do not exist.
342 | #if 1
343 | if (buf[3] & 0x07) { WriteLog("Error reading data from Wiimote: Attempt to read from write-only registers.\n"); }
344 | #else
345 | GPASSERT(!(buf[3] & 0x07)); //Error reading data from Wiimote: Attempt to read from write-only registers.
346 | #endif
347 | int size = (buf[3] >> 4) + 1, offset = (buf[4] << 8 | buf[5]);
348 | if (readBuf)
349 | {
350 | if (offset - readAddress + size <= readSize)
351 | memcpy(readBuf + offset - readAddress, buf + 6, size);
352 | if (waitForType == InputReport_ReadData && readAddress + readSize == offset + size) return;
353 | }
354 | break;
355 | }
356 | case InputReport_OutputReportAck: //= 0x22, /// Register write complete
357 | if (waitForType == InputReport_OutputReportAck) return;
358 | break;
359 | case InputReport_Buttons: //= 0x30, /// Button data only
360 | ParseButtons(buf);
361 | break;
362 | case InputReport_ButtonsAccel: //= 0x31, /// Button and accelerometer data
363 | ParseButtons(buf);
364 | break;
365 | case InputReport_IRAccel: //= 0x33, /// IR sensor and accelerometer data
366 | ParseButtons(buf);
367 | break;
368 | case InputReport_ButtonsExtension: //= 0x34, /// Button and extension controller data
369 | ParseButtons(buf);
370 | ParseExtension(buf+3);
371 | break;
372 | case InputReport_ExtensionAccel: //= 0x35, /// Extension and accelerometer data
373 | ParseButtons(buf);
374 | ParseExtension(buf+6);
375 | break;
376 | case InputReport_IRExtensionAccel: //= 0x37, /// IR sensor, extension controller and accelerometer data
377 | ParseButtons(buf);
378 | ParseExtension(buf+16);
379 | break;
380 | }
381 | WriteGPData();
382 | }
383 | }
384 |
385 | void WriteGPData()
386 | {
387 | for (GPGamepad& gp : pGPData->Gamepads)
388 | {
389 | for (unsigned int i = 0; i != _GPIDX_MAX; i++)
390 | {
391 | unsigned char o;
392 | switch (GPIDGetInterface(gp.IDs[i]))
393 | {
394 | case GPIDINTERFACE_WII:
395 | if (GPIDGetDevNum(gp.IDs[i]) != DevNum) continue;
396 | o = GPIDGetObjNum(gp.IDs[i]);
397 | switch (o)
398 | {
399 | case 0: gp.Vals[i] = ((State.WiiButtons1 & WiiButtons1_Up ) ? 0xFFFF : 0); continue;
400 | case 1: gp.Vals[i] = ((State.WiiButtons1 & WiiButtons1_Down ) ? 0xFFFF : 0); continue;
401 | case 2: gp.Vals[i] = ((State.WiiButtons1 & WiiButtons1_Left ) ? 0xFFFF : 0); continue;
402 | case 3: gp.Vals[i] = ((State.WiiButtons1 & WiiButtons1_Right) ? 0xFFFF : 0); continue;
403 | case 4: gp.Vals[i] = ((State.WiiButtons2 & WiiButtons2_A ) ? 0xFFFF : 0); continue;
404 | case 5: gp.Vals[i] = ((State.WiiButtons2 & WiiButtons2_B ) ? 0xFFFF : 0); continue;
405 | case 6: gp.Vals[i] = ((State.WiiButtons2 & WiiButtons2_One ) ? 0xFFFF : 0); continue;
406 | case 7: gp.Vals[i] = ((State.WiiButtons2 & WiiButtons2_Two ) ? 0xFFFF : 0); continue;
407 | case 8: gp.Vals[i] = ((State.WiiButtons1 & WiiButtons1_Plus ) ? 0xFFFF : 0); continue;
408 | case 9: gp.Vals[i] = ((State.WiiButtons2 & WiiButtons2_Minus) ? 0xFFFF : 0); continue;
409 | case 10: gp.Vals[i] = ((State.WiiButtons2 & WiiButtons2_Home ) ? 0xFFFF : 0); continue;
410 | case 11: gp.Vals[i] = ExtCal.YL.GetUp(State.ExtYL); continue;
411 | case 12: gp.Vals[i] = ExtCal.YL.GetDn(State.ExtYL); continue;
412 | case 13: gp.Vals[i] = ExtCal.XL.GetDn(State.ExtXL); continue;
413 | case 14: gp.Vals[i] = ExtCal.XL.GetUp(State.ExtXL); continue;
414 | case 15: gp.Vals[i] = ExtCal.YR.GetUp(State.ExtYR); continue;
415 | case 16: gp.Vals[i] = ExtCal.YR.GetDn(State.ExtYR); continue;
416 | case 17: gp.Vals[i] = ExtCal.XR.GetDn(State.ExtXR); continue;
417 | case 18: gp.Vals[i] = ExtCal.XR.GetUp(State.ExtXR); continue;
418 | case 19: gp.Vals[i] = ((State.ExtButtons2 & ExtButtons2_Classic_Up ) ? 0 : 0xFFFF); continue;
419 | case 20: gp.Vals[i] = ((State.ExtButtons1 & ExtButtons1_Classic_Down ) ? 0 : 0xFFFF); continue;
420 | case 21: gp.Vals[i] = ((State.ExtButtons2 & ExtButtons2_Classic_Left ) ? 0 : 0xFFFF); continue;
421 | case 22: gp.Vals[i] = ((State.ExtButtons1 & ExtButtons1_Classic_Right) ? 0 : 0xFFFF); continue;
422 | case 23: gp.Vals[i] = ((State.ExtButtons1 & ExtButtons1_Classic_Plus ) ? 0 : 0xFFFF); continue;
423 | case 24: gp.Vals[i] = ((State.ExtButtons1 & ExtButtons1_Classic_Minus) ? 0 : 0xFFFF); continue;
424 | case 25: gp.Vals[i] = ((State.ExtButtons1 & ExtButtons1_Classic_L ) ? 0 : 0xFFFF); continue;
425 | case 26: gp.Vals[i] = ((State.ExtButtons1 & ExtButtons1_Classic_R ) ? 0 : 0xFFFF); continue;
426 | case 27: gp.Vals[i] = ((State.ExtButtons2 & ExtButtons2_Classic_ZL ) ? 0 : 0xFFFF); continue;
427 | case 28: gp.Vals[i] = ((State.ExtButtons2 & ExtButtons2_Classic_ZR ) ? 0 : 0xFFFF); continue;
428 | case 29: gp.Vals[i] = ((State.ExtButtons2 & ExtButtons2_Classic_B ) ? 0 : 0xFFFF); continue;
429 | case 30: gp.Vals[i] = ((State.ExtButtons2 & ExtButtons2_Classic_A ) ? 0 : 0xFFFF); continue;
430 | case 31: gp.Vals[i] = ((State.ExtButtons2 & ExtButtons2_Classic_Y ) ? 0 : 0xFFFF); continue;
431 | case 32: gp.Vals[i] = ((State.ExtButtons2 & ExtButtons2_Classic_X ) ? 0 : 0xFFFF); continue;
432 | case 33: gp.Vals[i] = ((State.ExtButtons1 & ExtButtons1_Classic_Home ) ? 0 : 0xFFFF); continue;
433 | case 34: gp.Vals[i] = ((State.ExtButtons3 & ExtButtons3_Pro_RStick ) ? 0 : 0xFFFF); continue;
434 | case 35: gp.Vals[i] = ((State.ExtButtons3 & ExtButtons3_Pro_LStick ) ? 0 : 0xFFFF); continue;
435 | case 36: gp.Vals[i] = ExtCal.TL.GetUp(State.ExtTL); continue;
436 | case 37: gp.Vals[i] = ExtCal.TR.GetUp(State.ExtTR); continue;
437 | }
438 | break;
439 | case GPIDINTERFACE_CAPTURE_NEXT_KEY:
440 | if (!(CaptureSources & (1 << GPIDINTERFACE_WII))) break;
441 | o =
442 | (((State.WiiButtons1 & WiiButtons1_Up ) && !(StatePrev.WiiButtons1 & WiiButtons1_Up )) ? 0 :
443 | (((State.WiiButtons1 & WiiButtons1_Down ) && !(StatePrev.WiiButtons1 & WiiButtons1_Down )) ? 1 :
444 | (((State.WiiButtons1 & WiiButtons1_Left ) && !(StatePrev.WiiButtons1 & WiiButtons1_Left )) ? 2 :
445 | (((State.WiiButtons1 & WiiButtons1_Right ) && !(StatePrev.WiiButtons1 & WiiButtons1_Right )) ? 3 :
446 | (((State.WiiButtons2 & WiiButtons2_A ) && !(StatePrev.WiiButtons2 & WiiButtons2_A )) ? 4 :
447 | (((State.WiiButtons2 & WiiButtons2_B ) && !(StatePrev.WiiButtons2 & WiiButtons2_B )) ? 5 :
448 | (((State.WiiButtons2 & WiiButtons2_One ) && !(StatePrev.WiiButtons2 & WiiButtons2_One )) ? 6 :
449 | (((State.WiiButtons2 & WiiButtons2_Two ) && !(StatePrev.WiiButtons2 & WiiButtons2_Two )) ? 7 :
450 | (((State.WiiButtons1 & WiiButtons1_Plus ) && !(StatePrev.WiiButtons1 & WiiButtons1_Plus )) ? 8 :
451 | (((State.WiiButtons2 & WiiButtons2_Minus ) && !(StatePrev.WiiButtons2 & WiiButtons2_Minus )) ? 9 :
452 | (((State.WiiButtons2 & WiiButtons2_Home ) && !(StatePrev.WiiButtons2 & WiiButtons2_Home )) ? 10 :
453 | ((ExtCal.YL.GetUp(State.ExtYL) >= 0x8000 && ExtCal.YL.GetUp(StatePrev.ExtYL) < 0x8000) ? 11 :
454 | ((ExtCal.YL.GetDn(State.ExtYL) >= 0x8000 && ExtCal.YL.GetDn(StatePrev.ExtYL) < 0x8000) ? 12 :
455 | ((ExtCal.XL.GetDn(State.ExtXL) >= 0x8000 && ExtCal.XL.GetDn(StatePrev.ExtXL) < 0x8000) ? 13 :
456 | ((ExtCal.XL.GetUp(State.ExtXL) >= 0x8000 && ExtCal.XL.GetUp(StatePrev.ExtXL) < 0x8000) ? 14 :
457 | ((ExtCal.YR.GetUp(State.ExtYR) >= 0x8000 && ExtCal.YR.GetUp(StatePrev.ExtYR) < 0x8000) ? 15 :
458 | ((ExtCal.YR.GetDn(State.ExtYR) >= 0x8000 && ExtCal.YR.GetDn(StatePrev.ExtYR) < 0x8000) ? 16 :
459 | ((ExtCal.XR.GetDn(State.ExtXR) >= 0x8000 && ExtCal.XR.GetDn(StatePrev.ExtXR) < 0x8000) ? 17 :
460 | ((ExtCal.XR.GetUp(State.ExtXR) >= 0x8000 && ExtCal.XR.GetUp(StatePrev.ExtXR) < 0x8000) ? 18 :
461 | ((!(State.ExtButtons2 & ExtButtons2_Classic_Up ) && (StatePrev.ExtButtons2 & ExtButtons2_Classic_Up )) ? 19 :
462 | ((!(State.ExtButtons1 & ExtButtons1_Classic_Down ) && (StatePrev.ExtButtons1 & ExtButtons1_Classic_Down )) ? 20 :
463 | ((!(State.ExtButtons2 & ExtButtons2_Classic_Left ) && (StatePrev.ExtButtons2 & ExtButtons2_Classic_Left )) ? 21 :
464 | ((!(State.ExtButtons1 & ExtButtons1_Classic_Right) && (StatePrev.ExtButtons1 & ExtButtons1_Classic_Right)) ? 22 :
465 | ((!(State.ExtButtons1 & ExtButtons1_Classic_Plus ) && (StatePrev.ExtButtons1 & ExtButtons1_Classic_Plus )) ? 23 :
466 | ((!(State.ExtButtons1 & ExtButtons1_Classic_Minus) && (StatePrev.ExtButtons1 & ExtButtons1_Classic_Minus)) ? 24 :
467 | ((!(State.ExtButtons1 & ExtButtons1_Classic_L ) && (StatePrev.ExtButtons1 & ExtButtons1_Classic_L )) ? 25 :
468 | ((!(State.ExtButtons1 & ExtButtons1_Classic_R ) && (StatePrev.ExtButtons1 & ExtButtons1_Classic_R )) ? 26 :
469 | ((!(State.ExtButtons2 & ExtButtons2_Classic_ZL ) && (StatePrev.ExtButtons2 & ExtButtons2_Classic_ZL )) ? 27 :
470 | ((!(State.ExtButtons2 & ExtButtons2_Classic_ZR ) && (StatePrev.ExtButtons2 & ExtButtons2_Classic_ZR )) ? 28 :
471 | ((!(State.ExtButtons2 & ExtButtons2_Classic_B ) && (StatePrev.ExtButtons2 & ExtButtons2_Classic_B )) ? 29 :
472 | ((!(State.ExtButtons2 & ExtButtons2_Classic_A ) && (StatePrev.ExtButtons2 & ExtButtons2_Classic_A )) ? 30 :
473 | ((!(State.ExtButtons2 & ExtButtons2_Classic_Y ) && (StatePrev.ExtButtons2 & ExtButtons2_Classic_Y )) ? 31 :
474 | ((!(State.ExtButtons2 & ExtButtons2_Classic_X ) && (StatePrev.ExtButtons2 & ExtButtons2_Classic_X )) ? 32 :
475 | ((!(State.ExtButtons1 & ExtButtons1_Classic_Home ) && (StatePrev.ExtButtons1 & ExtButtons1_Classic_Home )) ? 33 :
476 | ((!(State.ExtButtons3 & ExtButtons3_Pro_RStick ) && (StatePrev.ExtButtons3 & ExtButtons3_Pro_RStick )) ? 34 :
477 | ((!(State.ExtButtons3 & ExtButtons3_Pro_LStick ) && (StatePrev.ExtButtons3 & ExtButtons3_Pro_LStick )) ? 35 :
478 | ((ExtCal.XR.GetUp(State.ExtTL) >= 0x8000 && ExtCal.XR.GetUp(StatePrev.ExtTL) < 0x8000) ? 36 :
479 | ((ExtCal.XR.GetUp(State.ExtTR) >= 0x8000 && ExtCal.XR.GetUp(StatePrev.ExtTR) < 0x8000) ? 37 :
480 | 0xFF))))))))))))))))))))))))))))))))))))));
481 | if (o == 0xFF) continue;
482 | gp.IDs[i] = GPIDMake(GPIDINTERFACE_WII, DevNum, o);
483 | break;
484 | }
485 | }
486 | }
487 | StatePrev = State;
488 | }
489 |
490 | static DWORD WINAPI ThreadFunc(Wii* self) { self->Run(); return 0; }
491 |
492 | //static const char* GetReportName(unsigned char n)
493 | //{
494 | // switch (n)
495 | // {
496 | // case InputReport_Status : return "InputReport_Status ";
497 | // case InputReport_ReadData : return "InputReport_ReadData ";
498 | // case InputReport_OutputReportAck : return "InputReport_OutputReportAck ";
499 | // case InputReport_Buttons : return "InputReport_Buttons ";
500 | // case InputReport_ButtonsAccel : return "InputReport_ButtonsAccel ";
501 | // case InputReport_IRAccel : return "InputReport_IRAccel ";
502 | // case InputReport_ButtonsExtension : return "InputReport_ButtonsExtension";
503 | // case InputReport_ExtensionAccel : return "InputReport_ExtensionAccel ";
504 | // case InputReport_IRExtensionAccel : return "InputReport_IRExtensionAccel";
505 | // case OutputReport_LEDs : return "OutputReport_LEDs ";
506 | // case OutputReport_Type : return "OutputReport_Type ";
507 | // case OutputReport_IR : return "OutputReport_IR ";
508 | // case OutputReport_Status : return "OutputReport_Status ";
509 | // case OutputReport_WriteMemory : return "OutputReport_WriteMemory ";
510 | // case OutputReport_ReadMemory : return "OutputReport_ReadMemory ";
511 | // case OutputReport_IR2 : return "OutputReport_IR2 ";
512 | // }
513 | // static char r[] = {'U','N','K','N','O','W','N','X','X','X','\0'};
514 | // r[7] = '0'+((n/100)%10);
515 | // r[8] = '0'+((n/10)%10);
516 | // r[9] = '0'+((n/1)%10);
517 | // return r;
518 | //}
519 | };
520 |
521 | unsigned int hash = (unsigned int)0x811c9dc5;
522 | for (const wchar_t* p = hidPath; *p; p++) hash = ((hash * (unsigned int)0x01000193) ^ (unsigned int)*p);
523 |
524 | static GPVector Wiis;
525 | Wii* w = nullptr;
526 | for (Wii* it : Wiis) { if (it->HidPathHash == hash) { w = it; break; } }
527 | if (!w)
528 | {
529 | if (!on) return 0;
530 | w = new Wii;
531 | memset(w, 0, sizeof(*w));
532 | w->DevNum = 0; recheck: for (Wii* it : Wiis) { if (it->DevNum == w->DevNum) { w->DevNum++; goto recheck; } }
533 | w->HidPathHash = hash;
534 | Wiis.push_back(w);
535 | }
536 | else
537 | {
538 | stop:
539 | w->AbortRead = true;
540 | Sleep(50);
541 | TerminateThread(w->hThread, 0);
542 | CloseHandle(w->hThread);
543 | w->AbortRead = false;
544 | if (!on)
545 | {
546 | if (w->h) CloseHandle(w->h);
547 | delete w;
548 | for (Wii*& it : Wiis) { if (it == w) { Wiis.erase(Wiis.begin() + (&it - &Wiis[0])); break; } }
549 | return 0;
550 | }
551 | }
552 | if (!w->h) w->h = CreateFileW(hidPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
553 | if (LEDs) { w->RequestLEDs(LEDs); LEDs = 0; }
554 | w->hThread = CreateThread(0, 0, (DWORD (WINAPI *)(LPVOID))Wii::ThreadFunc, w, 0, 0);
555 | for (int i = 0; i != 3000/50; i++)
556 | {
557 | LEDs = w->GetLEDs();
558 | if (LEDs || !WaitForSingleObject(w->hThread, 0)) break;
559 | Sleep(50);
560 | }
561 | if (!LEDs)
562 | {
563 | WriteLog("Failed to get Wii controller status\n");
564 | on = FALSE;
565 | goto stop;
566 | }
567 | return LEDs;
568 | }
569 |
--------------------------------------------------------------------------------
/GPWinMM.inl:
--------------------------------------------------------------------------------
1 | /* Gamepad Phoenix
2 | * Copyright (c) 2021-2023 Bernhard Schelling
3 | *
4 | * Gamepad Phoenix is free software: you can redistribute it and/or modify it under the terms
5 | * of the GNU General Public License as published by the Free Software Found-
6 | * ation, either version 3 of the License, or (at your option) any later version.
7 | *
8 | * Gamepad Phoenix is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 | * PURPOSE. See the GNU General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU General Public License along with Gamepad Phoenix.
13 | * If not, see .
14 | */
15 |
16 | namespace GPWinMM {
17 |
18 | enum
19 | {
20 | GPMM_SYSERR_NOERROR = 0, /* no error */
21 | GPMM_SYSERR_ERROR = 1, /* unspecified error */
22 | GPMM_SYSERR_BADDEVICEID = 2, /* device ID out of range */
23 | GPMM_SYSERR_NOTENABLED = 3, /* driver failed enable */
24 | GPMM_SYSERR_ALLOCATED = 4, /* device already allocated */
25 | GPMM_SYSERR_INVALHANDLE = 5, /* device handle is invalid */
26 | GPMM_SYSERR_NODRIVER = 6, /* no device driver present */
27 | GPMM_SYSERR_NOMEM = 7, /* memory allocation error */
28 | GPMM_SYSERR_NOTSUPPORTED = 8, /* function isn't supported */
29 | GPMM_SYSERR_BADERRNUM = 9, /* error value out of range */
30 | GPMM_SYSERR_INVALFLAG = 10, /* invalid flag passed */
31 | GPMM_SYSERR_INVALPARAM = 11, /* invalid parameter passed */
32 | GPMM_SYSERR_HANDLEBUSY = 12, /* handle being used simultaneously on another thread (eg callback) */
33 | GPMM_SYSERR_INVALIDALIAS = 13, /* specified alias not found */
34 | GPMM_SYSERR_BADDB = 14, /* bad registry database */
35 | GPMM_SYSERR_KEYNOTFOUND = 15, /* registry key not found */
36 | GPMM_SYSERR_READERROR = 16, /* registry read error */
37 | GPMM_SYSERR_WRITEERROR = 17, /* registry write error */
38 | GPMM_SYSERR_DELETEERROR = 18, /* registry delete error */
39 | GPMM_SYSERR_VALNOTFOUND = 19, /* registry value not found */
40 | GPMM_SYSERR_NODRIVERCB = 20, /* driver does not call DriverCallback */
41 | GPMM_SYSERR_MOREDATA = 21, /* more data to be returned */
42 | GPMM_SYSERR_LASTERROR = 21, /* last error in range */
43 | GPMM_JOYERR_PARMS = (160+5), /* bad parameters */
44 | GPMM_JOYERR_NOCANDO = (160+6), /* request not completed */
45 | GPMM_JOYERR_UNPLUGGED = (160+7), /* joystick is unplugged */
46 |
47 | /* constants used with JOYINFO and JOYINFOEX structures and MM_JOY* messages */
48 | GPMM_JOY_BUTTON1 = 0x0001,
49 | GPMM_JOY_BUTTON2 = 0x0002,
50 | GPMM_JOY_BUTTON3 = 0x0004,
51 | GPMM_JOY_BUTTON4 = 0x0008,
52 | GPMM_JOY_BUTTON1CHG = 0x0100,
53 | GPMM_JOY_BUTTON2CHG = 0x0200,
54 | GPMM_JOY_BUTTON3CHG = 0x0400,
55 | GPMM_JOY_BUTTON4CHG = 0x0800,
56 |
57 | /* constants used with JOYINFOEX */
58 | GPMM_JOY_BUTTON5 = 0x00000010,
59 | GPMM_JOY_BUTTON6 = 0x00000020,
60 | GPMM_JOY_BUTTON7 = 0x00000040,
61 | GPMM_JOY_BUTTON8 = 0x00000080,
62 | GPMM_JOY_BUTTON9 = 0x00000100,
63 | GPMM_JOY_BUTTON10 = 0x00000200,
64 | GPMM_JOY_BUTTON11 = 0x00000400,
65 | GPMM_JOY_BUTTON12 = 0x00000800,
66 | GPMM_JOY_BUTTON13 = 0x00001000,
67 | GPMM_JOY_BUTTON14 = 0x00002000,
68 | GPMM_JOY_BUTTON15 = 0x00004000,
69 | GPMM_JOY_BUTTON16 = 0x00008000,
70 | GPMM_JOY_BUTTON17 = 0x00010000,
71 | GPMM_JOY_BUTTON18 = 0x00020000,
72 | GPMM_JOY_BUTTON19 = 0x00040000,
73 | GPMM_JOY_BUTTON20 = 0x00080000,
74 | GPMM_JOY_BUTTON21 = 0x00100000,
75 | GPMM_JOY_BUTTON22 = 0x00200000,
76 | GPMM_JOY_BUTTON23 = 0x00400000,
77 | GPMM_JOY_BUTTON24 = 0x00800000,
78 | GPMM_JOY_BUTTON25 = 0x01000000,
79 | GPMM_JOY_BUTTON26 = 0x02000000,
80 | GPMM_JOY_BUTTON27 = 0x04000000,
81 | GPMM_JOY_BUTTON28 = 0x08000000,
82 | GPMM_JOY_BUTTON29 = 0x10000000,
83 | GPMM_JOY_BUTTON30 = 0x20000000,
84 | GPMM_JOY_BUTTON31 = 0x40000000,
85 | GPMM_JOY_BUTTON32 = 0x80000000,
86 |
87 | /* constants used with JOYINFOEX structure */
88 | GPMM_JOY_POVCENTERED = 0xFFFFFFFF,
89 | GPMM_JOY_POVFORWARD = 0,
90 | GPMM_JOY_POVRIGHT = 9000,
91 | GPMM_JOY_POVBACKWARD = 18000,
92 | GPMM_JOY_POVLEFT = 27000,
93 |
94 | GPMM_JOY_RETURNX = 0x00000001,
95 | GPMM_JOY_RETURNY = 0x00000002,
96 | GPMM_JOY_RETURNZ = 0x00000004,
97 | GPMM_JOY_RETURNR = 0x00000008,
98 | GPMM_JOY_RETURNU = 0x00000010, /* axis 5 */
99 | GPMM_JOY_RETURNV = 0x00000020, /* axis 6 */
100 | GPMM_JOY_RETURNPOV = 0x00000040,
101 | GPMM_JOY_RETURNBUTTONS = 0x00000080,
102 | GPMM_JOY_RETURNRAWDATA = 0x00000100,
103 | GPMM_JOY_RETURNPOVCTS = 0x00000200,
104 | GPMM_JOY_RETURNCENTERED = 0x00000400,
105 | GPMM_JOY_USEDEADZONE = 0x00000800,
106 | GPMM_JOY_RETURNALL = (GPMM_JOY_RETURNX | GPMM_JOY_RETURNY | GPMM_JOY_RETURNZ | GPMM_JOY_RETURNR | GPMM_JOY_RETURNU | GPMM_JOY_RETURNV | GPMM_JOY_RETURNPOV | GPMM_JOY_RETURNBUTTONS),
107 | GPMM_JOY_CAL_READALWAYS = 0x00010000,
108 | GPMM_JOY_CAL_READXYONLY = 0x00020000,
109 | GPMM_JOY_CAL_READ3 = 0x00040000,
110 | GPMM_JOY_CAL_READ4 = 0x00080000,
111 | GPMM_JOY_CAL_READXONLY = 0x00100000,
112 | GPMM_JOY_CAL_READYONLY = 0x00200000,
113 | GPMM_JOY_CAL_READ5 = 0x00400000,
114 | GPMM_JOY_CAL_READ6 = 0x00800000,
115 | GPMM_JOY_CAL_READZONLY = 0x01000000,
116 | GPMM_JOY_CAL_READRONLY = 0x02000000,
117 | GPMM_JOY_CAL_READUONLY = 0x04000000,
118 | GPMM_JOY_CAL_READVONLY = 0x08000000,
119 |
120 | /* joystick ID constants */
121 | GPMM_JOYSTICKID1 = 0,
122 | GPMM_JOYSTICKID2 = 1,
123 |
124 | /* joystick driver capabilites */
125 | GPMM_JOYCAPS_HASZ = 0x0001,
126 | GPMM_JOYCAPS_HASR = 0x0002,
127 | GPMM_JOYCAPS_HASU = 0x0004,
128 | GPMM_JOYCAPS_HASV = 0x0008,
129 | GPMM_JOYCAPS_HASPOV = 0x0010,
130 | GPMM_JOYCAPS_POV4DIR = 0x0020,
131 | GPMM_JOYCAPS_POVCTS = 0x0040,
132 | };
133 |
134 | struct GPJoyInfoEx
135 | {
136 | DWORD dwSize; /* size of structure */
137 | DWORD dwFlags; /* flags to indicate what to return */
138 | DWORD dwXpos, dwYpos, dwZpos, dwRpos, dwUpos, dwVpos; // x/y/z/rudder/5th/6th axis position
139 | DWORD dwButtons; /* button states */
140 | DWORD dwButtonNumber; /* current button number pressed */
141 | DWORD dwPOV; /* point of view state */
142 | DWORD dwReserved1, dwReserved2;
143 | };
144 |
145 | struct GPJoyCaps
146 | {
147 | WORD wMid, wPid; // manufacturer/product ID
148 | union { WCHAR szPname[32]; char szPnameA[32]; }; // product name (NULL terminated string)
149 | struct Extra
150 | {
151 | UINT wXmin, wXmax, wYmin, wYmax, wZmin, wZmax; // min/max x/y/z position values
152 | UINT wNumButtons; // number of buttons */
153 | UINT wPeriodMin, wPeriodMax; // minimum/maximum message period when captured */
154 | UINT wRmin, wRmax, wUmin, wUmax, wVmin, wVmax; // min/max rudder/5th/6th axis position values
155 | UINT wCaps; /* joystick capabilites */
156 | UINT wMaxAxes; /* maximum number of axes supported */
157 | UINT wNumAxes; /* number of axes in use */
158 | UINT wMaxButtons; /* maximum number of buttons supported */
159 | union { WCHAR szRegKey[32]; char szRegKeyA[32]; }; // registry key
160 | union { WCHAR szOEMVxD[260]; char szOEMVxDA[260]; }; // OEM VxD in use
161 | };
162 | Extra* GetExtra(bool isW) const { return (Extra*)((char*)&extra - (isW ? 0 : 32)); }
163 | DWORD GetSize(bool isW) const { return (DWORD)sizeof(*this) - (DWORD)(isW ? 0 : (32+32+260)); }
164 | void SetStrings(bool isW, const WCHAR* pname, const WCHAR* regkey, const WCHAR* oemvxd)
165 | {
166 | if (isW) { wcscpy(szPname, pname); wcscpy(extra.szRegKey, regkey); wcscpy(extra.szOEMVxD, oemvxd); }
167 | else { WideCharToMultiByte(CP_ACP, 0, pname, -1, szPnameA, 32, NULL, NULL); WideCharToMultiByte(CP_ACP, 0, regkey, -1, GetExtra(false)->szRegKeyA, 32, NULL, NULL); WideCharToMultiByte(CP_ACP, 0, oemvxd, -1, GetExtra(false)->szOEMVxDA, 260, NULL, NULL); }
168 | }
169 | private: Extra extra;
170 | };
171 | GPSTATIC_ASSERT(sizeof(GPJoyCaps) == 4+32*2+76+32*2+260*2);
172 |
173 | struct GPJoyInfo { UINT wXpos, wYpos, wZpos, wButtons; };
174 |
175 | // All but GPjoyGetNumDevs return error code (0 means no error)
176 | static UINT WINAPI GPjoyConfigChanged(DWORD dwFlags)
177 | {
178 | return 0;
179 | }
180 |
181 | static bool CheckStarted(UINT_PTR uJoyID)
182 | {
183 | static bool Started[GPData::NUM_GAMEPADS], Logged[GPData::NUM_GAMEPADS];
184 | if (uJoyID >= GPData::NUM_GAMEPADS) return false;
185 | if (Started[uJoyID]) return true;
186 | if ((pGPData->Options & (OPTION_Disable_MMSys|OPTION_Disable_XInput)) == OPTION_Disable_MMSys)
187 | {
188 | GameUsesXInput = true;
189 | }
190 | else if (pGPData->Options & OPTION_Disable_MMSys)
191 | {
192 | if (Logged[uJoyID]) return false;
193 | WriteLog("Application tried to %s %s %s %d but the interface is disabled, returning no connected device\n", "read input for", "WinMM", "joystick", (int)(uJoyID + 1));
194 | Logged[uJoyID] = true;
195 | return false;
196 | }
197 | bool isXInputPad = (GameUsesXInput && !ForceVirtualDevices && !(pGPData->Options & OPTION_Disable_XInput));
198 | WriteLog("Application started reading input for %s %s %d%s\n", "WinMM", "joystick", (int)(uJoyID + 1) + 1, (isXInputPad ? " (simulating XInput gamepad because XInput was also loaded)" : ""));
199 | Started[uJoyID] = true;
200 | return true;
201 | }
202 |
203 | static UINT WINAPI GPjoyGetDevCaps(bool isW, UINT_PTR uJoyID, GPJoyCaps* pjc, UINT cbjc)
204 | {
205 | if (!pjc || cbjc != pjc->GetSize(isW)) return GPMM_SYSERR_INVALPARAM;
206 | if (!CheckStarted(uJoyID)) return GPMM_SYSERR_NODRIVER;
207 | if (!pGPData->Gamepads[uJoyID].Used) return GPMM_JOYERR_UNPLUGGED;
208 |
209 | if (!GameUsesXInput) ForceVirtualDevices = true; // if the caller has seen virtual devices once, keep returning only virtual devices
210 | bool isXInputPad = (GameUsesXInput && !ForceVirtualDevices && !(pGPData->Options & OPTION_Disable_XInput));
211 | bool usePOVtoButtons = (!isXInputPad && (pGPData->Options & OPTION_DI_POVtoButtons));
212 | bool useTriggersToButtons = (!isXInputPad && (pGPData->Options & OPTION_DI_TriggersToButtons));
213 |
214 | pjc->wMid = (WORD)(0x2000);
215 | pjc->wPid = (WORD)(0x2000 + uJoyID);
216 | pjc->SetStrings(isW, L"GamepadPhoenix", L"DINPUT.DLL", L"");
217 | auto* e = pjc->GetExtra(isW);
218 | e->wXmin = e->wYmin = e->wZmin = e->wRmin = e->wUmin = e->wVmin = 0;
219 | e->wXmax = e->wYmax = e->wZmax = e->wRmax = e->wUmax = e->wVmax = 0xFFFF;
220 | e->wNumButtons = 10 + (usePOVtoButtons ? 4 : 0) + (useTriggersToButtons ? 2 : 0);
221 | e->wPeriodMin = 10;
222 | e->wPeriodMax = 1000;
223 | e->wCaps = GPMM_JOYCAPS_HASR | GPMM_JOYCAPS_HASU
224 | | (usePOVtoButtons ? 0 : GPMM_JOYCAPS_HASPOV | GPMM_JOYCAPS_POV4DIR)
225 | | (isXInputPad ? GPMM_JOYCAPS_HASZ : (useTriggersToButtons ? 0 : GPMM_JOYCAPS_HASV | GPMM_JOYCAPS_HASZ));
226 | e->wMaxAxes = 6;
227 | e->wNumAxes = (isXInputPad ? 5 : (useTriggersToButtons ? 4 : 6));
228 | e->wMaxButtons = 32;
229 | return 0;
230 | }
231 | static UINT WINAPI GPjoyGetDevCapsA(UINT_PTR uJoyID, GPJoyCaps* pjc, UINT cbjc) { return GPjoyGetDevCaps(false, uJoyID, pjc, cbjc); }
232 | static UINT WINAPI GPjoyGetDevCapsW(UINT_PTR uJoyID, GPJoyCaps* pjc, UINT cbjc) { return GPjoyGetDevCaps(true, uJoyID, pjc, cbjc); }
233 |
234 | static UINT WINAPI GPjoyGetNumDevs(VOID)
235 | {
236 | UINT n = GPData::NUM_GAMEPADS;
237 | while (--n) if (pGPData->Gamepads[n].Used) break;
238 | return n + 1;
239 | }
240 |
241 | static UINT WINAPI GPjoyGetPos(UINT uJoyID, GPJoyInfo* pji)
242 | {
243 | if (!pji) return GPMM_SYSERR_INVALPARAM;
244 | if (!CheckStarted(uJoyID)) return GPMM_SYSERR_NODRIVER;
245 | GPGamepad& gp = pGPData->Gamepads[uJoyID];
246 | if (!gp.Used) return GPMM_JOYERR_UNPLUGGED;
247 |
248 | RunInputUpdaters(gp);
249 | const unsigned short* vals = gp.Vals, gpOptions = pGPData->Options;
250 | bool isXInputPad = (GameUsesXInput && !ForceVirtualDevices && !(gpOptions & OPTION_Disable_XInput));
251 | bool usePOVtoButtons = (!isXInputPad && (gpOptions & OPTION_DI_POVtoButtons));
252 | bool useTriggersToButtons = (!isXInputPad && (gpOptions & OPTION_DI_TriggersToButtons));
253 | bool mergeDPad = !!(gpOptions & OPTION_DPadToLStick);
254 |
255 | pji->wXpos = 0x7FFF + (UINT)(gp.Axis(GPIDX_LSTICK_R, mergeDPad) * 0x8000 / 0xFFFF) - (UINT)(gp.Axis(GPIDX_LSTICK_L, mergeDPad) * 0x7FFF / 0xFFFF);
256 | pji->wYpos = 0x7FFF + (UINT)(gp.Axis(GPIDX_LSTICK_D, mergeDPad) * 0x8000 / 0xFFFF) - (UINT)(gp.Axis(GPIDX_LSTICK_U, mergeDPad) * 0x7FFF / 0xFFFF);
257 | int gpidx_btn_a = ((gpOptions & OPTION_SwapAandB) ? GPIDX_BTN_B : GPIDX_BTN_A);
258 | int gpidx_btn_b = ((gpOptions & OPTION_SwapAandB) ? GPIDX_BTN_A : GPIDX_BTN_B);
259 | int gpidx_trigger_l = ((gpOptions & OPTION_SwapL1R1andL2R2) ? GPIDX_BTN_L : GPIDX_TRIGGER_L);
260 | int gpidx_trigger_r = ((gpOptions & OPTION_SwapL1R1andL2R2) ? GPIDX_BTN_R : GPIDX_TRIGGER_R);
261 | int gpidx_btn_l = ((gpOptions & OPTION_SwapL1R1andL2R2) ? GPIDX_TRIGGER_L : GPIDX_BTN_L);
262 | int gpidx_btn_r = ((gpOptions & OPTION_SwapL1R1andL2R2) ? GPIDX_TRIGGER_R : GPIDX_BTN_R);
263 | pji->wButtons = 0
264 | | ((vals[gpidx_btn_a ] & 0x8000u) >> 15)
265 | | ((vals[gpidx_btn_b ] & 0x8000u) >> 14)
266 | | ((vals[GPIDX_BTN_X ] & 0x8000u) >> 13)
267 | | ((vals[GPIDX_BTN_Y ] & 0x8000u) >> 12)
268 | | ((vals[gpidx_btn_l ] & 0x8000u) >> 11)
269 | | ((vals[gpidx_btn_r ] & 0x8000u) >> 10)
270 | | ((vals[GPIDX_BTN_START ] & 0x8000u) >> 9)
271 | | ((vals[GPIDX_BTN_BACK ] & 0x8000u) >> 8)
272 | | ((vals[GPIDX_BTN_LSTICK ] & 0x8000u) >> 7)
273 | | ((vals[GPIDX_BTN_RSTICK ] & 0x8000u) >> 6)
274 | ;
275 | if (isXInputPad)
276 | pji->wZpos = 0x7FFF + (UINT)(vals[gpidx_trigger_l] * 0x7F81 / 0xFFFF) - (UINT)(vals[gpidx_trigger_r] * 0x7F7F / 0xFFFF);
277 | else
278 | pji->wZpos = 0x7FFF + (UINT)(vals[gpidx_trigger_l] * 0x8000 / 0xFFFF);
279 | if (usePOVtoButtons)
280 | pji->wButtons |= 0
281 | | ((vals[GPIDX_DPAD_U ] & 0x8000u) >> 5)
282 | | ((vals[GPIDX_DPAD_D ] & 0x8000u) >> 4)
283 | | ((vals[GPIDX_DPAD_L ] & 0x8000u) >> 3)
284 | | ((vals[GPIDX_DPAD_R ] & 0x8000u) >> 2);
285 | if (useTriggersToButtons)
286 | pji->wZpos = 0, pji->wButtons |= 0
287 | | ((vals[gpidx_trigger_l ] & 0x8000u) >> 1)
288 | | ((vals[gpidx_trigger_r ] & 0x8000u) >> 0);
289 | return 0;
290 | }
291 |
292 | static UINT WINAPI GPjoyGetPosEx(UINT uJoyID, GPJoyInfoEx* pji)
293 | {
294 | if (!pji || pji->dwSize != sizeof(*pji)) return GPMM_SYSERR_INVALPARAM;
295 | if (uJoyID == 0xFFFF || uJoyID == 0xFFFFFFFF) uJoyID = 0;
296 | GPJoyInfo ji;
297 | UINT res = GPjoyGetPos(uJoyID, &ji);
298 | if (res) return res;
299 |
300 | const GPGamepad& gp = pGPData->Gamepads[uJoyID];
301 | const unsigned short* vals = gp.Vals, gpOptions = pGPData->Options;
302 | bool isXInputPad = (GameUsesXInput && !ForceVirtualDevices && !(gpOptions & OPTION_Disable_XInput));
303 | bool usePOVtoButtons = (!isXInputPad && (gpOptions & OPTION_DI_POVtoButtons));
304 | bool useTriggersToButtons = (!isXInputPad && (gpOptions & OPTION_DI_TriggersToButtons));
305 |
306 | pji->dwButtons = pji->dwButtonNumber = 0;
307 | if (pji->dwFlags & GPMM_JOY_RETURNBUTTONS)
308 | {
309 | pji->dwButtons = ji.wButtons;
310 | for (UINT i = 1; (ji.wButtons & ~(i-1)) && i; i <<= 1)
311 | if (ji.wButtons & i)
312 | pji->dwButtonNumber++;
313 | }
314 | pji->dwXpos = ji.wXpos;
315 | pji->dwYpos = ji.wYpos;
316 | pji->dwZpos = ji.wZpos;
317 | pji->dwRpos = 0x7FFF - (UINT)(gp.Axis(GPIDX_RSTICK_L) * 0x7FFF / 0xFFFF) + (UINT)(gp.Axis(GPIDX_RSTICK_R) * 0x8000 / 0xFFFF);
318 | pji->dwUpos = 0x7FFF - (UINT)(gp.Axis(GPIDX_RSTICK_U) * 0x7FFF / 0xFFFF) + (UINT)(gp.Axis(GPIDX_RSTICK_D) * 0x8000 / 0xFFFF);
319 | if (!isXInputPad && !useTriggersToButtons)
320 | pji->dwVpos = 0x7FFF + (UINT)(vals[(gpOptions & OPTION_SwapL1R1andL2R2) ? GPIDX_BTN_R : GPIDX_TRIGGER_R] * 0x8000 / 0xFFFF);
321 | if (!usePOVtoButtons)
322 | {
323 | unsigned int mask =
324 | ((vals[GPIDX_DPAD_U] & 0x8000u) >> 15) | // 1 UP
325 | ((vals[GPIDX_DPAD_D] & 0x8000u) >> 14) | // 2 DOWN
326 | ((vals[GPIDX_DPAD_L] & 0x8000u) >> 13) | // 4 LEFT
327 | ((vals[GPIDX_DPAD_R] & 0x8000u) >> 12); // 8 RIGHT
328 | static const DWORD DPADDatas[] = { 0xFFFF, 0, 18000, 0xFFFF, 27000, 31500, 22500, 27000, 9000, 4500, 13500, 9000, 0xFFFF, 0, 18000, 0xFFFF };
329 | pji->dwPOV = DPADDatas[mask];
330 | }
331 | return 0;
332 | }
333 |
334 | static UINT WINAPI GPjoyGetThreshold(UINT uJoyID, LPUINT puThreshold)
335 | {
336 | if (!puThreshold) return GPMM_SYSERR_INVALPARAM;
337 | if (!CheckStarted(uJoyID)) return GPMM_SYSERR_NODRIVER;
338 | if (!pGPData->Gamepads[uJoyID].Used) return GPMM_JOYERR_UNPLUGGED;
339 | *puThreshold = 0;
340 | return 0;
341 | }
342 |
343 | static UINT WINAPI GPjoyReleaseCapture(UINT uJoyID)
344 | {
345 | return GPMM_JOYERR_NOCANDO;
346 | }
347 |
348 | static UINT WINAPI GPjoySetCapture(HWND hwnd, UINT uJoyID, UINT uPeriod, BOOL fChanged)
349 | {
350 | return GPMM_JOYERR_NOCANDO;
351 | }
352 |
353 | static UINT WINAPI GPjoySetThreshold(UINT uJoyID, UINT uThreshold)
354 | {
355 | if (!CheckStarted(uJoyID)) return GPMM_SYSERR_NODRIVER;
356 | if (!pGPData->Gamepads[uJoyID].Used) return GPMM_JOYERR_UNPLUGGED;
357 | if (!uThreshold) return 0;
358 | return GPMM_JOYERR_NOCANDO;
359 | }
360 |
361 | static void Hook()
362 | {
363 | LOGSCOPE();
364 | GPCHECKNORECURSION();
365 |
366 | static bool hookedWinMM;
367 | if (hookedWinMM) return;
368 | HMODULE hmWinMM = GetModuleHandleA("winmm");
369 | if (!hmWinMM) return;
370 | hookedWinMM = true;
371 |
372 | CreateHook(hmWinMM, "joyConfigChanged", GPjoyConfigChanged, false);
373 | CreateHook(hmWinMM, "joyGetDevCapsA", GPjoyGetDevCapsA, false);
374 | CreateHook(hmWinMM, "joyGetDevCapsW", GPjoyGetDevCapsW, false);
375 | CreateHook(hmWinMM, "joyGetNumDevs", GPjoyGetNumDevs, false);
376 | CreateHook(hmWinMM, "joyGetPos", GPjoyGetPos, false);
377 | CreateHook(hmWinMM, "joyGetPosEx", GPjoyGetPosEx, false);
378 | CreateHook(hmWinMM, "joyGetThreshold", GPjoyGetThreshold, false);
379 | CreateHook(hmWinMM, "joyReleaseCapture", GPjoyReleaseCapture, false);
380 | CreateHook(hmWinMM, "joySetCapture", GPjoySetCapture, false);
381 | CreateHook(hmWinMM, "joySetThreshold", GPjoySetThreshold, true);
382 | WriteLog("Intercepting WinMM interface\n");
383 | }
384 |
385 | }; // namespace GPWinMM
386 |
--------------------------------------------------------------------------------
/GPXInput.inl:
--------------------------------------------------------------------------------
1 | /* Gamepad Phoenix
2 | * Copyright (c) 2021-2023 Bernhard Schelling
3 | *
4 | * Gamepad Phoenix is free software: you can redistribute it and/or modify it under the terms
5 | * of the GNU General Public License as published by the Free Software Found-
6 | * ation, either version 3 of the License, or (at your option) any later version.
7 | *
8 | * Gamepad Phoenix is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 | * PURPOSE. See the GNU General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU General Public License along with Gamepad Phoenix.
13 | * If not, see .
14 | */
15 |
16 | namespace GPXInput {
17 |
18 | enum
19 | {
20 | GPXI_GAMEPAD_DPAD_UP = 0x0001,
21 | GPXI_GAMEPAD_DPAD_DOWN = 0x0002,
22 | GPXI_GAMEPAD_DPAD_LEFT = 0x0004,
23 | GPXI_GAMEPAD_DPAD_RIGHT = 0x0008,
24 | GPXI_GAMEPAD_START = 0x0010,
25 | GPXI_GAMEPAD_BACK = 0x0020,
26 | GPXI_GAMEPAD_LEFT_THUMB = 0x0040,
27 | GPXI_GAMEPAD_RIGHT_THUMB = 0x0080,
28 | GPXI_GAMEPAD_LEFT_SHOULDER = 0x0100,
29 | GPXI_GAMEPAD_RIGHT_SHOULDER = 0x0200,
30 | GPXI_GAMEPAD_A = 0x1000,
31 | GPXI_GAMEPAD_B = 0x2000,
32 | GPXI_GAMEPAD_X = 0x4000,
33 | GPXI_GAMEPAD_Y = 0x8000,
34 | GPXI_GAMEPAD_ALL_BUTTONS = 0xF3FF,
35 | GPXI_GAMEPAD_GUIDE = 0x0400,
36 |
37 | GPXI_KEYSTROKE_KEYDOWN = 0x0001,
38 | GPXI_KEYSTROKE_KEYUP = 0x0002,
39 | GPXI_KEYSTROKE_REPEAT = 0x0004,
40 |
41 | GPXI_PAD_A = 0x5800,
42 | GPXI_PAD_B = 0x5801,
43 | GPXI_PAD_X = 0x5802,
44 | GPXI_PAD_Y = 0x5803,
45 | GPXI_PAD_RSHOULDER = 0x5804,
46 | GPXI_PAD_LSHOULDER = 0x5805,
47 | GPXI_PAD_LTRIGGER = 0x5806,
48 | GPXI_PAD_RTRIGGER = 0x5807,
49 | GPXI_PAD_DPAD_UP = 0x5810,
50 | GPXI_PAD_DPAD_DOWN = 0x5811,
51 | GPXI_PAD_DPAD_LEFT = 0x5812,
52 | GPXI_PAD_DPAD_RIGHT = 0x5813,
53 | GPXI_PAD_START = 0x5814,
54 | GPXI_PAD_BACK = 0x5815,
55 | GPXI_PAD_LTHUMB_PRESS = 0x5816,
56 | GPXI_PAD_RTHUMB_PRESS = 0x5817,
57 | GPXI_PAD_LTHUMB_UP = 0x5820,
58 | GPXI_PAD_LTHUMB_DOWN = 0x5821,
59 | GPXI_PAD_LTHUMB_RIGHT = 0x5822,
60 | GPXI_PAD_LTHUMB_LEFT = 0x5823,
61 | GPXI_PAD_LTHUMB_UPLEFT = 0x5824,
62 | GPXI_PAD_LTHUMB_UPRIGHT = 0x5825,
63 | GPXI_PAD_LTHUMB_DOWNRIGHT = 0x5826,
64 | GPXI_PAD_LTHUMB_DOWNLEFT = 0x5827,
65 | GPXI_PAD_RTHUMB_UP = 0x5830,
66 | GPXI_PAD_RTHUMB_DOWN = 0x5831,
67 | GPXI_PAD_RTHUMB_RIGHT = 0x5832,
68 | GPXI_PAD_RTHUMB_LEFT = 0x5833,
69 | GPXI_PAD_RTHUMB_UPLEFT = 0x5834,
70 | GPXI_PAD_RTHUMB_UPRIGHT = 0x5835,
71 | GPXI_PAD_RTHUMB_DOWNRIGHT = 0x5836,
72 | GPXI_PAD_RTHUMB_DOWNLEFT = 0x5837,
73 |
74 | GPXI_GAMEPAD_LEFT_THUMB_DEADZONE = 7849,
75 | GPXI_GAMEPAD_RIGHT_THUMB_DEADZONE = 8689,
76 | GPXI_GAMEPAD_TRIGGER_THRESHOLD = 30,
77 |
78 | GPXI_DEVTYPE_GAMEPAD = 0x01,
79 | GPXI_DEVSUBTYPE_GAMEPAD = 0x01,
80 | GPXI_DEVSUBTYPE_WHEEL = 0x02,
81 | GPXI_DEVSUBTYPE_ARCADE_STICK = 0x03,
82 | GPXI_DEVSUBTYPE_FLIGHT_SICK = 0x04,
83 | GPXI_DEVSUBTYPE_DANCE_PAD = 0x05,
84 | GPXI_DEVSUBTYPE_GUITAR = 0x06,
85 | GPXI_DEVSUBTYPE_DRUM_KIT = 0x08,
86 |
87 | GPXI_CAPS_VOICE_SUPPORTED = 0x0004,
88 | GPXI_FLAG_GAMEPAD = 0x00000001,
89 |
90 | GPXI_BATTERY_DEVTYPE_GAMEPAD = 0x00,
91 | GPXI_BATTERY_DEVTYPE_HEADSET = 0x01,
92 | GPXI_BATTERY_TYPE_DISCONNECTED = 0x00,
93 | GPXI_BATTERY_TYPE_WIRED = 0x01,
94 | GPXI_BATTERY_TYPE_ALKALINE = 0x02,
95 | GPXI_BATTERY_TYPE_NIMH = 0x03,
96 | GPXI_BATTERY_TYPE_UNKNOWN = 0xFF,
97 | GPXI_BATTERY_LEVEL_EMPTY = 0x00,
98 | GPXI_BATTERY_LEVEL_LOW = 0x01,
99 | GPXI_BATTERY_LEVEL_MEDIUM = 0x02,
100 | GPXI_BATTERY_LEVEL_FULL = 0x03,
101 |
102 | GPXI_XUSER_MAX_COUNT = 4,
103 | GPXI_XUSER_INDEX_ANY = 0x000000FF,
104 | };
105 | GPSTATIC_ASSERT(GPData::NUM_GAMEPADS >= GPXI_XUSER_MAX_COUNT);
106 |
107 | struct GPXINPUT_GAMEPAD
108 | {
109 | WORD wButtons;
110 | BYTE bLeftTrigger, bRightTrigger;
111 | SHORT sThumbLX, sThumbLY, sThumbRX, sThumbRY;
112 | };
113 |
114 | struct GPXINPUT_STATE
115 | {
116 | DWORD dwPacketNumber;
117 | GPXINPUT_GAMEPAD Gamepad;
118 | };
119 |
120 | struct GPXINPUT_VIBRATION
121 | {
122 | WORD wLeftMotorSpeed, wRightMotorSpeed;
123 | };
124 |
125 | struct GPXINPUT_CAPABILITIES
126 | {
127 | BYTE Type, SubType;
128 | WORD Flags;
129 | GPXINPUT_GAMEPAD Gamepad;
130 | GPXINPUT_VIBRATION Vibration;
131 | };
132 |
133 | struct GPXINPUT_KEYSTROKE
134 | {
135 | WORD VirtualKey;
136 | WCHAR Unicode;
137 | WORD Flags;
138 | BYTE UserIndex, HidCode;
139 | };
140 |
141 | struct GPXINPUT_BATTERY_INFORMATION
142 | {
143 | BYTE BatteryType, BatteryLevel;
144 | };
145 |
146 | static bool CheckStarted(DWORD dwUserIndex)
147 | {
148 | static bool Started[GPXI_XUSER_MAX_COUNT], Logged[GPXI_XUSER_MAX_COUNT];
149 | if (Started[dwUserIndex]) return true;
150 | if (pGPData->Options & OPTION_Disable_XInput)
151 | {
152 | if (Logged[dwUserIndex]) return false;
153 | WriteLog("Application tried to %s %s %s %d but the interface is disabled, returning no connected device\n", "read input for", "XInput", "pad", (int)(dwUserIndex + 1));
154 | Logged[dwUserIndex] = true;
155 | return false;
156 | }
157 | WriteLog("Application started reading input for %s %s %d%s\n", "XInput", "pad", (int)(dwUserIndex + 1), "");
158 | Started[dwUserIndex] = true;
159 | return true;
160 | }
161 |
162 | typedef DWORD (WINAPI *GPXInputGetStateFN)(DWORD dwUserIndex, GPXINPUT_STATE* pState);
163 | static GPXInputGetStateFN OrgGetState;
164 | DWORD WINAPI GPXInputGetState(DWORD dwUserIndex, GPXINPUT_STATE* pState)
165 | {
166 | #pragma GPLINKER_DLL_EXPORT_AS_HINT(XInputGetState, 2)
167 | LOGSCOPE("dwUserIndex: %u - pState: %p - Prev PacketNumber: %u - %s", dwUserIndex, pState, pState->dwPacketNumber, (dwUserIndex >= GPXI_XUSER_MAX_COUNT ? "INVALID USER INDEX" : (pGPData->Gamepads[dwUserIndex].Used ? "CONNECTED GAMEPAD" : "GAMEPAD NOT CONNECTED")));
168 | if (!GameUsesXInput) GameUsesXInput = true;
169 | if (dwUserIndex >= GPXI_XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS;
170 |
171 | GPGamepad& gp = pGPData->Gamepads[dwUserIndex];
172 | if (!gp.Used || !CheckStarted(dwUserIndex)) return ERROR_DEVICE_NOT_CONNECTED;
173 |
174 | RunInputUpdaters(gp);
175 | const unsigned short* vals = gp.Vals, gpOptions = pGPData->Options;
176 | int gpidx_btn_a = ((gpOptions & OPTION_SwapAandB) ? GPIDX_BTN_B : GPIDX_BTN_A);
177 | int gpidx_btn_b = ((gpOptions & OPTION_SwapAandB) ? GPIDX_BTN_A : GPIDX_BTN_B);
178 | int gpidx_trigger_l = ((gpOptions & OPTION_SwapL1R1andL2R2) ? GPIDX_BTN_L : GPIDX_TRIGGER_L);
179 | int gpidx_trigger_r = ((gpOptions & OPTION_SwapL1R1andL2R2) ? GPIDX_BTN_R : GPIDX_TRIGGER_R);
180 | int gpidx_btn_l = ((gpOptions & OPTION_SwapL1R1andL2R2) ? GPIDX_TRIGGER_L : GPIDX_BTN_L);
181 | int gpidx_btn_r = ((gpOptions & OPTION_SwapL1R1andL2R2) ? GPIDX_TRIGGER_R : GPIDX_BTN_R);
182 | bool mergeDPad = !!(gpOptions & OPTION_DPadToLStick);
183 |
184 | pState->Gamepad.sThumbLY = (short)(gp.Axis(GPIDX_LSTICK_U, mergeDPad) * 0x7FFF / 0xFFFF) - (short)(gp.Axis(GPIDX_LSTICK_D, mergeDPad) * 0x8000 / 0xFFFF);
185 | pState->Gamepad.sThumbLX = (short)(gp.Axis(GPIDX_LSTICK_R, mergeDPad) * 0x7FFF / 0xFFFF) - (short)(gp.Axis(GPIDX_LSTICK_L, mergeDPad) * 0x8000 / 0xFFFF);
186 | pState->Gamepad.sThumbRY = (short)(gp.Axis(GPIDX_RSTICK_U ) * 0x7FFF / 0xFFFF) - (short)(gp.Axis(GPIDX_RSTICK_D ) * 0x8000 / 0xFFFF);
187 | pState->Gamepad.sThumbRX = (short)(gp.Axis(GPIDX_RSTICK_R ) * 0x7FFF / 0xFFFF) - (short)(gp.Axis(GPIDX_RSTICK_L ) * 0x8000 / 0xFFFF);
188 | pState->Gamepad.bLeftTrigger = (BYTE)(vals[gpidx_trigger_l] * 0xFF / 0xFFFF);
189 | pState->Gamepad.bRightTrigger = (BYTE)(vals[gpidx_trigger_r] * 0xFF / 0xFFFF);
190 | pState->Gamepad.wButtons = 0
191 | | ((vals[GPIDX_DPAD_U ] & 0x8000u) >> 15) //GPXI_GAMEPAD_DPAD_UP = 0x0001,
192 | | ((vals[GPIDX_DPAD_D ] & 0x8000u) >> 14) //GPXI_GAMEPAD_DPAD_DOWN = 0x0002,
193 | | ((vals[GPIDX_DPAD_L ] & 0x8000u) >> 13) //GPXI_GAMEPAD_DPAD_LEFT = 0x0004,
194 | | ((vals[GPIDX_DPAD_R ] & 0x8000u) >> 12) //GPXI_GAMEPAD_DPAD_RIGHT = 0x0008,
195 | | ((vals[GPIDX_BTN_START ] & 0x8000u) >> 11) //GPXI_GAMEPAD_START = 0x0010,
196 | | ((vals[GPIDX_BTN_BACK ] & 0x8000u) >> 10) //GPXI_GAMEPAD_BACK = 0x0020,
197 | | ((vals[GPIDX_BTN_LSTICK ] & 0x8000u) >> 9) //GPXI_GAMEPAD_LEFT_THUMB = 0x0040,
198 | | ((vals[GPIDX_BTN_RSTICK ] & 0x8000u) >> 8) //GPXI_GAMEPAD_RIGHT_THUMB = 0x0080,
199 | | ((vals[gpidx_btn_l ] & 0x8000u) >> 7) //GPXI_GAMEPAD_LEFT_SHOULDER = 0x0100,
200 | | ((vals[gpidx_btn_r ] & 0x8000u) >> 6) //GPXI_GAMEPAD_RIGHT_SHOULDER = 0x0200,
201 | | ((vals[gpidx_btn_a ] & 0x8000u) >> 3) //GPXI_GAMEPAD_A = 0x1000,
202 | | ((vals[gpidx_btn_b ] & 0x8000u) >> 2) //GPXI_GAMEPAD_B = 0x2000,
203 | | ((vals[GPIDX_BTN_X ] & 0x8000u) >> 1) //GPXI_GAMEPAD_X = 0x4000,
204 | | ((vals[GPIDX_BTN_Y ] & 0x8000u) >> 0) //GPXI_GAMEPAD_Y = 0x8000,
205 | ;
206 |
207 | // dwPacketNumber must start at 1 for some games
208 | static GPXINPUT_STATE PrevState[GPXI_XUSER_MAX_COUNT];// = { { 1, { 0,0,0,0,0,0,0} }, { 1, { 0,0,0,0,0,0,0} }, { 1, { 0,0,0,0,0,0,0} }, { 1, { 0,0,0,0,0,0,0} }, };
209 | GPXINPUT_STATE* prev = &PrevState[dwUserIndex];
210 | if (memcmp(&pState->Gamepad, &prev->Gamepad, sizeof(pState->Gamepad)))
211 | {
212 | prev->Gamepad = pState->Gamepad;
213 | prev->dwPacketNumber++;
214 | }
215 | pState->dwPacketNumber = prev->dwPacketNumber;
216 | return ERROR_SUCCESS;
217 | }
218 |
219 | DWORD WINAPI GPXInputSetState(DWORD dwUserIndex, GPXINPUT_VIBRATION* pVibration)
220 | {
221 | #pragma GPLINKER_DLL_EXPORT_AS_HINT(XInputSetState, 3)
222 | //WriteLog("[GPXInputSetState] dwUserIndex: %u - pVibration: %p\n", dwUserIndex, pVibration);
223 | if (!GameUsesXInput) GameUsesXInput = true;
224 | if (dwUserIndex >= GPXI_XUSER_MAX_COUNT || !pVibration) return ERROR_BAD_ARGUMENTS;
225 | if (!pGPData->Gamepads[dwUserIndex].Used || !CheckStarted(dwUserIndex)) return ERROR_DEVICE_NOT_CONNECTED;
226 | //TODO: Vibration
227 | return ERROR_SUCCESS;
228 | }
229 |
230 | DWORD WINAPI GPXInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags, GPXINPUT_CAPABILITIES* pCapabilities)
231 | {
232 | #pragma GPLINKER_DLL_EXPORT_AS_HINT(XInputGetCapabilities, 4)
233 | //WriteLog("[GPXInputGetCapabilities] dwUserIndex: %u - dwFlags: 0x%x - pCapabilities: %p\n", dwUserIndex, dwFlags, pCapabilities);
234 | if (!GameUsesXInput) GameUsesXInput = true;
235 | if (dwUserIndex >= GPXI_XUSER_MAX_COUNT || (dwFlags & ~GPXI_FLAG_GAMEPAD) || !pCapabilities) return ERROR_BAD_ARGUMENTS;
236 | if (!pGPData->Gamepads[dwUserIndex].Used || !CheckStarted(dwUserIndex)) return ERROR_DEVICE_NOT_CONNECTED;
237 | pCapabilities->Type = GPXI_DEVTYPE_GAMEPAD;
238 | pCapabilities->SubType = GPXI_DEVSUBTYPE_GAMEPAD;
239 | pCapabilities->Flags = 12;
240 | pCapabilities->Gamepad.wButtons = GPXI_GAMEPAD_ALL_BUTTONS;
241 | pCapabilities->Gamepad.bLeftTrigger = pCapabilities->Gamepad.bRightTrigger = (BYTE)-1;
242 | pCapabilities->Gamepad.sThumbLX = pCapabilities->Gamepad.sThumbLY = pCapabilities->Gamepad.sThumbRX = pCapabilities->Gamepad.sThumbRY = (SHORT)0xffc0;
243 | pCapabilities->Vibration.wLeftMotorSpeed = pCapabilities->Vibration.wRightMotorSpeed = 0xff; //TODO
244 | return ERROR_SUCCESS;
245 | }
246 |
247 | void WINAPI GPXInputEnable(BOOL enable) // not in xinput9_1_0
248 | {
249 | #pragma GPLINKER_DLL_EXPORT_AS_HINT(XInputEnable, 5)
250 | if (!GameUsesXInput) GameUsesXInput = true;
251 | //WriteLog("[GPXInputEnable] UNSUPPORTED - enable: %d\n", enable);
252 | //DEBUGBREAKONCE
253 | //fpXInputEnable(enable);
254 | }
255 |
256 | DWORD WINAPI GPXInputGetDSoundAudioDeviceGuids(DWORD dwUserIndex, GUID* pDSoundRenderGuid, GUID* pDSoundCaptureGuid) //not in xinput1_4
257 | {
258 | #pragma GPLINKER_DLL_EXPORT_AS_HINT(XInputGetDSoundAudioDeviceGuids, 6)
259 | //WriteLog("[GPXInputGetDSoundAudioDeviceGuids] dwUserIndex: %u - pDSoundRenderGuid: %p - pDSoundCaptureGuid: %p\n", dwUserIndex, pDSoundRenderGuid, pDSoundCaptureGuid);
260 | if (dwUserIndex >= GPXI_XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS;
261 | if (!pGPData->Gamepads[dwUserIndex].Used || !CheckStarted(dwUserIndex)) return ERROR_DEVICE_NOT_CONNECTED;
262 | if (pDSoundRenderGuid) memset(pDSoundRenderGuid, 0, sizeof(*pDSoundRenderGuid));
263 | if (pDSoundCaptureGuid) memset(pDSoundCaptureGuid, 0, sizeof(*pDSoundCaptureGuid));
264 | //DEBUGBREAKONCE
265 | return ERROR_SUCCESS;
266 | }
267 |
268 | DWORD WINAPI GPXInputGetBatteryInformation(DWORD dwUserIndex, BYTE devType, GPXINPUT_BATTERY_INFORMATION* pBatteryInformation) // only in xinput1_3 and xinput1_4
269 | {
270 | #pragma GPLINKER_DLL_EXPORT_AS_HINT(XInputGetBatteryInformation, 7)
271 | //WriteLog("[GPXInputGetBatteryInformation] dwUserIndex: %u - devType: %u - pBatteryInformation: %p\n", dwUserIndex, devType, pBatteryInformation);
272 | if (dwUserIndex >= GPXI_XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS;
273 | if (!pGPData->Gamepads[dwUserIndex].Used || !CheckStarted(dwUserIndex)) return ERROR_DEVICE_NOT_CONNECTED;
274 | if (pBatteryInformation)
275 | {
276 | pBatteryInformation->BatteryType = (devType == GPXI_BATTERY_DEVTYPE_GAMEPAD ? GPXI_BATTERY_TYPE_WIRED : GPXI_BATTERY_TYPE_DISCONNECTED);
277 | pBatteryInformation->BatteryLevel = (devType == GPXI_BATTERY_DEVTYPE_GAMEPAD ? GPXI_BATTERY_LEVEL_FULL : GPXI_BATTERY_LEVEL_EMPTY);
278 | }
279 | return ERROR_SUCCESS;
280 | }
281 |
282 | DWORD WINAPI GPXInputGetKeystroke(DWORD dwUserIndex, DWORD dwReserved, GPXINPUT_KEYSTROKE* pKeystroke) // only in xinput1_3 and xinput1_4
283 | {
284 | #pragma GPLINKER_DLL_EXPORT_AS_HINT(XInputGetKeystroke, 8)
285 | //WriteLog("[GPXInputGetKeystroke] UNSUPPORTED - dwUserIndex: %u - dwReserved: 0x%x - pKeystroke: %p\n", dwUserIndex, dwReserved, pKeystroke);
286 | if (dwUserIndex >= GPXI_XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS;
287 | if (!pGPData->Gamepads[dwUserIndex].Used || !CheckStarted(dwUserIndex)) return ERROR_DEVICE_NOT_CONNECTED;
288 | return ERROR_EMPTY; //fpXInputGetKeystroke(dwUserIndex, dwReserved, pKeystroke);
289 | }
290 |
291 | DWORD WINAPI GPXInputGetAudioDeviceIds(DWORD dwUserIndex, LPWSTR pRenderDeviceId, UINT *pRenderCount, LPWSTR pCaptureDeviceId, UINT *pCaptureCount) //only in xinput1_4
292 | {
293 | #pragma GPLINKER_DLL_EXPORT_AS_HINT(XInputGetAudioDeviceIds, 10)
294 | //WriteLog("[GPXInputGetAudioDeviceIds] dwUserIndex: %u - pRenderDeviceId: %p - pRenderCount: %p - pCaptureDeviceId: %p - pCaptureCount: %p\n", dwUserIndex, pRenderDeviceId, pRenderCount, pCaptureDeviceId, pCaptureCount);
295 | if (dwUserIndex >= GPXI_XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS;
296 | if (!pGPData->Gamepads[dwUserIndex].Used || !CheckStarted(dwUserIndex)) return ERROR_DEVICE_NOT_CONNECTED;
297 | if (pRenderCount && *pRenderCount) { *pRenderDeviceId = '\0'; *pRenderCount = 0; }
298 | if (pCaptureCount && *pCaptureCount) { *pCaptureDeviceId = '\0'; *pCaptureCount = 0; }
299 | return ERROR_SUCCESS;
300 | }
301 |
302 | DWORD WINAPI GPXInputGetStateEx(DWORD dwUserIndex, GPXINPUT_STATE* pState) // hidden function Ordinal 100
303 | {
304 | #pragma GPLINKER_DLL_EXPORT_UNNAMED(100)
305 | //WriteLog("[GPXInputGetStateEx] dwUserIndex: %u - pState: %p\n", dwUserIndex, pState);
306 | return GPXInputGetState(dwUserIndex, pState);
307 | }
308 |
309 | DWORD WINAPI GPXInputWaitForGuideButton(DWORD dwUserIndex, DWORD dwFlag, void* pUnknown) // hidden function Ordinal 101
310 | {
311 | #pragma GPLINKER_DLL_EXPORT_UNNAMED(101)
312 | //WriteLog("[GPXInputWaitForGuideButton] UNSUPPORTED - dwUserIndex: %u - dwFlag: 0x%x - pUnknown: %p\n", dwUserIndex, dwFlag, pUnknown);
313 | return ERROR_SUCCESS; // do nothing for now
314 | }
315 |
316 | DWORD WINAPI GPXInputCancelGuideButtonWait(DWORD dwUserIndex) // hidden function Ordinal 102
317 | {
318 | #pragma GPLINKER_DLL_EXPORT_UNNAMED(102)
319 | //WriteLog("[GPXInputCancelGuideButtonWait] UNSUPPORTED - dwUserIndex: %u\n", dwUserIndex);
320 | return ERROR_SUCCESS; // do nothing for now
321 | }
322 |
323 | DWORD WINAPI GPXInputPowerOffController(DWORD dwUserIndex) // hidden function Ordinal 103
324 | {
325 | #pragma GPLINKER_DLL_EXPORT_UNNAMED(103)
326 | //WriteLog("[GPXInputPowerOffController] UNSUPPORTED - dwUserIndex: %u\n", dwUserIndex);
327 | return E_FAIL;
328 | }
329 |
330 | DWORD WINAPI GPXInputGetBaseBusInformation(DWORD dwUserIndex, DWORD dwFlags) // hidden function Ordinal 104
331 | {
332 | #pragma GPLINKER_DLL_EXPORT_UNNAMED(104)
333 | //WriteLog("[GPXInputGetBaseBusInformation] UNSUPPORTED - dwUserIndex: %u - dwFlags: 0x%x\n", dwUserIndex, dwFlags);
334 | return E_FAIL;
335 | }
336 |
337 | DWORD WINAPI GPXInputGetCapabilitiesEx(DWORD a1, DWORD dwUserIndex, DWORD dwFlags, GPXINPUT_CAPABILITIES* pCapabilities) // hidden function Ordinal 108
338 | {
339 | #pragma GPLINKER_DLL_EXPORT_UNNAMED(108)
340 | //WriteLog("[GPXInputGetCapabilitiesEx] a1: %u - dwUserIndex: %u - dwFlags: 0x%x - pCapabilities: %p\n", a1, dwUserIndex, dwFlags, pCapabilities);
341 | return GPXInputGetCapabilities(dwUserIndex, dwFlags, pCapabilities);
342 | }
343 |
344 | static void Hook(bool forceLoad = false)
345 | {
346 | LOGSCOPE("forceLoad: %d", forceLoad);
347 | GPCHECKNORECURSION();
348 | wchar_t buf[512];
349 | wchar_t* base = buf + GetSystemDirectoryW(buf, 480) + 1, *ver = base + 6;
350 | wcscpy(base - 1, L"\\xinput");
351 |
352 | bool redoForceLoad = false;
353 | redo:
354 | static short LoadedNs;
355 | static HMODULE LoadedHms[10];
356 | if (LoadedNs == ((1<<10)-1)) return;
357 | for (unsigned char n = 0; n != 10; n++)
358 | {
359 | if (LoadedNs&(1<Gamepads));
431 | bool queried[GPXI_XUSER_MAX_COUNT] = { false, false, false, false };
432 |
433 | for (unsigned int i = 0, devnum; i != _GPIDX_MAX; i++)
434 | {
435 | unsigned int gpId = gp.IDs[i];
436 | switch (GPIDGetInterface(gpId))
437 | {
438 | case GPIDINTERFACE_XINPUT:
439 | devnum = GPIDGetDevNum(gpId);
440 | if (devnum < GPXI_XUSER_MAX_COUNT)
441 | {
442 | if (!queried[devnum]) statebits[devnum] ^= 1;
443 | GPXINPUT_STATE& state = states[statebits[devnum]][devnum];
444 | if (!queried[devnum])
445 | {
446 | queried[devnum] = true;
447 | //LOGSCOPE("Call GetState %d", devnum);
448 | if (OrgGetState(devnum, &state) != ERROR_SUCCESS) memset(&state, 0, sizeof(state));
449 | }
450 | switch (GPIDGetObjNum(gpId))
451 | {
452 | case 0: gp.Vals[i] = (state.Gamepad.sThumbLY > 0 ? (unsigned short)(state.Gamepad.sThumbLY * 0xFFFF / 0x7FFF) : 0); break;
453 | case 1: gp.Vals[i] = (state.Gamepad.sThumbLY < 0 ? (unsigned short)(state.Gamepad.sThumbLY * -0xFFFF / 0x8000) : 0); break;
454 | case 2: gp.Vals[i] = (state.Gamepad.sThumbLX < 0 ? (unsigned short)(state.Gamepad.sThumbLX * -0xFFFF / 0x8000) : 0); break;
455 | case 3: gp.Vals[i] = (state.Gamepad.sThumbLX > 0 ? (unsigned short)(state.Gamepad.sThumbLX * 0xFFFF / 0x7FFF) : 0); break;
456 | case 4: gp.Vals[i] = (state.Gamepad.sThumbRY > 0 ? (unsigned short)(state.Gamepad.sThumbRY * 0xFFFF / 0x7FFF) : 0); break;
457 | case 5: gp.Vals[i] = (state.Gamepad.sThumbRY < 0 ? (unsigned short)(state.Gamepad.sThumbRY * -0xFFFF / 0x8000) : 0); break;
458 | case 6: gp.Vals[i] = (state.Gamepad.sThumbRX < 0 ? (unsigned short)(state.Gamepad.sThumbRX * -0xFFFF / 0x8000) : 0); break;
459 | case 7: gp.Vals[i] = (state.Gamepad.sThumbRX > 0 ? (unsigned short)(state.Gamepad.sThumbRX * 0xFFFF / 0x7FFF) : 0); break;
460 | case 8: gp.Vals[i] = (unsigned short)(state.Gamepad.bLeftTrigger * 0xFFFF / 0xFF); break;
461 | case 9: gp.Vals[i] = (unsigned short)(state.Gamepad.bRightTrigger * 0xFFFF / 0xFF); break;
462 | case 10: gp.Vals[i] = ((state.Gamepad.wButtons & GPXI_GAMEPAD_DPAD_UP ) ? 0xFFFF : 0); break;
463 | case 11: gp.Vals[i] = ((state.Gamepad.wButtons & GPXI_GAMEPAD_DPAD_DOWN ) ? 0xFFFF : 0); break;
464 | case 12: gp.Vals[i] = ((state.Gamepad.wButtons & GPXI_GAMEPAD_DPAD_LEFT ) ? 0xFFFF : 0); break;
465 | case 13: gp.Vals[i] = ((state.Gamepad.wButtons & GPXI_GAMEPAD_DPAD_RIGHT ) ? 0xFFFF : 0); break;
466 | case 14: gp.Vals[i] = ((state.Gamepad.wButtons & GPXI_GAMEPAD_START ) ? 0xFFFF : 0); break;
467 | case 15: gp.Vals[i] = ((state.Gamepad.wButtons & GPXI_GAMEPAD_BACK ) ? 0xFFFF : 0); break;
468 | case 16: gp.Vals[i] = ((state.Gamepad.wButtons & GPXI_GAMEPAD_LEFT_THUMB ) ? 0xFFFF : 0); break;
469 | case 17: gp.Vals[i] = ((state.Gamepad.wButtons & GPXI_GAMEPAD_RIGHT_THUMB ) ? 0xFFFF : 0); break;
470 | case 18: gp.Vals[i] = ((state.Gamepad.wButtons & GPXI_GAMEPAD_LEFT_SHOULDER ) ? 0xFFFF : 0); break;
471 | case 19: gp.Vals[i] = ((state.Gamepad.wButtons & GPXI_GAMEPAD_RIGHT_SHOULDER) ? 0xFFFF : 0); break;
472 | case 20: gp.Vals[i] = ((state.Gamepad.wButtons & GPXI_GAMEPAD_A ) ? 0xFFFF : 0); break;
473 | case 21: gp.Vals[i] = ((state.Gamepad.wButtons & GPXI_GAMEPAD_B ) ? 0xFFFF : 0); break;
474 | case 22: gp.Vals[i] = ((state.Gamepad.wButtons & GPXI_GAMEPAD_X ) ? 0xFFFF : 0); break;
475 | case 23: gp.Vals[i] = ((state.Gamepad.wButtons & GPXI_GAMEPAD_Y ) ? 0xFFFF : 0); break;
476 | }
477 | }
478 | break;
479 |
480 | case GPIDINTERFACE_CAPTURE_NEXT_KEY:
481 | if (!(CaptureSources & (1 << GPIDINTERFACE_XINPUT))) break;
482 | for (devnum = 0; devnum != GPXI_XUSER_MAX_COUNT; devnum++)
483 | {
484 | if (!queried[devnum]) statebits[devnum] ^= 1;
485 | GPXINPUT_STATE &state = states[statebits[devnum]][devnum], &prev = states[!statebits[devnum]][devnum];
486 | if (!queried[devnum])
487 | {
488 | queried[devnum] = true;
489 | if (OrgGetState(devnum, &state) != ERROR_SUCCESS) memset(&state, 0, sizeof(state));
490 | }
491 | unsigned int o =
492 | ((state.Gamepad.sThumbLY > 0x4000 && prev.Gamepad.sThumbLY <= 0x4000) ? 0 :
493 | ((state.Gamepad.sThumbLY < -0x4000 && prev.Gamepad.sThumbLY >= -0x4000) ? 1 :
494 | ((state.Gamepad.sThumbLX < -0x4000 && prev.Gamepad.sThumbLX >= -0x4000) ? 2 :
495 | ((state.Gamepad.sThumbLX > 0x4000 && prev.Gamepad.sThumbLX <= 0x4000) ? 3 :
496 | ((state.Gamepad.sThumbRY > 0x4000 && prev.Gamepad.sThumbRY <= 0x4000) ? 4 :
497 | ((state.Gamepad.sThumbRY < -0x4000 && prev.Gamepad.sThumbRY >= -0x4000) ? 5 :
498 | ((state.Gamepad.sThumbRX < -0x4000 && prev.Gamepad.sThumbRX >= -0x4000) ? 6 :
499 | ((state.Gamepad.sThumbRX > 0x4000 && prev.Gamepad.sThumbRX <= 0x4000) ? 7 :
500 | ((state.Gamepad.bLeftTrigger > 0x80 && prev.Gamepad.bLeftTrigger <= 0x80) ? 8 :
501 | ((state.Gamepad.bRightTrigger > 0x80 && prev.Gamepad.bRightTrigger <= 0x80) ? 9 :
502 | (((state.Gamepad.wButtons & GPXI_GAMEPAD_DPAD_UP ) && !(prev.Gamepad.wButtons & GPXI_GAMEPAD_DPAD_UP )) ? 10 :
503 | (((state.Gamepad.wButtons & GPXI_GAMEPAD_DPAD_DOWN ) && !(prev.Gamepad.wButtons & GPXI_GAMEPAD_DPAD_DOWN )) ? 11 :
504 | (((state.Gamepad.wButtons & GPXI_GAMEPAD_DPAD_LEFT ) && !(prev.Gamepad.wButtons & GPXI_GAMEPAD_DPAD_LEFT )) ? 12 :
505 | (((state.Gamepad.wButtons & GPXI_GAMEPAD_DPAD_RIGHT ) && !(prev.Gamepad.wButtons & GPXI_GAMEPAD_DPAD_RIGHT )) ? 13 :
506 | (((state.Gamepad.wButtons & GPXI_GAMEPAD_START ) && !(prev.Gamepad.wButtons & GPXI_GAMEPAD_START )) ? 14 :
507 | (((state.Gamepad.wButtons & GPXI_GAMEPAD_BACK ) && !(prev.Gamepad.wButtons & GPXI_GAMEPAD_BACK )) ? 15 :
508 | (((state.Gamepad.wButtons & GPXI_GAMEPAD_LEFT_THUMB ) && !(prev.Gamepad.wButtons & GPXI_GAMEPAD_LEFT_THUMB )) ? 16 :
509 | (((state.Gamepad.wButtons & GPXI_GAMEPAD_RIGHT_THUMB ) && !(prev.Gamepad.wButtons & GPXI_GAMEPAD_RIGHT_THUMB )) ? 17 :
510 | (((state.Gamepad.wButtons & GPXI_GAMEPAD_LEFT_SHOULDER ) && !(prev.Gamepad.wButtons & GPXI_GAMEPAD_LEFT_SHOULDER )) ? 18 :
511 | (((state.Gamepad.wButtons & GPXI_GAMEPAD_RIGHT_SHOULDER) && !(prev.Gamepad.wButtons & GPXI_GAMEPAD_RIGHT_SHOULDER)) ? 19 :
512 | (((state.Gamepad.wButtons & GPXI_GAMEPAD_A ) && !(prev.Gamepad.wButtons & GPXI_GAMEPAD_A )) ? 20 :
513 | (((state.Gamepad.wButtons & GPXI_GAMEPAD_B ) && !(prev.Gamepad.wButtons & GPXI_GAMEPAD_B )) ? 21 :
514 | (((state.Gamepad.wButtons & GPXI_GAMEPAD_X ) && !(prev.Gamepad.wButtons & GPXI_GAMEPAD_X )) ? 22 :
515 | (((state.Gamepad.wButtons & GPXI_GAMEPAD_Y ) && !(prev.Gamepad.wButtons & GPXI_GAMEPAD_Y )) ? 23 :
516 | 0xFF))))))))))))))))))))))));
517 | if (o == 0xFF) continue;
518 | gp.IDs[i] = GPIDMake(GPIDINTERFACE_XINPUT, devnum, o);
519 | break;
520 | }
521 | break;
522 | }
523 | }
524 | }
525 | };
526 |
527 | InputUpdaters.push_back(GPXICallbacks::Update);
528 | }
529 |
530 | }; // namespace GPXInput
531 |
--------------------------------------------------------------------------------
/GamepadPhoenix.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x64
7 | {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF0}
8 | GamepadPhoenix
9 | GamepadPhoenix
10 | 512
11 | GamepadPhoenix.ico
12 | false
13 | false
14 | true
15 | 0
16 | 1.0.0.0
17 | false
18 | false
19 | false
20 | 4
21 | false
22 |
23 |
24 | Exe
25 | build\Debug\
26 | v3.5
27 | DEBUG;TRACE
28 | true
29 |
30 |
31 | WinExe
32 | build\Release
33 | v3.5
34 |
35 |
36 | full
37 | false
38 | true
39 |
40 |
41 | none
42 | true
43 |
44 |
45 | false
46 | AnyCPU
47 | $(OutputPath)
48 | true
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | Form
58 |
59 |
60 | Form
61 |
62 |
63 | Form
64 |
65 |
66 |
67 | ResXFileCodeGenerator
68 | Resources.Designer.cs
69 | Designer
70 |
71 |
72 | True
73 | True
74 | Resources.resx
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 |
110 |
--------------------------------------------------------------------------------
/GamepadPhoenix.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/GamepadPhoenix.ico
--------------------------------------------------------------------------------
/GamepadPhoenix.sln:
--------------------------------------------------------------------------------
1 | Microsoft Visual Studio Solution File, Format Version 12.00
2 | # Visual Studio 2013
3 | VisualStudioVersion = 12.0.0.0
4 | MinimumVisualStudioVersion = 10.0.0.0
5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GamepadPhoenix", "GamepadPhoenix.csproj", "{FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF0}"
6 | ProjectSection(ProjectDependencies) = postProject
7 | {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF1} = {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF1}
8 | {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF2} = {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF2}
9 | EndProjectSection
10 | EndProject
11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GamepadPhoenix32", "GamepadPhoenix32.vcxproj", "{FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF1}"
12 | EndProject
13 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GamepadPhoenix64", "GamepadPhoenix64.vcxproj", "{FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF2}"
14 | EndProject
15 | Global
16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
17 | Debug|Any CPU = Debug|Any CPU
18 | Release|Any CPU = Release|Any CPU
19 | EndGlobalSection
20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
21 | {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22 | {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
23 | {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
24 | {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF0}.Release|Any CPU.Build.0 = Release|Any CPU
25 | {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF1}.Debug|Any CPU.ActiveCfg = Debug|Win32
26 | {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF1}.Debug|Any CPU.Build.0 = Debug|Win32
27 | {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF1}.Release|Any CPU.ActiveCfg = Release|Win32
28 | {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF1}.Release|Any CPU.Build.0 = Release|Win32
29 | {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF2}.Debug|Any CPU.ActiveCfg = Debug|x64
30 | {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF2}.Debug|Any CPU.Build.0 = Debug|x64
31 | {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF2}.Release|Any CPU.ActiveCfg = Release|x64
32 | {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF2}.Release|Any CPU.Build.0 = Release|x64
33 | EndGlobalSection
34 | GlobalSection(SolutionProperties) = preSolution
35 | HideSolutionNode = FALSE
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/GamepadPhoenix32.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 2012
5 | 2013
6 | 2015
7 | 2017
8 | 2019
9 | 2022
10 | 9999
11 |
12 |
13 |
14 | Debug
15 | Win32
16 |
17 |
18 | Release
19 | Win32
20 |
21 |
22 |
23 | GamepadPhoenix32
24 | {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF1}
25 |
26 |
27 |
28 | DynamicLibrary
29 | v110_xp
30 | v120_xp
31 | v140
32 | v141
33 | v142
34 | v143
35 | $(DefaultPlatformToolset)
36 | false
37 | NotSet
38 | true
39 | true
40 |
41 |
42 |
43 |
44 |
45 |
46 | GamepadPhoenix32
47 | $(ProjectDir)\build\$(Configuration)\
48 | $(ProjectDir)\build\$(Configuration)32\
49 | $(IntDir)
50 | $(IntDir)
51 | false
52 | true
53 | false
54 | WindowsLocalDebugger
55 |
56 |
57 |
58 | false
59 | Level3
60 | true
61 | false
62 | false
63 | Fast
64 | false
65 | _HAS_EXCEPTIONS=0;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;WIN32;_WINDOWS;%(PreprocessorDefinitions)
66 | _DEBUG;%(PreprocessorDefinitions)
67 | NDEBUG;%(PreprocessorDefinitions)
68 |
69 |
70 | Disabled
71 | EnableFastChecks
72 | MultiThreadedDebug
73 | ProgramDatabase
74 |
75 |
76 | Full
77 | true
78 | true
79 | MultiThreaded
80 | true
81 | true
82 | Size
83 | true
84 | AnySuitable
85 | false
86 | StreamingSIMDExtensions2
87 | /Gw %(AdditionalOptions)
88 |
89 |
90 | true
91 | Console
92 | false
93 |
94 |
95 | true
96 |
97 |
98 | true
99 | true
100 | UseLinkTimeCodeGeneration
101 | true
102 | false
103 |
104 |
105 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/GamepadPhoenix64.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 2012
5 | 2013
6 | 2015
7 | 2017
8 | 2019
9 | 2022
10 | 9999
11 |
12 |
13 |
14 | Debug
15 | x64
16 |
17 |
18 | Release
19 | x64
20 |
21 |
22 |
23 | GamepadPhoenix64
24 | {FFFFFFFF-FFFF-4FFF-FFFF-FFFFFFFFFFF2}
25 |
26 |
27 |
28 | DynamicLibrary
29 | v110_xp
30 | v120_xp
31 | v140
32 | v141
33 | v142
34 | v143
35 | $(DefaultPlatformToolset)
36 | false
37 | NotSet
38 | true
39 | true
40 |
41 |
42 |
43 |
44 |
45 |
46 | GamepadPhoenix64
47 | $(ProjectDir)\build\$(Configuration)\
48 | $(ProjectDir)\build\$(Configuration)64\
49 | $(IntDir)
50 | $(IntDir)
51 | false
52 | true
53 | false
54 | WindowsLocalDebugger
55 |
56 |
57 |
58 | false
59 | Level3
60 | true
61 | false
62 | false
63 | Fast
64 | false
65 | _HAS_EXCEPTIONS=0;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;WIN32;_WINDOWS;%(PreprocessorDefinitions)
66 | _DEBUG;%(PreprocessorDefinitions)
67 | NDEBUG;%(PreprocessorDefinitions)
68 | WIN64;_WIN64;%(PreprocessorDefinitions)
69 |
70 |
71 | Disabled
72 | EnableFastChecks
73 | MultiThreadedDebug
74 | ProgramDatabase
75 |
76 |
77 | Full
78 | true
79 | true
80 | MultiThreaded
81 | true
82 | true
83 | Size
84 | true
85 | AnySuitable
86 | false
87 | StreamingSIMDExtensions2
88 | /Gw %(AdditionalOptions)
89 |
90 |
91 | true
92 | Console
93 | false
94 |
95 |
96 | true
97 |
98 |
99 | true
100 | true
101 | UseLinkTimeCodeGeneration
102 | true
103 | false
104 |
105 |
106 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 | X64;%(PreprocessorDefinitions)
128 |
129 |
130 |
--------------------------------------------------------------------------------
/GamepadPhoenixDLL.rc:
--------------------------------------------------------------------------------
1 | #include
2 | 1 VERSIONINFO
3 | FILEVERSION 0,9,5,0
4 | PRODUCTVERSION 0,9,5,0
5 | FILEOS VOS_NT_WINDOWS32
6 | FILETYPE VFT_DLL
7 | {
8 | BLOCK "StringFileInfo"
9 | {
10 | BLOCK "040904b0"
11 | {
12 | VALUE "FileDescription", "Gamepad Phoenix"
13 | VALUE "FileVersion", "0.9.5"
14 | VALUE "InternalName", "GamepadPhoenix"
15 | VALUE "LegalCopyright", "(C) 2021-2023 Bernhard Schelling"
16 | #ifdef X64
17 | VALUE "OriginalFilename", "GamepadPhoenix64.dll"
18 | #else
19 | VALUE "OriginalFilename", "GamepadPhoenix32.dll"
20 | #endif
21 | VALUE "ProductName", "Gamepad Phoenix"
22 | VALUE "ProductVersion", "0.9.5"
23 | }
24 | }
25 | BLOCK "VarFileInfo"
26 | {
27 | VALUE "Translation", 0x0000 0x04B0
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | ===========================================================================
624 |
625 | Portions of this software are Copyright (c) 2009-2017 Tsuda Kageyu.
626 | Portions of this software are Copyright (c) 2008-2009, Vyacheslav Patkov.
627 |
628 | MinHook - The Minimalistic API Hooking Library for x64/x86
629 | Copyright (c) 2009-2017 Tsuda Kageyu
630 | All rights reserved.
631 |
632 | Hacker Disassembler Engine 64 C
633 | Copyright (c) 2008-2009 Vyacheslav Patkov
634 | All rights reserved.
635 |
636 | Hacker Disassembler Engine 32 C
637 | Copyright (c) 2008-2009 Vyacheslav Patkov
638 | All rights reserved.
639 |
640 | Redistribution and use in source and binary forms, with or without
641 | modification, are permitted provided that the following conditions
642 | are met:
643 |
644 | 1. Redistributions of source code must retain the above copyright
645 | notice, this list of conditions and the following disclaimer.
646 | 2. Redistributions in binary form must reproduce the above copyright
647 | notice, this list of conditions and the following disclaimer in the
648 | documentation and/or other materials provided with the distribution.
649 |
650 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
651 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
652 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
653 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
654 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
655 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
656 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
657 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
658 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
659 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
660 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
661 |
--------------------------------------------------------------------------------
/PresetsForm.cs:
--------------------------------------------------------------------------------
1 | /* Gamepad Phoenix
2 | * Copyright (c) 2021-2023 Bernhard Schelling
3 | *
4 | * Gamepad Phoenix is free software: you can redistribute it and/or modify it under the terms
5 | * of the GNU General Public License as published by the Free Software Found-
6 | * ation, either version 3 of the License, or (at your option) any later version.
7 | *
8 | * Gamepad Phoenix is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 | * PURPOSE. See the GNU General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU General Public License along with Gamepad Phoenix.
13 | * If not, see .
14 | */
15 |
16 | using System;
17 | using System.Drawing;
18 | using System.Windows.Forms;
19 |
20 | namespace GamepadPhoenix
21 | {
22 | class PresetsForm : Form
23 | {
24 | internal PresetsForm()
25 | {
26 | InitializeComponent();
27 | }
28 |
29 | internal ListBox lstPresets;
30 | internal TextBox txtName;
31 | internal Button btnDelete;
32 | internal Button btnOK;
33 | internal Label lblAutoLoad;
34 |
35 | ///
36 | /// Required designer variable.
37 | ///
38 | private System.ComponentModel.IContainer components = null;
39 |
40 | ///
41 | /// Clean up any resources being used.
42 | ///
43 | /// true if managed resources should be disposed; otherwise, false.
44 | protected override void Dispose(bool disposing)
45 | {
46 | if (disposing && (components != null))
47 | {
48 | components.Dispose();
49 | }
50 | base.Dispose(disposing);
51 | }
52 |
53 | #region Windows Form Designer generated code
54 |
55 | ///
56 | /// Required method for Designer support - do not modify
57 | /// the contents of this method with the code editor.
58 | ///
59 | private void InitializeComponent()
60 | {
61 | System.Windows.Forms.Button btnCancel;
62 | this.btnOK = new System.Windows.Forms.Button();
63 | this.lstPresets = new System.Windows.Forms.ListBox();
64 | this.txtName = new System.Windows.Forms.TextBox();
65 | this.btnDelete = new System.Windows.Forms.Button();
66 | this.lblAutoLoad = new System.Windows.Forms.Label();
67 | btnCancel = new System.Windows.Forms.Button();
68 | this.SuspendLayout();
69 | //
70 | // btnCancel
71 | //
72 | btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
73 | btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
74 | btnCancel.Location = new System.Drawing.Point(181, 304);
75 | btnCancel.Name = "btnCancel";
76 | btnCancel.Size = new System.Drawing.Size(60, 23);
77 | btnCancel.TabIndex = 4;
78 | btnCancel.Text = "Cancel";
79 | btnCancel.UseVisualStyleBackColor = true;
80 | //
81 | // btnOK
82 | //
83 | this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
84 | this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK;
85 | this.btnOK.Location = new System.Drawing.Point(49, 304);
86 | this.btnOK.Name = "btnOK";
87 | this.btnOK.Size = new System.Drawing.Size(60, 23);
88 | this.btnOK.TabIndex = 2;
89 | this.btnOK.Text = "OK";
90 | this.btnOK.UseVisualStyleBackColor = true;
91 | //
92 | // lstPresets
93 | //
94 | this.lstPresets.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
95 | | System.Windows.Forms.AnchorStyles.Left)
96 | | System.Windows.Forms.AnchorStyles.Right)));
97 | this.lstPresets.FormattingEnabled = true;
98 | this.lstPresets.IntegralHeight = false;
99 | this.lstPresets.Location = new System.Drawing.Point(7, 34);
100 | this.lstPresets.Name = "lstPresets";
101 | this.lstPresets.Size = new System.Drawing.Size(234, 237);
102 | this.lstPresets.TabIndex = 1;
103 | //
104 | // txtName
105 | //
106 | this.txtName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
107 | | System.Windows.Forms.AnchorStyles.Right)));
108 | this.txtName.Location = new System.Drawing.Point(7, 277);
109 | this.txtName.Name = "txtName";
110 | this.txtName.Size = new System.Drawing.Size(234, 20);
111 | this.txtName.TabIndex = 0;
112 | //
113 | // btnDelete
114 | //
115 | this.btnDelete.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
116 | this.btnDelete.Location = new System.Drawing.Point(115, 304);
117 | this.btnDelete.Name = "btnDelete";
118 | this.btnDelete.Size = new System.Drawing.Size(60, 23);
119 | this.btnDelete.TabIndex = 3;
120 | this.btnDelete.Text = "Delete";
121 | this.btnDelete.UseVisualStyleBackColor = true;
122 | //
123 | // lblAutoLoad
124 | //
125 | this.lblAutoLoad.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
126 | | System.Windows.Forms.AnchorStyles.Right)));
127 | this.lblAutoLoad.Location = new System.Drawing.Point(24, 3);
128 | this.lblAutoLoad.Name = "lblAutoLoad";
129 | this.lblAutoLoad.Size = new System.Drawing.Size(210, 28);
130 | this.lblAutoLoad.TabIndex = 5;
131 | this.lblAutoLoad.Text = "Press \'L1\' on a device with an existing preset to load it automatically.";
132 | this.lblAutoLoad.TextAlign = System.Drawing.ContentAlignment.TopCenter;
133 | //
134 | // PresetsForm
135 | //
136 | this.AcceptButton = this.btnOK;
137 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
138 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
139 | this.CancelButton = btnCancel;
140 | this.ClientSize = new System.Drawing.Size(249, 334);
141 | this.Controls.Add(this.lstPresets);
142 | this.Controls.Add(this.lblAutoLoad);
143 | this.Controls.Add(this.btnDelete);
144 | this.Controls.Add(this.txtName);
145 | this.Controls.Add(btnCancel);
146 | this.Controls.Add(this.btnOK);
147 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;
148 | this.MaximizeBox = false;
149 | this.MinimizeBox = false;
150 | this.MinimumSize = new System.Drawing.Size(180, 160);
151 | this.Name = "PresetsForm";
152 | this.ShowInTaskbar = false;
153 | this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show;
154 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
155 | this.Text = "Presets";
156 | this.ResumeLayout(false);
157 | this.PerformLayout();
158 |
159 | }
160 |
161 | #endregion
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Gamepad Phoenix
2 |
3 | Gamepad Phoenix is a tool for Windows to play any game (old or new) with any gamepad (old or new).
4 |
5 | ## Screenshot
6 | [
](https://img.itch.zone/aW1hZ2UvMTA0MTc1OS8xMTczMTgxNy5wbmc=/original/a0WDD8.png)|[
](https://img.itch.zone/aW1hZ2UvMTA0MTc1OS82MDkwODkxLnBuZw==/original/PSmpx%2F.png)|[
](https://img.itch.zone/aW1hZ2UvMTA0MTc1OS8xMTc0MTQzNi5wbmc=/original/3sADGM.png)
7 | :---:|:---:|:---:
8 | Map Controller|Setup Games|More
9 |
10 | ## Features
11 | - Create a unified button and axis mapping for up to 4 controllers
12 | - Supports XInput, DirectInput and Wii controllers
13 | - Manage and launch games through the tool
14 | - Emulates XInput, DirectInput (any version) and WinMM APIs
15 | - Custom deadzone settings for each emulated analog stick
16 | - Automatic detection of API, no configuration/file copying needed
17 | - Supports both DRM free games and games with launchers/stores
18 | - Create controller presets, load one by pressing a single button
19 | - Keyboard and mouse inputs can be mapped to controllers
20 | - Easy reordering of controllers
21 | - Tool can be navigated by gamepad
22 | - Borderless fullscreen for any game
23 |
24 | ## Download
25 | You can download the latest version of Gamepad Phoenix for free (donations welcome!) on [itch.io](https://schelling.itch.io/gamepad-phoenix).
26 | Just extract the ZIP file and then run GamepadPhoenix.exe.
27 |
28 | ## Donations
29 | Tips and donations are welcome, either through the [itch.io page](https://schelling.itch.io/gamepad-phoenix)
30 | or the Sponsor button at the top of the [GitHub repository](https://github.com/schellingb/GamepadPhoenix).
31 |
32 | Thanks for your consideration!
33 |
34 | ## Usage
35 |
36 | ### Map Controllers
37 | To map an entire emulated controller, just click the "Assign All Buttons/Axes" button in the top-right of the window and press the buttons and stick directions in order as prompted.
38 | If a button or axis is not available on the real controller, you can click the "Clear" button to skip assignment.
39 | Individual parts of the gamepad can be remapped by clicking them either on the graphic in the center or by clicking a specific part in the lists on the sides of the window.
40 |
41 | - To avoid input from a XInput gamepad getting misrecognized, you can set the drop-down selection to "Assign only from XInput".
42 | - To clear all mappings of a controller, right click the controller tab and select "Clear All Assignments".
43 | - To add another emulated gamepad, click on the '+' tab between the last controller tab and the "Launch Game" tab.
44 | - Up to 4 emulated controllers can be defined.
45 |
46 | ### Manage Presets
47 | You can load and save controller mapping presets using the two buttons in the top-left of the window.
48 |
49 | While loading a preset, if you press L1 on a controller and a matching preset exists, it will be loaded automatically.
50 |
51 | ### Setup Games
52 | On the "Launch Game" tab, press "New" to create a new game launch configuration.
53 | Next, click "Select Game EXE" to browse for the executable of the game to launch through Gamepad Phoenix.
54 | Selecting the game .EXE will automatically fill out the fields 'Name', 'Target' and 'Start In'.
55 | You can modify them afterwards as needed and define optional launch command line arguments as well.
56 |
57 | Don't forget to click the "Save" button to store it in the games list.
58 |
59 | The games list can be re-ordered by dragging items with the mouse.
60 |
61 | #### Launch Game Options
62 | The following per-game options can be toggled by clicking on the Options box in the game details.
63 |
64 | - __Map D-Pad to Left Stick__
65 | Will make the D-Pad on all emulated controllers also control the left analog stick.
66 |
67 | - __Swap A and B Buttons__
68 | Switch the A and B button on all emulated controllers.
69 |
70 | - __Swap L1/R1 and L2/R2__
71 | Switch the upper shoulder/bumper buttons with the lower triggers.
72 |
73 | - __DirectInput: Map Triggers to Buttons instead of Analog Axis__
74 | Modifies the analog triggers to be regular digital buttons (required for some older games)
75 |
76 | - __DirectInput: Map D-Pad to Buttons instead of Point of View Hat__
77 | Modifies the D-Pad to be 4 separate digital instead of a POV hat (required for some older games)
78 |
79 | - __Use Indirect Loading (Prepare redirector DLL to allow external stores/launchers)__
80 | See section on [indirect loading](#indirect-loading) below.
81 |
82 | - __Disable XInput (return no connected controllers)__
83 | When set, the game will find no connected XInput controllers and will have to use other interfaces (most commonly DirectInput) to access the gamepads.
84 |
85 | - __Disable DirectInput (return no joystick or only fake XInput gamepads)__
86 | When set, Gamepad Phoenix will not return DirectInput specific gamepads (with separate axis for the two triggers) but instead return only controllers when XInput is also used.
87 |
88 | - __Disable MMSys (return no joystick or only fake XInput gamepads)__
89 | When set, Gamepad Phoenix will not return MMSys specific gamepads (with separate axis for the two triggers) but instead return only controllers when XInput is also used.
90 |
91 | - __Force game window to borderless fullscreen__
92 | Will resize the game window to fill the entire screen. Useful for games that don't support this natively.
93 |
94 | #### Indirect Loading
95 | The game option 'Use Indirect Loading' can be required for some games that refuse to run directly by launching the .EXE file.
96 | Things like launchers, updaters or game stores can make the direct loading method not work.
97 | Check the log view below the game details for how a game behaves when launched and try this option when the gamepad emulation does not work.
98 |
99 | When enabled, two additional buttons "Prepare" and "Restore" will appear next to the "Launch" button.
100 | Use the "Prepare" button to analyze the game and set up an appropriate redirector DLL automatically.
101 |
102 | After preparing, the game can be launched through the tool or directly through its launcher or store.
103 |
104 | ### Deadzone Settings
105 |
106 |
107 | The left and right analog sticks of each emulated gamepad can be tweaked by clicking the "Set Deadzones" button below the gamepad image.
108 | The settings window will show both raw inputs coming in and corrected stick movement to be sent to the game. For each analog stick there are 6 settings available:
109 |
110 | - Deadzone: Set area around the center of how much stick input will be ignored
111 | - Max Limit: Define area around the outer border of how much stick input will be ignored
112 | - Anti-Deadzone: Define area around the center of output of where stick movement will start
113 | - Sensitivity: Increasing sensitivity will make large stick movements appear smaller, decreasing it does the inverse
114 | - Shift Horizontal: Shift the center stick position horizontally
115 | - Shift Vertical: Shift the center stick position vertically
116 |
117 | ### Connect Wii Controllers
118 | Gamepad Phoenix supports communication with Bluetooth powered Wii Remote Controllers and using them just like regular Windows controllers.
119 |
120 | Buttons and axes from the main controller and extensions can be mapped. Motion controls are not supported.
121 | Supported extensions are Classic Controller (including Pro and NES/SNES Classic Mini variants), Nunchuk and the WiiU Pro Controller.
122 |
123 | To connect to a controller, make sure the PC has a Bluetooth module installed (can be either built-in or a USB dongle).
124 | Then switch to the "More" tab in Gamepad Phoenix and click the "Connect New Controller" in the "Wii Controllers" section.
125 |
126 | Next, press the red SYNC button behind the battery cover of the Wii Remote Controller. After a few seconds, the status info text should
127 | switch from "Searching For Wii Controller" to "Registering HID Service" and finally to "Found New Controller".
128 |
129 | Once the controller has been connected, the LEDs pattern can be set with the four checkboxes in the Wii Controller list.
130 | The buttons and axes can be mapped to any of the gamepads in the "Controller" tabs like a regular controller.
131 | Make sure to check the [deadzone settings](#deadzone-settings) to confirm or adjust calibration issues and offsets.
132 |
133 | The controller will not be paired to the PC and needs to be connected again once it loses power or the sync button gets pressed.
134 |
135 | ### Mouse/Keyboard Inputs
136 | Besides physical gamepads, mouse and keyboard inputs can also be freely mapped to each emulated gamepad button and axis.
137 | To bind mouse movement strongly move the mouse into a direction while reading inputs. To bind a mouse button hold it for a short duration.
138 | To avoid mouse or keyboard inputs getting assigned switch "Assign from any source" to "Assign only from Gamepads".
139 |
140 | When using mouse movement as an analog stick, use [deadzone settings](#deadzone-settings) to customize the amount of movement needed to control the stick.
141 | It is suggested to use a high setting for "Max Limit" and a low setting for "Sensitivity" to reduce the movement required to reach maximum stick tilt.
142 | For mouse inputs the "Sensitivity" deadzone setting controls how slow/fast the stick centers itself back when stopping mouse movement.
143 |
144 | ### Command Line Option
145 | To directly launch a configured game you can pass the game name to the program:
146 | ```sh
147 | GamepadPhoenix.exe "My Game"
148 | ```
149 | This will start Gamepad Phoenix in minimized state and launch the game configured with the name "My Game".
150 |
151 | ### Gamepad Controls
152 | The tool itself can be navigated with the mapped controllers.
153 |
154 | - While holding select/back, L and R switch tabs
155 | - While holding select/back, A/B/X/Y jump to the "Launch Game" tab
156 | - While holding select/back, Left/Right swaps the gamepad order
157 | - On the "Launch Game" tab, Up/Down selects the previous/next game
158 | - On the "Launch Game" tab, Left/Right scrolls the game list by 10
159 | - On the "Launch Game" tab, Start/A/B/X/Y launches the selected game
160 |
161 | ## License
162 | Gamepad Phoenix is available under the [GPL-3.0 license](https://choosealicense.com/licenses/gpl-3.0/).
163 | If you are interested in parts of this program under a more permissive or public domain license, feel free to contact me.
164 |
--------------------------------------------------------------------------------
/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 GamepadPhoenix {
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", "4.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("GamepadPhoenix.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 | /// Looks up a localized resource of type System.Drawing.Bitmap.
65 | ///
66 | internal static System.Drawing.Bitmap A {
67 | get {
68 | object obj = ResourceManager.GetObject("A", resourceCulture);
69 | return ((System.Drawing.Bitmap)(obj));
70 | }
71 | }
72 |
73 | ///
74 | /// Looks up a localized resource of type System.Drawing.Bitmap.
75 | ///
76 | internal static System.Drawing.Bitmap B {
77 | get {
78 | object obj = ResourceManager.GetObject("B", resourceCulture);
79 | return ((System.Drawing.Bitmap)(obj));
80 | }
81 | }
82 |
83 | ///
84 | /// Looks up a localized resource of type System.Drawing.Bitmap.
85 | ///
86 | internal static System.Drawing.Bitmap BG {
87 | get {
88 | object obj = ResourceManager.GetObject("BG", resourceCulture);
89 | return ((System.Drawing.Bitmap)(obj));
90 | }
91 | }
92 |
93 | ///
94 | /// Looks up a localized resource of type System.Drawing.Bitmap.
95 | ///
96 | internal static System.Drawing.Bitmap Circle {
97 | get {
98 | object obj = ResourceManager.GetObject("Circle", resourceCulture);
99 | return ((System.Drawing.Bitmap)(obj));
100 | }
101 | }
102 |
103 | ///
104 | /// Looks up a localized resource of type System.Drawing.Bitmap.
105 | ///
106 | internal static System.Drawing.Bitmap DPAD {
107 | get {
108 | object obj = ResourceManager.GetObject("DPAD", resourceCulture);
109 | return ((System.Drawing.Bitmap)(obj));
110 | }
111 | }
112 |
113 | ///
114 | /// Looks up a localized resource of type System.Drawing.Bitmap.
115 | ///
116 | internal static System.Drawing.Bitmap DPADBlack {
117 | get {
118 | object obj = ResourceManager.GetObject("DPADBlack", resourceCulture);
119 | return ((System.Drawing.Bitmap)(obj));
120 | }
121 | }
122 |
123 | ///
124 | /// Looks up a localized resource of type System.Drawing.Bitmap.
125 | ///
126 | internal static System.Drawing.Bitmap DPADDown {
127 | get {
128 | object obj = ResourceManager.GetObject("DPADDown", resourceCulture);
129 | return ((System.Drawing.Bitmap)(obj));
130 | }
131 | }
132 |
133 | ///
134 | /// Looks up a localized resource of type System.Drawing.Bitmap.
135 | ///
136 | internal static System.Drawing.Bitmap DPADLeft {
137 | get {
138 | object obj = ResourceManager.GetObject("DPADLeft", resourceCulture);
139 | return ((System.Drawing.Bitmap)(obj));
140 | }
141 | }
142 |
143 | ///
144 | /// Looks up a localized resource of type System.Drawing.Bitmap.
145 | ///
146 | internal static System.Drawing.Bitmap DPADRight {
147 | get {
148 | object obj = ResourceManager.GetObject("DPADRight", resourceCulture);
149 | return ((System.Drawing.Bitmap)(obj));
150 | }
151 | }
152 |
153 | ///
154 | /// Looks up a localized resource of type System.Drawing.Bitmap.
155 | ///
156 | internal static System.Drawing.Bitmap DPADUp {
157 | get {
158 | object obj = ResourceManager.GetObject("DPADUp", resourceCulture);
159 | return ((System.Drawing.Bitmap)(obj));
160 | }
161 | }
162 |
163 | ///
164 | /// Looks up a localized resource of type System.Drawing.Bitmap.
165 | ///
166 | internal static System.Drawing.Bitmap Glow {
167 | get {
168 | object obj = ResourceManager.GetObject("Glow", resourceCulture);
169 | return ((System.Drawing.Bitmap)(obj));
170 | }
171 | }
172 |
173 | ///
174 | /// Looks up a localized resource of type System.Drawing.Bitmap.
175 | ///
176 | internal static System.Drawing.Bitmap GlowAssign {
177 | get {
178 | object obj = ResourceManager.GetObject("GlowAssign", resourceCulture);
179 | return ((System.Drawing.Bitmap)(obj));
180 | }
181 | }
182 |
183 | ///
184 | /// Looks up a localized resource of type System.Drawing.Bitmap.
185 | ///
186 | internal static System.Drawing.Bitmap GlowHover {
187 | get {
188 | object obj = ResourceManager.GetObject("GlowHover", resourceCulture);
189 | return ((System.Drawing.Bitmap)(obj));
190 | }
191 | }
192 |
193 | ///
194 | /// Looks up a localized resource of type System.Drawing.Bitmap.
195 | ///
196 | internal static System.Drawing.Bitmap GlowPress {
197 | get {
198 | object obj = ResourceManager.GetObject("GlowPress", resourceCulture);
199 | return ((System.Drawing.Bitmap)(obj));
200 | }
201 | }
202 |
203 | ///
204 | /// Looks up a localized resource of type System.Drawing.Bitmap.
205 | ///
206 | internal static System.Drawing.Bitmap L1 {
207 | get {
208 | object obj = ResourceManager.GetObject("L1", resourceCulture);
209 | return ((System.Drawing.Bitmap)(obj));
210 | }
211 | }
212 |
213 | ///
214 | /// Looks up a localized resource of type System.Drawing.Bitmap.
215 | ///
216 | internal static System.Drawing.Bitmap L2 {
217 | get {
218 | object obj = ResourceManager.GetObject("L2", resourceCulture);
219 | return ((System.Drawing.Bitmap)(obj));
220 | }
221 | }
222 |
223 | ///
224 | /// Looks up a localized resource of type System.Drawing.Bitmap.
225 | ///
226 | internal static System.Drawing.Bitmap LEDOff {
227 | get {
228 | object obj = ResourceManager.GetObject("LEDOff", resourceCulture);
229 | return ((System.Drawing.Bitmap)(obj));
230 | }
231 | }
232 |
233 | ///
234 | /// Looks up a localized resource of type System.Drawing.Bitmap.
235 | ///
236 | internal static System.Drawing.Bitmap LEDOn {
237 | get {
238 | object obj = ResourceManager.GetObject("LEDOn", resourceCulture);
239 | return ((System.Drawing.Bitmap)(obj));
240 | }
241 | }
242 |
243 | ///
244 | /// Looks up a localized resource of type System.Byte[].
245 | ///
246 | internal static byte[] LICENSE {
247 | get {
248 | object obj = ResourceManager.GetObject("LICENSE", resourceCulture);
249 | return ((byte[])(obj));
250 | }
251 | }
252 |
253 | ///
254 | /// Looks up a localized resource of type System.Drawing.Bitmap.
255 | ///
256 | internal static System.Drawing.Bitmap R1 {
257 | get {
258 | object obj = ResourceManager.GetObject("R1", resourceCulture);
259 | return ((System.Drawing.Bitmap)(obj));
260 | }
261 | }
262 |
263 | ///
264 | /// Looks up a localized resource of type System.Drawing.Bitmap.
265 | ///
266 | internal static System.Drawing.Bitmap R2 {
267 | get {
268 | object obj = ResourceManager.GetObject("R2", resourceCulture);
269 | return ((System.Drawing.Bitmap)(obj));
270 | }
271 | }
272 |
273 | ///
274 | /// Looks up a localized resource of type System.Drawing.Bitmap.
275 | ///
276 | internal static System.Drawing.Bitmap Select {
277 | get {
278 | object obj = ResourceManager.GetObject("Select", resourceCulture);
279 | return ((System.Drawing.Bitmap)(obj));
280 | }
281 | }
282 |
283 | ///
284 | /// Looks up a localized resource of type System.Drawing.Bitmap.
285 | ///
286 | internal static System.Drawing.Bitmap Start {
287 | get {
288 | object obj = ResourceManager.GetObject("Start", resourceCulture);
289 | return ((System.Drawing.Bitmap)(obj));
290 | }
291 | }
292 |
293 | ///
294 | /// Looks up a localized resource of type System.Drawing.Bitmap.
295 | ///
296 | internal static System.Drawing.Bitmap Stick {
297 | get {
298 | object obj = ResourceManager.GetObject("Stick", resourceCulture);
299 | return ((System.Drawing.Bitmap)(obj));
300 | }
301 | }
302 |
303 | ///
304 | /// Looks up a localized resource of type System.Drawing.Bitmap.
305 | ///
306 | internal static System.Drawing.Bitmap StickDown {
307 | get {
308 | object obj = ResourceManager.GetObject("StickDown", resourceCulture);
309 | return ((System.Drawing.Bitmap)(obj));
310 | }
311 | }
312 |
313 | ///
314 | /// Looks up a localized resource of type System.Drawing.Bitmap.
315 | ///
316 | internal static System.Drawing.Bitmap StickLeft {
317 | get {
318 | object obj = ResourceManager.GetObject("StickLeft", resourceCulture);
319 | return ((System.Drawing.Bitmap)(obj));
320 | }
321 | }
322 |
323 | ///
324 | /// Looks up a localized resource of type System.Drawing.Bitmap.
325 | ///
326 | internal static System.Drawing.Bitmap StickPress {
327 | get {
328 | object obj = ResourceManager.GetObject("StickPress", resourceCulture);
329 | return ((System.Drawing.Bitmap)(obj));
330 | }
331 | }
332 |
333 | ///
334 | /// Looks up a localized resource of type System.Drawing.Bitmap.
335 | ///
336 | internal static System.Drawing.Bitmap StickRight {
337 | get {
338 | object obj = ResourceManager.GetObject("StickRight", resourceCulture);
339 | return ((System.Drawing.Bitmap)(obj));
340 | }
341 | }
342 |
343 | ///
344 | /// Looks up a localized resource of type System.Drawing.Bitmap.
345 | ///
346 | internal static System.Drawing.Bitmap StickUp {
347 | get {
348 | object obj = ResourceManager.GetObject("StickUp", resourceCulture);
349 | return ((System.Drawing.Bitmap)(obj));
350 | }
351 | }
352 |
353 | ///
354 | /// Looks up a localized resource of type System.Drawing.Bitmap.
355 | ///
356 | internal static System.Drawing.Bitmap X {
357 | get {
358 | object obj = ResourceManager.GetObject("X", resourceCulture);
359 | return ((System.Drawing.Bitmap)(obj));
360 | }
361 | }
362 |
363 | ///
364 | /// Looks up a localized resource of type System.Drawing.Bitmap.
365 | ///
366 | internal static System.Drawing.Bitmap Y {
367 | get {
368 | object obj = ResourceManager.GetObject("Y", resourceCulture);
369 | return ((System.Drawing.Bitmap)(obj));
370 | }
371 | }
372 | }
373 | }
374 |
--------------------------------------------------------------------------------
/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 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 |
122 | gfx\A.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
123 |
124 |
125 | gfx\B.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
126 |
127 |
128 | gfx\BG.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
129 |
130 |
131 | gfx\Circle.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
132 |
133 |
134 | gfx\DPAD.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
135 |
136 |
137 | gfx\DPAD-Black.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
138 |
139 |
140 | gfx\DPADDown.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
141 |
142 |
143 | gfx\DPADLeft.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
144 |
145 |
146 | gfx\DPADRight.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
147 |
148 |
149 | gfx\DPADUp.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
150 |
151 |
152 | gfx\Glow.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
153 |
154 |
155 | gfx\GlowAssign.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
156 |
157 |
158 | gfx\GlowHover.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
159 |
160 |
161 | gfx\GlowPress.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
162 |
163 |
164 | gfx\L1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
165 |
166 |
167 | gfx\L2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
168 |
169 |
170 | gfx\LEDOff.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
171 |
172 |
173 | gfx\LEDOn.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
174 |
175 |
176 | gfx\LICENSE;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
177 |
178 |
179 | gfx\R1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
180 |
181 |
182 | gfx\R2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
183 |
184 |
185 | gfx\Select.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
186 |
187 |
188 | gfx\Start.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
189 |
190 |
191 | gfx\Stick.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
192 |
193 |
194 | gfx\StickDown.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
195 |
196 |
197 | gfx\StickLeft.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
198 |
199 |
200 | gfx\StickPress.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
201 |
202 |
203 | gfx\StickRight.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
204 |
205 |
206 | gfx\StickUp.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
207 |
208 |
209 | gfx\X.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
210 |
211 |
212 | gfx\Y.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
213 |
214 |
--------------------------------------------------------------------------------
/app.config:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gfx/A.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/A.png
--------------------------------------------------------------------------------
/gfx/B.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/B.png
--------------------------------------------------------------------------------
/gfx/BG.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/BG.png
--------------------------------------------------------------------------------
/gfx/Circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/Circle.png
--------------------------------------------------------------------------------
/gfx/DPAD-Black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/DPAD-Black.png
--------------------------------------------------------------------------------
/gfx/DPAD.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/DPAD.png
--------------------------------------------------------------------------------
/gfx/DPADDown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/DPADDown.png
--------------------------------------------------------------------------------
/gfx/DPADLeft.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/DPADLeft.png
--------------------------------------------------------------------------------
/gfx/DPADRight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/DPADRight.png
--------------------------------------------------------------------------------
/gfx/DPADUp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/DPADUp.png
--------------------------------------------------------------------------------
/gfx/Glow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/Glow.png
--------------------------------------------------------------------------------
/gfx/GlowAssign.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/GlowAssign.png
--------------------------------------------------------------------------------
/gfx/GlowHover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/GlowHover.png
--------------------------------------------------------------------------------
/gfx/GlowPress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/GlowPress.png
--------------------------------------------------------------------------------
/gfx/L1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/L1.png
--------------------------------------------------------------------------------
/gfx/L2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/L2.png
--------------------------------------------------------------------------------
/gfx/LEDOff.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/LEDOff.png
--------------------------------------------------------------------------------
/gfx/LEDOn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/LEDOn.png
--------------------------------------------------------------------------------
/gfx/LICENSE:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/LICENSE
--------------------------------------------------------------------------------
/gfx/R1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/R1.png
--------------------------------------------------------------------------------
/gfx/R2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/R2.png
--------------------------------------------------------------------------------
/gfx/Select.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/Select.png
--------------------------------------------------------------------------------
/gfx/Start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/Start.png
--------------------------------------------------------------------------------
/gfx/Stick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/Stick.png
--------------------------------------------------------------------------------
/gfx/StickDown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/StickDown.png
--------------------------------------------------------------------------------
/gfx/StickLeft.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/StickLeft.png
--------------------------------------------------------------------------------
/gfx/StickPress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/StickPress.png
--------------------------------------------------------------------------------
/gfx/StickRight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/StickRight.png
--------------------------------------------------------------------------------
/gfx/StickUp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/StickUp.png
--------------------------------------------------------------------------------
/gfx/X.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/X.png
--------------------------------------------------------------------------------
/gfx/Y.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/gfx/Y.png
--------------------------------------------------------------------------------
/minhook.inl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/GamepadPhoenix/55aabc298c1ff6711922683f103c685c6fb947c0/minhook.inl
--------------------------------------------------------------------------------