1 /** 2 Grimoire 3 Copyright (c) 2017 Enalye 4 5 This software is provided 'as-is', without any express or implied warranty. 6 In no event will the authors be held liable for any damages arising 7 from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute 11 it freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; 14 you must not claim that you wrote the original software. 15 If you use this software in a product, an acknowledgment 16 in the product documentation would be appreciated but 17 is not required. 18 19 2. Altered source versions must be plainly marked as such, 20 and must not be misrepresented as being the original software. 21 22 3. This notice may not be removed or altered from any source distribution. 23 */ 24 25 module common.controller; 26 27 import derelict.sdl2.sdl; 28 import core.all; 29 import common.resource; 30 31 import std..string; 32 import std.file: exists; 33 import std.stdio: writeln, printf; 34 import std.path; 35 36 private struct Controller { 37 SDL_GameController* sdlController; 38 SDL_Joystick* sdlJoystick; 39 int index, joystickId; 40 } 41 42 private { 43 Controller[] _controllers; 44 45 Timer[6] _analogTimers, _analogTimeoutTimers; 46 47 Vec2f _left = Vec2f.zero, _right = Vec2f.zero; 48 49 bool _buttonA, _buttonB, _buttonX, _buttonY, 50 _buttonSelect, _buttonMode, _buttonStart, 51 _buttonL1, _buttonR1, _buttonL2, _buttonR2, _buttonL3, _buttonR3, 52 _buttonLeft, _buttonRight, _buttonUp, _buttonDown; 53 54 bool _singleButtonA, _singleButtonB, _singleButtonX, _singleButtonY, 55 _singleButtonSelect, _singleButtonMode, _singleButtonStart, 56 _singleButtonL1, _singleButtonR1, _singleButtonL2, _singleButtonR2, _singleButtonL3, _singleButtonR3, 57 _singleButtonLeft, _singleButtonRight, _singleButtonUp, _singleButtonDown; 58 } 59 60 ///Open all the connected controllers 61 void initializeControllers() { 62 const(char)[] dbPath = buildPath(getResourceFolder(), "gamecontrollerdb.txt"); 63 if(!exists(dbPath)) { 64 writeln("Could not find \'gamecontrollerdb.txt\'."); 65 return; 66 } 67 if(-1 == SDL_GameControllerAddMappingsFromFile(toStringz(dbPath))) { 68 writeln("Could not open \'gamecontrollerdb.txt\'."); 69 return; 70 } 71 foreach(index; 0.. SDL_NumJoysticks()) 72 addController(index); 73 SDL_GameControllerEventState(SDL_ENABLE); 74 } 75 76 ///Close all the connected controllers 77 void destroyControllers() { 78 foreach(ref controller; _controllers) { 79 SDL_GameControllerClose(controller.sdlController); 80 } 81 } 82 83 ///Update the state of the controllers 84 void updateControllers(float deltaTime) { 85 foreach(axisIndex; 0.. 4) { 86 _analogTimers[axisIndex].update(deltaTime); 87 _analogTimeoutTimers[axisIndex].update(deltaTime); 88 } 89 } 90 91 ///Attempt to connect a new controller 92 void addController(int index) { 93 writeln("Detected device at index ", index, "."); 94 95 auto c = SDL_JoystickNameForIndex(index); 96 auto d = fromStringz(c); 97 writeln("Device name: ", d); 98 99 if(!SDL_IsGameController(index)) { 100 writeln("The device is not recognised as a game controller."); 101 auto stick = SDL_JoystickOpen(index); 102 auto guid = SDL_JoystickGetGUID(stick); 103 writeln("The device guid is: "); 104 foreach(i; 0.. 16) 105 printf("%02x", guid.data[i]); 106 writeln(""); 107 return; 108 } 109 writeln("The device has been detected as a game controller."); 110 foreach(ref controller; _controllers) { 111 if(controller.index == index) { 112 writeln("The controller is already open, aborted."); 113 return; 114 } 115 } 116 117 auto sdlController = SDL_GameControllerOpen(index); 118 if(!sdlController) { 119 writeln("Could not connect the game controller."); 120 return; 121 } 122 123 Controller controller; 124 controller.sdlController = sdlController; 125 controller.index = index; 126 controller.sdlJoystick = SDL_GameControllerGetJoystick(controller.sdlController); 127 controller.joystickId = SDL_JoystickInstanceID(controller.sdlJoystick); 128 _controllers ~= controller; 129 130 writeln("The game controller is now connected."); 131 } 132 133 ///Remove a connected controller 134 void removeController(int joystickId) { 135 writeln("Controller disconnected: ", joystickId); 136 137 int index; 138 bool isControllerPresent; 139 foreach(ref controller; _controllers) { 140 if(controller.joystickId == joystickId) { 141 isControllerPresent = true; 142 break; 143 } 144 index ++; 145 } 146 147 if(!isControllerPresent) 148 return; 149 150 SDL_GameControllerClose(_controllers[index].sdlController); 151 152 //Remove from list 153 if(index + 1 == _controllers.length) 154 _controllers.length --; 155 else if(index == 0) 156 _controllers = _controllers[1.. $]; 157 else 158 _controllers = _controllers[0.. index] ~ _controllers[(index + 1) .. $]; 159 } 160 161 ///Called upon remapping 162 void remapController(int joystickId) { 163 writeln("Controller remapped: ", joystickId); 164 } 165 166 ///Change the value of a controller axis. 167 void setControllerAxis(SDL_GameControllerAxis axis, short value) { 168 auto v = rlerp(-32_768, 32_767, cast(float)value) * 2f - 1f; 169 switch(axis) { 170 case SDL_CONTROLLER_AXIS_LEFTX: 171 _left.x = v; 172 break; 173 case SDL_CONTROLLER_AXIS_LEFTY: 174 _left.y = v; 175 break; 176 case SDL_CONTROLLER_AXIS_RIGHTX: 177 _right.x = v; 178 break; 179 case SDL_CONTROLLER_AXIS_RIGHTY: 180 _right.y = v; 181 break; 182 case SDL_CONTROLLER_AXIS_TRIGGERLEFT: 183 _buttonL2 = v > .1f; 184 break; 185 case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: 186 _buttonR2 = v > .1f; 187 break; 188 default: 189 break; 190 } 191 } 192 193 ///Handle the timing of the axis 194 private bool updateAnalogTimer(int axisIndex, float x, float y) { 195 if(axisIndex == -1) 196 return false; 197 198 enum deadzone = .5f; 199 if((x < deadzone && x > -deadzone) && (y < deadzone && y > -deadzone)) { 200 _analogTimeoutTimers[axisIndex].stop(); 201 return false; 202 } 203 else { 204 if(_analogTimers[axisIndex].isRunning) 205 return false; 206 _analogTimers[axisIndex].start(_analogTimeoutTimers[axisIndex].isRunning ? .15f : .35f); 207 _analogTimeoutTimers[axisIndex].start(5f); 208 } 209 return true; 210 } 211 212 ///Change the value of a controller button. 213 void setControllerButton(SDL_GameControllerButton button, bool state) { 214 switch(button) { 215 case SDL_CONTROLLER_BUTTON_A: 216 _buttonA = state; 217 _singleButtonA = state; 218 break; 219 case SDL_CONTROLLER_BUTTON_B: 220 _buttonB = state; 221 _singleButtonB = state; 222 break; 223 case SDL_CONTROLLER_BUTTON_X: 224 _buttonX = state; 225 _singleButtonX = state; 226 break; 227 case SDL_CONTROLLER_BUTTON_Y: 228 _buttonY = state; 229 _singleButtonY = state; 230 break; 231 case SDL_CONTROLLER_BUTTON_BACK: 232 _buttonSelect = state; 233 _singleButtonSelect = state; 234 break; 235 case SDL_CONTROLLER_BUTTON_GUIDE: 236 _buttonMode = state; 237 _singleButtonMode = state; 238 break; 239 case SDL_CONTROLLER_BUTTON_START: 240 _buttonStart = state; 241 _singleButtonStart = state; 242 break; 243 case SDL_CONTROLLER_BUTTON_LEFTSTICK: 244 _buttonL3 = state; 245 _singleButtonL3 = state; 246 break; 247 case SDL_CONTROLLER_BUTTON_RIGHTSTICK: 248 _buttonR3 = state; 249 _singleButtonR3 = state; 250 break; 251 case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: 252 _buttonL1 = state; 253 _singleButtonL1 = state; 254 break; 255 case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: 256 _buttonR1 = state; 257 _singleButtonR1 = state; 258 break; 259 case SDL_CONTROLLER_BUTTON_DPAD_UP: 260 _buttonUp = state; 261 _singleButtonUp = state; 262 break; 263 case SDL_CONTROLLER_BUTTON_DPAD_DOWN: 264 _buttonDown = state; 265 _singleButtonDown = state; 266 break; 267 case SDL_CONTROLLER_BUTTON_DPAD_LEFT: 268 _buttonLeft = state; 269 _singleButtonLeft = state; 270 break; 271 case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: 272 _buttonRight = state; 273 _singleButtonRight = state; 274 break; 275 default: 276 break; 277 } 278 } 279 280 @property { 281 ///Left analog stick 282 Vec2f inputLAnalog() { 283 return _left; 284 } 285 286 ///Right analog stick 287 Vec2f inputRAnalog() { 288 return _right; 289 } 290 291 //Continuous buttons 292 293 ///Is the A button pressed. 294 bool inputA() { 295 _singleButtonA = false; 296 return _buttonA; 297 } 298 299 ///Is the B button pressed. 300 bool inputB() { 301 _singleButtonB = false; 302 return _buttonB; 303 } 304 305 ///Is the X button pressed. 306 bool inputX() { 307 _singleButtonX = false; 308 return _buttonX; 309 } 310 311 ///Is the Y button pressed. 312 bool inputY() { 313 _singleButtonY = false; 314 return _buttonY; 315 } 316 317 ///Is the Select button pressed. 318 bool inputSelect() { 319 _singleButtonSelect = false; 320 return _buttonSelect; 321 } 322 323 ///Is the Mode button pressed. 324 bool inputMode() { 325 _singleButtonMode = false; 326 return _buttonMode; 327 } 328 329 ///Is the Start button pressed. 330 bool inputStart() { 331 _singleButtonStart = false; 332 return _buttonStart; 333 } 334 335 ///Is the L1 button pressed. 336 bool inputL1() { 337 _singleButtonL1 = false; 338 return _buttonL1; 339 } 340 341 ///Is the R1 button pressed. 342 bool inputR1() { 343 _singleButtonR1 = false; 344 return _buttonR1; 345 } 346 347 ///Is the L2 button pressed. 348 bool inputL2() { 349 _singleButtonL2 = false; 350 return _buttonL2; 351 } 352 353 ///Is the R2 button pressed. 354 bool inputR2() { 355 _singleButtonR2 = false; 356 return _buttonR2; 357 } 358 359 ///Is the L3 button pressed. 360 bool inputL3() { 361 _singleButtonL3 = false; 362 return _buttonL3; 363 } 364 365 ///Is the R3 button pressed. 366 bool inputR3() { 367 _singleButtonR3 = false; 368 return _buttonR3; 369 } 370 371 ///Is the Left button pressed. 372 bool inputLeft() { 373 _singleButtonLeft = false; 374 return _buttonLeft; 375 } 376 377 ///Is the Right button pressed. 378 bool inputRight() { 379 _singleButtonRight = false; 380 return _buttonRight; 381 } 382 383 ///Is the Up button pressed. 384 bool inputUp() { 385 _singleButtonUp = false; 386 return _buttonUp; 387 } 388 389 ///Is the Down button pressed. 390 bool inputDown() { 391 _singleButtonDown = false; 392 return _buttonDown; 393 } 394 395 //Single action buttons 396 397 ///Is the A button pressed. 398 ///Returns true only if the button was not already tested. 399 bool inputSingleA() { 400 auto state = _singleButtonA; 401 _singleButtonA = false; 402 return state; 403 } 404 405 ///Is the B button pressed. 406 ///Returns true only if the button was not already tested. 407 bool inputSingleB() { 408 auto state = _singleButtonB; 409 _singleButtonB = false; 410 return state; 411 } 412 413 ///Is the X button pressed. 414 ///Returns true only if the button was not already tested. 415 bool inputSingleX() { 416 auto state = _singleButtonX; 417 _singleButtonX = false; 418 return state; 419 } 420 421 ///Is the Y button pressed. 422 ///Returns true only if the button was not already tested. 423 bool inputSingleY() { 424 auto state = _singleButtonY; 425 _singleButtonY = false; 426 return state; 427 } 428 429 ///Is the Select button pressed. 430 ///Returns true only if the button was not already tested. 431 bool inputSingleSelect() { 432 auto state = _singleButtonSelect; 433 _singleButtonSelect = false; 434 return state; 435 } 436 437 ///Is the Mode button pressed. 438 ///Returns true only if the button was not already tested. 439 bool inputSingleMode() { 440 auto state = _singleButtonMode; 441 _singleButtonMode = false; 442 return state; 443 } 444 445 ///Is the Start button pressed. 446 ///Returns true only if the button was not already tested. 447 bool inputSingleStart() { 448 auto state = _singleButtonStart; 449 _singleButtonStart = false; 450 return state; 451 } 452 453 ///Is the L1 button pressed. 454 ///Returns true only if the button was not already tested. 455 bool inputSingleL1() { 456 auto state = _singleButtonL1; 457 _singleButtonL1 = false; 458 return state; 459 } 460 461 ///Is the R1 button pressed. 462 ///Returns true only if the button was not already tested. 463 bool inputSingleR1() { 464 auto state = _singleButtonR1; 465 _singleButtonR1 = false; 466 return state; 467 } 468 469 ///Is the L2 button pressed. 470 ///Returns true only if the button was not already tested. 471 bool inputSingleL2() { 472 auto state = _singleButtonL2; 473 _singleButtonL2 = false; 474 return state; 475 } 476 477 ///Is the R2 button pressed. 478 ///Returns true only if the button was not already tested. 479 bool inputSingleR2() { 480 auto state = _singleButtonR2; 481 _singleButtonR2 = false; 482 return state; 483 } 484 485 ///Is the L3 button pressed. 486 ///Returns true only if the button was not already tested. 487 bool inputSingleL3() { 488 auto state = _singleButtonL3; 489 _singleButtonL3 = false; 490 return state; 491 } 492 493 ///Is the R3 button pressed. 494 ///Returns true only if the button was not already tested. 495 bool inputSingleR3() { 496 auto state = _singleButtonR3; 497 _singleButtonR3 = false; 498 return state; 499 } 500 501 ///Is the Left button pressed. 502 ///Returns true only if the button was not already tested. 503 bool inputSingleLeft() { 504 auto state = _singleButtonRight; 505 _singleButtonRight = false; 506 return state; 507 } 508 509 ///Is the Right button pressed. 510 ///Returns true only if the button was not already tested. 511 bool inputSingleRight() { 512 auto state = _singleButtonRight; 513 _singleButtonRight = false; 514 return state; 515 } 516 517 ///Is the Up button pressed. 518 ///Returns true only if the button was not already tested. 519 bool inputSingleUp() { 520 auto state = _singleButtonUp; 521 _singleButtonUp = false; 522 return state; 523 } 524 525 ///Is the Down button pressed. 526 ///Returns true only if the button was not already tested. 527 bool inputSingleDown() { 528 auto state = _singleButtonDown; 529 _singleButtonDown = false; 530 return state; 531 } 532 533 ///Returns the left stick x-axis as a button. 534 bool inputSingleLeftX() { 535 return updateAnalogTimer(0, _left.x, 0f); 536 } 537 538 ///Returns the left stick y-axis as a button. 539 bool inputSingleLeftY() { 540 return updateAnalogTimer(1, 0f, _left.y); 541 } 542 543 ///Returns the left stick x and y axis as a button. 544 bool inputSingleLeftXY() { 545 return updateAnalogTimer(2, _left.x, _left.y); 546 } 547 548 ///Returns the right stick x-axis as a button. 549 bool inputSingleRightX() { 550 return updateAnalogTimer(3, _right.x, 0f); 551 } 552 553 ///Returns the right stick y-axis as a button. 554 bool inputSingleRightY() { 555 return updateAnalogTimer(4, 0f, _right.y); 556 } 557 558 ///Returns the right stick x and y axis as a button. 559 bool inputSingleRightXY() { 560 return updateAnalogTimer(5, _right.x, _right.y); 561 } 562 }