I'm trying to bind to arrow keys in C using the GNU Readline library. I've printed out all possible combinations of ASCII (0-255) key values of rl_bind_key
, but the arrow keys don't seem to be detected.
How can I bind to them?
static int readline_func(int count, int key) {
printf("key pressed\n");
return 0;
}
int i = 0;
for (; i < 255; i++) {
rl_bind_key(i, readline_func);
}
Thanks for your help!
It's not quite that simple to bind arrow keys.
First, arrow keys are not single characters; they are character sequences. The precise character sequence sent by each arrow key will depend on your terminal emulator, but if you're using Linux with an xterm-like terminal emulator, you'll probably find that the arrow keys send the sequences:
(You can find more information in the useful compendium of control sequences maintained by Thomas Dickey. Note that CSI
is the "Control Sequence Initiator" ESC[).
To bind these sequences, you'll need to use rl_bind_keyseq
, specifying a readline-style "keyseq" (see man readline
; search for keyseq
). For example, to bind right-arrow to a function, you could call:
rl_bind_keyseq("\\e[C", right_arrow_function);
The initial readline bindings include bindings for all standard keys, using a variety of different possible key-to-keyseq mappings in case the terminal emulator is using some other emulation.
You might think that using rl_bind_key
to bind the escape key (0x1B) would override that key sequence (since it starts with an escape), but that's not how readline works.
Readline binds multi-character sequences using a trie of linked keymaps, where each key in the sequence is bound to the next keymap in turn. The precise mechanism isn't important -- readline will deal with it -- but you need to know that it is not possible to bind a prefix of a bound key sequence, because the prefix will be bound to a sub-keymap and the sub-keymap binding takes precedence over any other kind of binding.
So any attempt to rebind a prefix of a bound keyseq will fail without any error indication; rl_bind_key
(or rl_bind_keyseq
) will return 0 even though the binding has no effect. Consequently, your loop over all the possible 8-bit characters would have attempted to bind ESC, and the call to rl_bind_key
would have succeeded, but the escape key would remain bound to the sub-keymap. (I personally find the lack of an error return irritating; it would be nice to get an error indication.)
When the rl_command_function
is called, by the way, the key
argument will contain the code for the last key in the sequence. (That's a result of the fact that it is the last key which actually holds the binding information, in the corresponding sub-keymap.) That's OK for arrow keys, but it is annoying for binding the large number of keys, including PageUp and PageDown, whose code sequences have the form ESC[p
~ where p
is some (possibly multidigit) number which identifies the key, but the last character in all the sequences is ~.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With