├── .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 --------------------------------------------------------------------------------