>From 7952868af8260143f6267ef4069b79cda0ccaa35 Mon Sep 17 00:00:00 2001
From: Antoine Cellerier <dionoea@videolan.org>
Date: Thu, 22 Jan 2009 23:39:20 +0100
Subject: [PATCH] Allow more than one hotkey per action. (Integer list method)

---
 include/vlc_common.h        |    2 +-
 include/vlc_configuration.h |    9 ++
 include/vlc_main.h          |    3 +-
 modules/control/hotkeys.c   |    5 +-
 src/config/cmdline.c        |   24 +++++-
 src/config/configuration.h  |    7 ++-
 src/config/core.c           |  100 ++++++++++++++++++++++-
 src/config/file.c           |  108 +++++++++++++++++--------
 src/libvlc-module.c         |  192 +++++++++++++++++++++---------------------
 src/libvlccore.sym          |    2 +
 src/misc/action.c           |    9 +-
 src/modules/cache.c         |    9 ++
 src/modules/entry.c         |   16 ++++
 13 files changed, 345 insertions(+), 141 deletions(-)

diff --git a/include/vlc_common.h b/include/vlc_common.h
index a231d83..fc2c320 100644
--- a/include/vlc_common.h
+++ b/include/vlc_common.h
@@ -425,7 +425,6 @@ struct vlc_list_t
 #define VLC_VAR_VOID      0x0010
 #define VLC_VAR_BOOL      0x0020
 #define VLC_VAR_INTEGER   0x0030
-#define VLC_VAR_HOTKEY    0x0031
 #define VLC_VAR_STRING    0x0040
 #define VLC_VAR_MODULE    0x0041
 #define VLC_VAR_FILE      0x0042
@@ -436,6 +435,7 @@ struct vlc_list_t
 #define VLC_VAR_ADDRESS   0x0070
 #define VLC_VAR_MUTEX     0x0080
 #define VLC_VAR_LIST      0x0090
+#define VLC_VAR_HOTKEY    0x0091
 /**@}*/
 
 /*****************************************************************************
diff --git a/include/vlc_configuration.h b/include/vlc_configuration.h
index 5ccb29e..2d30a84 100644
--- a/include/vlc_configuration.h
+++ b/include/vlc_configuration.h
@@ -139,6 +139,11 @@ typedef union
     char       *psz;
     int         i;
     float       f;
+    struct
+    {
+        int count;
+        int *i;
+    } list;
 } module_value_t;
 
 typedef union
@@ -203,6 +208,8 @@ struct module_config_t
 VLC_EXPORT( int,    __config_GetType,  (vlc_object_t *, const char *) LIBVLC_USED );
 VLC_EXPORT( int,    __config_GetInt,   (vlc_object_t *, const char *) LIBVLC_USED );
 VLC_EXPORT( void,   __config_PutInt,   (vlc_object_t *, const char *, int) );
+VLC_EXPORT( int *,  __config_GetIntList,(vlc_object_t *, const char *, int *) LIBVLC_USED );
+VLC_EXPORT( void,   __config_PutIntList,(vlc_object_t *, const char *, int *, int) );
 VLC_EXPORT( float,  __config_GetFloat, (vlc_object_t *, const char *) LIBVLC_USED );
 VLC_EXPORT( void,   __config_PutFloat, (vlc_object_t *, const char *, float) );
 VLC_EXPORT( char *, __config_GetPsz,   (vlc_object_t *, const char *) LIBVLC_USED );
@@ -229,6 +236,8 @@ VLC_EXPORT( bool, __config_ExistIntf,  ( vlc_object_t *, const char * ) LIBVLC_U
 #define config_GetType(a,b) __config_GetType(VLC_OBJECT(a),b)
 #define config_GetInt(a,b) __config_GetInt(VLC_OBJECT(a),b)
 #define config_PutInt(a,b,c) __config_PutInt(VLC_OBJECT(a),b,c)
+#define config_GetIntList(a,b,c) __config_GetIntList(VLC_OBJECT(a),b,c)
+#define config_PutIntList(a,b,c,d) __config_PutIntList(VLC_OBJECT(a),b,c,d)
 #define config_GetFloat(a,b) __config_GetFloat(VLC_OBJECT(a),b)
 #define config_PutFloat(a,b,c) __config_PutFloat(VLC_OBJECT(a),b,c)
 #define config_GetPsz(a,b) __config_GetPsz(VLC_OBJECT(a),b)
diff --git a/include/vlc_main.h b/include/vlc_main.h
index 119b177..985c173 100644
--- a/include/vlc_main.h
+++ b/include/vlc_main.h
@@ -45,7 +45,8 @@ struct libvlc_int_t
     {
         const char *psz_action;
         int i_action;
-        int i_key;
+        int *pi_keys;
+        int i_keys;
     } *p_hotkeys;
 };
 
diff --git a/modules/control/hotkeys.c b/modules/control/hotkeys.c
index 3e93d61..a5b2f79 100644
--- a/modules/control/hotkeys.c
+++ b/modules/control/hotkeys.c
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * hotkeys.c: Hotkey handling for vlc
  *****************************************************************************
- * Copyright (C) 2005 the VideoLAN team
+ * Copyright (C) 2005-2009 the VideoLAN team
  * $Id$
  *
  * Authors: Sigmund Augdal Helberg <dnumgis@videolan.org>
@@ -161,7 +161,8 @@ static void Run( intf_thread_t *p_intf )
          p_hotkey->psz_action != NULL;
          p_hotkey++ )
     {
-        p_hotkey->i_key = config_GetInt( p_intf, p_hotkey->psz_action );
+        p_hotkey->pi_keys = config_GetIntList( p_intf, p_hotkey->psz_action,
+                                               &p_hotkey->i_keys );
     }
 
     for( ;; )
diff --git a/src/config/cmdline.c b/src/config/cmdline.c
index c9fa3ce..6d510e1 100644
--- a/src/config/cmdline.c
+++ b/src/config/cmdline.c
@@ -300,8 +300,30 @@ int __config_LoadCmdLine( vlc_object_t *p_this, int *pi_argc,
                         config_PutFloat( p_this, psz_name, (float)atof(optarg) );
                         break;
                     case CONFIG_ITEM_KEY:
-                        config_PutInt( p_this, psz_name, ConfigStringToKey( optarg ) );
+                    {
+                        int i_count = 0;
+                        int *pi;
+                        const char *psz_parser = optarg;
+                        const char *psz_next;
+                        while( psz_parser )
+                        {
+                            ConfigStringToKey( psz_parser, &psz_next );
+                            i_count++;
+                            psz_parser = psz_next;
+                        }
+                        pi = malloc( i_count*sizeof(int) );
+                        i_count = 0;
+                        psz_parser = optarg;
+                        while( psz_parser )
+                        {
+                            pi[i_count] = ConfigStringToKey( psz_parser, &psz_next );
+                            i_count++;
+                            psz_parser = psz_next;
+                        }
+                        config_PutIntList( p_this, psz_name, pi, i_count );
+                        free( pi );
                         break;
+                    }
                     case CONFIG_ITEM_BOOL:
                         config_PutInt( p_this, psz_name, !flag );
                         break;
diff --git a/src/config/configuration.h b/src/config/configuration.h
index 9d1ba85..3055189 100644
--- a/src/config/configuration.h
+++ b/src/config/configuration.h
@@ -52,8 +52,13 @@ static inline int IsConfigFloatType (int type)
 {
     return type == CONFIG_ITEM_FLOAT;
 }
+static inline int IsConfigIntegerListType (int type)
+{
+    return type == CONFIG_ITEM_KEY;
+}
 
-int ConfigStringToKey( const char * );
+int ConfigStringToKey( const char *, char const ** );
+int CopyIntegerList( module_value_t *, const module_value_t * );
 
 /* The configuration file and directory */
 #if defined (SYS_BEOS)
