From 49a4c07e23d2d608162d9d333eb4b5889701713a Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 2 Jun 2026 19:50:05 -0400 Subject: [PATCH] examples/input/05-gamepad-rumble: add some visual feedback. --- .../input/05-gamepad-rumble/gamepad-rumble.c | 72 +++++++++++++++++- .../input/05-gamepad-rumble/onmouseover.webp | Bin 1862 -> 11672 bytes .../input/05-gamepad-rumble/thumbnail.png | Bin 362 -> 1145 bytes 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/examples/input/05-gamepad-rumble/gamepad-rumble.c b/examples/input/05-gamepad-rumble/gamepad-rumble.c index e49037a3d8..b0a504480a 100644 --- a/examples/input/05-gamepad-rumble/gamepad-rumble.c +++ b/examples/input/05-gamepad-rumble/gamepad-rumble.c @@ -12,6 +12,25 @@ static SDL_Window *window = NULL; static SDL_Renderer *renderer = NULL; +typedef struct GamepadInfo +{ + SDL_JoystickID gamepad_id; + const char *action; +} GamepadInfo; + +static GamepadInfo gamepads_info[16]; /* if you have more than this, we'll ignore it. */ + +static GamepadInfo *FindGamepadInfo(SDL_JoystickID which) +{ + int i; + for (i = 0; i < SDL_arraysize(gamepads_info); i++) { + if (gamepads_info[i].gamepad_id == which) { + return &gamepads_info[i]; + } + } + return NULL; /* not found */ +} + /* This function runs once at startup. */ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) { @@ -33,22 +52,39 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) /* This function runs when a new event (mouse input, keypresses, etc) occurs. */ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) { + GamepadInfo *info; 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); + info = FindGamepadInfo(0); /* find an empty space */ + if (info) { + info->gamepad_id = event->gdevice.which; + info->action = "idle"; + } } else if (event->type == SDL_EVENT_GAMEPAD_REMOVED) { SDL_Gamepad *gamepad = SDL_GetGamepadFromID(event->gdevice.which); SDL_CloseGamepad(gamepad); + info = FindGamepadInfo(event->gdevice.which); + if (info) { + info->gamepad_id = 0; + } } else if (event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) { SDL_Gamepad *gamepad = SDL_GetGamepadFromID(event->gbutton.which); + info = FindGamepadInfo(event->gbutton.which); switch (event->gbutton.button) { case SDL_GAMEPAD_BUTTON_SOUTH: SDL_RumbleGamepad(gamepad, 0xFFFF, 0x0000, 5000); + if (info) { + info->action = "rumble high frequency"; + } break; case SDL_GAMEPAD_BUTTON_EAST: SDL_RumbleGamepad(gamepad, 0x0000, 0xFFFF, 5000); + if (info) { + info->action = "rumble low frequency"; + } break; default: break; @@ -56,19 +92,49 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) } else if (event->type == SDL_EVENT_GAMEPAD_BUTTON_UP) { SDL_Gamepad *gamepad = SDL_GetGamepadFromID(event->gbutton.which); SDL_RumbleGamepad(gamepad, 0x0000, 0x0000, 0); + info = FindGamepadInfo(event->gbutton.which); + if (info) { + info->action = "idle"; + } } return SDL_APP_CONTINUE; /* carry on with the program! */ } +static void draw_centered_text(const int rw, int *y, const char *str) +{ + const int x = (rw - (((int) SDL_strlen(str)) * SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE)) / 2; + if (*str) { + SDL_RenderDebugText(renderer, (float) x, (float) *y, str); + } + *y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 2; +} + /* 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); + int rw, rh, y, i; + SDL_GetCurrentRenderOutputSize(renderer, &rw, &rh); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); /* clear to black */ SDL_RenderClear(renderer); - SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); - SDL_RenderDebugText(renderer, 8, 8, "Connect gamepad and press buttons to rumble"); + y = SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 8; + SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255); /* yellow text */ + draw_centered_text(rw, &y, "Connect gamepads and press buttons to rumble."); + y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 3; + + /* report all the visible joysticks and what they are doing at the moment. */ + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); /* white text */ + for (i = 0; i < SDL_arraysize(gamepads_info); i++) { + const SDL_JoystickID which = gamepads_info[i].gamepad_id; + if (which == 0) { + draw_centered_text(rw, &y, ""); /* just leave a blank line. */ + } else { + char str[128]; + SDL_snprintf(str, sizeof (str), "%s: %s", SDL_GetGamepadNameForID(which), gamepads_info[i].action); + draw_centered_text(rw, &y, str); + } + } SDL_RenderPresent(renderer); diff --git a/examples/input/05-gamepad-rumble/onmouseover.webp b/examples/input/05-gamepad-rumble/onmouseover.webp index 10d0eeffa47df48398c2864f55fea07993865494..2e8c8ee1268cdf573cd396eabd7c7c96b4248211 100644 GIT binary patch literal 11672 zcmeHrRZyH=)9nDk2@u@f-2%Zwa3^?hcbDJ{8rwH4zsia zd8h54%r8Dej@%_zz5zPJzIXdpyEJ$L4guh{Q)dv&i(3u+=~S^|E!q?5V~cz?01WlG z2y*MmIm=lUt_Eg;*^fxwyM!OxPM|S9mdT9`~f z27(GPeifc+8tR${%AX^R0HdFwJY#Oq9=oOr|l5xvDIEFe%21yoSZ`_T&t16XMgvTJVn3;)s(WeiR9Y4=6PkTQy1@$`gx;-y;;_u&qc%vto}%d1F<{~A z#(eVw4%hSP13Pt!s>S?(mK!JVt0=HJCVe?NDk`)29iLb>FVRCy@*Mq|PXKa8xOgxX z!jGX9L>A7p8_}AOBtBHEM7zmKn(|=&vi$&*gjunGjD$9qnMp2ISF#!R0VV?$D7~=o zcw2uwa|?@qqhJpWP{Qwcs*YS&62uqC+BB3XC2t$&t6wdw>^v4nh9rzf6iKy8VG4eA zTevg%H%jQ;atJ8L1I8hrUL5AO1n?zyUU39R5`5ZpPNBy|V-LT@RrSv+>=>2^ z>!c0>c`srQ&WgFqkS4S-`p=_-Vij_%9}2C;6;SM<|9$ztN%{Zg|AfN-V>Uhmz>qds zr%(XkoqShOYv~yNOD__-#&Vt>45U?k)13nSnk6<&SlA!SmxLm567vx*ISt;@hRB*; z=R~t^<#3cy^DaOSQmz|%qYmKR@Q!dqhJO6YH0S-YEB>iL*x_*&o`9M;^F~ups)~~Cd*1>7u#beSK01mnJU9~^D)_UBwo8& zY6LmE$pZ^^F}h)$IyktTBXLy>{|3=J!On}q1gpkdP&FjFq3X1cBx1aY-WED(9rAe< z5xZdhjN~S9Hk;aO$3&?>3utfRblm|q3dWB7hnxgvM&vI8g}ylXS|3b@uvN8o zVGj!p_LE4sc+}k<{MR?fYX}WI-GdzPB=22@rzhET<%0;cObDmHY&q8Sv1P|!K{`tm zftHjg$#E)A`a-9u`n8y+D(sA0z3_U3)Nb&QwY%4@a{$X(`dV&?9_@{kfaqQ({gm4! zejrzw#cp$-O2_7kd4Pz35#3V;5p&!V();keqHI9+51OQvZ*B~%LtI#)czO}H<-6sG z6>yA+$34M6ssCWnE~LH4M>$u{0F_d+{@nASCh>Oqv>k}orgX<=sf(|F=k@sQw7WR? zvyf;xNJzRj^8pBz$|;BGqeMv`)%y8@Sot#@6A9dBIUimfbHrQ$X_J$Dav-|ti&cyo z{mUhGcukvA*S@Qt=pfs{0hcW(|8S3SE&)AV)3z|{+Ef&)nXsK>IP-RBfMK67E+JGd zJMBf(Ivhl{P)!AmWCqRDl|%E=*4-J!apbl>bMLO3J{Cp|oAK(o}8W$lBP;u0nDG%-3E+JJ#K#S@t@Po-` zu)dC3OM<+Pe(E}JS03Xtttzio#@Vw9tj^F9OHu%i!7^Sq#- z=v!vSq|lR5=&wr^L*gKV4Bq284Bq|l6W_74Xa0&Jd%PuKNwH&H)axq@#Tx4TmHo?A z%hzwpgScbwT?;?g!)Sl?q2U?k`=&saI?3=3Qf-NT)R!8McGj*p@x+kr!2P7cB`>W3 z42|MY$xh>MPv6=pKCb|L|7OtnCvtFID$A$-6`YFtq~NY!H!5lWm9|nlw=F|ci2*a` z-|g-2Dr4C^Ow-vF%dYHnw-=Lq)R~}ip(3? zWaoZq>bB@#w+Rz^sc;MA4q5upf0vHlFsb$_0rE!I5}wKCspUMt20r_8(J&PivX%== z&)#mqou$jtZj^qG3$Mvlr4{nFron?PH}68!2Ykp$H$-3A>&C+lW5QfF+p%5qVGPMv z0k^IM5jG{u6s^O;7M8lSogcaRkP;KV+_(kstncx#gYA8~L}<2Om_(!b!sjvatoDi) z=py3W1?ZN=s@V8Y2cajyf#V^ElT-MFc0-);x38URrl%CIf!)k})Lv$nde;jR;hC5n z(L;uV@?3b5Dw?s^VHQxotCN3wCQGyZXk5lrBoXDnUkV;CI}Z6UW`9bC(>9@X)5pQ22Vp2nH)Nk*S_%ZIvnETQ;Dg4D-a zQbt^6p@tEK@f~9dH51h$GcONYUmUYM5Q+T5t@G1X9y z-l>ZTh4B)lNVEVx;vZc{;K9QWOfRQx+r@l^gkUci8B_ z%xre7%YA0FR)~;_Sk|oC59veE-7-BshQcbBOEfeJ2`1a5rtSmB)VIM-C2iitj*A#5 zXe#VKL%ypAt=7AVRUU#bgygK;OM!}6M;mT87kboFBA)D=I@$s+JRDLn&9+r+7 zxG(RO;geEC$-VPsSTB@3l4Q%6J*#}6Ow0zE_G2N&-aMg|InZfAftFrYP z>o7&jmFp0Ha=X1B4}w9FQ|u#;jP3QtOhZf5lXwZ@W2IH>Gy?O5XH*bPdA?94$V`0^ z{8RJ=rXC!-?@?P>J7~OB^~rKw1Kx(6<%#<9Ko?IH`}tjm+tC>T*_F+{asWDg9%F%X zOwPPK*VCOwJ8plT6h=!f%LOxr0D?=Gh4Q;93q&UE8_!*mN3ReTw6mEE!*sUxT1M!# zJ8O}U@Zlrf%fVocnc z^hKvITFAg^z;=Joe`YMffn3=fLC3_R?XiGD%S-n>7|I?=$X0$3WhRF_n-$OKoHwp^ zSw;%6Cc-0r@wBXd)^$i9drynxc?ZzIEF=s)l)2O)Az>ZKeF`3Qd&CjgMB?x%qXV3O zJZpL}|In{vg1@e_q@;3``|73W+1SrW*7wa$`A@{*z?w6qab5m6L8rJ~@_f!0jx@MS z`bwi+&!??ce|C9d?1^f?Z1;ZnO1`EowvU&;$Sf>~U%dOv{mP=1nomV%Pc@zxPq8*t zXHbIpbyv}VqWj=nZhN*NbBQB1w&@x*1if*aWS=|xX0n>G(?ieBlu{SHnYtwxo z4)c`b@ZYp@68riLL_XlFosgTb5Zvau9KONhBgAWUb(=tr!4Arohz-( z`nX0tFd~X2eTh(dvnk(y?9EEj@oj!@E5-^Bcn=vbtGHcvoD$9;5s2<|pp{$Qh*U~A z=6CAY>QR{CnKE*_yIqdwMp0@IY=H->H9j&G1ou+sQt&8oV7Hky!;UQGE5pDa^3 zad1|yWEL7#+7PvF^ij4N1&HcK zx@065y(I4IMEzfRf{XK?x$XM%kTF>BBN~yA=ODiv+uc(i0l`3hs_&&3d&@po$_ zzmab%Gt?iSTk7RJQ^gg10P;h_FR_i1lw-EI=wjM@QY}85mRxe5bRT>~?79BkFJ3xGPA{9n;&^DysDqrtVkY)FrHqDrC|_kMqxZ>wnRTpRL$6 zALLBLkVqPkB&1`ixDE+`ZQQTb(K#a}48)M+bKtZN#D>L1 zcO4Wwh@6S2Y##hg=s;Nz7S%0G6~`Q&*H`cUH2-va(=v9%8HG2!jRexalUmaov|-S<4IzDGzvEJZHIXbMX;zmDtsd?TXCI?^w~*rG73o8Uot9 zs<}b$RyC#3q-t~=1rT);(A&DV3b@eC{`1NDE&{;Zcz)iSOsQR)&QxwH0_u*`c&@J> zuB=^rEE&jh*hkVx7R?!Y;snTLx)~?oP{(xreo)}$$oyMdM(-x3b~S4eK2_^VtJ07w z>wQ>C`SQ|vMA3=K`ccoPT2txF>L;*R|8%2jWN=i$@5kWlwKPX#N$dD;IJ5Z zAED^~;FwjY+7AlOvhIi__%wy_06q$)$PI$An)GDJEOiB>F)kWOJSC}RXH@YX+!znV zEw=riWQ=2$8#UOo;k5tJedWUbSiW?9t0a?GwK8%oc6v{P^j{Sw=WK>f1E@e?5Qq zYK?DeHa-AA002mW0>A?R?QcuCzk9XpH$NBY-@RHg6aql#%%of?koH5BAJkHEER?Ox z0Hhzxdnf)JxI!vfJ$4`S>Il-mflzlffc-pJ&q%Lw>T_aQ`yf9c%3zI`kZvr1FbS9w zJah*$!1y5iSt!aQ$iwkf^iCrc`Nr+|pk?TA^Fp{D821`@kNiY?r}#{|D+B#XIb^avB<}d z>^tIFTd>>A4tbhgzh@jjc}2Rub<~ayHUF{q6eWg`GCH<$n>B=;Q>)HwgfuQ1zfgfN z@iN9-Zgq|Akz1LiCyAXUUi2DiY*DmF7AM%fmVqY9Q#^i7_xnvv79DTUH+veh2ARzT zx<~^!t{&g4`uP-68+L=%rHL)%fqgq?yE#Hf8mqCjMRk2?3R zp>>ICg|p~aE`z@MRD|71TXUoJ(soJT-PBh&GElkz!WZg}?6UD!=Q)wk;L0;3Y>?$U zv!+u~Je@{#Xa%s#{LroxrTzDgmh$eRO{C}c(5KBcb7uptqUIL?Ye`xZP3v82wY)HN@36oiO=m=1Fhy7?H^dr6XWQxL>x{3Tr6s?jT0Vl^Qnw@ zh#+mySaRV9+KN#j6wvNl{=DSwj8J(s_vNYP&&`VXfzkv*yJ)lpPtK3mcKj3y`360| z`_0m~7R?hWd%2&oLX^PFDmI;HWNgOsd#| zNZWcilqQWaNm_r|kJoc6x7TEh!x+`cZSE;0bKX(O;ycCE+sVM=gw24)4Kh1{h=oxI z&5iciaewGI#GzRw{Z)1(ZN3isps(7$tDHNunNP?bJJrVqhLgrG1-*Nl6|0}Kv@mMB zq`8o=fOKg~%hg8QJ+m04XZsdre0!wdy*UZxD?8CQLI>?rlE@B=D7R7Fo0gjXeiZ2j zPFQ?x2MxQ)&qt-i@Q3|I^~0@ z+j!#kWq8;@?E#lwn#03+f`B4tvi}TEG`JTw0K~Q!xw*fy10&Zgl;?sZ(k_ZE9q_H$ z@KS0qIcYv@B0b51Mdy}Gc-;7AalX)OT{x#dvOC&RJfYj(D+wuNX*3u6O*NkOTezlI z1rLo=D1Q42Y@cKZfjAvmR8{FH7ue}_^WVs>okwO2Xs>)X(^Gu-o|MnJ&Ht3c_iz;d zn7**7JSTJ~r6e%ate;yqpeYpk^)={M!FpKbr+wZn!3}OR8bpmLg?>a7Rd|zsa^l$t zrW{xnQO`sD%8h>KfT=qaJGFoEjv{D8MpMdr`VYJL6qOAd9eI4H$hy`^0+BR==U+Pe z%U(#ZZ*28OQ~&_=KkRh~^Dlc{zXJeNasRRx&A;qbst7}m+YR`Ky##q4&_+-jn*dgK z-qqLDlwDCr?L6gX@-y0SPA$pd zW)7qtJn}?%%6d(D+;s(M_l5#;f=$8oFXjel3-+e03-;i5Oi`=N@1ufMIaF$v2LzkG zoTCr5QXHJlxDJh><<%lX8ytTKI@bOQ@1zbl1&IAK`qe>M3g0+8V0-6bSke$XuBQN7oEvDa}Uq~NA?p`rF0**IjH#kAr$O|)_S0x(Oqju@8 zqq%#R()M^T{&Gyl#guV;G!J6k!VqMiRsgM)iCOb2*RQ%Ih=R6NUj+m47{U4b_xge7 zB!VsqIH3gkBB_%Gc<)%Q*I>trJrmkF@3(*S?uIui^~?|T$t-G7J71S#4PL2C<#0;o z`I9mn<3(e;$1>@&PGC_6pgL??tRjL=TUhaW5|6CZWEi4NP&6*;iRzBr11Kj6{>ZnKsQJ$WhH01G3loGu0g|)av)RGGUpj4 zbDr(tX$34>w&VVZ67!sw^qH&b zJ+I;L?m&@)fPYZbpYls4o)54bggAQdMsMWjxQ%i8{0}LaB-Be@5sl8 zXjXl-}|H2#d{ObJHn0J^R|a{1Vq;!tA962f<-fK=B5?tn>I~T8J6H7nEbI) zgfx7S7EyYWuDZA`T%MKv0bqGl26%T%!Zsd-Y`X&(($1dK@@)S!Y5aH^c^uPh_{*Xw zdm5uMdN!_<30arI>NMuNyW>y2n$GL!FgmGmF*j{RQqdV-jHN0hpxkSd{a9-)NEI!Hk~2Z5fUwj((Mq#Pi2p0fOT&ISfg+fvmgxMF z70wiXwrNiGUHh>zY}F84=^s6x^}lq)=D&KL z_-{wd{@W4Pb@Jr{!~FaJP|bh!y!xPit*_jjr>7hB)No_8PXefC+P}{26+KGC*OIG?DG*xsygL0B_^~wfMLqj-=E&V|>E9v6_TuJqiSl-KhDXiW zhosO6R(FWJp9+LDJRLKjUcd2}H0kbV0=DpJEBm@4Up;Q6f0=e=E;_Hq*Ba(K2xA z8W5OW56$lN%^)6g`3PK%RglQB*SS22&)DcLM<^S>-2J{gBS)mTz0OjC2|fQ_`!hvG zNl<3pG=2R%$5%#&Gv#vByBkgt-Q3n4McN1PAENgiiXSAA$?MqX&T}#!Q*U6RyNmkf z{opQqT+?cVMQOTD$837icI?zeL>bkCynZ6O>=*?JpFKsSBv#tL z*EHG`@67x#J2l-#X6^HmsU+z-?`rmIE^mAEnQE{2p++Xt7f%*@NzsT0qjwwD(Avm zw;rl8P7EoC-at=6FZ5*xv7lX(^5(J2HVRvVZAt4yd8=Z1+hS~;7RrYc_iWnUC3>hj zZ^0Il$b#FLyrzLOx{&S5`#ldIeiI6>|N9-uF4-UTPBFakR+QXa#B3Yq`tmUkyW;XlC*+0b2^qp4 z%)dhEc4+{?u`-EM8jM&?%m;yxYo~E^bl8}fn-^n<0E3T9 z&!V2Z(CVyzqvkJSPWIfsg)(cDydN9i`_D7)kW+vGjPpE}PdZms%7&|BmSl;vgN*3bn+&QF4Uil3Sh_z>1#pteHKO$&oIWnmYowZjO}R0l z+1S}0IEP#vXX2q|k8&u+!`+;FZl6$b88yD#!}(UDlMZ?|m6Z>|>nf=8Ynjf(RE#JK zpu!`67lCza_k#n>zwPz67GlWWrwEY<#n=)RFvDBGi(sFK^+0PwHv}>lGKbX5c#FRCtS23(>99?FuYBq;2CL&zU#LR`#(Z`k2YY zji;d4HWN4K!ck+t%(e#`&gYbQ2Ci3`iKW|N)lqqT3~vj?Ttam1ENq?k z7?*_}i0D6r<38({h|2t1Fs;9GJ66tJk8Sj&=TZY2NPw9jsOdXjMG0UJ)fvp zTddG;Js(-h&Ofm1pzuH=&Z9At;3x1uV=O37`uS+S-#LytoR#=Zil8c>`>hAMxe97e zsa!W=a}}a_jxNtP?Foci2Y^niM)09e<}U^zk8|wQ2I&*?0gUI>=?*bvuSjFY(<)==``IgucS3wq>wJSf7s(SN$l-94o z)vSoV{i;h5 zoS(5a=>{z2ZfCJCe)w@5r9R0Id%$w14V0^wzeX?^-~Jf}&cmSE(Rbi+Jc4jVW4dN(`$O{>IyZ<9O{OU=;@U$J|3^lMB0 zXx(5E%>B@PSGkk;9eT9;QBg<72{a@(U1c|`oaplujDTCcRGJQ|j6J>Aw*GL25`3sX=Pm|=+t(%XeN_(uzU5k^?XsrA%_sgtTQf9arC{2 zSR5gLZM4I9@)%Vv$z7!^GGC}_C*MP4iv=1NnzkwL)6z;4iRgR*g9IAfmy|HUnvMMPK7PemSRj47xY14UG;G%#KfZds5Nn< z25tGjQM6n-?~umgKbcDdW>Cp>w06aUCW=a|;VpB;bM}RnFqsgf~N-Oo=_~*1U zIk`XV!po{~>puWzU7wSLD&3g5eC~b-ZM|KNXj5%{Kq_*ufqO6 zwpn9$p(M(@w;b)F{2@}aoJ*pg z#Ucz6sP@F-6XLuUeOh`F5A8Yn$XE`W7*w_x&3}F>q;X- z0roNnE)RVLWcZ+UeRP^3x3dNs_1PIPv=<4u+t_K9Kby$#5dO)&2`3#uHA|ikaN(TB z=HZ($)XfLh{%j!Nuu>stTd{P>tYtWR@-3s=nPA z=t9V4Z;OT7hx(%xxKD1SVYW@RkCDbn<*)~q4wE4`<3g75x`FX{fg-%}uBT)sWe&Kq-xl z!6j82A>}x-iV_pOAIZJr-pkdAZojMjq~2Ckp5+OrQZ4W?1eGzEN!~owz8AtU3d#V> z_GL9aX3e^=?G}uxq_y2l?c-jZdmAfZCN1p_rqeB0uZ_+}yFnG3h`hk+Fa_F6TCJ%X9VwyLxnYNU!LX12N zK<&Ze(9&Mwj{|Y)mH;?H<{%!|dJc#s>l0>;kKO5x+Q`Qz2=*bTCG+n_IHSwp&sbL` z&s4nbHl=BKC?3?b^+kg8;Lk^^Jvf`yFqSSER9P}ssk3*c#?w);g1BeRpMLY?l7`%~ zVxi0EeoGSyL)9Z>FtZRPk(PR_)jYiaNDyru7|4R-9^!~5Dl;ozey_5eu;}N<7p};C Ueqwh{OUr9vPc+*6`HgG;2OZ0>ga7~l literal 1862 zcmeH@_dDAO0EfRpxKc$+FPsoXt%jN{+Jx9@0@VMYKq_k0A~{v+6jFXrtvqUaX<-3 znZU&YA=V??oRn&+Wy{+NL6@PA{DY2Sh)ZA4^kd)zw6xEXPU6HLU**Uj1&)?(s{%}c zgQ!^~3-7hX{Z^WW1WqdUsqM$Al0!Ha=FJZkFc_=#tuI>W5)1&B^B=Y- z!@RLgBYS}bGPl`=xZNK-N5MG>x3ZI^sTJ9T_VIMt0$F9Y;5~sSRN=|JTpJxpTc*hpA+V0Z zH#5yW$Sc|^+&pAILHVe5iQB{a>xC_vHhuno`7eKyP&+7y z0zr_Ce2KyA{_r@nTW@mhtt>3271@D|RneKlD_zIC1?a$u2&-0G%fxX_fD>gaou*&8 z%uf=-R4%w^yi&)dG8D+;s?G7@jFn(!zYrQn|CVSjR@a$)eytKT@G^rPD_>F?vE5g$Nz~l$E?(rSO}h$BOrW z{U6$h-hO&mD7A62dkgzO8iy#V1eQ6C59(o=!NBt8mQF$~Cm{ zMMR%*W&rJ>t6U*yD=AfPzVsZ+*Z-u&*6n=`2|BP%e}Y{kKLWG+3s{Gu;{|sicD6!I zk>{9Flz^K_hkgM-V|a>A^z3So5b@PRa0AuTXyc^-uX0Act5KJ^nfsnw8dE9~<1p&s z`_(IKS4XS3u(m_^^B8`m0rHg01ydR6A2k2y$~D&~4*K+CSSBbek)T8@Wh*`%1lM-w z_Cl;eR#bXkWY48P=TlZ|k}ty+6sLXj1ea45Z_G?;^AGVuBQluP z<0G%s2E%9;`gI|xcfDSQnrVgf_>@wH>jp=ucLfd3XJ+%f=^>w?CHbs(0l zK}|fX9EbMDqFMJu@O1^dM-Ys^rI?E767t|8bV^Y;yIJLhU%iC*DqCh7sy(arXldSO zBLrELXa7W>fc`z!O$yL-R@tLWkuL9q4ZYf0K9N%X{+{l6Myop+7e|67o1K;aUgV@} zVAZ&tJKvXYC*Pbtx}PFA=~gw16DGGmr1|taN|Yt}3A(X8AXFu@Yr20%T~J4sDb)^$ Wj2gWkzC+%bdo(j-S|tkn`~CvVUX8Z^ diff --git a/examples/input/05-gamepad-rumble/thumbnail.png b/examples/input/05-gamepad-rumble/thumbnail.png index ffc13aa1e6b9624a8449344170ca32d3ac1522f8..8634cdd1c0cea38b7cf6173b4c8b6ef4130c8c12 100644 GIT binary patch literal 1145 zcmeAS@N?(olHy`uVBq!ia0y~yU}|7sV0^&D3>5L$Z&D7VI0Jk_T!Hj|5MYR_@_Gm4 zXq31{l%yn6u?Oe{q-weXq6XI+}H5xzE(oasoa}JQR((zdL&V>VGJm{GgkY5ojY4 zcyKc&@AmWd;^&|CJl*%|>T~(`KSig7vz_^=_vZ1*Plu=7Uma)rzvBF#KgIuCIZr>m za68GocjJ?%L8pp#zM3EKO3*f&asAOg-LDaRRlRrL%q#1ST^laJol&jN9kK6be%zM> zAD8k^){T?h5o8k*SG4i+L8hBmH{ajhm#}hw%*Ee&N599(e7G?GC8K!l1ZU|*<=We6=GxC3> zZhun$H%m96@~+LC?z20C+@IwbFMlDt^s~Y3oHNId&flSW`>=fOzFRrbpCZ?9|9$J< z&c4@)*PmGh>wo@Vb=&gR7rS}qKg{ESgvkTnHYAX0WYc_ZRiM-@Z>|EG;?me39EvQD~4ZM6sYQ^ze|2CK&%G_GC>Gh}C zC)R4TMg7aM?mTh9)QLZ%b}PG&>4K^DYp*0dY+omM%uMeQV|3sa!JfG7uE*91M)7`W zFxy`hxTRsY`2HKu6jTKmKK#(UW4C?J)0gGGTmSklp3Zjo@Td6v>VKSf>~rovnw|Vn zb@~h4eD2bj0W~+j>h80gb}ekrSruu;^-=FXo!yvYyI`x$?AnvgCui3bzd2pMa;r@= z$DZEj(KW?3xqtu5m@WSjdPki1akMV)yO02+Y(OFN1N(l)mI$x?yJpscax{adtDnm{ Hr-UW|ikR|& delta 316 zcmV-C0mJ_J2Lc@SoYn@h0Lo;lpeNQSUrINm4 zCy9W6!SC04d3V3wb@+xWK?>fv;%J*z8Cw~Liw(qU=SX#ENP0{u# zwypIZbN1f$9=*kuIhS@aFb^eidS;z^OxdF@xvtT(l*~0s#*)uIE~f(@>j>=6N9{Rc zGHQLa7WEa_j=-AFS{^6Qa0IS-8$qAz5jNWB^Eypqa=T?tam%s$&sx@#Z@G=9XxEsQ zk2WvM*xeHIeHk2VY|Hi9a*u0^`|`21_Os7tA9a7<-~COKAp|5B|BJs=Z*xtWlH?8m O0000