Wait for a keypress before continuing?

S

Seebs

I shouldn't need to say this to anyone over the age of four, but being
obnoxious to people trying to help does not encourage others to answer your
question. You don't win points for insulting people who are trying to solve
your problems.

The frustrating part, of course, is that the people who do this are doing
it for reasons such that the explanation seems only proof that they are even
more right than they had previously expected.

Pathological narcissism is scary. If you ever find yourself going longer
than usual without being wrong, start checking your work more carefully. :)

-s
 
S

Seebs

Is there an equivalent to msvcrt for Linux users? I haven't found
one, and have resorted to some very clumsy code which turns off
keyboard excho then reads stdin. Seems such an obvious thing to want
to do I am surprised there is not a standard library module for it. Or
have I missed someting (wouldn't be the first time!)

There's no direct equivalent to the whole of msvcrt. The Unixy way to
do stuff like that on the command line is usually curses. But to make
a long story short: Unix evolved in a setting where there was often
not a user at *THE* console, and users were often on devices such that
it made sense to have all the line editing happen on the remote end, with
the remote end sending a completed line once the user was done with all
that stuff like backspaces.

Unix programs that do stuff like this for tty input do exist, of course,
but for the most part, they use an entire API designed for creating such
utilities, rather than one or two specialized functions. (Another part
of the reason for this: The Unix solution scales nicely to the case where
the five people using your program will be doing so on physically
different hardware terminals which don't use the same escape sequences
for cursor movement.)

Usually when people omit something obvious from a design, it's because of
other constraints or history to the design which make it less obvious.

-s
 
S

Steven D'Aprano

Hans said:
Strictly speaking, os.system is deprecated and you should use
the equivalent invocation of subprocess.call:

Strictly speaking, os.system is *not* deprecated in either Python 2.x or
3.x.

Latest stable documentation for Python 2.7 and 3.2:
http://docs.python.org/library/os.html#os.system
http://docs.python.org/py3k/library/os.html#os.system

And docs in development for 3.3 (unstable):
http://docs.python.org/dev/library/os.html#os.system

Deprecation means that there are active plans to remove the feature. There
are no such plans to remove os.system. What the docs say is much milder:

"The subprocess module provides more powerful facilities for spawning new
processes and retrieving their results; using that module is preferable to
using this function."

Using subprocess may be recommended, but that is not the same as saying that
os.system is deprecated. os.system will not be going away any time in the
foreseeable future.
 
T

Terry Reedy

There's no direct equivalent to the whole of msvcrt. The Unixy way to
do stuff like that on the command line is usually curses. But to make
a long story short: Unix evolved in a setting where there was often
not a user at *THE* console, and users were often on devices such that
it made sense to have all the line editing happen on the remote end, with
the remote end sending a completed line once the user was done with all
that stuff like backspaces.

Unix programs that do stuff like this for tty input do exist, of course,
but for the most part, they use an entire API designed for creating such
utilities, rather than one or two specialized functions. (Another part
of the reason for this: The Unix solution scales nicely to the case where
the five people using your program will be doing so on physically
different hardware terminals which don't use the same escape sequences
for cursor movement.)

The difference is between "Hit <enter> to continue" (which we can do in
portable Python) versus "Hit any key to continue" (which we cannot, and
which also leads to the joke about people searching for the 'any' key
;-). The equivalent contrast for GUIs is "Click OK to continue" versus
"Click anywhere to continue" If having to click a specific area is okay
for GUIs, having to hit a specific key for TUIs should be also.
 
S

Seebs

The difference is between "Hit <enter> to continue" (which we can do in
portable Python) versus "Hit any key to continue" (which we cannot, and
which also leads to the joke about people searching for the 'any' key
;-).

And more importantly, frustration and confusion when people pick control
or shift.
The equivalent contrast for GUIs is "Click OK to continue" versus
"Click anywhere to continue" If having to click a specific area is okay
for GUIs, having to hit a specific key for TUIs should be also.

In general I agree.

-s
 
E

Ethan Furman

Seebs said:
Pathological narcissism is scary. If you ever find yourself going longer
than usual without being wrong, start checking your work more carefully. :)


+1 QOTW
 
S

Steven D'Aprano

Terry said:
The difference is between "Hit <enter> to continue" (which we can do in
portable Python) versus "Hit any key to continue" (which we cannot, and
which also leads to the joke about people searching for the 'any' key
;-). The equivalent contrast for GUIs is "Click OK to continue" versus
"Click anywhere to continue" If having to click a specific area is okay
for GUIs, having to hit a specific key for TUIs should be also.

Poor analogy. A better analogy to a GUI would be comparing:


What would you like to do? Select an option and then click OK:
( ) Cancel
( ) Print
(x) Save
[__OK__]


versus:


What would you like to do?
[__Cancel__] [__Print__] [__Save__]


Actually, a better analogy would be a GUI that made you do this:


What would you like to do? Type the first letter of the option
you prefer in the text field, then click the OK button:
Options: Cancel | Print | Save
My option: [ ............ ] [__OK__]


(ASCII art best viewed with a fixed-width font.)

Generally speaking, the second UI would be preferred.

The raw_input/input UI is well-designed for entering plain text data. It is
extremely poor as a command interface.

Bringing it back to text interfaces, it would be useful to have a text
interface such that commands can be executed using a single key press. You
might want to detect and respond to (say) the arrow keys, or ESC, or P
rather than P<enter>. Curses apps can do it, proof that even under Unix it
is desirable. (Imagine how awkward it would be to use a TUI mail client or
text editor where the only user input was from something like raw_input.)
Unfortunately curses is quite heavyweight for a simple CLI script.