diff --git a/src/config/core.c b/src/config/core.c
index fbd5331..e704c07 100644
--- a/src/config/core.c
+++ b/src/config/core.c
@@ -60,13 +60,23 @@ int IsConfigIntegerType (int type)
 {
     static const unsigned char config_types[] =
     {
-        CONFIG_ITEM_INTEGER, CONFIG_ITEM_KEY, CONFIG_ITEM_BOOL,
+        CONFIG_ITEM_INTEGER, CONFIG_ITEM_BOOL,
         CONFIG_CATEGORY, CONFIG_SUBCATEGORY
     };
 
     return memchr (config_types, type, sizeof (config_types)) != NULL;
 }
 
+int CopyIntegerList (module_value_t *dst, const module_value_t *src)
+{
+    if (dst==src) return VLC_SUCCESS;
+    dst->list.i = realloc (dst->list.i, src->list.count*sizeof(int));
+    if (!dst->list.i) return VLC_ENOMEM;
+    dst->list.count = src->list.count;
+    memcpy (dst->list.i, src->list.i, src->list.count*sizeof(int));
+    return VLC_SUCCESS;
+}
+
 
 /*****************************************************************************
  * config_GetType: get the type of a variable (bool, int, float, string)
@@ -94,10 +104,13 @@ int __config_GetType( vlc_object_t *p_this, const char *psz_name )
         break;
 
     case CONFIG_ITEM_INTEGER:
-    case CONFIG_ITEM_KEY:
         i_type = VLC_VAR_INTEGER;
         break;
 
+    case CONFIG_ITEM_KEY:
+        i_type = VLC_VAR_HOTKEY;
+        break;
+
     case CONFIG_ITEM_FLOAT:
         i_type = VLC_VAR_FLOAT;
         break;
@@ -163,6 +176,41 @@ int __config_GetInt( vlc_object_t *p_this, const char *psz_name )
 }
 
 /*****************************************************************************
+ * config_GetIntList: get the value of an int list variable
+ *****************************************************************************
+ * This function is used to get the value of variables which are internally
+ * represented by an integer list (CONFIG_ITEM_KEY)
+ *****************************************************************************/
+int *__config_GetIntList( vlc_object_t *p_this, const char *psz_name, int *i_count )
+{
+    module_config_t *p_config;
+    int *pi;
+
+    p_config = config_FindConfig( p_this, psz_name );
+
+    /* sanity checks */
+    if( !p_config )
+    {
+        msg_Err( p_this, "option %s does not exist", psz_name );
+        return NULL;
+    }
+
+    if (!IsConfigIntegerListType (p_config->i_type))
+    {
+        msg_Err( p_this, "option %s does not refer to an int list", psz_name );
+        return NULL;
+    }
+
+    vlc_mutex_lock( p_config->p_lock );
+    *i_count = p_config->value.list.count;
+    pi = malloc( *i_count * sizeof(int) );
+    if(pi) memcpy( pi, p_config->value.list.i, *i_count * sizeof(int) );
+    vlc_mutex_unlock( p_config->p_lock );
+
+    return pi;
+}
+
+/*****************************************************************************
  * config_GetFloat: get the value of a float variable
  *****************************************************************************
  * This function is used to get the value of variables which are internally
@@ -343,6 +391,50 @@ void __config_PutInt( vlc_object_t *p_this, const char *psz_name, int i_value )
 }
 
 /*****************************************************************************
+ * config_PutIntList: set the integer value of an int variable
+ *****************************************************************************
+ * This function is used to set the value of variables which are internally
+ * represented by an integer list (CONFIG_ITEM_KEY)
+ *****************************************************************************/
+void __config_PutIntList( vlc_object_t *p_this, const char *psz_name, int *pi_values, int i_count )
+{
+    module_config_t *p_config;
+    /* vlc_value_t oldval, val; */
+    module_value_t value;
+    value.list.count = i_count;
+    value.list.i = pi_values;
+
+    p_config = config_FindConfig( p_this, psz_name );
+
+    /* sanity checks */
+    if( !p_config )
+    {
+        msg_Warn( p_this, "option %s does not exist", psz_name );
+        return;
+    }
+
+    if (!IsConfigIntegerListType (p_config->i_type))
+    {
+        msg_Err( p_this, "option %s does not refer to an int list", psz_name );
+        return;
+    }
+
+    /* backup old value */
+    /* oldval.i_int = p_config->value.i; */
+
+    CopyIntegerList( &p_config->value, &value );
+
+    p_config->b_dirty = true;
+
+    /* val.i_int = p_config->value.i; */
+
+    if( p_config->pf_callback )
+    {
+        assert(0); /* FIXME */
+    }
+}
+
+/*****************************************************************************
  * config_PutFloat: set the value of a float variable
  *****************************************************************************
  * This function is used to set the value of variables which are internally
@@ -550,6 +642,10 @@ void __config_ResetAll( vlc_object_t *p_this )
             if (IsConfigIntegerType (p_module->p_config[i].i_type))
                 p_module->p_config[i].value.i = p_module->p_config[i].orig.i;
             else
+            if (IsConfigIntegerListType (p_module->p_config[i].i_type))
+                CopyIntegerList(&p_module->p_config[i].value,
+                                &p_module->p_config[i].orig);
+            else
             if (IsConfigFloatType (p_module->p_config[i].i_type))
                 p_module->p_config[i].value.f = p_module->p_config[i].orig.f;
             else
diff --git a/src/config/file.c b/src/config/file.c
index d6cc24e..d44342c 100644
--- a/src/config/file.c
+++ b/src/config/file.c
@@ -42,7 +42,7 @@
 #include "configuration.h"
 #include "modules/modules.h"
 
-static char *ConfigKeyToString( int );
+static char *ConfigKeyToString( const int *, int );
 
 static inline char *strdupnull (const char *src)
 {
@@ -255,6 +255,9 @@ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name )
         for (size_t i = 0; i < module->confsize; i++)
         {
             module_config_t *p_item = module->p_config + i;
+            const char *psz_parser;
+            const char *psz_next;
+            int i_count;
 
             if ((p_item->i_type & CONFIG_HINT)
              || strcmp (p_item->psz_name, psz_option_name))
@@ -287,8 +290,28 @@ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name )
                 case CONFIG_ITEM_KEY:
                     if( !*psz_option_value )
                         break;                    /* ignore empty option */
