Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
Jonathan Gordon | f787242 | 2006-08-16 08:07:59 +0000 | [diff] [blame] | 8 | * $Id$ |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 9 | * |
| 10 | * Copyright (C) 2006 Jonathan Gordon |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 11 | * Copyright (C) 2017 William Wilgus |
Steve Bavin | ea358a1 | 2008-01-21 09:48:44 +0000 | [diff] [blame] | 12 | * |
Daniel Stenberg | 2acc0ac | 2008-06-28 18:10:04 +0000 | [diff] [blame] | 13 | * This program is free software; you can redistribute it and/or |
| 14 | * modify it under the terms of the GNU General Public License |
| 15 | * as published by the Free Software Foundation; either version 2 |
| 16 | * of the License, or (at your option) any later version. |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 17 | * |
| 18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 19 | * KIND, either express or implied. |
| 20 | * |
| 21 | ****************************************************************************/ |
| 22 | #include <stdio.h> |
| 23 | #include <string.h> |
| 24 | #include <stdlib.h> |
| 25 | |
| 26 | #include "config.h" |
Jonathan Gordon | b973156 | 2006-08-17 13:31:34 +0000 | [diff] [blame] | 27 | #include "lang.h" |
| 28 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 29 | #if defined(HAVE_LCD_BITMAP) && !defined(BOOTLOADER) |
| 30 | #include "language.h" |
| 31 | #endif |
| 32 | |
Jonathan Gordon | 8b9fdb5 | 2009-01-05 09:59:11 +0000 | [diff] [blame] | 33 | #include "appevents.h" |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 34 | #include "button.h" |
| 35 | #include "action.h" |
| 36 | #include "kernel.h" |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 37 | |
Jonathan Gordon | f178131 | 2006-08-17 12:33:36 +0000 | [diff] [blame] | 38 | #include "splash.h" |
Steve Bavin | ea358a1 | 2008-01-21 09:48:44 +0000 | [diff] [blame] | 39 | #include "settings.h" |
Frank Gevaerts | c61076e | 2009-06-11 20:36:02 +0000 | [diff] [blame] | 40 | #include "misc.h" |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 41 | |
Jonathan Gordon | a398c28 | 2010-06-21 06:04:19 +0000 | [diff] [blame] | 42 | #ifdef HAVE_TOUCHSCREEN |
| 43 | #include "statusbar-skinned.h" |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 44 | #include "viewport.h" |
Jonathan Gordon | a398c28 | 2010-06-21 06:04:19 +0000 | [diff] [blame] | 45 | #endif |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 46 | |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 47 | #ifdef HAVE_BACKLIGHT |
| 48 | #include "backlight.h" |
| 49 | #if CONFIG_CHARGING |
| 50 | #include "power.h" |
| 51 | #endif |
| 52 | #endif /* HAVE_BACKLIGHT */ |
| 53 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 54 | /*#define LOGF_ENABLE*/ |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 55 | #include "logf.h" |
| 56 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 57 | #define REPEAT_WINDOW_TICKS HZ/4 |
| 58 | #define ACTION_FILTER_TICKS HZ/2 /* timeout between filtered actions SL/BL */ |
| 59 | |
| 60 | /* holds the action state between calls to get_action \ get_action_custom) */ |
| 61 | static action_last_t action_last = |
| 62 | { |
| 63 | .action = ACTION_NONE, |
| 64 | .button = BUTTON_NONE | BUTTON_REL, /* allow the ipod wheel to |
| 65 | work on startup */ |
| 66 | .context = CONTEXT_STD, |
| 67 | .data = 0, |
| 68 | .repeated = false, |
| 69 | .tick = 0, |
| 70 | .wait_for_release = false, |
Jonathan Gordon | f178131 | 2006-08-17 12:33:36 +0000 | [diff] [blame] | 71 | |
Maurus Cuelenaere | 1392dc2 | 2008-08-23 09:46:38 +0000 | [diff] [blame] | 72 | #ifdef HAVE_TOUCHSCREEN |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 73 | .ts_data = 0, |
| 74 | .ts_short_press = false, |
Jonathan Gordon | fa13cbe | 2007-10-22 12:26:53 +0000 | [diff] [blame] | 75 | #endif |
| 76 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 77 | #ifdef HAVE_BACKLIGHT |
| 78 | .backlight_mask = SEL_ACTION_NONE, |
| 79 | .bl_filter_tick = 0, |
| 80 | #endif |
| 81 | |
| 82 | #ifndef HAS_BUTTON_HOLD |
| 83 | .keys_locked = false, |
| 84 | .screen_has_lock = false, |
| 85 | .sl_filter_tick = 0, |
| 86 | .softlock_mask = SEL_ACTION_NONE, |
| 87 | .unlock_combo = BUTTON_NONE, |
| 88 | #endif |
| 89 | }; /* action_last_t action_last */ |
| 90 | |
| 91 | /****************************************************************************** |
| 92 | ** INTERNAL ACTION FUNCTIONS ************************************************** |
| 93 | ******************************************************************************* |
| 94 | */ |
| 95 | |
| 96 | /****************************************** |
| 97 | * has_flag compares value to a (SINGLE) flag |
| 98 | * returns true if set, false otherwise |
| 99 | */ |
| 100 | static inline bool has_flag(unsigned int value, unsigned int flag) |
| 101 | { |
| 102 | return ((value & flag) == flag); |
| 103 | } |
Jonathan Gordon | 63c8511 | 2007-06-04 13:52:02 +0000 | [diff] [blame] | 104 | |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 105 | #if defined(HAVE_BACKLIGHT) || !defined(HAS_BUTTON_HOLD) |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 106 | /* HELPER FUNCTIONS selective softlock and backlight */ |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 107 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 108 | /**************************************************************** |
| 109 | * is_action_filtered, selective softlock and backlight use this |
| 110 | * to lookup which actions are filtered, matches are only true if |
| 111 | * action is found and supplied SEL_ACTION mask has the flag. |
| 112 | * returns false if the action isn't found or isn't enabled, |
| 113 | * true if the action is found and is enabled |
| 114 | */ |
| 115 | static bool is_action_filtered(int action, unsigned int mask, int context) |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 116 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 117 | bool match = false; |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 118 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 119 | switch (action) |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 120 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 121 | case ACTION_NONE: |
| 122 | break; |
| 123 | /*Actions that are not mapped will not turn on the backlight option NOUNMAPPED*/ |
| 124 | case ACTION_UNKNOWN: |
| 125 | match = has_flag(mask, SEL_ACTION_NOUNMAPPED); |
| 126 | break; |
| 127 | case ACTION_WPS_PLAY: |
| 128 | case ACTION_FM_PLAY: |
| 129 | match = has_flag(mask, SEL_ACTION_PLAY); |
| 130 | break; |
| 131 | case ACTION_STD_PREVREPEAT: |
| 132 | case ACTION_STD_NEXTREPEAT: |
| 133 | case ACTION_WPS_SEEKBACK: |
| 134 | case ACTION_WPS_SEEKFWD: |
| 135 | case ACTION_WPS_STOPSEEK: |
| 136 | match = has_flag(mask, SEL_ACTION_SEEK); |
| 137 | break; |
| 138 | case ACTION_STD_PREV: |
| 139 | case ACTION_STD_NEXT: |
| 140 | case ACTION_WPS_SKIPNEXT: |
| 141 | case ACTION_WPS_SKIPPREV: |
| 142 | case ACTION_FM_NEXT_PRESET: |
| 143 | case ACTION_FM_PREV_PRESET: |
| 144 | match = has_flag(mask, SEL_ACTION_SKIP); |
| 145 | break; |
| 146 | case ACTION_WPS_VOLUP: |
| 147 | case ACTION_WPS_VOLDOWN: |
| 148 | match = has_flag(mask, SEL_ACTION_VOL); |
| 149 | break; |
| 150 | case ACTION_SETTINGS_INC:/*FMS*/ |
| 151 | case ACTION_SETTINGS_INCREPEAT:/*FMS*/ |
| 152 | case ACTION_SETTINGS_DEC:/*FMS*/ |
| 153 | case ACTION_SETTINGS_DECREPEAT:/*FMS*/ |
| 154 | match = (context == CONTEXT_FM) && has_flag(mask, SEL_ACTION_VOL); |
| 155 | break; |
| 156 | default: |
| 157 | /* display action code of unfiltered actions */ |
| 158 | logf ("unfiltered actions: context: %d action: %d, last btn: %d, \ |
| 159 | mask: %d", context, action, action_last.button, mask); |
| 160 | break; |
| 161 | }/*switch*/ |
| 162 | |
| 163 | return match; |
| 164 | } |
| 165 | |
| 166 | /******************************************************************************* |
| 167 | * is_action_discarded: |
| 168 | * Most every action takes two rounds through get_action_worker, |
| 169 | * once for the keypress and once for the key release, |
| 170 | * actions with pre_button codes take even more, some actions however, only |
| 171 | * take once; actions defined with only a button and no release/repeat event, |
| 172 | * these actions should be acted upon immediately except when we have |
| 173 | * selective backlighting/softlock enabled and in this case we only act upon |
| 174 | * them immediately if there is no chance they have another event tied to them |
| 175 | * determined using !is_prebutton or if action is completed |
| 176 | * returns true if event was discarded and false if it was kept |
| 177 | */ |
| 178 | static bool is_action_discarded(action_cur_t *cur, bool filtered, long *tick) |
| 179 | { |
| 180 | bool ret = true; |
| 181 | bool completed = (cur->button & (BUTTON_REPEAT | BUTTON_REL)) != 0; |
| 182 | |
| 183 | #ifdef HAVE_SCROLLWHEEL |
| 184 | /* Scrollwheel doesn't generate release events */ |
| 185 | completed |= (cur->button & (BUTTON_SCROLL_BACK | BUTTON_SCROLL_FWD)) != 0; |
| 186 | #endif |
| 187 | |
| 188 | /*directly after a match a key release event may trigger another*/ |
| 189 | if (filtered && cur->action != ACTION_UNKNOWN) |
| 190 | { |
| 191 | *tick = current_tick + ACTION_FILTER_TICKS; |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 192 | } |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 193 | /* has button been released/repeat or is this the only action it could be */ |
| 194 | if (completed || !cur->is_prebutton) |
| 195 | { |
| 196 | /* if the action is not filtered and this isn't just a |
| 197 | * key release event then return false |
| 198 | * keeping action, and reset tick |
| 199 | */ |
| 200 | if (!filtered && *tick < current_tick) |
| 201 | { |
| 202 | *tick = 0; |
| 203 | ret = false; |
| 204 | } |
| 205 | } |
| 206 | |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 207 | return ret; |
| 208 | } |
| 209 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 210 | /******************************************************* |
| 211 | * action_handle_backlight is used to both delay |
| 212 | * and activate the backlight if HAVE_BACKLIGHT |
| 213 | * and SEL_ACTION_ENABLED; backlight state is |
| 214 | * set true/false and ignore_next sets the backlight |
| 215 | * driver to ignore backlight_on commands from |
| 216 | * other modules for a finite duration; |
| 217 | * Ignore is set each time the action system |
| 218 | * handles the backlight as a precaution since, if |
| 219 | * the action system was not triggered the device would |
| 220 | * appear unresponsive to the user. |
| 221 | * If a backlight_on event hasn't been handled in the |
| 222 | * ignore duration it will timeout and the next call |
| 223 | * to backlight_on will trigger as normal |
| 224 | */ |
| 225 | static void action_handle_backlight(bool backlight, bool ignore_next) |
Tomer Shalev | a39be4b | 2009-10-05 17:53:45 +0000 | [diff] [blame] | 226 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 227 | #if !defined(HAVE_BACKLIGHT) |
| 228 | (void) backlight; |
| 229 | (void) ignore_next; |
| 230 | return; |
| 231 | #else /* HAVE_BACKLIGHT */ |
| 232 | if (backlight) |
| 233 | { |
| 234 | backlight_on_ignore(false, 0); |
| 235 | backlight_on(); |
| 236 | } |
Tomer Shalev | a39be4b | 2009-10-05 17:53:45 +0000 | [diff] [blame] | 237 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 238 | backlight_on_ignore(ignore_next, 5*HZ);/*must be set everytime we handle bl*/ |
| 239 | |
| 240 | #ifdef HAVE_BUTTON_LIGHT |
| 241 | if (backlight) |
| 242 | { |
| 243 | buttonlight_on_ignore(false, 0); |
| 244 | buttonlight_on(); |
| 245 | } |
| 246 | |
| 247 | buttonlight_on_ignore(ignore_next, 5*HZ);/* as a precautionary fallback */ |
| 248 | #endif /* HAVE_BUTTON_LIGHT */ |
| 249 | |
| 250 | #endif/* HAVE_BACKLIGHT */ |
| 251 | } |
| 252 | |
| 253 | #endif /*defined(HAVE_BACKLIGHT) || !defined(HAS_BUTTON_HOLD) HELPER FUNCTIONS*/ |
| 254 | |
| 255 | /****************************************************************** |
| 256 | * action_poll_button filters button presses for get_action_worker; |
| 257 | * if button_get_w_tmo returns... |
| 258 | * BUTTON_NONE, SYS_EVENTS, MULTIMEDIA BUTTONS, ACTION_REDRAW |
| 259 | * they are allowed to pass immediately through to handler. |
| 260 | * if waiting for button release ACTION_NONE is returned until |
| 261 | * button is released/repeated. |
| 262 | */ |
| 263 | static inline bool action_poll_button(action_last_t *last, action_cur_t *cur) |
| 264 | { |
| 265 | bool ret = true; |
| 266 | int *button = &cur->button; |
| 267 | |
| 268 | *button = button_get_w_tmo(cur->timeout); |
| 269 | /* ************************************************************************** |
| 270 | * if action_wait_for_release() was called without a button being pressed |
| 271 | * then actually waiting for release would do the wrong thing, i.e. |
| 272 | * the next key press is entirely ignored. So, if here comes a normal |
| 273 | * button press (neither release nor repeat) the press is a fresh one and |
| 274 | * no point in waiting for release |
| 275 | * |
| 276 | * This logic doesn't work for touchscreen which can send normal |
| 277 | * button events repeatedly before the first repeat (as in BUTTON_REPEAT). |
| 278 | * These cannot be distinguished from the very first touch |
| 279 | * but there's nothing we can do about it here |
| 280 | */ |
| 281 | if (*button == BUTTON_NONE || (*button & (BUTTON_REPEAT|BUTTON_REL)) == 0) |
| 282 | { |
| 283 | last->wait_for_release = false; |
| 284 | } |
| 285 | /* ******************************************************** |
| 286 | * Can return button immediately, sys_event & multimedia |
| 287 | * button presses don't use the action system, Data from |
| 288 | * sys events can be pulled with button_get_data. |
| 289 | * BUTTON_REDRAW should result in a screen refresh |
| 290 | */ |
| 291 | if (*button == BUTTON_NONE || (*button & (SYS_EVENT|BUTTON_MULTIMEDIA)) != 0) |
| 292 | { |
| 293 | return true; |
| 294 | } |
| 295 | else if (*button == BUTTON_REDRAW) |
| 296 | { /* screen refresh */ |
| 297 | *button = ACTION_REDRAW; |
| 298 | return true; |
| 299 | } |
| 300 | /* ************************************************* |
| 301 | * If waiting for release, Don't send any buttons |
| 302 | * through until we see the release event |
| 303 | */ |
| 304 | if (last->wait_for_release) |
| 305 | { |
| 306 | if (has_flag(*button, BUTTON_REL)) |
| 307 | { /* remember the button for button eating on context change */ |
| 308 | last->wait_for_release = false; |
| 309 | last->button = *button; |
| 310 | } |
| 311 | |
| 312 | *button = ACTION_NONE; |
| 313 | } |
| 314 | #ifdef HAVE_SCROLLWHEEL |
| 315 | /* ********************************************* |
| 316 | * Scrollwheel doesn't generate release events |
| 317 | * further processing needed |
| 318 | */ |
| 319 | else if ((last->button & (BUTTON_SCROLL_BACK | BUTTON_SCROLL_FWD)) != 0) |
| 320 | { |
| 321 | ret = false; |
| 322 | } |
| 323 | #endif |
| 324 | /* ************************************************************* |
| 325 | * On Context Changed eat all buttons until the previous button |
| 326 | * was |BUTTON_REL (also eat the |BUTTON_REL button) |
| 327 | */ |
| 328 | else if ((cur->context != last->context) && ((last->button & BUTTON_REL) == 0)) |
| 329 | { |
| 330 | if (has_flag(*button, BUTTON_REL)) |
| 331 | { |
| 332 | last->button = *button; |
| 333 | last->action = ACTION_NONE; |
| 334 | } |
| 335 | |
| 336 | *button = ACTION_NONE; /* "safest" return value */ |
| 337 | } |
| 338 | /* **************************** |
| 339 | * regular button press, |
| 340 | * further processing needed |
| 341 | */ |
| 342 | else |
| 343 | { |
| 344 | ret = false; |
| 345 | } |
| 346 | |
| 347 | /* current context might contain ALLOW_SOFTLOCK save prior to stripping it */ |
| 348 | if (!ret) |
| 349 | { |
| 350 | last->context = cur->context; |
| 351 | } |
| 352 | |
| 353 | return ret; |
| 354 | } |
| 355 | |
| 356 | /********************************************* |
| 357 | * update_screen_has_lock sets screen_has_lock |
| 358 | * if passed context contains ALLOW_SOFTLOCK |
| 359 | * and removes ALLOW_SOFTLOCK from the passed |
| 360 | * context flag |
| 361 | */ |
| 362 | static inline void update_screen_has_lock(action_last_t *last, action_cur_t *cur) |
| 363 | { |
| 364 | #if defined(HAS_BUTTON_HOLD) |
| 365 | (void) last; |
| 366 | (void) cur; |
| 367 | return; |
| 368 | #else |
| 369 | last->screen_has_lock = has_flag(cur->context, ALLOW_SOFTLOCK); |
| 370 | cur->context &= ~ALLOW_SOFTLOCK; |
| 371 | #endif |
| 372 | } |
| 373 | |
| 374 | /*********************************************** |
| 375 | * get_action_touchscreen allows touchscreen |
| 376 | * presses to have short_press and repeat events |
| 377 | */ |
| 378 | static inline bool get_action_touchscreen(action_last_t *last, action_cur_t *cur) |
| 379 | { |
| 380 | |
| 381 | #if !defined(HAVE_TOUCHSCREEN) |
| 382 | (void) last; |
| 383 | (void) cur; |
| 384 | return false; |
| 385 | #else |
| 386 | if (has_flag(cur->button, BUTTON_TOUCHSCREEN)) |
| 387 | { |
| 388 | last->repeated = false; |
| 389 | last->ts_short_press = false; |
| 390 | if (has_flag(last->button, BUTTON_TOUCHSCREEN)) |
| 391 | { |
| 392 | if (has_flag(cur->button, BUTTON_REL) && |
| 393 | !has_flag(last->button, BUTTON_REPEAT)) |
| 394 | { |
| 395 | last->ts_short_press = true; |
| 396 | } |
| 397 | else if (has_flag(cur->button, BUTTON_REPEAT)) |
| 398 | { |
| 399 | last->repeated = true; |
| 400 | } |
| 401 | } |
| 402 | |
| 403 | last->button = cur->button; |
| 404 | cur->action = ACTION_TOUCHSCREEN; |
| 405 | return true; |
| 406 | } |
| 407 | |
| 408 | return false; |
| 409 | #endif |
| 410 | } |
| 411 | |
| 412 | /****************************************************************************** |
| 413 | * button_flip_horizontally, passed button is horizontally inverted to support |
| 414 | * RTL language if the given language and context combination require it |
| 415 | * Affected contexts: CONTEXT_STD, CONTEXT_TREE, CONTEXT_LIST, CONTEXT_MAINMENU |
| 416 | * Affected buttons with rtl language: |
| 417 | * BUTTON_LEFT, BUTTON_RIGHT, |
| 418 | * Affected buttons with rtl language and !simulator: |
| 419 | * BUTTON_SCROLL_BACK, BUTTON_SCROLL_FWD, BUTTON_MINUS, BUTTON_PLUS |
| 420 | */ |
| 421 | static inline void button_flip_horizontally(int context, int *button) |
| 422 | { |
| 423 | |
| 424 | #if !defined(HAVE_LCD_BITMAP) || defined(BOOTLOADER) |
| 425 | (void) context; |
| 426 | (void) *button; |
| 427 | return; |
| 428 | #else |
| 429 | int newbutton = *button; |
Tomer Shalev | a39be4b | 2009-10-05 17:53:45 +0000 | [diff] [blame] | 430 | if (!(lang_is_rtl() && ((context == CONTEXT_STD) || |
Tomer Shalev | 694ea7e | 2009-10-08 22:19:36 +0000 | [diff] [blame] | 431 | (context == CONTEXT_TREE) || (context == CONTEXT_LIST) || |
| 432 | (context == CONTEXT_MAINMENU)))) |
Tomer Shalev | a39be4b | 2009-10-05 17:53:45 +0000 | [diff] [blame] | 433 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 434 | return; |
Tomer Shalev | a39be4b | 2009-10-05 17:53:45 +0000 | [diff] [blame] | 435 | } |
| 436 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 437 | newbutton &= ~(BUTTON_LEFT | BUTTON_RIGHT); |
| 438 | if (has_flag(*button, BUTTON_LEFT)) |
| 439 | { |
Tomer Shalev | a39be4b | 2009-10-05 17:53:45 +0000 | [diff] [blame] | 440 | newbutton |= BUTTON_RIGHT; |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 441 | } |
| 442 | |
| 443 | if (has_flag(*button, BUTTON_RIGHT)) |
| 444 | { |
Tomer Shalev | a39be4b | 2009-10-05 17:53:45 +0000 | [diff] [blame] | 445 | newbutton |= BUTTON_LEFT; |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 446 | } |
| 447 | #ifndef SIMULATOR |
| 448 | #ifdef HAVE_SCROLLWHEEL |
| 449 | newbutton &= ~(BUTTON_SCROLL_BACK | BUTTON_SCROLL_FWD); |
| 450 | if (has_flag(*button, BUTTON_SCROLL_BACK)) |
| 451 | { |
Tomer Shalev | a39be4b | 2009-10-05 17:53:45 +0000 | [diff] [blame] | 452 | newbutton |= BUTTON_SCROLL_FWD; |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 453 | } |
| 454 | |
| 455 | if (has_flag(*button, BUTTON_SCROLL_FWD)) |
| 456 | { |
Tomer Shalev | a39be4b | 2009-10-05 17:53:45 +0000 | [diff] [blame] | 457 | newbutton |= BUTTON_SCROLL_BACK; |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 458 | } |
Tomer Shalev | a39be4b | 2009-10-05 17:53:45 +0000 | [diff] [blame] | 459 | #endif |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 460 | |
| 461 | #if defined(BUTTON_MINUS) && defined(BUTTON_PLUS) |
William Wilgus | 52af55e | 2017-11-18 17:06:40 +0100 | [diff] [blame] | 462 | newbutton &= ~(BUTTON_MINUS | BUTTON_PLUS); |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 463 | if (has_flag(*button, BUTTON_MINUS)) |
| 464 | { |
Tomer Shalev | 3deed06 | 2009-12-05 15:54:05 +0000 | [diff] [blame] | 465 | newbutton |= BUTTON_PLUS; |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 466 | } |
| 467 | |
| 468 | if (has_flag(*button, BUTTON_PLUS)) |
| 469 | { |
Tomer Shalev | 3deed06 | 2009-12-05 15:54:05 +0000 | [diff] [blame] | 470 | newbutton |= BUTTON_MINUS; |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 471 | } |
Tomer Shalev | 3deed06 | 2009-12-05 15:54:05 +0000 | [diff] [blame] | 472 | #endif |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 473 | #endif /* !SIMULATOR */ |
Tomer Shalev | a39be4b | 2009-10-05 17:53:45 +0000 | [diff] [blame] | 474 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 475 | *button = newbutton; |
| 476 | #endif /* !HAVE_LCD_BITMAP | BOOTLOADER */ |
| 477 | } /* button_flip_horizontally */ |
| 478 | |
| 479 | /********************************************************************** |
| 480 | * action_code_worker is the worker function for action_code_lookup. |
| 481 | * returns ACTION_UNKNOWN or the requested return value from the list. |
| 482 | * BE AWARE IF YOUR DESIRED ACTION IS IN A LOWER 'CHAINED' CONTEXT:: |
| 483 | * *** is_prebutton can miss pre_buttons |
| 484 | * ** An action without pre_button_code (pre_button_code = BUTTON_NONE) |
| 485 | * * will be returned from the higher context |
| 486 | */ |
| 487 | static inline int action_code_worker(action_last_t *last, |
| 488 | action_cur_t *cur, |
| 489 | int *end ) |
| 490 | { |
| 491 | int ret = ACTION_UNKNOWN; |
| 492 | int i = 0; |
| 493 | unsigned int found = 0; |
| 494 | while (cur->items[i].button_code != BUTTON_NONE) |
| 495 | { |
| 496 | if (cur->items[i].button_code == cur->button) |
| 497 | { |
| 498 | /******************************************************** |
| 499 | * { Action Code, Button code, Prereq button code } |
| 500 | * CAVEAT: This will allways return the action without |
| 501 | * pre_button_code (pre_button_code = BUTTON_NONE) |
| 502 | * if it is found before 'falling through' |
| 503 | * to a lower 'chained' context. |
| 504 | * |
| 505 | * Example: button = UP|REL, last_button = UP; |
| 506 | * while looking in CONTEXT_WPS there is an action defined |
| 507 | * {ACTION_FOO, BUTTON_UP|BUTTON_REL, BUTTON_NONE} |
| 508 | * then ACTION_FOO in CONTEXT_WPS will be returned |
| 509 | * EVEN THOUGH you are expecting a fully matched |
| 510 | * ACTION_BAR from CONTEXT_STD |
| 511 | * {ACTION_BAR, BUTTON_UP|BUTTON_REL, BUTTON_UP} |
| 512 | */ |
| 513 | if (cur->items[i].pre_button_code == last->button) |
| 514 | { /* Always allow an exact match */ |
| 515 | found++; |
| 516 | *end = i; |
| 517 | } |
| 518 | else if (!found && cur->items[i].pre_button_code == BUTTON_NONE) |
| 519 | { /* Only allow Loose match if exact match wasn't found */ |
| 520 | found++; |
| 521 | *end = i; |
| 522 | } |
| 523 | } |
| 524 | else if (has_flag(cur->items[i].pre_button_code, cur->button)) |
| 525 | { /* This could be another action depending on next button press */ |
| 526 | cur->is_prebutton = true; |
| 527 | if (found > 1) /* There is already an exact match */ |
| 528 | { |
| 529 | break; |
| 530 | } |
| 531 | } |
| 532 | i++; |
| 533 | } |
| 534 | |
| 535 | if (!found) |
| 536 | { |
| 537 | *end = i; |
| 538 | } |
| 539 | else |
| 540 | { |
| 541 | ret = cur->items[*end].action_code; |
| 542 | } |
| 543 | |
| 544 | return ret; |
Tomer Shalev | a39be4b | 2009-10-05 17:53:45 +0000 | [diff] [blame] | 545 | } |
Tomer Shalev | a39be4b | 2009-10-05 17:53:45 +0000 | [diff] [blame] | 546 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 547 | /*************************************************************************** |
| 548 | * get_next_context returns the next CONTEXT to be searched for action_code |
| 549 | * by action_code_lookup(); if needed it first continues incrementing till |
| 550 | * the end of current context map is reached; If there is another |
| 551 | * 'chained' context below the current context this new context is returned |
| 552 | * if there is not a 'chained' context to return, CONTEXT_STD is returned; |
| 553 | */ |
Jens Arnold | a0f3113 | 2006-12-12 07:55:17 +0000 | [diff] [blame] | 554 | static inline int get_next_context(const struct button_mapping *items, int i) |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 555 | { |
| 556 | while (items[i].button_code != BUTTON_NONE) |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 557 | { |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 558 | i++; |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 559 | } |
| 560 | |
Steve Bavin | ea358a1 | 2008-01-21 09:48:44 +0000 | [diff] [blame] | 561 | return (items[i].action_code == ACTION_NONE ) ? |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 562 | CONTEXT_STD : items[i].action_code; |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 563 | } |
Andree Buschmann | f1ee740 | 2011-11-11 19:40:32 +0000 | [diff] [blame] | 564 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 565 | /************************************************************************ |
| 566 | * action_code_lookup passes current button, last button and is_prebutton |
| 567 | * to action_code_worker() which uses the current button map to |
| 568 | * lookup action_code. |
| 569 | * BE AWARE IF YOUR DESIRED ACTION IS IN A LOWER 'CHAINED' CONTEXT:: |
| 570 | * *** is_prebutton can miss pre_buttons |
| 571 | * ** An action without pre_button_code (pre_button_code = BUTTON_NONE) |
| 572 | * * will be returned from the higher context see action_code_worker() |
| 573 | * for a more in-depth explanation |
| 574 | * places action into current_action |
| 575 | */ |
| 576 | static inline void action_code_lookup(action_last_t *last, action_cur_t *cur) |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 577 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 578 | int action = ACTION_NONE; |
| 579 | int context = cur->context; |
| 580 | int i = 0; |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 581 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 582 | cur->is_prebutton = false; |
Steve Bavin | ea358a1 | 2008-01-21 09:48:44 +0000 | [diff] [blame] | 583 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 584 | for(;;) |
Thomas Martitz | 54e6baf | 2012-07-18 10:25:32 +0200 | [diff] [blame] | 585 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 586 | /* logf("context = %x",context); */ |
| 587 | #if (BUTTON_REMOTE != 0) |
William Wilgus | e41a563 | 2019-04-22 16:23:28 -0500 | [diff] [blame] | 588 | if ((cur->button & BUTTON_REMOTE) != 0) |
Jonathan Gordon | 0e445fc | 2009-07-03 05:08:33 +0000 | [diff] [blame] | 589 | { |
William Wilgus | 52af55e | 2017-11-18 17:06:40 +0100 | [diff] [blame] | 590 | context |= CONTEXT_REMOTE; |
Jonathan Gordon | 0e445fc | 2009-07-03 05:08:33 +0000 | [diff] [blame] | 591 | } |
Magnus Holmgren | 4480e3a | 2010-11-14 13:13:06 +0000 | [diff] [blame] | 592 | #endif |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 593 | |
William Wilgus | 71e3f6c | 2017-12-11 02:24:42 +0100 | [diff] [blame] | 594 | if ((context & CONTEXT_PLUGIN) && cur->get_context_map) |
| 595 | cur->items = cur->get_context_map(context); |
| 596 | else |
| 597 | cur->items = get_context_mapping(context); |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 598 | |
| 599 | if (cur->items != NULL) |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 600 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 601 | action = action_code_worker(last, cur, &i); |
| 602 | |
| 603 | if (action == ACTION_UNKNOWN) |
| 604 | { |
| 605 | context = get_next_context(cur->items, i); |
| 606 | |
| 607 | if (context != (int)CONTEXT_STOPSEARCHING) |
| 608 | { |
| 609 | i = 0; |
| 610 | continue; |
| 611 | } |
| 612 | } |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 613 | } |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 614 | /* No more items, action was found, or STOPSEARCHING was specified */ |
| 615 | break; |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 616 | } |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 617 | cur->action = action; |
| 618 | } |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 619 | |
Jonathan Gordon | f178131 | 2006-08-17 12:33:36 +0000 | [diff] [blame] | 620 | #ifndef HAS_BUTTON_HOLD |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 621 | /************************************* |
| 622 | * do_key_lock (dis)/enables softlock |
| 623 | * based on lock flag, last button and |
| 624 | * buttons still in queue are purged |
| 625 | * if HAVE_TOUCHSCREEN then depending |
| 626 | * on user selection it will be locked |
| 627 | * or unlocked as well |
| 628 | */ |
| 629 | static inline void do_key_lock(bool lock) |
| 630 | { |
| 631 | action_last.keys_locked = lock; |
| 632 | action_last.button = BUTTON_NONE; |
| 633 | button_clear_queue(); |
Jean-Louis Biasini | df6eb82 | 2013-09-02 11:03:56 +0200 | [diff] [blame] | 634 | #if defined(HAVE_TOUCHPAD) || defined(HAVE_TOUCHSCREEN) |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 635 | /* disable touch device on keylock if std behavior or selected disable touch */ |
| 636 | if (!has_flag(action_last.softlock_mask, SEL_ACTION_ENABLED) || |
| 637 | has_flag(action_last.softlock_mask, SEL_ACTION_NOTOUCH)) |
Jean-Louis Biasini | df6eb82 | 2013-09-02 11:03:56 +0200 | [diff] [blame] | 638 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 639 | button_enable_touch(!lock); |
Jean-Louis Biasini | df6eb82 | 2013-09-02 11:03:56 +0200 | [diff] [blame] | 640 | } |
| 641 | #endif |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 642 | } |
| 643 | |
| 644 | /********************************************** |
| 645 | * do_auto_softlock when user selects autolock |
| 646 | * unlock_combo stored for later unlock |
| 647 | * activates autolock on backlight timeout |
| 648 | * toggles autolock on / off by |
| 649 | * ACTION_STD_KEYLOCK presses; |
| 650 | */ |
| 651 | static inline int do_auto_softlock(action_last_t *last, action_cur_t *cur) |
| 652 | { |
| 653 | |
| 654 | #if !defined(HAVE_BACKLIGHT) |
| 655 | (void) last; |
| 656 | return cur->action; |
| 657 | #else |
| 658 | int action = cur->action; |
| 659 | bool is_timeout = false; |
| 660 | int timeout; |
| 661 | if (has_flag(last->softlock_mask, SEL_ACTION_ALOCK_OK)) |
| 662 | { |
| 663 | timeout = backlight_get_current_timeout(); |
| 664 | is_timeout = (timeout > 0 && (current_tick > action_last.tick + timeout)); |
| 665 | } |
| 666 | |
| 667 | if (is_timeout) |
| 668 | { |
| 669 | do_key_lock(true); |
| 670 | } |
| 671 | else if (action == ACTION_STD_KEYLOCK) |
| 672 | { |
| 673 | last->unlock_combo = cur->button;/* set unlock combo to allow unlock */ |
| 674 | last->softlock_mask ^= SEL_ACTION_ALOCK_OK; |
| 675 | action_handle_backlight(true, false); |
| 676 | /* If we don't wait for a moment for the backlight queue |
| 677 | * to process, the user will never see the message */ |
| 678 | if (!is_backlight_on(false)) |
| 679 | { |
| 680 | sleep(HZ/2); |
| 681 | } |
| 682 | |
| 683 | if (has_flag(last->softlock_mask, SEL_ACTION_ALOCK_OK)) |
| 684 | { |
| 685 | splash(HZ/2, ID2P(LANG_ACTION_AUTOLOCK_ON)); |
| 686 | action = ACTION_REDRAW; |
| 687 | } |
| 688 | else |
| 689 | { |
| 690 | splash(HZ/2, ID2P(LANG_ACTION_AUTOLOCK_OFF)); |
| 691 | } |
| 692 | } |
| 693 | |
| 694 | return action; |
| 695 | #endif /* HAVE_BACKLIGHT */ |
| 696 | } |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 697 | |
Jonathan Gordon | f178131 | 2006-08-17 12:33:36 +0000 | [diff] [blame] | 698 | #endif /* HAS_BUTTON_HOLD */ |
Steve Bavin | ea358a1 | 2008-01-21 09:48:44 +0000 | [diff] [blame] | 699 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 700 | /***************************************************** |
| 701 | * do_softlock Handles softlock once action is known |
| 702 | * selective softlock allows user selected actions to |
| 703 | * bypass a currently locked state, special lock state |
| 704 | * autolock is handled here as well if HAVE_BACKLIGHT |
| 705 | */ |
| 706 | static inline void do_softlock(action_last_t *last, action_cur_t *cur) |
| 707 | { |
| 708 | #if defined(HAS_BUTTON_HOLD) |
| 709 | (void) last; |
| 710 | (void) cur; |
| 711 | return; |
| 712 | #else |
| 713 | int action = cur->action; |
| 714 | |
| 715 | if (!last->screen_has_lock) |
| 716 | { /* no need to check softlock return immediately */ |
| 717 | return; |
| 718 | } |
| 719 | |
| 720 | bool filtered = true; |
| 721 | bool notify_user = false; |
| 722 | bool sl_activate = true; /* standard softlock behavior */ |
| 723 | |
| 724 | if ((!last->keys_locked) && has_flag(last->softlock_mask, SEL_ACTION_AUTOLOCK)) |
Maurus Cuelenaere | 7b1d12e | 2009-10-28 21:36:24 +0000 | [diff] [blame] | 725 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 726 | action = do_auto_softlock(last, cur); |
| 727 | } |
| 728 | /* Lock/Unlock toggled by ACTION_STD_KEYLOCK presses*/ |
| 729 | if ((action == ACTION_STD_KEYLOCK) |
| 730 | || (last->keys_locked && last->unlock_combo == cur->button)) |
| 731 | { |
| 732 | last->unlock_combo = cur->button; |
| 733 | do_key_lock(!last->keys_locked); |
| 734 | notify_user = true; |
| 735 | } |
| 736 | #if (BUTTON_REMOTE != 0)/* Allow remote actions through */ |
| 737 | else if (has_flag(cur->button, BUTTON_REMOTE)) |
| 738 | { |
| 739 | return; |
Maurus Cuelenaere | 7b1d12e | 2009-10-28 21:36:24 +0000 | [diff] [blame] | 740 | } |
| 741 | #endif |
| 742 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 743 | else if (last->keys_locked && action != ACTION_REDRAW) |
| 744 | { |
| 745 | if (has_flag(last->softlock_mask, SEL_ACTION_ENABLED)) |
| 746 | { |
| 747 | filtered = is_action_filtered(action, last->softlock_mask, cur->context); |
| 748 | |
| 749 | sl_activate = !is_action_discarded(cur, filtered, &last->sl_filter_tick); |
| 750 | } |
| 751 | |
| 752 | if (sl_activate) |
| 753 | { /*All non-std softlock options are set to 0 if advanced sl is disabled*/ |
| 754 | if (!has_flag(last->softlock_mask, SEL_ACTION_NONOTIFY)) |
| 755 | { /* always true on standard softlock behavior*/ |
| 756 | notify_user = has_flag(cur->button, BUTTON_REL); |
| 757 | action = ACTION_REDRAW; |
| 758 | } |
| 759 | else |
| 760 | action = ACTION_NONE; |
| 761 | } |
| 762 | else if (!filtered) |
| 763 | { /* catch blocked actions on fast repeated presses */ |
| 764 | action = ACTION_NONE; |
| 765 | } |
| 766 | }/* keys_locked */ |
| 767 | |
| 768 | #ifdef BUTTON_POWER /*always notify if power button pressed while keys locked*/ |
| 769 | notify_user |= (has_flag(cur->button, BUTTON_POWER|BUTTON_REL) |
| 770 | && last->keys_locked); |
Tomer Shalev | f7bd725 | 2009-10-05 17:17:30 +0000 | [diff] [blame] | 771 | #endif |
| 772 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 773 | if (notify_user) |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 774 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 775 | action_handle_backlight(true, false); |
| 776 | |
| 777 | #ifdef HAVE_BACKLIGHT |
| 778 | /* If we don't wait for a moment for the backlight queue to process, |
| 779 | * the user will never see the message |
| 780 | */ |
| 781 | if (!is_backlight_on(false)) |
| 782 | { |
| 783 | sleep(HZ/2); |
| 784 | } |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 785 | #endif |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 786 | if (last->keys_locked) |
| 787 | { |
| 788 | splash(HZ/2, ID2P(LANG_KEYLOCK_ON)); |
| 789 | } |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 790 | else |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 791 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 792 | splash(HZ/2, ID2P(LANG_KEYLOCK_OFF)); |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 793 | } |
Jonathan Gordon | ca701bf | 2007-03-04 07:45:12 +0000 | [diff] [blame] | 794 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 795 | action = ACTION_REDRAW; |
| 796 | last->button = BUTTON_NONE; |
| 797 | button_clear_queue(); |
| 798 | } |
| 799 | |
| 800 | cur->action = action; |
| 801 | #endif/*!HAS_BUTTON_HOLD*/ |
| 802 | } |
| 803 | |
| 804 | /********************************************************************** |
| 805 | * update_action_last copies the current action values into action_last |
| 806 | * saving the current state & allowing get_action_worker() to return |
| 807 | * while waiting for the next button press; Since some actions take |
| 808 | * multiple buttons, this allows those actions to be looked up and |
| 809 | * returned in a non-blocking way; |
| 810 | * Returns action, checks\sets repeated, plays keyclick (if applicable) |
| 811 | */ |
| 812 | static inline int update_action_last(action_last_t *last, action_cur_t *cur) |
| 813 | { |
| 814 | int action = cur->action; |
| 815 | |
| 816 | logf ("action system: context: %d last context: %d, action: %d, \ |
| 817 | last action: %d, button %d, last btn: %d, last repeated: %d, \ |
| 818 | last_data: %d", cur->context, last->context, cur->action, |
| 819 | last->action, cur->button, last->button, last->repeated, last->data); |
| 820 | |
| 821 | if (action == last->action) |
| 822 | { |
| 823 | last->repeated = (current_tick < last->tick + REPEAT_WINDOW_TICKS); |
| 824 | } |
| 825 | else |
| 826 | { |
| 827 | last->repeated = false; |
| 828 | } |
| 829 | |
| 830 | last->action = action; |
| 831 | last->button = cur->button; |
| 832 | last->data = button_get_data(); |
| 833 | last->tick = current_tick; |
Jonathan Gordon | eb2ea7f | 2012-01-12 22:28:36 +1100 | [diff] [blame] | 834 | |
| 835 | #if CONFIG_CODEC == SWCODEC |
| 836 | /* Produce keyclick */ |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 837 | keyclick_click(false, action); |
Jonathan Gordon | eb2ea7f | 2012-01-12 22:28:36 +1100 | [diff] [blame] | 838 | #endif |
| 839 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 840 | return action; |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 841 | } |
| 842 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 843 | /******************************************************** |
| 844 | * init_act_cur initializes passed struct action_cur_t |
| 845 | * with context, timeout,and get_context_map. |
| 846 | * other values set to default |
| 847 | * if get_context_map is NULL standard |
| 848 | * context mapping will be used |
| 849 | */ |
| 850 | static void init_act_cur(action_cur_t *cur, |
| 851 | int context, int timeout, |
| 852 | const struct button_mapping* (*get_context_map)(int)) |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 853 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 854 | cur->action = ACTION_UNKNOWN; |
| 855 | cur->button = BUTTON_NONE; |
| 856 | cur->context = context; |
| 857 | cur->is_prebutton = false; |
| 858 | cur->items = NULL; |
| 859 | cur->timeout = timeout; |
William Wilgus | 71e3f6c | 2017-12-11 02:24:42 +0100 | [diff] [blame] | 860 | cur->get_context_map = get_context_map; |
Linus Nielsen Feltzing | 224c0a1 | 2006-08-15 12:27:07 +0000 | [diff] [blame] | 861 | } |
| 862 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 863 | /******************************************************* |
| 864 | * do_backlight allows exemptions to the backlight on |
| 865 | * user selected actions; Actions need to be looked up |
| 866 | * before the decision to turn on backlight is made, |
| 867 | * if selective backlighting is enabled then |
| 868 | * filter first keypress events may need |
| 869 | * to be taken into account as well |
| 870 | * IF SEL_ACTION_ENABLED then: |
| 871 | * Returns action or is FFKeypress is enabled, |
| 872 | * ACTION_NONE on first keypress |
| 873 | * delays backlight_on until action is known |
| 874 | * handles backlight_on if needed |
| 875 | */ |
| 876 | static inline int do_backlight(action_last_t *last, action_cur_t *cur, int action) |
Michael Sevakis | 873e0fd | 2007-07-22 21:02:24 +0000 | [diff] [blame] | 877 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 878 | |
| 879 | #if !defined(HAVE_BACKLIGHT) |
| 880 | (void) last; |
| 881 | (void) cur; |
| 882 | return action; |
| 883 | #else |
| 884 | if (!has_flag(last->backlight_mask, SEL_ACTION_ENABLED) |
| 885 | || (action & (SYS_EVENT|BUTTON_MULTIMEDIA)) != 0 |
| 886 | || action == ACTION_REDRAW) |
| 887 | { |
| 888 | return action; |
| 889 | } |
| 890 | |
| 891 | bool filtered; |
| 892 | bool bl_activate = false; |
| 893 | bool bl_is_off = !is_backlight_on(false); |
| 894 | |
| 895 | #if CONFIG_CHARGING /* disable if on external power */ |
| 896 | bl_is_off &= !(has_flag(last->backlight_mask, SEL_ACTION_NOEXT) |
| 897 | && power_input_present()); |
| 898 | #endif |
| 899 | /* skip if backlight on | incorrect context | SEL_ACTION_NOEXT + ext pwr */ |
| 900 | if ((cur->context == CONTEXT_FM || cur->context == CONTEXT_WPS) && bl_is_off) |
| 901 | { |
| 902 | filtered = is_action_filtered(action, last->backlight_mask, cur->context); |
| 903 | bl_activate = !is_action_discarded(cur, filtered, &last->bl_filter_tick); |
| 904 | } |
| 905 | else /* standard backlight behaviour */ |
| 906 | { |
| 907 | bl_activate = true; |
| 908 | } |
| 909 | |
| 910 | if (action != ACTION_NONE && bl_activate) |
| 911 | { |
| 912 | action_handle_backlight(true, true); |
| 913 | /* Handle first keypress enables backlight only */ |
| 914 | if (has_flag(last->backlight_mask, SEL_ACTION_FFKEYPRESS) && bl_is_off) |
| 915 | { |
| 916 | action = ACTION_NONE; |
| 917 | last->button = BUTTON_NONE; |
| 918 | } |
| 919 | } |
| 920 | else |
| 921 | { |
| 922 | action_handle_backlight(false, true);/* set ignore next true */ |
| 923 | } |
| 924 | |
| 925 | return action; |
| 926 | #endif /* !HAVE_BACKLIGHT */ |
Michael Sevakis | 873e0fd | 2007-07-22 21:02:24 +0000 | [diff] [blame] | 927 | } |
| 928 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 929 | /******************************************************************** |
| 930 | * get_action_worker() searches the button list of the passed context |
| 931 | * for the just pressed button. If there is a match it returns the |
| 932 | * value from the list. If there is no match, the last item in the |
| 933 | * list "points" to the next context in a chain so the "chain" is |
| 934 | * followed until the button is found. ACTION_NONE int the button |
| 935 | * list will get CONTEXT_STD which is always the last list checked. |
| 936 | * |
| 937 | * BE AWARE IF YOUR DESIRED ACTION IS IN A LOWER 'CHAINED' CONTEXT:: |
| 938 | * *** is_prebutton can miss pre_buttons |
| 939 | * ** An action without pre_button_code (pre_button_code = BUTTON_NONE) |
| 940 | * * will be returned from the higher context see action_code_worker() |
| 941 | * for a more in-depth explanation |
| 942 | * |
| 943 | * Timeout can be: TIMEOUT_NOBLOCK to return immediatly |
| 944 | * TIMEOUT_BLOCK to wait for a button press |
| 945 | * Any number >0 to wait that many ticks for a press |
| 946 | */ |
| 947 | static int get_action_worker(action_last_t *last, action_cur_t *cur) |
Jonathan Gordon | ca701bf | 2007-03-04 07:45:12 +0000 | [diff] [blame] | 948 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 949 | send_event(GUI_EVENT_ACTIONUPDATE, NULL); |
Jonathan Gordon | ca701bf | 2007-03-04 07:45:12 +0000 | [diff] [blame] | 950 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 951 | /*if button = none/special; returns immediately*/ |
| 952 | if (action_poll_button(last, cur)) |
| 953 | { |
| 954 | return cur->button; |
| 955 | } |
| 956 | |
| 957 | update_screen_has_lock(last, cur); |
| 958 | |
| 959 | if (get_action_touchscreen(last, cur)) |
| 960 | { |
| 961 | return cur->action; |
| 962 | } |
| 963 | |
| 964 | button_flip_horizontally(cur->context, &cur->button); |
| 965 | |
| 966 | action_code_lookup(last, cur); |
| 967 | |
| 968 | do_softlock(last, cur); |
| 969 | |
| 970 | return update_action_last(last, cur); |
Jonathan Gordon | ca701bf | 2007-03-04 07:45:12 +0000 | [diff] [blame] | 971 | } |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 972 | /* |
| 973 | ******************************************************************************* |
| 974 | * END INTERNAL ACTION FUNCTIONS *********************************************** |
| 975 | *******************************************************************************/ |
Jonathan Gordon | fa13cbe | 2007-10-22 12:26:53 +0000 | [diff] [blame] | 976 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 977 | /****************************************************************************** |
| 978 | * EXPORTED ACTION FUNCTIONS *************************************************** |
| 979 | ******************************************************************************* |
| 980 | */ |
Maurus Cuelenaere | 1392dc2 | 2008-08-23 09:46:38 +0000 | [diff] [blame] | 981 | #ifdef HAVE_TOUCHSCREEN |
Maurus Cuelenaere | cad30d3 | 2008-06-02 16:08:01 +0000 | [diff] [blame] | 982 | /* return BUTTON_NONE on error |
| 983 | * BUTTON_REPEAT if repeated press |
| 984 | * BUTTON_REPEAT|BUTTON_REL if release after repeated press |
Alexander Levin | 46854ed | 2010-04-19 19:49:42 +0000 | [diff] [blame] | 985 | * BUTTON_REL if it's a short press = release after press |
Maurus Cuelenaere | 1392dc2 | 2008-08-23 09:46:38 +0000 | [diff] [blame] | 986 | * BUTTON_TOUCHSCREEN if press |
Maurus Cuelenaere | cad30d3 | 2008-06-02 16:08:01 +0000 | [diff] [blame] | 987 | */ |
Maurus Cuelenaere | 1392dc2 | 2008-08-23 09:46:38 +0000 | [diff] [blame] | 988 | int action_get_touchscreen_press(short *x, short *y) |
Jonathan Gordon | fa13cbe | 2007-10-22 12:26:53 +0000 | [diff] [blame] | 989 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 990 | |
Jonathan Gordon | fa13cbe | 2007-10-22 12:26:53 +0000 | [diff] [blame] | 991 | int data; |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 992 | int ret = BUTTON_TOUCHSCREEN; |
| 993 | |
| 994 | if (!has_flag(action_last.button, BUTTON_TOUCHSCREEN)) |
Jonathan Gordon | fa13cbe | 2007-10-22 12:26:53 +0000 | [diff] [blame] | 995 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 996 | return BUTTON_NONE; |
| 997 | } |
| 998 | |
| 999 | data = button_get_data(); |
| 1000 | if (has_flag(action_last.button, BUTTON_REL)) |
| 1001 | { |
| 1002 | *x = (action_last.ts_data&0xffff0000)>>16; |
| 1003 | *y = (action_last.ts_data&0xffff); |
Jonathan Gordon | fa13cbe | 2007-10-22 12:26:53 +0000 | [diff] [blame] | 1004 | } |
| 1005 | else |
| 1006 | { |
| 1007 | *x = (data&0xffff0000)>>16; |
| 1008 | *y = (data&0xffff); |
| 1009 | } |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1010 | |
| 1011 | action_last.ts_data = data; |
| 1012 | |
| 1013 | if (action_last.repeated) |
| 1014 | { |
| 1015 | ret = BUTTON_REPEAT; |
| 1016 | } |
| 1017 | else if (action_last.ts_short_press) |
| 1018 | { |
| 1019 | ret = BUTTON_REL; |
| 1020 | } |
Maurus Cuelenaere | cad30d3 | 2008-06-02 16:08:01 +0000 | [diff] [blame] | 1021 | /* This is to return a BUTTON_REL after a BUTTON_REPEAT. */ |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1022 | else if (has_flag(action_last.button, BUTTON_REL)) |
| 1023 | { |
| 1024 | ret = BUTTON_REPEAT|BUTTON_REL; |
| 1025 | } |
| 1026 | |
| 1027 | return ret; |
Jonathan Gordon | fa13cbe | 2007-10-22 12:26:53 +0000 | [diff] [blame] | 1028 | } |
Thomas Martitz | 891c446 | 2009-10-11 20:11:48 +0000 | [diff] [blame] | 1029 | |
| 1030 | int action_get_touchscreen_press_in_vp(short *x1, short *y1, struct viewport *vp) |
| 1031 | { |
| 1032 | short x, y; |
| 1033 | int ret; |
| 1034 | |
| 1035 | ret = action_get_touchscreen_press(&x, &y); |
| 1036 | |
| 1037 | if (ret != BUTTON_NONE && viewport_point_within_vp(vp, x, y)) |
| 1038 | { |
| 1039 | *x1 = x - vp->x; |
| 1040 | *y1 = y - vp->y; |
| 1041 | return ret; |
| 1042 | } |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1043 | |
| 1044 | if (has_flag(ret, BUTTON_TOUCHSCREEN)) |
| 1045 | { |
Thomas Martitz | 891c446 | 2009-10-11 20:11:48 +0000 | [diff] [blame] | 1046 | return ACTION_UNKNOWN; |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1047 | } |
| 1048 | |
Thomas Martitz | 891c446 | 2009-10-11 20:11:48 +0000 | [diff] [blame] | 1049 | return BUTTON_NONE; |
| 1050 | } |
Jonathan Gordon | fa13cbe | 2007-10-22 12:26:53 +0000 | [diff] [blame] | 1051 | #endif |
Jonathan Gordon | 0e445fc | 2009-07-03 05:08:33 +0000 | [diff] [blame] | 1052 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1053 | bool action_userabort(int timeout) |
Jonathan Gordon | 0e445fc | 2009-07-03 05:08:33 +0000 | [diff] [blame] | 1054 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1055 | int action = get_custom_action(CONTEXT_STD, timeout, NULL); |
| 1056 | bool ret = (action == ACTION_STD_CANCEL); |
| 1057 | if (!ret) |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1058 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1059 | default_event_handler(action); |
| 1060 | } |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1061 | |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1062 | return ret; |
| 1063 | } |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1064 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1065 | void action_wait_for_release(void) |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1066 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1067 | action_last.wait_for_release = true; |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1068 | } |
| 1069 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1070 | int get_action(int context, int timeout) |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1071 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1072 | action_cur_t current; |
| 1073 | init_act_cur(¤t, context, timeout, NULL); |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1074 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1075 | int action = get_action_worker(&action_last, ¤t); |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1076 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1077 | #ifdef HAVE_TOUCHSCREEN |
| 1078 | if (action == ACTION_TOUCHSCREEN) |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1079 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1080 | action = sb_touch_to_button(context); |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1081 | } |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1082 | #endif |
| 1083 | |
| 1084 | action = do_backlight(&action_last, ¤t, action); |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1085 | |
| 1086 | return action; |
| 1087 | } |
| 1088 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1089 | int get_custom_action(int context,int timeout, |
| 1090 | const struct button_mapping* (*get_context_map)(int)) |
| 1091 | { |
| 1092 | action_cur_t current; |
| 1093 | init_act_cur(¤t, context, timeout, get_context_map); |
| 1094 | |
| 1095 | return get_action_worker(&action_last, ¤t); |
| 1096 | } |
| 1097 | |
| 1098 | intptr_t get_action_data(void) |
| 1099 | { |
| 1100 | return action_last.data; |
| 1101 | } |
| 1102 | |
| 1103 | int get_action_statuscode(int *button) |
| 1104 | { |
| 1105 | int ret = 0; |
| 1106 | if (button) |
| 1107 | { |
| 1108 | *button = action_last.button; |
| 1109 | } |
| 1110 | |
| 1111 | if (has_flag(action_last.button, BUTTON_REMOTE)) |
| 1112 | { |
| 1113 | ret |= ACTION_REMOTE; |
| 1114 | } |
| 1115 | |
| 1116 | if (action_last.repeated) |
| 1117 | { |
| 1118 | ret |= ACTION_REPEAT; |
| 1119 | } |
| 1120 | |
| 1121 | return ret; |
| 1122 | } |
| 1123 | |
| 1124 | #ifdef HAVE_BACKLIGHT |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1125 | /* Enable selected actions to leave the backlight off */ |
| 1126 | void set_selective_backlight_actions(bool selective, unsigned int mask, |
| 1127 | bool filter_fkp) |
| 1128 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1129 | action_handle_backlight(true, selective); |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1130 | if (selective) /* we will handle filter_first_keypress here so turn it off*/ |
| 1131 | { |
| 1132 | set_backlight_filter_keypress(false);/* turnoff ffkp in button.c */ |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1133 | action_last.backlight_mask = mask | SEL_ACTION_ENABLED; |
| 1134 | if (filter_fkp) |
| 1135 | { |
| 1136 | action_last.backlight_mask |= SEL_ACTION_FFKEYPRESS; |
| 1137 | } |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1138 | } |
| 1139 | else |
| 1140 | { |
| 1141 | set_backlight_filter_keypress(filter_fkp); |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1142 | action_last.backlight_mask = SEL_ACTION_NONE; |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1143 | } |
| 1144 | } |
| 1145 | #endif /* HAVE_BACKLIGHT */ |
| 1146 | |
| 1147 | #ifndef HAS_BUTTON_HOLD |
| 1148 | bool is_keys_locked(void) |
| 1149 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1150 | return (action_last.screen_has_lock && action_last.keys_locked); |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1151 | } |
| 1152 | |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1153 | /* Enable selected actions to bypass a locked state */ |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1154 | void set_selective_softlock_actions(bool selective, unsigned int mask) |
| 1155 | { |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1156 | action_last.keys_locked = false; |
| 1157 | if (selective) |
| 1158 | { |
| 1159 | action_last.softlock_mask = mask | SEL_ACTION_ENABLED; |
| 1160 | } |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1161 | else |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1162 | { |
| 1163 | action_last.softlock_mask = SEL_ACTION_NONE; |
| 1164 | } |
William Wilgus | dc87e9e | 2016-11-22 06:21:31 +0100 | [diff] [blame] | 1165 | } |
William Wilgus | b10c0e5 | 2017-09-26 16:32:07 +0200 | [diff] [blame] | 1166 | #endif /* !HAS_BUTTON_HOLD */ |
| 1167 | /* |
| 1168 | ******************************************************************************* |
| 1169 | * END EXPORTED ACTION FUNCTIONS *********************************************** |
| 1170 | *******************************************************************************/ |