controllermap.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  1. /*
  2. Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
  3. This software is provided 'as-is', without any express or implied
  4. warranty. In no event will the authors be held liable for any damages
  5. arising from the use of this software.
  6. Permission is granted to anyone to use this software for any purpose,
  7. including commercial applications, and to alter it and redistribute it
  8. freely.
  9. */
  10. /* Game controller mapping generator */
  11. /* Gabriel Jacobo <gabomdq@gmail.com> */
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include "SDL.h"
  16. #ifndef SDL_JOYSTICK_DISABLED
  17. #ifdef __IPHONEOS__
  18. #define SCREEN_WIDTH 320
  19. #define SCREEN_HEIGHT 480
  20. #else
  21. #define SCREEN_WIDTH 512
  22. #define SCREEN_HEIGHT 320
  23. #endif
  24. #define MARKER_BUTTON 1
  25. #define MARKER_AXIS 2
  26. enum
  27. {
  28. SDL_CONTROLLER_BINDING_AXIS_LEFTX_NEGATIVE,
  29. SDL_CONTROLLER_BINDING_AXIS_LEFTX_POSITIVE,
  30. SDL_CONTROLLER_BINDING_AXIS_LEFTY_NEGATIVE,
  31. SDL_CONTROLLER_BINDING_AXIS_LEFTY_POSITIVE,
  32. SDL_CONTROLLER_BINDING_AXIS_RIGHTX_NEGATIVE,
  33. SDL_CONTROLLER_BINDING_AXIS_RIGHTX_POSITIVE,
  34. SDL_CONTROLLER_BINDING_AXIS_RIGHTY_NEGATIVE,
  35. SDL_CONTROLLER_BINDING_AXIS_RIGHTY_POSITIVE,
  36. SDL_CONTROLLER_BINDING_AXIS_TRIGGERLEFT,
  37. SDL_CONTROLLER_BINDING_AXIS_TRIGGERRIGHT,
  38. SDL_CONTROLLER_BINDING_AXIS_MAX,
  39. };
  40. #define BINDING_COUNT (SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_MAX)
  41. static struct
  42. {
  43. int x, y;
  44. double angle;
  45. int marker;
  46. } s_arrBindingDisplay[BINDING_COUNT] = {
  47. { 387, 167, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_A */
  48. { 431, 132, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_B */
  49. { 342, 132, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_X */
  50. { 389, 101, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_Y */
  51. { 174, 132, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_BACK */
  52. { 233, 132, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_GUIDE */
  53. { 289, 132, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_START */
  54. { 75, 154, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_LEFTSTICK */
  55. { 305, 230, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_RIGHTSTICK */
  56. { 77, 40, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_LEFTSHOULDER */
  57. { 396, 36, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_RIGHTSHOULDER */
  58. { 154, 188, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_DPAD_UP */
  59. { 154, 249, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_DPAD_DOWN */
  60. { 116, 217, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_DPAD_LEFT */
  61. { 186, 217, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_DPAD_RIGHT */
  62. { 74, 153, 270.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_LEFTX_NEGATIVE */
  63. { 74, 153, 90.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_LEFTX_POSITIVE */
  64. { 74, 153, 0.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_LEFTY_NEGATIVE */
  65. { 74, 153, 180.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_LEFTY_POSITIVE */
  66. { 306, 231, 270.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_RIGHTX_NEGATIVE */
  67. { 306, 231, 90.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_RIGHTX_POSITIVE */
  68. { 306, 231, 0.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_RIGHTY_NEGATIVE */
  69. { 306, 231, 180.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_RIGHTY_POSITIVE */
  70. { 91, -20, 180.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_TRIGGERLEFT */
  71. { 375, -20, 180.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_TRIGGERRIGHT */
  72. };
  73. static int s_arrBindingOrder[BINDING_COUNT] = {
  74. SDL_CONTROLLER_BUTTON_A,
  75. SDL_CONTROLLER_BUTTON_B,
  76. SDL_CONTROLLER_BUTTON_Y,
  77. SDL_CONTROLLER_BUTTON_X,
  78. SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_LEFTX_NEGATIVE,
  79. SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_LEFTX_POSITIVE,
  80. SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_LEFTY_NEGATIVE,
  81. SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_LEFTY_POSITIVE,
  82. SDL_CONTROLLER_BUTTON_LEFTSTICK,
  83. SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_RIGHTX_NEGATIVE,
  84. SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_RIGHTX_POSITIVE,
  85. SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_RIGHTY_NEGATIVE,
  86. SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_RIGHTY_POSITIVE,
  87. SDL_CONTROLLER_BUTTON_RIGHTSTICK,
  88. SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
  89. SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_TRIGGERLEFT,
  90. SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
  91. SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_TRIGGERRIGHT,
  92. SDL_CONTROLLER_BUTTON_DPAD_UP,
  93. SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
  94. SDL_CONTROLLER_BUTTON_DPAD_DOWN,
  95. SDL_CONTROLLER_BUTTON_DPAD_LEFT,
  96. SDL_CONTROLLER_BUTTON_BACK,
  97. SDL_CONTROLLER_BUTTON_GUIDE,
  98. SDL_CONTROLLER_BUTTON_START,
  99. };
  100. typedef struct
  101. {
  102. SDL_GameControllerBindType bindType;
  103. union
  104. {
  105. int button;
  106. struct {
  107. int axis;
  108. int axis_min;
  109. int axis_max;
  110. } axis;
  111. struct {
  112. int hat;
  113. int hat_mask;
  114. } hat;
  115. } value;
  116. SDL_bool committed;
  117. } SDL_GameControllerExtendedBind;
  118. static SDL_GameControllerExtendedBind s_arrBindings[BINDING_COUNT];
  119. typedef struct
  120. {
  121. SDL_bool m_bMoving;
  122. int m_nStartingValue;
  123. int m_nFarthestValue;
  124. } AxisState;
  125. static int s_nNumAxes;
  126. static AxisState *s_arrAxisState;
  127. static int s_iCurrentBinding;
  128. static Uint32 s_unPendingAdvanceTime;
  129. static SDL_bool s_bBindingComplete;
  130. SDL_Texture *
  131. LoadTexture(SDL_Renderer *renderer, const char *file, SDL_bool transparent)
  132. {
  133. SDL_Surface *temp;
  134. SDL_Texture *texture;
  135. /* Load the sprite image */
  136. temp = SDL_LoadBMP(file);
  137. if (temp == NULL) {
  138. SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", file, SDL_GetError());
  139. return NULL;
  140. }
  141. /* Set transparent pixel as the pixel at (0,0) */
  142. if (transparent) {
  143. if (temp->format->palette) {
  144. SDL_SetColorKey(temp, SDL_TRUE, *(Uint8 *) temp->pixels);
  145. }
  146. }
  147. /* Create textures from the image */
  148. texture = SDL_CreateTextureFromSurface(renderer, temp);
  149. if (!texture) {
  150. SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create texture: %s\n", SDL_GetError());
  151. SDL_FreeSurface(temp);
  152. return NULL;
  153. }
  154. SDL_FreeSurface(temp);
  155. /* We're ready to roll. :) */
  156. return texture;
  157. }
  158. static int
  159. StandardizeAxisValue(int nValue)
  160. {
  161. if (nValue > SDL_JOYSTICK_AXIS_MAX/2) {
  162. return SDL_JOYSTICK_AXIS_MAX;
  163. } else if (nValue < SDL_JOYSTICK_AXIS_MIN/2) {
  164. return SDL_JOYSTICK_AXIS_MIN;
  165. } else {
  166. return 0;
  167. }
  168. }
  169. static void
  170. SetCurrentBinding(int iBinding)
  171. {
  172. int iIndex;
  173. SDL_GameControllerExtendedBind *pBinding;
  174. if (iBinding < 0) {
  175. return;
  176. }
  177. if (iBinding == BINDING_COUNT) {
  178. s_bBindingComplete = SDL_TRUE;
  179. return;
  180. }
  181. s_iCurrentBinding = iBinding;
  182. pBinding = &s_arrBindings[s_arrBindingOrder[s_iCurrentBinding]];
  183. SDL_zerop(pBinding);
  184. for (iIndex = 0; iIndex < s_nNumAxes; ++iIndex) {
  185. s_arrAxisState[iIndex].m_nFarthestValue = s_arrAxisState[iIndex].m_nStartingValue;
  186. }
  187. s_unPendingAdvanceTime = 0;
  188. }
  189. static SDL_bool
  190. BBindingContainsBinding(const SDL_GameControllerExtendedBind *pBindingA, const SDL_GameControllerExtendedBind *pBindingB)
  191. {
  192. if (pBindingA->bindType != pBindingB->bindType)
  193. {
  194. return SDL_FALSE;
  195. }
  196. switch (pBindingA->bindType)
  197. {
  198. case SDL_CONTROLLER_BINDTYPE_AXIS:
  199. if (pBindingA->value.axis.axis != pBindingB->value.axis.axis) {
  200. return SDL_FALSE;
  201. }
  202. if (!pBindingA->committed) {
  203. return SDL_FALSE;
  204. }
  205. {
  206. int minA = SDL_min(pBindingA->value.axis.axis_min, pBindingA->value.axis.axis_max);
  207. int maxA = SDL_max(pBindingA->value.axis.axis_min, pBindingA->value.axis.axis_max);
  208. int minB = SDL_min(pBindingB->value.axis.axis_min, pBindingB->value.axis.axis_max);
  209. int maxB = SDL_max(pBindingB->value.axis.axis_min, pBindingB->value.axis.axis_max);
  210. return (minA <= minB && maxA >= maxB);
  211. }
  212. /* Not reached */
  213. default:
  214. return SDL_memcmp(pBindingA, pBindingB, sizeof(*pBindingA)) == 0;
  215. }
  216. }
  217. static void
  218. ConfigureBinding(const SDL_GameControllerExtendedBind *pBinding)
  219. {
  220. SDL_GameControllerExtendedBind *pCurrent;
  221. int iIndex;
  222. int iCurrentElement = s_arrBindingOrder[s_iCurrentBinding];
  223. /* Do we already have this binding? */
  224. for (iIndex = 0; iIndex < SDL_arraysize(s_arrBindings); ++iIndex) {
  225. pCurrent = &s_arrBindings[iIndex];
  226. if (BBindingContainsBinding(pCurrent, pBinding)) {
  227. if (iIndex == SDL_CONTROLLER_BUTTON_A && iCurrentElement != SDL_CONTROLLER_BUTTON_B) {
  228. /* Skip to the next binding */
  229. SetCurrentBinding(s_iCurrentBinding + 1);
  230. return;
  231. }
  232. if (iIndex == SDL_CONTROLLER_BUTTON_B) {
  233. /* Go back to the previous binding */
  234. SetCurrentBinding(s_iCurrentBinding - 1);
  235. return;
  236. }
  237. /* Already have this binding, ignore it */
  238. return;
  239. }
  240. }
  241. #ifdef DEBUG_CONTROLLERMAP
  242. switch ( pBinding->bindType )
  243. {
  244. case SDL_CONTROLLER_BINDTYPE_NONE:
  245. break;
  246. case SDL_CONTROLLER_BINDTYPE_BUTTON:
  247. SDL_Log("Configuring button binding for button %d\n", pBinding->value.button);
  248. break;
  249. case SDL_CONTROLLER_BINDTYPE_AXIS:
  250. SDL_Log("Configuring axis binding for axis %d %d/%d committed = %s\n", pBinding->value.axis.axis, pBinding->value.axis.axis_min, pBinding->value.axis.axis_max, pBinding->committed ? "true" : "false");
  251. break;
  252. case SDL_CONTROLLER_BINDTYPE_HAT:
  253. SDL_Log("Configuring hat binding for hat %d %d\n", pBinding->value.hat.hat, pBinding->value.hat.hat_mask);
  254. break;
  255. }
  256. #endif /* DEBUG_CONTROLLERMAP */
  257. /* Should the new binding override the existing one? */
  258. pCurrent = &s_arrBindings[iCurrentElement];
  259. if (pCurrent->bindType != SDL_CONTROLLER_BINDTYPE_NONE) {
  260. SDL_bool bNativeDPad, bCurrentDPad;
  261. SDL_bool bNativeAxis, bCurrentAxis;
  262. bNativeDPad = (iCurrentElement == SDL_CONTROLLER_BUTTON_DPAD_UP ||
  263. iCurrentElement == SDL_CONTROLLER_BUTTON_DPAD_DOWN ||
  264. iCurrentElement == SDL_CONTROLLER_BUTTON_DPAD_LEFT ||
  265. iCurrentElement == SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
  266. bCurrentDPad = (pCurrent->bindType == SDL_CONTROLLER_BINDTYPE_HAT);
  267. if (bNativeDPad && bCurrentDPad) {
  268. /* We already have a binding of the type we want, ignore the new one */
  269. return;
  270. }
  271. bNativeAxis = (iCurrentElement >= SDL_CONTROLLER_BUTTON_MAX);
  272. bCurrentAxis = (pCurrent->bindType == SDL_CONTROLLER_BINDTYPE_AXIS);
  273. if (bNativeAxis == bCurrentAxis &&
  274. (pBinding->bindType != SDL_CONTROLLER_BINDTYPE_AXIS ||
  275. pBinding->value.axis.axis != pCurrent->value.axis.axis)) {
  276. /* We already have a binding of the type we want, ignore the new one */
  277. return;
  278. }
  279. }
  280. *pCurrent = *pBinding;
  281. if (pBinding->committed) {
  282. s_unPendingAdvanceTime = SDL_GetTicks();
  283. } else {
  284. s_unPendingAdvanceTime = 0;
  285. }
  286. }
  287. static SDL_bool
  288. BMergeAxisBindings(int iIndex)
  289. {
  290. SDL_GameControllerExtendedBind *pBindingA = &s_arrBindings[iIndex];
  291. SDL_GameControllerExtendedBind *pBindingB = &s_arrBindings[iIndex+1];
  292. if (pBindingA->bindType == SDL_CONTROLLER_BINDTYPE_AXIS &&
  293. pBindingB->bindType == SDL_CONTROLLER_BINDTYPE_AXIS &&
  294. pBindingA->value.axis.axis == pBindingB->value.axis.axis) {
  295. if (pBindingA->value.axis.axis_min == pBindingB->value.axis.axis_min) {
  296. pBindingA->value.axis.axis_min = pBindingA->value.axis.axis_max;
  297. pBindingA->value.axis.axis_max = pBindingB->value.axis.axis_max;
  298. pBindingB->bindType = SDL_CONTROLLER_BINDTYPE_NONE;
  299. return SDL_TRUE;
  300. }
  301. }
  302. return SDL_FALSE;
  303. }
  304. static void
  305. WatchJoystick(SDL_Joystick * joystick)
  306. {
  307. SDL_Window *window = NULL;
  308. SDL_Renderer *screen = NULL;
  309. SDL_Texture *background, *button, *axis, *marker;
  310. const char *name = NULL;
  311. SDL_bool done = SDL_FALSE;
  312. SDL_Event event;
  313. SDL_Rect dst;
  314. Uint8 alpha=200, alpha_step = -1;
  315. Uint32 alpha_ticks = 0;
  316. SDL_JoystickID nJoystickID;
  317. int iIndex;
  318. /* Create a window to display joystick axis position */
  319. window = SDL_CreateWindow("Game Controller Map", SDL_WINDOWPOS_CENTERED,
  320. SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,
  321. SCREEN_HEIGHT, 0);
  322. if (window == NULL) {
  323. SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError());
  324. return;
  325. }
  326. screen = SDL_CreateRenderer(window, -1, 0);
  327. if (screen == NULL) {
  328. SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError());
  329. SDL_DestroyWindow(window);
  330. return;
  331. }
  332. background = LoadTexture(screen, "controllermap.bmp", SDL_FALSE);
  333. button = LoadTexture(screen, "button.bmp", SDL_TRUE);
  334. axis = LoadTexture(screen, "axis.bmp", SDL_TRUE);
  335. SDL_RaiseWindow(window);
  336. /* scale for platforms that don't give you the window size you asked for. */
  337. SDL_RenderSetLogicalSize(screen, SCREEN_WIDTH, SCREEN_HEIGHT);
  338. /* Print info about the joystick we are watching */
  339. name = SDL_JoystickName(joystick);
  340. SDL_Log("Watching joystick %d: (%s)\n", SDL_JoystickInstanceID(joystick),
  341. name ? name : "Unknown Joystick");
  342. SDL_Log("Joystick has %d axes, %d hats, %d balls, and %d buttons\n",
  343. SDL_JoystickNumAxes(joystick), SDL_JoystickNumHats(joystick),
  344. SDL_JoystickNumBalls(joystick), SDL_JoystickNumButtons(joystick));
  345. SDL_Log("\n\n\
  346. ====================================================================================\n\
  347. Press the buttons on your controller when indicated\n\
  348. (Your controller may look different than the picture)\n\
  349. If you want to correct a mistake, press backspace or the back button on your device\n\
  350. To skip a button, press SPACE or click/touch the screen\n\
  351. To exit, press ESC\n\
  352. ====================================================================================\n");
  353. nJoystickID = SDL_JoystickInstanceID(joystick);
  354. s_nNumAxes = SDL_JoystickNumAxes(joystick);
  355. s_arrAxisState = (AxisState *)SDL_calloc(s_nNumAxes, sizeof(*s_arrAxisState));
  356. for (iIndex = 0; iIndex < s_nNumAxes; ++iIndex) {
  357. AxisState *pAxisState = &s_arrAxisState[iIndex];
  358. Sint16 nInitialValue;
  359. pAxisState->m_bMoving = SDL_JoystickGetAxisInitialState(joystick, iIndex, &nInitialValue);
  360. pAxisState->m_nStartingValue = nInitialValue;
  361. pAxisState->m_nFarthestValue = nInitialValue;
  362. }
  363. /* Loop, getting joystick events! */
  364. while (!done && !s_bBindingComplete) {
  365. int iElement = s_arrBindingOrder[s_iCurrentBinding];
  366. switch (s_arrBindingDisplay[iElement].marker) {
  367. case MARKER_AXIS:
  368. marker = axis;
  369. break;
  370. case MARKER_BUTTON:
  371. marker = button;
  372. break;
  373. default:
  374. break;
  375. }
  376. dst.x = s_arrBindingDisplay[iElement].x;
  377. dst.y = s_arrBindingDisplay[iElement].y;
  378. SDL_QueryTexture(marker, NULL, NULL, &dst.w, &dst.h);
  379. if (SDL_GetTicks() - alpha_ticks > 5) {
  380. alpha_ticks = SDL_GetTicks();
  381. alpha += alpha_step;
  382. if (alpha == 255) {
  383. alpha_step = -1;
  384. }
  385. if (alpha < 128) {
  386. alpha_step = 1;
  387. }
  388. }
  389. SDL_SetRenderDrawColor(screen, 0xFF, 0xFF, 0xFF, SDL_ALPHA_OPAQUE);
  390. SDL_RenderClear(screen);
  391. SDL_RenderCopy(screen, background, NULL, NULL);
  392. SDL_SetTextureAlphaMod(marker, alpha);
  393. SDL_SetTextureColorMod(marker, 10, 255, 21);
  394. SDL_RenderCopyEx(screen, marker, NULL, &dst, s_arrBindingDisplay[iElement].angle, NULL, SDL_FLIP_NONE);
  395. SDL_RenderPresent(screen);
  396. while (SDL_PollEvent(&event) > 0) {
  397. switch (event.type) {
  398. case SDL_JOYDEVICEREMOVED:
  399. if (event.jaxis.which == nJoystickID) {
  400. done = SDL_TRUE;
  401. }
  402. break;
  403. case SDL_JOYAXISMOTION:
  404. if (event.jaxis.which == nJoystickID) {
  405. AxisState *pAxisState = &s_arrAxisState[event.jaxis.axis];
  406. int nValue = event.jaxis.value;
  407. int nCurrentDistance, nFarthestDistance;
  408. if (!pAxisState->m_bMoving) {
  409. pAxisState->m_bMoving = SDL_TRUE;
  410. pAxisState->m_nStartingValue = nValue;
  411. pAxisState->m_nFarthestValue = nValue;
  412. }
  413. nCurrentDistance = SDL_abs(nValue - pAxisState->m_nStartingValue);
  414. nFarthestDistance = SDL_abs(pAxisState->m_nFarthestValue - pAxisState->m_nStartingValue);
  415. if (nCurrentDistance > nFarthestDistance) {
  416. pAxisState->m_nFarthestValue = nValue;
  417. nFarthestDistance = SDL_abs(pAxisState->m_nFarthestValue - pAxisState->m_nStartingValue);
  418. }
  419. #ifdef DEBUG_CONTROLLERMAP
  420. SDL_Log("AXIS %d nValue %d nCurrentDistance %d nFarthestDistance %d\n", event.jaxis.axis, nValue, nCurrentDistance, nFarthestDistance);
  421. #endif
  422. if (nFarthestDistance >= 16000) {
  423. /* If we've gone out far enough and started to come back, let's bind this axis */
  424. SDL_bool bCommitBinding = (nCurrentDistance <= 10000) ? SDL_TRUE : SDL_FALSE;
  425. SDL_GameControllerExtendedBind binding;
  426. SDL_zero(binding);
  427. binding.bindType = SDL_CONTROLLER_BINDTYPE_AXIS;
  428. binding.value.axis.axis = event.jaxis.axis;
  429. binding.value.axis.axis_min = StandardizeAxisValue(pAxisState->m_nStartingValue);
  430. binding.value.axis.axis_max = StandardizeAxisValue(pAxisState->m_nFarthestValue);
  431. binding.committed = bCommitBinding;
  432. ConfigureBinding(&binding);
  433. }
  434. }
  435. break;
  436. case SDL_JOYHATMOTION:
  437. if (event.jhat.which == nJoystickID) {
  438. if (event.jhat.value != SDL_HAT_CENTERED) {
  439. SDL_GameControllerExtendedBind binding;
  440. #ifdef DEBUG_CONTROLLERMAP
  441. SDL_Log("HAT %d %d\n", event.jhat.hat, event.jhat.value);
  442. #endif
  443. SDL_zero(binding);
  444. binding.bindType = SDL_CONTROLLER_BINDTYPE_HAT;
  445. binding.value.hat.hat = event.jhat.hat;
  446. binding.value.hat.hat_mask = event.jhat.value;
  447. binding.committed = SDL_TRUE;
  448. ConfigureBinding(&binding);
  449. }
  450. }
  451. break;
  452. case SDL_JOYBALLMOTION:
  453. break;
  454. case SDL_JOYBUTTONDOWN:
  455. if (event.jbutton.which == nJoystickID) {
  456. SDL_GameControllerExtendedBind binding;
  457. #ifdef DEBUG_CONTROLLERMAP
  458. SDL_Log("BUTTON %d\n", event.jbutton.button);
  459. #endif
  460. SDL_zero(binding);
  461. binding.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
  462. binding.value.button = event.jbutton.button;
  463. binding.committed = SDL_TRUE;
  464. ConfigureBinding(&binding);
  465. }
  466. break;
  467. case SDL_FINGERDOWN:
  468. case SDL_MOUSEBUTTONDOWN:
  469. /* Skip this step */
  470. SetCurrentBinding(s_iCurrentBinding + 1);
  471. break;
  472. case SDL_KEYDOWN:
  473. if (event.key.keysym.sym == SDLK_BACKSPACE || event.key.keysym.sym == SDLK_AC_BACK) {
  474. SetCurrentBinding(s_iCurrentBinding - 1);
  475. break;
  476. }
  477. if (event.key.keysym.sym == SDLK_SPACE) {
  478. SetCurrentBinding(s_iCurrentBinding + 1);
  479. break;
  480. }
  481. if ((event.key.keysym.sym != SDLK_ESCAPE)) {
  482. break;
  483. }
  484. /* Fall through to signal quit */
  485. case SDL_QUIT:
  486. done = SDL_TRUE;
  487. break;
  488. default:
  489. break;
  490. }
  491. }
  492. SDL_Delay(15);
  493. /* Wait 100 ms for joystick events to stop coming in,
  494. in case a controller sends multiple events for a single control (e.g. axis and button for trigger)
  495. */
  496. if (s_unPendingAdvanceTime && SDL_GetTicks() - s_unPendingAdvanceTime >= 100) {
  497. SetCurrentBinding(s_iCurrentBinding + 1);
  498. }
  499. }
  500. if (s_bBindingComplete) {
  501. char mapping[1024];
  502. char trimmed_name[128];
  503. char *spot;
  504. int iIndex;
  505. char pszElement[12];
  506. SDL_strlcpy(trimmed_name, name, SDL_arraysize(trimmed_name));
  507. while (SDL_isspace(trimmed_name[0])) {
  508. SDL_memmove(&trimmed_name[0], &trimmed_name[1], SDL_strlen(trimmed_name));
  509. }
  510. while (trimmed_name[0] && SDL_isspace(trimmed_name[SDL_strlen(trimmed_name) - 1])) {
  511. trimmed_name[SDL_strlen(trimmed_name) - 1] = '\0';
  512. }
  513. while ((spot = SDL_strchr(trimmed_name, ',')) != NULL) {
  514. SDL_memmove(spot, spot + 1, SDL_strlen(spot));
  515. }
  516. /* Initialize mapping with GUID and name */
  517. SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), mapping, SDL_arraysize(mapping));
  518. SDL_strlcat(mapping, ",", SDL_arraysize(mapping));
  519. SDL_strlcat(mapping, trimmed_name, SDL_arraysize(mapping));
  520. SDL_strlcat(mapping, ",", SDL_arraysize(mapping));
  521. SDL_strlcat(mapping, "platform:", SDL_arraysize(mapping));
  522. SDL_strlcat(mapping, SDL_GetPlatform(), SDL_arraysize(mapping));
  523. SDL_strlcat(mapping, ",", SDL_arraysize(mapping));
  524. for (iIndex = 0; iIndex < SDL_arraysize(s_arrBindings); ++iIndex) {
  525. SDL_GameControllerExtendedBind *pBinding = &s_arrBindings[iIndex];
  526. if (pBinding->bindType == SDL_CONTROLLER_BINDTYPE_NONE) {
  527. continue;
  528. }
  529. if (iIndex < SDL_CONTROLLER_BUTTON_MAX) {
  530. SDL_GameControllerButton eButton = (SDL_GameControllerButton)iIndex;
  531. SDL_strlcat(mapping, SDL_GameControllerGetStringForButton(eButton), SDL_arraysize(mapping));
  532. } else {
  533. const char *pszAxisName;
  534. switch (iIndex - SDL_CONTROLLER_BUTTON_MAX) {
  535. case SDL_CONTROLLER_BINDING_AXIS_LEFTX_NEGATIVE:
  536. if (!BMergeAxisBindings(iIndex)) {
  537. SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
  538. }
  539. pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTX);
  540. break;
  541. case SDL_CONTROLLER_BINDING_AXIS_LEFTX_POSITIVE:
  542. SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
  543. pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTX);
  544. break;
  545. case SDL_CONTROLLER_BINDING_AXIS_LEFTY_NEGATIVE:
  546. if (!BMergeAxisBindings(iIndex)) {
  547. SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
  548. }
  549. pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTY);
  550. break;
  551. case SDL_CONTROLLER_BINDING_AXIS_LEFTY_POSITIVE:
  552. SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
  553. pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTY);
  554. break;
  555. case SDL_CONTROLLER_BINDING_AXIS_RIGHTX_NEGATIVE:
  556. if (!BMergeAxisBindings(iIndex)) {
  557. SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
  558. }
  559. pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTX);
  560. break;
  561. case SDL_CONTROLLER_BINDING_AXIS_RIGHTX_POSITIVE:
  562. SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
  563. pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTX);
  564. break;
  565. case SDL_CONTROLLER_BINDING_AXIS_RIGHTY_NEGATIVE:
  566. if (!BMergeAxisBindings(iIndex)) {
  567. SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
  568. }
  569. pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTY);
  570. break;
  571. case SDL_CONTROLLER_BINDING_AXIS_RIGHTY_POSITIVE:
  572. SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
  573. pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTY);
  574. break;
  575. case SDL_CONTROLLER_BINDING_AXIS_TRIGGERLEFT:
  576. pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_TRIGGERLEFT);
  577. break;
  578. case SDL_CONTROLLER_BINDING_AXIS_TRIGGERRIGHT:
  579. pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
  580. break;
  581. }
  582. SDL_strlcat(mapping, pszAxisName, SDL_arraysize(mapping));
  583. }
  584. SDL_strlcat(mapping, ":", SDL_arraysize(mapping));
  585. pszElement[0] = '\0';
  586. switch (pBinding->bindType) {
  587. case SDL_CONTROLLER_BINDTYPE_BUTTON:
  588. SDL_snprintf(pszElement, sizeof(pszElement), "b%d", pBinding->value.button);
  589. break;
  590. case SDL_CONTROLLER_BINDTYPE_AXIS:
  591. if (pBinding->value.axis.axis_min == 0 && pBinding->value.axis.axis_max == SDL_JOYSTICK_AXIS_MIN) {
  592. /* The negative half axis */
  593. SDL_snprintf(pszElement, sizeof(pszElement), "-a%d", pBinding->value.axis.axis);
  594. } else if (pBinding->value.axis.axis_min == 0 && pBinding->value.axis.axis_max == SDL_JOYSTICK_AXIS_MAX) {
  595. /* The positive half axis */
  596. SDL_snprintf(pszElement, sizeof(pszElement), "+a%d", pBinding->value.axis.axis);
  597. } else {
  598. SDL_snprintf(pszElement, sizeof(pszElement), "a%d", pBinding->value.axis.axis);
  599. if (pBinding->value.axis.axis_min > pBinding->value.axis.axis_max) {
  600. /* Invert the axis */
  601. SDL_strlcat(pszElement, "~", SDL_arraysize(pszElement));
  602. }
  603. }
  604. break;
  605. case SDL_CONTROLLER_BINDTYPE_HAT:
  606. SDL_snprintf(pszElement, sizeof(pszElement), "h%d.%d", pBinding->value.hat.hat, pBinding->value.hat.hat_mask);
  607. break;
  608. default:
  609. SDL_assert(!"Unknown bind type");
  610. break;
  611. }
  612. SDL_strlcat(mapping, pszElement, SDL_arraysize(mapping));
  613. SDL_strlcat(mapping, ",", SDL_arraysize(mapping));
  614. }
  615. SDL_Log("Mapping:\n\n%s\n\n", mapping);
  616. /* Print to stdout as well so the user can cat the output somewhere */
  617. printf("%s\n", mapping);
  618. }
  619. SDL_free(s_arrAxisState);
  620. s_arrAxisState = NULL;
  621. SDL_DestroyRenderer(screen);
  622. SDL_DestroyWindow(window);
  623. }
  624. int
  625. main(int argc, char *argv[])
  626. {
  627. const char *name;
  628. int i;
  629. SDL_Joystick *joystick;
  630. /* Enable standard application logging */
  631. SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
  632. /* Initialize SDL (Note: video is required to start event loop) */
  633. if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
  634. SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
  635. exit(1);
  636. }
  637. /* Print information about the joysticks */
  638. SDL_Log("There are %d joysticks attached\n", SDL_NumJoysticks());
  639. for (i = 0; i < SDL_NumJoysticks(); ++i) {
  640. name = SDL_JoystickNameForIndex(i);
  641. SDL_Log("Joystick %d: %s\n", i, name ? name : "Unknown Joystick");
  642. joystick = SDL_JoystickOpen(i);
  643. if (joystick == NULL) {
  644. SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_JoystickOpen(%d) failed: %s\n", i,
  645. SDL_GetError());
  646. } else {
  647. char guid[64];
  648. SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick),
  649. guid, sizeof (guid));
  650. SDL_Log(" axes: %d\n", SDL_JoystickNumAxes(joystick));
  651. SDL_Log(" balls: %d\n", SDL_JoystickNumBalls(joystick));
  652. SDL_Log(" hats: %d\n", SDL_JoystickNumHats(joystick));
  653. SDL_Log(" buttons: %d\n", SDL_JoystickNumButtons(joystick));
  654. SDL_Log("instance id: %d\n", SDL_JoystickInstanceID(joystick));
  655. SDL_Log(" guid: %s\n", guid);
  656. SDL_Log(" VID/PID: 0x%.4x/0x%.4x\n", SDL_JoystickGetVendor(joystick), SDL_JoystickGetProduct(joystick));
  657. SDL_JoystickClose(joystick);
  658. }
  659. }
  660. #ifdef __ANDROID__
  661. if (SDL_NumJoysticks() > 0) {
  662. #else
  663. if (argv[1]) {
  664. #endif
  665. int device;
  666. #ifdef __ANDROID__
  667. device = 0;
  668. #else
  669. device = atoi(argv[1]);
  670. #endif
  671. joystick = SDL_JoystickOpen(device);
  672. if (joystick == NULL) {
  673. SDL_Log("Couldn't open joystick %d: %s\n", device, SDL_GetError());
  674. } else {
  675. WatchJoystick(joystick);
  676. SDL_JoystickClose(joystick);
  677. }
  678. }
  679. else {
  680. SDL_Log("\n\nUsage: ./controllermap number\nFor example: ./controllermap 0\nOr: ./controllermap 0 >> gamecontrollerdb.txt");
  681. }
  682. SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK);
  683. return 0;
  684. }
  685. #else
  686. int
  687. main(int argc, char *argv[])
  688. {
  689. SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL compiled without Joystick support.\n");
  690. exit(1);
  691. }
  692. #endif
  693. /* vi: set ts=4 sw=4 expandtab: */