input.c 23 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099
  1. /* -*- mode: c; tab-width: 4; c-basic-offset: 3; c-file-style: "linux" -*- */
  2. //
  3. // Copyright (c) 2009, Wei Mingzhi <whistler_wmz@users.sf.net>.
  4. // Portions Copyright (c) 2009, netwan.
  5. //
  6. // All rights reserved.
  7. //
  8. // This file is part of SDLPAL.
  9. //
  10. // SDLPAL is free software: you can redistribute it and/or modify
  11. // it under the terms of the GNU General Public License as published by
  12. // the Free Software Foundation, either version 3 of the License, or
  13. // (at your option) any later version.
  14. //
  15. // This program is distributed in the hope that it will be useful,
  16. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. // GNU General Public License for more details.
  19. //
  20. // You should have received a copy of the GNU General Public License
  21. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. //
  23. #include "main.h"
  24. #include <math.h>
  25. volatile PALINPUTSTATE g_InputState;
  26. #if PAL_HAS_JOYSTICKS
  27. static SDL_Joystick *g_pJoy = NULL;
  28. #endif
  29. #if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION <= 2
  30. #define SDL_JoystickNameForIndex SDL_JoystickName
  31. #endif
  32. BOOL g_fUseJoystick = TRUE;
  33. static void _default_init_filter() {}
  34. static int _default_input_event_filter(const SDL_Event *event, volatile PALINPUTSTATE *state) { return 0; }
  35. static void _default_input_shutdown_filter() {}
  36. static void (*input_init_filter)() = _default_init_filter;
  37. static int (*input_event_filter)(const SDL_Event *, volatile PALINPUTSTATE *) = _default_input_event_filter;
  38. static void (*input_shutdown_filter)() = _default_input_shutdown_filter;
  39. static VOID
  40. PAL_KeyboardEventFilter(
  41. const SDL_Event *lpEvent
  42. )
  43. /*++
  44. Purpose:
  45. Handle keyboard events.
  46. Parameters:
  47. [IN] lpEvent - pointer to the event.
  48. Return value:
  49. None.
  50. --*/
  51. {
  52. switch (lpEvent->type)
  53. {
  54. case SDL_KEYDOWN:
  55. //
  56. // Pressed a key
  57. //
  58. if (lpEvent->key.keysym.mod & KMOD_ALT)
  59. {
  60. if (lpEvent->key.keysym.sym == SDLK_RETURN)
  61. {
  62. //
  63. // Pressed Alt+Enter (toggle fullscreen)...
  64. //
  65. VIDEO_ToggleFullscreen();
  66. return;
  67. }
  68. else if (lpEvent->key.keysym.sym == SDLK_F4)
  69. {
  70. //
  71. // Pressed Alt+F4 (Exit program)...
  72. //
  73. PAL_Shutdown(0);
  74. }
  75. }
  76. switch (lpEvent->key.keysym.sym)
  77. {
  78. case SDLK_UP:
  79. case SDLK_KP8:
  80. if (gpGlobals->fInBattle || g_InputState.dir != kDirNorth)
  81. {
  82. g_InputState.prevdir = (gpGlobals->fInBattle ? kDirUnknown : g_InputState.dir);
  83. g_InputState.dir = kDirNorth;
  84. g_InputState.dwKeyPress |= kKeyUp;
  85. }
  86. break;
  87. case SDLK_DOWN:
  88. case SDLK_KP2:
  89. if (gpGlobals->fInBattle || g_InputState.dir != kDirSouth)
  90. {
  91. g_InputState.prevdir = (gpGlobals->fInBattle ? kDirUnknown : g_InputState.dir);
  92. g_InputState.dir = kDirSouth;
  93. g_InputState.dwKeyPress |= kKeyDown;
  94. }
  95. break;
  96. case SDLK_LEFT:
  97. case SDLK_KP4:
  98. if (gpGlobals->fInBattle || g_InputState.dir != kDirWest)
  99. {
  100. g_InputState.prevdir = (gpGlobals->fInBattle ? kDirUnknown : g_InputState.dir);
  101. g_InputState.dir = kDirWest;
  102. g_InputState.dwKeyPress |= kKeyLeft;
  103. }
  104. break;
  105. case SDLK_RIGHT:
  106. case SDLK_KP6:
  107. if (gpGlobals->fInBattle || g_InputState.dir != kDirEast)
  108. {
  109. g_InputState.prevdir = (gpGlobals->fInBattle ? kDirUnknown : g_InputState.dir);
  110. g_InputState.dir = kDirEast;
  111. g_InputState.dwKeyPress |= kKeyRight;
  112. }
  113. break;
  114. case SDLK_ESCAPE:
  115. case SDLK_INSERT:
  116. case SDLK_LALT:
  117. case SDLK_RALT:
  118. case SDLK_KP0:
  119. g_InputState.dwKeyPress |= kKeyMenu;
  120. break;
  121. case SDLK_RETURN:
  122. case SDLK_SPACE:
  123. case SDLK_KP_ENTER:
  124. case SDLK_LCTRL:
  125. g_InputState.dwKeyPress |= kKeySearch;
  126. break;
  127. case SDLK_PAGEUP:
  128. case SDLK_KP9:
  129. g_InputState.dwKeyPress |= kKeyPgUp;
  130. break;
  131. case SDLK_PAGEDOWN:
  132. case SDLK_KP3:
  133. g_InputState.dwKeyPress |= kKeyPgDn;
  134. break;
  135. case SDLK_HOME:
  136. g_InputState.dwKeyPress |= kKeyHome;
  137. break;
  138. case SDLK_END:
  139. g_InputState.dwKeyPress |= kKeyEnd;
  140. break;
  141. case SDLK_7: //7 for mobile device
  142. case SDLK_r:
  143. g_InputState.dwKeyPress |= kKeyRepeat;
  144. break;
  145. case SDLK_2: //2 for mobile device
  146. case SDLK_a:
  147. g_InputState.dwKeyPress |= kKeyAuto;
  148. break;
  149. case SDLK_d:
  150. g_InputState.dwKeyPress |= kKeyDefend;
  151. break;
  152. case SDLK_e:
  153. g_InputState.dwKeyPress |= kKeyUseItem;
  154. break;
  155. case SDLK_w:
  156. g_InputState.dwKeyPress |= kKeyThrowItem;
  157. break;
  158. case SDLK_q:
  159. g_InputState.dwKeyPress |= kKeyFlee;
  160. break;
  161. case SDLK_s:
  162. g_InputState.dwKeyPress |= kKeyStatus;
  163. break;
  164. case SDLK_f:
  165. case SDLK_5: // 5 for mobile device
  166. g_InputState.dwKeyPress |= kKeyForce;
  167. break;
  168. case SDLK_HASH: //# for mobile device
  169. case SDLK_p:
  170. VIDEO_SaveScreenshot();
  171. break;
  172. default:
  173. break;
  174. }
  175. break;
  176. case SDL_KEYUP:
  177. //
  178. // Released a key
  179. //
  180. switch (lpEvent->key.keysym.sym)
  181. {
  182. case SDLK_UP:
  183. case SDLK_KP8:
  184. if (g_InputState.dir == kDirNorth)
  185. {
  186. g_InputState.dir = g_InputState.prevdir;
  187. }
  188. g_InputState.prevdir = kDirUnknown;
  189. break;
  190. case SDLK_DOWN:
  191. case SDLK_KP2:
  192. if (g_InputState.dir == kDirSouth)
  193. {
  194. g_InputState.dir = g_InputState.prevdir;
  195. }
  196. g_InputState.prevdir = kDirUnknown;
  197. break;
  198. case SDLK_LEFT:
  199. case SDLK_KP4:
  200. if (g_InputState.dir == kDirWest)
  201. {
  202. g_InputState.dir = g_InputState.prevdir;
  203. }
  204. g_InputState.prevdir = kDirUnknown;
  205. break;
  206. case SDLK_RIGHT:
  207. case SDLK_KP6:
  208. if (g_InputState.dir == kDirEast)
  209. {
  210. g_InputState.dir = g_InputState.prevdir;
  211. }
  212. g_InputState.prevdir = kDirUnknown;
  213. break;
  214. default:
  215. break;
  216. }
  217. break;
  218. }
  219. }
  220. static VOID
  221. PAL_MouseEventFilter(
  222. const SDL_Event *lpEvent
  223. )
  224. /*++
  225. Purpose:
  226. Handle mouse events.
  227. Parameters:
  228. [IN] lpEvent - pointer to the event.
  229. Return value:
  230. None.
  231. --*/
  232. {
  233. #if PAL_HAS_MOUSE
  234. static short hitTest = 0; // Double click detect;
  235. const SDL_VideoInfo *vi;
  236. double screenWidth, gridWidth;
  237. double screenHeight, gridHeight;
  238. double mx, my;
  239. double thumbx;
  240. double thumby;
  241. INT gridIndex;
  242. BOOL isLeftMouseDBClick = FALSE;
  243. BOOL isLeftMouseClick = FALSE;
  244. BOOL isRightMouseClick = FALSE;
  245. static INT lastReleaseButtonTime, lastPressButtonTime, betweenTime;
  246. static INT lastPressx = 0;
  247. static INT lastPressy = 0;
  248. static INT lastReleasex = 0;
  249. static INT lastReleasey = 0;
  250. if (lpEvent->type!= SDL_MOUSEBUTTONDOWN && lpEvent->type != SDL_MOUSEBUTTONUP)
  251. return;
  252. vi = SDL_GetVideoInfo();
  253. screenWidth = vi->current_w;
  254. screenHeight = vi->current_h;
  255. gridWidth = screenWidth / 3;
  256. gridHeight = screenHeight / 3;
  257. mx = lpEvent->button.x;
  258. my = lpEvent->button.y;
  259. thumbx = ceil(mx / gridWidth);
  260. thumby = floor(my / gridHeight);
  261. gridIndex = thumbx + thumby * 3 - 1;
  262. switch (lpEvent->type)
  263. {
  264. case SDL_MOUSEBUTTONDOWN:
  265. lastPressButtonTime = SDL_GetTicks();
  266. lastPressx = lpEvent->button.x;
  267. lastPressy = lpEvent->button.y;
  268. switch (gridIndex)
  269. {
  270. case 2:
  271. g_InputState.prevdir = g_InputState.dir;
  272. g_InputState.dir = kDirNorth;
  273. break;
  274. case 6:
  275. g_InputState.prevdir = g_InputState.dir;
  276. g_InputState.dir = kDirSouth;
  277. break;
  278. case 0:
  279. g_InputState.prevdir = g_InputState.dir;
  280. g_InputState.dir = kDirWest;
  281. break;
  282. case 8:
  283. g_InputState.prevdir = g_InputState.dir;
  284. g_InputState.dir = kDirEast;
  285. break;
  286. case 1:
  287. //g_InputState.prevdir = g_InputState.dir;
  288. //g_InputState.dir = kDirNorth;
  289. g_InputState.dwKeyPress |= kKeyUp;
  290. break;
  291. case 7:
  292. //g_InputState.prevdir = g_InputState.dir;
  293. //g_InputState.dir = kDirSouth;
  294. g_InputState.dwKeyPress |= kKeyDown;
  295. break;
  296. case 3:
  297. //g_InputState.prevdir = g_InputState.dir;
  298. //g_InputState.dir = kDirWest;
  299. g_InputState.dwKeyPress |= kKeyLeft;
  300. break;
  301. case 5:
  302. //g_InputState.prevdir = g_InputState.dir;
  303. //g_InputState.dir = kDirEast;
  304. g_InputState.dwKeyPress |= kKeyRight;
  305. break;
  306. }
  307. break;
  308. case SDL_MOUSEBUTTONUP:
  309. lastReleaseButtonTime = SDL_GetTicks();
  310. lastReleasex = lpEvent->button.x;
  311. lastReleasey = lpEvent->button.y;
  312. hitTest ++;
  313. if (abs(lastPressx - lastReleasex) < 25 &&
  314. abs(lastPressy - lastReleasey) < 25)
  315. {
  316. betweenTime = lastReleaseButtonTime - lastPressButtonTime;
  317. if (betweenTime >500)
  318. {
  319. isRightMouseClick = TRUE;
  320. }
  321. else if (betweenTime >=0)
  322. {
  323. if((betweenTime < 100) && (hitTest >= 2))
  324. {
  325. isLeftMouseClick = TRUE;
  326. hitTest = 0;
  327. }
  328. else
  329. {
  330. isLeftMouseClick = TRUE;
  331. if(betweenTime > 100)
  332. {
  333. hitTest = 0;
  334. }
  335. }
  336. }
  337. }
  338. switch (gridIndex)
  339. {
  340. case 2:
  341. if( isLeftMouseDBClick )
  342. {
  343. AUDIO_IncreaseVolume();
  344. break;
  345. }
  346. case 6:
  347. case 0:
  348. if( isLeftMouseDBClick )
  349. {
  350. AUDIO_DecreaseVolume();
  351. break;
  352. }
  353. case 7:
  354. if (isRightMouseClick) //repeat attack
  355. {
  356. g_InputState.dwKeyPress |= kKeyRepeat;
  357. break;
  358. }
  359. case 8:
  360. g_InputState.dir = kDirUnknown;
  361. g_InputState.prevdir = kDirUnknown;
  362. break;
  363. case 1:
  364. if( isRightMouseClick )
  365. {
  366. g_InputState.dwKeyPress |= kKeyForce;
  367. }
  368. break;
  369. case 3:
  370. if( isRightMouseClick )
  371. {
  372. g_InputState.dwKeyPress |= kKeyAuto;
  373. }
  374. break;
  375. case 5:
  376. if( isRightMouseClick )
  377. {
  378. g_InputState.dwKeyPress |= kKeyDefend;
  379. }
  380. break;
  381. case 4:
  382. if (isRightMouseClick) // menu
  383. {
  384. g_InputState.dwKeyPress |= kKeyMenu;
  385. }
  386. else if (isLeftMouseClick) // search
  387. {
  388. g_InputState.dwKeyPress |= kKeySearch;
  389. }
  390. break;
  391. }
  392. break;
  393. }
  394. #endif
  395. }
  396. static VOID
  397. PAL_JoystickEventFilter(
  398. const SDL_Event *lpEvent
  399. )
  400. /*++
  401. Purpose:
  402. Handle joystick events.
  403. Parameters:
  404. [IN] lpEvent - pointer to the event.
  405. Return value:
  406. None.
  407. --*/
  408. {
  409. #if PAL_HAS_JOYSTICKS
  410. switch (lpEvent->type)
  411. {
  412. case SDL_JOYAXISMOTION:
  413. //
  414. // Moved an axis on joystick
  415. //
  416. switch (lpEvent->jaxis.axis)
  417. {
  418. case 0:
  419. //
  420. // X axis
  421. //
  422. if (lpEvent->jaxis.value > 20000)
  423. {
  424. if (g_InputState.dir != kDirEast)
  425. {
  426. g_InputState.dwKeyPress |= kKeyRight;
  427. }
  428. g_InputState.prevdir = g_InputState.dir;
  429. g_InputState.dir = kDirEast;
  430. }
  431. else if (lpEvent->jaxis.value < -20000)
  432. {
  433. if (g_InputState.dir != kDirWest)
  434. {
  435. g_InputState.dwKeyPress |= kKeyLeft;
  436. }
  437. g_InputState.prevdir = g_InputState.dir;
  438. g_InputState.dir = kDirWest;
  439. }
  440. else
  441. {
  442. if (g_InputState.prevdir != kDirEast &&
  443. g_InputState.prevdir != kDirWest)
  444. {
  445. g_InputState.dir = g_InputState.prevdir;
  446. }
  447. g_InputState.prevdir = kDirUnknown;
  448. }
  449. break;
  450. case 1:
  451. //
  452. // Y axis
  453. //
  454. if (lpEvent->jaxis.value > 20000)
  455. {
  456. if (g_InputState.dir != kDirSouth)
  457. {
  458. g_InputState.dwKeyPress |= kKeyDown;
  459. }
  460. g_InputState.prevdir = g_InputState.dir;
  461. g_InputState.dir = kDirSouth;
  462. }
  463. else if (lpEvent->jaxis.value < -20000)
  464. {
  465. if (g_InputState.dir != kDirNorth)
  466. {
  467. g_InputState.dwKeyPress |= kKeyUp;
  468. }
  469. g_InputState.prevdir = g_InputState.dir;
  470. g_InputState.dir = kDirNorth;
  471. }
  472. else
  473. {
  474. if (g_InputState.prevdir != kDirNorth &&
  475. g_InputState.prevdir != kDirSouth)
  476. {
  477. g_InputState.dir = g_InputState.prevdir;
  478. }
  479. g_InputState.prevdir = kDirUnknown;
  480. }
  481. break;
  482. }
  483. break;
  484. case SDL_JOYBUTTONDOWN:
  485. //
  486. // Pressed the joystick button
  487. //
  488. switch (lpEvent->jbutton.button & 1)
  489. {
  490. case 0:
  491. g_InputState.dwKeyPress |= kKeyMenu;
  492. break;
  493. case 1:
  494. g_InputState.dwKeyPress |= kKeySearch;
  495. break;
  496. }
  497. break;
  498. }
  499. #endif
  500. }
  501. #if PAL_HAS_TOUCH
  502. #define TOUCH_NONE 0
  503. #define TOUCH_UP 1
  504. #define TOUCH_DOWN 2
  505. #define TOUCH_LEFT 3
  506. #define TOUCH_RIGHT 4
  507. #define TOUCH_BUTTON1 5
  508. #define TOUCH_BUTTON2 6
  509. #define TOUCH_BUTTON3 7
  510. #define TOUCH_BUTTON4 8
  511. static float gfTouchXMin = 0.0f;
  512. static float gfTouchXMax = 1.0f;
  513. static float gfTouchYMin = 0.0f;
  514. static float gfTouchYMax = 1.0f;
  515. VOID
  516. PAL_SetTouchBounds(
  517. DWORD dwScreenWidth,
  518. DWORD dwScreenHeight,
  519. SDL_Rect renderRect
  520. )
  521. {
  522. gfTouchXMin = (float)renderRect.x / dwScreenWidth;
  523. gfTouchXMax = (float)(renderRect.x + renderRect.w) / dwScreenWidth;
  524. gfTouchYMin = (float)renderRect.y / dwScreenHeight;
  525. gfTouchYMax = (float)(renderRect.y + renderRect.h) / dwScreenHeight;
  526. }
  527. static int
  528. PAL_GetTouchArea(
  529. float X,
  530. float Y
  531. )
  532. {
  533. if (X < gfTouchXMin || X > gfTouchXMax || Y < 0.5f || Y > gfTouchYMax)
  534. {
  535. //
  536. // Upper area or cropped area
  537. //
  538. return TOUCH_NONE;
  539. }
  540. else
  541. {
  542. X = (X - gfTouchXMin) / (gfTouchXMax - gfTouchXMin);
  543. Y = (Y - gfTouchYMin) / (gfTouchYMax - gfTouchYMin);
  544. }
  545. if (X < 1.0f / 3)
  546. {
  547. if (Y - 0.5f < (1.0f / 6 - fabsf(X - 1.0f / 3 / 2)) * (0.5f / (1.0f / 3)))
  548. {
  549. return TOUCH_UP;
  550. }
  551. else if (Y - 0.75f > fabsf(X - 1.0f / 3 / 2) * (0.5f / (1.0f / 3)))
  552. {
  553. return TOUCH_DOWN;
  554. }
  555. else if (X < 1.0f / 3 / 2 && fabsf(Y - 0.75f) < 0.25f - X * (0.5f / (1.0f / 3)))
  556. {
  557. return TOUCH_LEFT;
  558. }
  559. else
  560. {
  561. return TOUCH_RIGHT;
  562. }
  563. }
  564. else if (X > 1.0f - 1.0f / 3)
  565. {
  566. if (X < 1.0f - (1.0f / 3 / 2))
  567. {
  568. if (Y < 0.75f)
  569. {
  570. return TOUCH_BUTTON1;
  571. }
  572. else
  573. {
  574. return TOUCH_BUTTON3;
  575. }
  576. }
  577. else
  578. {
  579. if (Y < 0.75f)
  580. {
  581. return TOUCH_BUTTON2;
  582. }
  583. else
  584. {
  585. return TOUCH_BUTTON4;
  586. }
  587. }
  588. }
  589. else
  590. {
  591. return TOUCH_NONE;
  592. }
  593. }
  594. static VOID
  595. PAL_SetTouchAction(
  596. int area
  597. )
  598. {
  599. switch (area)
  600. {
  601. case TOUCH_UP:
  602. g_InputState.dir = kDirNorth;
  603. g_InputState.dwKeyPress |= kKeyUp;
  604. break;
  605. case TOUCH_DOWN:
  606. g_InputState.dir = kDirSouth;
  607. g_InputState.dwKeyPress |= kKeyDown;
  608. break;
  609. case TOUCH_LEFT:
  610. g_InputState.dir = kDirWest;
  611. g_InputState.dwKeyPress |= kKeyLeft;
  612. break;
  613. case TOUCH_RIGHT:
  614. g_InputState.dir = kDirEast;
  615. g_InputState.dwKeyPress |= kKeyRight;
  616. break;
  617. case TOUCH_BUTTON1:
  618. if (gpGlobals->fInBattle)
  619. {
  620. g_InputState.dwKeyPress |= kKeyRepeat;
  621. }
  622. else
  623. {
  624. g_InputState.dwKeyPress |= kKeyForce;
  625. }
  626. break;
  627. case TOUCH_BUTTON2:
  628. g_InputState.dwKeyPress |= kKeyMenu;
  629. break;
  630. case TOUCH_BUTTON3:
  631. g_InputState.dwKeyPress |= kKeyUseItem;
  632. break;
  633. case TOUCH_BUTTON4:
  634. g_InputState.dwKeyPress |= kKeySearch;
  635. break;
  636. }
  637. }
  638. static VOID
  639. PAL_UnsetTouchAction(
  640. int area
  641. )
  642. {
  643. switch (area)
  644. {
  645. case TOUCH_UP:
  646. case TOUCH_DOWN:
  647. case TOUCH_LEFT:
  648. case TOUCH_RIGHT:
  649. g_InputState.dir = kDirUnknown;
  650. break;
  651. }
  652. }
  653. #endif
  654. static VOID
  655. PAL_TouchEventFilter(
  656. const SDL_Event *lpEvent
  657. )
  658. /*++
  659. Purpose:
  660. Handle touch events.
  661. Parameters:
  662. [IN] lpEvent - pointer to the event.
  663. Return value:
  664. None.
  665. --*/
  666. {
  667. #if PAL_HAS_TOUCH
  668. static SDL_TouchID finger1 = -1, finger2 = -1;
  669. static int prev_touch1 = TOUCH_NONE;
  670. static int prev_touch2 = TOUCH_NONE;
  671. switch (lpEvent->type)
  672. {
  673. case SDL_FINGERDOWN:
  674. if (finger1 == -1)
  675. {
  676. int area = PAL_GetTouchArea(lpEvent->tfinger.x, lpEvent->tfinger.y);
  677. finger1 = lpEvent->tfinger.fingerId;
  678. prev_touch1 = area;
  679. PAL_SetTouchAction(area);
  680. }
  681. else if (finger2 == -1)
  682. {
  683. int area = PAL_GetTouchArea(lpEvent->tfinger.x, lpEvent->tfinger.y);
  684. finger2 = lpEvent->tfinger.fingerId;
  685. prev_touch2 = area;
  686. PAL_SetTouchAction(area);
  687. }
  688. break;
  689. case SDL_FINGERUP:
  690. if (lpEvent->tfinger.fingerId == finger1)
  691. {
  692. PAL_UnsetTouchAction(prev_touch1);
  693. finger1 = -1;
  694. prev_touch1 = TOUCH_NONE;
  695. }
  696. else if (lpEvent->tfinger.fingerId == finger2)
  697. {
  698. PAL_UnsetTouchAction(prev_touch2);
  699. finger2 = -1;
  700. prev_touch2 = TOUCH_NONE;
  701. }
  702. break;
  703. case SDL_FINGERMOTION:
  704. if (lpEvent->tfinger.fingerId == finger1)
  705. {
  706. int area = PAL_GetTouchArea(lpEvent->tfinger.x, lpEvent->tfinger.y);
  707. if (prev_touch1 != area && area != TOUCH_NONE)
  708. {
  709. PAL_UnsetTouchAction(prev_touch1);
  710. prev_touch1 = area;
  711. PAL_SetTouchAction(area);
  712. }
  713. }
  714. else if (lpEvent->tfinger.fingerId == finger2)
  715. {
  716. int area = PAL_GetTouchArea(lpEvent->tfinger.x, lpEvent->tfinger.y);
  717. if (prev_touch2 != area && area != TOUCH_NONE)
  718. {
  719. PAL_UnsetTouchAction(prev_touch2);
  720. prev_touch2 = area;
  721. PAL_SetTouchAction(area);
  722. }
  723. }
  724. break;
  725. }
  726. #endif
  727. }
  728. static int SDLCALL
  729. PAL_EventFilter(
  730. const SDL_Event *lpEvent
  731. )
  732. /*++
  733. Purpose:
  734. SDL event filter function. A filter to process all events.
  735. Parameters:
  736. [IN] lpEvent - pointer to the event.
  737. Return value:
  738. 1 = the event will be added to the internal queue.
  739. 0 = the event will be dropped from the queue.
  740. --*/
  741. {
  742. switch (lpEvent->type)
  743. {
  744. #if SDL_VERSION_ATLEAST(2,0,0)
  745. case SDL_WINDOWEVENT:
  746. if (lpEvent->window.event == SDL_WINDOWEVENT_RESIZED)
  747. {
  748. //
  749. // resized the window
  750. //
  751. VIDEO_Resize(lpEvent->window.data1, lpEvent->window.data2);
  752. }
  753. break;
  754. #ifdef __IOS__
  755. case SDL_APP_WILLENTERBACKGROUND:
  756. g_bRenderPaused = TRUE;
  757. break;
  758. case SDL_APP_DIDENTERFOREGROUND:
  759. g_bRenderPaused = FALSE;
  760. VIDEO_UpdateScreen(NULL);
  761. break;
  762. #endif
  763. #else
  764. case SDL_VIDEORESIZE:
  765. //
  766. // resized the window
  767. //
  768. VIDEO_Resize(lpEvent->resize.w, lpEvent->resize.h);
  769. break;
  770. #endif
  771. case SDL_QUIT:
  772. //
  773. // clicked on the close button of the window. Quit immediately.
  774. //
  775. PAL_Shutdown(0);
  776. }
  777. PAL_KeyboardEventFilter(lpEvent);
  778. PAL_MouseEventFilter(lpEvent);
  779. PAL_JoystickEventFilter(lpEvent);
  780. PAL_TouchEventFilter(lpEvent);
  781. //
  782. // All events are handled here; don't put anything to the internal queue
  783. //
  784. return 0;
  785. }
  786. VOID
  787. PAL_ClearKeyState(
  788. VOID
  789. )
  790. /*++
  791. Purpose:
  792. Clear the record of pressed keys.
  793. Parameters:
  794. None.
  795. Return value:
  796. None.
  797. --*/
  798. {
  799. g_InputState.dwKeyPress = 0;
  800. }
  801. VOID
  802. PAL_InitInput(
  803. VOID
  804. )
  805. /*++
  806. Purpose:
  807. Initialize the input subsystem.
  808. Parameters:
  809. None.
  810. Return value:
  811. None.
  812. --*/
  813. {
  814. memset((void *)&g_InputState, 0, sizeof(g_InputState));
  815. g_InputState.dir = kDirUnknown;
  816. g_InputState.prevdir = kDirUnknown;
  817. //
  818. // Check for joystick
  819. //
  820. #if PAL_HAS_JOYSTICKS
  821. if (SDL_NumJoysticks() > 0 && g_fUseJoystick)
  822. {
  823. int i;
  824. for (i = 0; i < SDL_NumJoysticks(); i++)
  825. {
  826. //
  827. // HACKHACK: applesmc and Android Accelerometer shouldn't be considered as real joysticks
  828. //
  829. if (strcmp(SDL_JoystickNameForIndex(i), "applesmc") != 0 && strcmp(SDL_JoystickNameForIndex(i), "Android Accelerometer") != 0)
  830. {
  831. g_pJoy = SDL_JoystickOpen(i);
  832. break;
  833. }
  834. }
  835. if (g_pJoy != NULL)
  836. {
  837. SDL_JoystickEventState(SDL_ENABLE);
  838. }
  839. }
  840. #endif
  841. #ifdef PAL_ALLOW_KEYREPEAT
  842. SDL_EnableKeyRepeat(0, 0);
  843. #endif
  844. input_init_filter();
  845. }
  846. VOID
  847. PAL_ShutdownInput(
  848. VOID
  849. )
  850. /*++
  851. Purpose:
  852. Shutdown the input subsystem.
  853. Parameters:
  854. None.
  855. Return value:
  856. None.
  857. --*/
  858. {
  859. #if PAL_HAS_JOYSTICKS
  860. # if SDL_VERSION_ATLEAST(2,0,0)
  861. if (g_pJoy != NULL)
  862. {
  863. SDL_JoystickClose(g_pJoy);
  864. g_pJoy = NULL;
  865. }
  866. # else
  867. if (SDL_JoystickOpened(0))
  868. {
  869. assert(g_pJoy != NULL);
  870. SDL_JoystickClose(g_pJoy);
  871. g_pJoy = NULL;
  872. }
  873. # endif
  874. #endif
  875. input_shutdown_filter();
  876. }
  877. VOID
  878. PAL_ProcessEvent(
  879. VOID
  880. )
  881. /*++
  882. Purpose:
  883. Process all events.
  884. Parameters:
  885. None.
  886. Return value:
  887. None.
  888. --*/
  889. {
  890. #if PAL_HAS_NATIVEMIDI
  891. MIDI_CheckLoop();
  892. #endif
  893. while (PAL_PollEvent(NULL));
  894. }
  895. int
  896. PAL_PollEvent(
  897. SDL_Event *event
  898. )
  899. /*++
  900. Purpose:
  901. Poll and process one event.
  902. Parameters:
  903. [OUT] event - Events polled from SDL.
  904. Return value:
  905. Return value of PAL_PollEvent.
  906. --*/
  907. {
  908. SDL_Event evt;
  909. int ret = SDL_PollEvent(&evt);
  910. if (ret != 0 && !input_event_filter(&evt, &g_InputState))
  911. {
  912. PAL_EventFilter(&evt);
  913. }
  914. if (event != NULL)
  915. {
  916. *event = evt;
  917. }
  918. return ret;
  919. }
  920. VOID
  921. PAL_RegisterInputFilter(
  922. void (*init_filter)(),
  923. int (*event_filter)(const SDL_Event *, volatile PALINPUTSTATE *),
  924. void (*shutdown_filter)()
  925. )
  926. /*++
  927. Purpose:
  928. Register caller-defined input event filter.
  929. Parameters:
  930. [IN] init_filter - Filter that will be called inside PAL_InitInput
  931. [IN] event_filter - Filter that will be called inside PAL_PollEvent,
  932. return non-zero value from this filter disables
  933. further internal event processing.
  934. [IN] shutdown_filter - Filter that will be called inside PAL_ShutdownInput
  935. Passing NULL to either parameter means the caller does not provide such filter.
  936. Return value:
  937. None.
  938. --*/
  939. {
  940. if (init_filter)
  941. input_init_filter = init_filter;
  942. if (event_filter)
  943. input_event_filter = event_filter;
  944. if (shutdown_filter)
  945. input_shutdown_filter = shutdown_filter;
  946. }