Colin Hancey
Colin Hancey

Reputation: 229

Prevent Command Line Usage During Function Run in Python/Terminal?

I'm using Terminal to run a python script with a series of print statements, separated by the time.sleep function.

If I'm printing various items over a period of 10 seconds, I would like to be able to prevent the user from inputting new commands into the command line during this time.

Is this possible in Terminal? Is there a work-around?



My goal here is to be able to provide the user with a lot of print statements, then have them answer a question only after the question is asked.

Because I don't want to overwhelm the user, I want to time delay the print statements so it appears more manageable (well, it's really for theatrical effect).

ie

for i in range(10):
    print "Eating cheeseburger..."
    time.sleep(1)

response = raw_input("What is your favorite color?")
if response == "blue":
    blah blah blah etc.

Right now, the user can input a response before the question is asked, and while the cheeseburger is still being eaten. I want to prevent this.

Upvotes: 0

Views: 951

Answers (2)

Eryk Sun
Eryk Sun

Reputation: 34300

The following is a version of Saurabh Shirodkar's answer written for the Windows console using ctypes.

import sys
import msvcrt
import ctypes

kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

ENABLE_ECHO_INPUT = 0x0004

def _check_bool(result, func, args):
    if not result:
        raise ctypes.WinError(ctypes.get_last_error())
    return args

kernel32.GetConsoleMode.errcheck = _check_bool
kernel32.GetConsoleMode.argtypes = (ctypes.c_void_p,
    ctypes.POINTER(ctypes.c_ulong))
kernel32.SetConsoleMode.errcheck = _check_bool
kernel32.SetConsoleMode.argtypes = (ctypes.c_void_p, ctypes.c_ulong)
kernel32.FlushConsoleInputBuffer.errcheck = _check_bool
kernel32.FlushConsoleInputBuffer.argtypes = (ctypes.c_void_p,)

def echo_input(enable=True, conin=sys.stdin):
    h = msvcrt.get_osfhandle(conin.fileno())
    mode = ctypes.c_ulong()
    kernel32.GetConsoleMode(h, ctypes.byref(mode))
    if enable:
        mode.value |= ENABLE_ECHO_INPUT
    else:
        mode.value &= ~ENABLE_ECHO_INPUT
    kernel32.SetConsoleMode(h, mode)

def flush_input(conin=sys.stdin):
    h = msvcrt.get_osfhandle(conin.fileno())
    kernel32.FlushConsoleInputBuffer(h)

if __name__ == '__main__':
    import time

    if sys.version_info[0] == 2:
        input = raw_input

    echo_input(False)

    for i in range(10):
        print(i)
        time.sleep(1)

    echo_input(True)
    flush_input()

    print(input("Answer now: "))

Upvotes: 1

Saurabh Shirodkar
Saurabh Shirodkar

Reputation: 334

The question is a platform specific one, as different operating systems handle standard input and output differently. I will attempt to answer your question for Linux:

You can use os.system to access the linux command stty -echo to make any text entered on the terminal invisible, and stty echo to make it visible again.

The next thing you want to achieve is to clear the stdin buffer when user input is asked. This can be achieved through the termios function tcflush that can be used to flush all input that has been received but not read by the terminal yet.

import os
import time
import termios
import sys

os.system("stty -echo")
for i in range(10):
    print(i)
    time.sleep(1)
os.system("stty echo")

termios.tcflush(sys.stdin, termios.TCIOFLUSH)

print(raw_input("Answer now:"))

Upvotes: 3

Related Questions