From dc8b1894919788650c4b01c4c21b3df37fff70b4 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sun, 31 May 2026 08:32:17 -0700 Subject: [PATCH] examples: Added input/05-gamepad-rumble --- .../05-gamepad-rumble.vcxproj | 12 +++ examples/CMakeLists.txt | 1 + examples/input/05-gamepad-rumble/README.txt | 1 + .../input/05-gamepad-rumble/gamepad-rumble.c | 83 ++++++++++++++++++ .../input/05-gamepad-rumble/onmouseover.webp | Bin 0 -> 1862 bytes .../input/05-gamepad-rumble/thumbnail.png | Bin 0 -> 362 bytes 6 files changed, 97 insertions(+) create mode 100644 VisualC/examples/input/05-gamepad-rumble/05-gamepad-rumble.vcxproj create mode 100644 examples/input/05-gamepad-rumble/README.txt create mode 100644 examples/input/05-gamepad-rumble/gamepad-rumble.c create mode 100644 examples/input/05-gamepad-rumble/onmouseover.webp create mode 100644 examples/input/05-gamepad-rumble/thumbnail.png diff --git a/VisualC/examples/input/05-gamepad-rumble/05-gamepad-rumble.vcxproj b/VisualC/examples/input/05-gamepad-rumble/05-gamepad-rumble.vcxproj new file mode 100644 index 0000000000..ba30e01ef8 --- /dev/null +++ b/VisualC/examples/input/05-gamepad-rumble/05-gamepad-rumble.vcxproj @@ -0,0 +1,12 @@ + + + + {5F4CC3F4-265F-4295-98E3-19BD09108B39} + + + + + + + + \ No newline at end of file diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 752eb640e3..1e6b086d7e 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -152,6 +152,7 @@ add_sdl_example_executable(input-joystick-polling SOURCES input/01-joystick-poll add_sdl_example_executable(input-joystick-events SOURCES input/02-joystick-events/joystick-events.c) add_sdl_example_executable(input-gamepad-polling SOURCES input/03-gamepad-polling/gamepad-polling.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/gamepad_front.png) add_sdl_example_executable(input-gamepad-events SOURCES input/04-gamepad-events/gamepad-events.c) +add_sdl_example_executable(input-gamepad-rumble SOURCES input/05-gamepad-rumble/gamepad-rumble.c) add_sdl_example_executable(camera-read-and-draw SOURCES camera/01-read-and-draw/read-and-draw.c) add_sdl_example_executable(pen-drawing-lines SOURCES pen/01-drawing-lines/drawing-lines.c) add_sdl_example_executable(asyncio-load-bitmaps SOURCES asyncio/01-load-bitmaps/load-bitmaps.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.png ${CMAKE_CURRENT_SOURCE_DIR}/../test/gamepad_front.png ${CMAKE_CURRENT_SOURCE_DIR}/../test/speaker.png ${CMAKE_CURRENT_SOURCE_DIR}/../test/icon2x.png) diff --git a/examples/input/05-gamepad-rumble/README.txt b/examples/input/05-gamepad-rumble/README.txt new file mode 100644 index 0000000000..b720fbfd6e --- /dev/null +++ b/examples/input/05-gamepad-rumble/README.txt @@ -0,0 +1 @@ +This example code rumbles gamepads when buttons are pressed. diff --git a/examples/input/05-gamepad-rumble/gamepad-rumble.c b/examples/input/05-gamepad-rumble/gamepad-rumble.c new file mode 100644 index 0000000000..e49037a3d8 --- /dev/null +++ b/examples/input/05-gamepad-rumble/gamepad-rumble.c @@ -0,0 +1,83 @@ +/* + * This example rumbles gamepads on button presses. + * + * This code is public domain. Feel free to use it for any purpose! + */ + +#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ +#include +#include + +/* We will use this renderer to draw into this window every frame. */ +static SDL_Window *window = NULL; +static SDL_Renderer *renderer = NULL; + +/* This function runs once at startup. */ +SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) +{ + SDL_SetAppMetadata("Example Input Gamepad Rumble", "1.0", "com.example.input-gamepad-rumble"); + + if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD)) { + SDL_Log("Couldn't initialize SDL: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + if (!SDL_CreateWindowAndRenderer("examples/input/gamepad-rumble", 640, 480, SDL_WINDOW_RESIZABLE, &window, &renderer)) { + SDL_Log("Couldn't create window/renderer: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs when a new event (mouse input, keypresses, etc) occurs. */ +SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) +{ + if (event->type == SDL_EVENT_QUIT) { + return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */ + } else if (event->type == SDL_EVENT_GAMEPAD_ADDED) { + /* this event is sent for each hotplugged stick, but also each already-connected gamepad during SDL_Init(). */ + SDL_OpenGamepad(event->gdevice.which); + } else if (event->type == SDL_EVENT_GAMEPAD_REMOVED) { + SDL_Gamepad *gamepad = SDL_GetGamepadFromID(event->gdevice.which); + SDL_CloseGamepad(gamepad); + } else if (event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) { + SDL_Gamepad *gamepad = SDL_GetGamepadFromID(event->gbutton.which); + switch (event->gbutton.button) { + case SDL_GAMEPAD_BUTTON_SOUTH: + SDL_RumbleGamepad(gamepad, 0xFFFF, 0x0000, 5000); + break; + case SDL_GAMEPAD_BUTTON_EAST: + SDL_RumbleGamepad(gamepad, 0x0000, 0xFFFF, 5000); + break; + default: + break; + } + } else if (event->type == SDL_EVENT_GAMEPAD_BUTTON_UP) { + SDL_Gamepad *gamepad = SDL_GetGamepadFromID(event->gbutton.which); + SDL_RumbleGamepad(gamepad, 0x0000, 0x0000, 0); + } + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once per frame, and is the heart of the program. */ +SDL_AppResult SDL_AppIterate(void *appstate) +{ + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderClear(renderer); + + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDL_RenderDebugText(renderer, 8, 8, "Connect gamepad and press buttons to rumble"); + + SDL_RenderPresent(renderer); + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once at shutdown. */ +void SDL_AppQuit(void *appstate, SDL_AppResult result) +{ + SDL_Quit(); + /* SDL will clean up the window/renderer for us. We let the gamepads leak. */ +} diff --git a/examples/input/05-gamepad-rumble/onmouseover.webp b/examples/input/05-gamepad-rumble/onmouseover.webp new file mode 100644 index 0000000000000000000000000000000000000000..10d0eeffa47df48398c2864f55fea07993865494 GIT binary patch literal 1862 zcmWIYbaS&~XJ80-bqWXzuuw2!XJ80OV3^CO)xh+C(e7>8&M?j8%aj-FoWW=y+nJg7 zr)K8U*8x}lGW=tF`u%}?>;I;|7XMZMWM7!~S&!ik_mA@1_7CclKQZr-KVZ-BZ{fG4 zpICpme>{JA?uQACKbC*y|0(+*sDVJO4lYulxb~ z&-GvGf6H%>`}S|6eS+=G{b~098~zHgO)KJdxVR#1&8+)}d9zp-aQ)t{rH~T8_58Q& z_Jl3hSKA*5?rX|!-McTkyTrxGbphAgH&(hAHRG0>9l&33e{p2m+p1NP)+PBGmW-|VFT%R^%uiVFe z>jv{_Hjy0y+s*`E-uFmfhdI{wozkZRrdRHba)xsln0#RP=h!f-_U-qro0?cZ^v&XZ zcs{>gafhz!OR@aTi-qDtIjz2{9NRzdl@@z7yW$e|W$!=DnbACR@AU+!?Vl%_*9bR1 z%Qnr++b3bS!8vVa{?8L7jqZt?CkOj@dfw3ZnSJ$z$gSVzhyQ+^9*}*x)MtmkSIZ@1 zhX3XM^4-=;o^h=cjaqU)!f35wLf2LG4VUz`HA!B5o`2^Ae?Y>Ok1ZaeD-X7by;;I| z@=+t-?Kv~=*y`;3D*5B;i+X+E1<7jr)}3j+_>k*B>9sE3N|}(hnUbe(yx4jBB6H5~ zgyOk>_HAKaIc2-ocb925GE=Ti;$fL`Hrp}IO4(;c;(fmVYVQ8<(WJkX=yGp+Bs|>q}UN98~_{iy{u=h;z+5}QM z$9LE9kY+Q5519=?Wn6YqU#nQn_L(K?M$A08L)Oh+_>SDZthmsdd=l83**|d7sL^>b#aF6*G-F-){EGpzeY}&iz;;&{Vb7rjAEAZ-K{qv0y zvo|m)XrDiE+T&3q)7|5ej4#ED`xuK`8Z>9l`>8SeH0z2ZlaERG6h7BJx@zLxp2h51 z`dd}!$4{Tr{V|ElX$${r*{BJhWHwy-TiY0<|Np@9X^Z?)C(p8)et!l_{QpLOU6(nh z)lEuuo1zS(`u5dyUz&7O)oE|!gtVAltOcsi4y~IWu6zHeXiMdaD@i{uP0wvFIi${T z@Ib>Qws6t8HNI;$pR{C?*j~CpYT0{EtK)q~&Z%Y0QgF$hZ|cxK?;>mb4L3oBu)QrM zl54(9;6CEt#eXHMR#!!WQ{`;!t-squa=u@^IboNLN!iWMTLru1xJ=R#q+9P@ov7SY zX1*d{;ee<0%EGSP+NO5z9$9(tQV{t91gQpb2PVA&ro>mI-*m7OyH^S zIeO~M*SEc2`!ynJ+gjg?-!!+a{VG@d?cO)Jy+@~6PA@Yu;8!iGN}F5db91rY&UF_z zPdQ`ib!^gkJH6%1@~=7GoOgd~nPikzyG87)=#9Puv(87!sh=-kSyw6TIRCYv*{v6! zt$dS