I note also that even the Python interactive interpreter under Linux has an
extremely limited detect-single-keypress capability: Ctrl-C generates a
KeyboardInterrupt without needing to hit Enter, and Ctrl-D exits the
interpreter.
 
C

Chris Angelico

The raw_input/input UI is well-designed for entering plain text data. It is
extremely poor as a command interface.

... (Imagine how awkward it would be to use a TUI mail client or
text editor where the only user input was from something like raw_input.)

I run a MUD and play several. MUDs by definition have only line-based
input (if you use a raw TELNET client, you have character-based input,
but most MUD clients send entire lines of text at once); yet it is
possible to implement a reasonably-viable file editor. It's not
difficult to become quite proficient with line-based editors,
especially if you rig some client-side support (which I have done on
two of the MUDs).

Line-based input is excellent as a command interface, if commands
consist of verbs and parameters. It's terrible for playing Tetris on.

ChrisA
 
P

peter

Is there an equivalent to msvcrt for Linux users?  I haven't found
one, and have resorted to some very clumsy code which turns off
keyboard excho then reads stdin. Seems such an obvious thing to want
to do I am surprised there is not a standard library module for it. Or
have I missed someting (wouldn't be the first time!)

The quick and dirty way is to invoke stty(1) using os.system:

import os

def getpassword(prompt="Password: "):
     try:
         os.system("stty -echo")
         passwd = raw_input(prompt)
     finally:
         os.system("stty echo")
     return passwd

Strictly speaking, os.system is deprecated and you should use
the equivalent invocation of subprocess.call:

import subprocess

def getpassword(prompt="Password: "):
     try:
         subprocess.call(["stty", "-echo"])
         passwd = raw_input(prompt)
     finally:
         subprocess.call(["stty", "echo"])
     return passwd

If you don't want to use an external process, use termios:

import termios, sys

def getpassword(prompt="Password: "):
     fd = sys.stdin.fileno()
     old = termios.tcgetattr(fd)
     new = termios.tcgetattr(fd)
     new[3] = new[3] & ~termios.ECHO          # lflags
     try:
         termios.tcsetattr(fd, termios.TCSADRAIN, new)
         passwd = raw_input(prompt)
     finally:
         termios.tcsetattr(fd, termios.TCSADRAIN, old)
     return passwd

These functions work on any Posix system (including Mac OSX),
but not on Windows.

Hope this helps,

-- HansM

This is very similar to my solution, which was to use stty turn off
keyboard echo, then repeatedly read sys.stdin.read(1) until a unique
keystroke had been defined. For example, the 'Insert' key seems to
return a sequence of four codes, namely 27, 91, 50, 126. It works but
has two disadvantages which I have managed to live with:-

1. As character 27 is used to signal the start of a 'special' key
sequence, it cannot detect a single press of the Esc key. The
workaround is to detect a double press instead.

2. Some keys seem to return different sets of codes depending on the
circumstances. For example, F1 returns 27,91,91,65 from the command
line, and 27,79,80 from a GUI window. I suspect there may be
variations between flavours of Linux too. The solution is to detect
all possibilities - so far I haven't found any overlaps.

Not pretty, but as I said it works. I know now not to spend time
looking further. Whilst there may be a historical reason for the
current situation, it would be a great convenience for amateur coders
like mayself if the gurus could devise a platform independent version
of mscvrt.

If anyone is interested in the code I can post it, but it's quite long
as it comprises multiple if statements to cover each combination.

Peter
 
D

Dennis Lee Bieber

Not pretty, but as I said it works. I know now not to spend time
looking further. Whilst there may be a historical reason for the
current situation, it would be a great convenience for amateur coders
like mayself if the gurus could devise a platform independent version
of mscvrt.
What would they call it... It sure wouldn't be "MicroSoft Visual C
RunTime".

Note that the documentation for msvcrt states that /it/ is how the
getpass module is implemented on Windows.

Take a look at the bottom of getpass.py and look at the loops it has
to do to handle three different environments.
 
N

Nobody

This is very similar to my solution, which was to use stty turn off
keyboard echo, then repeatedly read sys.stdin.read(1) until a unique
keystroke had been defined. For example, the 'Insert' key seems to
return a sequence of four codes, namely 27, 91, 50, 126. It works but
has two disadvantages which I have managed to live with:-

1. As character 27 is used to signal the start of a 'special' key
sequence, it cannot detect a single press of the Esc key. The
workaround is to detect a double press instead.

2. Some keys seem to return different sets of codes depending on the
circumstances. For example, F1 returns 27,91,91,65 from the command
line, and 27,79,80 from a GUI window. I suspect there may be
variations between flavours of Linux too. The solution is to detect
all possibilities - so far I haven't found any overlaps.

Escape sequences vary between terminals. A given key may have different
escape sequences on the Linux console, xterm, a vt220, etc. The
termcap and terminfo databases exist for this purpose (terminfo is newer).

Some escape sequences vary by "mode". E.g. the cursor keys typically
produce different sequences depending upon whether the terminal is in
"keypad" mode.

The normal solution for distinguishing the escape key from an escape
sequence is a timeout. Unfortunately, it needs to be quite long in order
to reliably support network (ssh, telnet, etc) connections.
Not pretty, but as I said it works. I know now not to spend time
looking further. Whilst there may be a historical reason for the
current situation, it would be a great convenience for amateur coders
like mayself if the gurus could devise a platform independent version
of mscvrt.

The platform-independent high-level terminal interface is called "curses".
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,169
Latest member
ArturoOlne
Top