input.c 25 KB

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