3 # curses_check_for_keypress - loop until user presses a key.
5 # Copyright (C) 2008-2011 William Trevor King
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Lesser General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this program. If not, see
19 # <http://www.gnu.org/licenses/>.
21 """Enables looping until the user presses a key.
23 Uses the curses module to monitor for a single keypress, because other
24 methods of aquiring keyboard input generally require the user to press
27 Usual usage looks like the following, but leaving out the `test_mode`
28 option, which is used to get curses working with doctest's
29 stdin/stdout manipulations.
31 >>> c = CheckForKeypress('testing usual usage, press any key to stop loop...',
33 testing usual usage, press any key to stop loop...
35 Use `quiet_sleep` or your own sleep function instead of `_test_sleep`
36 if you need to reduce the loop rate.
39 ... while c.input() == None:
40 ... c.output('sleeping\\n')
43 ... c.cleanup() # doctest: +ELLIPSIS
48 An example with error catching is
50 >>> c = CheckForKeypress('testing error catching, wait for the error...',
52 testing error catching, wait for the error...
54 >>> class TestException (Exception):
57 ... while c.input() == None:
59 ... print >> _sys.stderr, 'testing error output'
60 ... raise TestException, 'testing error exception'
61 ... c.output('sleeping %d\\n' % i)
64 ... raise Exception, '_test_error_catching() failed!'
65 ... except TestException, e:
66 ... print 'caught exception:', e
74 caught exception: testing error exception
77 import curses as _curses # http://www.amk.ca/python/howto/curses/curses.html
78 import curses.ascii as _curses_ascii
79 from time import sleep as _sleep
81 import StringIO as _StringIO
94 class CheckForKeypress (object):
95 def __init__(self, prompt="Press any key to continue",
96 timeout_ms=0, test_mode=False):
97 self.test_mode = test_mode
98 self.last = None # last byte number read
99 self.lasta = None # last as an ASCII character
100 if test_mode == True:
104 # redirect stderr to a file, because exiting curses mode clears
105 # any error messages that had been printed to the screen
106 _sys.stderr = _StringIO.StringIO()
107 # initialize raw curses mode
109 self.stdscr = _curses.initscr()
112 self.stdscr.scrollok(1)
114 self.stdscr.addstr(0,0,prompt+'\n')
116 self.stdscr.nodelay(True)
118 self.stdscr.halfdelay(timeout_ms)
126 if self.test_mode or not self._active:
128 # return to standard terminal
129 while self.input() != None : # eat up the buffer
131 self.stdscr.scrollok(0)
135 # print any errors and restore stderr
136 contents = _sys.stderr.getvalue()
137 _sys.stderr = _sys.__stderr__
138 if len(contents) > 0:
139 print >> _sys.stderr, contents
143 if self.test_mode == True:
149 c = self.stdscr.getch()
154 self.lasta = _curses_ascii.unctrl(c)
164 def _output(self, string):
165 if self.test_mode == True:
168 #y,x = self.stdscr.getyx()
169 self.stdscr.addstr(string)
172 if self.test_mode == True:
174 self.stdscr.refresh()
176 def output(self, string):
181 if __name__ == '__main__':
182 c = CheckForKeypress('testing...')
186 while c.input() == None:
187 c.output('%d/%d (sleeping)\n' % (i, i_max))
190 raise Exception, "you didn't press a key!"