Index: etc/menu.conf =================================================================== --- etc/menu.conf (revision 25255) +++ etc/menu.conf (working copy) @@ -1,3 +1,23 @@ + + + + + + + + + + + + + + + + + + + + Index: input/input.c =================================================================== --- input/input.c (revision 25256) +++ input/input.c (working copy) @@ -1373,7 +1373,7 @@ } -static int +int mp_input_get_key_from_name(const char *name) { int i,ret = 0,len = strlen(name); if(len == 1) { // Direct key code Index: input/input.h =================================================================== --- input/input.h (revision 25255) +++ input/input.h (working copy) @@ -238,6 +238,9 @@ void mp_input_rm_event_fd(int fd); +/// Get cmd from name. +int mp_input_get_key_from_name(const char *name); + // This function can be used to put a command in the system again. It's used by libmpdemux // when it performs a blocking operation to resend the command it received to the main // loop. Index: libmenu/menu_list.c =================================================================== --- libmenu/menu_list.c (revision 25255) +++ libmenu/menu_list.c (working copy) @@ -153,6 +153,8 @@ } void menu_list_read_cmd(menu_t* menu,int cmd) { + list_entry_t* m; + int i; switch(cmd) { case MENU_CMD_UP: while(mpriv->current->prev) { @@ -179,6 +181,27 @@ if(!mpriv->current->hide) return; } break; + case MENU_CMD_HOME: + mpriv->current = mpriv->menu; + break; + case MENU_CMD_END: + for(m = mpriv->current ; m && m->next ; m = m->next) + /**/; + if(m) + mpriv->current = m; + break; + case MENU_CMD_PAGE_UP: + for(i = 0, m = mpriv->current ; m && m->prev && i < mpriv->disp_lines ; m = m->prev, i++) + /**/; + if(m) + mpriv->current = m; + break; + case MENU_CMD_PAGE_DOWN: + for(i = 0, m = mpriv->current ; m && m->next && i < mpriv->disp_lines ; m = m->next, i++) + /**/; + if(m) + mpriv->current = m; + break; case MENU_CMD_LEFT: case MENU_CMD_CANCEL: menu->show = 0; @@ -187,59 +210,27 @@ } } -void menu_list_jump_to_key(menu_t* menu,int c) { +int menu_list_jump_to_key(menu_t* menu,int c) { if(c < 256 && isalnum(c)) { list_entry_t* e = mpriv->current; if(e->txt[0] == c) e = e->next; for( ; e ; e = e->next) { if(e->txt[0] == c) { mpriv->current = e; - return; + return 1; } } for(e = mpriv->menu ; e ; e = e->next) { if(e->txt[0] == c) { mpriv->current = e; - return; + return 1; } } - } else - menu_dflt_read_key(menu,c); + return 1; + } + return 0; } -void menu_list_read_key(menu_t* menu,int c,int jump_to) { - list_entry_t* m; - int i; - switch(c) { - case KEY_HOME: - mpriv->current = mpriv->menu; - break; - case KEY_END: - for(m = mpriv->current ; m && m->next ; m = m->next) - /**/; - if(m) - mpriv->current = m; - break; - case KEY_PAGE_UP: - for(i = 0, m = mpriv->current ; m && m->prev && i < mpriv->disp_lines ; m = m->prev, i++) - /**/; - if(m) - mpriv->current = m; - break; - case KEY_PAGE_DOWN: - for(i = 0, m = mpriv->current ; m && m->next && i < mpriv->disp_lines ; m = m->next, i++) - /**/; - if(m) - mpriv->current = m; - break; - default: - if(jump_to) - menu_list_jump_to_key(menu,c); - else - menu_dflt_read_key(menu,c); - } -} - void menu_list_add_entry(menu_t* menu,list_entry_t* entry) { list_entry_t* l; mpriv->count++; Index: libmenu/vf_menu.c =================================================================== --- libmenu/vf_menu.c (revision 25255) +++ libmenu/vf_menu.c (working copy) @@ -73,6 +73,14 @@ menu_read_cmd(priv->current,MENU_CMD_OK); else if(strcmp(arg,"cancel") == 0) menu_read_cmd(priv->current,MENU_CMD_CANCEL); + else if(strcmp(arg,"home") == 0) + menu_read_cmd(priv->current,MENU_CMD_HOME); + else if(strcmp(arg,"end") == 0) + menu_read_cmd(priv->current,MENU_CMD_END); + else if(strcmp(arg,"pageup") == 0) + menu_read_cmd(priv->current,MENU_CMD_PAGE_UP); + else if(strcmp(arg,"pagedown") == 0) + menu_read_cmd(priv->current,MENU_CMD_PAGE_DOWN); else if(strcmp(arg,"hide") == 0 || strcmp(arg,"toggle") == 0) priv->current->show = 0; else Index: libmenu/menu_cmdlist.c =================================================================== --- libmenu/menu_cmdlist.c (revision 25255) +++ libmenu/menu_cmdlist.c (working copy) @@ -91,10 +91,6 @@ } } -static void read_key(menu_t* menu,int c){ - menu_list_read_key(menu,c,0); -} - static void free_entry(list_entry_t* entry) { if(entry->ok) free(entry->ok); @@ -152,7 +148,6 @@ static int open_cmdlist(menu_t* menu, char* args) { menu->draw = menu_list_draw; menu->read_cmd = read_cmd; - menu->read_key = read_key; menu->close = close_menu; if(!args) { Index: libmenu/menu_txt.c =================================================================== --- libmenu/menu_txt.c (revision 25255) +++ libmenu/menu_txt.c (working copy) @@ -66,26 +66,19 @@ menu->show = 0; menu->cl = 1; break; - } -} - -static void read_key(menu_t* menu,int c) { - switch (c) { - case KEY_HOME: + case MENU_CMD_HOME: mpriv->cur_line = 0; break; - case KEY_END: + case MENU_CMD_END: mpriv->cur_line = mpriv->num_lines - 1; break; - case KEY_PAGE_UP: + case MENU_CMD_PAGE_UP: mpriv->cur_line = mpriv->cur_line > mpriv->disp_lines ? mpriv->cur_line - mpriv->disp_lines : 0; break; - case KEY_PAGE_DOWN: + case MENU_CMD_PAGE_DOWN: mpriv->cur_line = mpriv->cur_line + mpriv->disp_lines > mpriv->num_lines - 1 ? mpriv->num_lines - 1 : mpriv->cur_line + mpriv->disp_lines; break; - default: - menu_dflt_read_key(menu,c); } } @@ -129,7 +122,6 @@ menu->draw = draw; menu->read_cmd = read_cmd; - menu->read_key = read_key; if(!mpriv->file) { mp_msg(MSGT_GLOBAL,MSGL_WARN,MSGTR_LIBMENU_MenuTxtNeedATxtFileName); Index: libmenu/menu.c =================================================================== --- libmenu/menu.c (revision 25255) +++ libmenu/menu.c (working copy) @@ -15,6 +15,7 @@ #include "osdep/keycodes.h" #include "asxparser.h" #include "stream/stream.h" +#include "input/input.h" #include "libmpcodecs/img_format.h" #include "libmpcodecs/mp_image.h" @@ -46,6 +47,18 @@ NULL }; +typedef struct key_cmd_s { + int key; + char *cmd; +} key_cmd_t; + +typedef struct menu_cmd_bindings_s { + char *name; + key_cmd_t *bindings; + int binding_num; + struct menu_cmd_bindings_s *parent; +} menu_cmd_bindings_t; + struct menu_def_st { char* name; menu_info_t* type; @@ -56,8 +69,18 @@ static struct MPContext *menu_ctx = NULL; static menu_def_t* menu_list = NULL; static int menu_count = 0; +static menu_cmd_bindings_t *cmd_bindings = NULL; +static int cmd_bindings_num = 0; +menu_cmd_bindings_t *get_cmd_bindings(const char *name) { + int i; + for (i = 0; i < cmd_bindings_num; ++i) + if (!strcasecmp(cmd_bindings[i].name, name)) + return &cmd_bindings[i]; + return NULL; +} + static int menu_parse_config(char* buffer) { char *element,*body, **attribs, *name; menu_info_t* minfo = NULL; @@ -84,6 +107,59 @@ continue; } + if (!strcasecmp(element, "keybindings")) { + menu_cmd_bindings_t *bindings = cmd_bindings; + const char *parent_bindings; + cmd_bindings = realloc(cmd_bindings, + (cmd_bindings_num+1)*sizeof(menu_cmd_bindings_t)); + for (i = 0; i < cmd_bindings_num; ++i) + if (cmd_bindings[i].parent) + cmd_bindings[i].parent = cmd_bindings[i].parent-bindings+cmd_bindings; + bindings = &cmd_bindings[cmd_bindings_num]; + memset(bindings, 0, sizeof(menu_cmd_bindings_t)); + bindings->name = strdup(name); + parent_bindings = asx_get_attrib("parent",attribs); + if (parent_bindings) + bindings->parent = get_cmd_bindings(parent_bindings); + free(element); + asx_free_attribs(attribs); + if (body) { + char *bd = body; + char *b, *key, *cmd; + int keycode; + for(;;) { + r = asx_get_element(parser,&bd,&element,&b,&attribs); + if(r < 0) { + mp_msg(MSGT_GLOBAL,MSGL_WARN,MSGTR_LIBMENU_SyntaxErrorAtLine, + parser->line); + free(body); + asx_parser_free(parser); + return 0; + } + if(r == 0) + break; + key = asx_get_attrib("key",attribs); + cmd = asx_get_attrib("cmd",attribs); + if (key && (keycode = mp_input_get_key_from_name(key)) >= 0) { + mp_msg(MSGT_GLOBAL,MSGL_V, + "[libmenu] got keybinding element %s %s=>[%s].\n", + element, key, cmd ? cmd : ""); + bindings->bindings = realloc(bindings->bindings, + (bindings->binding_num+1)*sizeof(key_cmd_t)); + bindings->bindings[bindings->binding_num].key = keycode; + bindings->bindings[bindings->binding_num].cmd = cmd ? strdup(cmd) + : NULL; + ++bindings->binding_num; + } + free(element); + asx_free_attribs(attribs); + free(b); + } + free(body); + } + ++cmd_bindings_num; + continue; + } // Try to find this menu type in our list for(i = 0, minfo = NULL ; menu_info_list[i] ; i++) { if(strcasecmp(element,menu_info_list[i]->name) == 0) { @@ -178,30 +254,34 @@ } free(menu_list); menu_count = 0; + for (i = 0; i < cmd_bindings_num; ++i) { + free(cmd_bindings[i].name); + while(cmd_bindings[i].binding_num > 0) + free(cmd_bindings[i].bindings[--cmd_bindings[i].binding_num].cmd); + free(cmd_bindings[i].bindings); + } + free(cmd_bindings); } /// Default read_key function -void menu_dflt_read_key(menu_t* menu,int cmd) { - switch(cmd) { - case KEY_UP: - menu->read_cmd(menu,MENU_CMD_UP); - break; - case KEY_DOWN: - menu->read_cmd(menu,MENU_CMD_DOWN); - break; - case KEY_LEFT: - menu->read_cmd(menu,MENU_CMD_LEFT); - break; - case KEY_ESC: - menu->read_cmd(menu,MENU_CMD_CANCEL); - break; - case KEY_RIGHT: - menu->read_cmd(menu,MENU_CMD_RIGHT); - break; - case KEY_ENTER: - menu->read_cmd(menu,MENU_CMD_OK); - break; +int menu_dflt_read_key(menu_t* menu,int cmd) { + int i; + menu_cmd_bindings_t *bindings = get_cmd_bindings(menu->type->name); + if (!bindings) + bindings = get_cmd_bindings(menu->type->type->name); + if (!bindings) + bindings = get_cmd_bindings("default"); + while (bindings) { + for (i = 0; i < bindings->binding_num; ++i) { + if (bindings->bindings[i].key == cmd) { + if (bindings->bindings[i].cmd) + mp_input_queue_cmd(mp_input_parse_cmd(bindings->bindings[i].cmd)); + return 1; + } + } + bindings = bindings->parent; } + return 0; } menu_t* menu_open(char *name) { Index: libmenu/menu_list.h =================================================================== --- libmenu/menu_list.h (revision 25255) +++ libmenu/menu_list.h (working copy) @@ -38,12 +38,11 @@ typedef void (*free_entry_t)(list_entry_t* entry); void menu_list_read_cmd(menu_t* menu,int cmd); -void menu_list_read_key(menu_t* menu,int c,int jump_to); void menu_list_draw(menu_t* menu,mp_image_t* mpi); void menu_list_add_entry(menu_t* menu,list_entry_t* entry); void menu_list_init(menu_t* menu); void menu_list_uninit(menu_t* menu,free_entry_t free_func); -void menu_list_jump_to_key(menu_t* menu,int c); +int menu_list_jump_to_key(menu_t* menu,int c); extern const menu_list_priv_t menu_list_priv_dflt; Index: libmenu/menu_param.c =================================================================== --- libmenu/menu_param.c (revision 25255) +++ libmenu/menu_param.c (working copy) @@ -157,10 +157,6 @@ } } -static void read_key(menu_t* menu,int c) { - menu_list_read_key(menu,c,0); -} - static void read_cmd(menu_t* menu,int cmd) { list_entry_t* e = mpriv->p.current; @@ -247,7 +243,6 @@ menu->draw = menu_list_draw; menu->read_cmd = read_cmd; - menu->read_key = read_key; menu->close = closeMenu; Index: libmenu/menu_console.c =================================================================== --- libmenu/menu_console.c (revision 25255) +++ libmenu/menu_console.c (working copy) @@ -221,20 +221,6 @@ return; } -static void read_cmd(menu_t* menu,int cmd) { - switch(cmd) { - case MENU_CMD_UP: - break; - case MENU_CMD_DOWN: - case MENU_CMD_OK: - break; - case MENU_CMD_CANCEL: - menu->show = 0; - menu->cl = 1; - break; - } -} - static void check_child(menu_t* menu) { #ifndef __MINGW32__ fd_set rfd; @@ -362,16 +348,16 @@ //mpriv->input = mpriv->cur_history->buffer; } -static void read_key(menu_t* menu,int c) { - if(!mpriv->child || !mpriv->raw_child) switch(c) { - case KEY_ESC: +static void read_cmd(menu_t* menu,int cmd) { + switch(cmd) { + case MENU_CMD_CANCEL: if(mpriv->hide_time) mpriv->hide_ts = GetTimerMS(); else menu->show = 0; mpriv->show_ts = 0; return; - case KEY_ENTER: { + case MENU_CMD_OK: { mp_cmd_t* c; if(mpriv->child) { char *str = mpriv->cur_history->buffer; @@ -422,28 +408,32 @@ } return; } - case KEY_DELETE: - case KEY_BS: { - unsigned int i = strlen(mpriv->cur_history->buffer); - if(i > 0) - mpriv->cur_history->buffer[i-1] = '\0'; - return; - } - case KEY_UP: + case MENU_CMD_UP: if(mpriv->cur_history->prev) mpriv->cur_history = mpriv->cur_history->prev; break; - case KEY_DOWN: + case MENU_CMD_DOWN: if(mpriv->cur_history->next) mpriv->cur_history = mpriv->cur_history->next; break; } +} +static void read_key(menu_t* menu,int c) { if(mpriv->child && mpriv->raw_child) { write(mpriv->child_fd[0],&c,sizeof(int)); return; } + if (c == KEY_DELETE || c == KEY_BS) { + unsigned int i = strlen(mpriv->cur_history->buffer); + if(i > 0) + mpriv->cur_history->buffer[i-1] = '\0'; + return; + } + if (menu_dflt_read_key(menu, c)) + return; + if(isascii(c)) { int l = strlen(mpriv->cur_history->buffer); if(l >= mpriv->cur_history->size) { @@ -453,7 +443,7 @@ mpriv->cur_history->buffer[l] = (char)c; mpriv->cur_history->buffer[l+1] = '\0'; } - + return; } Index: libmenu/menu_filesel.c =================================================================== --- libmenu/menu_filesel.c (revision 25255) +++ libmenu/menu_filesel.c (working copy) @@ -370,19 +370,16 @@ } static void read_key(menu_t* menu,int c){ - if(c == KEY_BS) - read_cmd(menu,MENU_CMD_LEFT); - else { char **str; for (str=mpriv->actions; str && *str; str++) if (c == (*str)[0]) { action = &(*str)[2]; read_cmd(menu,MENU_CMD_ACTION); - break; + return; } - if (!str || !*str) - menu_list_read_key(menu,c,1); - } + if (menu_dflt_read_key(menu, c)) + return; + menu_list_jump_to_key(menu, c); } static void clos(menu_t* menu) { Index: libmenu/menu_pt.c =================================================================== --- libmenu/menu_pt.c (revision 25255) +++ libmenu/menu_pt.c (working copy) @@ -96,7 +96,9 @@ } static void read_key(menu_t* menu,int c){ - menu_list_read_key(menu,c,1); + if (menu_dflt_read_key(menu, c)) + return; + menu_list_jump_to_key(menu, c); } static void close_menu(menu_t* menu) { Index: libmenu/menu.h =================================================================== --- libmenu/menu.h (revision 25255) +++ libmenu/menu.h (working copy) @@ -38,6 +38,10 @@ #define MENU_CMD_LEFT 4 #define MENU_CMD_RIGHT 5 #define MENU_CMD_ACTION 6 +#define MENU_CMD_HOME 7 +#define MENU_CMD_END 8 +#define MENU_CMD_PAGE_UP 9 +#define MENU_CMD_PAGE_DOWN 10 /// Global init/uninit int menu_init(struct MPContext *mpctx, char* cfg_file); @@ -52,7 +56,7 @@ void menu_read_key(menu_t* menu,int cmd); //// Default implementation -void menu_dflt_read_key(menu_t* menu,int cmd); +int menu_dflt_read_key(menu_t* menu,int cmd); /////////// Helpers