![small](https://istack.dev59.com/g1THp.webp)
![resized](https://istack.dev59.com/z1H9l.webp)
这是对@EthanField的方案的实现,包括三个函数:
- main函数用于创建图形用户界面、xterm终端和连接管道
- on_resize函数会在包含终端的窗口大小调整时被调用
- get_xterm_pts函数用于解析输出以获取pts,以便将stdin提供给xterm终端
import tkinter as tk
import subprocess as sp
from re import match
from threading import Thread
from queue import Queue
def main():
root = tk.Tk()
queue = Queue()
termf = tk.Frame(root, width=800, height=800)
termf.pack(fill=tk.BOTH, expand=tk.YES, padx=0, pady=0)
wid = termf.winfo_id()
sp.Popen("""echo '*VT100.allowWindowOps: true' | xrdb -merge""", shell=True)
cmd = (
f'xterm -into {wid} -geometry 100x50 '
r'-sb -l -lc -lf /dev/stdout '
"""-e /bin/bash -c "ps -o tt=;bash" """
r'| tee'
)
print('Launching:', cmd)
process = sp.Popen(
cmd, shell=True, stdout=sp.PIPE, stderr=sp.PIPE)
print('Xterm pid:', process.pid)
thread = Thread(target=lambda: get_xterm_pts(termf, process, queue))
thread.start()
termf.bind("<Configure>", lambda event: on_resize(event, queue))
root.mainloop()
def on_resize(event, queue):
"""On resize: send escape sequence to pts"""
magic_x, magic_y = 6.1, 13
print('Resize (w, h):', event.width, event.height)
if not queue.queue: return
width = int(event.width / magic_x)
height = int(event.height / magic_y)
print('To (lin,col):', height, width)
ctl = f"\u001b[8;{height};{width}t"
with open(queue.queue[0], 'w') as f:
f.write(ctl)
def get_xterm_pts(parent, process, queue):
"""Retrieve pts(`process`) -> `queue`"""
while True:
out = process.stdout.readline().decode()
print('Xterm out' + out)
match_pts = match(r'pts/\d+', out)
if match_pts:
pts = '/dev/' + match_pts.group(0)
print('-----------> pts:', pts)
queue.put(pts)
break
if out == b'' and process.poll() is not None:
break
fake_event = tk.Event()
fake_event.width = parent.winfo_width()
fake_event.height = parent.winfo_height()
on_resize(fake_event, queue)
if __name__ == '__main__':
main()
在新线程中查找新shell的pts似乎有点多,但我们想要交互式shell的pts而不是生成它的sh
。我曾尝试使用一些Popen ps将管道连接到pts,但这种方式并不可靠。
11844 pts/1 00:00:00 sh <- pid returned to Popen
11847 pts/1 00:00:00 xterm <- then ...
11848 pts/1 00:00:00 tee <- that is how a pipe work, first plug, then spawn (apparently) (seems logical)
11854 pts/35 00:00:00 bash <- then favorite shell is Michel
echo -e '\e[4;600;800t'
。请参考 http://invisible-island.net/xterm/ctlseqs/ctlseqs.html 中的窗口操作。 - esmit