/GBA4iOS/GBAExternalController.m

https://gitlab.com/fengluo/gba4ios · Objective C · 491 lines · 379 code · 93 blank · 19 comment · 80 complexity · 9d90be845c360f9b99cf95378c64131f MD5 · raw file

  1. //
  2. // GBAExternalController.m
  3. // GBA4iOS
  4. //
  5. // Created by Riley Testut on 11/22/13.
  6. // Copyright (c) 2013 Riley Testut. All rights reserved.
  7. //
  8. #import "GBAExternalController_Private.h"
  9. #import "GBAControllerSkin.h"
  10. #import "GBASettingsViewController.h"
  11. @interface GBAExternalController ()
  12. @property (strong, nonatomic) NSMutableDictionary *previousButtonStates; // Don't use controller snapshots cause we only want to update individual buttons each time
  13. @end
  14. @implementation GBAExternalController
  15. - (instancetype)initWithController:(GCController *)controller
  16. {
  17. self = [super init];
  18. if (self)
  19. {
  20. _controller = controller;
  21. _previousButtonStates = [NSMutableDictionary dictionary];
  22. [self configureController];
  23. }
  24. return self;
  25. }
  26. + (GBAExternalController *)externalControllerWithController:(GCController *)controller
  27. {
  28. GBAExternalController *externalController = [[GBAExternalController alloc] initWithController:controller];
  29. return externalController;
  30. }
  31. + (void)registerControllerDefaults
  32. {
  33. NSDictionary *controllerButtons = @{[GBAExternalController keyForButtonInput:GBAExternalControllerButtonInputA]: @(GBAControllerButtonA),
  34. [GBAExternalController keyForButtonInput:GBAExternalControllerButtonInputB]: @(GBAControllerButtonB),
  35. [GBAExternalController keyForButtonInput:GBAExternalControllerButtonInputX]: @(GBAControllerButtonSelect),
  36. [GBAExternalController keyForButtonInput:GBAExternalControllerButtonInputY]: @(GBAControllerButtonStart),
  37. [GBAExternalController keyForButtonInput:GBAExternalControllerButtonInputLeftTrigger]: @(GBAControllerButtonL),
  38. [GBAExternalController keyForButtonInput:GBAExternalControllerButtonInputRightTrigger]: @(GBAControllerButtonR)};
  39. [[NSUserDefaults standardUserDefaults] registerDefaults:@{GBASettingsExternalControllerButtonsKey: controllerButtons}];
  40. }
  41. + (NSString *)keyForButtonInput:(GBAExternalControllerButtonInput)buttonInput
  42. {
  43. NSString *string = @"";
  44. switch (buttonInput)
  45. {
  46. case GBAExternalControllerButtonInputA:
  47. string = @"A";
  48. break;
  49. case GBAExternalControllerButtonInputB:
  50. string = @"B";
  51. break;
  52. case GBAExternalControllerButtonInputX:
  53. string = @"X";
  54. break;
  55. case GBAExternalControllerButtonInputY:
  56. string = @"Y";
  57. break;
  58. case GBAExternalControllerButtonInputUp:
  59. string = @"Up";
  60. break;
  61. case GBAExternalControllerButtonInputDown:
  62. string = @"Down";
  63. break;
  64. case GBAExternalControllerButtonInputLeft:
  65. string = @"Left";
  66. break;
  67. case GBAExternalControllerButtonInputRight:
  68. string = @"Right";
  69. break;
  70. case GBAExternalControllerButtonInputLeftShoulder:
  71. string = @"L1";
  72. break;
  73. case GBAExternalControllerButtonInputLeftTrigger:
  74. string = @"L2";
  75. break;
  76. case GBAExternalControllerButtonInputRightShoulder:
  77. string = @"R1";
  78. break;
  79. case GBAExternalControllerButtonInputRightTrigger:
  80. string = @"R2";
  81. break;
  82. }
  83. return string;
  84. }
  85. #ifdef USE_POLLING
  86. - (void)configureController
  87. {
  88. __weak __typeof__(self) weakSelf = self;
  89. self.controller.controllerPausedHandler = ^(GCController *controller)
  90. {
  91. [weakSelf.delegate controllerInputDidPressMenuButton:weakSelf];
  92. };
  93. }
  94. #pragma mark - Update Controls
  95. - (void)updateControllerInputs
  96. {
  97. GCController *controller = self.controller;
  98. [self updateControllerButton:controller.gamepad.buttonA];
  99. [self updateControllerButton:controller.gamepad.buttonB];
  100. [self updateControllerButton:controller.gamepad.buttonX];
  101. [self updateControllerButton:controller.gamepad.buttonY];
  102. [self updateControllerButton:controller.gamepad.leftShoulder];
  103. [self updateControllerButton:controller.gamepad.rightShoulder];
  104. [self updateControllerButton:controller.extendedGamepad.leftTrigger];
  105. [self updateControllerButton:controller.extendedGamepad.rightTrigger];
  106. [self updateControllerDPad:controller.gamepad.dpad];
  107. [self updateControllerDPad:controller.extendedGamepad.leftThumbstick];
  108. }
  109. - (void)updateControllerButton:(GCControllerButtonInput *)button
  110. {
  111. GBAExternalControllerButtonInput externalControllerButtonInput = [self externalControllerButtonInputForButton:button];
  112. BOOL previouslyPressed = [self.previousButtonStates[@(externalControllerButtonInput)] boolValue];
  113. if (previouslyPressed == (button.value > 0))
  114. {
  115. return;
  116. }
  117. GBAControllerButton controllerButton = [GBAExternalController controllerButtonForControllerButtonInput:externalControllerButtonInput];
  118. NSSet *set = [NSSet setWithObject:@(controllerButton)];
  119. if (button.value > 0)
  120. {
  121. [self.delegate controllerInput:self didPressButtons:set];
  122. }
  123. else
  124. {
  125. [self.delegate controllerInput:self didReleaseButtons:set];
  126. }
  127. self.previousButtonStates[@(externalControllerButtonInput)] = @(button.value > 0);
  128. }
  129. - (void)updateControllerDPad:(GCControllerDirectionPad *)dPad
  130. {
  131. NSMutableSet *pressedButtons = [NSMutableSet set];
  132. NSMutableSet *releasedButtons = [NSMutableSet set];
  133. // Up
  134. BOOL previouslyPressedUp = [self.previousButtonStates[@(GBAExternalControllerButtonInputUp)] boolValue];
  135. if ([dPad.up isPressed] && !previouslyPressedUp)
  136. {
  137. [pressedButtons addObject:@(GBAControllerButtonUp)];
  138. self.previousButtonStates[@(GBAExternalControllerButtonInputUp)] = @(dPad.up.pressed);
  139. }
  140. else if (![dPad.up isPressed] && previouslyPressedUp)
  141. {
  142. [releasedButtons addObject:@(GBAControllerButtonUp)];
  143. self.previousButtonStates[@(GBAExternalControllerButtonInputUp)] = @(dPad.up.pressed);
  144. }
  145. // Down
  146. BOOL previouslyPressedDown = [self.previousButtonStates[@(GBAExternalControllerButtonInputDown)] boolValue];
  147. if ([dPad.down isPressed] && !previouslyPressedDown)
  148. {
  149. [pressedButtons addObject:@(GBAControllerButtonDown)];
  150. self.previousButtonStates[@(GBAExternalControllerButtonInputDown)] = @(dPad.down.pressed);
  151. }
  152. else if (![dPad.down isPressed] && previouslyPressedDown)
  153. {
  154. [releasedButtons addObject:@(GBAControllerButtonDown)];
  155. self.previousButtonStates[@(GBAExternalControllerButtonInputDown)] = @(dPad.down.pressed);
  156. }
  157. // Left
  158. BOOL previouslyPressedLeft = [self.previousButtonStates[@(GBAExternalControllerButtonInputLeft)] boolValue];
  159. if ([dPad.left isPressed] && !previouslyPressedLeft)
  160. {
  161. [pressedButtons addObject:@(GBAControllerButtonLeft)];
  162. self.previousButtonStates[@(GBAExternalControllerButtonInputLeft)] = @(dPad.left.pressed);
  163. }
  164. else if (![dPad.left isPressed] && previouslyPressedLeft)
  165. {
  166. [releasedButtons addObject:@(GBAControllerButtonLeft)];
  167. self.previousButtonStates[@(GBAExternalControllerButtonInputLeft)] = @(dPad.left.pressed);
  168. }
  169. // Right
  170. BOOL previouslyPressedRight = [self.previousButtonStates[@(GBAExternalControllerButtonInputRight)] boolValue];
  171. if ([dPad.right isPressed] && !previouslyPressedRight)
  172. {
  173. [pressedButtons addObject:@(GBAControllerButtonRight)];
  174. self.previousButtonStates[@(GBAExternalControllerButtonInputRight)] = @(dPad.right.pressed);
  175. }
  176. else if (![dPad.right isPressed] && previouslyPressedRight)
  177. {
  178. [releasedButtons addObject:@(GBAControllerButtonRight)];
  179. self.previousButtonStates[@(GBAExternalControllerButtonInputRight)] = @(dPad.right.pressed);
  180. }
  181. if ([pressedButtons count] > 0)
  182. {
  183. [self.delegate controllerInput:self didPressButtons:pressedButtons];
  184. }
  185. if ([releasedButtons count] > 0)
  186. {
  187. [self.delegate controllerInput:self didReleaseButtons:releasedButtons];
  188. }
  189. }
  190. /* Keeping all this code around in case Apple fixes the stupid delayed button bug, since it is much more efficient :( */
  191. #else
  192. - (void)configureController
  193. {
  194. __weak __typeof__(self) weakSelf = self;
  195. self.controller.controllerPausedHandler = ^(GCController *controller)
  196. {
  197. [weakSelf.delegate controllerInputDidPressMenuButton:weakSelf];
  198. };
  199. GCGamepad *gamepad = self.controller.gamepad;
  200. // Standard Buttons
  201. gamepad.buttonA.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed)
  202. {
  203. [self controllerButtonInput:GBAExternalControllerButtonInputA wasPressed:pressed];
  204. };
  205. gamepad.buttonB.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed)
  206. {
  207. [self controllerButtonInput:GBAExternalControllerButtonInputB wasPressed:pressed];
  208. };
  209. gamepad.buttonX.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed)
  210. {
  211. [self controllerButtonInput:GBAExternalControllerButtonInputX wasPressed:pressed];
  212. };
  213. gamepad.buttonY.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed)
  214. {
  215. [self controllerButtonInput:GBAExternalControllerButtonInputY wasPressed:pressed];
  216. };
  217. gamepad.leftShoulder.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed)
  218. {
  219. [self controllerButtonInput:GBAExternalControllerButtonInputLeftShoulder wasPressed:pressed];
  220. };
  221. gamepad.rightShoulder.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed)
  222. {
  223. [self controllerButtonInput:GBAExternalControllerButtonInputRightShoulder wasPressed:pressed];
  224. };
  225. // D-Pad
  226. gamepad.dpad.valueChangedHandler = ^(GCControllerDirectionPad *dpad, float xValue, float yValue)
  227. {
  228. [self controllerDPadDidChange:dpad];
  229. };
  230. // Extended Profile
  231. GCExtendedGamepad *extendedGamepad = self.controller.extendedGamepad;
  232. if (extendedGamepad == nil)
  233. {
  234. return;
  235. }
  236. extendedGamepad.leftTrigger.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed)
  237. {
  238. [self controllerButtonInput:GBAExternalControllerButtonInputLeftTrigger wasPressed:pressed];
  239. };
  240. extendedGamepad.rightTrigger.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed)
  241. {
  242. [self controllerButtonInput:GBAExternalControllerButtonInputRightTrigger wasPressed:pressed];
  243. };
  244. extendedGamepad.leftThumbstick.valueChangedHandler = ^(GCControllerDirectionPad *dpad, float xValue, float yValue)
  245. {
  246. [self controllerDPadDidChange:dpad];
  247. };
  248. }
  249. #pragma mark - Controls
  250. - (void)controllerButtonInput:(GBAExternalControllerButtonInput)buttonInput wasPressed:(BOOL)pressed
  251. {
  252. BOOL previouslyPressed = [self.previousButtonStates[@(buttonInput)] boolValue];
  253. GBAControllerButton controllerButton = [GBAExternalController controllerButtonForControllerButtonInput:buttonInput];
  254. NSSet *set = [NSSet setWithObject:@(controllerButton)];
  255. if (pressed && !previouslyPressed)
  256. {
  257. [self.delegate controllerInput:self didPressButtons:set];
  258. }
  259. else if (!pressed && previouslyPressed)
  260. {
  261. [self.delegate controllerInput:self didReleaseButtons:set];
  262. }
  263. self.previousButtonStates[@(buttonInput)] = @(pressed);
  264. }
  265. - (void)controllerDPadDidChange:(GCControllerDirectionPad *)dPad
  266. {
  267. NSMutableSet *pressedButtons = [NSMutableSet set];
  268. NSMutableSet *releasedButtons = [NSMutableSet set];
  269. // Up
  270. BOOL previouslyPressedUp = [self.previousButtonStates[@(GBAExternalControllerButtonInputUp)] boolValue];
  271. if ([dPad.up isPressed] && !previouslyPressedUp)
  272. {
  273. [pressedButtons addObject:@(GBAControllerButtonUp)];
  274. self.previousButtonStates[@(GBAExternalControllerButtonInputUp)] = @(dPad.up.pressed);
  275. }
  276. else if (![dPad.up isPressed] && previouslyPressedUp)
  277. {
  278. [releasedButtons addObject:@(GBAControllerButtonUp)];
  279. self.previousButtonStates[@(GBAExternalControllerButtonInputUp)] = @(dPad.up.pressed);
  280. }
  281. // Down
  282. BOOL previouslyPressedDown = [self.previousButtonStates[@(GBAExternalControllerButtonInputDown)] boolValue];
  283. if ([dPad.down isPressed] && !previouslyPressedDown)
  284. {
  285. [pressedButtons addObject:@(GBAControllerButtonDown)];
  286. self.previousButtonStates[@(GBAExternalControllerButtonInputDown)] = @(dPad.down.pressed);
  287. }
  288. else if (![dPad.down isPressed] && previouslyPressedDown)
  289. {
  290. [releasedButtons addObject:@(GBAControllerButtonDown)];
  291. self.previousButtonStates[@(GBAExternalControllerButtonInputDown)] = @(dPad.down.pressed);
  292. }
  293. // Left
  294. BOOL previouslyPressedLeft = [self.previousButtonStates[@(GBAExternalControllerButtonInputLeft)] boolValue];
  295. if ([dPad.left isPressed] && !previouslyPressedLeft)
  296. {
  297. [pressedButtons addObject:@(GBAControllerButtonLeft)];
  298. self.previousButtonStates[@(GBAExternalControllerButtonInputLeft)] = @(dPad.left.pressed);
  299. }
  300. else if (![dPad.left isPressed] && previouslyPressedLeft)
  301. {
  302. [releasedButtons addObject:@(GBAControllerButtonLeft)];
  303. self.previousButtonStates[@(GBAExternalControllerButtonInputLeft)] = @(dPad.left.pressed);
  304. }
  305. // Right
  306. BOOL previouslyPressedRight = [self.previousButtonStates[@(GBAExternalControllerButtonInputRight)] boolValue];
  307. if ([dPad.right isPressed] && !previouslyPressedRight)
  308. {
  309. [pressedButtons addObject:@(GBAControllerButtonRight)];
  310. self.previousButtonStates[@(GBAExternalControllerButtonInputRight)] = @(dPad.right.pressed);
  311. }
  312. else if (![dPad.right isPressed] && previouslyPressedRight)
  313. {
  314. [releasedButtons addObject:@(GBAControllerButtonRight)];
  315. self.previousButtonStates[@(GBAExternalControllerButtonInputRight)] = @(dPad.right.pressed);
  316. }
  317. if ([pressedButtons count] > 0)
  318. {
  319. [self.delegate controllerInput:self didPressButtons:pressedButtons];
  320. }
  321. if ([releasedButtons count] > 0)
  322. {
  323. [self.delegate controllerInput:self didReleaseButtons:releasedButtons];
  324. }
  325. }
  326. #endif
  327. #pragma mark - Helper Methods
  328. + (GBAControllerButton)controllerButtonForControllerButtonInput:(GBAExternalControllerButtonInput)buttonInput
  329. {
  330. GBAControllerButton controllerButton = 0;
  331. switch (buttonInput)
  332. {
  333. case GBAExternalControllerButtonInputLeft:
  334. controllerButton = GBAControllerButtonLeft;
  335. break;
  336. case GBAExternalControllerButtonInputRight:
  337. controllerButton = GBAControllerButtonRight;
  338. break;
  339. case GBAExternalControllerButtonInputUp:
  340. controllerButton = GBAControllerButtonUp;
  341. break;
  342. case GBAExternalControllerButtonInputDown:
  343. controllerButton = GBAControllerButtonDown;
  344. break;
  345. case GBAExternalControllerButtonInputLeftShoulder:
  346. controllerButton = GBAControllerButtonL;
  347. break;
  348. case GBAExternalControllerButtonInputRightShoulder:
  349. controllerButton = GBAControllerButtonR;
  350. break;
  351. default: {
  352. NSDictionary *buttonDictionary = [[NSUserDefaults standardUserDefaults] dictionaryForKey:GBASettingsExternalControllerButtonsKey];
  353. NSString *buttonString = [GBAExternalController keyForButtonInput:buttonInput];
  354. controllerButton = [buttonDictionary[buttonString] integerValue];
  355. break;
  356. }
  357. }
  358. return controllerButton;
  359. }
  360. - (GBAExternalControllerButtonInput)externalControllerButtonInputForButton:(GCControllerButtonInput *)button
  361. {
  362. GCController *controller = self.controller;
  363. GBAExternalControllerButtonInput externalControllerButtonInput = 0;
  364. if (button == controller.gamepad.buttonA)
  365. {
  366. externalControllerButtonInput = GBAExternalControllerButtonInputA;
  367. }
  368. else if (button == controller.gamepad.buttonB)
  369. {
  370. externalControllerButtonInput = GBAExternalControllerButtonInputB;
  371. }
  372. else if (button == controller.gamepad.buttonX)
  373. {
  374. externalControllerButtonInput = GBAExternalControllerButtonInputX;
  375. }
  376. else if (button == controller.gamepad.buttonY)
  377. {
  378. externalControllerButtonInput = GBAExternalControllerButtonInputY;
  379. }
  380. else if (button == controller.gamepad.leftShoulder)
  381. {
  382. externalControllerButtonInput = GBAExternalControllerButtonInputLeftShoulder;
  383. }
  384. else if (button == controller.gamepad.rightShoulder)
  385. {
  386. externalControllerButtonInput = GBAExternalControllerButtonInputRightShoulder;
  387. }
  388. else if (button == controller.extendedGamepad.leftTrigger)
  389. {
  390. externalControllerButtonInput = GBAExternalControllerButtonInputLeftTrigger;
  391. }
  392. else if (button == controller.extendedGamepad.rightTrigger)
  393. {
  394. externalControllerButtonInput = GBAExternalControllerButtonInputRightTrigger;
  395. }
  396. return externalControllerButtonInput;
  397. }
  398. @end