mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
231 lines
7.3 KiB
Python
231 lines
7.3 KiB
Python
|
#!/usr/bin/env python3
|
||
|
|
||
|
# Interactive test program for assorted ancillary changes to the
|
||
|
# terminal window - title, position, size, z-order, colour palette
|
||
|
# etc.
|
||
|
|
||
|
import argparse
|
||
|
import sys
|
||
|
import termios
|
||
|
import os
|
||
|
from time import sleep
|
||
|
|
||
|
def send(s):
|
||
|
sys.stdout.write(s)
|
||
|
sys.stdout.flush()
|
||
|
|
||
|
def query(s, lastchar=None):
|
||
|
send(s)
|
||
|
|
||
|
old_attrs = termios.tcgetattr(0)
|
||
|
new_attrs = old_attrs.copy()
|
||
|
new_attrs[3] &= ~(termios.ECHO | termios.ICANON)
|
||
|
new_attrs[6][termios.VMIN] = 0
|
||
|
new_attrs[6][termios.VTIME] = 1
|
||
|
try:
|
||
|
termios.tcsetattr(0, termios.TCSANOW, new_attrs)
|
||
|
|
||
|
s = b""
|
||
|
while True:
|
||
|
c = os.read(0, 1)
|
||
|
if len(c) == 0:
|
||
|
break
|
||
|
s += c
|
||
|
if lastchar is not None and c[0] == lastchar:
|
||
|
break
|
||
|
return s
|
||
|
|
||
|
finally:
|
||
|
termios.tcsetattr(0, termios.TCSANOW, old_attrs)
|
||
|
|
||
|
def pause(prompt):
|
||
|
input(prompt + (" " if len(prompt) > 0 else "") + "--More--")
|
||
|
|
||
|
def main():
|
||
|
testnames = [
|
||
|
"title",
|
||
|
"icon",
|
||
|
"minimise",
|
||
|
"maximise",
|
||
|
"minquery",
|
||
|
"setpalette",
|
||
|
"querypalette",
|
||
|
"winpos",
|
||
|
"setwinsize",
|
||
|
"querywinsize",
|
||
|
"zorder",
|
||
|
"mousereport",
|
||
|
]
|
||
|
|
||
|
parser = argparse.ArgumentParser(
|
||
|
description='Test PuTTY\'s ancillary terminal updates')
|
||
|
parser.add_argument("test", choices=testnames, nargs="*",
|
||
|
help='Sub-test to perform (default: all of them)')
|
||
|
args = parser.parse_args()
|
||
|
|
||
|
if len(args.test) == 0:
|
||
|
dotest = lambda s: True
|
||
|
else:
|
||
|
testset = set(args.test)
|
||
|
dotest = lambda s: s in testset
|
||
|
|
||
|
if dotest("title"):
|
||
|
send("\033]2;Title test 1\a")
|
||
|
pause("Title test 1.")
|
||
|
send("\033]2;Title test 2\a")
|
||
|
pause("Title test 2.")
|
||
|
|
||
|
if dotest("icon"):
|
||
|
send("\033]1;Icon-title test 1\a")
|
||
|
pause("Icon-title test 1.")
|
||
|
send("\033]1;Icon-title test 2\a")
|
||
|
pause("Icon-title test 2.")
|
||
|
|
||
|
if dotest("minimise"):
|
||
|
pause("About to minimise and restore.")
|
||
|
send("\033[2t")
|
||
|
sleep(2)
|
||
|
send("\033[1t")
|
||
|
|
||
|
if dotest("maximise"):
|
||
|
pause("About to maximise.")
|
||
|
send("\033[9;1t")
|
||
|
pause("About to unmaximise.")
|
||
|
send("\033[9;0t")
|
||
|
|
||
|
if dotest("minquery"):
|
||
|
pause("Query minimised status.")
|
||
|
s = query("\033[11t")
|
||
|
if s == b"\033[1t":
|
||
|
print("Reply: not minimised")
|
||
|
elif s == b"\033[2t":
|
||
|
print("Reply: minimised")
|
||
|
else:
|
||
|
print("Reply unknown:", repr(s))
|
||
|
|
||
|
if dotest("setpalette"):
|
||
|
print("Palette testing:")
|
||
|
teststr = ""
|
||
|
for i in range(8):
|
||
|
teststr += "\033[0;{:d}m{:X}".format(i+30, i)
|
||
|
for i in range(8):
|
||
|
teststr += "\033[1;{:d}m{:X}".format(i+30, i+8)
|
||
|
teststr += "\033[0;39mG\033[1mH\033[0;7mI\033[1mJ"
|
||
|
teststr += "\033[m"
|
||
|
teststr += " " * 9 + "K" + "\b" * 10
|
||
|
for c in "0123456789ABCDEFGHIJKL":
|
||
|
pause("Base: " + teststr)
|
||
|
send("\033]P" + c + "ff0000")
|
||
|
pause(c + " red: " + teststr)
|
||
|
send("\033]P" + c + "00ff00")
|
||
|
pause(c + " green: " + teststr)
|
||
|
send("\033]P" + c + "0000ff")
|
||
|
pause(c + " blue: " + teststr)
|
||
|
send("\033]R")
|
||
|
|
||
|
if dotest("querypalette"):
|
||
|
send("\033]R")
|
||
|
nfail = 262
|
||
|
for i in range(nfail):
|
||
|
s = query("\033]4;{:d};?\a".format(i), 7).decode("ASCII")
|
||
|
prefix, suffix = "\033]4;{:d};rgb:".format(i), "\a"
|
||
|
if s.startswith(prefix) and s.endswith(suffix):
|
||
|
rgb = [int(word, 16) for word in
|
||
|
s[len(prefix):-len(suffix)].split("/")]
|
||
|
if 0 <= i < 8:
|
||
|
j = i
|
||
|
expected_rgb = [0xbbbb * ((j>>n) & 1) for n in range(3)]
|
||
|
elif 0 <= i-8 < 8:
|
||
|
j = i-8
|
||
|
expected_rgb = [0x5555 + 0xaaaa * ((j>>n) & 1)
|
||
|
for n in range(3)]
|
||
|
elif 0 <= i-16 < 216:
|
||
|
j = i-16
|
||
|
expected_rgb = [(0 if v==0 else 0x3737+0x2828*v) for v in
|
||
|
(j // 36, j // 6 % 6, j % 6)]
|
||
|
elif 0 <= i-232 < 24:
|
||
|
j = i-232
|
||
|
expected_rgb = [j * 0x0a0a + 0x0808] * 3
|
||
|
else:
|
||
|
expected_rgb = [
|
||
|
[0xbbbb, 0xbbbb, 0xbbbb], [0xffff, 0xffff, 0xffff],
|
||
|
[0x0000, 0x0000, 0x0000], [0x5555, 0x5555, 0x5555],
|
||
|
[0x0000, 0x0000, 0x0000], [0x0000, 0xffff, 0x0000],
|
||
|
][i-256]
|
||
|
if expected_rgb == rgb:
|
||
|
nfail -= 1
|
||
|
else:
|
||
|
print(i, "unexpected: {:04x} {:04x} {:04x}".format(*rgb))
|
||
|
else:
|
||
|
print(i, "bad format:", repr(s))
|
||
|
print("Query palette: {:d} colours wrong".format(nfail))
|
||
|
|
||
|
if dotest("winpos"):
|
||
|
print("Query window position: ", end="")
|
||
|
s = query("\033[13t").decode("ASCII")
|
||
|
prefix, suffix = "\033[3;", "t"
|
||
|
if s.startswith(prefix) and s.endswith(suffix):
|
||
|
x, y = [int(word) for word in
|
||
|
s[len(prefix):-len(suffix)].split(";")]
|
||
|
print("x={:d} y={:d}".format(x, y))
|
||
|
else:
|
||
|
print("bad format:", repr(s))
|
||
|
x, y = 50, 50
|
||
|
|
||
|
pause("About to move window.")
|
||
|
send("\033[3;{:d};{:d}t".format(x+50, y+50))
|
||
|
pause("About to move it back again.")
|
||
|
send("\033[3;{:d};{:d}t".format(x, y))
|
||
|
|
||
|
if dotest("setwinsize"):
|
||
|
pause("About to DECCOLM to 132 cols.")
|
||
|
send("\033[?3h")
|
||
|
pause("About to DECCOLM to 80 cols.")
|
||
|
send("\033[?3l")
|
||
|
pause("About to DECCOLM to 132 cols again.")
|
||
|
send("\033[?3h")
|
||
|
pause("About to reset the terminal.")
|
||
|
send("\033c")
|
||
|
pause("About to DECSLPP to 30 rows.")
|
||
|
send("\033[30t")
|
||
|
pause("About to DECSLPP to 24 rows.")
|
||
|
send("\033[24t")
|
||
|
pause("About to DECSNLS to 30 rows.")
|
||
|
send("\033[*30|")
|
||
|
pause("About to DECSNLS to 24 rows.")
|
||
|
send("\033[*24|")
|
||
|
pause("About to DECSCPP to 90 cols.")
|
||
|
send("\033[$90|")
|
||
|
pause("About to DECSCPP to 80 cols.")
|
||
|
send("\033[$80|")
|
||
|
pause("About to xterm to 90x30.")
|
||
|
send("\033[8;30;90t")
|
||
|
pause("About to xterm back to 80x24.")
|
||
|
send("\033[8;24;80t")
|
||
|
|
||
|
if dotest("querywinsize"):
|
||
|
print("Query window size: ", end="")
|
||
|
s = query("\033[14t").decode("ASCII")
|
||
|
prefix, suffix = "\033[4;", "t"
|
||
|
if s.startswith(prefix) and s.endswith(suffix):
|
||
|
h, w = [int(word) for word in
|
||
|
s[len(prefix):-len(suffix)].split(";")]
|
||
|
print("w={:d} h={:d}".format(w, h))
|
||
|
else:
|
||
|
print("bad format:", repr(s))
|
||
|
|
||
|
if dotest("zorder"):
|
||
|
pause("About to lower to bottom and then raise.")
|
||
|
send("\033[6t")
|
||
|
sleep(2)
|
||
|
send("\033[5t")
|
||
|
|
||
|
if dotest("mousereport"):
|
||
|
send("\033[?1000h")
|
||
|
pause("Mouse reporting on: expect clicks to generate input")
|
||
|
send("\033[?1000l")
|
||
|
pause("Mouse reporting off: expect clicks to select")
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main()
|