Page 1 of 3

how does vim distinguish ESC key from the escape sequence ?

Posted: Thu Jul 12, 2018 1:48 am
by lovelyshell
When we press home key, vim receives three ascii code: \e O H.

How does vim determine that the user pressed home, rather than pressed Esc O H.

One approach I thought of is: read() the stdin with a large count argument to drain it, test the return value. If larger than 1, we think it's an escape sequence generated by a function key.

However, there is a problem:
If vim ran on a remote server, and the user operated it through putty. The user wanted to insert a line above and insert a character H, so he pressed Esc O H. The three keystrokes were wrapped into three net packages and transferred to server. These packages arrived at the same time due to network congestion.
Thus, these three characters all appeared in the stdin buffer of vim at the same time, and were mistaken as an escape sequence of home.

I don't know how vim avoids such problem, and do you have a better approach?

Re: how does vim distinguish ESC key from the escape sequenc

Posted: Thu Jul 12, 2018 6:16 am
by Solar
A trip through history

You are assuming that Vim handles e.g. the network traffic of a remote session directly. It doesn't.

Have a look at the name of the client software you mentioned yourself -- putty. That's actually PuTTY. The "TTY" in there stands for teletype. Originally, you were actually accessing a computer (the kind that filled a whole room) through a teletyper. Which means you had no "screen", you interacted with the computer a line at a time.

1966 - QED, "quick editor", Butler Lampson / L. Peter Deutsch for the SDS 940. Ken Thompson ported QED to the Compatible Time-Sharing System, adding regex support, and later wrote a version for Multics in BCPL. (One of the QED regex commands added was "g/<re>/p" -- global, regular expression, print -- which would print all lines ("globally") from the current file which matched the regular expression. This would later become the stand-alone command "grep".)

1971 - ED, "editor", Dennis Ritchie (with Ken Thompson) for the PDP-7. (We just had "grep"... when you want to apply ED commands to a stream of data, there is a standalone for that as well -- "sed".)

