diff --git a/ChangeLog b/ChangeLog
index ee70774da5b4c6290ab2672b6aae4216a60d648c..1cbd48325f92a1459a96c51c8d343ee44e854400 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,36 @@
 CVS code -
-
+- General:
+	- Complete overhaul and abstraction of the lowest level of
+	  keyboard input, mostly rewritten but incorporating a few bits
+	  from the old functions and adding support for Pico's Esc Esc
+	  [three-digit decimal ASCII code] input method.  New functions
+	  get_kbinput(), get_verbatim_kbinput(), get_ignored_kbinput(),
+	  get_accepted_kbinput(), get_ascii_kbinput(),
+	  get_escape_seq_kbinput(), and get_skip_tilde_kbinput().  These
+	  should work properly on FreeBSD (due to code and input
+	  provided by Lee Nelson and Wouter van Hemel, respectively).
+	  (DLR)
+	- The -K/--keypad command line/rcfile option has been removed,
+	  and keypad() is now always TRUE.  keypad_on() in winio.c and
+	  the check for _use_keypad in configure.ac have both been
+	  removed. (DLR)
+	- The -d/--rebinddelete command line/rcfile option, equivalent
+	  to Pico's -d, has been added.  It is intended to work around
+	  the problem with Backspace/Delete confusion on some terminals,
+	  notably FreeBSD; if your Backspace key acts like Delete, this
+	  option will fix that. (DLR)
+- files.c:
+  do_browser():
+	- Some of the Pico compatibility options in the file browser
+	  that don't work properly for Pico 4.6 have been removed. 
+	  Backspace, 'g', 'l', 'q', and 'u' are invalid, 'd' deletes the
+	  highlighted file, and 'r' renames the highlighted file. (DLR)
+- nano.h:
+	- Define KEY_SUSPEND as -1 when slang is used, as slang has no
+	  KEY_SUSPEND equivalent.  When nano is compiled with slang
+	  support, pressing Ctrl-Z to suspend nano at the Linux console
+	  with keypad(TRUE) generates Ctrl-Z instead of KEY_SUSPEND
+	  (which is what ncurses generates then). (DLR)
 - AUTHORS
 	- Updated to show 1.2/1.3 maintainers.
 
diff --git a/configure.ac b/configure.ac
index c7302cb3ade4486341d1d31af698df901ee3d2a0..da0ef4140ac7f07a2d6cd8c5c4ea6083462ec626 100644
--- a/configure.ac
+++ b/configure.ac
@@ -330,20 +330,6 @@ AC_CHECK_LIB([$CURSES_LIB_NAME], use_default_colors, AC_DEFINE(HAVE_USE_DEFAULT_
 if test x$slang_support != xyes; then
     AC_CHECK_LIB([$CURSES_LIB_NAME], wresize, AC_DEFINE(HAVE_WRESIZE, 1, [Define this if you have the wresize function in your ncurses-type library.]))
     AC_CHECK_LIB([$CURSES_LIB_NAME], resizeterm, AC_DEFINE(HAVE_RESIZETERM, 1, [Define this if you have the resizeterm function in your ncurses-type library.]))
-
-    # Taken from aumix (can't tell from the variable name?)
-    AC_CACHE_CHECK([for private member _use_keypad in WINDOW],
-    aumix_cv_struct_window_usekeypad,
-    [AC_TRY_COMPILE([#ifdef HAVE_NCURSES_H
-#include <ncurses.h>
-#else
-#include <curses.h>
-#endif], [WINDOW w; w._use_keypad;],
-    aumix_cv_struct_window_usekeypad=yes, aumix_cv_struct_window_usekeypad=no)])
-    
-    if test $aumix_cv_struct_window_usekeypad = yes; then
-	AC_DEFINE(HAVE_USEKEYPAD, 1, [Define this if your curses lib has the _use_keypad flag.])
-    fi
 fi
 
 dnl Parse any configure options
diff --git a/files.c b/files.c
index b70ed9461f01e3e155985f135f4d5ecb2c152d2d..4193a932756f26e0d25532373cb8c531f50fc2cf 100644
--- a/files.c
+++ b/files.c
@@ -2477,9 +2477,9 @@ char *do_browser(const char *inpath)
     struct stat st;
     char *foo, *retval = NULL;
     static char *path = NULL;
-    int numents = 0, i = 0, j = 0, kbinput = 0, longest = 0, abort = 0;
-    int col = 0, selected = 0, editline = 0, width = 0, filecols = 0;
-    int lineno = 0, kb;
+    int numents = 0, i = 0, j = 0, kbinput = -1, meta, longest = 0;
+    int abort = 0, col = 0, selected = 0, editline = 0, width = 0;
+    int filecols = 0, lineno = 0;
     char **filelist = (char **)NULL;
 #if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
     MEVENT mevent;
@@ -2505,7 +2505,6 @@ char *do_browser(const char *inpath)
     /* Sort the list by directory first, then alphabetically */
     qsort(filelist, numents, sizeof(char *), diralphasort);
 
-    kb = keypad_on(edit, 1);
     titlebar(path);
     bottombars(browser_list);
     curs_set(0);
@@ -2569,34 +2568,23 @@ char *do_browser(const char *inpath)
             break;
 #endif
 	case NANO_UP_KEY:
-	case KEY_UP:
-	case 'u':
 	    if (selected - width >= 0)
 		selected -= width;
 	    break;
 	case NANO_BACK_KEY:
-	case KEY_LEFT:
-	case NANO_BACKSPACE_KEY:
-	case 127:
-	case 'l':
 	    if (selected > 0)
 		selected--;
 	    break;
-	case KEY_DOWN:
 	case NANO_DOWN_KEY:
-	case 'd':
 	    if (selected + width <= numents - 1)
 		selected += width;
 	    break;
-	case KEY_RIGHT:
 	case NANO_FORWARD_KEY:
-	case 'r':
 	    if (selected < numents - 1)
 		selected++;
 	    break;
 	case NANO_PREVPAGE_KEY:
 	case NANO_PREVPAGE_FKEY:
-	case KEY_PPAGE:
 	case '-':
 	    if (selected >= (editwinrows + lineno % editwinrows) * width)
 		selected -= (editwinrows + lineno % editwinrows) * width; 
@@ -2605,7 +2593,6 @@ char *do_browser(const char *inpath)
 	    break;
 	case NANO_NEXTPAGE_KEY:
 	case NANO_NEXTPAGE_FKEY:
-	case KEY_NPAGE:	
 	case ' ':
 	    selected += (editwinrows - lineno % editwinrows) * width;
 	    if (selected >= numents)
@@ -2615,7 +2602,6 @@ char *do_browser(const char *inpath)
 	case NANO_HELP_FKEY:
 	     do_help();
 	     break;
-	case KEY_ENTER:
 	case NANO_ENTER_KEY:
 	case 's': /* More Pico compatibility */
 	case 'S':
@@ -2678,10 +2664,8 @@ char *do_browser(const char *inpath)
 	    return do_browser(path);
 
 	/* Goto a specific directory */
-	case 'g':	/* Pico compatibility */
-	case 'G':
 	case NANO_GOTO_KEY:
-
+	case NANO_GOTO_FKEY:
 	    curs_set(1);
 	    j = statusq(0, gotodir_list, "",
 #ifndef NANO_SMALL
@@ -2726,11 +2710,10 @@ char *do_browser(const char *inpath)
 	    return do_browser(path);
 
 	/* Stuff we want to abort the browser */
-	case 'q':
-	case 'Q':
 	case 'e':	/* Pico compatibility, yeech */
 	case 'E':
 	case NANO_CANCEL_KEY:
+	case NANO_EXIT_KEY:
 	case NANO_EXIT_FKEY:
 	    abort = 1;
 	    break;
@@ -2806,12 +2789,11 @@ char *do_browser(const char *inpath)
 	    }
 	}
  	wrefresh(edit);
-    } while ((kbinput = wgetch(edit)) != NANO_EXIT_KEY);
+    } while ((kbinput = get_kbinput(edit, &meta, ISSET(REBIND_DELETE))) != NANO_EXIT_KEY && kbinput != NANO_EXIT_FKEY);
     curs_set(1);
     blank_edit();
     titlebar(NULL);
     edit_refresh();
