Hi, This is about a small problem with readline that has long been bugging me: when pressing an unbound key or key combination in bash and other readline programs, somewhat cryptic characters are often inserted into the command line. For example, you might get "~" for Insert, "4~" for F12, or ";5A" for Ctrl+Up. This can be particularly confusing for new users.
The reason for this issue is that readline does not parse control sequences as defined in section 5.4 of the ECMA-48 standard correctly. VT100 terminals and its numerous descendants of course use those for many keys or key combinations that don't have single-character codes. They start with the control sequence introducer (CSI), normally represented by "\e[", followed by parameter and intermediate bytes in the range from 0x20 to 0x3F, followed by a final byte in the range from 0x40 to 0x7E. Readline, at least in its default config, stops parsing these sequences after the first byte following the "\e[", leaving any remaining bytes to spill onto the command line. As far as I understand it, there's currently no way to address this in the readline config, short of explicitly binding all the CSI keycodes to nothing anyway. Well actually, a single binding seems to suffice for codes that differ only in the last character, but that doesn't help with the F-keys and the likes of Insert. Either way, it would be a rather long list of bindings, which would slow down startup and lead to an explosion in the number of keymaps allocated internally by readline. Hence the small patch below, which avoids such inefficiencies. It defines a function called 'skip-csi-seq' that skips over the parameter, intermediate, and final bytes. This is assigned to "\e[". Since bindings for longer sequences take precedence over shorter ones, CSI sequences that do have functions bound to them continue to work. Here's the result in the output of 'bind': $ bind -p | grep e\\[ "\e[D": backward-char "\e[H": beginning-of-line "\e[3~": delete-char "\e[F": end-of-line "\e[C": forward-char "\e[B": next-history "\e[A": previous-history "\e[": skip-csi-seq This is working correctly here, including when adding bindings for longer keycodes: no more odd characters being inserted when accidentally hitting the wrong key. Please consider this for inclusion into readline. Kind regards, Andy --- emacs_keymap.c 2009-01-04 19:32:32.000000000 +0000 +++ emacs_keymap.c 2009-07-19 08:23:32.796875000 +0100 @@ -417,7 +417,7 @@ { ISFUNC, rl_do_lowercase_version }, /* Meta-Z */ /* Some more punctuation. */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-[ */ /* was rl_arrow_keys */ + { ISFUNC, rl_skip_csi_seq }, /* Meta-[ */ /* was rl_arrow_keys */ { ISFUNC, rl_delete_horizontal_space }, /* Meta-\ */ { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-] */ { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-^ */ --- funmap.c 2009-01-04 19:32:33.000000000 +0000 +++ funmap.c 2009-07-19 08:25:34.906250000 +0100 @@ -123,6 +123,7 @@ { "revert-line", rl_revert_line }, { "self-insert", rl_insert }, { "set-mark", rl_set_mark }, + { "skip-csi-seq", rl_skip_csi_seq }, { "start-kbd-macro", rl_start_kbd_macro }, { "tab-insert", rl_tab_insert }, { "tilde-expand", rl_tilde_expand }, --- readline.h 2009-07-19 05:28:30.000000000 +0100 +++ readline.h 2009-07-19 08:23:38.546875000 +0100 @@ -197,6 +197,7 @@ /* Miscellaneous bindable commands. */ extern int rl_abort PARAMS((int, int)); extern int rl_tty_status PARAMS((int, int)); +extern int rl_skip_csi_seq PARAMS((int, int)); /* Bindable commands for incremental and non-incremental history searching. */ extern int rl_history_search_forward PARAMS((int, int)); --- text.c 2009-01-04 19:32:34.000000000 +0000 +++ text.c 2009-07-19 08:23:45.890625000 +0100 @@ -571,6 +571,18 @@ } int +rl_skip_csi_seq (count, c) + int count, c; +{ + RL_SETSTATE(RL_STATE_MOREINPUT); + do + c = rl_read_key (); + while (c >= 0x20 && c < 0x40); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + return 0; +} + +int rl_arrow_keys (count, c) int count, c; {