When using ksh in emacs mode you need to bind some of the "special keys" (delete, home, end, up and down) in order to make them work as intended. Example for a xterm:
bind '^XF' = end-of-line bind '^XH' = beginning-of-line But if you want to use the same key from the console or the `delete key` it becomes much more complicated. This is related to the fact that ksh binds at most 3 characters when most of the terminals uses 4 characters. So you end up with some lines in your kshrc like: bind -m '^[[3'='^X' bind '^X~'=delete-char-forward ... The funny part is that even if your binding work you end up with a '~' character printed for some keys. If you want more details you can have a look at nicm@'s explanation: http://marc.info/?l=openbsd-misc&m=125542186700477 The patch below is adapted from a Debian pdksh patch. It adds the two xterm bindings for home/end as default (they are not more than 3 chars) and a way to handle the 4-characters bindings ending with a '~'. To do the later we use a mask on the function definition to know if we should eat a '~' or not. Yeah its a hack but is there any other case where a 4-characters binding is needed ? With this patch applied I don't need any tweak on my vaio or my ibook for both X and console. Comments? Martin Index: emacs.c =================================================================== RCS file: /home/aer/cvs/src/bin/ksh/emacs.c,v retrieving revision 1.42 diff -u -p -r1.42 emacs.c --- emacs.c 2 Jun 2009 06:47:47 -0000 1.42 +++ emacs.c 22 Nov 2010 13:16:05 -0000 @@ -303,6 +303,18 @@ static struct x_defbindings const x_defb { XFUNC_next_com, 2, 'B' }, { XFUNC_mv_forw, 2, 'C' }, { XFUNC_mv_back, 2, 'D' }, + { XFUNC_mv_end, 2, 'F' }, + { XFUNC_mv_begin, 2, 'H' }, + /* These for home/end/delete/up & down keys. The mask is used + * to deal with 4-characters sequences send by some terminals. + */ + { XFUNC_mv_begin | 0x80, 2, '1' }, + { XFUNC_mv_begin | 0x80, 2, '7' }, + { XFUNC_mv_end | 0x80, 2, '4' }, + { XFUNC_mv_end | 0x80, 2, '8' }, + { XFUNC_del_char | 0x80, 2, '3' }, + { XFUNC_prev_com | 0x80, 2, '5' }, + { XFUNC_next_com | 0x80, 2, '6' }, }; int @@ -360,6 +372,13 @@ x_emacs(char *buf, size_t len) f = x_curprefix == -1 ? XFUNC_insert : x_tab[x_curprefix][c&CHARMASK]; + /* Is it a 4-characters control sequence ending with a '~'? */ + if (f & 0x80) { + f &= 0x7F; + if ((i = x_e_getc()) != '~') + x_e_ungetc(i); + } + if (macroptr && f == XFUNC_ins_string) f = XFUNC_insert; @@ -1288,14 +1307,19 @@ x_mapout(int c) static void x_print(int prefix, int key) { + int f = x_tab[prefix][key]; + if (prefix == 1) shprintf("%s", x_mapout(x_prefix1)); if (prefix == 2) shprintf("%s", x_mapout(x_prefix2)); - shprintf("%s = ", x_mapout(key)); - if (x_tab[prefix][key] != XFUNC_ins_string) - shprintf("%s\n", x_ftab[x_tab[prefix][key]].xf_name); - else + + /* Restore character '~' when printing a binding. */ + shprintf("%s%s = ", x_mapout(key), (f & 0x80) ? "~" : ""); + + if (META(f) != XFUNC_ins_string) + shprintf("%s\n", x_ftab[META(f)].xf_name); + else shprintf("'%s'\n", x_atab[prefix][key]); } @@ -1308,6 +1332,7 @@ x_bind( const char *a1, const char *a2, int prefix, key; char *sp = NULL; char *m1, *m2; + int hastilde = 0; if (x_tab == NULL) { bi_errorf("cannot bind, not a tty"); @@ -1346,6 +1371,19 @@ x_bind( const char *a1, const char *a2, else break; } + + /* Only allow 4-characters binding if they ends with a '~'. */ + if (strnlen(m2, 4) == 4) { + if (m2[3] == '~' && m2[4] == '\0') { + hastilde = 1; + } else { + bi_errorf("key sequence too long"); + afree(m2, ATEMP); + + return (1); + } + } + afree(m2, ATEMP); if (a2 == NULL) { @@ -1377,7 +1415,7 @@ x_bind( const char *a1, const char *a2, if (x_tab[prefix][key] == XFUNC_ins_string && x_atab[prefix][key]) afree((void *)x_atab[prefix][key], AEDIT); - x_tab[prefix][key] = f; + x_tab[prefix][key] = f | (hastilde ? 0x80 : 0); x_atab[prefix][key] = sp; /* Track what the user has bound so x_emacs_keys() won't toast things */