1976 - EM, "editor for mortals", George Coulouris (if you compare today's Vim commands with the somewhat clunky syntax of sed commands, thank George for doing most of that transitional work).

1978 - EX, "editor extended", Bill Joy, for BSD

When video displays became more common, things like the VT100 were used as "user terminals", or just terminals, instead of teletypers. This allowed new things to be done.

1980 - curses library, Ken Arnold, for BSD

The curses library ("cursor optimization") allowed access to the whole screen of a video terminal, and made a new kind of application possible. (Of course, one of the first such application was "rogue", the terminal/ASCII-based adventure game...)

Bill Joy added a mode to EX that allowed the whole screen to be used for displaying text buffers; this mode was entered via the EX command ":visual", which could be abbreviated ":vi". Eventually, that mode became so popular that a shortcut was created to start EX directly in visual mode -- vi was born.

1987 - Stevie, a vi-clone for Atari ST, ported to Unix, OS/2 and Amiga by Tony Andrews.

1991 - Vim, Bram Moolenaar, for Amiga, adding many vi features that were missing from Stevie, and later much more. Eventually ported basically everywhere.

---

When you today start PuTTY, gnome-terminal, xterm or whatever, what you are actually using is a terminal emulator (yes, the "terminal" software we use in 2018 re-enacts a 1978 video terminal as an extension of a 1968 teletype).

Vim does not care whether your session is local or remote. Actually, unless you are actually using the console on a Unix / Linux / BSD machine, you are going through X11, at which point your session is remote for all practical purposes as far as Vim is concerned (the X11 server is providing your graphic card's services to X11 clients, which might be local or remote). All the network traffic and keystroke handling is done by lower layers, long before Vim "sees" them.

So now you can refine your question, and ask how those lower layers distinguish between "Home" and "<Esc> O H", to which I can only say...


...I have no idea. :lol: 8)

Re: how does vim distinguish ESC key from the escape sequenc

Posted: Thu Jul 12, 2018 7:34 am
by davidv1992
I dont agree that the question is how those lower layers use to distinguish between the home and esc keys. From testing what non-canonical mode hands as input to programs, the raw bytes provided to a program using it really are 27 for esc, and the sequence 27 91 72 for the home key.

These need to be distinguished then by vim, either directly or through one of the libraries it uses (which would then most likely be ncurses), but how it does that is a very good question, as the OPs assertion that you cannot use whether they arrive at the same time or not is (to the best of my knowledge) correct.

Wikipedia (cited from this stackoverflow question) seems to suggest that the timing approach (either via termcontrol variables or directly in userland) is actually the method commonly used to do this, but I have to admit this seems somewhat fragile to me, especially once things like network delay noise are added to the timing of keystrokes arriving.

Re: how does vim distinguish ESC key from the escape sequenc

Posted: Thu Jul 12, 2018 7:52 am
by Schol-R-LEA
davidv1992 wrote:I dont agree that the question is how those lower layers use to distinguish between the home and esc keys. From testing what non-canonical mode hands as input to programs, the raw bytes provided to a program using it really are 27 for esc, and the sequence 27 91 72 for the home key.

These need to be distinguished then by vim, either directly or through one of the libraries it uses (which would then most likely be ncurses), but how it does that is a very good question, as the OPs assertion that you cannot use whether they arrive at the same time or not is (to the best of my knowledge) correct.
Actually, it is very possible that they arrived in the same packet in both instances, though I suppose it depends on just how the instance of ncurses used by PuTTY handles the presence of an ESC keystroke. I don't know for certain, but I am guessing that, since ESC is usually used for key combos, the library code would by default collect at least three or four more before passing it to the application - which in this case is PuTTY, not vim.

This important, because the client's instance of the ncurses library (where it is being typed in) is not the same as the server's instance of ncurses (which is what vim is using to read the input from the SSH server). AFAIK, vim itself isn't network-aware; the instance of vim running on the remote system isn't going to know or care where the input stream is coming from (though it presumably assumes that it is unbuffered). The vim instance on the server is using the ncurses library functions on the server, but I don't think that ncurses is network-aware, either - it is just expecting a raw character stream from somewhere.

Just what the implications of this are, aren't clear to me.

@Solar: I have two things to take (highly pedantic) note of, less as corrections to you (as you probably know both of these things already) than as a teachable moment for others here.

First, the base of that list probably ought to be TECO, even though it was not in the direct lineage of ED (especially in terms of the command language). Both Lampson and Deutsch would have been familiar with TECO, both using it and modifying the code for it (certainly Deutsch was, given that he virtually grew up in the Project MAC computer labs), so it would have at least influenced the design of QED even if they specifically chose to avoid the particular command language it used (and not without good reason - even EMACS fans like myself agree that TECO's command system is insane, which is probably why Stallman created the original Editor Macros library in the first place).

Second, it is worth mentioning that remote use was the primary intended use model for X Window System - originally, the local use was a kludge to allow you to test and debug applications more readily. X was meant to be a remote protocol, and it was expected that it would be used on top of some other window manager. It wasn't even really a graphics system in and of itself; it was meant as a communication protocol running between graphics managers. The original version ran on an experimental OS called V, and was initially a more portable version of an earlier protocol called W, so that it could be used by platforms running operating systems other than V.

Somehow, when it got moved over to Unix about a year into its development, things went a little off course. The initial port in 1985 was for the DECStation series of 'diskless workstations' (try to guess what people actually called them :-) ) running the Ultrix variant of Unix, meaning that the workstation was basically running almost nothing else locally, including a different window manager. This quickly led some of the other workstation developers to realize that all that hard work of making a window manager was already done for them, so why have another one when X can do double duty? The fact that X wasn't] a window manager, or even graphics manager (it was just a communication protocol) didn't seem to register with them, which set us on the course that led to the current situation in the Unix/Linux/BSD world.

Anyway, now you know, or at least, now you know what my understanding of the matter is (I can't guarantee that I have all of this right in every particular). Comments and corrections welcome.

Re: how does vim distinguish ESC key from the escape sequenc

Posted: Thu Jul 12, 2018 9:09 am
by lovelyshell
Actually, it is very possible that they arrived in the same packet in both instances,
I also think these key strokes will be probably wrapped together into one net package, because I heard that putty doesn't send out a net package immediately he received a keystroke. To improve transmission efficiency, he waits for several milliseconds to collect more keystrokes.

I don't know whether it's true.

Re: how does vim distinguish ESC key from the escape sequenc

Posted: Thu Jul 12, 2018 10:37 am
by iansjack
Isn't the sequence <Esc> followed by a key released code as opposed to <Esc> O H followed by a key released code? Or have I misunderstood the question.

Re: how does vim distinguish ESC key from the escape sequenc

Posted: Thu Jul 12, 2018 10:44 am
by simeonz
I consulted with these SO answers:
How can I know that the user hit the ESC key in a console with ncurses (Linux)?
How to distinguish between Escape and Escape Sequence
and these man pages:
wgetch
keypad

Essentially, the curses family of libraries apparently use the wait mechanism to which you alluded earlier. The library (whichever implementation) has a "keypad" option, which enables automatic translation of the terminal-specific escape codes to the corresponding function keys. By default it is disabled, but can be enabled if the application so desires. The translation normally works by a timeout, probably in the manner in which the 2nd SO answer I linked to demonstrated. However, if notimeout is also set, the library apparently assumes that the input is received from an "intelligent" emulation source, which doesn't ever block in the middle of an escape sequence. If so, any character sequence is interpreted immediately, either as function key or raw input, without causing additional typing delay if the escape code happens to be the escape key.

Regarding putty, I don't know how tightly ssh is wrapped around the terminal emulation concept, but assuming that it has special notions of code sequences that must be presented as one character block, it can arrange to supply them as one non-blocking read. In particular, it can wait until a proper amount of TCP data is received before delivering it to the pseudo-terminal on the other end. (Edit: Meaning, only when the protocol is aware that this was not originally an actual escape key.) The point is, the ssh protocol may be aware of this requirement. If ssh did have an intelligent way to group escape sequences in one non-blocking read, then the notimeout option would be useful to avoid typing delays following the ESC key. Assuming, of course, that vim detects ssh or the terminal type, or something. (Edit: This is flaky to think of it. The ssh server cannot know whether the application uses notimeout, because this is a library issue and not a terminal configuration. The ssh server has no way of knowing whether it can bypass most of the delay when passing the escape code alone - i.e. the escape key itself.)

Now, that being said, vim's source code for unix-like here doesn't make any references to curses functions that I can see. Which suggested to me that it may not actually be using a curses library. The only thing I found to confirm this was a random answer here. Either way, the library does not affect the mechanism of terminal emulation, so probably it doesn't matter.

Re: how does vim distinguish ESC key from the escape sequenc

Posted: Thu Jul 12, 2018 10:54 am
by Schol-R-LEA
iansjack wrote:Isn't the sequence <Esc> followed by a key released code as opposed to <Esc> O H followed by a key released code? Or have I misunderstood the question.
The main issue here is that it is over an SSH connection - obviously, a PC-specific keyboard code such as key released isn't going to be transmitted, when the receiving server may not be able to interpret it meaningfully. I don't know enough about either SSH or curses to say if some equivalent key-up code is sent, or some other code indicating that a given set of signals is a key combination involving an escape rather than individual key presses represented by an escape sequence, but I doubt it.

EDIT: From Simeonz's post, I gather curses does indeed 'cook' the escape sequences in some way. Am I interpreting what you said correctly, simeonz?

Re: how does vim distinguish ESC key from the escape sequenc

Posted: Thu Jul 12, 2018 11:19 am
by simeonz
Schol-R-LEA wrote:EDIT: From Simeonz's post, I gather curses does indeed 'cook' the escape sequences in some way. Am I interpreting what you said correctly, simeonz?
Basically, input blocking coming from the terminal is used as an out of band information of sorts, providing separator to differentiate escape sequences from escape key containing sequences. In the most trivial case, the terminal emulation code will cook the function keys using time delay as a "signal" when necessary and the ncurses library will uncook it by waiting with a timeout. So, yes. Assuming that you use the ncurses library, it will do some uncooking (or cooking, depending on how you want to look at it.)

When you think about the terminal emulation on the ssh client side, the ssh client code, the tcp connection, the ssh server code, the pseudo-terminal connection from the ssh server to the terminal client (vim in this case), and the code translating escape sequences in the terminal client (vim code or ncurses or something), you begin to question the sanity of the entire approach, whose entire aim is to let you press some ESC key.

Re: how does vim distinguish ESC key from the escape sequenc

Posted: Thu Jul 12, 2018 2:06 pm
by Schol-R-LEA
I suppose the questions then become a) does the server you are connecting to have an X client running on it, and is your local system running an X server to connect to it, b) can you connect to said client using X11 forwarding from PuTTY (you can find the option in the PuTTY client under Connection-> SSH -> X11), and does the connection remain stable, c) is the network connection and the general performance of the two systems up to running vim under X remotely instead of as a terminal app, and finally, d) would you rather use it that way rather than sticking to the ncurses instance?

