PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/apps/action.c

https://github.com/jdgordon/rockbox
C | 445 lines | 332 code | 44 blank | 69 comment | 101 complexity | e03490b1129f30307530038a4fa7aa74 MD5 | raw file
  1. /***************************************************************************
  2. * __________ __ ___.
  3. * Open \______ \ ____ ____ | | _\_ |__ _______ ___
  4. * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
  5. * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
  6. * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
  7. * \/ \/ \/ \/ \/
  8. * $Id$
  9. *
  10. * Copyright (C) 2006 Jonathan Gordon
  11. *
  12. * This program is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU General Public License
  14. * as published by the Free Software Foundation; either version 2
  15. * of the License, or (at your option) any later version.
  16. *
  17. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  18. * KIND, either express or implied.
  19. *
  20. ****************************************************************************/
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <stdlib.h>
  24. #include "config.h"
  25. #include "lang.h"
  26. #include "appevents.h"
  27. #include "button.h"
  28. #include "action.h"
  29. #include "kernel.h"
  30. #include "debug.h"
  31. #include "splash.h"
  32. #include "settings.h"
  33. #include "pcmbuf.h"
  34. #include "misc.h"
  35. #if defined(HAVE_LCD_BITMAP) && !defined(BOOTLOADER)
  36. #include "language.h"
  37. #endif
  38. #include "viewport.h"
  39. #ifdef HAVE_TOUCHSCREEN
  40. #include "statusbar-skinned.h"
  41. #endif
  42. static int last_button = BUTTON_NONE|BUTTON_REL; /* allow the ipod wheel to
  43. work on startup */
  44. static intptr_t last_data = 0;
  45. static int last_action = ACTION_NONE;
  46. static bool repeated = false;
  47. static bool wait_for_release = false;
  48. #ifdef HAVE_TOUCHSCREEN
  49. static bool short_press = false;
  50. #endif
  51. #define REPEAT_WINDOW_TICKS HZ/4
  52. static int last_action_tick = 0;
  53. /* software keylock stuff */
  54. #ifndef HAS_BUTTON_HOLD
  55. static bool keys_locked = false;
  56. static int unlock_combo = BUTTON_NONE;
  57. static bool screen_has_lock = false;
  58. #endif /* HAVE_SOFTWARE_KEYLOCK */
  59. /*
  60. * do_button_check is the worker function for get_default_action.
  61. * returns ACTION_UNKNOWN or the requested return value from the list.
  62. */
  63. static inline int do_button_check(const struct button_mapping *items,
  64. int button, int last_button, int *start)
  65. {
  66. int i = 0;
  67. int ret = ACTION_UNKNOWN;
  68. while (items[i].button_code != BUTTON_NONE)
  69. {
  70. if (items[i].button_code == button)
  71. {
  72. if ((items[i].pre_button_code == BUTTON_NONE)
  73. || (items[i].pre_button_code == last_button))
  74. {
  75. ret = items[i].action_code;
  76. break;
  77. }
  78. }
  79. i++;
  80. }
  81. *start = i;
  82. return ret;
  83. }
  84. #if defined(HAVE_LCD_BITMAP) && !defined(BOOTLOADER)
  85. /*
  86. * button is horizontally inverted to support RTL language if the given language
  87. * and context combination require that
  88. */
  89. static int button_flip_horizontally(int context, int button)
  90. {
  91. int newbutton;
  92. if (!(lang_is_rtl() && ((context == CONTEXT_STD) ||
  93. (context == CONTEXT_TREE) || (context == CONTEXT_LIST) ||
  94. (context == CONTEXT_MAINMENU))))
  95. {
  96. return button;
  97. }
  98. newbutton = button &
  99. ~(BUTTON_LEFT | BUTTON_RIGHT
  100. #if defined(BUTTON_SCROLL_BACK) && defined(BUTTON_SCROLL_FWD) && \
  101. !defined(SIMULATOR)
  102. | BUTTON_SCROLL_BACK | BUTTON_SCROLL_FWD
  103. #endif
  104. #if defined(BUTTON_MINUS) && defined(BUTTON_PLUS) && \
  105. !defined(SIMULATOR)
  106. | BUTTON_MINUS | BUTTON_PLUS
  107. #endif
  108. );
  109. if (button & BUTTON_LEFT)
  110. newbutton |= BUTTON_RIGHT;
  111. if (button & BUTTON_RIGHT)
  112. newbutton |= BUTTON_LEFT;
  113. #if defined(BUTTON_SCROLL_BACK) && defined(BUTTON_SCROLL_FWD) && \
  114. !defined(SIMULATOR)
  115. if (button & BUTTON_SCROLL_BACK)
  116. newbutton |= BUTTON_SCROLL_FWD;
  117. if (button & BUTTON_SCROLL_FWD)
  118. newbutton |= BUTTON_SCROLL_BACK;
  119. #endif
  120. #if defined(BUTTON_MINUS) && defined(BUTTON_PLUS) && \
  121. !defined(SIMULATOR)
  122. if (button & BUTTON_MINUS)
  123. newbutton |= BUTTON_PLUS;
  124. if (button & BUTTON_PLUS)
  125. newbutton |= BUTTON_MINUS;
  126. #endif
  127. return newbutton;
  128. }
  129. #endif
  130. static inline int get_next_context(const struct button_mapping *items, int i)
  131. {
  132. while (items[i].button_code != BUTTON_NONE)
  133. i++;
  134. return (items[i].action_code == ACTION_NONE ) ?
  135. CONTEXT_STD :
  136. items[i].action_code;
  137. }
  138. /*
  139. * int get_action_worker(int context, struct button_mapping *user_mappings,
  140. int timeout)
  141. This function searches the button list for the given context for the just
  142. pressed button.
  143. If there is a match it returns the value from the list.
  144. If there is no match..
  145. the last item in the list "points" to the next context in a chain
  146. so the "chain" is followed until the button is found.
  147. putting ACTION_NONE will get CONTEXT_STD which is always the last list checked.
  148. Timeout can be TIMEOUT_NOBLOCK to return immediatly
  149. TIMEOUT_BLOCK to wait for a button press
  150. Any number >0 to wait that many ticks for a press
  151. */
  152. static int get_action_worker(int context, int timeout,
  153. const struct button_mapping* (*get_context_map)(int) )
  154. {
  155. const struct button_mapping *items = NULL;
  156. int button;
  157. int i=0;
  158. int ret = ACTION_UNKNOWN;
  159. static int last_context = CONTEXT_STD;
  160. send_event(GUI_EVENT_ACTIONUPDATE, NULL);
  161. if (timeout == TIMEOUT_NOBLOCK)
  162. button = button_get(false);
  163. else if (timeout == TIMEOUT_BLOCK)
  164. button = button_get(true);
  165. else
  166. button = button_get_w_tmo(timeout);
  167. /* Data from sys events can be pulled with button_get_data
  168. * multimedia button presses don't go through the action system */
  169. if (button == BUTTON_NONE || button & (SYS_EVENT|BUTTON_MULTIMEDIA))
  170. return button;
  171. /* Don't send any buttons through untill we see the release event */
  172. if (wait_for_release)
  173. {
  174. if (button&BUTTON_REL)
  175. {
  176. /* remember the button for the below button eating on context
  177. * change */
  178. last_button = button;
  179. wait_for_release = false;
  180. }
  181. return ACTION_NONE;
  182. }
  183. #if CONFIG_CODEC == SWCODEC
  184. /* Produce keyclick */
  185. keyclick_click(button);
  186. #endif
  187. if ((context != last_context) && ((last_button & BUTTON_REL) == 0)
  188. #ifdef HAVE_SCROLLWHEEL
  189. /* Scrollwheel doesn't generate release events */
  190. && !(last_button & (BUTTON_SCROLL_BACK | BUTTON_SCROLL_FWD))
  191. #endif
  192. )
  193. {
  194. if (button & BUTTON_REL)
  195. {
  196. last_button = button;
  197. last_action = ACTION_NONE;
  198. }
  199. /* eat all buttons until the previous button was |BUTTON_REL
  200. (also eat the |BUTTON_REL button) */
  201. return ACTION_NONE; /* "safest" return value */
  202. }
  203. last_context = context;
  204. #ifndef HAS_BUTTON_HOLD
  205. screen_has_lock = ((context & ALLOW_SOFTLOCK) == ALLOW_SOFTLOCK);
  206. if (screen_has_lock && keys_locked)
  207. {
  208. if (button == unlock_combo)
  209. {
  210. last_button = BUTTON_NONE;
  211. keys_locked = false;
  212. splash(HZ/2, str(LANG_KEYLOCK_OFF));
  213. return ACTION_REDRAW;
  214. }
  215. else
  216. #if (BUTTON_REMOTE != 0)
  217. if ((button & BUTTON_REMOTE) == 0)
  218. #endif
  219. {
  220. if ((button & BUTTON_REL))
  221. splash(HZ/2, str(LANG_KEYLOCK_ON));
  222. return ACTION_REDRAW;
  223. }
  224. }
  225. context &= ~ALLOW_SOFTLOCK;
  226. #endif /* HAS_BUTTON_HOLD */
  227. #ifdef HAVE_TOUCHSCREEN
  228. if (button & BUTTON_TOUCHSCREEN)
  229. {
  230. repeated = false;
  231. short_press = false;
  232. if (last_button & BUTTON_TOUCHSCREEN)
  233. {
  234. if ((button & BUTTON_REL) &&
  235. ((last_button & BUTTON_REPEAT)==0))
  236. {
  237. short_press = true;
  238. }
  239. else if (button & BUTTON_REPEAT)
  240. repeated = true;
  241. }
  242. last_button = button;
  243. return ACTION_TOUCHSCREEN;
  244. }
  245. #endif
  246. #if defined(HAVE_LCD_BITMAP) && !defined(BOOTLOADER)
  247. button = button_flip_horizontally(context, button);
  248. #endif
  249. /* logf("%x,%x",last_button,button); */
  250. while (1)
  251. {
  252. /* logf("context = %x",context); */
  253. #if (BUTTON_REMOTE != 0)
  254. if (button & BUTTON_REMOTE)
  255. context |= CONTEXT_REMOTE;
  256. #endif
  257. if ((context & CONTEXT_PLUGIN) && get_context_map)
  258. items = get_context_map(context);
  259. else
  260. items = get_context_mapping(context);
  261. if (items == NULL)
  262. break;
  263. ret = do_button_check(items,button,last_button,&i);
  264. if (ret == ACTION_UNKNOWN)
  265. {
  266. context = get_next_context(items,i);
  267. if (context != (int)CONTEXT_STOPSEARCHING)
  268. {
  269. i = 0;
  270. continue;
  271. }
  272. }
  273. /* Action was found or STOPSEARCHING was specified */
  274. break;
  275. }
  276. /* DEBUGF("ret = %x\n",ret); */
  277. #ifndef HAS_BUTTON_HOLD
  278. if (screen_has_lock && (ret == ACTION_STD_KEYLOCK))
  279. {
  280. unlock_combo = button;
  281. keys_locked = true;
  282. splash(HZ/2, str(LANG_KEYLOCK_ON));
  283. button_clear_queue();
  284. return ACTION_REDRAW;
  285. }
  286. #endif
  287. if ((current_tick - last_action_tick < REPEAT_WINDOW_TICKS)
  288. && (ret == last_action))
  289. repeated = true;
  290. else
  291. repeated = false;
  292. last_button = button;
  293. last_action = ret;
  294. last_data = button_get_data();
  295. last_action_tick = current_tick;
  296. return ret;
  297. }
  298. int get_action(int context, int timeout)
  299. {
  300. int button = get_action_worker(context,timeout,NULL);
  301. #ifdef HAVE_TOUCHSCREEN
  302. if (button == ACTION_TOUCHSCREEN)
  303. button = sb_touch_to_button(context);
  304. #endif
  305. return button;
  306. }
  307. int get_custom_action(int context,int timeout,
  308. const struct button_mapping* (*get_context_map)(int))
  309. {
  310. return get_action_worker(context,timeout,get_context_map);
  311. }
  312. bool action_userabort(int timeout)
  313. {
  314. int action = get_action_worker(CONTEXT_STD,timeout,NULL);
  315. bool ret = (action == ACTION_STD_CANCEL);
  316. if(!ret)
  317. {
  318. default_event_handler(action);
  319. }
  320. return ret;
  321. }
  322. #ifndef HAS_BUTTON_HOLD
  323. bool is_keys_locked(void)
  324. {
  325. return (screen_has_lock && keys_locked);
  326. }
  327. #endif
  328. intptr_t get_action_data(void)
  329. {
  330. return last_data;
  331. }
  332. int get_action_statuscode(int *button)
  333. {
  334. int ret = 0;
  335. if (button)
  336. *button = last_button;
  337. if (last_button & BUTTON_REMOTE)
  338. ret |= ACTION_REMOTE;
  339. if (repeated)
  340. ret |= ACTION_REPEAT;
  341. return ret;
  342. }
  343. #ifdef HAVE_TOUCHSCREEN
  344. /* return BUTTON_NONE on error
  345. * BUTTON_REPEAT if repeated press
  346. * BUTTON_REPEAT|BUTTON_REL if release after repeated press
  347. * BUTTON_REL if it's a short press = release after press
  348. * BUTTON_TOUCHSCREEN if press
  349. */
  350. int action_get_touchscreen_press(short *x, short *y)
  351. {
  352. static int last_data = 0;
  353. int data;
  354. if ((last_button & BUTTON_TOUCHSCREEN) == 0)
  355. return BUTTON_NONE;
  356. data = button_get_data();
  357. if (last_button & BUTTON_REL)
  358. {
  359. *x = (last_data&0xffff0000)>>16;
  360. *y = (last_data&0xffff);
  361. }
  362. else
  363. {
  364. *x = (data&0xffff0000)>>16;
  365. *y = (data&0xffff);
  366. }
  367. last_data = data;
  368. if (repeated)
  369. return BUTTON_REPEAT;
  370. if (short_press)
  371. return BUTTON_REL;
  372. /* This is to return a BUTTON_REL after a BUTTON_REPEAT. */
  373. if (last_button & BUTTON_REL)
  374. return BUTTON_REPEAT|BUTTON_REL;
  375. return BUTTON_TOUCHSCREEN;
  376. }
  377. int action_get_touchscreen_press_in_vp(short *x1, short *y1, struct viewport *vp)
  378. {
  379. short x, y;
  380. int ret;
  381. ret = action_get_touchscreen_press(&x, &y);
  382. if (ret != BUTTON_NONE && viewport_point_within_vp(vp, x, y))
  383. {
  384. *x1 = x - vp->x;
  385. *y1 = y - vp->y;
  386. return ret;
  387. }
  388. if (ret & BUTTON_TOUCHSCREEN)
  389. return ACTION_UNKNOWN;
  390. return BUTTON_NONE;
  391. }
  392. #endif
  393. /* Don't let get_action*() return any ACTION_* values until the current buttons
  394. * have been released. SYS_* and BUTTON_NONE will go through.
  395. * Any actions relying on _RELEASE won't get seen.
  396. */
  397. void action_wait_for_release(void)
  398. {
  399. wait_for_release = true;
  400. }