diff -u --recursive GSnes9x-3.12-vanilla/src/confiles.c GSnes9x-3.12/src/confiles.c
--- GSnes9x-3.12-vanilla/src/confiles.c	Wed Mar 21 11:13:40 2001
+++ GSnes9x-3.12/src/confiles.c	Sun Sep  2 18:40:04 2001
@@ -46,6 +46,7 @@
 	"ROM_FILE", "NAME", "COMPANY", "IMAGE_FILE", "SNAP_FILE",
 	/* Global. */
 	"SNES9X_COMMAND", "ROMS_DIR", "SERVER", "NETPORT",
+	"JOYDEV0", "JOYDEV1", "JOYDEV2", "JOYDEV3",
 
 	/* Conf. files only. */
 	"JOYMAP0MAP", "JOYMAP1MAP", "JOYMAP2MAP", "JOYMAP3MAP",
@@ -133,7 +134,7 @@
 				break;
 			case UNKNOW_KEYWORD:
 				fclose (file);
-				g_warning (_("Unknow keyword %s."), lval);
+				g_warning (_("Unknown keyword %s."), lval);
 				g_warning (_("Configuration file corrupted. "
 					     "Recreating it with default "
 					     "values."));
diff -u --recursive GSnes9x-3.12-vanilla/src/defs.h GSnes9x-3.12/src/defs.h
--- GSnes9x-3.12-vanilla/src/defs.h	Thu Mar  8 08:06:03 2001
+++ GSnes9x-3.12/src/defs.h	Mon Sep  3 10:02:01 2001
@@ -53,7 +53,7 @@
 
 #define MIX_STR_PREFS     0
 #define ROM_STR_PREFS     5
-#define GLOB_STR_PREFS    4
+#define GLOB_STR_PREFS    8
 
 #define MIX_NUM_PREFS     7
 #define ROM_NUM_PREFS     0
@@ -137,7 +137,11 @@
 	SNES9X_COMMAND = 5,
 	ROMS_DIR       = 6,
 	SERVER         = 7,
