Selective Backlight/Advanced Softlock - Selective actions based on context

Selective backlight allows the user to choose actions that will not
enable the backlight when pressed.

Advanced softlock allows user to choose actions that  will not be
blocked by screenlock on devices without a hold button.

Both only occur in FM and WPS Contexts.

Update:
Back from the dead
-Cleaned up code, removed unnecessary calls, re-arranged last filter action
  timeout conditional to work in case last_filtered_action_tick was never set
-Added entries to the manual
-Fixed back button on some menus not activating backlight
-Made menus more intuitive, no actions selected now changes menu item to off.
-Added talk fuctionality.
-Added option to disable selective backlight while on external power.
-Rewrote backlight and softlock handling code to fix issue with scrollwheels
-Menu changed to have toggle(yes/no) and settings
-Optimized selective actions lookup
-Added option to disable notification of 'buttons locked' while softlocked
-Removed uneeded code, consolidated action lookup to single function
-Fixed incorrect name on selective softlock menu
-Added option to disable touch on touchscreen devices
-Fixed backlight on original screenlock without selective screenlock active
-Added text selection in mask_select for when show_icons is off
-Fixed voice in mask_select to speak if voice is defined instead of spelling
-Added more lang defines (play skip seek)
-Added option to disable unknown keys turning on backlight
-Fixed Conditional argument In wrong place causing players without
	backlight to fail to build
-Fixed Disable Unknown blocking detection of context change
-Fixed canceling menu didn't update new settings
-Added Autolock on backlight off
-Removed backlight_on_force from backlight.c, Now sets ignore next to false
	and uses backlight_on
-Cleaned up autolock code added strings to lang file
-Fixed issue where rapid presses would bypass softlock
-Removed old softlock code, Cleaned selective actions code
-Changed menu to match existing RB menus
-Fixed Backlight_on_Hold blocked by backlight_ignore_next
-Fixed ignore_next for ipod
-Fixed bug allowing context with softlock to bypass selective backlight
-Changed mask_select to no longer prompt for changes to be saved
-Changed menu names
-Added ignore timeout to allow ipod scroll wheel to work properly and other
 players to still work properly, removed some previous code including
 ignore_event
-Increased ignore timeout to prevent sd card accesses from interrupting action
 code and turning on backlight
-Changed Unknown action to unmapped action in menu, changed handling code
-Removed unneeded logic and variables for handling unfiltered actions
-Reverted unmapped action code to previous functionality
-Added manual entries (thanks JohnB)
-Removed elusive unhandled unicode character from manual, changed formatting slightly

Actions:
Volume,Play,Seek,Skip

Extras:
Disable unmapped actions
Disable selective backlight on external power
Disable touch during softlock on touchscreen devices
Disable softlock notifications (power button still notifies)
Autolock on backlight off

Method:
Adds a function to ignore backlight on next call
 If selected action occurs backlight is forced on,
 Filter_first_keypress stays intact.

Selective softlock allows selected actions through, bypasses the normal
 softlock routine.

ToDo:
DONE

