gamepad-rumble.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /*
  2. * This example rumbles gamepads on button presses.
  3. *
  4. * This code is public domain. Feel free to use it for any purpose!
  5. */
  6. #define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
  7. #include <SDL3/SDL.h>
  8. #include <SDL3/SDL_main.h>
  9. /* We will use this renderer to draw into this window every frame. */
  10. static SDL_Window *window = NULL;
  11. static SDL_Renderer *renderer = NULL;
  12. typedef struct GamepadInfo
  13. {
  14. SDL_JoystickID gamepad_id;
  15. const char *action;
  16. } GamepadInfo;
  17. static GamepadInfo gamepads_info[16]; /* if you have more than this, we'll ignore it. */
  18. static GamepadInfo *FindGamepadInfo(SDL_JoystickID which)
  19. {
  20. int i;
  21. for (i = 0; i < SDL_arraysize(gamepads_info); i++) {
  22. if (gamepads_info[i].gamepad_id == which) {
  23. return &gamepads_info[i];
  24. }
  25. }
  26. return NULL; /* not found */
  27. }
  28. /* This function runs once at startup. */
  29. SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
  30. {
  31. SDL_SetAppMetadata("Example Input Gamepad Rumble", "1.0", "com.example.input-gamepad-rumble");
  32. if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD)) {
  33. SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
  34. return SDL_APP_FAILURE;
  35. }
  36. if (!SDL_CreateWindowAndRenderer("examples/input/gamepad-rumble", 640, 480, SDL_WINDOW_RESIZABLE, &window, &renderer)) {
  37. SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
  38. return SDL_APP_FAILURE;
  39. }
  40. return SDL_APP_CONTINUE; /* carry on with the program! */
  41. }
  42. /* This function runs when a new event (mouse input, keypresses, etc) occurs. */
  43. SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
  44. {
  45. GamepadInfo *info;
  46. if (event->type == SDL_EVENT_QUIT) {
  47. return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
  48. } else if (event->type == SDL_EVENT_GAMEPAD_ADDED) {
  49. /* this event is sent for each hotplugged stick, but also each already-connected gamepad during SDL_Init(). */
  50. SDL_OpenGamepad(event->gdevice.which);
  51. info = FindGamepadInfo(0); /* find an empty space */
  52. if (info) {
  53. info->gamepad_id = event->gdevice.which;
  54. info->action = "idle";
  55. }
  56. } else if (event->type == SDL_EVENT_GAMEPAD_REMOVED) {
  57. SDL_Gamepad *gamepad = SDL_GetGamepadFromID(event->gdevice.which);
  58. SDL_CloseGamepad(gamepad);
  59. info = FindGamepadInfo(event->gdevice.which);
  60. if (info) {
  61. info->gamepad_id = 0;
  62. }
  63. } else if (event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) {
  64. SDL_Gamepad *gamepad = SDL_GetGamepadFromID(event->gbutton.which);
  65. info = FindGamepadInfo(event->gbutton.which);
  66. switch (event->gbutton.button) {
  67. case SDL_GAMEPAD_BUTTON_SOUTH:
  68. SDL_RumbleGamepad(gamepad, 0xFFFF, 0x0000, 5000);
  69. if (info) {
  70. info->action = "rumble high frequency";
  71. }
  72. break;
  73. case SDL_GAMEPAD_BUTTON_EAST:
  74. SDL_RumbleGamepad(gamepad, 0x0000, 0xFFFF, 5000);
  75. if (info) {
  76. info->action = "rumble low frequency";
  77. }
  78. break;
  79. default:
  80. break;
  81. }
  82. } else if (event->type == SDL_EVENT_GAMEPAD_BUTTON_UP) {
  83. SDL_Gamepad *gamepad = SDL_GetGamepadFromID(event->gbutton.which);
  84. SDL_RumbleGamepad(gamepad, 0x0000, 0x0000, 0);
  85. info = FindGamepadInfo(event->gbutton.which);
  86. if (info) {
  87. info->action = "idle";
  88. }
  89. }
  90. return SDL_APP_CONTINUE; /* carry on with the program! */
  91. }
  92. static void draw_centered_text(const int rw, int *y, const char *str)
  93. {
  94. const int x = (rw - (((int) SDL_strlen(str)) * SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE)) / 2;
  95. if (*str) {
  96. SDL_RenderDebugText(renderer, (float) x, (float) *y, str);
  97. }
  98. *y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 2;
  99. }
  100. /* This function runs once per frame, and is the heart of the program. */
  101. SDL_AppResult SDL_AppIterate(void *appstate)
  102. {
  103. int rw, rh, y, i;
  104. SDL_GetCurrentRenderOutputSize(renderer, &rw, &rh);
  105. SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); /* clear to black */
  106. SDL_RenderClear(renderer);
  107. y = SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 8;
  108. SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255); /* yellow text */
  109. draw_centered_text(rw, &y, "Connect gamepads and press buttons to rumble.");
  110. y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 3;
  111. /* report all the visible joysticks and what they are doing at the moment. */
  112. SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); /* white text */
  113. for (i = 0; i < SDL_arraysize(gamepads_info); i++) {
  114. const SDL_JoystickID which = gamepads_info[i].gamepad_id;
  115. if (which == 0) {
  116. draw_centered_text(rw, &y, ""); /* just leave a blank line. */
  117. } else {
  118. char str[128];
  119. SDL_snprintf(str, sizeof (str), "%s: %s", SDL_GetGamepadNameForID(which), gamepads_info[i].action);
  120. draw_centered_text(rw, &y, str);
  121. }
  122. }
  123. SDL_RenderPresent(renderer);
  124. return SDL_APP_CONTINUE; /* carry on with the program! */
  125. }
  126. /* This function runs once at shutdown. */
  127. void SDL_AppQuit(void *appstate, SDL_AppResult result)
  128. {
  129. SDL_Quit();
  130. /* SDL will clean up the window/renderer for us. We let the gamepads leak. */
  131. }