Files
SplitBit-Emulator/Programs/CosmOS/Apps/Press.asm
T
AnachronautandClaude Opus 5 b3726c950a Deliver the keys that are not characters
An arrow key has never reached this machine. Voyager threw it away for want of
anywhere to put it, and a terminal sent ESC [ A, which arrived in the middle of
whatever was being read and made it unrecognisable - typing Up at the CosmOS
prompt put three bytes in the command line and got "I do not know".

So the console names them: one byte each, 0x80 upward, above ASCII so nothing
written before them can collide. Up, Down, Left, Right, Home, End and forward
Delete, with room above for the paging and function keys.

The console normalises, which is what it already does. Behind a window it turns
the key somebody pressed into a byte; on a terminal it turns the sequence into
the same byte. That is the act it has always performed on Return and Backspace,
one layer further along, and it is why a program need not know which of the two
it is talking to. What a key MEANS is not the console's business - that belongs
to whoever is reading, the same way what is on a disk belongs to the system and
what a drive is belongs to the machine.

Translated only when standard input really is a terminal. Nothing else sends
these sequences, a pipe holds exactly the bytes somebody put in it, and it keeps
the Escape-or-Up timing problem out of every test here: a test writes the key
values themselves. Line mode drops them, in both front ends, because line mode
delivers characters and a line somebody else has finished editing cannot be
moved about in.

Press.sbx says what it was handed, in hexadecimal and by name, and reads a line
before it reads keys so both halves of that rule are checked. Two recordings,
one fed as standard input and one as a keyboard, agreeing byte for byte; each
break fails exactly one of them. Three checks in terminal.sh type real escape
sequences at a pseudo-terminal, which is the only place they are ever read as
sequences: that they arrive as keys, that Escape alone is still Escape, and that
a character typed straight after an escape is held rather than swallowed.

Five recordings re-blessed for Press.sbx appearing on the shared disk, and the
whole of that diff is the file's own line and the counts above it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
2026-08-31 22:24:11 -04:00

179 lines
3.2 KiB
NASM

; What the console just handed over, in hexadecimal and by name.
;
; The keys that are not characters - the arrows, Home, End and forward Delete - arrive as
; the console's own values above ASCII rather than as the escape sequences a terminal sends
; or as nothing at all, which is what a window used to make of them. This is what shows
; that, and it shows both halves of the rule in one run:
;
; A LINE FIRST, read the way everything reads one. Line mode delivers characters, so the
; keys are dropped before they reach the buffer and what comes back is what a person could
; have typed. Pressing Up while something else is collecting a line does nothing, which is
; an improvement on putting an escape and a bracket in the middle of it.
;
; THEN THE KEYS, in key mode, where a program has asked for every keystroke as it happens
; and these are keystrokes like any other.
;
; Written by Anachronaut
#Include services.asm
#Program
#Base 0x4000
start:
SETD.0 LineText
CALL printString
CALL newLine
SETD.0 Buffer
INIB 0d63
CALL readLine
SETD.0 Buffer
CALL showBytes
SETD.0 KeyText
CALL printString
CALL newLine
INIA 0x01
OUTA 0x02 ; Key mode. Nothing echoes, so everything below says what it saw.
keyLoop:
INA 0x00
INIB 0xFF
XOR
BRQ keyDone ; Nothing more is coming.
INIB 0x71 ; q, which is how this is stopped.
XOR
BRQ keyDone
CALL showKey
BRI keyLoop
keyDone:
RSTA
OUTA 0x02 ; Line mode, the way it was found.
SETD.0 DoneText
CALL printString
CALL newLine
RSTA
SWI osExit
; DP0 names a string of bytes ending in a zero. Prints each as two hexadecimal digits, so
; that what is in the buffer can be read rather than guessed at.
showBytes:
LDA.0
BRA showBytesDone
CALL printByteHex
INIA 0x20
OUTA 0x00
INCD.0
BRI showBytes
showBytesDone:
CALL newLine
RET
; A holds a key. Prints its value and then what it is.
;
; A survives a CALL, so the byte is still here after printing it - but only until something
; else is put in A, which the space below does. So it is kept where the naming can find it.
showKey:
SETD.1 KeyByte
STA.1
CALL printByteHex
INIA 0x20
OUTA 0x00
SETD.1 KeyByte
LDA.1
; XOR leaves the answer in Q and A alone, so one load stands for the whole ladder.
INIB 0x80
XOR
BRQ keyUp
INIB 0x81
XOR
BRQ keyDown
INIB 0x82
XOR
BRQ keyLeft
INIB 0x83
XOR
BRQ keyRight
INIB 0x84
XOR
BRQ keyHome
INIB 0x85
XOR
BRQ keyEnd
INIB 0x86
XOR
BRQ keyDelete
; An ordinary character, which is its own best name.
OUTA 0x00
CALL newLine
RET
keyUp:
SETD.0 UpText
BRI keySay
keyDown:
SETD.0 DownText
BRI keySay
keyLeft:
SETD.0 LeftText
BRI keySay
keyRight:
SETD.0 RightText
BRI keySay
keyHome:
SETD.0 HomeText
BRI keySay
keyEnd:
SETD.0 EndText
BRI keySay
keyDelete:
SETD.0 DeleteText
keySay:
CALL printString
CALL newLine
RET
#Data
#Base 0x2000
LineText:
"a line, then keys. q stops."
KeyText:
"keys:"
DoneText:
"done"
UpText:
"up"
DownText:
"down"
LeftText:
"left"
RightText:
"right"
HomeText:
"home"
EndText:
"end"
DeleteText:
"delete"
KeyByte:
0x00
Buffer:
#Reserve 0d64
#Vectors
Boot start
#Include console.asm