diff --git a/apps/SOURCES b/apps/SOURCES
index 26e53d1..51a94b3 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -52,6 +52,7 @@ root_menu.c
 screens.c
 settings.c
 settings_list.c
+shortcuts.c
 status.c
 cuesheet.c
 talk.c
diff --git a/apps/main.c b/apps/main.c
index 07a8bba..23f8627 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -363,6 +363,7 @@ static void init(void)
 #ifdef DEBUG
     debug_init();
 #endif
+    shortcuts_init();
     /* Keep the order of this 3 (viewportmanager handles statusbars)
      * Must be done before any code uses the multi-screen API */
     gui_syncstatusbar_init(&statusbars);
diff --git a/apps/menu.c b/apps/menu.c
index 6a28b1d..5d42814 100644
--- a/apps/menu.c
+++ b/apps/menu.c
@@ -280,19 +280,10 @@ static int talk_menu_item(int selected_item, void *data)
         return 0;
 }
 
-void do_setting_from_menu(const struct menu_item_ex *temp,
-                          struct viewport parent[NB_SCREENS])
+void do_setting_screen(const struct settings_list *setting, char * title,
+                        struct viewport parent[NB_SCREENS])
 {
-    int setting_id;
-    const struct settings_list *setting =
-            find_setting(temp->variable, &setting_id);
-    char *title;
     char padded_title[MAX_PATH];
-    if ((temp->flags&MENU_TYPE_MASK) == MT_SETTING_W_TEXT)
-        title = temp->callback_and_desc->desc;
-    else
-        title = ID2P(setting->lang_id);
-
     /* Pad the title string by repeating it. This is needed
        so the scroll settings title can actually be used to
        test the setting */
@@ -319,6 +310,21 @@ void do_setting_from_menu(const struct menu_item_ex *temp,
     option_screen((struct settings_list *)setting, parent,
                   setting->flags&F_TEMPVAR, title);
 }
+    
+
+void do_setting_from_menu(const struct menu_item_ex *temp,
+                          struct viewport parent[NB_SCREENS])
+{
+    char *title;
+    int setting_id;
+    const struct settings_list *setting =
+        find_setting(temp->variable, &setting_id);
+    if (temp && ((temp->flags&MENU_TYPE_MASK) == MT_SETTING_W_TEXT))
+        title = temp->callback_and_desc->desc;
+    else
+        title = ID2P(setting->lang_id);
+    do_setting_screen(setting, title, parent);
+}
 
 /* display a menu */
 int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
diff --git a/apps/root_menu.c b/apps/root_menu.c
index 472c1db..1cf2e3e 100644
--- a/apps/root_menu.c
+++ b/apps/root_menu.c
@@ -379,6 +379,7 @@ static int load_bmarks(void* param)
 }
 
 int time_screen(void* ignored);     
+int do_shortcut_menu(void);
 
 /* These are all static const'd from apps/menus/ *.c
    so little hack so we can use them */
@@ -416,12 +417,16 @@ static const struct root_items items[] = {
                                                         &playlist_options },
     [GO_TO_PLAYLIST_VIEWER] = { playlist_view, NULL, &playlist_options },
     [GO_TO_SYSTEM_SCREEN] = { miscscrn, &info_menu, &system_menu },
+    [GO_TO_SHORTCUTMENU] = { do_shortcut_menu, NULL, NULL },
     
 };
 static const int nb_items = sizeof(items)/sizeof(*items);
 
 static int item_callback(int action, const struct menu_item_ex *this_item) ;
 
+MENUITEM_RETURNVALUE(shortcut_menu, "shortcuts", GO_TO_SHORTCUTMENU,
+                        NULL, Icon_file_view_menu);
+
 MENUITEM_RETURNVALUE(file_browser, ID2P(LANG_DIR_BROWSER), GO_TO_FILEBROWSER,
                         NULL, Icon_file_view_menu);
 #ifdef HAVE_TAGCACHE
@@ -493,6 +498,7 @@ MAKE_MENU(root_menu_, ID2P(LANG_ROCKBOX_TITLE),
 #if CONFIG_KEYPAD == PLAYER_PAD
             ,&do_shutdown_item
 #endif
+            ,&shortcut_menu
         );
 
 static int item_callback(int action, const struct menu_item_ex *this_item) 
