[Pythonmac-SIG] Non blocking terminal input

Samuel M. Smith smithsm at samuelsmith.org
Fri Feb 6 13:39:14 EST 2004


Thanks Bob for the clue of where to look.
Actually it took some digging to make it work. The python termios 
doesn't have the O_NONBLOCK flag it is in os.open(). In unix both  
fcntl and open support O_NONBLOCK but only python os.open() exports it. 
This kind of threw me because I didn't want to open the console I just 
wanted to change is state so os.fcntl was what I wanted but it didn't 
support. I tried os.open anyway and reopened the console. This seemed 
problematic but I guess you can open the same file multiple times with 
different file descriptors. The only problem I had was mixing print to 
stdout and writes to the new nonblocking fd = 3. Newlines were getting 
mixed up.

Anyway I thought others might be interested. Here is a short class that 
supports nonblocking reads from the console.

class ConsoleNB(object):
    """Class to manage non blocking reads from console.

       Opens non blocking read file descriptor on console
       Use instance method close to close file descriptor
       Use instance methods getline & put to read & write to console
       Needs os module
    """

    def __init__(self, canonical = True):
       """Initialization method for instance.

          opens fd on terminal console in non blocking mode
          os.ctermid() returns path name of console usually '/dev/tty'
          os.O_NONBLOCK makes non blocking io
          os.O_RDWR allows both read and write.
          Don't use print as same time since it could mess up non 
blocking reads.
          Default is canonical mode so no characters available until 
newline
       """
       #need to add code to enable  non canonical mode

       self.fd = os.open(os.ctermid(),os.O_NONBLOCK | os.O_RDWR)

    def close(self):
       """Closes fd. Should use  in try finally block.

       """
       os.close(self.fd)

    def getline(self,bs = 80):
       """Gets nonblocking line from console up to bs characters 
including newline.

          Returns None if no characters available else returns line.
          In canonical mode no chars available until newline is entered.
       """
       line = None
       try:
          line = os.read(self.fd, bs)
       except OSError, ex1:  #if no chars available generates exception
          try: #need to catch correct exception
             errno = ex1.args[0] #if args not sequence get TypeError
             if errno == 35:
                pass #No characters available
             else:
                raise #re raise exception ex1
          except TypeError, ex2:  #catch args[0] mismatch above
             raise ex1 #ignore TypeError, re-raise exception ex1

       return line

    def put(self, data = '\n'):
       """Writes data string to console.

       """
       os.write(self.fd, data)





On Feb 1, 2004, at 12:28, Bob Ippolito wrote:

> On Feb 1, 2004, at 1:57 PM, Samuel M. Smith wrote:
>
>> Is there an equivalent on mac/unix to the msvcrt module for windows 
>> kbhit() function?
>> Or in other words is there some way to do non blocking reads of the 
>> terminal as opposed to blocking reads vis a vis raw_input()?
>
> The reason stdin acts as a line based input is because there are 
> certain flags set on it... serial ports are the same way.  I remember 
> delving into this a while ago, and I *think* the constants/functions 
> you need to use are in the termios module.
>
> After you've set the right flags, you can even use select() on stdin 
> and it'll let you know when a key has been pressed.
>
> -bob
>
> (this is pretty standard *nix stuff..)
>
>
**********************************************************************
Samuel M. Smith Ph.D.
2966 Fort Hill Road
Eagle Mountain, Utah 84043
801-768-2768 voice
801-768-2769 fax
**********************************************************************
"The greatest source of failure and unhappiness in the world is
giving up what we want most for what we want at the moment"
**********************************************************************




More information about the Pythonmac-SIG mailing list