linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: [PATCH] tty canonical mode: nicer erase behaviour
@ 2001-09-23 22:12 zefram
  2001-09-24  0:03 ` Alan Cox
  2001-09-24  1:25 ` Linus Torvalds
  0 siblings, 2 replies; 14+ messages in thread
From: zefram @ 2001-09-23 22:12 UTC (permalink / raw)
  To: linux-kernel; +Cc: torvalds

Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:
>Your xterm is not following Linux policy - this is a solved problem in
>Linuxspace. Debian bit the bullet a few years ago and did the neccessary
>deed to make all their terminal emulators and console match.

So Linux policy is to support only terminals that generate ^? for
backspace?  I thought Unix-like systems were supposed to be usable from a
great variety of text terminals.  Debian's policy works when your universe
consists solely of Linux machines configured to Debian specifications,
where your terminals are just the Linux console, xterm and screen,
but it fails to handle glass ttys, or xterms running on other systems.

I recall the reaction when someone proposed changing zsh's line editor
(ZLE) to treat backspace and delete characters differently.  Just among
the developers we have users of a wide variety of terminals, and the
proposed change would have broken the line editor for many of us.
As it is, ZLE just works, with no extra effort, on any text terminal,
and we get no complaints.

>                                                   Original telnet has
>IAC sequences to send a "delete" regardless of keymapping policies that
>are not known at end points.

Yes, it was a nice model, a pity it fell out of use.  Telnet defined a
Network Virtual Terminal, that was intended to be a common terminal type
to be emulated on all Telnet sessions, which would have eliminated the
need for the server to know what terminal type was being used on the
client end.  Of course, the NVT was a product of its time: no cursor
addressing, no display attributes, and on the input side only a single
erase key.  The closest equivalent to this model that is currently in
use is the de facto almost-universal capability to emulate a VT100.

These days telnet connections (and rsh and ssh) are used more as dumb
pipes to talk to the user's actual terminal.  We can't change that,
and the result is that Unix systems have to handle whatever terminal
type the user is using.

-zefram

