summaryrefslogtreecommitdiffstats
path: root/apps/action.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/action.c')
-rw-r--r--apps/action.c153
1 files changed, 140 insertions, 13 deletions
diff --git a/apps/action.c b/apps/action.c
index b31c4fa927..208fea4a97 100644
--- a/apps/action.c
+++ b/apps/action.c
@@ -34,6 +34,7 @@
#include "button.h"
#include "action.h"
#include "kernel.h"
+#include "core_alloc.h"
#include "splash.h"
#include "settings.h"
@@ -69,6 +70,10 @@ static action_last_t action_last =
.tick = 0,
.wait_for_release = false,
+#ifndef DISABLE_ACTION_REMAP
+ .key_remap = 0,
+#endif
+
#ifdef HAVE_TOUCHSCREEN
.ts_data = 0,
.ts_short_press = false,
@@ -120,7 +125,7 @@ static bool is_action_filtered(int action, unsigned int mask, int context)
{
case ACTION_NONE:
break;
-/*Actions that are not mapped will not turn on the backlight option NOUNMAPPED*/
+ /* Actions that are not mapped will not turn on the backlight */
case ACTION_UNKNOWN:
match = has_flag(mask, SEL_ACTION_NOUNMAPPED);
break;
@@ -128,15 +133,15 @@ static bool is_action_filtered(int action, unsigned int mask, int context)
case ACTION_FM_PLAY:
match = has_flag(mask, SEL_ACTION_PLAY);
break;
- //case ACTION_STD_PREVREPEAT: // seek not exempted outside of WPS
- //case ACTION_STD_NEXTREPEAT:
+ /* case ACTION_STD_PREVREPEAT:*/ /* seek not exempted outside of WPS */
+ /* case ACTION_STD_NEXTREPEAT: */
case ACTION_WPS_SEEKBACK:
case ACTION_WPS_SEEKFWD:
case ACTION_WPS_STOPSEEK:
match = has_flag(mask, SEL_ACTION_SEEK);
break;
- //case ACTION_STD_PREV: // skip/scrollwheel not exempted outside of WPS
- //case ACTION_STD_NEXT:
+ /* case ACTION_STD_PREV: */ /* skip/scrollwheel not */
+ /* case ACTION_STD_NEXT: */ /* exempted outside of WPS */
case ACTION_WPS_SKIPNEXT:
case ACTION_WPS_SKIPPREV:
case ACTION_FM_NEXT_PRESET:
@@ -144,8 +149,8 @@ static bool is_action_filtered(int action, unsigned int mask, int context)
match = has_flag(mask, SEL_ACTION_SKIP);
break;
#ifdef HAVE_VOLUME_IN_LIST
- case ACTION_LIST_VOLUP: // volume exempted outside of WPS if the device supports it
- case ACTION_LIST_VOLDOWN:
+ case ACTION_LIST_VOLUP: /* volume exempted outside of WPS */
+ case ACTION_LIST_VOLDOWN: /* ( if the device supports it )*/
#endif
case ACTION_WPS_VOLUP:
case ACTION_WPS_VOLDOWN:
@@ -499,7 +504,7 @@ static inline int action_code_worker(action_last_t *last,
int *end )
{
int ret = ACTION_UNKNOWN;
- int i = 0;
+ int i = *end;
unsigned int found = 0;
while (cur->items[i].button_code != BUTTON_NONE)
{
@@ -583,21 +588,52 @@ static inline int get_next_context(const struct button_mapping *items, int i)
* for a more in-depth explanation
* places action into current_action
*/
+
static inline void action_code_lookup(action_last_t *last, action_cur_t *cur)
{
- int action = ACTION_NONE;
+ int action, i;
int context = cur->context;
- int i = 0;
-
cur->is_prebutton = false;
-#ifdef HAVE_LOCKED_ACTIONS
+#if !defined(HAS_BUTTON_HOLD) && !defined(BOOTLOADER)
/* This only applies to the first context, to allow locked contexts to
* specify a fall through to their non-locked version */
if (is_keys_locked())
context |= CONTEXT_LOCKED;
#endif
+#ifndef DISABLE_ACTION_REMAP
+ /* attempt to look up the button in user supplied remap */
+ if(last->key_remap && (context & CONTEXT_PLUGIN) == 0)
+ {
+ if ((cur->button & BUTTON_REMOTE) != 0)
+ {
+ context |= CONTEXT_REMOTE;
+ }
+ cur->items = core_get_data(last->key_remap);
+ i = 0;
+ action = ACTION_UNKNOWN;
+ /* check the lut at the beginning for the desired context */
+ while (cur->items[i].button_code != BUTTON_NONE)
+ {
+ if (cur->items[i].action_code == CORE_CONTEXT_REMAP(context))
+ {
+ i = cur->items[i].button_code;
+ action = action_code_worker(last, cur, &i);
+ if (action != ACTION_UNKNOWN)
+ {
+ cur->action = action;
+ return;
+ }
+ }
+ i++;
+ }
+ }
+#endif
+
+ i = 0;
+ action = ACTION_NONE;
+ /* attempt to look up the button in the in-built keymaps */
for(;;)
{
/* logf("context = %x",context); */
@@ -609,9 +645,13 @@ static inline void action_code_lookup(action_last_t *last, action_cur_t *cur)
#endif
if ((context & CONTEXT_PLUGIN) && cur->get_context_map)
+ {
cur->items = cur->get_context_map(context);
+ }
else
+ {
cur->items = get_context_mapping(context);
+ }
if (cur->items != NULL)
{
@@ -960,7 +1000,8 @@ static inline int do_backlight(action_last_t *last, action_cur_t *cur, int actio
&& power_input_present());
#endif
/* skip if backlight on | incorrect context | SEL_ACTION_NOEXT + ext pwr */
- if ((cur->context == CONTEXT_FM || cur->context == CONTEXT_WPS) && bl_is_off)
+ if (bl_is_off && (cur->context == CONTEXT_FM || cur->context == CONTEXT_WPS ||
+ cur->context == CONTEXT_MAINMENU))
{
filtered = is_action_filtered(action, last->backlight_mask, cur->context);
bl_activate = !is_action_discarded(cur, filtered, &last->bl_filter_tick);
@@ -1150,6 +1191,92 @@ int get_action(int context, int timeout)
return action;
}
+int action_set_keymap(struct button_mapping* core_keymap, int count)
+{
+#ifdef DISABLE_ACTION_REMAP
+ (void)core_keymap;
+ (void)count;
+ return -1;
+#else
+ if (count <= 0 || core_keymap == NULL)
+ return action_set_keymap_handle(0, 0);
+
+ size_t keyremap_buf_size = count * sizeof(struct button_mapping);
+ int handle = core_alloc(keyremap_buf_size);
+ if (handle < 0)
+ return -6;
+
+ memcpy(core_get_data(handle), core_keymap, keyremap_buf_size);
+ return action_set_keymap_handle(handle, count);
+#endif
+}
+
+int action_set_keymap_handle(int handle, int count)
+{
+#ifdef DISABLE_ACTION_REMAP
+ (void)core_keymap;
+ (void)count;
+ return -1;
+#else
+ /* free an existing remap */
+ action_last.key_remap = core_free(action_last.key_remap);
+
+ /* if clearing the remap, we're done */
+ if (count <= 0 || handle <= 0)
+ return 0;
+
+ /* validate the keymap */
+ struct button_mapping* core_keymap = core_get_data(handle);
+ struct button_mapping* entry = &core_keymap[count - 1];
+ if (entry->action_code != (int) CONTEXT_STOPSEARCHING ||
+ entry->button_code != BUTTON_NONE) /* check for sentinel at end*/
+ {
+ /* missing sentinel entry */
+ return -1;
+ }
+
+ /* check the lut at the beginning for invalid offsets */
+ for (int i = 0; i < count; ++i)
+ {
+ entry = &core_keymap[i];
+ if (entry->action_code == (int)CONTEXT_STOPSEARCHING)
+ break;
+
+ if ((entry->action_code & CONTEXT_REMAPPED) == CONTEXT_REMAPPED)
+ {
+ int firstbtn = entry->button_code;
+ int endpos = firstbtn + entry->pre_button_code;
+ if (firstbtn > count || firstbtn < i || endpos > count)
+ {
+ /* offset out of bounds */
+ return -2;
+ }
+
+ if (core_keymap[endpos].button_code != BUTTON_NONE)
+ {
+ /* stop sentinel is not at end of action lut */
+ return -3;
+ }
+ }
+ else
+ {
+ /* something other than a context remap in the lut */
+ return -4;
+ }
+
+ if (i+1 >= count)
+ {
+ /* no sentinel in the lut */
+ return -5;
+ }
+ }
+
+ /* success */
+ action_last.key_remap = handle;
+ return count;
+#endif
+}
+
int get_custom_action(int context,int timeout,
const struct button_mapping* (*get_context_map)(int))
{