-                    p_item->value.i = ConfigStringToKey(psz_option_value);
-                    p_item->saved.i = p_item->value.i;
+                    psz_parser = psz_option_value;
+                    i_count = 0;
+                    while( psz_parser )
+                    {
+                        ConfigStringToKey( psz_parser, &psz_next );
+                        i_count ++;
+                        psz_parser = psz_next;
+                    }
+                    p_item->value.list.count = i_count;
+                    p_item->value.list.i = malloc( i_count*sizeof(int) );
+                    p_item->saved.list.count = i_count;
+                    p_item->saved.list.i = malloc( i_count*sizeof(int) );
+                    psz_parser = psz_option_value;
+                    i_count = 0;
+                    while( psz_parser )
+                    {
+                        p_item->value.list.i[i_count] =
+                        p_item->saved.list.i[i_count] =
+                            ConfigStringToKey( psz_parser, &psz_next );
+                        i_count++;
+                        psz_parser = psz_next;
+                    }
                     break;
 
                 default:
@@ -573,24 +596,30 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
             if (IsConfigIntegerType (p_item->i_type))
             {
                 int val = b_retain ? p_item->saved.i : p_item->value.i;
-                if (p_item->i_type == CONFIG_ITEM_KEY)
-                {
-                    char *psz_key = ConfigKeyToString (val);
-                    config_Write (file, p_item->psz_text, N_("key"),
-                                  val == p_item->orig.i,
-                                  p_item->psz_name, "%s",
-                                  psz_key ? psz_key : "");
-                    free (psz_key);
-                }
-                else
-                    config_Write (file, p_item->psz_text,
-                                  (p_item->i_type == CONFIG_ITEM_BOOL)
-                                      ? N_("boolean") : N_("integer"),
-                                  val == p_item->orig.i,
-                                  p_item->psz_name, "%d", val);
+                config_Write (file, p_item->psz_text,
+                              (p_item->i_type == CONFIG_ITEM_BOOL)
+                                  ? N_("boolean") : N_("integer"),
+                              val == p_item->orig.i,
+                              p_item->psz_name, "%d", val);
                 p_item->saved.i = val;
             }
             else
