LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   If no raw_input: (Python question) (https://www.linuxquestions.org/questions/programming-9/if-no-raw_input-python-question-657949/)

xadrith 07-24-2008 07:54 AM

If no raw_input: (Python question)
 
Is there a way to base operation of a loop based on whether or not a user has or has not inputted a value from the computer?

such as a:

Code:

If no raw_input():
          (continue for loop)
      else:
          clear()
          print msg

I know this syntax doesn't work, but I'm looking for a way to be able to take raw_input based solely on the user's discretion without pausing the program to wait for that input.

Rather, if they DID decide to hit enter, it would proceed with the rest of the if-else statement, thus skipping the process of the for loop and just continuing to render the rest of the complete message all at once.

Thanks for reading :)

x.D

xadrith 07-24-2008 09:49 AM

perhaps curses??
 
I was reading some information on the curses module for Python. I got a warm n' fuzzy reading about what it does, like perhaps this is what I was looking for:

Quote:

From: http://www.amk.ca/python/howto/curses/curses.html

Usually curses applications turn off automatic echoing of keys to the screen, in order to be able to read keys and only display them under certain circumstances. This requires calling the noecho() function.
My understanding is that this would read input from the user (such as him/her pressing the enter key) but would not disrupt the for loop from continuing to execute its code (which would be scrolling the text message on the screen).

Applying that. I've tried defining a function that would take input discretely, but when I try to put that function into the other function that unfolds the text, my indenting gets all screwed up...

I want to believe I'm on the right track, but I want even more to get this to work correctly:

Here's a sample of what I've been toying with:

Code:

import curses

def enter_skip():
    stdscr = curses.initscr()
    stdscr.keypad(1)
    curses.noecho(x = bool(raw_input())

def unfolding_message(msg,delay): =
    try:                          | 
        delay=float(delay)        | 
    except ValueError:            | 
        delay=0.100              |== This functions's indenting gets 
    for char in msg:              |  messed up after making the 
        time.sleep(delay)        |  enter_skip function.
        sys.stdout.write(char)    |   
        sys.stdout.flush()        | 
    print                        = 

===================================

What I want to do with it:

def unfolding_message(msg,delay):
    try:
        delay=float(delay)
    except ValueError:
        delay=0.100
    enter_skip()
    if x == True:
        for char in msg:
            time.sleep(delay)
            sys.stdout.write(char)
            sys.stdout.flush()
        print
    else:
        clear()
        print msg

I'm not a retarded programmer... (I think) I'm just a baby programmer, a toddler. Just looking for some guidance...

Is the curses module, in fact, what I am looking for? Or is it something simpler than that?

This project ties into a previous thread, if you wish to see it, it is located here:

http://www.linuxquestions.org/questi...ython-657725/?

Thanks for your time,

x.D

DeuceNegative 07-25-2008 11:58 AM

Not exactly sure what you're doing (sorry, I didn't look at the other thread), but it seems like you want to check for loop exit condition by doing a non-blocking read from stdin--something like this:

Code:

import sys, os, select, time, termios

def getInput():
        input = ''
        while len(select.select([sys.stdin.fileno()], [], [], 0.0)[0])>0:
                input += os.read(sys.stdin.fileno(), 4096)
        return input


if __name__=='__main__':
        try:
                attsorig = termios.tcgetattr(sys.stdin.fileno())  #so we can reset when done
               
                atts = termios.tcgetattr(sys.stdin.fileno())
                atts[3] = atts[3] & ~termios.ECHO    #don't echo characters
                atts[3] = atts[3] & ~termios.ICANON  #non-buffered input (don't wait for <ENTER>)
                termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, atts)

                while not getInput():
                        print "Waiting..."
                        time.sleep(0.5)
                print "All done."
        finally:
                termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, attsorig)

This little script prints "Waiting..." until you type any key, then it finishes. It uses the select module to check if anything is ready to read from stdin, and if so reads it using os.read() (won't block if select says something is ready to read).

Normally, the terminal doesn't `feed' the user's input to stdin until the user hits <ENTER>. One of the above termios operations turns that behavior off, so you get every key as the user types it. The other turns of echoing the input back to stdout, which it seems your interested in. I believe this can all be done through curses module, and it's probably more portable that way.

Not that if you need to reset the terminal attributes back at the end (the finally clause). If you don't, use the command reset (you won't see it echoed) to reset the terminal.

DeuceNegative 07-25-2008 12:21 PM

Now that I read your post a little closer, it seems you do not really care about the non-buffered input (not waiting for <ENTER>) and maybe not the non-echoed input, either. Here's a simpler example:

Code:

import sys, os, select, time

i = 0

def getInput():
        input = ''
        while len(select.select([sys.stdin.fileno()], [], [], 0.0)[0])>0:
                input += os.read(sys.stdin.fileno(), 4096)
        return input

def doWork():
        global i
        time.sleep(0.5)
        i += 1

if __name__=='__main__':
        input = ''
        while not input:
                doWork()
                input = getInput()
        print "got user input: %r" % input
        print "did %d units of work" % i

Just type something and hit <ENTER> in order to stop the program.

jcookeman 07-26-2008 07:21 AM

I don't see much difference in this post with this one.

There is more than one way to do this. Of course, you can do this with curses if you choose to go down that route. Otherwise, you can do it with my original suggestion of using select and termios which DeuceNegative has already showed you here.

Of course your write to stdout will be not work correctly after calling curses.initscr(). Continuing with our advice so far, a crude example:

Code:

import time
import select
import termios

class Screen:
    def __init__(self):
          self.__attsorig = termios.tcgetattr(sys.stdin.fileno())
          self.__atts = termios.tcgetattr(sys.stdin.fileno())
          #don't echo characters
          self.__atts[3] = self.__atts[3] & ~termios.ECHO
          #non-buffered input (don't wait for <ENTER>)
          self.__atts[3] = self.__atts[3] & ~termios.ICANON
          termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, self.__atts)


    def reset(self):
          termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, self.__attsorig)

    def unfold_message(self, msg, delay):
          try:
              delay=float(delay)
          except ValueError:
              delay=0.100
          for char in msg:
              # Check if the user has hit a key
              if select.select([sys.stdin],[],[],0) == ([sys.stdin],[],[]):
                    delay = 0
                    # Get keystrokes from stdin
                    whocares = os.read(sys.stdin.fileno(), 1024)
              time.sleep(delay)
              sys.stdout.write(char)
              sys.stdout.flush()
          print

if __name__ == "__main__":
    screen = Screen()
    screen.unfold_message("hello, this is a test", 0.1)
    screen.reset()



All times are GMT -5. The time now is 08:03 PM.