From c73409ac27a161b4cf7ef6e70a80aceef114812e Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Wed, 7 Dec 2022 10:40:54 +0000 Subject: [PATCH] term: new set(), register_cleanup() methods --- mmgen/term.py | 38 ++++++++++++++++++++++++++++++++------ test/misc/term.py | 6 +----- test/misc/term_ni.py | 34 ++++++++++++++++++++++++++++++++++ test/test_py_d/ts_misc.py | 38 +++++++++++++++++++++++++++++++++++++- 4 files changed, 104 insertions(+), 12 deletions(-) create mode 100755 test/misc/term_ni.py diff --git a/mmgen/term.py b/mmgen/term.py index 72e6e550..edb73dc4 100755 --- a/mmgen/term.py +++ b/mmgen/term.py @@ -41,10 +41,25 @@ _term_dimensions = namedtuple('terminal_dimensions',['width','height']) class MMGenTerm(object): + @classmethod + def register_cleanup(cls): + if g.platform == 'linux' and not hasattr(cls,'cleanup_registered'): + import atexit + atexit.register( + lambda: termios.tcsetattr( + cls.stdin_fd, + termios.TCSADRAIN, + cls.orig_term) ) + cls.cleanup_registered = True + @classmethod def init(cls,noecho=False): pass + @classmethod + def set(cls,*args,**kwargs): + pass + @classmethod def reset(cls): pass @@ -60,16 +75,23 @@ class MMGenTermLinux(MMGenTerm): termios.tcsetattr( cls.stdin_fd, termios.TCSANOW, cls.orig_term ) cls.cur_term = cls.orig_term + @classmethod + def set(cls,setting): + d = { + 'echo': lambda t: t[:3] + [t[3] | (termios.ECHO | termios.ECHONL)] + t[4:], # echo input chars + 'noecho': lambda t: t[:3] + [t[3] & ~(termios.ECHO | termios.ECHONL)] + t[4:], # don’t echo input chars + } + termios.tcsetattr( cls.stdin_fd, termios.TCSANOW, d[setting](cls.cur_term) ) + cls.cur_term = termios.tcgetattr(cls.stdin_fd) + @classmethod def init(cls,noecho=False): cls.stdin_fd = sys.stdin.fileno() - if not hasattr(cls,'orig_term'): - cls.orig_term = termios.tcgetattr(cls.stdin_fd) - if noecho: # don’t echo input characters - t = termios.tcgetattr(cls.stdin_fd) - t[3] &= ~(termios.ECHO | termios.ECHONL) - termios.tcsetattr( cls.stdin_fd, termios.TCSANOW, t ) cls.cur_term = termios.tcgetattr(cls.stdin_fd) + if not hasattr(cls,'orig_term'): + cls.orig_term = cls.cur_term + if noecho: + cls.set('noecho') @classmethod def get_terminal_size(cls): @@ -137,6 +159,10 @@ class MMGenTermLinuxStub(MMGenTermLinux): def init(cls,noecho=False): cls.stdin_fd = sys.stdin.fileno() + @classmethod + def set(cls,*args,**kwargs): + pass + @classmethod def reset(cls): pass diff --git a/test/misc/term.py b/test/misc/term.py index 5c3b592a..99ed0d91 100755 --- a/test/misc/term.py +++ b/test/misc/term.py @@ -137,11 +137,7 @@ def tt_txview(): if not keypress_confirm('Continue testing transaction view?',default_yes=True): break -if g.platform == 'linux': - import termios,atexit - fd = sys.stdin.fileno() - old = termios.tcgetattr(fd) - atexit.register(lambda: termios.tcsetattr(fd,termios.TCSADRAIN,old)) +term_mod.register_cleanup() tt_start() diff --git a/test/misc/term_ni.py b/test/misc/term_ni.py new file mode 100755 index 00000000..92fdf7fd --- /dev/null +++ b/test/misc/term_ni.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 + +import sys,os +os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(os.path.dirname(sys.argv[0]))))) +sys.path[0] = os.curdir + +from mmgen.common import * + +cmd_args = opts.init() + +from mmgen.term import get_term,get_char_raw +term = get_term() + +if cmd_args[0] == 'echo': + + from mmgen.ui import line_input + + term.init(noecho=True) + line_input('noecho> ') + get_char_raw() + + term.set('echo') + line_input('echo> ') + + term.set('noecho') + line_input('noecho> ') + get_char_raw() + +elif cmd_args[0] == 'cleanup': + + term.register_cleanup() + + import tty + tty.setcbreak(term.stdin_fd) diff --git a/test/test_py_d/ts_misc.py b/test/test_py_d/ts_misc.py index 9942433f..396cb39d 100755 --- a/test/test_py_d/ts_misc.py +++ b/test/test_py_d/ts_misc.py @@ -27,13 +27,15 @@ from .ts_base import * from .ts_main import TestSuiteMain class TestSuiteMisc(TestSuiteBase): - 'miscellaneous tests (RPC backends)' + 'miscellaneous tests (RPC backends, xmrwallet_txview, term)' networks = ('btc',) tmpdir_nums = [99] passthru_opts = ('daemon_data_dir','rpc_port') cmd_group = ( ('rpc_backends', 'RPC backends'), ('xmrwallet_txview', "'mmgen-xmrwallet' txview"), + ('term_echo', "term.set('echo')"), + ('term_cleanup', 'term.register_cleanup()'), ) need_daemon = True color = True @@ -54,6 +56,40 @@ class TestSuiteMisc(TestSuiteBase): assert s in res, s return t + def term_echo(self): + + def test_echo(): + t.expect('echo> ','foo\n') + t.expect('foo') + + def test_noecho(): + t.expect('noecho> ','foo\n') + import pexpect + try: + t.expect('foo') + except pexpect.TIMEOUT: + imsg('[input not echoed - OK]') + t.send('x') + + if self.skip_for_win(): + return 'skip' + + t = self.spawn('test/misc/term_ni.py',['echo'],cmd_dir='.',pexpect_spawn=True,timeout=1) + t.p.logfile = None + t.p.logfile_read = sys.stdout if opt.verbose or opt.exact_output else None + t.p.logfile_send = None + + test_noecho() + test_echo() + test_noecho() + + return t + + def term_cleanup(self): + if self.skip_for_win(): + return 'skip' + return self.spawn('test/misc/term_ni.py',['cleanup'],cmd_dir='.',pexpect_spawn=True) + class TestSuiteHelp(TestSuiteBase): 'help, info and usage screens' networks = ('btc','ltc','bch','eth','xmr')