+            if (IsConfigIntegerListType (p_item->i_type))
+            {
+                int count = b_retain ? p_item->saved.list.count
+                                     : p_item->value.list.count;
+                const int *i = b_retain ? p_item->saved.list.i
+                                        : p_item->value.list.i;
+                char *psz_key = ConfigKeyToString (i, count);
+                config_Write (file, p_item->psz_text, N_("key"),
+                              count == p_item->orig.list.count &&
+                              !memcmp(i,p_item->orig.list.i,count),
+                              p_item->psz_name, "%s",
+                              psz_key ? psz_key : "");
+                free (psz_key);
+                CopyIntegerList(&p_item->saved,&p_item->value);
+            }
+            else
             if (IsConfigFloatType (p_item->i_type))
             {
                 float val = b_retain ? p_item->saved.f : p_item->value.f;
@@ -721,11 +750,12 @@ char *config_GetCustomConfigFile( libvlc_int_t *p_libvlc )
     return psz_configfile;
 }
 
-int ConfigStringToKey( const char *psz_key )
+int ConfigStringToKey( const char *psz_key, char const **ppsz_next )
 {
     int i_key = 0;
     unsigned int i;
     const char *psz_parser = strchr( psz_key, '-' );
+    *ppsz_next = NULL;
     while( psz_parser && psz_parser != psz_key )
     {
         for( i = 0; i < sizeof(vlc_modifiers) / sizeof(key_descriptor_t); i++ )
@@ -736,25 +766,32 @@ int ConfigStringToKey( const char *psz_key )
                 i_key |= vlc_modifiers[i].i_key_code;
             }
         }
+        if( i == sizeof(vlc_modifiers) / sizeof(key_descriptor_t) )
+            break;
         psz_key = psz_parser + 1;
         psz_parser = strchr( psz_key, '-' );
     }
     for( i = 0; i < sizeof(vlc_keys) / sizeof( key_descriptor_t ); i++ )
     {
-        if( !strcasecmp( vlc_keys[i].psz_key_string, psz_key ) )
+        if( !strncasecmp( vlc_keys[i].psz_key_string, psz_key,
+                          strlen( vlc_keys[i].psz_key_string ) ) )
         {
             i_key |= vlc_keys[i].i_key_code;
+            psz_key += strlen( vlc_keys[i].psz_key_string );
+            if( *psz_key == ',' )
+                *ppsz_next = psz_key+1;
             break;
         }
     }
     return i_key;
 }
 
