input.c 25 KB

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