-	NETPORT        = 8
+	NETPORT        = 8,
+	JOYDEV0        = 9,
+	JOYDEV1        = 10,
+	JOYDEV2        = 11,
+	JOYDEV3        = 12
 } GSnes9xStringPrefs;
 
 typedef enum {
@@ -205,6 +209,8 @@
 	gboolean     about_open;     /* The about window is open. */
 	gboolean     help_open;      /* The help window is open. */
 	gint         width, height;  /* Width & length of the pixmap window. */
+	guint        timer;          /* Timer for joystick code. */
+	int          jsfd;           /* FD to joystick device. */
 };
 
 struct _BrowseStruct {
diff -u --recursive GSnes9x-3.12-vanilla/src/globalprefs.c GSnes9x-3.12/src/globalprefs.c
--- GSnes9x-3.12-vanilla/src/globalprefs.c	Fri Apr 27 07:29:48 2001
+++ GSnes9x-3.12/src/globalprefs.c	Sun Sep  2 18:40:04 2001
@@ -573,6 +573,8 @@
 	GtkWidget *check;
 	GtkWidget *spin;
 	GtkWidget *button;	
+	GtkWidget *text;
+	GtkWidget *txt_label;
 	GtkObject *adj;
 	gchar     *label;
 	gint       i, j;
@@ -581,11 +583,11 @@
 
 	F_NAME();
 	
-	table = gtk_table_new (5, 11, FALSE);
+	table = gtk_table_new (5, 13, FALSE);
 
 	for (j = 0; j < NUM_OF_BUTTONS; j++) {
 		button = gtk_button_new_with_label (_(button_names[j]));
-		gtk_table_attach (GTK_TABLE (table), button, j+2, j+3, 0, 1,
+		gtk_table_attach (GTK_TABLE (table), button, j+5, j+6, 0, 1,
 				  GTK_FILL, GTK_FILL, 5, 2);
 		gtk_widget_show (button);
 	}
@@ -613,6 +615,15 @@
 				  5, 2);
 		gtk_widget_show (check);
 		gpd->check[JOYMAP0+i] = check;
+		txt_label = gtk_label_new (_("Device:"));
+		gtk_table_attach (GTK_TABLE (table), txt_label, 2, 3, i+1, i+2,
+		                  GTK_FILL, GTK_FILL, 5, 2);
+		gtk_widget_show (txt_label);
+		text = gtk_entry_new_with_max_length (CONF_STR_LEN);
+		gtk_table_attach (GTK_TABLE (table), text, 4, 5, i+1, i+2,
+		                  GTK_FILL, GTK_FILL, 5, 2);
+		gtk_widget_show (text);
+		gpd->entry[JOYDEV0+i-ROM_STR_PREFS] = text;
 		for (j = 0; j < NUM_OF_BUTTONS; j++) {
 			adj = gtk_adjustment_new
 				(gpd->data->prefs->buttons[i][j],
@@ -620,7 +631,7 @@
 			spin = gtk_spin_button_new
 				(GTK_ADJUSTMENT (adj), 0.5, 0);
 			gtk_table_attach
-				(GTK_TABLE (table), spin, j+2, j+3, i+1, i+2,
+				(GTK_TABLE (table), spin, j+5, j+6, i+1, i+2,
 				 GTK_FILL, GTK_FILL, 5, 2);
 			gtk_widget_set_usize (spin, 35, 23);
 			gtk_widget_show (spin);
@@ -633,6 +644,11 @@
 			    (gpointer) gpd);
 	
 	for (i = 0; i < NUM_OF_JOYS; i++)
+		gtk_signal_connect (GTK_OBJECT (gpd->check[JOYMAP0+i]),
+				    "toggled", GTK_SIGNAL_FUNC
+				    (toggle_to_active_cb),
+				    (gpointer) gpd->entry[JOYDEV0+i-
+				                          ROM_STR_PREFS]);
 		for (j = 0; j < NUM_OF_BUTTONS; j++)
 			gtk_signal_connect (GTK_OBJECT (gpd->check[JOYMAP0+i]),
 					    "toggled", GTK_SIGNAL_FUNC
@@ -697,6 +713,8 @@
 		for (i = 0; i < NUM_OF_JOYS; i++) {
 			gtk_widget_set_sensitive (gpd->check[JOYMAP0+i],
 						  FALSE);
+			gtk_widget_set_sensitive (gpd->entry[JOYDEV0+i-
+			                          ROM_STR_PREFS], FALSE);
 			for (j = 0; j < NUM_OF_BUTTONS; j++)
 				gtk_widget_set_sensitive (gpd->buttons[i][j],
 							  FALSE);
@@ -704,7 +722,13 @@
 	} else {
 		gtk_widget_set_sensitive (gpd->check[SWAP], TRUE);
 		for (i = 0; i < NUM_OF_JOYS; i++) {
-			gtk_widget_set_sensitive (gpd->check[JOYMAP0+i], TRUE);
+			gtk_widget_set_sensitive (gpd->check[JOYMAP0+i], 
+			                          GTK_TOGGLE_BUTTON (gpd->
+						  check[JOYMAP0+i])->active);
+			gtk_widget_set_sensitive (gpd->entry[JOYDEV0+i-
+			                          ROM_STR_PREFS], 
+						  GTK_TOGGLE_BUTTON (gpd->
+						  check[JOYMAP0+i])->active);
 			for (j = 0; j < NUM_OF_BUTTONS; j++)
 				gtk_widget_set_sensitive (
 					gpd->buttons[i][j],
@@ -1007,6 +1031,13 @@
 					"1 0 4 3 6 7 8 9 which is suitable "
 					"for Sidewinder gamepads."), NULL);
 	}
+	
+	for (i = 0; i < NUM_OF_JOYS; i++) {
+		tool = gtk_tooltips_new ();
+		gtk_tooltips_set_tip (tool,
+				      gpd->entry[JOYDEV0+i-ROM_STR_PREFS],
+				      _("Specify the joytick device."), NULL);
+	}
 }
 
 void
@@ -1106,17 +1137,27 @@
 		for (i = 0; i < NUM_OF_JOYS; i++) {
 			gtk_widget_set_sensitive (gpd->check[JOYMAP0+i],
 						  FALSE);
+			gtk_widget_set_sensitive (gpd->check[JOYDEV0+i-
+			                          ROM_STR_PREFS], FALSE);
 			for (j = 0; j < NUM_OF_BUTTONS; j++)
 				gtk_widget_set_sensitive (gpd->buttons[i][j],
 							  FALSE);
 		}
 	}
 
-	for (i = 0; i < NUM_OF_JOYS; i++)
-		if (!gpd->data->prefs->bool_prefs[JOYMAP0+i])
+	for (i = 0; i < NUM_OF_JOYS; i++) {
+		gtk_entry_set_text (GTK_ENTRY (gpd->entry[JOYDEV0+i-
+				    ROM_STR_PREFS]), 
+		                    gpd->data->prefs->string_prefs[JOYDEV0+i-
+				                                ROM_STR_PREFS]);
+		if (!gpd->data->prefs->bool_prefs[JOYMAP0+i]) {
+			gtk_widget_set_sensitive (gpd->entry[JOYDEV0+i-
+			                          ROM_STR_PREFS], FALSE);
 			for (j = 0; j < NUM_OF_BUTTONS; j++)
 				gtk_widget_set_sensitive (gpd->buttons[i][j],
 							  FALSE);
+		}
+	}
 #ifdef NO_ESD_SUPPORT
 	gtk_widget_set_sensitive (gpd->check[WITH_ESD-ROM_BOOL_PREFS], FALSE);
 #endif
@@ -1189,6 +1230,12 @@
 
 	for (i = 0; i < NUM_OF_JOYS; i++) {
 		if (gpd->data->prefs->bool_prefs[JOYMAP0+i])
+			text = gtk_entry_get_text (GTK_ENTRY 
+			       (gpd->entry[JOYDEV0+i-ROM_STR_PREFS]));
+			g_free (gpd->data->prefs->string_prefs[JOYDEV0+i-
+			        ROM_STR_PREFS]);
+			gpd->data->prefs->string_prefs[JOYDEV0+i-ROM_STR_PREFS]
+			        = g_strdup (text);
 			for (j = 0; j < NUM_OF_BUTTONS; j++) {
 				number = gtk_spin_button_get_value_as_int
 					(GTK_SPIN_BUTTON (gpd->buttons[i][j]));
diff -u --recursive GSnes9x-3.12-vanilla/src/main.c GSnes9x-3.12/src/main.c
--- GSnes9x-3.12-vanilla/src/main.c	Fri Apr 27 10:13:37 2001
+++ GSnes9x-3.12/src/main.c	Mon Sep  3 15:01:06 2001
@@ -16,7 +16,14 @@
  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define TIMER_FREQMS 50
+
 #include "gsnes9x.h"
+#include <linux/joystick.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 
 /* For use in the worst case. */
 /* It's not a variable! :) */
@@ -39,9 +46,18 @@
 int
 main (gint argc, gchar *argv[])
 {
+	gchar *geometry = NULL;
+	poptContext pctx;
+	struct poptOption options[] = {
+		{ "geometry", '\0', POPT_ARG_STRING, &geometry, 0,
+		   N_("Specify the geometry of the window."),
+		   N_("GEOMETRY") },
+		{ NULL, '\0', 0, NULL, 0 }
+	};
 	F_NAME();
 	
-	gnome_init (PACKAGE, VERSION, argc, argv);
+	gnome_init_with_popt_table (PACKAGE, VERSION, argc, argv, options, 0, &pctx);
+	poptFreeContext (pctx);
 	
 #ifdef ENABLE_NLS
 	setlocale (LC_CTYPE, "");
@@ -53,15 +69,52 @@
 	
 	gnome_window_icon_set_default_from_file ("/usr/share/pixmaps/gsnes9x-icon.png");
 
-	main_window (gsnes9x_init ());
+	main_window (gsnes9x_init (), geometry);
 
 	gtk_main ();
 
 	return 0;
 }
 
+int
+timer_handler (gpointer data)
+{
+	struct js_event js;
+	if (read (((GSnes9xData *) data)->jsfd, &js, sizeof (struct js_event))) {
+		switch (js.type & ~JS_EVENT_INIT) {
+			case JS_EVENT_BUTTON:
+				if (js.number == ((GSnes9xData *) data)->prefs->buttons[0][0] && js.value == 1)
+					play_cb (NULL, (GSnes9xData *) data);
+				if (js.number == ((GSnes9xData *) data)->prefs->buttons[0][2] && js.value == 1) {
+					int prev = ((GSnes9xData *) data)->current_rom - 10;
+					gtk_clist_moveto ((GtkCList *) ((GSnes9xData *) data)->clist, prev, 0, .5, 0);
+					gtk_clist_select_row ((GtkCList *) ((GSnes9xData *) data)->clist, prev, 0);
+				}
+				if (js.number == ((GSnes9xData *) data)->prefs->buttons[0][1] && js.value == 1) {
+					int next = ((GSnes9xData *) data)->current_rom + 10;
+					gtk_clist_moveto ((GtkCList *) ((GSnes9xData *) data)->clist, next, 0, .5, 0);
+					gtk_clist_select_row ((GtkCList *) ((GSnes9xData *) data)->clist, next, 0);
+				}
+				break;
+			case JS_EVENT_AXIS:
+				if (js.number == 1 && js.value == -32767) {
+					int prev = ((GSnes9xData *) data)->current_rom - 1;
+					gtk_clist_moveto ((GtkCList *) ((GSnes9xData *) data)->clist, prev, 0, .5, 0);
+					gtk_clist_select_row ((GtkCList *) ((GSnes9xData *) data)->clist, prev, 0);
+				}
+				if (js.number == 1 && js.value == 32767) {
+					int next = ((GSnes9xData *) data)->current_rom + 1;
+					gtk_clist_moveto ((GtkCList *) ((GSnes9xData *) data)->clist, next, 0, .5, 0);
+					gtk_clist_select_row ((GtkCList *) ((GSnes9xData *) data)->clist, next, 0);
+				}
+				break;
+		}
+	}
+	return 1;
+}
+
 void
-main_window (GlobalPrefs *prefs)
+main_window (GlobalPrefs *prefs, const gchar *geometry)
 {
 	gchar       *status;
 	GtkWidget   *vbox;
@@ -74,6 +127,18 @@
 	data->roms_list = g_list_first (get_roms_list ());
 	data->app       = gnome_app_new (PACKAGE, PACKAGE);
 	data->status    = gtk_label_new ("");
+
+	if (geometry != NULL) {
+		gint x, y, w, h;
+		if (gnome_parse_geometry (geometry, &x, &y, &w, &h)) {
+			if (x != -1)
+				gtk_widget_set_uposition (data->app, x, y);
+			if (w != -1)
+				gtk_window_set_default_size (data->app, w, h);
+		} else
+			g_error (_("Unable to parse the geometry string '%s'"),
+				   geometry);
+	}
 	
 	gtk_misc_set_alignment (GTK_MISC (data->status), 0, 0.5);
 	
@@ -120,6 +185,11 @@
 	gtk_signal_connect (GTK_OBJECT (data->image_w), "draw",
 			    GTK_SIGNAL_FUNC (resize_pixmap_cb),
 			    (gpointer) data);
+
+	if ((data->jsfd = open (data->prefs->string_prefs[JOYDEV0-ROM_STR_PREFS], O_RDONLY | O_NONBLOCK)) < 0) {
+		g_error (_("Error opening joystick device"));
+	}
+	data->timer = gtk_timeout_add (TIMER_FREQMS, timer_handler, data);
 }
 
 GlobalPrefs*
diff -u --recursive GSnes9x-3.12-vanilla/src/main.h GSnes9x-3.12/src/main.h
--- GSnes9x-3.12-vanilla/src/main.h	Fri Oct 15 08:00:00 1999
+++ GSnes9x-3.12/src/main.h	Mon Sep  3 14:36:40 2001
@@ -21,7 +21,7 @@
 #define GSNES9X_GSNES9X_MAIN_H
 
 int          main             (gint argc, gchar *argv[]);
-void         main_window      (GlobalPrefs *prefs);
+void         main_window      (GlobalPrefs *prefs, const gchar *geometry);
 GlobalPrefs* gsnes9x_init     ();
 void         get_roms_window  (GSnes9xData *gsnes_data);
 void         get_image_window (GSnes9xData *gsnes_data);
diff -u --recursive GSnes9x-3.12-vanilla/src/util.c GSnes9x-3.12/src/util.c
--- GSnes9x-3.12-vanilla/src/util.c	Fri Apr 27 03:19:37 2001
+++ GSnes9x-3.12/src/util.c	Sun Sep  2 18:40:04 2001
@@ -131,6 +131,11 @@
 				(prefs->string_prefs[NETPORT-ROM_STR_PREFS]);
 		}
 	}
+
+        if (prefs->string_prefs[JOYDEV0-ROM_STR_PREFS]) {
+		process[cont++] = g_strdup ("-joydev1");
+		process[cont++] = g_strdup (prefs->string_prefs[JOYDEV0-ROM_STR_PREFS]);
+	}
 	
 	if (rom_info->bool_prefs[TRANSPARENCY])
 		process[cont++] = g_strdup ("-transparency");