-char *ConfigKeyToString( int i_key )
+char *ConfigKeyToString( const int *pi_keys, int i_keys )
 {
-    char *psz_key = malloc( 100 );
+    char *psz_key = malloc( 100*i_keys );
     char *p;
     size_t index;
+    int i;
 
     if ( !psz_key )
     {
@@ -763,21 +800,26 @@ char *ConfigKeyToString( int i_key )
     *psz_key = '\0';
     p = psz_key;
 
-    for( index = 0; index < (sizeof(vlc_modifiers) / sizeof(key_descriptor_t));
-         index++ )
+    for( i = 0; i < i_keys; i++ )
     {
-        if( i_key & vlc_modifiers[index].i_key_code )
+        int i_key = pi_keys[i];
+        if( i ) *p++ = ',';
+        for( index = 0; index < (sizeof(vlc_modifiers) / sizeof(key_descriptor_t));
+             index++ )
         {
-            p += sprintf( p, "%s-", vlc_modifiers[index].psz_key_string );
+            if( i_key & vlc_modifiers[index].i_key_code )
+            {
+                p += sprintf( p, "%s-", vlc_modifiers[index].psz_key_string );
+            }
         }
-    }
-    for( index = 0; index < (sizeof(vlc_keys) / sizeof( key_descriptor_t));
-         index++)
-    {
-        if( (int)( i_key & ~KEY_MODIFIER ) == vlc_keys[index].i_key_code )
+        for( index = 0; index < (sizeof(vlc_keys) / sizeof( key_descriptor_t));
+             index++)
         {
-            p += sprintf( p, "%s", vlc_keys[index].psz_key_string );
-            break;
+            if( (int)( i_key & ~KEY_MODIFIER ) == vlc_keys[index].i_key_code )
+            {
+                p += sprintf( p, "%s", vlc_keys[index].psz_key_string );
+                break;
+            }
         }
     }
     return psz_key;
diff --git a/src/libvlc-module.c b/src/libvlc-module.c
index c5ee5ef..0b47112 100644
--- a/src/libvlc-module.c
+++ b/src/libvlc-module.c
@@ -2629,102 +2629,102 @@ vlc_module_end ()
  *****************************************************************************/
 const struct hotkey libvlc_hotkeys[] =
 {
-    { "key-quit", ACTIONID_QUIT, 0, },
-    { "key-play-pause", ACTIONID_PLAY_PAUSE, 0, },
-    { "key-play", ACTIONID_PLAY, 0, },
-    { "key-pause", ACTIONID_PAUSE, 0, },
-    { "key-stop", ACTIONID_STOP, 0, },
-    { "key-position", ACTIONID_POSITION, 0, },
-    { "key-jump-extrashort", ACTIONID_JUMP_BACKWARD_EXTRASHORT, 0, },
-    { "key-jump+extrashort", ACTIONID_JUMP_FORWARD_EXTRASHORT, 0, },
-    { "key-jump-short", ACTIONID_JUMP_BACKWARD_SHORT, 0, },
-    { "key-jump+short", ACTIONID_JUMP_FORWARD_SHORT, 0, },
-    { "key-jump-medium", ACTIONID_JUMP_BACKWARD_MEDIUM, 0, },
-    { "key-jump+medium", ACTIONID_JUMP_FORWARD_MEDIUM, 0, },
-    { "key-jump-long", ACTIONID_JUMP_BACKWARD_LONG, 0, },
-    { "key-jump+long", ACTIONID_JUMP_FORWARD_LONG, 0, },
-    { "key-frame-next", ACTIONID_FRAME_NEXT, 0, },
-    { "key-prev", ACTIONID_PREV, 0, },
-    { "key-next", ACTIONID_NEXT, 0, },
-    { "key-faster", ACTIONID_FASTER, 0, },
-    { "key-slower", ACTIONID_SLOWER, 0, },
-    { "key-toggle-fullscreen", ACTIONID_TOGGLE_FULLSCREEN, 0, },
-    { "key-leave-fullscreen", ACTIONID_LEAVE_FULLSCREEN, 0, },
-    { "key-vol-up", ACTIONID_VOL_UP, 0, },
-    { "key-vol-down", ACTIONID_VOL_DOWN, 0, },
-    { "key-vol-mute", ACTIONID_VOL_MUTE, 0, },
-    { "key-subdelay-down", ACTIONID_SUBDELAY_DOWN, 0, },
-    { "key-subdelay-up", ACTIONID_SUBDELAY_UP, 0, },
-    { "key-audiodelay-down", ACTIONID_AUDIODELAY_DOWN, 0, },
-    { "key-audiodelay-up", ACTIONID_AUDIODELAY_UP, 0, },
-    { "key-audio-track", ACTIONID_AUDIO_TRACK, 0, },
-    { "key-subtitle-track", ACTIONID_SUBTITLE_TRACK, 0, },
-    { "key-aspect-ratio", ACTIONID_ASPECT_RATIO, 0, },
-    { "key-crop", ACTIONID_CROP, 0, },
-    { "key-deinterlace", ACTIONID_DEINTERLACE, 0, },
-    { "key-intf-show", ACTIONID_INTF_SHOW, 0, },
-    { "key-intf-hide", ACTIONID_INTF_HIDE, 0, },
-    { "key-snapshot", ACTIONID_SNAPSHOT, 0, },
-    { "key-zoom", ACTIONID_ZOOM, 0, },
-    { "key-unzoom", ACTIONID_UNZOOM, 0, },
-    { "key-crop-top", ACTIONID_CROP_TOP, 0, },
-    { "key-uncrop-top", ACTIONID_UNCROP_TOP, 0, },
-    { "key-crop-left", ACTIONID_CROP_LEFT, 0, },
-    { "key-uncrop-left", ACTIONID_UNCROP_LEFT, 0, },
-    { "key-crop-bottom", ACTIONID_CROP_BOTTOM, 0, },
-    { "key-uncrop-bottom", ACTIONID_UNCROP_BOTTOM, 0, },
-    { "key-crop-right", ACTIONID_CROP_RIGHT, 0, },
-    { "key-uncrop-right", ACTIONID_UNCROP_RIGHT, 0, },
-    { "key-nav-activate", ACTIONID_NAV_ACTIVATE, 0, },
-    { "key-nav-up", ACTIONID_NAV_UP, 0, },
-    { "key-nav-down", ACTIONID_NAV_DOWN, 0, },
-    { "key-nav-left", ACTIONID_NAV_LEFT, 0, },
-    { "key-nav-right", ACTIONID_NAV_RIGHT, 0, },
-    { "key-disc-menu", ACTIONID_DISC_MENU, 0, },
-    { "key-title-prev", ACTIONID_TITLE_PREV, 0, },
-    { "key-title-next", ACTIONID_TITLE_NEXT, 0, },
-    { "key-chapter-prev", ACTIONID_CHAPTER_PREV, 0, },
-    { "key-chapter-next", ACTIONID_CHAPTER_NEXT, 0, },
-    { "key-zoom-quarter", ACTIONID_ZOOM_QUARTER, 0, },
-    { "key-zoom-half", ACTIONID_ZOOM_HALF, 0, },
-    { "key-zoom-original", ACTIONID_ZOOM_ORIGINAL, 0, },
-    { "key-zoom-double", ACTIONID_ZOOM_DOUBLE, 0, },
-    { "key-set-bookmark1", ACTIONID_SET_BOOKMARK1, 0, },
-    { "key-set-bookmark2", ACTIONID_SET_BOOKMARK2, 0, },
-    { "key-set-bookmark3", ACTIONID_SET_BOOKMARK3, 0, },
-    { "key-set-bookmark4", ACTIONID_SET_BOOKMARK4, 0, },
-    { "key-set-bookmark5", ACTIONID_SET_BOOKMARK5, 0, },
-    { "key-set-bookmark6", ACTIONID_SET_BOOKMARK6, 0, },
-    { "key-set-bookmark7", ACTIONID_SET_BOOKMARK7, 0, },
-    { "key-set-bookmark8", ACTIONID_SET_BOOKMARK8, 0, },
-    { "key-set-bookmark9", ACTIONID_SET_BOOKMARK9, 0, },
-    { "key-set-bookmark10", ACTIONID_SET_BOOKMARK10, 0, },
-    { "key-play-bookmark1", ACTIONID_PLAY_BOOKMARK1, 0, },
-    { "key-play-bookmark2", ACTIONID_PLAY_BOOKMARK2, 0, },
-    { "key-play-bookmark3", ACTIONID_PLAY_BOOKMARK3, 0, },
-    { "key-play-bookmark4", ACTIONID_PLAY_BOOKMARK4, 0, },
-    { "key-play-bookmark5", ACTIONID_PLAY_BOOKMARK5, 0, },
-    { "key-play-bookmark6", ACTIONID_PLAY_BOOKMARK6, 0, },
-    { "key-play-bookmark7", ACTIONID_PLAY_BOOKMARK7, 0, },
-    { "key-play-bookmark8", ACTIONID_PLAY_BOOKMARK8, 0, },
-    { "key-play-bookmark9", ACTIONID_PLAY_BOOKMARK9, 0, },
-    { "key-play-bookmark10", ACTIONID_PLAY_BOOKMARK10, 0, },
-    { "key-history-back", ACTIONID_HISTORY_BACK, 0, },
-    { "key-history-forward", ACTIONID_HISTORY_FORWARD, 0, },
-    { "key-record", ACTIONID_RECORD, 0, },
-    { "key-dump", ACTIONID_DUMP, 0, },
-    { "key-random", ACTIONID_RANDOM, 0, },
-    { "key-loop", ACTIONID_LOOP, 0, },
-    { "key-wallpaper", ACTIONID_WALLPAPER, 0, },
-    { "key-menu-on", ACTIONID_MENU_ON, 0, },
-    { "key-menu-off", ACTIONID_MENU_OFF, 0, },
-    { "key-menu-right", ACTIONID_MENU_RIGHT, 0, },
-    { "key-menu-left", ACTIONID_MENU_LEFT, 0, },
-    { "key-menu-up", ACTIONID_MENU_UP, 0, },
-    { "key-menu-down", ACTIONID_MENU_DOWN, 0, },
-    { "key-menu-select", ACTIONID_MENU_SELECT, 0, },
-    { "key-audiodevice-cycle", ACTIONID_AUDIODEVICE_CYCLE, 0, },
-    { NULL, 0, 0, }
+    { "key-quit", ACTIONID_QUIT, NULL, 0, },
+    { "key-play-pause", ACTIONID_PLAY_PAUSE, NULL, 0, },
+    { "key-play", ACTIONID_PLAY, NULL, 0, },
+    { "key-pause", ACTIONID_PAUSE, NULL, 0, },
+    { "key-stop", ACTIONID_STOP, NULL, 0, },
+    { "key-position", ACTIONID_POSITION, NULL, 0, },
+    { "key-jump-extrashort", ACTIONID_JUMP_BACKWARD_EXTRASHORT, NULL, 0, },
+    { "key-jump+extrashort", ACTIONID_JUMP_FORWARD_EXTRASHORT, NULL, 0, },
+    { "key-jump-short", ACTIONID_JUMP_BACKWARD_SHORT, NULL, 0, },
+    { "key-jump+short", ACTIONID_JUMP_FORWARD_SHORT, NULL, 0, },
+    { "key-jump-medium", ACTIONID_JUMP_BACKWARD_MEDIUM, NULL, 0, },
+    { "key-jump+medium", ACTIONID_JUMP_FORWARD_MEDIUM, NULL, 0, },
+    { "key-jump-long", ACTIONID_JUMP_BACKWARD_LONG, NULL, 0, },
+    { "key-jump+long", ACTIONID_JUMP_FORWARD_LONG, NULL, 0, },
+    { "key-frame-next", ACTIONID_FRAME_NEXT, NULL, 0, },
+    { "key-prev", ACTIONID_PREV, NULL, 0, },
+    { "key-next", ACTIONID_NEXT, NULL, 0, },
+    { "key-faster", ACTIONID_FASTER, NULL, 0, },
+    { "key-slower", ACTIONID_SLOWER, NULL, 0, },
+    { "key-toggle-fullscreen", ACTIONID_TOGGLE_FULLSCREEN, NULL, 0, },
+    { "key-leave-fullscreen", ACTIONID_LEAVE_FULLSCREEN, NULL, 0, },
+    { "key-vol-up", ACTIONID_VOL_UP, NULL, 0, },
+    { "key-vol-down", ACTIONID_VOL_DOWN, NULL, 0, },
+    { "key-vol-mute", ACTIONID_VOL_MUTE, NULL, 0, },
+    { "key-subdelay-down", ACTIONID_SUBDELAY_DOWN, NULL, 0, },
+    { "key-subdelay-up", ACTIONID_SUBDELAY_UP, NULL, 0, },
+    { "key-audiodelay-down", ACTIONID_AUDIODELAY_DOWN, NULL, 0, },
+    { "key-audiodelay-up", ACTIONID_AUDIODELAY_UP, NULL, 0, },
+    { "key-audio-track", ACTIONID_AUDIO_TRACK, NULL, 0, },
+    { "key-subtitle-track", ACTIONID_SUBTITLE_TRACK, NULL, 0, },
+    { "key-aspect-ratio", ACTIONID_ASPECT_RATIO, NULL, 0, },
+    { "key-crop", ACTIONID_CROP, NULL, 0, },
+    { "key-deinterlace", ACTIONID_DEINTERLACE, NULL, 0, },
+    { "key-intf-show", ACTIONID_INTF_SHOW, NULL, 0, },
+    { "key-intf-hide", ACTIONID_INTF_HIDE, NULL, 0, },
+    { "key-snapshot", ACTIONID_SNAPSHOT, NULL, 0, },
+    { "key-zoom", ACTIONID_ZOOM, NULL, 0, },
+    { "key-unzoom", ACTIONID_UNZOOM, NULL, 0, },
+    { "key-crop-top", ACTIONID_CROP_TOP, NULL, 0, },
+    { "key-uncrop-top", ACTIONID_UNCROP_TOP, NULL, 0, },
+    { "key-crop-left", ACTIONID_CROP_LEFT, NULL, 0, },
+    { "key-uncrop-left", ACTIONID_UNCROP_LEFT, NULL, 0, },
+    { "key-crop-bottom", ACTIONID_CROP_BOTTOM, NULL, 0, },
+    { "key-uncrop-bottom", ACTIONID_UNCROP_BOTTOM, NULL, 0, },
+    { "key-crop-right", ACTIONID_CROP_RIGHT, NULL, 0, },
+    { "key-uncrop-right", ACTIONID_UNCROP_RIGHT, NULL, 0, },
+    { "key-nav-activate", ACTIONID_NAV_ACTIVATE, NULL, 0, },
+    { "key-nav-up", ACTIONID_NAV_UP, NULL, 0, },
+    { "key-nav-down", ACTIONID_NAV_DOWN, NULL, 0, },
+    { "key-nav-left", ACTIONID_NAV_LEFT, NULL, 0, },
+    { "key-nav-right", ACTIONID_NAV_RIGHT, NULL, 0, },
+    { "key-disc-menu", ACTIONID_DISC_MENU, NULL, 0, },
+    { "key-title-prev", ACTIONID_TITLE_PREV, NULL, 0, },
+    { "key-title-next", ACTIONID_TITLE_NEXT, NULL, 0, },
+    { "key-chapter-prev", ACTIONID_CHAPTER_PREV, NULL, 0, },
+    { "key-chapter-next", ACTIONID_CHAPTER_NEXT, NULL, 0, },
+    { "key-zoom-quarter", ACTIONID_ZOOM_QUARTER, NULL, 0, },
+    { "key-zoom-half", ACTIONID_ZOOM_HALF, NULL, 0, },
+    { "key-zoom-original", ACTIONID_ZOOM_ORIGINAL, NULL, 0, },
+    { "key-zoom-double", ACTIONID_ZOOM_DOUBLE, NULL, 0, },
+    { "key-set-bookmark1", ACTIONID_SET_BOOKMARK1, NULL, 0, },
+    { "key-set-bookmark2", ACTIONID_SET_BOOKMARK2, NULL, 0, },
+    { "key-set-bookmark3", ACTIONID_SET_BOOKMARK3, NULL, 0, },
+    { "key-set-bookmark4", ACTIONID_SET_BOOKMARK4, NULL, 0, },
+    { "key-set-bookmark5", ACTIONID_SET_BOOKMARK5, NULL, 0, },
+    { "key-set-bookmark6", ACTIONID_SET_BOOKMARK6, NULL, 0, },
+    { "key-set-bookmark7", ACTIONID_SET_BOOKMARK7, NULL, 0, },
+    { "key-set-bookmark8", ACTIONID_SET_BOOKMARK8, NULL, 0, },
+    { "key-set-bookmark9", ACTIONID_SET_BOOKMARK9, NULL, 0, },
+    { "key-set-bookmark10", ACTIONID_SET_BOOKMARK10, 0, 0, },
+    { "key-play-bookmark1", ACTIONID_PLAY_BOOKMARK1, NULL, 0, },
+    { "key-play-bookmark2", ACTIONID_PLAY_BOOKMARK2, NULL, 0, },
+    { "key-play-bookmark3", ACTIONID_PLAY_BOOKMARK3, NULL, 0, },
+    { "key-play-bookmark4", ACTIONID_PLAY_BOOKMARK4, NULL, 0, },
+    { "key-play-bookmark5", ACTIONID_PLAY_BOOKMARK5, NULL, 0, },
+    { "key-play-bookmark6", ACTIONID_PLAY_BOOKMARK6, NULL, 0, },
+    { "key-play-bookmark7", ACTIONID_PLAY_BOOKMARK7, NULL, 0, },
+    { "key-play-bookmark8", ACTIONID_PLAY_BOOKMARK8, NULL, 0, },
+    { "key-play-bookmark9", ACTIONID_PLAY_BOOKMARK9, NULL, 0, },
+    { "key-play-bookmark10", ACTIONID_PLAY_BOOKMARK10, 0, 0, },
+    { "key-history-back", ACTIONID_HISTORY_BACK, NULL, 0, },
+    { "key-history-forward", ACTIONID_HISTORY_FORWARD, NULL, 0, },
+    { "key-record", ACTIONID_RECORD, NULL, 0, },
+    { "key-dump", ACTIONID_DUMP, NULL, 0, },
+    { "key-random", ACTIONID_RANDOM, NULL, 0, },
+    { "key-loop", ACTIONID_LOOP, NULL, 0, },
+    { "key-wallpaper", ACTIONID_WALLPAPER, NULL, 0, },
+    { "key-menu-on", ACTIONID_MENU_ON, NULL, 0, },
+    { "key-menu-off", ACTIONID_MENU_OFF, NULL, 0, },
+    { "key-menu-right", ACTIONID_MENU_RIGHT, NULL, 0, },
+    { "key-menu-left", ACTIONID_MENU_LEFT, NULL, 0, },
+    { "key-menu-up", ACTIONID_MENU_UP, NULL, 0, },
+    { "key-menu-down", ACTIONID_MENU_DOWN, NULL, 0, },
+    { "key-menu-select", ACTIONID_MENU_SELECT, NULL, 0, },
+    { "key-audiodevice-cycle", ACTIONID_AUDIODEVICE_CYCLE, NULL, 0, },
+    { NULL, 0, NULL, 0, }
 };
 
 const size_t libvlc_hotkeys_size = sizeof (libvlc_hotkeys);
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index f8275b9..353376f 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -58,12 +58,14 @@ config_GetDataDir
 __config_GetFloat
 config_GetHomeDir
 __config_GetInt
+__config_GetIntList
 __config_GetPsz
 __config_GetType
 config_GetUserConfDir
 config_GetUserDataDir
 __config_PutFloat
 __config_PutInt
+__config_PutIntList
 __config_PutPsz
 __config_RemoveIntf
 __config_ResetAll
diff --git a/src/misc/action.c b/src/misc/action.c
index af731a3..02c2d0d 100644
--- a/src/misc/action.c
+++ b/src/misc/action.c
@@ -33,14 +33,15 @@ int vlc_key_to_action (vlc_object_t *libvlc, const char *varname,
     (void)varname;
     (void)prevkey;
 
-    while (key->i_key != curkey.i_int)
+    while (true)
     {
+        int i_key;
         if (key->psz_action == NULL)
             return VLC_SUCCESS; /* key is not mapped to anything */
-
+        for (i_key=0; i_key<key->i_keys; i_key++)
+            if (key->pi_keys[i_key] == curkey.i_int)
+                return var_SetInteger (libvlc, "key-action", key->i_action);
         key++;
     }
-
-    return var_SetInteger (libvlc, "key-action", key->i_action);
 }
 
diff --git a/src/modules/cache.c b/src/modules/cache.c
index e4002f4..1cdb15b 100644
--- a/src/modules/cache.c
+++ b/src/modules/cache.c
@@ -388,6 +388,15 @@ static int CacheLoadConfig( module_t *p_module, FILE *file )
                         ? strdup (p_module->p_config[i].orig.psz) : NULL;
             p_module->p_config[i].saved.psz = NULL;
         }
+        else if (IsConfigIntegerListType (p_module->p_config[i].i_type))
+        {
+            p_module->p_config[i].value.list.count =
+            p_module->p_config[i].orig.list.count =
+            p_module->p_config[i].saved.list.count = 0;
+            p_module->p_config[i].value.list.i =
+            p_module->p_config[i].orig.list.i =
+            p_module->p_config[i].saved.list.i = NULL;
+        }
         else
         {
             memcpy (&p_module->p_config[i].value, &p_module->p_config[i].orig,
diff --git a/src/modules/entry.c b/src/modules/entry.c
index ac96e49..3a69567 100644
--- a/src/modules/entry.c
+++ b/src/modules/entry.c
@@ -312,6 +312,22 @@ int vlc_config_set (module_config_t *restrict item, int id, ...)
                 ret = 0;
             }
             else
+            if (IsConfigIntegerListType (item->i_type))
+            {
+                item->orig.list.count = item->saved.list.count =
+                item->value.list.count = 1;
+                item->orig.list.i = malloc(sizeof(int));
+                item->saved.list.i = malloc(sizeof(int));
+                item->value.list.i = malloc(sizeof(int));
+                if( item->orig.list.i && item->saved.list.i && item->value.list.i )
+                {
+                    item->orig.list.i[0] = item->saved.list.i[0] =
+                    item->value.list.i[0] = va_arg (ap, int);
+                    ret = 0;
+                }
+                else
+                    ret = VLC_ENOMEM;
+            }
             if (IsConfigFloatType (item->i_type))
             {
                 item->orig.f = item->saved.f =
-- 
1.5.6.5