previous commit (#1) has attribution for folder_select.c which mask_select
is based from.

Change-Id: I08132ddcfd64c81751ef23b720f3ec6d68695fe4
This commit is contained in:
William Wilgus 2016-11-22 06:21:31 +01:00
parent 16a9f84571
commit dc87e9e9f3
18 changed files with 1504 additions and 333 deletions

View file

@ -95,6 +95,9 @@ gui/pitchscreen.c
gui/quickscreen.c gui/quickscreen.c
#endif #endif
gui/folder_select.c gui/folder_select.c
#if defined(HAVE_BACKLIGHT) || !defined(HAS_BUTTON_HOLD)
gui/mask_select.c
#endif
gui/wps.c gui/wps.c
gui/scrollbar.c gui/scrollbar.c

View file

@ -42,6 +42,16 @@
#include "statusbar-skinned.h" #include "statusbar-skinned.h"
#endif #endif
#ifdef HAVE_BACKLIGHT
#include "backlight.h"
#if CONFIG_CHARGING
#include "power.h"
#endif
#endif /* HAVE_BACKLIGHT */
#define LOGF_ENABLE
#include "logf.h"
static int last_button = BUTTON_NONE|BUTTON_REL; /* allow the ipod wheel to static int last_button = BUTTON_NONE|BUTTON_REL; /* allow the ipod wheel to
work on startup */ work on startup */
static intptr_t last_data = 0; static intptr_t last_data = 0;
@ -56,19 +66,34 @@ static bool short_press = false;
#define REPEAT_WINDOW_TICKS HZ/4 #define REPEAT_WINDOW_TICKS HZ/4
static int last_action_tick = 0; static int last_action_tick = 0;
#if defined(HAVE_BACKLIGHT) || !defined(HAS_BUTTON_HOLD)
static inline bool is_action_normal(int action);
static inline bool mask_has_flag(unsigned int mask, unsigned int flag);
static inline bool is_action_completed(int button);
#define LAST_FILTER_TICKS HZ/2 /* timeout between filtered actions */
#endif /* defined(HAVE_BACKLIGHT) || !defined(HAS_BUTTON_HOLD) */
#ifdef HAVE_BACKLIGHT
static unsigned int backlight_mask = SEL_ACTION_NONE;
static int do_backlight(int action, int context, bool is_pre_btn);
static void handle_backlight(bool backlight, bool ignore_next);
#endif /* HAVE_BACKLIGHT */
/* software keylock stuff */ /* software keylock stuff */
#ifndef HAS_BUTTON_HOLD #ifndef HAS_BUTTON_HOLD
static bool keys_locked = false; static bool keys_locked = false;
static int unlock_combo = BUTTON_NONE;
static bool screen_has_lock = false; static bool screen_has_lock = false;
static unsigned int softlock_mask = SEL_ACTION_NONE;
static inline int do_softlock_unlock_combo(int button, int context);
static int do_softlock(int button, int action, int context, bool is_pre_btn);
#endif /* HAVE_SOFTWARE_KEYLOCK */ #endif /* HAVE_SOFTWARE_KEYLOCK */
/* /*
* do_button_check is the worker function for get_default_action. * do_button_check is the worker function for get_default_action.
* returns ACTION_UNKNOWN or the requested return value from the list. * returns ACTION_UNKNOWN or the requested return value from the list.
* BE AWARE is_pre_button can miss pre buttons if a match is found first.
*/ */
static inline int do_button_check(const struct button_mapping *items, static inline int do_button_check(const struct button_mapping *items,int button,
int button, int last_button, int *start) int last_button, int *start, bool *prebtn)
{ {
int i = 0; int i = 0;
int ret = ACTION_UNKNOWN; int ret = ACTION_UNKNOWN;
@ -88,6 +113,8 @@ static inline int do_button_check(const struct button_mapping *items,
break; break;
} }
} }
else if (items[i].pre_button_code & button)
*prebtn = true; /* determine if this could be another action */
i++; i++;
} }
*start = i; *start = i;
@ -188,8 +215,8 @@ static int gui_unboost_callback(struct timeout *tmo)
#endif #endif
/* /*
* int get_action_worker(int context, struct button_mapping *user_mappings, * int get_action_worker(int context, int timeout, bool *is_pre_button,
int timeout) struct button_mapping *user_mappings)
This function searches the button list for the given context for the just This function searches the button list for the given context for the just
pressed button. pressed button.
If there is a match it returns the value from the list. If there is a match it returns the value from the list.
@ -197,12 +224,14 @@ static int gui_unboost_callback(struct timeout *tmo)
the last item in the list "points" to the next context in a chain the last item in the list "points" to the next context in a chain
so the "chain" is followed until the button is found. so the "chain" is followed until the button is found.
putting ACTION_NONE will get CONTEXT_STD which is always the last list checked. putting ACTION_NONE will get CONTEXT_STD which is always the last list checked.
BE AWARE is_pre_button can miss pre buttons if a match is found first.
it is more for actions that are not yet completed in the desired context
but are defined in a lower 'chained' context.
Timeout can be TIMEOUT_NOBLOCK to return immediatly Timeout can be TIMEOUT_NOBLOCK to return immediatly
TIMEOUT_BLOCK to wait for a button press TIMEOUT_BLOCK to wait for a button press
Any number >0 to wait that many ticks for a press Any number >0 to wait that many ticks for a press
*/ */
static int get_action_worker(int context, int timeout, static int get_action_worker(int context, int timeout, bool *is_pre_button,
const struct button_mapping* (*get_context_map)(int) ) const struct button_mapping* (*get_context_map)(int) )
{ {
const struct button_mapping *items = NULL; const struct button_mapping *items = NULL;
@ -288,39 +317,24 @@ static int get_action_worker(int context, int timeout,
return ACTION_NONE; /* "safest" return value */ return ACTION_NONE; /* "safest" return value */
} }
last_context = context; last_context = context;
#ifndef HAS_BUTTON_HOLD #ifndef HAS_BUTTON_HOLD
screen_has_lock = ((context & ALLOW_SOFTLOCK) == ALLOW_SOFTLOCK); screen_has_lock = ((context & ALLOW_SOFTLOCK) == ALLOW_SOFTLOCK);
context &= ~ALLOW_SOFTLOCK;
if (is_keys_locked()) if (is_keys_locked())
{ {
if (button == unlock_combo) ret = do_softlock_unlock_combo(button, context);
{ if (!is_keys_locked())
last_button = BUTTON_NONE; return ret;
keys_locked = false;
#if defined(HAVE_TOUCHPAD) || defined(HAVE_TOUCHSCREEN)
/* enable back touch device */
button_enable_touch(true);
#endif
splash(HZ/2, str(LANG_KEYLOCK_OFF));
return ACTION_REDRAW;
}
else
#if (BUTTON_REMOTE != 0)
if ((button & BUTTON_REMOTE) == 0)
#endif
{
if ((button & BUTTON_REL))
splash(HZ/2, str(LANG_KEYLOCK_ON));
return ACTION_REDRAW;
}
} }
#if defined(HAVE_TOUCHPAD) || defined(HAVE_TOUCHSCREEN) #if defined(HAVE_TOUCHPAD) || defined(HAVE_TOUCHSCREEN)
else else if (!mask_has_flag(softlock_mask, SEL_ACTION_NOTOUCH))
{ {
/* make sure touchpad get reactivated if we quit the screen */ /* make sure touchpad get reactivated if we quit the screen */
button_enable_touch(true); button_enable_touch(true);
} }
#endif #endif
context &= ~ALLOW_SOFTLOCK;
#endif /* HAS_BUTTON_HOLD */ #endif /* HAS_BUTTON_HOLD */
#ifdef HAVE_TOUCHSCREEN #ifdef HAVE_TOUCHSCREEN
@ -348,6 +362,7 @@ static int get_action_worker(int context, int timeout,
#endif #endif
/* logf("%x,%x",last_button,button); */ /* logf("%x,%x",last_button,button); */
*is_pre_button = false; /* could the button be another actions pre_button */
while (1) while (1)
{ {
/* logf("context = %x",context); */ /* logf("context = %x",context); */
@ -363,7 +378,7 @@ static int get_action_worker(int context, int timeout,
if (items == NULL) if (items == NULL)
break; break;
ret = do_button_check(items,button,last_button,&i); ret = do_button_check(items, button, last_button, &i, is_pre_button);
if (ret == ACTION_UNKNOWN) if (ret == ACTION_UNKNOWN)
{ {
@ -375,24 +390,13 @@ static int get_action_worker(int context, int timeout,
continue; continue;
} }
} }
/* Action was found or STOPSEARCHING was specified */ /* Action was found or STOPSEARCHING was specified */
break; break;
} }
/* DEBUGF("ret = %x\n",ret); */ /* DEBUGF("ret = %x\n",ret); */
#ifndef HAS_BUTTON_HOLD #ifndef HAS_BUTTON_HOLD
if (screen_has_lock && (ret == ACTION_STD_KEYLOCK)) if(screen_has_lock && is_action_normal(ret))
{ ret = do_softlock(button, ret, last_context & ~ALLOW_SOFTLOCK, is_pre_button);
unlock_combo = button;
keys_locked = true;
splash(HZ/2, str(LANG_KEYLOCK_ON));
#if defined(HAVE_TOUCHPAD) || defined(HAVE_TOUCHSCREEN)
/* disable touch device on keylock */
button_enable_touch(false);
#endif
button_clear_queue();
return ACTION_REDRAW;
}
#endif #endif
if ((current_tick - last_action_tick < REPEAT_WINDOW_TICKS) if ((current_tick - last_action_tick < REPEAT_WINDOW_TICKS)
&& (ret == last_action)) && (ret == last_action))
@ -411,27 +415,38 @@ static int get_action_worker(int context, int timeout,
#endif #endif
return ret; return ret;
} }/* get_action_worker */
int get_action(int context, int timeout) int get_action(int context, int timeout)
{ {
int button = get_action_worker(context,timeout,NULL); bool is_pre_button = false;
int button = get_action_worker(context, timeout, &is_pre_button, NULL);
#ifdef HAVE_TOUCHSCREEN #ifdef HAVE_TOUCHSCREEN
if (button == ACTION_TOUCHSCREEN) if (button == ACTION_TOUCHSCREEN)
button = sb_touch_to_button(context); button = sb_touch_to_button(context);
#endif #endif
#ifdef HAVE_BACKLIGHT
if (mask_has_flag(backlight_mask, SEL_ACTION_ENABLED) &&
is_action_normal(button))
button = do_backlight(button, context & ~ALLOW_SOFTLOCK, is_pre_button);
#endif
return button; return button;
} }
int get_custom_action(int context,int timeout, int get_custom_action(int context,int timeout,
const struct button_mapping* (*get_context_map)(int)) const struct button_mapping* (*get_context_map)(int))
{ {
return get_action_worker(context,timeout,get_context_map); bool is_pre_button = false;
return get_action_worker(context,timeout, &is_pre_button, get_context_map);
} }
bool action_userabort(int timeout) bool action_userabort(int timeout)
{ {
int action = get_action_worker(CONTEXT_STD,timeout,NULL); bool is_pre_button = false;
int action = get_action_worker(CONTEXT_STD,timeout, &is_pre_button, NULL);
bool ret = (action == ACTION_STD_CANCEL); bool ret = (action == ACTION_STD_CANCEL);
if (!ret) if (!ret)
{ {
@ -440,13 +455,6 @@ bool action_userabort(int timeout)
return ret; return ret;
} }
#ifndef HAS_BUTTON_HOLD
bool is_keys_locked(void)
{
return (screen_has_lock && keys_locked);
}
#endif
intptr_t get_action_data(void) intptr_t get_action_data(void)
{ {
return last_data; return last_data;
@ -533,3 +541,337 @@ void action_wait_for_release(void)
wait_for_release = true; wait_for_release = true;
} }
#if defined(HAVE_BACKLIGHT) || !defined(HAS_BUTTON_HOLD)
/* HELPER FUNCTIONS
* Selective softlock and backlight use this lookup based on mask to decide
* which actions are filtered, or could be filtered but not currently set.
* returns false if the action isn't found, true if the action is found
*/
static bool is_action_filtered(int action, unsigned int mask, int context)
{
bool match = false;
switch (action)
{
case ACTION_NONE:
break;
/*Actions that are not mapped will not turn on the backlight option NOUNMAPPED*/
case ACTION_UNKNOWN:
match = mask_has_flag(mask, SEL_ACTION_NOUNMAPPED);
break;
case ACTION_WPS_PLAY:
case ACTION_FM_PLAY:
match = mask_has_flag(mask, SEL_ACTION_PLAY);
break;
case ACTION_STD_PREVREPEAT:
case ACTION_STD_NEXTREPEAT:
case ACTION_WPS_SEEKBACK:
case ACTION_WPS_SEEKFWD:
case ACTION_WPS_STOPSEEK:
match = mask_has_flag(mask, SEL_ACTION_SEEK);
break;
case ACTION_STD_PREV:
case ACTION_STD_NEXT:
case ACTION_WPS_SKIPNEXT:
case ACTION_WPS_SKIPPREV:
case ACTION_FM_NEXT_PRESET:
case ACTION_FM_PREV_PRESET:
match = mask_has_flag(mask, SEL_ACTION_SKIP);
break;
case ACTION_WPS_VOLUP:
case ACTION_WPS_VOLDOWN:
match = mask_has_flag(mask, SEL_ACTION_VOL);
break;
case ACTION_SETTINGS_INC:/*FMS*/
case ACTION_SETTINGS_INCREPEAT:/*FMS*/
case ACTION_SETTINGS_DEC:/*FMS*/
case ACTION_SETTINGS_DECREPEAT:/*FMS*/
match = (context == CONTEXT_FM) && mask_has_flag(mask, SEL_ACTION_VOL);
break;
default:
/* display action code of unfiltered actions */
logf ("unfiltered actions: context: %d action: %d, last btn: %d, \
mask: %d", context, action, last_button, mask);
break;
}/*switch*/
return match;
}
/* compares mask to a flag return true if set false otherwise*/
static inline bool mask_has_flag(unsigned int mask, unsigned int flag)
{
return ((mask & flag) != 0);
}
/* returns true if the supplied context is to be filtered by selective BL/SL*/
static inline bool is_context_filtered(int context)
{
return (context == CONTEXT_FM || context == CONTEXT_WPS);
}
/* returns true if action can be passed on to selective backlight/softlock */
static inline bool is_action_normal(int action)
{
return (action != ACTION_REDRAW && (action & SYS_EVENT) == 0);
}
/*returns true if Button & released, repeated; or won't generate those events*/
static inline bool is_action_completed(int button)
{
return ((button & (BUTTON_REPEAT | BUTTON_REL)) != 0
#ifdef HAVE_SCROLLWHEEL
/* Scrollwheel doesn't generate release events */
|| (button & (BUTTON_SCROLL_BACK | BUTTON_SCROLL_FWD)) != 0
#endif
);
}
/* most every action takes two rounds through get_action_worker,
* once for the keypress and once for the key release,
* actions with pre_button codes take even more, some actions however, only
* take once; actions defined with only a button and no release/repeat event,
* these actions should be acted upon immediately except when we have
* selective backlighting/softlock enabled and in this case we only act upon
* them immediately if there is no chance they have another event tied to them
* determined using is_pre_button and is_action_completed()
*returns true if event was not filtered and false if it was
*/
static bool is_action_unfiltered(int action,int button, bool is_pre_button,
bool filtered, int *tick)
{
bool ret = false;
/*directly after a match a key release event may trigger another*/
if (filtered && action != ACTION_UNKNOWN)
*tick = current_tick + LAST_FILTER_TICKS;
/* has button been rel/rep or is this the only action it could be */
if (is_action_completed(button) || !is_pre_button)
{
/* reset last action , if the action is not filtered and
this isn't just a key release event then return true */
if (!filtered && *tick < current_tick)
{
*tick = 0;
ret = true;
}
}/*is_action_completed() || !is_pre_button*/
return ret;
}
#endif /*defined(HAVE_BACKLIGHT) || !defined(HAS_BUTTON_HOLD) HELPER FUNCTIONS*/
#ifdef HAVE_BACKLIGHT
static void handle_backlight(bool backlight, bool ignore_next)
{
if (backlight)
{
backlight_on_ignore(false, 0);
backlight_on();
#ifdef HAVE_BUTTON_LIGHT
buttonlight_on_ignore(false, 0);
buttonlight_on();
}
buttonlight_on_ignore(ignore_next, 5*HZ);/* as a precautionary fallback */
#else
}
#endif
backlight_on_ignore(ignore_next, 5*HZ);/*must be set everytime we handle bl*/
}
/* Need to look up actions before we can decide to turn on backlight, if
* selective backlighting is true filter first keypress events need to be
* taken into account as well
*/
static int do_backlight(int action, int context, bool is_pre_btn)
{
static int last_filtered_tick = 0;
bool bl_is_active = is_backlight_on(false);
bool bl_activate = false;
bool filtered;
#if CONFIG_CHARGING /* disable if on external power */
if (!bl_is_active && is_context_filtered(context) &&
!(mask_has_flag(backlight_mask, SEL_ACTION_NOEXT) && power_input_present()))
#else /* skip if backlight is on or incorrect context */
if (!bl_is_active && is_context_filtered(context))
#endif
{
filtered = is_action_filtered(action, backlight_mask, context);
bl_activate = is_action_unfiltered(action, last_button, is_pre_btn,
filtered, &last_filtered_tick);
}/*is_context_filtered(context)*/
else
bl_activate = true;
if (action != ACTION_NONE && bl_activate)
{
handle_backlight(true, true);
if (mask_has_flag(backlight_mask, SEL_ACTION_FFKEYPRESS) && !bl_is_active)
{
action = ACTION_NONE;
last_button = BUTTON_NONE;
}
}
else
handle_backlight(false, true);/* set ignore next true */
return action;
}
/* Enable selected actions to leave the backlight off */
void set_selective_backlight_actions(bool selective, unsigned int mask,
bool filter_fkp)
{
handle_backlight(true, selective);
if (selective) /* we will handle filter_first_keypress here so turn it off*/
{
set_backlight_filter_keypress(false);/* turnoff ffkp in button.c */
backlight_mask = mask | SEL_ACTION_ENABLED;
if(filter_fkp)
backlight_mask |= SEL_ACTION_FFKEYPRESS;
}
else
{
set_backlight_filter_keypress(filter_fkp);
backlight_mask = SEL_ACTION_NONE;
}
}
#endif /* HAVE_BACKLIGHT */
#ifndef HAS_BUTTON_HOLD
bool is_keys_locked(void)
{
return (screen_has_lock && keys_locked);
}
static inline void do_key_lock(bool lock)
{
keys_locked = lock;
last_button = BUTTON_NONE;
button_clear_queue();
#if defined(HAVE_TOUCHPAD) || defined(HAVE_TOUCHSCREEN)
/* disable touch device on keylock if std behavior or selected disable touch */
if (!mask_has_flag(softlock_mask, SEL_ACTION_ENABLED) ||
mask_has_flag(softlock_mask, SEL_ACTION_NOTOUCH))
button_enable_touch(!lock);
#endif
}
/* user selected autolock based on backlight timeout; toggles autolock on / off
by ACTION_STD_KEYLOCK presses, Activates autolock if set on backlight timeout
*/
#ifdef HAVE_BACKLIGHT
static inline int do_auto_softlock(int button, int action, int *unlock_combo)
{
if(mask_has_flag(softlock_mask, SEL_ACTION_ALOCK_OK) && !is_backlight_on(false))
do_key_lock(true);
else if (action == ACTION_STD_KEYLOCK)
{
*unlock_combo = button;/* set unlock combo to allow unlock */
softlock_mask ^= SEL_ACTION_ALOCK_OK;
handle_backlight(true, false);
/* If we don't wait for a moment for the backlight queue
* to process, the user will never see the message */
if (!is_backlight_on(false))
sleep(HZ/2);
if (mask_has_flag(softlock_mask, SEL_ACTION_ALOCK_OK))
{
splash(HZ/2, ID2P(LANG_ACTION_AUTOLOCK_ON));
action = ACTION_REDRAW;
}
else
splash(HZ/2, ID2P(LANG_ACTION_AUTOLOCK_OFF));
}
return action;
}
#endif
/* Allows unlock softlock when action is not yet known but unlock_combo set*/
static inline int do_softlock_unlock_combo(int button, int context)
{
return do_softlock(button, ACTION_NONE, context, false);
}
/* Handles softlock once action is known */
static int do_softlock(int button, int action, int context, bool is_pre_btn)
{
static int last_filtered_tick = 0;
static int unlock_combo = BUTTON_NONE; /*Moved from GLOBAL*/
bool filtered = true;
bool notify_user = false;
bool sl_activate = true; /* standard softlock behavior */
#ifdef HAVE_BACKLIGHT
if (!keys_locked && mask_has_flag(softlock_mask, SEL_ACTION_AUTOLOCK))
action = do_auto_softlock(button, action, &unlock_combo);
#endif
/* Lock/Unlock toggled by ACTION_STD_KEYLOCK presses*/
if ((action == ACTION_STD_KEYLOCK) || (keys_locked && unlock_combo == button))
{
unlock_combo = button;
do_key_lock(!keys_locked);
notify_user = true;
}
#if (BUTTON_REMOTE != 0)/* Allow remote actions through */
else if (mask_has_flag(button, BUTTON_REMOTE))
notify_user = false;
#endif
else if (keys_locked && action != ACTION_NONE && action != ACTION_REDRAW)
{
if (mask_has_flag(softlock_mask, SEL_ACTION_ENABLED))
{
filtered = is_action_filtered(action, softlock_mask, context);
sl_activate = is_action_unfiltered(action, button, is_pre_btn,
filtered, &last_filtered_tick);
}
/*All non-std softlock options are set to 0 if advanced sl is disabled*/
if (sl_activate)
{
if (!mask_has_flag(softlock_mask, SEL_ACTION_NONOTIFY))
{ /* always true on standard softlock behavior*/
notify_user = mask_has_flag(button, BUTTON_REL);
action = ACTION_REDRAW;
}
else
action = ACTION_NONE;
}
else if (!filtered)/*catch blocked actions on fast repeated presses*/
action = ACTION_NONE;
} /* keys_locked */
#ifdef BUTTON_POWER /*always notify if power button pressed while keys locked*/
notify_user |= (mask_has_flag(button, BUTTON_POWER) && keys_locked);
#endif
if (notify_user)
{
#ifdef HAVE_BACKLIGHT
handle_backlight(true, false);
/* If we don't wait for a moment for the backlight queue
* to process, the user will never see the message */
if (!is_backlight_on(false))
sleep(HZ/2);
#endif
if (keys_locked)
splash(HZ/2, ID2P(LANG_KEYLOCK_ON));
else
splash(HZ/2, ID2P(LANG_KEYLOCK_OFF));
last_button = BUTTON_NONE;
action = ACTION_REDRAW;
button_clear_queue();
}
return action;
}
void set_selective_softlock_actions(bool selective, unsigned int mask)
{
keys_locked = false;
if(selective)
softlock_mask = mask | SEL_ACTION_ENABLED;
else
softlock_mask = SEL_ACTION_NONE;
}
#endif /* HAS_BUTTON_HOLD */

View file

@ -41,7 +41,36 @@
#else #else
#define ALLOW_SOFTLOCK 0 #define ALLOW_SOFTLOCK 0
#endif #endif
#if defined(HAVE_BACKLIGHT) || !defined(HAS_BUTTON_HOLD)
/* Selective action selection flags */
#define SEL_ACTION_NONE 0
#define SEL_ACTION_VOL 0x001U
#define SEL_ACTION_PLAY 0x002U
#define SEL_ACTION_SEEK 0x004U
#define SEL_ACTION_SKIP 0x008U
#define SEL_ACTION_NOUNMAPPED 0x010U/* disable backlight on unmapped buttons */
/* Available 0x020U*/
/* Available 0x040U*/
#define SEL_ACTION_NOTOUCH 0x080U/* disable touch screen/pad on screen lock */
#define SEL_ACTION_AUTOLOCK 0x100U/* autolock on backlight off */
#define SEL_ACTION_NOEXT 0x200U/* disable selective backlight while charge*/
#define SEL_ACTION_NONOTIFY 0x200U/* don't notify user softlock is active */
/* Flags below are internal to selective functions */
#define SEL_ACTION_ALOCK_OK 0x400U/*autolock only active after key lock once*/
#define SEL_ACTION_FFKEYPRESS 0x400U/* backlight Filter First Keypress active*/
#define SEL_ACTION_ENABLED 0x800U
/* Selective Actions flags */
#ifndef HAS_BUTTON_HOLD
bool is_keys_locked(void);
void set_selective_softlock_actions(bool selective, unsigned int mask);
#endif
#ifdef HAVE_BACKLIGHT
void set_selective_backlight_actions(bool selective, unsigned int mask,
bool filter_fkp);
#endif
#endif /* defined(HAVE_BACKLIGHT) || !defined(HAS_BUTTON_HOLD) */
enum { enum {
CONTEXT_STD = 0, CONTEXT_STD = 0,
/* These CONTEXT_ values were here before me, /* These CONTEXT_ values were here before me,
@ -347,9 +376,6 @@ bool action_userabort(int timeout);
/* no other code should need this apart from action.c */ /* no other code should need this apart from action.c */
const struct button_mapping* get_context_mapping(int context); const struct button_mapping* get_context_mapping(int context);
#ifndef HAS_BUTTON_HOLD
bool is_keys_locked(void);
#endif
/* returns the status code variable from action.c for the button just pressed /* returns the status code variable from action.c for the button just pressed
If button != NULL it will be set to the actual button code */ If button != NULL it will be set to the actual button code */

287
apps/gui/mask_select.c Normal file
View file

@ -0,0 +1,287 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* Copyright (C) 2016 William Wilgus
* Derivative of folder_select.c by:
* Copyright (C) 2012 Jonathan Gordon
* Copyright (C) 2012 Thomas Martitz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
/* TODO add language defines */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lang.h"
#include "language.h"
#include "list.h"
#include "plugin.h"
#include "mask_select.h"
#include "talk.h"
/*
* Order for changing child states:
* 1) expand folder
* 2) collapse and select
* 3) deselect (skip to 1)
*/
enum child_state {
EXPANDED,
SELECTED,
COLLAPSED,
DESELECTED,
};
/* Children of main categories */
struct child {
const char* name;
struct category *category;
enum child_state state;
int key_value;
};
/* Main Categories in root */
struct category {
const char *name;
struct child *children;
int children_count;
int depth;
struct category* previous;
int key_value; /*values of all children OR|D*/
};
/* empty category for children of root only one level needed */
static struct category empty = {
.name = "",
.children = NULL,
.children_count = 0,
.depth = 1,
.previous = NULL,
};
/* Or | all keyvalues that user selected */
static int calculate_mask_r(struct category *root, int mask)
{
int i = 0;
while (i < root->children_count)
{
struct child *this = &root->children[i];
if (this->state == SELECTED)
mask |= this->key_value;
else if (this->state == EXPANDED)
mask = calculate_mask_r(this->category, mask);
i++;
}
return mask;
}
static int count_items(struct category *start)
{
int count = 0;
int i;
for (i=0; i<start->children_count; i++)
{
struct child *foo = &start->children[i];
if (foo->state == EXPANDED)
count += count_items(foo->category);
count++;
}
return count;
}
static struct child* find_index(struct category *start,
int index,struct category **parent)
{
int i = 0;
*parent = NULL;
while (i < start->children_count)
{
struct child *foo = &start->children[i];
if (i == index)
{
*parent = start;
return foo;
}
i++;
if (foo->state == EXPANDED)
{
struct child *bar = find_index(foo->category, index - i, parent);
if (bar)
{
return bar;
}
index -= count_items(foo->category);
}
}
return NULL;
}
/* simplelist uses this callback to change
the states of the categories/children */
static int item_action_callback(int action, struct gui_synclist *list)
{
struct category *root = (struct category*)list->data;
struct category *parent;
struct child *this = find_index(root, list->selected_item, &parent);
if (action == ACTION_STD_OK)
{
switch (this->state)
{
case EXPANDED:
this->state = SELECTED;
if (global_settings.talk_menu)
talk_id(LANG_ON, false);
break;
case SELECTED:
this->state = this->category->children_count == 0 ?
DESELECTED : COLLAPSED;
if (global_settings.talk_menu && this->category->children_count == 0)
talk_id(LANG_OFF, false);
break;
case COLLAPSED:
if (this->category == NULL)
this->category = root;
this->state = this->category->children_count == 0 ?
SELECTED : EXPANDED;
if (global_settings.talk_menu && this->category->children_count == 0)
talk_id(LANG_ON, false);
break;
case DESELECTED:
this->state = SELECTED;
if (global_settings.talk_menu)
talk_id(LANG_ON, false);
break;
default:
/* do nothing */
return action;
}
list->nb_items = count_items(root);
return ACTION_REDRAW;
}
return action;
}
static const char * item_get_name(int selected_item, void * data,
char * buffer, size_t buffer_len)
{
struct category *root = (struct category*)data;
struct category *parent;
struct child *this = find_index(root, selected_item , &parent);
buffer[0] = '\0';
if (parent->depth >= 0)
for(int i = 0; i <= parent->depth; i++)
strcat(buffer, "\t\0");
/* state of selection needs icons so if icons are disabled use text*/
if (!global_settings.show_icons)
{
if (this->state == SELECTED)
strcat(buffer, "+\0");
else
strcat(buffer," \0");
}
strlcat(buffer, P2STR((const unsigned char *)this->name), buffer_len);
return buffer;
}
static int item_get_talk(int selected_item, void *data)
{
struct category *root = (struct category*)data;
struct category *parent;
struct child *this = find_index(root, selected_item , &parent);
if (global_settings.talk_menu)
{
long id = P2ID((const unsigned char *)(this->name));
if(id>=0)
talk_id(id, true);
else
talk_spell(this->name, true);
talk_id(VOICE_PAUSE,true);
if (this->state == SELECTED)
talk_id(LANG_ON, true);
else if (this->state == DESELECTED)
talk_id(LANG_OFF, true);
}
return 0;
}
static enum themable_icons item_get_icon(int selected_item, void * data)
{
struct category *root = (struct category*)data;
struct category *parent;
struct child *this = find_index(root, selected_item, &parent);
switch (this->state)
{
case SELECTED:
return Icon_Submenu;
case COLLAPSED:
return Icon_NOICON;
case EXPANDED:
return Icon_Submenu_Entered;
default:
return Icon_NOICON;
}
return Icon_NOICON;
}
/* supply your original mask,the page header (ie. User do this..), mask items
and count, they will be selected automatically if the mask includes
them. If user selects new items and chooses to save settings
new mask returned otherwise, original is returned
*/
int mask_select(int mask, const unsigned char* headermsg,
struct s_mask_items *mask_items, size_t items)
{
struct simplelist_info info;
struct child action_child[items];
for (unsigned i = 0; i < items; i++)
{
action_child[i].name = mask_items[i].name;
action_child[i].category = &empty;
action_child[i].key_value = mask_items[i].bit_value;
action_child[i].state = mask_items[i].bit_value & mask ?
SELECTED : DESELECTED;
}
struct category root = {
.name = "",
.children = (struct child*) &action_child,
.children_count = items,
.depth = -1,
.previous = NULL,
};
simplelist_info_init(&info, P2STR(headermsg), count_items(&root), &root);
info.get_name = item_get_name;
info.action_callback = item_action_callback;
info.get_icon = item_get_icon;
info.get_talk = item_get_talk;
simplelist_show_list(&info);
return calculate_mask_r(&root,0);
}

41
apps/gui/mask_select.h Normal file
View file

@ -0,0 +1,41 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2016 William Wilgus
* Derivative of folder_select.h by:
* Copyright (C) 2011 Jonathan Gordon
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef __MASK_SELECT_H__
#define __MASK_SELECT_H__
/**
* A GUI browser to select masks on a target
*
* It reads an original mask supplied to function
* and pre-selects the corresponding actions in the UI. If the user is done it
* returns the new mask, assuming the user confirms the yesno dialog.
*
* Returns new mask if the selected options have changed, otherwise
* returns the mask originally supplied */
struct s_mask_items {
const char* name;
const int bit_value;
};
int mask_select(int mask, const unsigned char* headermsg,
struct s_mask_items *mask_items, size_t items);
#endif /* __MASK_SELECT_H__ */

View file

@ -13479,3 +13479,171 @@
ibassodx90: "Android Debug Bridge" ibassodx90: "Android Debug Bridge"
</voice> </voice>
</phrase> </phrase>
<phrase>
id: LANG_ACTION_ENABLED
desc: Selective Actions
user: core
<source>
*: "Enabled"
</source>
<dest>
*: "Enabled"
</dest>
<voice>
*: "Enabled"
</voice>
</phrase>
<phrase>
id: LANG_ACTION_PLAY
desc: Selective Actions
user: core
<source>
*: "Play"
</source>
<dest>
*: "Play"
</dest>
<voice>
*: "Play"
</voice>
</phrase>
<phrase>
id: LANG_ACTION_SEEK
desc: Selective Actions
user: core
<source>
*: "Seek"
</source>
<dest>
*: "Seek"
</dest>
<voice>
*: "Seek"
</voice>
</phrase>
<phrase>
id: LANG_ACTION_SKIP
desc: Selective Actions
user: core
<source>
*: "Skip"
</source>
<dest>
*: "Skip"
</dest>
<voice>
*: "Skip"
</voice>
</phrase>
<phrase>
id: LANG_BACKLIGHT_SELECTIVE
desc: Backlight behaviour setting
user: core
<source>
*: "Selective Backlight"
</source>
<dest>
*: "Selective Backlight"
</dest>
<voice>
*: "Selective Backlight"
</voice>
</phrase>
<phrase>
id: LANG_ACTION_DISABLE_EXT_POWER
desc: Backlight behaviour setting
user: core
<source>
*: "Disable on External Power"
</source>
<dest>
*: "Disable on External Power"
</dest>
<voice>
*: "Disable on External Power"
</voice>
</phrase>
<phrase>
id: LANG_ACTION_DISABLE_UNMAPPED
desc: Backlight behaviour setting
user: core
<source>
*: "Disable Unmapped Keys"
</source>
<dest>
*: "Disable Unmapped Keys"
</dest>
<voice>
*: "Disable Unmapped Keys"
</voice>
</phrase>
<phrase>
id: LANG_SOFTLOCK_SELECTIVE
desc: Softlock behaviour setting
user: core
<source>
*: "Advanced Key Lock"
</source>
<dest>
*: "Advanced Key Lock"
</dest>
<voice>
*: "Advanced Key Lock"
</voice>
</phrase>
<phrase>
id: LANG_ACTION_AUTOLOCK_ON
desc: Softlock behaviour setting
user: core
<source>
*: "Autolock On"
</source>
<dest>
*: "Autolock On"
</dest>
<voice>
*: "Autolock On"
</voice>
</phrase>
<phrase>
id: LANG_ACTION_AUTOLOCK_OFF
desc: Softlock behaviour setting
user: core
<source>
*: "Autolock Off"
</source>
<dest>
*: "Autolock Off"
</dest>
<voice>
*: "Autolock Off"
</voice>
</phrase>
<phrase>
id: LANG_ACTION_DISABLE_NOTIFY
desc: Softlock behaviour setting
user: core
<source>
*: "Disable Notify"
</source>
<dest>
*: "Disable Notify"
</dest>
<voice>
*: "Disable Notify"
</voice>
</phrase>
<phrase>
id: LANG_ACTION_DISABLE_TOUCH
desc: Softlock behaviour setting
user: core
<source>
*: "Disable Touch"
</source>
<dest>
*: "Disable Touch"
</dest>
<voice>
*: "Disable Touch"
</voice>
</phrase>

View file

@ -38,6 +38,10 @@
#ifdef HAVE_REMOTE_LCD #ifdef HAVE_REMOTE_LCD
#include "lcd-remote.h" #include "lcd-remote.h"
#endif #endif
#ifdef HAVE_BACKLIGHT
#include "mask_select.h"
#include "splash.h"
#endif
#ifdef HAVE_TOUCHSCREEN #ifdef HAVE_TOUCHSCREEN
#include "screens.h" #include "screens.h"
#endif #endif
@ -46,9 +50,29 @@
#include "rbunicode.h" #include "rbunicode.h"
#ifdef HAVE_BACKLIGHT #ifdef HAVE_BACKLIGHT
static int filterfirstkeypress_callback(int action,const struct menu_item_ex *this_item) static int selectivebacklight_callback(int action,const struct menu_item_ex *this_item)
{ {
(void)this_item; (void)this_item;
switch (action)
{
case ACTION_EXIT_MENUITEM:
case ACTION_STD_MENU:
case ACTION_STD_CANCEL:
set_selective_backlight_actions(
global_settings.bl_selective_actions,
global_settings.bl_selective_actions_mask,
global_settings.bl_filter_first_keypress);
break;
}
return action;
}
static int filterfirstkeypress_callback(int action,const struct menu_item_ex *this_item)
{
/*(void)this_item;REMOVED*/
switch (action) switch (action)
{ {
case ACTION_EXIT_MENUITEM: case ACTION_EXIT_MENUITEM:
@ -56,13 +80,43 @@ static int filterfirstkeypress_callback(int action,const struct menu_item_ex *th
#ifdef HAVE_REMOTE_LCD #ifdef HAVE_REMOTE_LCD
set_remote_backlight_filter_keypress( set_remote_backlight_filter_keypress(
global_settings.remote_bl_filter_first_keypress); global_settings.remote_bl_filter_first_keypress);
#endif #endif /* HAVE_REMOTE_LCD */
selectivebacklight_callback(action,this_item);/*uses Filter First KP*/
break; break;
} }
return action; return action;
} }
static int selectivebacklight_set_mask(void* param)
{
(void)param;
int mask = global_settings.bl_selective_actions_mask;
struct s_mask_items maskitems[]={
{ID2P(LANG_VOLUME) , SEL_ACTION_VOL},
{ID2P(LANG_ACTION_PLAY), SEL_ACTION_PLAY},
{ID2P(LANG_ACTION_SEEK), SEL_ACTION_SEEK},
{ID2P(LANG_ACTION_SKIP), SEL_ACTION_SKIP},
{ID2P(LANG_ACTION_DISABLE_UNMAPPED), SEL_ACTION_NOUNMAPPED}
#if CONFIG_CHARGING
,{ID2P(LANG_ACTION_DISABLE_EXT_POWER), SEL_ACTION_NOEXT}
#endif #endif
};
mask = mask_select(mask, ID2P(LANG_BACKLIGHT_SELECTIVE)
, maskitems, ARRAYLEN(maskitems));
if (mask == SEL_ACTION_NONE || mask == SEL_ACTION_NOEXT)
global_settings.bl_selective_actions = false;
else if (global_settings.bl_selective_actions_mask != mask)
global_settings.bl_selective_actions = true;
global_settings.bl_selective_actions_mask = mask;
return true;
}
#endif /* HAVE_BACKLIGHT */
#ifdef HAVE_LCD_FLIP #ifdef HAVE_LCD_FLIP
static int flipdisplay_callback(int action,const struct menu_item_ex *this_item) static int flipdisplay_callback(int action,const struct menu_item_ex *this_item)
{ {
@ -104,6 +158,18 @@ MENUITEM_SETTING(backlight_fade_out, &global_settings.backlight_fade_out, NULL);
MENUITEM_SETTING(bl_filter_first_keypress, MENUITEM_SETTING(bl_filter_first_keypress,
&global_settings.bl_filter_first_keypress, &global_settings.bl_filter_first_keypress,
filterfirstkeypress_callback); filterfirstkeypress_callback);
MENUITEM_SETTING(bl_selective_actions,
&global_settings.bl_selective_actions,
selectivebacklight_callback);
MENUITEM_FUNCTION(sel_backlight_mask, 0, ID2P(LANG_SETTINGS),
selectivebacklight_set_mask, NULL,
selectivebacklight_callback, Icon_Menu_setting);
MAKE_MENU(sel_backlight, ID2P(LANG_BACKLIGHT_SELECTIVE),
NULL, Icon_Menu_setting, &bl_selective_actions, &sel_backlight_mask);
#ifdef HAVE_LCD_SLEEP_SETTING #ifdef HAVE_LCD_SLEEP_SETTING
MENUITEM_SETTING(lcd_sleep_after_backlight_off, MENUITEM_SETTING(lcd_sleep_after_backlight_off,
&global_settings.lcd_sleep_after_backlight_off, NULL); &global_settings.lcd_sleep_after_backlight_off, NULL);
@ -124,6 +190,8 @@ MENUITEM_SETTING(flip_display, &global_settings.flip_display, flipdisplay_callba
#endif #endif
#endif /* HAVE_LCD_BITMAP */ #endif /* HAVE_LCD_BITMAP */
/* now the actual menu */ /* now the actual menu */
MAKE_MENU(lcd_settings,ID2P(LANG_LCD_MENU), MAKE_MENU(lcd_settings,ID2P(LANG_LCD_MENU),
NULL, Icon_Display_menu NULL, Icon_Display_menu
@ -141,6 +209,7 @@ MAKE_MENU(lcd_settings,ID2P(LANG_LCD_MENU),
,&backlight_fade_in, &backlight_fade_out ,&backlight_fade_in, &backlight_fade_out
#endif #endif
,&bl_filter_first_keypress ,&bl_filter_first_keypress
,&sel_backlight
# ifdef HAVE_LCD_SLEEP_SETTING # ifdef HAVE_LCD_SLEEP_SETTING
,&lcd_sleep_after_backlight_off ,&lcd_sleep_after_backlight_off
# endif # endif

View file

@ -49,12 +49,67 @@
#include "dircache.h" #include "dircache.h"
#endif #endif
#include "folder_select.h" #include "folder_select.h"
#ifndef HAS_BUTTON_HOLD
#include "mask_select.h"
#endif
#if defined(DX50) || defined(DX90) #if defined(DX50) || defined(DX90)
#include "governor-ibasso.h" #include "governor-ibasso.h"
#include "usb-ibasso.h" #include "usb-ibasso.h"
#endif #endif
#ifndef HAS_BUTTON_HOLD
static int selectivesoftlock_callback(int action,
const struct menu_item_ex *this_item)
{
(void)this_item;
switch (action)
{
case ACTION_STD_MENU:
case ACTION_STD_CANCEL:
case ACTION_EXIT_MENUITEM:
set_selective_softlock_actions(
global_settings.bt_selective_softlock_actions,
global_settings.bt_selective_softlock_actions_mask);
break;
}
return action;
}
static int selectivesoftlock_set_mask(void* param)
{
(void)param;
int mask = global_settings.bt_selective_softlock_actions_mask;
struct s_mask_items maskitems[]={
{ID2P(LANG_VOLUME) , SEL_ACTION_VOL},
{ID2P(LANG_ACTION_PLAY), SEL_ACTION_PLAY},
{ID2P(LANG_ACTION_SEEK), SEL_ACTION_SEEK},
{ID2P(LANG_ACTION_SKIP), SEL_ACTION_SKIP},
#ifdef HAVE_BACKLIGHT
{ID2P(LANG_ACTION_AUTOLOCK_ON), SEL_ACTION_AUTOLOCK},
#endif
#if defined(HAVE_TOUCHPAD) || defined(HAVE_TOUCHSCREEN)
{ID2P(LANG_ACTION_DISABLE_TOUCH) , SEL_ACTION_NOTOUCH},
#endif
{ID2P(LANG_ACTION_DISABLE_NOTIFY), SEL_ACTION_NONOTIFY}
};
mask = mask_select(mask, ID2P(LANG_SOFTLOCK_SELECTIVE)
, maskitems,ARRAYLEN(maskitems));
if (mask == SEL_ACTION_NONE)
global_settings.bt_selective_softlock_actions = false;
else if (global_settings.bt_selective_softlock_actions_mask != mask)
global_settings.bt_selective_softlock_actions = true;
global_settings.bt_selective_softlock_actions_mask = mask;
return true;
}
#endif /* !HAS_BUTTON_HOLD */
/***********************************/ /***********************************/
/* TAGCACHE MENU */ /* TAGCACHE MENU */
#ifdef HAVE_TAGCACHE #ifdef HAVE_TAGCACHE
@ -330,6 +385,19 @@ MENUITEM_SETTING(touchpad_deadzone, &global_settings.touchpad_deadzone, NULL);
MENUITEM_SETTING(shortcuts_replaces_quickscreen, &global_settings.shortcuts_replaces_qs, NULL); MENUITEM_SETTING(shortcuts_replaces_quickscreen, &global_settings.shortcuts_replaces_qs, NULL);
#endif #endif
#ifndef HAS_BUTTON_HOLD
MENUITEM_SETTING(bt_selective_actions,
&global_settings.bt_selective_softlock_actions,
selectivesoftlock_callback);
MENUITEM_FUNCTION(sel_softlock_mask, 0, ID2P(LANG_SETTINGS),
selectivesoftlock_set_mask, NULL,
selectivesoftlock_callback, Icon_Menu_setting);
MAKE_MENU(sel_softlock, ID2P(LANG_SOFTLOCK_SELECTIVE),
NULL, Icon_Menu_setting, &bt_selective_actions, &sel_softlock_mask);
#endif /* !HAS_BUTTON_HOLD */
#if defined(DX50) || defined(DX90) #if defined(DX50) || defined(DX90)
MENUITEM_SETTING(governor, &global_settings.governor, NULL); MENUITEM_SETTING(governor, &global_settings.governor, NULL);
MENUITEM_SETTING(usb_mode, &global_settings.usb_mode, NULL); MENUITEM_SETTING(usb_mode, &global_settings.usb_mode, NULL);
@ -380,6 +448,9 @@ MAKE_MENU(system_menu, ID2P(LANG_SYSTEM),
#ifdef HAVE_TOUCHPAD_DEADZONE #ifdef HAVE_TOUCHPAD_DEADZONE
&touchpad_deadzone, &touchpad_deadzone,
#endif #endif
#ifndef HAS_BUTTON_HOLD
&sel_softlock,
#endif
#ifdef USB_ENABLE_HID #ifdef USB_ENABLE_HID
&usb_hid, &usb_hid,
&usb_keypad_mode, &usb_keypad_mode,

View file

@ -1064,17 +1064,27 @@ void settings_apply(bool read_disk)
#ifdef HAVE_BACKLIGHT #ifdef HAVE_BACKLIGHT
set_backlight_filter_keypress(global_settings.bl_filter_first_keypress); set_backlight_filter_keypress(global_settings.bl_filter_first_keypress);
set_selective_backlight_actions(global_settings.bl_selective_actions,
global_settings.bl_selective_actions_mask,
global_settings.bl_filter_first_keypress);
#ifdef HAVE_REMOTE_LCD #ifdef HAVE_REMOTE_LCD
set_remote_backlight_filter_keypress(global_settings.remote_bl_filter_first_keypress); set_remote_backlight_filter_keypress(global_settings.remote_bl_filter_first_keypress);
#endif #endif
#ifdef HAS_BUTTON_HOLD #ifdef HAS_BUTTON_HOLD
backlight_set_on_button_hold(global_settings.backlight_on_button_hold); backlight_set_on_button_hold(global_settings.backlight_on_button_hold);
#endif #endif
#ifdef HAVE_LCD_SLEEP_SETTING #ifdef HAVE_LCD_SLEEP_SETTING
lcd_set_sleep_after_backlight_off(global_settings.lcd_sleep_after_backlight_off); lcd_set_sleep_after_backlight_off(global_settings.lcd_sleep_after_backlight_off);
#endif #endif
#endif /* HAVE_BACKLIGHT */ #endif /* HAVE_BACKLIGHT */
#ifndef HAS_BUTTON_HOLD
set_selective_softlock_actions(
global_settings.bt_selective_softlock_actions,
global_settings.bt_selective_softlock_actions_mask);
#endif
#ifdef HAVE_TOUCHPAD_SENSITIVITY_SETTING #ifdef HAVE_TOUCHPAD_SENSITIVITY_SETTING
touchpad_set_sensitivity(global_settings.touchpad_sensitivity); touchpad_set_sensitivity(global_settings.touchpad_sensitivity);
#endif #endif

View file

@ -670,7 +670,13 @@ struct user_settings
#if CONFIG_CHARGING #if CONFIG_CHARGING
int backlight_timeout_plugged; int backlight_timeout_plugged;
#endif #endif
#ifndef HAS_BUTTON_HOLD
bool bt_selective_softlock_actions;
int bt_selective_softlock_actions_mask;
#endif
#ifdef HAVE_BACKLIGHT #ifdef HAVE_BACKLIGHT
bool bl_selective_actions; /* backlight disable on some actions */
int bl_selective_actions_mask;/* mask of actions that will not enable backlight */
#ifdef HAS_BUTTON_HOLD #ifdef HAS_BUTTON_HOLD
int backlight_on_button_hold; /* what to do with backlight when hold int backlight_on_button_hold; /* what to do with backlight when hold
switch is on */ switch is on */
@ -679,7 +685,8 @@ struct user_settings
int lcd_sleep_after_backlight_off; /* when to put lcd to sleep after backlight int lcd_sleep_after_backlight_off; /* when to put lcd to sleep after backlight
has turned off */ has turned off */
#endif #endif
#endif #endif /* HAVE_BACKLIGHT */
#if defined(HAVE_BACKLIGHT_FADING_INT_SETTING) #if defined(HAVE_BACKLIGHT_FADING_INT_SETTING)
int backlight_fade_in; /* backlight fade in timing: 0..3 */ int backlight_fade_in; /* backlight fade in timing: 0..3 */
int backlight_fade_out; /* backlight fade in timing: 0..7 */ int backlight_fade_out; /* backlight fade in timing: 0..7 */

View file

@ -1071,9 +1071,26 @@ const struct settings_list settings[] = {
/** End of old RTC config block **/ /** End of old RTC config block **/
#ifndef HAS_BUTTON_HOLD
OFFON_SETTING(0, bt_selective_softlock_actions,
LANG_ACTION_ENABLED, false,
"No Screen Lock For Selected Actions", NULL),
INT_SETTING(0, bt_selective_softlock_actions_mask, LANG_SOFTLOCK_SELECTIVE,
0, "Selective Screen Lock Actions", UNIT_INT,
0, 2048,2, NULL, NULL, NULL),
#endif /* !HAS_BUTTON_HOLD */
#ifdef HAVE_BACKLIGHT #ifdef HAVE_BACKLIGHT
OFFON_SETTING(0, caption_backlight, LANG_CAPTION_BACKLIGHT, OFFON_SETTING(0, caption_backlight, LANG_CAPTION_BACKLIGHT,
false, "caption backlight", NULL), false, "caption backlight", NULL),
OFFON_SETTING(0, bl_selective_actions,
LANG_ACTION_ENABLED, false,
"No Backlight On Selected Actions", NULL),
INT_SETTING(0, bl_selective_actions_mask, LANG_BACKLIGHT_SELECTIVE,
0, "Selective Backlight Actions", UNIT_INT,
0, 2048,2, NULL, NULL, NULL),
#ifdef HAVE_REMOTE_LCD #ifdef HAVE_REMOTE_LCD
OFFON_SETTING(0, remote_caption_backlight, LANG_CAPTION_BACKLIGHT, OFFON_SETTING(0, remote_caption_backlight, LANG_CAPTION_BACKLIGHT,
false, "remote caption backlight", NULL), false, "remote caption backlight", NULL),

View file

@ -654,6 +654,7 @@ Udo Schläpfer
Thomas White Thomas White
Karl Huber Karl Huber
Adam Sampson Adam Sampson
William Wilgus
The libmad team The libmad team
The wavpack team The wavpack team

View file

@ -103,6 +103,8 @@ static void backlight_thread(void);
static long backlight_stack[DEFAULT_STACK_SIZE/sizeof(long)]; static long backlight_stack[DEFAULT_STACK_SIZE/sizeof(long)];
static const char backlight_thread_name[] = "backlight"; static const char backlight_thread_name[] = "backlight";
static struct event_queue backlight_queue SHAREDBSS_ATTR; static struct event_queue backlight_queue SHAREDBSS_ATTR;
static bool ignore_backlight_on = false;
static int backlight_ignored_timer = 0;
#ifdef BACKLIGHT_DRIVER_CLOSE #ifdef BACKLIGHT_DRIVER_CLOSE
static unsigned int backlight_thread_id = 0; static unsigned int backlight_thread_id = 0;
#endif #endif
@ -123,6 +125,8 @@ static void backlight_timeout_handler(void);
#ifdef HAVE_BUTTON_LIGHT #ifdef HAVE_BUTTON_LIGHT
static int buttonlight_timer; static int buttonlight_timer;
static int buttonlight_timeout = 5*HZ; static int buttonlight_timeout = 5*HZ;
static bool ignore_buttonlight_on = false;
static int buttonlight_ignored_timer = 0;
/* Update state of buttonlight according to timeout setting */ /* Update state of buttonlight according to timeout setting */
static void buttonlight_update_state(void) static void buttonlight_update_state(void)
@ -140,11 +144,21 @@ static void buttonlight_update_state(void)
} }
/* external interface */ /* external interface */
void buttonlight_on(void) void buttonlight_on(void)
{
if(!ignore_buttonlight_on)
{ {
queue_remove_from_head(&backlight_queue, BUTTON_LIGHT_ON); queue_remove_from_head(&backlight_queue, BUTTON_LIGHT_ON);
queue_post(&backlight_queue, BUTTON_LIGHT_ON, 0); queue_post(&backlight_queue, BUTTON_LIGHT_ON, 0);
} }
}
void buttonlight_on_ignore(bool value, int timeout)
{
ignore_buttonlight_on = value;
buttonlight_ignored_timer = timeout;
}
void buttonlight_off(void) void buttonlight_off(void)
{ {
@ -723,7 +737,19 @@ static void backlight_timeout_handler(void)
buttonlight_hw_off(); buttonlight_hw_off();
} }
} }
if (buttonlight_ignored_timer > 0)
{
buttonlight_ignored_timer -= BACKLIGHT_THREAD_TIMEOUT;
if (buttonlight_ignored_timer <= 0)
ignore_buttonlight_on = false;
}
#endif /* HAVE_BUTTON_LIGHT */ #endif /* HAVE_BUTTON_LIGHT */
if (backlight_ignored_timer > 0)
{
backlight_ignored_timer -= BACKLIGHT_THREAD_TIMEOUT;
if (backlight_ignored_timer <= 0)
ignore_backlight_on = false;
}
} }
void backlight_init(void) void backlight_init(void)
@ -767,10 +793,19 @@ void backlight_close(void)
#endif /* BACKLIGHT_DRIVER_CLOSE */ #endif /* BACKLIGHT_DRIVER_CLOSE */
void backlight_on(void) void backlight_on(void)
{
if(!ignore_backlight_on)
{ {
queue_remove_from_head(&backlight_queue, BACKLIGHT_ON); queue_remove_from_head(&backlight_queue, BACKLIGHT_ON);
queue_post(&backlight_queue, BACKLIGHT_ON, 0); queue_post(&backlight_queue, BACKLIGHT_ON, 0);
} }
}
void backlight_on_ignore(bool value, int timeout)
{
ignore_backlight_on = value;
backlight_ignored_timer = timeout;
}
void backlight_off(void) void backlight_off(void)
{ {
@ -829,8 +864,13 @@ void backlight_set_timeout_plugged(int value)
void backlight_hold_changed(bool hold_button) void backlight_hold_changed(bool hold_button)
{ {
if (!hold_button || (backlight_on_button_hold > 0)) if (!hold_button || (backlight_on_button_hold > 0))
{
/* if unlocked or override in effect */ /* if unlocked or override in effect */
backlight_on();
/*backlight_on(); REMOVED*/
queue_remove_from_head(&backlight_queue, BACKLIGHT_ON);
queue_post(&backlight_queue, BACKLIGHT_ON, 0);
}
} }
void backlight_set_on_button_hold(int index) void backlight_set_on_button_hold(int index)

View file

@ -31,6 +31,7 @@
#endif #endif
bool is_backlight_on(bool ignore_always_off); bool is_backlight_on(bool ignore_always_off);
void backlight_on_ignore(bool value, int timeout);
void backlight_on(void); void backlight_on(void);
void backlight_off(void); void backlight_off(void);
void backlight_set_timeout(int value); void backlight_set_timeout(int value);
@ -38,7 +39,6 @@ void backlight_set_timeout(int value);
#ifdef HAVE_BACKLIGHT #ifdef HAVE_BACKLIGHT
void backlight_init(void) INIT_ATTR; void backlight_init(void) INIT_ATTR;
void backlight_close(void); void backlight_close(void);
int backlight_get_current_timeout(void); int backlight_get_current_timeout(void);
#if defined(HAVE_BACKLIGHT_FADING_INT_SETTING) #if defined(HAVE_BACKLIGHT_FADING_INT_SETTING)
@ -99,6 +99,7 @@ void buttonlight_set_brightness(int val);
#endif /* HAVE_BUTTONLIGHT_BRIGHTNESS */ #endif /* HAVE_BUTTONLIGHT_BRIGHTNESS */
#ifdef HAVE_BUTTON_LIGHT #ifdef HAVE_BUTTON_LIGHT
void buttonlight_on_ignore(bool value, int timeout);
void buttonlight_on(void); void buttonlight_on(void);
void buttonlight_off(void); void buttonlight_off(void);
void buttonlight_set_timeout(int value); void buttonlight_set_timeout(int value);

7
manual/advanced_topics/main.tex Normal file → Executable file
View file

@ -694,6 +694,8 @@ current version.
of your \dap{}. The largest power savings can be achieved through disabling of your \dap{}. The largest power savings can be achieved through disabling
unneeded hardware components -- for some of those there are settings unneeded hardware components -- for some of those there are settings
available. available.
\opt{swcodec}{ \opt{swcodec}{
Another area of savings is avoiding or reducing CPU boosting Another area of savings is avoiding or reducing CPU boosting
through disabling computing intense features (e.g. sound processing) or through disabling computing intense features (e.g. sound processing) or
@ -705,8 +707,9 @@ current version.
\subsection{Display backlight} \subsection{Display backlight}
The active backlight consumes a lot of power. Therefore choose a setting that The active backlight consumes a lot of power. Therefore choose a setting that
disables the backlight after timeout (for setting \setting{Backlight} see disables the backlight after timeout (for setting \setting{Backlight} see
\reference{ref:Displayoptions}). Avoid to have the backlight enabled all the \reference{ref:Displayoptions}). Avoid having the backlight enabled all the
time. time (Activating \setting{selectivebacklight}
\reference{ref:selectivebacklight} can further reduce power consumption).
} }
\opt{lcd_sleep}{ \opt{lcd_sleep}{

30
manual/configure_rockbox/display_options.tex Normal file → Executable file
View file

@ -57,6 +57,36 @@
off will only turn the backlight on without having any other effect. When off will only turn the backlight on without having any other effect. When
disabled the first keypress will \emph{also} perform its appropriate action. disabled the first keypress will \emph{also} perform its appropriate action.
\item[\label{ref:selectivebacklight}Selective Backlight]
This option allows some selected actions in While Playing Screen and
FM screen to \emph{not} turn on the backlight in order to save power.
\begin{description}
\item[Enabled.]
Enables/disables the feature.
\item[Settings.]
Allows to select actions that will \emph{not} activate backlight.
\begin{itemize}
\item[Volume.]
Volume up/down.
\item[Play.]
Toggling Play/Pause.
\item[Seek.]
Seeking in a track.
\item[Skip.]
Skipping of a track.
\item[Disable Unmapped Keys.]
Buttons that have no action assigned and accidental button
combinations don't turn on backlight.
\item[Disable on External Power.]
When plugged goes back to regular behavior.
\end{itemize}
Selected actions are indicated by a leading +.
Note: If all options get de-selected, the entire feature is disabled.
\end{description}
\opt{lcd_sleep}{ \opt{lcd_sleep}{
\item[Sleep (After Backlight Off).] \item[Sleep (After Backlight Off).]
This setting controls how long rockbox will wait before turning off the This setting controls how long rockbox will wait before turning off the

55
manual/configure_rockbox/system_options.tex Normal file → Executable file
View file

@ -243,6 +243,61 @@ therefore result in better runtime.
\nopt{HAS_BUTTON_HOLD}{
\subsection{Advanced Key Lock}
This option allows users to select actions that when within WPS or FMS will \emph{not} be
blocked by the key lock (software hold switch).
\begin{description}
\item[Enabled.]
Enables/disables the feature.
\item[Settings.]
Allows to select actions that will \emph{not} be blocked by the key lock.
\begin{itemize}
\item[Volume.]
Volume up/down.
\item[Play.]
Toggling Play/Pause.
\item[Seek.]
Seeking in a track.
\item[Skip.]
Skipping of a track.
\opt{HAVE_BACKLIGHT}{
\item[Autolock On.]
When the backlight turns off, softlock will lock the screen,
activates when you press the lock key and if you manually lock
again, while active it then disables autolock.
\begin{itemize}
\item
(Lock Button Pressed \#1) >Auto Lock On
(device still unlocked till backlight timeout).
\item
(Lock Button Pressed \#2) >Auto Lock Off (device locked).
\item
(Lock Button Pressed \#3) >(device unlocked).
\end{itemize}
} %\opt{HAVE_BACKLIGHT}
\opt{touchpad}{
\item[Disable Touch.]
Blocks touch screen buttons like the original.
}
\item[Disable Notify.]
Suppresses the notification 'Buttons Locked'
(still will if power button is pressed).
\note{This is a pre-requisite for \setting{selectivebacklight}
\reference{ref:selectivebacklight} to work also during key lock.}
\end{itemize}
Selected actions are indicated by a leading +.
Note: If all options get de-selected, the entire feature is disabled.
\end{description}
} %\nopt{HAS_BUTTON_HOLD}
\opt{usb_hid}{ \opt{usb_hid}{
\subsection{\label{ref:USB_HID}USB HID} \subsection{\label{ref:USB_HID}USB HID}
This option turns the USB HID feature \setting{On} and \setting{Off}. This option turns the USB HID feature \setting{On} and \setting{Off}.