^ permalink raw reply	[flat|nested] 14+ messages in thread
* Re: [PATCH] tty canonical mode: nicer erase behaviour
@ 2001-09-23 21:26 zefram
  2001-09-23 21:48 ` Alan Cox
  0 siblings, 1 reply; 14+ messages in thread
From: zefram @ 2001-09-23 21:26 UTC (permalink / raw)
  To: linux-kernel; +Cc: torvalds

Pete Zaitcev <zaitcev@redhat.com> wrote:
>Rubbish. Programs get their erase characters from termios(3).

termios(3) gets its erase character from user setting via stty(1) or
tset(1), neither of which know what character will be generated by the
terminal's main backspace key.  The current situation is that the user
has to manually arrange for the correct setting.  My personal portable
shell setup, for example, contains a script that examines $TERM and sets
the tty erase character accordingly; I've never seen this functionality
available as a standard utility anywhere.

Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:
>> One of the long-standing problems preventing Unix from being a
>> user-friendly desktop OS is its handling of erase keys.  There are
>
>Not a kernel space issue

Yes, it's a wider issue, which I wanted to present as background for
the specific change I was proposing.

>                                                      Fix problem apps. 

The Linux tty canonical mode is a problem app.  Let's fix it.

Programs that talk to the tty directly, through the tty raw mode or by
any other means, do need to be fixed separately, if they exhibit the
same problem.  The patch I proposed doesn't affect them.

>They do different things, they are different keys.

On some keyboards they are different keys, and in some programs they do
different things.  Both of these are far from universal.

Programs that want to treat backspace and delete keys differently tend
to get it right already.  Under X, for example, the two keys are both
available, and are distinctly and consistently reported to the program;
many X programs implement text editing with both forward and backward
delete.  There is no problem here.

I am concerned, for the moment, with programs that only need one kind of
erase, and that talk to a physical terminal (or a simulation thereof)
via a character-stream interface.  These programs want to invoke their
backspacing erase function whenever the user presses the backspace key,
and they don't care about any other erase-related key.  Linux's tty line
discipline, in canonical mode, is such a program.

Unfortunately, the programs of which I speak can't see what key the
user is pressing, all they can see is the character that the terminal
decides to generate from the keypress.  And terminals are inconsistent
about which character they generate for the backspace key.  Even before
we look at glass ttys, we have the Linux console (with standard setup)
generating ^? for backspace, and xterm generating ^H for backspace.
Shouldn't the tty line editor work by default on these at least?  Among
glass ttys that I've personally used, the ADM3e and KDS7362 generate ^H,
and VT220 and ND120 generate ^?.

So, *for programs that only care about backspace*, by far the best
solution is to treat both ^H and ^? as backspace.  And as I said before,
the Linux tty line discipline is such a program.  Of course, we then have
the issue that the tty is already somewhat configurable in this regard,
though unfortunately not sufficiently to implement this solution.

>Erase character policy is precisely defined by posix.

It is when the IEXTEN bit is not set.  When it is set, the tty is
permitted to accept other non-standard control characters.  For example,
Linux has a WERASE (word erase) character, which is enabled only in
IEXTEN mode.

>Debian set a policy on this a long time back and have done wonders since

This is interesting.  I wasn't aware of their policy before, but I've
examined it now, after Nadav Har'El provided a URL.

Their policy appears to cover more than one related area, in an incomplete
manner.  For programs that need both forward and backward erase, it says,
basically, "programs shall make it work".  With respect to X programs,
the policy makes perfect sense and is just a statement of common sense.
For programs that interact with a tty through a character stream and
don't want to use terminfo, it insists that terminals generate ^? for
backspace, but ignores the cases where this isn't possible.

The Debian policy is a fine example of the original problem -- it shows
the hoops that people have to jump through (non-standard configuration
of xterm) to get a partial solution.

-zefram

^ permalink raw reply	[flat|nested] 14+ messages in thread
* [PATCH] tty canonical mode: nicer erase behaviour
@ 2001-09-23  2:26 zefram
  2001-09-23 20:05 ` Alan Cox
  2001-09-24  6:45 ` Kai Henningsen
  0 siblings, 2 replies; 14+ messages in thread
From: zefram @ 2001-09-23  2:26 UTC (permalink / raw)
  To: torvalds; +Cc: linux-kernel

problem rationale
-----------------

One of the long-standing problems preventing Unix from being a
user-friendly desktop OS is its handling of erase keys.  There are
often two such keys on a keyboard (Backspace and Delete), and which one
works depends very much on context -- many text editing programs will
only accept one of the erase-related characters (^H and ^?), and the
mapping from keys to characters is terminal-dependent.  Unfortunately,
any solution to this problem has to be implemented in each program that
faces this problem.

Theoretically every program should be able to determine which erase
character to accept by looking at terminfo, but that's very cumbersome,
particularly in programs that might not otherwise need to use terminfo.
It also utterly fails in programs that don't know what kind of terminal
they are interacting with.  The more practical solution, therefore, is
that the program should accept *both* ^H and ^? as erase characters.
Look at bash's and zsh's command line editors for examples of this
approach.

One of the programs that exhibits the ^H/^? problem is the tty
line discipline in the Linux kernel.  It falls into the category of
programs that don't know (and don't care) what kind of terminal they
are interacting with.  This patch implements the accept-both-characters
solution.

patch rationale
---------------

The exact semantics changed are: in canonical mode, if IEXTEN is on
and the ERASE character is set to either ^H or ^?, then both ^H and
^? are treated as ERASE characters.  The standard single-erase-character
behaviour is followed if IEXTEN is off (which prohibits non-POSIX extended
behaviour) or if the ERASE character is neither ^H or ^? (indicating
that the user actually wants erase behaviour other than the usual use
of the erase keys).

At first glance, a more obvious way to implement handling of both erase
characters would be to have an ERASE2 character setting in the tty state,
much as there is EOL and EOL2.  However, this solution would suffer
some annoying problems.  It would rely on the user setting the two erase
characters properly in order to take advantage of it.  Even if they're
set to ^H and ^? by default, user code that tries to set ERASE based on
the terminal type (and doesn't know about ERASE2) might end up with ERASE
and ERASE2 set to the same character, breaking the solution.  Also, code
(and users) that doesn't know about ERASE2 would get surprising results
if they try to set ERASE to something other than ^H/^?.  All of this
points to it being preferable not to change the tty settings interface,
but only change the behaviour to this preferable form.

the patch
---------

This patch is based on kernel version 2.4.8.  It will also apply cleanly
up to at least kernel version 2.4.10-pre14.

--- drivers/char/n_tty.c.orig	Sat Sep 22 22:14:19 2001
+++ drivers/char/n_tty.c	Sun Sep 23 02:59:30 2001
@@ -329,9 +329,11 @@
 	}
 }
 
-static void eraser(unsigned char c, struct tty_struct *tty)
+enum kill_type { ERASE, WERASE, KILL };
+
+static void eraser(int kill_type, unsigned char cc, struct tty_struct *tty)
 {
-	enum { ERASE, WERASE, KILL } kill_type;
+	unsigned char c;
 	int head, seen_alnums;
 	unsigned long flags;
 
@@ -339,11 +341,7 @@
 		/* opost('\a', tty); */		/* what do you think? */
 		return;
 	}
-	if (c == ERASE_CHAR(tty))
-		kill_type = ERASE;
-	else if (c == WERASE_CHAR(tty))
-		kill_type = WERASE;
-	else {
+	if (kill_type == KILL) {
 		if (!L_ECHO(tty)) {
 			spin_lock_irqsave(&tty->read_lock, flags);
 			tty->read_cnt -= ((tty->read_head - tty->canon_head) &
@@ -359,13 +357,12 @@
 			tty->read_head = tty->canon_head;
 			spin_unlock_irqrestore(&tty->read_lock, flags);
 			finish_erasing(tty);
-			echo_char(KILL_CHAR(tty), tty);
+			echo_char(cc, tty);
 			/* Add a newline if ECHOK is on and ECHOKE is off. */
 			if (L_ECHOK(tty))
 				opost('\n', tty);
 			return;
 		}
-		kill_type = KILL;
 	}
 
 	seen_alnums = 0;
@@ -392,7 +389,7 @@
 				}
 				echo_char(c, tty);
 			} else if (kill_type == ERASE && !L_ECHOE(tty)) {
-				echo_char(ERASE_CHAR(tty), tty);
+				echo_char(cc, tty);
 			} else if (c == '\t') {
 				unsigned int col = tty->canon_column;
 				unsigned long tail = tty->canon_head;
@@ -590,9 +587,19 @@
 		}
 	}
 	if (tty->icanon) {
-		if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
-		    (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
-			eraser(c, tty);
+		if (c == ERASE_CHAR(tty) ||
+		    (L_IEXTEN(tty) &&
+		     (ERASE_CHAR(tty) == 8 || ERASE_CHAR(tty) == 127) &&
+		     (c == 8 || c == 127))) {
+			eraser(ERASE, c, tty);
+			return;
+		}
+		if (c == KILL_CHAR(tty)) {
+			eraser(KILL, c, tty);
+			return;
+		}
+		if (c == WERASE_CHAR(tty) && L_IEXTEN(tty)) {
+			eraser(WERASE, c, tty);
 			return;
 		}
 		if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
@@ -822,6 +829,11 @@
 			set_bit('\n', &tty->process_char_map);
 			set_bit(EOL_CHAR(tty), &tty->process_char_map);
 			if (L_IEXTEN(tty)) {
+				if (ERASE_CHAR(tty) == 8 ||
+				    ERASE_CHAR(tty) == 127) {
+					set_bit(8, &tty->process_char_map);
+					set_bit(127, &tty->process_char_map);
+				}
 				set_bit(WERASE_CHAR(tty),
 					&tty->process_char_map);
 				set_bit(LNEXT_CHAR(tty),

-zefram

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2001-09-24  9:25 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <mailman.1001266380.13783.linux-kernel2news@redhat.com>
2001-09-23 18:12 ` [PATCH] tty canonical mode: nicer erase behaviour Pete Zaitcev
2001-09-23 22:12 zefram
2001-09-24  0:03 ` Alan Cox
2001-09-24  2:17   ` zefram
2001-09-24  1:25 ` Linus Torvalds
  -- strict thread matches above, loose matches on Subject: below --
2001-09-23 21:26 zefram
2001-09-23 21:48 ` Alan Cox
2001-09-23  2:26 zefram
2001-09-23 20:05 ` Alan Cox
2001-09-23 20:41   ` Nadav Har'El
2001-09-23 21:50     ` Alan Cox
2001-09-24  9:22       ` Nadav Har'El
2001-09-23 22:57     ` Matthias Andree
2001-09-24  6:45 ` Kai Henningsen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).