input.c 23 KB

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