Re: how does vim distinguish ESC key from the escape sequenc

Posted: Thu Jul 12, 2018 3:29 pm
by simeonz
Schol-R-LEA wrote:I suppose the questions then become a) does the server you are connecting to have an X client running on it, and is your local system running an X server to connect to it, b) can you connect to said client using X11 forwarding from PuTTY (you can find the option in the PuTTY client under Connection-> SSH -> X11), and does the connection remain stable, c) is the network connection and the general performance of the two systems up to running vim under X remotely instead of as a terminal app, and finally, d) would you rather use it that way rather than sticking to the ncurses instance?
:) In this case, you would be relying on the x window protocol to deliver the escape keypress losslessly to the x client (xterm), which then uses the terminal emulation timeout shenanigans to communicate that to vim. In the previous case, you would have to rely on the ssh protocol to deliver the escape key losslessly to the ssh server and then have the ssh server code communicate it to the terminal client (vim) using the timeout tricks. I am willing to speculate that the x protocol would be better tailored for delivering functional keypresses then ssh, but I could be wrong.

Re: how does vim distinguish ESC key from the escape sequenc

Posted: Thu Jul 12, 2018 6:34 pm
by lovelyshell
Isn't the sequence <Esc> followed by a key released code as opposed to <Esc> O H followed by a key released code?
I am afraid not.
Common unix programs can only use read(0, buf, len) to access keyboard, and get common ascii code for common key, get escape sequence for function key.
It seems that no console/terminal( namely that 0 above) passes break-code directly to the reader.
I remember in linux kernel, console implementation is part of the read()/write() implementation. It's quite low level.

