Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recognizing arrow keys with stdin

is it possible to have a cross-platform way to handle backspace and arrows keys within a C or OCaml program?

Actually an OCaml solution would be appreciated but many standard unix functions are wrapped directly to corresponding API calls so there's should be no problem in porting a C solution.

What I'm going to achieve is to catch the arrow keys to override its behaviour inside the shell (by repropting last line or operations like these). I think that this thing falls before the actual program and it's not handled by code itself so I don't know if it's possible.

The program is compiled either on Linux, OS X and Windows (on cygwin) so I would like to do it for all platforms..

like image 399
Jack Avatar asked Nov 09 '10 02:11

Jack


1 Answers

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

like image 125
Niki Yoshiuchi Avatar answered Oct 23 '22 08:10

Niki Yoshiuchi