3

I am using this command to disable echo and fetch user input using sys.stdin.read(1)

tty.setcbreak(sys.stdin.fileno())

However during the course of my program I need to again enable and disable console echo. I tried

fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
termios.tcsetattr(fd, termios.TCSADRAIN, old)

But that aint working. How can I elegantly enable echo?

ps: I am using code from Python nonblocking console input by mizipzor

Heres the code:

import sys
import select
import tty
import termios
import time

def is_number(s):
    try:
        float(s)
        return True
    except ValueError:
        return False

def calc_time(traw):
    tfactor = {
    's':    1,
    'm':    60,
    'h':    3600,
    }
    if is_number(g[:-1]):
        return float(g[:-1]) * tfactor.get(g[-1])
    else:
        return None   
def isData():
    return select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], [])

old_settings = termios.tcgetattr(sys.stdin)
try:
    tty.setcbreak(sys.stdin.fileno())
    i = 0
    while 1:
        print i
        i += 1
        time.sleep(.1)
        if isData():
            c = sys.stdin.read(1)
            if c:
                if c == 'p':
                    print """Paused. Use the Following commands now:
Hit 'n' to skip and continue with next link.
Hit '5s' or '3m' or '2h' to wait for 5 secs, 3 mins or 3 hours
Hit Enter to continue from here itself.
Hit Escape to quit this program"""
                    #expect these lines to enable echo back again
                    fd = sys.stdin.fileno()
                    old = termios.tcgetattr(fd)
                    old[3] = old[3] & termios.ECHO
                    termios.tcsetattr(fd, termios.TCSADRAIN, old)

                    g = raw_input("(ENABLE ECHO HERE):")
                    
                    if g == '\x1b':
                        print "Escaping..."
                        break
                    if g == 'n':
                        #log error
                        continue
                    elif g[-1] in ['s','m','h']:
                        tval = calc_time(g)
                        if tval is not None:
                            print "Waiting for %s seconds."%(tval)
                            time.sleep(tval)
                    continue

finally:
    termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
Neuron
  • 5,141
  • 5
  • 38
  • 59
jerrymouse
  • 16,964
  • 16
  • 76
  • 97

2 Answers2

5

If you take a look at the docs, there's an example there:

http://docs.python.org/library/termios.html#module-termios

You are missing the setting on of the echo flag:

old[3] = old[3] | termios.ECHO

So, the whole thing is:

fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
old[3] = old[3] | termios.ECHO
termios.tcsetattr(fd, termios.TCSADRAIN, old)
David K. Hess
  • 16,632
  • 2
  • 49
  • 73
  • @david-k-hess Exactly, I tried this example before posting here. However these lines in my program still do not enable echo. The example works fine when executed standalone. Guess somethings to do with tty.setcbreak, cannot figure out what. – jerrymouse Jan 06 '12 at 12:59
  • tty.setcbreak should not be changing echo behavior - it only controls input processing. My guess is you have a bug in your program. Is it too big to post? – David K. Hess Jan 06 '12 at 13:03
  • Or even better, can you reduce your program down as small as it can be and still exhibit the problem and post that? – David K. Hess Jan 06 '12 at 13:09
  • @david-k-hess I have updated the code. I didnt strip code to bare minimum because there is some generic code which could help other users. I just need to enable echo at `g = raw_input("(ENABLE ECHO HERE):")` and then disable it again. – jerrymouse Jan 06 '12 at 13:34
  • 1
    I still don't see how echo is being disabled - however, I did see a bug in my code and have edited it. It should be a bit-wise OR operation. – David K. Hess Jan 06 '12 at 14:35
  • 1
    I just checked the source code to the Python tty module - apparently it's interpretation of raw mode is to also turn off ECHO so that's why it's off. – David K. Hess Jan 06 '12 at 14:42
5

Writing this:

termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)

Instead of the above 4 lines solved it.

jerrymouse
  • 16,964
  • 16
  • 76
  • 97
  • I don't follow. Which 4 lines above? How is this different from the line from your question (besides not using the file descriptor and a different variable name)? – maxschlepzig Jul 18 '21 at 11:58