-    kb = keypad_on(edit, kb);
 
     /* cleanup */
     free_charptrarray(filelist, numents);
diff --git a/nano.c b/nano.c
index 1cb3aedc35591d9245a0a7e93905caad1480e6b1..c7bb5f528633d946c5fda5b36f7ca1ff96c0cf47 100644
--- a/nano.c
+++ b/nano.c
@@ -66,9 +66,6 @@ static sigjmp_buf jmpbuf;	/* Used to return to mainloop after SIGWINCH */
 /* What we do when we're all set to exit */
 RETSIGTYPE finish(int sigage)
 {
-    keypad(edit, TRUE);
-    keypad(bottomwin, TRUE);
-
     if (!ISSET(NO_HELP)) {
 	mvwaddstr(bottomwin, 1, 0, hblank);
 	mvwaddstr(bottomwin, 2, 0, hblank);
@@ -251,9 +248,6 @@ void window_init(void)
 void mouse_init(void)
 {
     if (ISSET(USE_MOUSE)) {
-	keypad_on(edit, 1);
-	keypad_on(bottomwin, 1);
-
 	mousemask(BUTTON1_RELEASED, NULL);
 	mouseinterval(50);
     } else
@@ -639,7 +633,6 @@ void usage(void)
     print1opt("-H", "--historylog", _("Log & read search/replace string history"));
     print1opt("-I", "--ignorercfiles", _("Don't look at nanorc files"));
 #endif
-    print1opt("-K", "--keypad", _("Use alternate keypad routines"));
 #ifndef NANO_SMALL
     print1opt("-M", "--mac", _("Write file in Mac format"));
     print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format"));
@@ -660,6 +653,7 @@ void usage(void)
 #endif
     print1opt("-c", "--const", _("Constantly show cursor position"));
 #ifndef NANO_SMALL
+    print1opt("-d", "--rebinddelete", _("Fix Backspace if it acts like Delete"));
     print1opt("-i", "--autoindent", _("Automatically indent new lines"));
     print1opt("-k", "--cut", _("Let ^K cut from cursor to end of line"));
 #endif
@@ -3001,6 +2995,7 @@ int main(int argc, char *argv[])
     const shortcut *s;
     int keyhandled = 0;	/* Have we handled the keystroke yet? */
     int kbinput = -1;		/* Input from keyboard */
+    int meta;
 
 #ifndef NANO_SMALL
     const toggle *t;
@@ -3019,7 +3014,6 @@ int main(int argc, char *argv[])
 	{"historylog", 0, 0, 'H'},
 	{"ignorercfiles", 0, 0, 'I'},
 #endif
-	{"keypad", 0, 0, 'K'},
 #ifndef DISABLE_JUSTIFY
 	{"quotestr", 1, 0, 'Q'},
 #endif
@@ -3032,6 +3026,7 @@ int main(int argc, char *argv[])
 	{"syntax", 1, 0, 'Y'},
 #endif
 	{"const", 0, 0, 'c'},
+	{"rebinddelete", 0, 0, 'd'},
 	{"nofollow", 0, 0, 'l'},
 #if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
 	{"mouse", 0, 0, 'm'},
@@ -3080,11 +3075,11 @@ int main(int argc, char *argv[])
 #endif
 
 #ifdef HAVE_GETOPT_LONG
-    while ((optchr = getopt_long(argc, argv, "h?BDFHIKMNQ:RST:VY:abcefgijklmo:pr:s:tvwxz",
+    while ((optchr = getopt_long(argc, argv, "h?BDFHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz",
 				 long_options, &option_index)) != -1) {
 #else
     while ((optchr =
-	    getopt(argc, argv, "h?BDFHIKMNQ:RST:VY:abcefgijklmo:pr:s:tvwxz")) != -1) {
+	    getopt(argc, argv, "h?BDFHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz")) != -1) {
 #endif
 
 	switch (optchr) {
@@ -3118,9 +3113,6 @@ int main(int argc, char *argv[])
 	    SET(NO_RCFILE);
 	    break;
 #endif
-	case 'K':
-	    SET(ALT_KEYPAD);
-	    break;
 #ifndef NANO_SMALL
 	case 'M':
 	    SET(MAC_FILE);
@@ -3173,6 +3165,9 @@ int main(int argc, char *argv[])
 	case 'c':
 	    SET(CONSTUPDATE);
 	    break;
+	case 'd':
+	    SET(REBIND_DELETE);
+	    break;
 #ifndef NANO_SMALL
 	case 'i':
 	    SET(AUTOINDENT);
@@ -3389,10 +3384,8 @@ int main(int argc, char *argv[])
     mouse_init();
 #endif
 
-    if (!ISSET(ALT_KEYPAD)) {
-	keypad(edit, TRUE);
-	keypad(bottomwin, TRUE);
-    }
+    keypad(edit, TRUE);
+    keypad(bottomwin, TRUE);
 
 #ifdef DEBUG
     fprintf(stderr, "Main: bottom win\n");
@@ -3456,160 +3449,12 @@ int main(int argc, char *argv[])
 	raw();
 #endif
 
-	kbinput = wgetch(edit);
+	kbinput = get_kbinput(edit, &meta, ISSET(REBIND_DELETE));
 #ifdef DEBUG
 	fprintf(stderr, "AHA!  %c (%d)\n", kbinput, kbinput);
 #endif
-	if (kbinput == 27) {	/* Grab Alt-key stuff first */
-	    kbinput = wgetch(edit);
+	if (meta == 1) {
 	    switch (kbinput) {
-		/* Alt-O, suddenly very important ;) */
-	    case 'O':
-		kbinput = wgetch(edit);
-		/* Shift or Ctrl + Arrows are Alt-O-[2,5,6]-[A,B,C,D] on some terms */
-		if (kbinput == '2' || kbinput == '5' || kbinput == '6')
-		    kbinput = wgetch(edit);
-		if ((kbinput <= 'D' && kbinput >= 'A') ||
-			(kbinput <= 'd' && kbinput >= 'a'))
-		    kbinput = abcd(kbinput);
-		else if (kbinput <= 'z' && kbinput >= 'j')
-		    print_numlock_warning();
-		else if (kbinput <= 'S' && kbinput >= 'P')
-		    kbinput = KEY_F(kbinput - 79);
-#ifdef DEBUG
-		else {
-		    fprintf(stderr, "I got Alt-O-%c! (%d)\n",
-			    kbinput, kbinput);
-		    break;
-		}
-#endif
-		break;
-	    case 27:
-		/* If we get Alt-Alt, the next keystroke should be the same as a
-		   control sequence */
-		modify_control_seq = 1;
-		keyhandled = 1;
-		break;
-	    case '[':
-		kbinput = wgetch(edit);
-		switch (kbinput) {
-		case '1':	/* Alt-[-1-[0-5,7-9] = F1-F8 in X at least */
-		    kbinput = wgetch(edit);
-		    if (kbinput >= '1' && kbinput <= '5') {
-			kbinput = KEY_F(kbinput - 48);
-			wgetch(edit);
-		    } else if (kbinput >= '7' && kbinput <= '9') {
-			kbinput = KEY_F(kbinput - 49);
-			wgetch(edit);
-		    } else if (kbinput == '~')
-			kbinput = KEY_HOME;
-#ifdef DEBUG
-		    else {
-			fprintf(stderr, "I got Alt-[-1-%c! (%d)\n",
-				kbinput, kbinput);
-			break;
-		    }
-#endif
-		    break;
-		case '2':	/* Alt-[-2-[0,1,3,4] = F9-F12 in many terms */
-		    kbinput = wgetch(edit);
-		    switch (kbinput) {
-		    case '0':
-			kbinput = KEY_F(9);
-			wgetch(edit);
-			break;
-		    case '1':
-			kbinput = KEY_F(10);
-			wgetch(edit);
-			break;
-		    case '3':
-			kbinput = KEY_F(11);
-			wgetch(edit);
-			break;
-		    case '4':
-			kbinput = KEY_F(12);
-			wgetch(edit);
-			break;
-		    case '~':
-			kbinput = NANO_INSERTFILE_KEY;
-			break;
-#ifdef DEBUG
-		    default:
-			fprintf(stderr, "I got Alt-[-2-%c! (%d)\n",
-				kbinput, kbinput);
-			break;
-#endif
-		    }
-		    break;
-		case '3':	/* Alt-[-3 = Delete? */
-		    kbinput = NANO_DELETE_KEY;
-		    wgetch(edit);
-		    break;
-		case '4':	/* Alt-[-4 = End? */
-		    kbinput = NANO_END_KEY;
-		    wgetch(edit);
-		    break;
-		case '5':	/* Alt-[-5 = Page Up */
-		    kbinput = KEY_PPAGE;
-		    wgetch(edit);
-		    break;
-		case 'V':	/* Alt-[-V = Page Up in Hurd Console */
-		case 'I':	/* Alt-[-I = Page Up - FreeBSD Console */
-		    kbinput = KEY_PPAGE;
-		    break;
-		case '6':	/* Alt-[-6 = Page Down */
-		    kbinput = KEY_NPAGE;
-		    wgetch(edit);
-		    break;
-		case 'U':	/* Alt-[-U = Page Down in Hurd Console */
-		case 'G':	/* Alt-[-G = Page Down - FreeBSD Console */
-		    kbinput = KEY_NPAGE;
-		    break;
-		case '7':
-		    kbinput = KEY_HOME;
-		    wgetch(edit);
-		    break;
-		case '8':
-		    kbinput = KEY_END;
-		    wgetch(edit);
-		    break;
-		case '9':	/* Alt-[-9 = Delete in Hurd Console */
-		    kbinput = KEY_DC;
-		    break;
-		case '@':	/* Alt-[-@ = Insert in Hurd Console */
-		case 'L':	/* Alt-[-L = Insert - FreeBSD Console */
-		    kbinput = NANO_INSERTFILE_KEY;
-		    break;
-		case '[':	/* Alt-[-[-[A-E], F1-F5 in Linux console */
-		    kbinput = wgetch(edit);
-		    if (kbinput >= 'A' && kbinput <= 'E')
-			kbinput = KEY_F(kbinput - 64);
-		    break;
-		case 'A':
-		case 'B':
-		case 'C':
-		case 'D':
-		case 'a':
-		case 'b':
-		case 'c':
-		case 'd':
-		    kbinput = abcd(kbinput);
-		    break;
-		case 'H':
-		    kbinput = KEY_HOME;
-		    break;
-		case 'F':
-		case 'Y':		/* End Key in Hurd Console */
-		    kbinput = KEY_END;
-		    break;
-		default:
-#ifdef DEBUG
-		    fprintf(stderr, "I got Alt-[-%c! (%d)\n",
-			    kbinput, kbinput);
-#endif
-		    break;
-		}
-		break;
 #ifdef ENABLE_MULTIBUFFER
 	    case NANO_OPENPREV_KEY:
 	    case NANO_OPENPREV_ALTKEY:
@@ -3656,23 +3501,6 @@ int main(int argc, char *argv[])
 		break;
 	    }
 	}
-	/* Hack, make insert key do something useful, like insert file */
-	else if (kbinput == KEY_IC)
-	    kbinput = NANO_INSERTFILE_KEY;
-
-	/* If modify_control_seq is set, we received an Alt-Alt
-	   sequence before this, so we make this key a control sequence
-	   by subtracting 32, 64, or 96, depending on its value. */
-	if (!keyhandled && modify_control_seq) {
-	    if (kbinput == ' ')
-		kbinput -= 32;
-	    else if (kbinput >= 'A' && kbinput < 'a')
-		kbinput -= 64;
-	    else if (kbinput >= 'a' && kbinput <= 'z')
-		kbinput -= 96;
-
-	    modify_control_seq = 0;
-	}
 
 	/* Look through the main shortcut list to see if we've hit a
 	   shortcut key */
@@ -3707,19 +3535,18 @@ int main(int argc, char *argv[])
 
 #ifdef _POSIX_VDISABLE
 	/* Don't even think about changing this string */
-	if (kbinput == 19)
-	    statusbar(_("XOFF ignored, mumble mumble."));
-	if (kbinput == 17)
+	if (kbinput == NANO_CONTROL_Q)
 	    statusbar(_("XON ignored, mumble mumble."));
+	if (kbinput == NANO_CONTROL_S)
+	    statusbar(_("XOFF ignored, mumble mumble."));
 #endif
 	/* If we're in raw mode or using Alt-Alt-x, we have to catch
 	   Control-S and Control-Q */
-	if (kbinput == 17 || kbinput == 19)
+	if (kbinput == NANO_CONTROL_Q || kbinput == NANO_CONTROL_S)
 	    keyhandled = 1;
 
-	/* Catch ^Z by hand when triggered also
-	   407 == ^Z in Linux console when keypad() is used? */
-	if (kbinput == 26 || kbinput == 407) {
+	/* Catch ^Z by hand when triggered also */
+	if (kbinput == NANO_SUSPEND_KEY) {
 	    if (ISSET(SUSPEND))
 		do_suspend(0);
 	    keyhandled = 1;
@@ -3734,18 +3561,10 @@ int main(int argc, char *argv[])
 		break;
 #endif
 
-	    case -1:		/* Stuff that we don't want to do squat */
-	    case 0:		/* Erg */
-	    case 29:		/* Ctrl-] */
-	    case 410:		/* Must ignore this, it's sent when we resize */
-#ifdef PDCURSES
-	    case 541:		/* ???? */
-	    case 542:		/* Control and alt in Windows *shrug* */
-	    case 543:		/* Right ctrl key */
-	    case 544:
-	    case 545:		/* Right alt key */
-#endif
-
+	    case NANO_CONTROL_3:	/* Ctrl-[ (Esc), which should
+	    				 * have been handled before we
+	    				 * got here */
+	    case NANO_CONTROL_5:	/* Ctrl-] */
 		break;
 	    default:
 #ifdef DEBUG
diff --git a/nano.h b/nano.h
index b442503b9677ce49b78bb710388feb112a6c3ab0..0444ab005a21bbdde2366154d83fcc34157f522b 100644
--- a/nano.h
+++ b/nano.h
@@ -48,6 +48,7 @@
 #include <slcurses.h>
 #define KEY_IC SL_KEY_IC
 #define KEY_DC SL_KEY_DELETE
+#define KEY_SUSPEND -1
 #elif defined(HAVE_NCURSES_H)
 #include <ncurses.h>
 #else /* Uh oh */
@@ -244,7 +245,7 @@ typedef struct historyheadtype {
 #define MAC_FILE		(1<<20)
 #define SMOOTHSCROLL		(1<<21)
 #define DISABLE_CURPOS		(1<<22)	/* Damn, we still need it */
-#define ALT_KEYPAD		(1<<23)
+#define REBIND_DELETE		(1<<23)
 #define NO_CONVERT		(1<<24)
 #define BACKUP_FILE		(1<<25)
 #define NO_RCFILE		(1<<26)
@@ -283,11 +284,12 @@ typedef struct historyheadtype {
 #define NANO_CONTROL_X 24
 #define NANO_CONTROL_Y 25
 #define NANO_CONTROL_Z 26
-
+#define NANO_CONTROL_3 27
 #define NANO_CONTROL_4 28
 #define NANO_CONTROL_5 29
 #define NANO_CONTROL_6 30
 #define NANO_CONTROL_7 31
+#define NANO_CONTROL_8 127
 
 #define NANO_ALT_A 'a'
 #define NANO_ALT_B 'b'
diff --git a/proto.h b/proto.h
index 9ad6a42b14b0e2e099f3aa82640007a6ca583736..609d6c6eb3236fe57eabf7b4cfeb443f45bc1cc0 100644
--- a/proto.h
+++ b/proto.h
@@ -424,6 +424,14 @@ int check_wildcard_match(const char *text, const char *pattern);
 #endif
 
 /* Public functions in winio.c */
+int get_kbinput(WINDOW *win, int *meta, int rebind_delete);
+char *get_verbatim_kbinput(WINDOW *win, int *kbinput_len);
+int get_ignored_kbinput(WINDOW *win);
+int get_accepted_kbinput(WINDOW *win, int kbinput, int *meta,
+	int rebind_delete);
+int get_ascii_kbinput(WINDOW *win, int kbinput);
+int get_escape_seq_kbinput(WINDOW *win, int kbinput);
+int get_skip_tilde_kbinput(WINDOW *win, int errval, int retval);
 int do_first_line(void);
 int do_last_line(void);
 int xpt(const filestruct *fileptr, int index);
@@ -482,7 +490,6 @@ int do_cursorpos(int constant);
 int do_cursorpos_void(void);
 int line_len(const char *ptr);
 int do_help(void);
-int keypad_on(WINDOW *win, int newval);
 void do_replace_highlight(int highlight_flag, const char *word);
 void fix_editbot(void);
 #ifdef DEBUG
diff --git a/rcfile.c b/rcfile.c
index cbdd52b68bb398b0886cca44de54f49bcaa290d5..071b7654bb0815ea08401a9c6f59709357e709f6 100644
--- a/rcfile.c
+++ b/rcfile.c
@@ -49,7 +49,6 @@ const static rcoption rcopts[] = {
 #ifndef DISABLE_WRAPJUSTIFY
     {"fill", 0},
 #endif
-    {"keypad", ALT_KEYPAD},
 #if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
     {"mouse", USE_MOUSE},
 #endif
@@ -68,6 +67,7 @@ const static rcoption rcopts[] = {
     {"operatingdir", 0},
 #endif
     {"preserve", PRESERVE},
+    {"rebinddelete", REBIND_DELETE},
 #ifndef DISABLE_JUSTIFY
     {"quotestr", 0},
 #endif
diff --git a/winio.c b/winio.c
index dd72bcc3c0258d550e7f615dbb8cb1205e4e5321..1a7590023c595b0663deda6df4c1bb91130aee18 100644
--- a/winio.c
+++ b/winio.c
@@ -34,6 +34,295 @@ static int statblank = 0;	/* Number of keystrokes left after
 				   we call statusbar(), before we
 				   actually blank the statusbar */
 
+/* Read in a single input character.  If it's ignored, swallow it and go
+ * on.  Otherwise, try to translate it from ASCII and extended (keypad)
+ * input.  Assume nodelay(win) is FALSE. */
+int get_kbinput(WINDOW *win, int *meta, int rebind_delete)
+{
+    int kbinput, retval;
+
+    kbinput = get_ignored_kbinput(win);
+    retval = get_accepted_kbinput(win, kbinput, meta, rebind_delete);
+
+    return retval;
+}
+
+/* Read in a string of input characters (e. g. an escape sequence)
+ * verbatim, and return the length of the string in kbinput_len.  Assume
+ * nodelay(win) is FALSE. */
+char *get_verbatim_kbinput(WINDOW *win, int *kbinput_len)
+{
+    char *verbatim_kbinput;
+    int kbinput = wgetch(win);
+
+    verbatim_kbinput = charalloc(1);
+    verbatim_kbinput[0] = kbinput;
+    *kbinput_len = 1;
+
+    if (kbinput >= '0' && kbinput <= '2')
+	/* Entering a three-digit decimal ASCII code from 000-255 in
+	 * verbatim mode will produce the corresponding ASCII
+	 * character. */
+	verbatim_kbinput[0] = (char)get_ascii_kbinput(win, kbinput);
+    else {
+	nodelay(win, TRUE);
+	while ((kbinput = wgetch(win)) != ERR) {
+	    *kbinput_len++;
+	    verbatim_kbinput = charealloc(verbatim_kbinput, *kbinput_len);
+	    verbatim_kbinput[*kbinput_len - 1] = (char)kbinput;
+	}
+	nodelay(win, FALSE);
+    }
+
+#ifdef DEBUG
+    fprintf(stderr, "get_verbatim_kbinput(): verbatim_kbinput = %s\n", verbatim_kbinput);
+#endif
+    return verbatim_kbinput;
+}
+
+/* Swallow input characters that should be quietly ignored, and return
+ * the first input character that shouldn't be. */
+int get_ignored_kbinput(WINDOW *win)
+{
+    int kbinput;
+
+    while (1) {
+	kbinput = wgetch(win);
+	switch (kbinput) {
+	    case ERR:
+	    case KEY_RESIZE:
+#ifdef PDCURSES
+	    case KEY_SHIFT_L:
+	    case KEY_SHIFT_R:
+	    case KEY_CONTROL_L:
+	    case KEY_CONTROL_R:
+	    case KEY_ALT_L:
+	    case KEY_ALT_R:
+#endif
+#ifdef DEBUG
+		fprintf(stderr, "get_ignored_kbinput(): kbinput = %d\n", kbinput);
+#endif
+		break;
+	    default:
+		return kbinput;
+	}
+    }
+}
+
+/* Translate acceptable ASCII and extended (keypad) input.  Set meta to
+ * 1 if we get a Meta sequence.  Assume nodelay(win) is FALSE. */
+int get_accepted_kbinput(WINDOW *win, int kbinput, int *meta,
+	int rebind_delete)
+{
+    *meta = 0;
+
+    switch (kbinput) {
+	case NANO_CONTROL_3: /* Escape */
+	    switch (kbinput = wgetch(win)) {
+		case NANO_CONTROL_3: /* Escape */
+		    kbinput = wgetch(win);
+		    /* Esc Esc [three-digit decimal ASCII code from
+		     * 000-255] == [corresponding ASCII character];
+		       Esc Esc 2 obviously can't be Ctrl-2 here */
+		    if (kbinput >= '0' && kbinput <= '2')
+			kbinput = get_ascii_kbinput(win, kbinput);
+		    /* Esc Esc [character] == Ctrl-[character];
+		     * Ctrl-Space (Ctrl-2) == Ctrl-@ == Ctrl-` */
+		    else if (kbinput == ' ' || kbinput == '@' || kbinput == '`')
+			kbinput = NANO_CONTROL_SPACE;
+		    /* Ctrl-3 (Ctrl-[, Esc) to Ctrl-7 (Ctrl-_) */
+		    else if (kbinput >= '3' && kbinput <= '7')
+			kbinput -= 24;
+		    /* Ctrl-8 (Ctrl-?) */
+		    else if (kbinput == '8' || kbinput == '?')
+			kbinput = NANO_CONTROL_8;
+		    /* Ctrl-A to Ctrl-_ */
+		    else if (kbinput >= 'A' && kbinput <= '_')
+			kbinput -= 64;
+		    /* Ctrl-A to Ctrl-Z */
+		    else if (kbinput >= 'a' && kbinput <= 'z')
+			kbinput -= 96;
+		    break;
+		/* Terminal breakage, part 1: We shouldn't get an escape
+		 * sequence here for terminals that support Delete, but
+		 * we do sometimes on FreeBSD.  Thank you, Wouter van
+		 * Hemel. */
+		case '[':
+		    nodelay(win, TRUE);
+		    kbinput = wgetch(win);
+		    switch (kbinput) {
+			case ERR:
+			    kbinput = '[';
+			    *meta = 1;
+			    break;
+			default:
+			    kbinput = get_escape_seq_kbinput(win, kbinput);
+			    break;
+		    }
+		    nodelay(win, FALSE);
+		    break;
+		case '`':
+		    /* Esc Space == Esc ` */
+		    kbinput = ' ';
+		    break;
+		default:
+		    /* Esc [character] == Meta-[character] */
+		    if (isupper(kbinput))
+			kbinput = tolower(kbinput);
+		    *meta = 1;
+		    break;
+	    }
+	    break;
+	case KEY_DOWN:
+	    kbinput = NANO_DOWN_KEY;
+	    break;
+	case KEY_UP:
+	    kbinput = NANO_UP_KEY;
+	    break;
+	case KEY_LEFT:
+	    kbinput = NANO_BACK_KEY;
+	    break;
+	case KEY_RIGHT:
+	    kbinput = NANO_FORWARD_KEY;
+	    break;
+	case KEY_HOME:
+	    kbinput = NANO_HOME_KEY;
+	    break;
+	case KEY_BACKSPACE:
+	    kbinput = NANO_BACKSPACE_KEY;
+	    break;
+	case KEY_DC:
+	    /* Terminal breakage, part 2: We should only get KEY_DC when
+	     * hitting Delete, but we get it when hitting Backspace
+	     * sometimes on FreeBSD.  Thank you, Lee Nelson. */
+	    kbinput = (rebind_delete) ? NANO_BACKSPACE_KEY : NANO_DELETE_KEY;
+	    break;
+	case KEY_IC:
+	    kbinput = NANO_INSERTFILE_KEY;
+	    break;
+	case KEY_NPAGE:
+	    kbinput = NANO_NEXTPAGE_KEY;
+	    break;
+	case KEY_PPAGE:
+	    kbinput = NANO_PREVPAGE_KEY;
+	    break;
+	case KEY_ENTER:
+	    kbinput = NANO_ENTER_KEY;
+	    break;
+	case KEY_END:
+	    kbinput = NANO_END_KEY;
+	    break;
+	case KEY_SUSPEND:
+	    kbinput = NANO_SUSPEND_KEY;
+	    break;
+	default:
+	    break;
+    }
+#ifdef DEBUG
+    fprintf(stderr, "get_accepted_kbinput(): kbinput = %d, meta = %d\n", kbinput, *meta);
+#endif
+    return kbinput;
+}
+
+/* Translate a three-digit decimal ASCII code from 000-255 into the
+ * corresponding ASCII character. */
+int get_ascii_kbinput(WINDOW *win, int kbinput)
+{
+    int retval;
+
+    switch (kbinput) {
+	case '0':
+	case '1':
+	case '2':
+	    retval = (kbinput - 48) * 100;
+	    break;
+	default:
+	    return kbinput;
+    }
+
+    kbinput = wgetch(win);
+    switch (kbinput) {
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	    retval += (kbinput - 48) * 10;
+	    break;
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	    if (retval < 200) {
+		retval += (kbinput - 48) * 10;
+		break;
+	    }
+	default:
+	    return kbinput;
+    }
+
+    kbinput = wgetch(win);
+    switch (kbinput) {
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	    retval += kbinput - 48;
+	    break;
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	    if (retval < 250) {
+		retval += kbinput - 48;
+		break;
+	    }
+	default:
+	    return kbinput;
+    }
+
+#ifdef DEBUG
+    fprintf(stderr, "get_ascii_kbinput(): kbinput = %d\n", kbinput);
+#endif
+    return retval;
+}
+
+/* Translate common escape sequences for some keys.  These are generated
+ * when the terminal doesn't support those keys.  Assume nodelay(win) is
+ * TRUE. */
+int get_escape_seq_kbinput(WINDOW *win, int kbinput)
+{
+    switch (kbinput) {
+	case '3':
+	    /* Esc [ 3 ~ == kdch1 on many terminals. */
+	    kbinput = get_skip_tilde_kbinput(win, kbinput, NANO_DELETE_KEY);
+	    break;
+	default:
+	    break;
+    }
+    return kbinput;
+}
+
+/* If there is no next character, return the passed-in error value.  If
+ * the next character's a tilde, eat it and return the passed-in
+ * return value.  Otherwise, return the next character.  Assume
+ * nodelay(win) is TRUE. */
+int get_skip_tilde_kbinput(WINDOW *win, int errval, int retval)
+{
+    int kbinput = wgetch(win);
+    switch (kbinput) {
+	case ERR:
+	    return errval;
+	case '~':
+	    return retval;
+	default:
+	    return kbinput;
+    }
+}
+
 int do_first_line(void)
 {
     current = fileage;
@@ -197,6 +486,7 @@ int nanogetstr(int allowtabs, const char *buf, const char *def,
 		)
 {
     int kbinput;
+    int meta;
     static int x = -1;
 	/* the cursor position in 'answer' */
     int xend;
@@ -247,7 +537,7 @@ int nanogetstr(int allowtabs, const char *buf, const char *def,
        input */
     wrefresh(edit);
 
-    while ((kbinput = wgetch(bottomwin)) != 13) {
+    while ((kbinput = get_kbinput(bottomwin, &meta, ISSET(REBIND_DELETE))) != NANO_ENTER_KEY) {
 	for (t = s; t != NULL; t = t->next) {
 #ifdef DEBUG
 	    fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput, kbinput);
@@ -273,64 +563,45 @@ int nanogetstr(int allowtabs, const char *buf, const char *def,
 	    tabbed = 0;
 
 	switch (kbinput) {
-
-	    /* Stuff we want to equate with <enter>, ASCII 13 */
-	case 343:
-	    ungetch(13);	/* Enter on iris-ansi $TERM, sometimes */
-	    break;
-	    /* Stuff we want to ignore */
-#ifdef PDCURSES
-	case 541:
-	case 542:
-	case 543:		/* Right ctrl again */
-	case 544:
-	case 545:		/* Right alt again */
-	    break;
-#endif
 #if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
 	case KEY_MOUSE:
 	    do_mouse();
 	    break;
 #endif
 	case NANO_HOME_KEY:
-	case KEY_HOME:
 	    x = 0;
 	    break;
 	case NANO_END_KEY:
-	case KEY_END:
 	    x = xend;
 	    break;
-	case KEY_RIGHT:
 	case NANO_FORWARD_KEY:
 	    if (x < xend)
 		x++;
 	    break;
-	case NANO_CONTROL_D:
+	case NANO_DELETE_KEY:
 	    if (x < xend) {
 		memmove(answer + x, answer + x + 1, xend - x);
 		xend--;
 	    }
 	    break;
-	case NANO_CONTROL_K:
-	case NANO_CONTROL_U:
+	case NANO_CUT_KEY:
+	case NANO_UNCUT_KEY:
 	    null_at(&answer, 0);
 	    xend = 0;
 	    x = 0;
 	    break;
-	case KEY_BACKSPACE:
-	case 127:
-	case NANO_CONTROL_H:
+	case NANO_BACKSPACE_KEY:
 	    if (x > 0) {
 		memmove(answer + x - 1, answer + x, xend - x + 1);
 		x--;
 		xend--;
 	    }
 	    break;
-	case NANO_CONTROL_I:
+	case NANO_TAB_KEY:
 #ifndef NANO_SMALL
 	    /* tab history completion */
 	    if (history_list != NULL) {
-		if (!complete || last_kbinput != NANO_CONTROL_I) {
+		if (!complete || last_kbinput != NANO_TAB_KEY) {
 		    history_list->current = (historytype *)history_list;
 		    history_list->len = strlen(answer);
 		}
@@ -358,15 +629,12 @@ int nanogetstr(int allowtabs, const char *buf, const char *def,
 	    }
 #endif
 	    break;
-	case KEY_LEFT:
 	case NANO_BACK_KEY:
 	    if (x > 0)
 		x--;
 	    break;
-	case KEY_UP:
 	case NANO_UP_KEY:
 #ifndef NANO_SMALL
-  do_upkey:
 	    if (history_list != NULL) {
 
 		/* if currentbuf is NULL, or if use_cb is 1, currentbuf
@@ -407,10 +675,8 @@ int nanogetstr(int allowtabs, const char *buf, const char *def,
 	    }
 #endif
 	    break;
-	case KEY_DOWN:
 	case NANO_DOWN_KEY:
 #ifndef NANO_SMALL
-  do_downkey:
 	    if (history_list != NULL) {
 
 		/* get newer search from the history list and save it 
@@ -452,71 +718,6 @@ int nanogetstr(int allowtabs, const char *buf, const char *def,
 	    }
 #endif
 	    break;
-	case KEY_DC:
-	    goto do_deletekey;
-	case 27:
-	    switch (kbinput = wgetch(edit)) {
-	    case 'O':
-		switch (kbinput = wgetch(edit)) {
-		case 'F':
-		    x = xend;
-		    break;
-		case 'H':
-		    x = 0;
-		    break;
-		}
-		break;
-	    case '[':
-		switch (kbinput = wgetch(edit)) {
-		case 'A':
-#ifndef NANO_SMALL
-		    goto do_upkey;
-#else
-		    break;
-#endif
-		case 'B':
-#ifndef NANO_SMALL
-		    goto do_downkey;
-#else
-		    break;
-#endif
-		case 'C':
-		    if (x < xend)
-			x++;
-		    break;
-		case 'D':
-		    if (x > 0)
-			x--;
-		    break;
-		case 'F':
-		    x = xend;
-		    break;
-		case 'H':
-		    x = 0;
-		    break;
-		case '1':
-		case '7':
-		    x = 0;
-		    goto skip_tilde;
-		case '3':
-		  do_deletekey:
-		    if (x < xend) {
-			memmove(answer + x, answer + x + 1, xend - x);
-			xend--;
-		    }
-		    goto skip_tilde;
-		case '4':
-		case '8':
-		    x = xend;
-		  skip_tilde:
-		    nodelay(edit, TRUE);
-		    kbinput = wgetch(edit);
-		    if (kbinput == '~' || kbinput == ERR)
-			kbinput = -1;
-		    nodelay(edit, FALSE);
-		    break;
-		}
-		break;
 	    default:
 
 		for (t = s; t != NULL; t = t->next) {
@@ -524,17 +725,14 @@ int nanogetstr(int allowtabs, const char *buf, const char *def,
 		    fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput,
 			    kbinput);
 #endif
-		    if (kbinput == t->val || kbinput == t->val - 32)
+		    if (meta == 1 && (kbinput == t->val || kbinput == t->val - 32))
 			/* We hit an Alt key.  Do like above.  We don't
 			   just ungetch() the letter and let it get
 			   caught above cause that screws the
 			   keypad... */
 			return t->val;
 		}
-	    }
-	    break;
 
-	default:
 	    if (kbinput < 32)
 		break;
 	    answer = charealloc(answer, xend + 2);
@@ -1546,7 +1744,7 @@ int line_len(const char *ptr)
 int do_help(void)
 {
 #ifndef DISABLE_HELP
-    int i, page = 0, kbinput = 0, no_more = 0, kp;
+    int i, page = 0, kbinput = -1, meta, no_more = 0;
     int no_help_flag = 0;
     const shortcut *oldshortcut;
 
@@ -1563,8 +1761,6 @@ int do_help(void)
 
     currshortcut = help_list;
 
-    kp = keypad_on(edit, 1);
-
     if (ISSET(NO_HELP)) {
 
 	/* Well, if we're going to do this, we should at least
@@ -1586,32 +1782,8 @@ int do_help(void)
 	    do_mouse();
 	    break;
 #endif
-	case 27:
-	    kbinput = wgetch(edit);
-	    switch(kbinput) {
-	    case '[':
-		kbinput = wgetch(edit);
-		switch(kbinput) {
-		    case '5':	/* Alt-[-5 = Page Up */
-			wgetch(edit);
-			goto do_pageupkey;
-		    case 'V':	/* Alt-[-V = Page Up in Hurd Console */
-		    case 'I':	/* Alt-[-I = Page Up - FreeBSD Console */
-			goto do_pageupkey;
-		    case '6':	/* Alt-[-6 = Page Down */
-			wgetch(edit);
-			goto do_pagedownkey;
-		    case 'U':	/* Alt-[-U = Page Down in Hurd Console */
-		    case 'G':	/* Alt-[-G = Page Down - FreeBSD Console */
-			goto do_pagedownkey;
-		}
-		break;
-	    }
-	    break;
 	case NANO_NEXTPAGE_KEY:
 	case NANO_NEXTPAGE_FKEY:
-	case KEY_NPAGE:
-	  do_pagedownkey:
 	    if (!no_more) {
 		blank_edit();
 		page++;
@@ -1619,8 +1791,6 @@ int do_help(void)
 	    break;
 	case NANO_PREVPAGE_KEY:
 	case NANO_PREVPAGE_FKEY:
-	case KEY_PPAGE:
-	  do_pageupkey:
 	    if (page > 0) {
 		no_more = 0;
 		blank_edit();
@@ -1649,8 +1819,7 @@ int do_help(void)
 	    no_more = 1;
 	    continue;
 	}
-    } while ((kbinput = wgetch(edit)) != NANO_EXIT_KEY &&
-	     kbinput != NANO_EXIT_FKEY);
+    } while ((kbinput = get_kbinput(edit, &meta, ISSET(REBIND_DELETE))) != NANO_EXIT_KEY && kbinput != NANO_EXIT_FKEY);
 
     currshortcut = oldshortcut;
 
@@ -1664,7 +1833,6 @@ int do_help(void)
 
     curs_set(1);
     edit_refresh();
-    kp = keypad_on(edit, kp);
 
     /* The help_init() at the beginning allocated help_text, which has
        now been written to screen. */
@@ -1678,19 +1846,6 @@ int do_help(void)
     return 1;
 }
 
-int keypad_on(WINDOW *win, int newval)
-{
-/* This is taken right from aumix.  Don't sue me. */
-#ifdef HAVE_USEKEYPAD
-    int old = win->_use_keypad;
-    keypad(win, newval);
-    return old;
-#else
-    keypad(win, newval);
-    return 1;
-#endif /* HAVE_USEKEYPAD */
-}
-
 /* Highlight the current word being replaced or spell checked. */
 void do_replace_highlight(int highlight_flag, const char *word)
 {