[erlang-questions] Reading (and ignoring) escape-sequences

Richard O'Keefe ok@REDACTED
Wed Mar 24 23:22:42 CET 2010


On Mar 25, 2010, at 12:11 AM, Mazen Harake wrote:

> I think you misunderstood a little of what my problem was; let me  
> try to describe the problem in another way.
>
> Take the following assumptions:
>
> 1) You have a menu in the terminal, this menu "pops up" prompting  
> for an optional selection
> 2) You can perform one of the following two actions:
>    a) Exit: Press Esc (\027) to exit the menu and don't make a  
> selection
>    b) Move: Press UpArrow (\027[A) or DownArrow (\027B) to move  
> between selections
> 3) The program reads character by character

Patient:  It hurts when I do <this>.
Doctor:   Don't do <that>.

This is an old MS-DOS convention, and MS-DOS programs that did it
used keycodes, not characters.

If you want to do that sort of thing in the terminal, use ncurses,
or choose some other character or key for "exit".  Full stop,
delete, or for that matter, use left arrow (I want this menu LEFT).

> In order to distinguish between action a and b you have to be able  
> to (very quickly) peek at the next character in buffer to know if  
> there is a "[" after the "\e".

I think we all understand the problem:  trying to retrofit an
MS-DOS keycode-based design onto an ECMA/ANSI terminal interface
which was never intended to be used that way.

> If there isn't then you _assume_ that the user pressed Esc only.  
> This is because it is assumed that a user can not press another key  
> fast enough.

However, on machines where Cmd-V pastes whatever is in the clipboard,
the user can *command* the (virtual) pressing of (virtual) keys at
the speed of electricity.  With all GUI desktop operating systems these
days having some such facility, there is now *NO* reliable way to tell
a "manually" typed ESC from an ESC that came from a keypress.  Indeed,
using the Terminal application on a Mac, I can tell it to make the
up arrow key send "Hello World!".  (I just did, for the fun of it.
And of course immediately changed it back.)  By looking at the byte
stream you get from a terminal emulator, there is *NO* way you can
tell what key was pressed.

> To relate this to what you wrote; Erlang does have timeouts but this  
> is not relevant because what is really needed is the ability to peek  
> into the second character without blocking for input.

No, it's relevant because waiting for the second character to turn
up or giving up after a few milliseconds gets the job done.

Hmm.  Is there anything that stops you (temporarily) configuring
the terminal emulator so that it sends ^B ^F ^N ^P for
left arrow, right arrow, down arrow, up arrow?

Or could you tell people to move down using space and up using
backspace?

> An even better solution would be if this was done at a lower level  
> so that perhaps (like ncurses) in erlang you would get e.g. 40x as  
> the character for UpArrow (or whatever, it would probably be defined  
> as macros anyway).

And that's what I recommended:  doing it in ncurses and feeding Erlang
a byte stream that is NOT ambiguous.  (However, as noted above, even
ncurses is not and these days CANNOT be infallible.)
>
> I'm curious; how would you handle the mentioned scenario in your  
> editor?

As I said, by designing the command sequences so that it doesn't MATTER
whether the ESC was manually typed or not.

> Anyway it was a surprise to me that these sort of things weren't  
> handled in a better way overall

Because there _isn't_ any good way to handle it.
Possible approaches:
  (0) use a window library like Erlang's gs for menus
  (1) don't use ESC
  (2) tell the emulator to send non-ESC sequences for arrows
  (3) use UNIX ptys to put some program of your own between Erlang
      and a "terminal", using ncurses to recognise "keys" and
      forwarding an unambiguous byte stream to Erlang.

> and even if Erlang wasn't really made to handle these kind of things  
> I would hope that it would have better support in the future because  
> it is absolutely gold to be able to write tools like e.g. table view  
> and the debugger without the need for gs (or wx) without the nasty  
> scrolling all the time (e.g. like top).

You can write such tools in Erlang right now, no worries;
just don't try to use ESC and ECMA escape sequences at the same
point in your protocols.

Let's imagine a little C program that is trying to handle the
problem.

	read one character with blocking;
	if (that character was ESC) {
	   /* did the user press ESC or an arrow key? */
A:	   if (it is possible to read one character without blocking) {
	      /*it was an arrow key*/
	   } else {
	      /*it was not*/
	   }
	} else {
	   /* it was some other key */
	}

Now let's imagine a possible execution of this program.
This involves nothing strange, indeed, nothing I have not
experienced.

	the program is running.
	the user types an ESC character.
	the program reads a character.
	the operating system switches to another process.
	the user types another character.
	the operating system switches back to our program.
	the program discovers that another character is ready.

WHOOPS!  The program just mistook a manually typed ESC for the
beginning of an escape sequence.

This happened a lot more on PDP-11s than on Pentiums, but it is
still _possible_.  There really isn't ANY reliable way to tell
an ESC from an escape sequence, and you are much better off
designing your interface so that you don't *care* than trying
to fight it.


More information about the erlang-questions mailing list