escape sequence goes both way
tags: learning learning terminal software
content
- the communication between a program and a terminal emulator is:
program -> sends bytes to tty -> terminal is tty -> terminal interprets the bytes based on some protocol -> renders the screen user sees
- this flow goes both ways
user interacts with terminal, key strokes, etc -> terminal sends bytes to program's stdin -> program decides what to do about it
ESC = "\x1b"
def read_key():
# get file descriptor for stdin
fd = sys.stdin.fileno()
# save current terminal settings
old = termios.tcgetattr(fd)
try:
# disable line buffering and echo so we get each keypress immediately
tty.setraw(fd)
# read one byte
ch = sys.stdin.read(1)
# if it's an escape byte (0x1b), an escape sequence may follow
if ch == ESC:
# read the next byte
ch2 = sys.stdin.read(1)
# CSI (Control Sequence Introducer): ESC [ means an arrow/special key
if ch2 == "[":
# read the final byte: A=up, B=down, C=right, D=left
ch3 = sys.stdin.read(1)
return ESC + "[" + ch3
# regular key, just return the single character
return ch
finally:
# restore original terminal settings
termios.tcsetattr(fd, termios.TCSADRAIN, old)explanation:
╭──────┬──────┬────────────────────────────────────────────────────╮
│ Byte │ Hex │ Meaning │
├──────┼──────┼────────────────────────────────────────────────────┤
│ ESC │ 0x1b │ "what follows is a special sequence" │
├──────┼──────┼────────────────────────────────────────────────────┤
│ [ │ 0x5b │ CSI introducer — together with ESC, signals a │
│ │ │ control sequence │
├──────┼──────┼────────────────────────────────────────────────────┤
│ A │ 0x41 │ the specific key (A=up, B=down, C=right, D=left) │
╰──────┴──────┴────────────────────────────────────────────────────╯
- The function
read_key- reads these 3 bytes one at a time
- and returns them concatenated as a single string
\x1b[A - assembles escape sequences
- without it, a single arrow keypress would arrive as 3 separate
read(1)calls (\x1b,[,A)
Note
The shell (like bash) is just another program that reads from stdin, interprets commands, and launches other programs