diff --git a/apps/root_menu.h b/apps/root_menu.h
index 2ffdced..8d11d9b 100644
--- a/apps/root_menu.h
+++ b/apps/root_menu.h
@@ -58,6 +58,7 @@ enum {
     GO_TO_PLAYLISTS_SCREEN,
     GO_TO_PLAYLIST_VIEWER,
     GO_TO_SYSTEM_SCREEN,
+    GO_TO_SHORTCUTMENU
 };
 
 extern const struct menu_item_ex root_menu_;
diff --git a/apps/shortcuts.c b/apps/shortcuts.c
new file mode 100644
index 0000000..0358eaa
--- /dev/null
+++ b/apps/shortcuts.c
@@ -0,0 +1,230 @@
+/***************************************************************************
+ *
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include "config.h"
+#include "system.h"
+#include "action.h"
+#include "list.h"
+#include "settings.h"
+#include "settings_list.h"
+#include "lang.h"
+#include "menu.h"
+#include "misc.h"
+#include "tree.h"
+#include "splash.h"
+#include "filefuncs.h"
+ 
+ 
+enum shortcut_type {
+    SHORTCUT_UNDEFINED = -1,
+    SHORTCUT_SETTING,
+    SHORTCUT_FILE,
+    SHORTCUT_BROWSER
+};
+#define MAX_SHORTCUT_NAME 32
+struct shortcut {
+    enum shortcut_type type;
+    char name[MAX_SHORTCUT_NAME];
+    union {
+        char path[MAX_PATH];
+        int  value;
+        const struct settings_list *setting;
+    } u;
+    unsigned flags;
+};
+
+#define MAX_SHORTCUTS 32
+int shortcut_count = 0;
+struct shortcut shortcuts[MAX_SHORTCUTS];
+ 
+static struct shortcut* get_shortcut(int index)
+{
+    return &shortcuts[index];
+}
+bool verify_shortcut(struct shortcut* sc)
+{
+    switch (sc->type)
+    {
+        case SHORTCUT_UNDEFINED:
+            return false;
+        case SHORTCUT_BROWSER:
+        case SHORTCUT_FILE:
+            if (sc->u.path[0] == '\0')
+                return false;
+            if (sc->name[0] == '\0')
+                strlcpy(sc->name, sc->u.path, MAX_SHORTCUT_NAME);
+            break;
+        case SHORTCUT_SETTING:
+            break;
+    }
+    return true;
+}
+int readline_cb(int n, char *buf, void *parameters)
+{
+    (void)n;
+    (void)parameters;
+    struct shortcut **param = (struct shortcut**)parameters;
+    struct shortcut* sc = *param;
+    char *name, *value;
+
+    if (!strcasecmp(skip_whitespace(buf), "[shortcut]"))
+    {
+        if (sc && verify_shortcut(sc))
+            shortcut_count++;
+        sc = get_shortcut(shortcut_count);
+        sc->type = SHORTCUT_UNDEFINED;
+        sc->name[0] = '\0';
+        sc->u.path[0] = '\0';
+        *param = sc;
+    }
+    else if (sc && settings_parseline(buf, &name, &value))
+    {
+        if (!strcmp(name, "type"))
+        {
+            if (!strcmp(value, "browse"))
+                sc->type = SHORTCUT_BROWSER;
+            else if (!strcmp(value, "file"))
+                sc->type = SHORTCUT_FILE;
+            else if (!strcmp(value, "setting"))
+                sc->type = SHORTCUT_SETTING;
+        }
+        else if (!strcmp(name, "name"))
+        {
+            strlcpy(sc->name, value, MAX_SHORTCUT_NAME);
+        }
+        else if (!strcmp(name, "data"))
+        {
+            switch (sc->type)
+            {
+                case SHORTCUT_UNDEFINED:
+                    *param = NULL;
+                    break;
+                case SHORTCUT_BROWSER:
+                case SHORTCUT_FILE:
+                    strlcpy(sc->u.path, value, MAX_PATH);
+                    break;
+                case SHORTCUT_SETTING:
+                {
+                    int i;
+                    /* Find the setting */
+                    for (i=0; i<nb_settings; i++)
+                        if (settings[i].cfg_name &&
+                            !strcmp(settings[i].cfg_name, value))
+                            break;
+                    if (i < nb_settings)
+                        sc->u.setting = &settings[i];
+                    else
+                        *param = NULL;
+                }
+                break;
+            }
+        }
+    }
+    return 0;
+}
+void shortcuts_init(void)
+{
+    int fd;
+    char buf[512];
+    struct shortcut *param = NULL;
+    shortcut_count = 0;
+    fd = open_utf8(ROCKBOX_DIR "/shortcuts.txt", O_RDONLY);
+    if (fd < 0)
+        return;
+    fast_readline(fd, buf, sizeof buf, &param, readline_cb);
+    close(fd);
+    if (param && verify_shortcut(param))
+        shortcut_count++;
+}
+
+const char * shortcut_menu_get_name(int selected_item, void * data,
+                                   char * buffer, size_t buffer_len)
+{
+    (void)data;
+    (void)buffer;
+    (void)buffer_len;
+    struct shortcut *sc = get_shortcut(selected_item);
+    if (sc->type == SHORTCUT_SETTING)
+        return sc->name[0] ? sc->name : P2STR(ID2P(sc->u.setting->lang_id));
+    return sc->name;
+}
+
+int shortcut_menu_get_action(int action, struct gui_synclist *lists)
+{
+    (void)lists;
+    if (action == ACTION_STD_OK)
+        return ACTION_STD_CANCEL;
+    return action;
+}
+void do_setting_screen(const struct settings_list *setting, const char * title,
+                        struct viewport parent[NB_SCREENS]);
+
+int do_shortcut_menu(void)
+{
+    struct simplelist_info list;
+    struct shortcut *sc;
+    int done = GO_TO_PREVIOUS;
+    simplelist_info_init(&list, "shortcuts", shortcut_count, NULL);
+    list.get_name = shortcut_menu_get_name;
+    list.action_callback = shortcut_menu_get_action;
+    
+    while (done == GO_TO_PREVIOUS)
+    {
+        if (simplelist_show_list(&list))
+            return GO_TO_PREVIOUS; /* some error happened?! */
+        if (list.selection == -1)
+            return GO_TO_PREVIOUS;
+        else
+        {
+            sc = get_shortcut(list.selection);
+            switch (sc->type)
+            {
+                case SHORTCUT_UNDEFINED:
+                    break;
+                case SHORTCUT_FILE:
+                    if (!file_exists(sc->u.path))
+                    {
+                        splash(HZ, ID2P(LANG_NO_FILES));
+                        break;
+                    }
+                    /* else fall through */
+                case SHORTCUT_BROWSER:
+                {
+                    struct browse_context browse;
+                    browse_context_init(&browse, global_settings.dirfilter, 0,
+                            NULL, NOICON, sc->u.path, NULL);
+                    if (sc->type == SHORTCUT_FILE)
+                        browse.flags |= BROWSE_RUNFILE;
+                    done = rockbox_browse(&browse);
+                }
+                break;
+                case SHORTCUT_SETTING:
+                    do_setting_screen(sc->u.setting,
+                            sc->name[0] ? sc->name : P2STR(ID2P(sc->u.setting->lang_id)),NULL);
+                    break;
+            }
+        }
+    }
+    return done;
+}
diff --git a/apps/tree.c b/apps/tree.c
index 24acd5a..7aed09a 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -997,7 +997,10 @@ int rockbox_browse(struct browse_context *browse)
         tc.browse = browse;
         strcpy(current, browse->root);
         set_current_file(current);
-        ret_val = dirbrowse();
+        if (browse->flags&BROWSE_RUNFILE)
+            ret_val = ft_enter(&tc);
+        else
+            ret_val = dirbrowse();
     }
     backup_count--;
     if (backup_count >= 0)
diff --git a/apps/tree.h b/apps/tree.h
index 2b29605..a12045c 100644
--- a/apps/tree.h
+++ b/apps/tree.h
@@ -36,8 +36,10 @@ struct entry {
 
 #define BROWSE_SELECTONLY       0x0001  /* exit on selecting a file */
 #define BROWSE_NO_CONTEXT_MENU  0x0002  /* disable context menu */
+#define BROWSE_RUNFILE          0x0004  /* do ft_open() on the file instead of browsing */
 #define BROWSE_SELECTED         0x0100  /* this bit is set if user selected item */
 
+
 struct tree_context;
 
 struct tree_cache {
