I am trying to make a simple timer which counts up until it is interrupted by keyboard input.
right now I am using CTRL+C to stop the timer, but I would like to do something more simple like hitting space or enter or "any key". I hear this can be done with the threading module, but after several attempts I clearly do not know what I am doing with that.
this is my current code:
def countup():
try:
a=0
for i in range(1000000) :
print i,'\r',
time.sleep(1)
except KeyboardInterrupt:
Z = raw_input("restart timer?" )
if Z == "Y" or Z == "y" :
countup()
Using thread and terminal capabilities you can write (press any key to stop):
import thread
import time
def read_key():
import termios
import sys
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
new = termios.tcgetattr(fd)
new[3] &= ~(termios.ICANON | termios.ECHO) # c_lflags
c = None
try:
termios.tcsetattr(fd, termios.TCSANOW, new)
c = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSANOW, old)
return c
def input_thread():
read_key()
thread.interrupt_main()
def countup():
try:
thread.start_new_thread(input_thread, ())
for i in range(1000000):
print i
time.sleep(1)
except KeyboardInterrupt:
Z = raw_input("restart timer? ")
if Z == 'y' or Z == 'Y':
countup()
Let's clarify a bit:
thread.start_new_thread()
create a new thread using input_thread()
as start function. While thread.interrupt_main()
raise KeyboardInterrupt
in the main thread.
termios.tcgetattr()
return the current terminal attribute. ~termios.ICANON
unset the canonical mode and ~termios.ECHO
prevent input print then termios.tsetattr()
act the change.
Alternatively, on Windows, getch()
from msvcrt can be use in place of read_key()
def input_thread():
msvcrt.getch()
thread.interrupt_main()
Reference
- Thread module
- Termios module
- Msvcrt module
There are two problems with your code as it stands:
- You aren't checking for keyboard input during the for loop, so the program isn't going to notice if you type random characters to stdin.
- KeyboardInterrupt exceptions are thrown specifically when the interrupt key (i.e. Ctrl-C) is pressed.
The problem is that you need to attempt to read from stdin, but not wait until input appears there if there isn't any to begin with. This page provides a good description of how to do this.
Based on the link above, this code should do the trick to make the countup stop if you hit enter:
import sys
import select
import time
def countup():
i = 0
while True:
print i
i += 1
time.sleep(1)
while sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
line = sys.stdin.readline()
if line:
r = raw_input("Restart?")
if r.lower() == "y":
countdown()
else:
break
countup()