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 */

Reply via email to