I want to write a Python program to get the current background color of an Xterm terminal. (This feature is available in termenv written in golang but I can't find any existing implementations in Python.)
This can be done by sending an OSC (Operating System Control) control sequence to stdout
and reading the response from stdin
. For example, to read the terminal background, the escape code is:
print('\033]11;?\033\\\033[6n')
The full response to this OSC query is '\x1b]11;rgb:2c2c/2c2c/2c2c\x1b\\\x1b[50;1R'
However, since not all terminals support this control sequence, we can't expect them to return anything in stdin. If nothing is supplied in stdin
and we still call stdin.read()
, read()
will wait forever until the user input something. So we need a function to tell whether stdin
contains anything for us to read.
I found that select
can be used to check if stdin
has inputs. However, when I tried using select
, it only passed for the first character, and it returned an empty array after that even if inputs are present:
print('\033]11;?\033\\\033[6n')
print(select.select([0], [], [], 0.1)) # Prints ([0], [], [])
print(repr(sys.stdin.read(1))) # Prints '\x1b'
print(select.select([0], [], [], 0.1)) # Prints ([], [], [])
print(repr(sys.stdin.read(1))) # Prints ']'
print(select.select([0], [], [], 0.1)) # Prints ([], [], [])
print(repr(sys.stdin.read(1))) # Prints '1'
Why would select
return an empty array (indicating that fd#0 (stdin) is not available for input) when there are inputs waiting to be read in stdin
? The go implementation using the native unix.Select
doesn't seem to have this issue.
I also tried using stdin.readable()
, but this always returns True
whether or not there are actually inputs present.