Recognizing arrow keys with stdin

I've done something pretty similar recently (although my code is Linux only). You have to set stdin to non-canonical mode in order to read arrow key presses. This should work on OS X and Linux and will probably work on Cygwin although I can't say for sure.

open Unix

let terminfo = tcgetattr stdin in
let newterminfo = {terminfo with c_icanon = false; c_vmin = 0; c_vtime = 0} in
at_exit (fun _ -> tcsetattr stdin TCSAFLUSH terminfo); (* reset stdin when you quit*)
tcsetattr stdin TCSAFLUSH newterminfo;

when canonical mode is off, you don't need to wait for a newline in order to read from stdin. c_vmin represents the minimum numbers of characters to read before returning (you probably want to be able to read a single character at a time) and c_vtime is the maximum read wait time (in 0.1s units).

You might also want to set c_echo to false so that the arrow key presses are printed to the terminal (but then you'll have to manually print everything else.

Most terminals represent arrow key presses using ANSI escape sequences. If you run cat with no arguments and start hitting the arrow keys you can see the escape sequences used. They are typically

up - "\033[A"
down - "\033[B"
left - "\033[D"
right - "\033[C"

Where '\033' is the ascii value for esc


Use ncurses to extract the sequences for the arrow key capabilities and then look for them when you read stdin. It's probably easier to use something like libedit or readline instead, and let that deal with the keyhandling.


The standard way of supporting keyboard input beyond lines of printable characters is through the ncurses library, which has an Ocaml binding. Another common possibility is the readline library (most famously used by Bash).

If all you're doing is reading input line by line, but want your users to have a decent line editor, there's no need to include any support in your program. Instead, just tell your users to use a wrapper program such as rlwrap (which is based on readline) or ledit. These wrappers do provide line edition and history, the two features you list as your requirements. I would recommend that you build input processing into your program only if you want something fancier, such as program-specific completion when the user presses Tab.