Re: how does vim distinguish ESC key from the escape sequenc

Posted: Thu Jul 12, 2018 7:04 pm
by lovelyshell
Thanks every one, I am still reading your replies slowly.
In the same time, I want to post two link I just found:
https://www.chiark.greenend.org.uk/~sgt ... delay.html
https://learningnetwork.cisco.com/thread/102016

They were talking about the transmit rate setting of putty. It seems that they wanted to reduce the transmit rate to sever( not powerful computer, but weak CISO device with small receive buffer) which can not process data that fast.
As they said, one approach to reduce transmit rate is key delay , namely wait a moment before sending a package.

Putty on my Ubuntu implements key-delay by providing a switch: enable/disable Nagles Algorithm.
And another tool TeraTerm seems more flexible:
https://learningnetwork.cisco.com/servl ... +paste.JPG

Re: how does vim distinguish ESC key from the escape sequenc

Posted: Fri Jul 13, 2018 12:43 am
by Solar
Schol-R-LEA wrote:...the base of that list probably ought to be TECO, even though it was not in the direct lineage of ED (especially in terms of the command language). Both Lampson and Deutsch would have been familiar with TECO, both using it and modifying the code for it...
I know the discussion has moved past this point now, but I explicitly limited my history lesson to direct lineage, not influences -- that would quickly have gotten out of hand. ;-)

Re: how does vim distinguish ESC key from the escape sequenc

Posted: Fri Jul 13, 2018 12:56 am
by iansjack
But couldn't read() return 3 bytes for the <Home> key and only one for the <Esc> key?