From 2f9ae98c96d104e38bd784041bd63d033e90023e Mon Sep 17 00:00:00 2001 From: d6 Date: Sat, 21 Jan 2023 22:54:20 -0500 Subject: [PATCH] better terminal support --- term.py | 74 +++++++++++++++++++++++++++----------------------------- term.tal | 49 ++++++++++++++++++++++++------------- 2 files changed, 68 insertions(+), 55 deletions(-) diff --git a/term.py b/term.py index 51b4bd4..ab5a7ba 100755 --- a/term.py +++ b/term.py @@ -1,51 +1,49 @@ -#!/usr/bin/python -# -# ./term.py term.rom /bin/bash +#/usr/bin/env python -from select import select -from subprocess import Popen, PIPE, STDOUT +import fcntl +import os +import pty import sys - -# currently unbuffered -# -# TODO: figure out a more reasonable buffering strategy -def run(args): - return Popen(args, stdin=PIPE, stdout=PIPE, stderr=STDOUT, bufsize=0) +import struct +import termios def main(): + + # check usage args = sys.argv[1:] - if len(args) < 2: - print('usage: %s ROM SHELL [ ARGS... ]') + if len(args) < 1: + print('usage: %s ROM') print('') - print('execute the given uxn terminal program (ROM)') - print('and start a shell process (SHELL + ARGS).') - print('') - print('example: %s term.rom /bin/bash -i' % sys.argv[0]) + print(' ROM: the rom file to launch') sys.exit(1) - term = run(['uxnemu', args[0]]) - term_out = term.stdout.fileno() + # path to rom to run + rom = args[0] - shell = run(args[1:]) - shell_out = shell.stdout.fileno() - - while shell.poll() is None and term.poll() is None: - # wait 100ms to see if anything is ready to write - ns, _, _ = select([term_out, shell_out], [], [], 0.1) - for n in ns: - if n == term_out: - shell.stdin.write(term.stdout.read(1)) - shell.stdin.flush() - elif n == shell_out: - term.stdin.write(shell.stdout.read(1)) - term.stdin.flush() - else: - raise Exception('unexpected fileno: %d (expected %d or %d)' % (n, term_out, shell_out)) + # fork with a new pty + pid, fd = pty.fork() - if shell.poll() is None: - shell.kill() - if term.poll() is None: - term.kill() + if pid == 0: + # set TERM to something we can handle + env = dict(os.environ) + env['TERM'] = 'dumb' + os.execvpe('bash', ['bash', '--noediting', '-i'], env) + else: + # set the terminal size + #cols, rows = 63, 32 + cols, rows = 79, 40 + size = struct.pack("HHHH", rows, cols, 8, 8) + fcntl.ioctl(fd, termios.TIOCSWINSZ, size) + # disable terminal echo + attr = termios.tcgetattr(fd) + attr[3] = attr[3] & ~termios.ECHO + termios.tcsetattr(fd, termios.TCSADRAIN, attr) + + # use fd for the terminals stdin/stdout + os.dup2(fd, sys.stdin.fileno()) + os.dup2(os.dup(fd), sys.stdout.fileno()) + os.execvp('uxnemu', ['uxnemu', rom]) + if __name__ == "__main__": main() diff --git a/term.tal b/term.tal index 7946c27..da14ca5 100644 --- a/term.tal +++ b/term.tal @@ -18,18 +18,18 @@ @subinput $1 ( reading from subprocess? ) |0100 - ( 32 characters = 256 pixels ) - #0020 .rows STZ2 - #0040 .cols STZ2 + ( 80 cols x 24 rows ) + #0028 .rows STZ2 + #0050 .cols STZ2 ( set screen height/width based on rows/cols ) .rows LDZ2 #30 SFT2 .Screen/h DEO2 .cols LDZ2 #30 SFT2 .Screen/w DEO2 ( set colors ) - #0ff0 .System/r DEO2 - #0f88 .System/g DEO2 - #0f0f .System/b DEO2 + #0cf0 .System/r DEO2 + #0c88 .System/g DEO2 + #0c0f .System/b DEO2 ( set pos, subinput flag ) .buffer .pos STZ @@ -99,15 +99,15 @@ ;draw-tile JMP2 @on-key - .Controller/key DEI #00 EQU ,&skip JCN #00 .subinput STZ + .Controller/key DEI #00 EQU ,&skip JCN #41 .tint STZ .Controller/key DEI ;read JSR2 &skip BRK @on-input - .Console/r DEI #00 EQU ,&skip JCN #01 .subinput STZ + .Console/r DEI #00 EQU ,&skip JCN #41 .tint STZ .Console/r DEI ;read JSR2 &skip BRK @@ -123,11 +123,10 @@ ;read-normal JMP2 ( TODO: we need line-editing! ) -@read-bel JMP2r -@read-bs JMP2r ( POP ;scroll JMP2 ) -@read-tab JMP2r ( POP POP2r #0000 DIV ) -@read-esc JMP2r -@read-del JMP2r +@read-bel POP JMP2r +@read-bs POP JMP2r ( POP ;scroll JMP2 ) +@read-esc POP JMP2r +@read-del POP JMP2r @write-line ( -> ) .pos LDZ .buffer @@ -135,17 +134,33 @@ &next LDZk .Console/w DEO INC ,&loop JMP &done #0a .Console/w DEO .buffer .pos STZ JMP2r +( @read-tab POP JMP2r ) +@read-tab + POP + .subinput LDZ ,&display JCN + #01 #0e DEO JMP2r ( POP POP2r #0000 DIV ) + &display + .cur-x LDZ2 NIP #07 AND #08 SUB + &loop + #20 DUP ;cursor-addr JSR2 STA + ;draw-tile JSR2 + ;forward JSR2 + INC DUP ,&loop JCN + POP JMP2r + @read-cr ( 0d -> ) + POP .subinput LDZ ,&display JCN ;write-line JSR2 &display - POP ;hide-cursor JSR2 #0000 .cur-x STZ2 ;down JMP2 @read-nl ( 0a -> ) - ,read-cr JMP + POP + JMP2r +( ,read-cr JMP ) @forward ( -> ) .cur-x LDZ2 INC2 DUP2 .cols LDZ2 LTH2 ,&ok JCN @@ -179,7 +194,6 @@ .subinput LDZ ,&display JCN .pos LDZ STZk INC .pos STZ &display - ;hide-cursor JSR2 DUP ;cursor-addr JSR2 STA ;draw-tile JSR2 ;forward JMP2 @@ -213,5 +227,6 @@ ~chr/ascii.tal ( screen to store characters for redraw, etc. ) -@screen $0800 ( 64 x 32 ) +( @screen $0800 ( 64 x 32 ) ) +@screen $0c80 ( 64 x 32 ) @end-screen