Pardus has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to hack my own readline module ( and yes I am aware there are perfectly good readline modules on cpan allready ).

I use Term::ReadKey to get raw keyboard input and then simply lookup the ord value of a key in a hash table to decide which action to take. But some keys, like the arrows keys, do not result in a single char value when pressed, but output an escape sequence (I believe the keyboard hardware is doing this). All these sequences start with an "\e" but unfortunately this char is the same as outputted when one presses the 'esc' key. And I want to be able to bind an action to the 'esc' key, independent of any escape sequence.

My current sollution is to have a time-out of a few milli seconds after reading the 'esc' key to check whether there are keys following closely, and if there are rendering it as an escape sequence. This basicly works but causes a nasty bug when for instance one keeps pressed down an arrow key. Also it might fail when the typing speed is non-typical, like for instance in a remote terminal.

I realize this to be a design flaw but I can't think up any correct sollution. Does anyone have an idea how to solve this kind of problems ?
--
Jaap Karssenberg || Pardus (Larus)? <pardus@cpan.org>
>>>> Zoidberg: So many memories, so many strange fluids gushing out of patients' bodies.... <<<<

Replies are listed 'Best First'.
Re: a ReadKey problem
by JamesNC (Chaplain) on Jan 28, 2003 at 13:50 UTC
    Which OS are you using? Behavior of the Term varies even in Win32 cmd vs command.com. (added this).. and make sure you are setting binmode... something like so:
    ReadMode 3; # stty mode binmode STDIN, ":raw"; while($key = ReadKey()){ print ord $key; }
    before you grab a key or you will get funky stuff :)
      Mostly linux, but it should be portable -- but shouldn't ReadKey do OS dependent stuff for me ?
      --
      Jaap Karssenberg || Pardus (Larus)? <pardus@cpan.org>
      >>>> Zoidberg: So many memories, so many strange fluids gushing out of patients' bodies.... <<<<

        It's not really OS dependant, actually. It depends on the terminal / terminal emulator you're using. Term::ReadKey is more low-level, and assumes you will figure out what terminal-type the user has and interpret accordingly.

        Perhaps you should look at the source of Term::Readline::Perl to see how it handles multi-char escape sequences, as it uses a similar system as you, with the hashes and all.

        bbfu
        Black flowers blossum
        Fearless on my breath

Re: a ReadKey problem
by Heidegger (Hermit) on Jan 28, 2003 at 10:45 UTC
    Do you get the whole string of the pressed key at once, like: \e\UP_ARROW_CODE? If so, you can trim the \e code and put the rest in the hash. If you get a single \e - this is your escape key, you can put it in the hash too. Can't you solve your problem with regexps?
      No I get the escape sequence as single chars, one by one. Once I've decided it is an escape sequence I read in the complete sequence (once again using time-outs) and look up this string in a hash.

      But the problem are the time-outs, the time-outs are unrelyable and I would like to get rid of them.
      --
      Jaap Karssenberg || Pardus (Larus)? <pardus@cpan.org>
      >>>> Zoidberg: So many memories, so many strange fluids gushing out of patients' bodies.... <<<<
Re: a ReadKey problem
by Anonymous Monk on Jan 28, 2003 at 12:31 UTC
    Use timeout to distinguish \e from Arrow, but use firm values after that. E.g. if Arrows are 3 chars long, read 1 char, if \e use action for \e which is read 1 char with timeout (timeout means real action for \e), if ok (and starts Arrowsequence) read last char without timeout.
Re: a ReadKey problem
by fishnuts (Acolyte) on Jan 28, 2003 at 23:02 UTC
    At least under unix (I wont even try to assume win32's behaviour), all keyboard control keys, such as cursor arrows, function keys, home/insert/del and friends, follow the escape code immediately with a '[' when dumped into the keyboard input buffer. So it would be reasonably safe to have your code immediately assume that escape was pressed by itself if the following character was NOT '['. The key sequence 'ESC','[' is highly unlikely to be used for anything other than the function/control keys.

    So, if the escape character WAS followed by '[', you can immediately jump to a keyboard control key parser, which 'listens' for a variable length sequence depending on the characters that follow.
    On a linux console, F1 through F5 are represented by '\e[[A' through '\e[[E'. F6 through F12 return '\e[[17~' through '\e[[24~', cursor keys return '\e[A' through '\e[D', and the INS/DEL/PG/etc matrix returns '\e[1~' through '\e[6~', respectively. So there are some easy-to-recognize patterns to look for.

    As someone else might have stated, the character sequences you get when someone hits a function or cursor control key are completely dependent on the OS that the keyboard is attached to. Luckily, most OSs adhere to the lowest common denominator of vt100 and/or ansi terminal emulation when passing data to the running program.

    The "raw" data coming from the keyboard are called scancodes, and they're usually exactly one byte in length, and have more correlation to the position of the key on the keyboard membrane matrix than what's on the keycap. Luckily, that's pretty standardized as well, but you wouldn't need to worry about the scancodes at all in your case.