Add custom action mapping to core
results of an idea I discussed in IRC changed the way the lookup in the remap file works.. entries consist of 3 int [action, button, prebtn] context look up table is at the beginning action_code contains the (context | CONTEXT_REMAPPED) button_code contains the index of the first remapped action for the matched context [0] CORE_CONTEXT_REMAP(ctx1) offset1=(3), count=(1) [1] CORE_CONTEXT_REMAP(ctx2, offset2=(5), count=(1) [2] sentinel, 0, 0 [3] act0, btn, 0 [4] sentinel 0, 0 [5] act1, btn, 0 [6] sentinel, 0, 0 Note: last entry of each group is always the sentinel [CONTEXT_STOPSEARCHING, BUTTON_NONE, BUTTON_NONE] contexts must match exactly -- re-mapped contexts run before the built in w/ fall through contexts ie. you can't remap std_context and expect it to match std_context actions from the WPS context. -- Done -- Code for reading core remap entries -- Done -- import of core remap entires from disk -- Done -- plugin to set new key mapping (the hard part) The plugin is started and FULLY functional you can add actions and contexts you can change context, action, button, prebtn delete keymap files load keymapfiles save user keymaps test keymaps before applying them loading keymaps to core still requires restart ----------------------------------------------------------------------------------------------- Change-Id: Ib8b88c5ae91af4d540e1829de5db32669cd68203
This commit is contained in:
parent
7952687185
commit
f7bb9e2167
14 changed files with 1928 additions and 3 deletions
|
@ -7,6 +7,7 @@ alarm_menu.c
|
|||
#endif
|
||||
abrepeat.c
|
||||
bookmark.c
|
||||
core_keymap.c
|
||||
debug_menu.c
|
||||
filetypes.c
|
||||
language.c
|
||||
|
|
104
apps/action.c
104
apps/action.c
|
@ -69,6 +69,11 @@ static action_last_t action_last =
|
|||
.tick = 0,
|
||||
.wait_for_release = false,
|
||||
|
||||
#ifndef DISABLE_ACTION_REMAP
|
||||
.check_remap = false,
|
||||
.core_keymap = NULL,
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TOUCHSCREEN
|
||||
.ts_data = 0,
|
||||
.ts_short_press = false,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -588,7 +593,9 @@ static inline void action_code_lookup(action_last_t *last, action_cur_t *cur)
|
|||
int action = ACTION_NONE;
|
||||
int context = cur->context;
|
||||
int i = 0;
|
||||
|
||||
#ifndef DISABLE_ACTION_REMAP
|
||||
last->check_remap = (last->core_keymap != NULL);
|
||||
#endif
|
||||
cur->is_prebutton = false;
|
||||
|
||||
#ifdef HAVE_LOCKED_ACTIONS
|
||||
|
@ -609,9 +616,42 @@ 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);
|
||||
}
|
||||
#ifndef DISABLE_ACTION_REMAP
|
||||
else if(last->check_remap) /* attempt to look up the button in user supplied remap */
|
||||
{
|
||||
cur->items = last->core_keymap;
|
||||
i = 0;
|
||||
action = ACTION_UNKNOWN;
|
||||
/* check the lut at the beginning for the desired context */
|
||||
while (cur->items[i].action_code != (int) CONTEXT_STOPSEARCHING)
|
||||
{
|
||||
if (cur->items[i].action_code == CORE_CONTEXT_REMAP(context))
|
||||
{
|
||||
i = cur->items[i].button_code;
|
||||
action = action_code_worker(last, cur, &i);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (action != ACTION_UNKNOWN)
|
||||
break;
|
||||
else
|
||||
{
|
||||
/* Not found -- fall through to inbuilt keymaps */
|
||||
i = 0;
|
||||
last->check_remap = false;
|
||||
cur->items = get_context_mapping(context);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
cur->items = get_context_mapping(context);
|
||||
}
|
||||
|
||||
if (cur->items != NULL)
|
||||
{
|
||||
|
@ -1150,6 +1190,66 @@ int get_action(int context, int timeout)
|
|||
return action;
|
||||
}
|
||||
|
||||
int action_set_keymap(struct button_mapping* core_keymap, int count)
|
||||
{
|
||||
|
||||
#ifdef DISABLE_ACTION_REMAP
|
||||
count = -1;
|
||||
#else
|
||||
if (count > 0 && core_keymap != NULL) /* saf-tey checks :) */
|
||||
{
|
||||
int i = 0;
|
||||
if (core_keymap[count - 1].action_code != (int) CONTEXT_STOPSEARCHING ||
|
||||
core_keymap[count - 1].button_code != BUTTON_NONE) /* check for sentinel at end*/
|
||||
count = -1;
|
||||
|
||||
/* check the lut at the beginning for invalid offsets */
|
||||
while (count > 0 && core_keymap[i].action_code != (int) CONTEXT_STOPSEARCHING)
|
||||
{
|
||||
if ((core_keymap[i].action_code & CONTEXT_REMAPPED) == CONTEXT_REMAPPED)
|
||||
{
|
||||
int firstbtn = core_keymap[i].button_code;
|
||||
int endpos = firstbtn + core_keymap[i].pre_button_code;
|
||||
if (firstbtn > count || firstbtn < i || endpos > count)
|
||||
{
|
||||
/* offset out of bounds */
|
||||
count = -2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (core_keymap[endpos].action_code != (int) CONTEXT_STOPSEARCHING)
|
||||
{
|
||||
/* stop sentinel is not at end of action lut*/
|
||||
count = -3;
|
||||
}
|
||||
}
|
||||
else /* something other than a context remap in the lut */
|
||||
{
|
||||
count = -4;
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
if (i >= count) /* no sentinel in the lut */
|
||||
{
|
||||
count = -5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (count <= 0)
|
||||
core_keymap = NULL;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
core_keymap = NULL;
|
||||
}
|
||||
action_last.core_keymap = core_keymap;
|
||||
return count;
|
||||
}
|
||||
|
||||
int get_custom_action(int context,int timeout,
|
||||
const struct button_mapping* (*get_context_map)(int))
|
||||
{
|
||||
|
|
|
@ -28,10 +28,13 @@
|
|||
#define TIMEOUT_NOBLOCK 0
|
||||
|
||||
#define CONTEXT_STOPSEARCHING 0xFFFFFFFF
|
||||
|
||||
#define CONTEXT_REMOTE 0x80000000 /* | this against another context to get remote buttons for that context */
|
||||
#define CONTEXT_CUSTOM 0x40000000 /* | this against anything to get your context number */
|
||||
#define CONTEXT_CUSTOM2 0x20000000 /* as above */
|
||||
#define CONTEXT_PLUGIN 0x10000000 /* for plugins using get_custom_action */
|
||||
#define CONTEXT_REMAPPED 0x08000000 /* marker for key remap context table */
|
||||
#define CORE_CONTEXT_REMAP(context) (CONTEXT_REMAPPED | context)
|
||||
#ifdef HAVE_LOCKED_ACTIONS
|
||||
#define CONTEXT_LOCKED 0x04000000 /* flag to use alternate keymap when screen is locked */
|
||||
#endif
|
||||
|
@ -415,6 +418,11 @@ typedef struct
|
|||
bool repeated;
|
||||
bool wait_for_release;
|
||||
|
||||
#ifndef DISABLE_ACTION_REMAP
|
||||
bool check_remap;
|
||||
struct button_mapping* core_keymap;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TOUCHSCREEN
|
||||
bool ts_short_press;
|
||||
int ts_data;
|
||||
|
@ -441,6 +449,9 @@ bool action_userabort(int timeout);
|
|||
/* no other code should need this apart from action.c */
|
||||
const struct button_mapping* get_context_mapping(int context);
|
||||
|
||||
/* load a key map to allow buttons for actions to be remapped see: core_keymap */
|
||||
int action_set_keymap(struct button_mapping* core_button_map, int count);
|
||||
|
||||
/* 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 */
|
||||
#define ACTION_REMOTE 0x1 /* remote was pressed */
|
||||
|
|
106
apps/core_keymap.c
Normal file
106
apps/core_keymap.c
Normal file
|
@ -0,0 +1,106 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2020 by William Wilgus
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "action.h"
|
||||
#include "core_alloc.h"
|
||||
#include "core_keymap.h"
|
||||
|
||||
#if !defined(__PCTOOL__) || defined(CHECKWPS)
|
||||
int core_load_key_remap(const char *filename)
|
||||
{
|
||||
static int keymap_handle = -1;
|
||||
char *buf;
|
||||
int fd = -1;
|
||||
int count = 0;
|
||||
size_t fsize = 0;
|
||||
if (keymap_handle > 0) /* free old buffer */
|
||||
{
|
||||
action_set_keymap(NULL, -1);
|
||||
keymap_handle = core_free(keymap_handle);
|
||||
}
|
||||
if (filename != NULL)
|
||||
count = open_key_remap(filename, &fd, &fsize);
|
||||
while (count > 0)
|
||||
{
|
||||
|
||||
keymap_handle = core_alloc_ex("key remap", fsize, &buflib_ops_locked);
|
||||
if (keymap_handle <= 0)
|
||||
{
|
||||
count = -30;
|
||||
break;
|
||||
}
|
||||
buf = core_get_data(keymap_handle);
|
||||
if (read(fd, buf, fsize) == (ssize_t) fsize)
|
||||
{
|
||||
count = action_set_keymap((struct button_mapping *) buf, count);
|
||||
}
|
||||
else
|
||||
count = -40;
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
return count;
|
||||
}
|
||||
|
||||
int open_key_remap(const char *filename, int *fd, size_t *fsize)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
while (filename && fd && fsize)
|
||||
{
|
||||
*fsize = 0;
|
||||
*fd = open(filename, O_RDONLY);
|
||||
if (*fd)
|
||||
{
|
||||
*fsize = filesize(*fd);
|
||||
|
||||
count = *fsize / sizeof(struct button_mapping);
|
||||
|
||||
if (count * sizeof(struct button_mapping) != *fsize)
|
||||
{
|
||||
count = -10;
|
||||
break;
|
||||
}
|
||||
|
||||
if (count > 1)
|
||||
{
|
||||
struct button_mapping header = {0};
|
||||
read(*fd, &header, sizeof(struct button_mapping));
|
||||
if (KEYREMAP_VERSION == header.action_code &&
|
||||
KEYREMAP_HEADERID == header.button_code &&
|
||||
header.pre_button_code == count)
|
||||
{
|
||||
count--;
|
||||
*fsize -= sizeof(struct button_mapping);
|
||||
}
|
||||
else /* Header mismatch */
|
||||
{
|
||||
count = -20;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
#endif /* !defined(__PCTOOL__) */
|
68
apps/core_keymap.h
Normal file
68
apps/core_keymap.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2020 by William Wilgus
|
||||
*
|
||||
* 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 CORE_KEYMAP_H
|
||||
#define CORE_KEYMAP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include "config.h"
|
||||
#define KEYREMAP_VERSION 1
|
||||
#define KEYREMAP_HEADERID (LAST_ACTION_PLACEHOLDER | (TARGET_ID << 8))
|
||||
|
||||
/* If exists remap file will be loaded at startup */
|
||||
#define CORE_KEYREMAP_FILE ROCKBOX_DIR "/keyremap.kmf"
|
||||
|
||||
/* open_key_remap(filename , *fd (you must close file_descriptor), *fsize)
|
||||
* checks/strips header and returns remaining count
|
||||
* fd is opened and set to first record
|
||||
* filesize contains the size of the remaining records
|
||||
*/
|
||||
int open_key_remap(const char *filename, int *fd, size_t *filesize);
|
||||
|
||||
/* load a remap file to allow buttons for actions to be remapped */
|
||||
int core_load_key_remap(const char *filename);
|
||||
|
||||
/*
|
||||
* entries consist of 3 int [action, button, prebtn]
|
||||
* the header (VERSION, LAST_DEFINED_ACTION, count) is stripped by open_key_remap
|
||||
*
|
||||
* context look up table is at the beginning
|
||||
* action_code contains (context | CONTEXT_REMAPPED)
|
||||
* button_code contains index of first remapped action for the matched context
|
||||
* prebtn_code contains count of actions in this remapped context
|
||||
* [-1] REMAP_VERSION, REMAP_HEADERID, entry count(9) / DISCARDED AFTER LOAD
|
||||
* [0] CORE_CONTEXT_REMAP(ctx1), offset1=(3), count=(1)
|
||||
* [1] CORE_CONTEXT_REMAP(ctx2, offset2=(5), count=(2)
|
||||
* [2] sentinel, 0, 0
|
||||
* [3] act0, btn, 0
|
||||
* [4] sentinel 0, 0
|
||||
* [5] act1, btn, 0
|
||||
* [6] act2, btn1
|
||||
* [7] sentinel, 0, 0
|
||||
*
|
||||
* Note:
|
||||
* last entry of each group is always the sentinel [CONTEXT_STOPSEARCHING, BUTTON_NONE, BUTTON_NONE]
|
||||
* contexts must match exactly -- re-mapped contexts run before the built in w/ fall through contexts
|
||||
* ie. you can't remap std_context and expect it to match std_context actions from the WPS context.
|
||||
*/
|
||||
|
||||
#endif /* CORE_KEYMAP_H */
|
||||
|
10
apps/main.c
10
apps/main.c
|
@ -31,6 +31,7 @@
|
|||
#include "led.h"
|
||||
#include "../kernel-internal.h"
|
||||
#include "button.h"
|
||||
#include "core_keymap.h"
|
||||
#include "tree.h"
|
||||
#include "filetypes.h"
|
||||
#include "panic.h"
|
||||
|
@ -175,6 +176,15 @@ int main(void)
|
|||
usb_start_monitoring();
|
||||
#endif
|
||||
|
||||
#if !defined(DISABLE_ACTION_REMAP) && defined(CORE_KEYREMAP_FILE)
|
||||
if (file_exists(CORE_KEYREMAP_FILE))
|
||||
{
|
||||
int mapct = core_load_key_remap(CORE_KEYREMAP_FILE);
|
||||
if (mapct <= 0)
|
||||
splashf(HZ, "key remap failed: %d, %s", mapct, CORE_KEYREMAP_FILE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef AUTOROCK
|
||||
{
|
||||
char filename[MAX_PATH];
|
||||
|
|
|
@ -47,6 +47,7 @@ jackpot,games
|
|||
jewels,games
|
||||
jpeg,viewers
|
||||
keybox,apps
|
||||
keyremap,apps
|
||||
lamp,apps
|
||||
logo,demos
|
||||
lrcplayer,apps
|
||||
|
|
|
@ -11,6 +11,7 @@ cube.c
|
|||
dict.c
|
||||
jackpot.c
|
||||
keybox.c
|
||||
keyremap.c
|
||||
logo.c
|
||||
lrcplayer.c
|
||||
mosaique.c
|
||||
|
|
1616
apps/plugins/keyremap.c
Normal file
1616
apps/plugins/keyremap.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -27,7 +27,7 @@
|
|||
*/
|
||||
#ifndef _ACTION_HELPER_H_
|
||||
#define _ACTION_HELPER_H_
|
||||
|
||||
extern const size_t action_helper_maxbuffer;
|
||||
char* action_name(int action);
|
||||
char* context_name(int context);
|
||||
|
||||
|
|
|
@ -140,10 +140,12 @@ printf "#define CONTEXTBUFSZ %d\n\n", $len_max_context;
|
|||
|
||||
if ($len_max_action > $len_max_context)
|
||||
{
|
||||
print "const size_t action_helper_maxbuffer = ACTIONBUFSZ;\n";
|
||||
print "static char name_buf[ACTIONBUFSZ];\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
print "const size_t action_helper_maxbuffer = CONTEXTBUFSZ;\n";
|
||||
print "static char name_buf[CONTEXTBUFSZ];\n";
|
||||
}
|
||||
print <<EOF
|
||||
|
|
|
@ -32,7 +32,9 @@ struct available_button
|
|||
* generated at compile time you can still call it as such though
|
||||
* eg available_buttons[0] or available_buttons[available_button_count] (NULL SENTINEL, 0)*/
|
||||
|
||||
extern const size_t button_helper_maxbuffer;
|
||||
extern const struct available_button * const available_buttons;
|
||||
extern const int available_button_count;
|
||||
|
||||
int get_button_names(char *buf, size_t bufsz, unsigned long button);
|
||||
#endif /* _BUTTON_HELPER_H_ */
|
||||
|
|
|
@ -26,12 +26,15 @@ my @buttons = ();
|
|||
my $count = 1; #null sentinel
|
||||
my $val;
|
||||
my $def;
|
||||
my $len_max_button = 0;
|
||||
while(my $line = <STDIN>)
|
||||
{
|
||||
chomp($line);
|
||||
if($line =~ /^#define (BUTTON_[^\s]+) (.+)$/)
|
||||
{
|
||||
$def = "{\"$1\", $2},\n";
|
||||
my $slen = length($1) + 1; # NULL terminator
|
||||
if ($slen > $len_max_button) { $len_max_button = $slen; }
|
||||
$val = $2;
|
||||
if($val =~ /^0/)
|
||||
{
|
||||
|
@ -53,6 +56,8 @@ print <<EOF
|
|||
#include "button.h"
|
||||
#include "button_helper.h"
|
||||
|
||||
const size_t button_helper_maxbuffer = $len_max_button;
|
||||
|
||||
static const struct available_button buttons[$count] = {
|
||||
EOF
|
||||
;
|
||||
|
|
|
@ -55,6 +55,8 @@ if ($def_type eq "rb_defines") {
|
|||
'^PLUGIN(_APPS_|_GAMES_|_)DATA_DIR$',
|
||||
'^ROCKBOX_DIR$',
|
||||
'^STYLE_(NONE|DEFAULT|INVERT|COLORBAR|GRADIENT|COLORED)',
|
||||
'^CORE_KEYMAP_FILE$',
|
||||
'CONTEXT_(STOPSEARCHING|REMOTE|CUSTOM|CUSTOM2|PLUGIN|REMAPPED)$',
|
||||
'^VIEWERS_DATA_DIR$');
|
||||
}
|
||||
elsif ($def_type eq "sound_defines") {
|
||||
|
|
Loading…
Reference in a new issue