Backspace, whatever the terminal calls it
CosmOS's line editor looks for 0x08, which is what Voyager's keyboard
sends. A POSIX terminal sends its own erase character instead, and on
most of them that is 0x7F.
It stayed hidden while the terminal was doing the editing: canonical
mode consumes the erase character itself and hands over a finished
line. Key mode turns ICANON off, which is the point of it, so from the
day the shell started editing its own line - 7360374 - Backspace worked
in Voyager and did nothing at all in the console-only emulator. The
Programming Manual already claimed the console normalised Backspace on a
terminal the way it normalises the arrow keys; the code did not.
The erase character is read from the terminal's own VERASE rather than
assumed to be 0x7F, because some terminals are set to 0x08 and a person
who has moved their erase key has said where it is. Forward Delete is
untouched and stays 0x86: two keys, two values.
Only when standard input really is a terminal. A file or a pipe holding
0x7F holds a byte somebody wrote, not a key somebody pressed.
Three checks in terminal.sh under a pseudo-terminal whose VERASE is set
on the slave side: erase at 0x7F arrives as Backspace, erase at 0x08
still does, and a 0x7F read from a file is left alone. The last one is
what fails on the obvious wrong fix of translating 0x7F unconditionally,
which was verified with break.sh along with the fix's removal.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
co-authored by
Claude Opus 5
parent
019c93a587
commit
8631a78229
+35
-1
@@ -610,14 +610,48 @@ static int consoleKeyFromEscape(void) {
|
||||
|
||||
// One key from standard input: a byte as it arrived, or one of the console's own key values
|
||||
// where a terminal sent a sequence meaning one.
|
||||
// ---- The terminal's erase key is not the one this machine knows ----
|
||||
//
|
||||
// SplitBit's Backspace is 0x08. That is what Voyager's keyboard sends and what CosmOS's line
|
||||
// editor looks for. A POSIX terminal sends whatever ITS erase character is, and on most of
|
||||
// them that is 0x7F.
|
||||
//
|
||||
// It went unnoticed for as long as the terminal was doing the editing: in canonical mode the
|
||||
// tty eats its own erase character and hands over a finished line. Key mode turns ICANON off,
|
||||
// which is the point of it, and from then on the byte arrives raw and means nothing to the
|
||||
// editor. So Backspace worked in Voyager and stopped working in the console-only emulator on
|
||||
// the day the shell started editing the line itself.
|
||||
//
|
||||
// VERASE IS ASKED RATHER THAN 0x7F ASSUMED, because the terminal is what knows: it was saved
|
||||
// on the way into raw mode, some terminals really are set to 0x08, and a person who has moved
|
||||
// their erase key somewhere else has said where it is.
|
||||
//
|
||||
// ONLY WHEN STANDARD INPUT IS A TERMINAL. A file or a pipe holding 0x7F holds a byte that
|
||||
// somebody wrote, not a key somebody pressed, and rewriting it would corrupt input that has
|
||||
// nothing to do with terminals. consoleTerminalSaved is exactly that question: it is only
|
||||
// ever set after an isatty succeeded.
|
||||
static int consoleEraseNormalized(int got) {
|
||||
if (!consoleTerminalSaved || got < 0) {
|
||||
return got;
|
||||
}
|
||||
const cc_t erase = consoleSavedTerminal.c_cc[VERASE];
|
||||
// A terminal with no erase key at all, which says so this way, has nothing to translate.
|
||||
if (erase == _POSIX_VDISABLE) {
|
||||
return got;
|
||||
}
|
||||
return got == (int)erase ? 0x08 : got;
|
||||
}
|
||||
|
||||
static int consoleKeyFromInput(int mayWait) {
|
||||
for (;;) {
|
||||
int got;
|
||||
if (consoleHeldByte >= 0) {
|
||||
// Already normalized on the way in, and doing it twice would be wrong the day
|
||||
// 0x08 is somebody's erase character: it is its own answer.
|
||||
got = consoleHeldByte;
|
||||
consoleHeldByte = -1;
|
||||
} else {
|
||||
got = consoleFromInput(mayWait);
|
||||
got = consoleEraseNormalized(consoleFromInput(mayWait));
|
||||
}
|
||||
if (got < 0) {
|
||||
return got;
|
||||
|
||||
Reference in New Issue
Block a user