Related
I am working on a self challenge of making a cash register in Python, and I'm looking to use the keyboard module for inputting values instead of typing them into the console. However, I think the keyboard module command I'm using to detect key presses is not becoming false after pressing the key, meaning the number I just typed is being inserted again and again. What is the proper command to use? Here is the code to test out the input before incorporating it into my main code:
import keyboard
running =True
price=""
while running:
if keyboard.is_pressed("1"):
price+="1"
if keyboard.is_pressed("2"):
price+="2"
if keyboard.is_pressed("3"):
price+="3"
if keyboard.is_pressed("4"):
price+="4"
if keyboard.is_pressed("5"):
price+="5"
if keyboard.is_pressed("6"):
price+="6"
if keyboard.is_pressed("7"):
price+="7"
if keyboard.is_pressed("8"):
price+="8"
if keyboard.is_pressed("9"):
price+="9"
if keyboard.is_pressed("0"):
price+="0"
if keyboard.is_pressed("Enter"):
running=False
subtotal=int(price)
print(subtotal)
subtotal=float(subtotal)/100
print("Subtotal: {}".format(subtotal))
There are usually many different ways to code something. Some are better than others. In a problem that is based on keyboard input, like your cash register/adding machine project, I would go with an event-driven approach. Your sample code represents a polling approach. It can work, but it may not be as efficient.
I've never used the keyboard module before, but I did some quick research and came up with the below program, which may give you guidance. Every time a key in the keyboard is pressed, the key_pressed() routine is triggered. Digits are stored, and the Enter key causes an addition and then clearing of the stored digits.
import keyboard
sin = ""
val = 0.0
def key_pressed(e, *a, **kw):
global sin, val
# print(e, a, kw)
k = e.name
if k in "0123456789":
sin += k
elif k == 'enter':
val += float(sin)/100.0
print("Entered: " + sin)
print('Value: ', val)
sin = ""
keyboard.on_press(key_pressed)
I took a look at the documentation located here https://github.com/boppreh/keyboard.
I ran and tested this code on python 3.9
import keyboard
from functools import partial
num = ""
def add(i):
global num
num += str(i)
print(num, end='\r')
for i in range(10): # numbers 0...9
keyboard.add_hotkey(str(i), partial(add, i)) # add hotkeys
keyboard.wait('enter') # block process until "ENTER" is pressed
print("\nNum:{}".format(num))
You could additionally unhook the hotkeys by calling keyboard.unhook_all_hotkeys() after grabbing the number. I imagine you could wait on "+" and "-" if you wanted to implement addition and subtraction of numbers.
I like the last example from this snippet from the Github docs that I ended up using:
import keyboard
# Don't do this! This will call `print('space')` immediately then fail when the key is actually pressed.
#keyboard.add_hotkey('space', print('space was pressed'))
# Do this instead
keyboard.add_hotkey('space', lambda: print('space was pressed'))
# or this
def on_space():
print('space was pressed')
keyboard.add_hotkey('space', on_space)
# or this
while True:
# Wait for the next event.
event = keyboard.read_event()
if event.event_type == keyboard.KEY_DOWN and event.name == 'space':
print('space was pressed')
I'm using raw_input in Python to interact with user in shell.
c = raw_input('Press s or n to continue:')
if c.upper() == 'S':
print 'YES'
It works as intended, but the user has to press enter in the shell after pressing 's'. Is there a way to accomplish what I need from an user input without needing to press enter in the shell? I'm using *nixes machines.
Under Windows, you need the msvcrt module, specifically, it seems from the way you describe your problem, the function msvcrt.getch:
Read a keypress and return the
resulting character. Nothing is echoed
to the console. This call will block
if a keypress is not already
available, but will not wait for Enter
to be pressed.
(etc -- see the docs I just pointed to). For Unix, see e.g. this recipe for a simple way to build a similar getch function (see also several alternatives &c in the comment thread of that recipe).
Actually in the meantime (almost 10 years from the start of this thread) a cross-platform module named pynput appeared.
Below a first cut - i.e. that works with lowercase 's' only.
I have tested it on Windows but I am almost 100% positive that it should work on Linux.
from pynput import keyboard
print('Press s or n to continue:')
with keyboard.Events() as events:
# Block for as much as possible
event = events.get(1e6)
if event.key == keyboard.KeyCode.from_char('s'):
print("YES")
Python does not provide a multiplatform solution out of the box.
If you are on Windows you could try msvcrt with:
import msvcrt
print 'Press s or n to continue:\n'
input_char = msvcrt.getch()
if input_char.upper() == 'S':
print 'YES'
curses can do that as well :
import curses, time
def input_char(message):
try:
win = curses.initscr()
win.addstr(0, 0, message)
while True:
ch = win.getch()
if ch in range(32, 127):
break
time.sleep(0.05)
finally:
curses.endwin()
return chr(ch)
c = input_char('Do you want to continue? y/[n]')
if c.lower() in ['y', 'yes']:
print('yes')
else:
print('no (got {})'.format(c))
To get a single character, I have used getch, but I don't know if it works on Windows.
Instead of the msvcrt module you could also use WConio:
>>> import WConio
>>> ans = WConio.getkey()
>>> ans
'y'
On a side note, msvcrt.kbhit() returns a boolean value determining if any key on the keyboard is currently being pressed.
So if you're making a game or something and want keypresses to do things but not halt the game entirely, you can use kbhit() inside an if statement to make sure that the key is only retrieved if the user actually wants to do something.
An example in Python 3:
# this would be in some kind of check_input function
if msvcrt.kbhit():
key = msvcrt.getch().decode("utf-8").lower() # getch() returns bytes data that we need to decode in order to read properly. i also forced lowercase which is optional but recommended
if key == "w": # here 'w' is used as an example
# do stuff
elif key == "a":
# do other stuff
elif key == "j":
# you get the point
I know this is old, but the solution wasn't good enough for me.
I need the solution to support cross-platform and without installing any external Python packages.
My solution for this, in case anyone else comes across this post
Reference: https://github.com/unfor19/mg-tools/blob/master/mgtools/get_key_pressed.py
from tkinter import Tk, Frame
def __set_key(e, root):
"""
e - event with attribute 'char', the released key
"""
global key_pressed
if e.char:
key_pressed = e.char
root.destroy()
def get_key(msg="Press any key ...", time_to_sleep=3):
"""
msg - set to empty string if you don't want to print anything
time_to_sleep - default 3 seconds
"""
global key_pressed
if msg:
print(msg)
key_pressed = None
root = Tk()
root.overrideredirect(True)
frame = Frame(root, width=0, height=0)
frame.bind("<KeyRelease>", lambda f: __set_key(f, root))
frame.pack()
root.focus_set()
frame.focus_set()
frame.focus_force() # doesn't work in a while loop without it
root.after(time_to_sleep * 1000, func=root.destroy)
root.mainloop()
root = None # just in case
return key_pressed
def __main():
c = None
while not c:
c = get_key("Choose your weapon ... ", 2)
print(c)
if __name__ == "__main__":
__main()
If you can use an external library, blessed (cross platform) can do do this quite easily:
from blessed import Terminal
term = Terminal()
with term.cbreak(): # set keys to be read immediately
print("Press any key to continue")
inp = term.inkey() # wait and read one character
Note that while inside the with block, line editing capabilities of the terminal will be disabled.
Documentation for cbreak, inkey, and an example with inkey.
Standard library solution for Unix-like operating systems (including Linux):
def getch():
import sys, termios
fd = sys.stdin.fileno()
orig = termios.tcgetattr(fd)
new = termios.tcgetattr(fd)
new[3] = new[3] & ~termios.ICANON
new[6][termios.VMIN] = 1
new[6][termios.VTIME] = 0
try:
termios.tcsetattr(fd, termios.TCSAFLUSH, new)
return sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, orig)
This works by putting the terminal into non-canonical input mode before reading from the terminal.
Alternative solution that does not echo the user's input (e.g. if the user presses z, z will not appear on screen):
def getch():
import sys, termios, tty
fd = sys.stdin.fileno()
orig = termios.tcgetattr(fd)
try:
tty.setcbreak(fd) # or tty.setraw(fd) if you prefer raw mode's behavior.
return sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, orig)
Usage example:
print('Press s or n to continue: ', end='', flush=True)
c = getch()
print()
if c.upper() == 'S':
print('YES')
use readchar:
import readchar
key = readchar.readkey()
if key == "a":
print("text")
https://pypi.org/project/readchar/ to webpage
in python, is there a way to, while waiting for a user input, count time so that after, say 30 seconds, the raw_input() function is automatically skipped?
The signal.alarm function, on which #jer's recommended solution is based, is unfortunately Unix-only. If you need a cross-platform or Windows-specific solution, you can base it on threading.Timer instead, using thread.interrupt_main to send a KeyboardInterrupt to the main thread from the timer thread. I.e.:
import thread
import threading
def raw_input_with_timeout(prompt, timeout=30.0):
print(prompt, end=' ')
timer = threading.Timer(timeout, thread.interrupt_main)
astring = None
try:
timer.start()
astring = input(prompt)
except KeyboardInterrupt:
pass
timer.cancel()
return astring
this will return None whether the 30 seconds time out or the user explicitly decides to hit control-C to give up on inputting anything, but it seems OK to treat the two cases in the same way (if you need to distinguish, you could use for the timer a function of your own that, before interrupting the main thread, records somewhere the fact that a timeout has happened, and in your handler for KeyboardInterrupt access that "somewhere" to discriminate which of the two cases occurred).
Edit: I could have sworn this was working but I must have been wrong -- the code above omits the obviously-needed timer.start(), and even with it I can't make it work any more. select.select would be the obvious other thing to try but it won't work on a "normal file" (including stdin) in Windows -- in Unix it works on all files, in Windows, only on sockets.
So I don't know how to do a cross-platform "raw input with timeout". A windows-specific one can be constructed with a tight loop polling msvcrt.kbhit, performing a msvcrt.getche (and checking if it's a return to indicate the output's done, in which case it breaks out of the loop, otherwise accumulates and keeps waiting) and checking the time to time out if needed. I cannot test because I have no Windows machine (they're all Macs and Linux ones), but here the untested code I would suggest:
import msvcrt
import time
def raw_input_with_timeout(prompt, timeout=30.0):
print(prompt, end=' ')
finishat = time.time() + timeout
result = []
while True:
if msvcrt.kbhit():
result.append(msvcrt.getche())
if result[-1] == '\r': # or \n, whatever Win returns;-)
return ''.join(result)
time.sleep(0.1) # just to yield to other processes/threads
else:
if time.time() > finishat:
return None
The OP in a comment says he does not want to return None upon timeout, but what's the alternative? Raising an exception? Returning a different default value? Whatever alternative he wants he can clearly put it in place of my return None;-).
If you don't want to time out just because the user is typing slowly (as opposed to, not typing at all!-), you could recompute finishat after every successful character input.
I found a solution to this problem in a blog post. Here's the code from that blog post:
import signal
class AlarmException(Exception):
pass
def alarmHandler(signum, frame):
raise AlarmException
def nonBlockingRawInput(prompt='', timeout=20):
signal.signal(signal.SIGALRM, alarmHandler)
signal.alarm(timeout)
try:
text = raw_input(prompt)
signal.alarm(0)
return text
except AlarmException:
print '\nPrompt timeout. Continuing...'
signal.signal(signal.SIGALRM, signal.SIG_IGN)
return ''
Please note: this code will only work on *nix OSs.
The input() function is designed to wait for the user to enter something (at least the [Enter] key).
If you are not dead set to use input(), below is a much lighter solution using tkinter. In tkinter, dialog boxes (and any widget) can be destroyed after a given time.
Here is an example :
import tkinter as tk
def W_Input (label='Input dialog box', timeout=5000):
w = tk.Tk()
w.title(label)
W_Input.data=''
wFrame = tk.Frame(w, background="light yellow", padx=20, pady=20)
wFrame.pack()
wEntryBox = tk.Entry(wFrame, background="white", width=100)
wEntryBox.focus_force()
wEntryBox.pack()
def fin():
W_Input.data = str(wEntryBox.get())
w.destroy()
wSubmitButton = tk.Button(w, text='OK', command=fin, default='active')
wSubmitButton.pack()
# --- optionnal extra code in order to have a stroke on "Return" equivalent to a mouse click on the OK button
def fin_R(event): fin()
w.bind("<Return>", fin_R)
# --- END extra code ---
w.after(timeout, w.destroy) # This is the KEY INSTRUCTION that destroys the dialog box after the given timeout in millisecondsd
w.mainloop()
W_Input() # can be called with 2 parameter, the window title (string), and the timeout duration in miliseconds
if W_Input.data : print('\nYou entered this : ', W_Input.data, end=2*'\n')
else : print('\nNothing was entered \n')
from threading import Timer
def input_with_timeout(x):
def time_up():
answer= None
print('time up...')
t = Timer(x,time_up) # x is amount of time in seconds
t.start()
try:
answer = input("enter answer : ")
except Exception:
print('pass\n')
answer = None
if answer != True: # it means if variable have somthing
t.cancel() # time_up will not execute(so, no skip)
input_with_timeout(5) # try this for five seconds
As it is self defined... run it in command line prompt , I hope you will get the answer
read this python doc you will be crystal clear what just happened in this code!!
A curses example which takes for a timed math test
#!/usr/bin/env python3
import curses
import curses.ascii
import time
#stdscr = curses.initscr() - Using curses.wrapper instead
def main(stdscr):
hd = 100 #Timeout in tenths of a second
answer = ''
stdscr.addstr('5+3=') #Your prompt text
s = time.time() #Timing function to show that solution is working properly
while True:
#curses.echo(False)
curses.halfdelay(hd)
start = time.time()
c = stdscr.getch()
if c == curses.ascii.NL: #Enter Press
break
elif c == -1: #Return on timer complete
break
elif c == curses.ascii.DEL: #Backspace key for corrections. Could add additional hooks for cursor movement
answer = answer[:-1]
y, x = curses.getsyx()
stdscr.delch(y, x-1)
elif curses.ascii.isdigit(c): #Filter because I only wanted digits accepted
answer += chr(c)
stdscr.addstr(chr(c))
hd -= int((time.time() - start) * 10) #Sets the new time on getch based on the time already used
stdscr.addstr('\n')
stdscr.addstr('Elapsed Time: %i\n'%(time.time() - s))
stdscr.addstr('This is the answer: %s\n'%answer)
#stdscr.refresh() ##implied with the call to getch
stdscr.addstr('Press any key to exit...')
curses.wrapper(main)
under linux one could use curses and getch function, its non blocking.
see getch()
https://docs.python.org/2/library/curses.html
function that waits for keyboard input for x seconds (you have to initialize a curses window (win1) first!
import time
def tastaturabfrage():
inittime = int(time.time()) # time now
waitingtime = 2.00 # time to wait in seconds
while inittime+waitingtime>int(time.time()):
key = win1.getch() #check if keyboard entry or screen resize
if key == curses.KEY_RESIZE:
empty()
resize()
key=0
if key == 118:
p(4,'KEY V Pressed')
yourfunction();
if key == 107:
p(4,'KEY K Pressed')
yourfunction();
if key == 99:
p(4,'KEY c Pressed')
yourfunction();
if key == 120:
p(4,'KEY x Pressed')
yourfunction();
else:
yourfunction
key=0
This is for newer python versions, but I believe it will still answer the question. What this does is it creates a message to the user that the time is up, then ends the code. I'm sure there's a way to make it skip the input rather than completely end the code, but either way, this should at least help...
import sys
import time
from threading import Thread
import pyautogui as pag
#imports the needed modules
xyz = 1 #for a reference call
choice1 = None #sets the starting status
def check():
time.sleep(15)#the time limit set on the message
global xyz
if choice1 != None: # if choice1 has input in it, than the time will not expire
return
if xyz == 1: # if no input has been made within the time limit, then this message
# will display
pag.confirm(text = 'Time is up!', title = 'Time is up!!!!!!!!!')
sys.exit()
Thread(target = check).start()#starts the timer
choice1 = input("Please Enter your choice: ")
I'm using raw_input in Python to interact with user in shell.
c = raw_input('Press s or n to continue:')
if c.upper() == 'S':
print 'YES'
It works as intended, but the user has to press enter in the shell after pressing 's'. Is there a way to accomplish what I need from an user input without needing to press enter in the shell? I'm using *nixes machines.
Under Windows, you need the msvcrt module, specifically, it seems from the way you describe your problem, the function msvcrt.getch:
Read a keypress and return the
resulting character. Nothing is echoed
to the console. This call will block
if a keypress is not already
available, but will not wait for Enter
to be pressed.
(etc -- see the docs I just pointed to). For Unix, see e.g. this recipe for a simple way to build a similar getch function (see also several alternatives &c in the comment thread of that recipe).
Actually in the meantime (almost 10 years from the start of this thread) a cross-platform module named pynput appeared.
Below a first cut - i.e. that works with lowercase 's' only.
I have tested it on Windows but I am almost 100% positive that it should work on Linux.
from pynput import keyboard
print('Press s or n to continue:')
with keyboard.Events() as events:
# Block for as much as possible
event = events.get(1e6)
if event.key == keyboard.KeyCode.from_char('s'):
print("YES")
Python does not provide a multiplatform solution out of the box.
If you are on Windows you could try msvcrt with:
import msvcrt
print 'Press s or n to continue:\n'
input_char = msvcrt.getch()
if input_char.upper() == 'S':
print 'YES'
curses can do that as well :
import curses, time
def input_char(message):
try:
win = curses.initscr()
win.addstr(0, 0, message)
while True:
ch = win.getch()
if ch in range(32, 127):
break
time.sleep(0.05)
finally:
curses.endwin()
return chr(ch)
c = input_char('Do you want to continue? y/[n]')
if c.lower() in ['y', 'yes']:
print('yes')
else:
print('no (got {})'.format(c))
To get a single character, I have used getch, but I don't know if it works on Windows.
Instead of the msvcrt module you could also use WConio:
>>> import WConio
>>> ans = WConio.getkey()
>>> ans
'y'
On a side note, msvcrt.kbhit() returns a boolean value determining if any key on the keyboard is currently being pressed.
So if you're making a game or something and want keypresses to do things but not halt the game entirely, you can use kbhit() inside an if statement to make sure that the key is only retrieved if the user actually wants to do something.
An example in Python 3:
# this would be in some kind of check_input function
if msvcrt.kbhit():
key = msvcrt.getch().decode("utf-8").lower() # getch() returns bytes data that we need to decode in order to read properly. i also forced lowercase which is optional but recommended
if key == "w": # here 'w' is used as an example
# do stuff
elif key == "a":
# do other stuff
elif key == "j":
# you get the point
I know this is old, but the solution wasn't good enough for me.
I need the solution to support cross-platform and without installing any external Python packages.
My solution for this, in case anyone else comes across this post
Reference: https://github.com/unfor19/mg-tools/blob/master/mgtools/get_key_pressed.py
from tkinter import Tk, Frame
def __set_key(e, root):
"""
e - event with attribute 'char', the released key
"""
global key_pressed
if e.char:
key_pressed = e.char
root.destroy()
def get_key(msg="Press any key ...", time_to_sleep=3):
"""
msg - set to empty string if you don't want to print anything
time_to_sleep - default 3 seconds
"""
global key_pressed
if msg:
print(msg)
key_pressed = None
root = Tk()
root.overrideredirect(True)
frame = Frame(root, width=0, height=0)
frame.bind("<KeyRelease>", lambda f: __set_key(f, root))
frame.pack()
root.focus_set()
frame.focus_set()
frame.focus_force() # doesn't work in a while loop without it
root.after(time_to_sleep * 1000, func=root.destroy)
root.mainloop()
root = None # just in case
return key_pressed
def __main():
c = None
while not c:
c = get_key("Choose your weapon ... ", 2)
print(c)
if __name__ == "__main__":
__main()
If you can use an external library, blessed (cross platform) can do do this quite easily:
from blessed import Terminal
term = Terminal()
with term.cbreak(): # set keys to be read immediately
print("Press any key to continue")
inp = term.inkey() # wait and read one character
Note that while inside the with block, line editing capabilities of the terminal will be disabled.
Documentation for cbreak, inkey, and an example with inkey.
Standard library solution for Unix-like operating systems (including Linux):
def getch():
import sys, termios
fd = sys.stdin.fileno()
orig = termios.tcgetattr(fd)
new = termios.tcgetattr(fd)
new[3] = new[3] & ~termios.ICANON
new[6][termios.VMIN] = 1
new[6][termios.VTIME] = 0
try:
termios.tcsetattr(fd, termios.TCSAFLUSH, new)
return sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, orig)
This works by putting the terminal into non-canonical input mode before reading from the terminal.
Alternative solution that does not echo the user's input (e.g. if the user presses z, z will not appear on screen):
def getch():
import sys, termios, tty
fd = sys.stdin.fileno()
orig = termios.tcgetattr(fd)
try:
tty.setcbreak(fd) # or tty.setraw(fd) if you prefer raw mode's behavior.
return sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, orig)
Usage example:
print('Press s or n to continue: ', end='', flush=True)
c = getch()
print()
if c.upper() == 'S':
print('YES')
use readchar:
import readchar
key = readchar.readkey()
if key == "a":
print("text")
https://pypi.org/project/readchar/ to webpage
in python, is there a way to, while waiting for a user input, count time so that after, say 30 seconds, the raw_input() function is automatically skipped?
The signal.alarm function, on which #jer's recommended solution is based, is unfortunately Unix-only. If you need a cross-platform or Windows-specific solution, you can base it on threading.Timer instead, using thread.interrupt_main to send a KeyboardInterrupt to the main thread from the timer thread. I.e.:
import thread
import threading
def raw_input_with_timeout(prompt, timeout=30.0):
print(prompt, end=' ')
timer = threading.Timer(timeout, thread.interrupt_main)
astring = None
try:
timer.start()
astring = input(prompt)
except KeyboardInterrupt:
pass
timer.cancel()
return astring
this will return None whether the 30 seconds time out or the user explicitly decides to hit control-C to give up on inputting anything, but it seems OK to treat the two cases in the same way (if you need to distinguish, you could use for the timer a function of your own that, before interrupting the main thread, records somewhere the fact that a timeout has happened, and in your handler for KeyboardInterrupt access that "somewhere" to discriminate which of the two cases occurred).
Edit: I could have sworn this was working but I must have been wrong -- the code above omits the obviously-needed timer.start(), and even with it I can't make it work any more. select.select would be the obvious other thing to try but it won't work on a "normal file" (including stdin) in Windows -- in Unix it works on all files, in Windows, only on sockets.
So I don't know how to do a cross-platform "raw input with timeout". A windows-specific one can be constructed with a tight loop polling msvcrt.kbhit, performing a msvcrt.getche (and checking if it's a return to indicate the output's done, in which case it breaks out of the loop, otherwise accumulates and keeps waiting) and checking the time to time out if needed. I cannot test because I have no Windows machine (they're all Macs and Linux ones), but here the untested code I would suggest:
import msvcrt
import time
def raw_input_with_timeout(prompt, timeout=30.0):
print(prompt, end=' ')
finishat = time.time() + timeout
result = []
while True:
if msvcrt.kbhit():
result.append(msvcrt.getche())
if result[-1] == '\r': # or \n, whatever Win returns;-)
return ''.join(result)
time.sleep(0.1) # just to yield to other processes/threads
else:
if time.time() > finishat:
return None
The OP in a comment says he does not want to return None upon timeout, but what's the alternative? Raising an exception? Returning a different default value? Whatever alternative he wants he can clearly put it in place of my return None;-).
If you don't want to time out just because the user is typing slowly (as opposed to, not typing at all!-), you could recompute finishat after every successful character input.
I found a solution to this problem in a blog post. Here's the code from that blog post:
import signal
class AlarmException(Exception):
pass
def alarmHandler(signum, frame):
raise AlarmException
def nonBlockingRawInput(prompt='', timeout=20):
signal.signal(signal.SIGALRM, alarmHandler)
signal.alarm(timeout)
try:
text = raw_input(prompt)
signal.alarm(0)
return text
except AlarmException:
print '\nPrompt timeout. Continuing...'
signal.signal(signal.SIGALRM, signal.SIG_IGN)
return ''
Please note: this code will only work on *nix OSs.
The input() function is designed to wait for the user to enter something (at least the [Enter] key).
If you are not dead set to use input(), below is a much lighter solution using tkinter. In tkinter, dialog boxes (and any widget) can be destroyed after a given time.
Here is an example :
import tkinter as tk
def W_Input (label='Input dialog box', timeout=5000):
w = tk.Tk()
w.title(label)
W_Input.data=''
wFrame = tk.Frame(w, background="light yellow", padx=20, pady=20)
wFrame.pack()
wEntryBox = tk.Entry(wFrame, background="white", width=100)
wEntryBox.focus_force()
wEntryBox.pack()
def fin():
W_Input.data = str(wEntryBox.get())
w.destroy()
wSubmitButton = tk.Button(w, text='OK', command=fin, default='active')
wSubmitButton.pack()
# --- optionnal extra code in order to have a stroke on "Return" equivalent to a mouse click on the OK button
def fin_R(event): fin()
w.bind("<Return>", fin_R)
# --- END extra code ---
w.after(timeout, w.destroy) # This is the KEY INSTRUCTION that destroys the dialog box after the given timeout in millisecondsd
w.mainloop()
W_Input() # can be called with 2 parameter, the window title (string), and the timeout duration in miliseconds
if W_Input.data : print('\nYou entered this : ', W_Input.data, end=2*'\n')
else : print('\nNothing was entered \n')
from threading import Timer
def input_with_timeout(x):
def time_up():
answer= None
print('time up...')
t = Timer(x,time_up) # x is amount of time in seconds
t.start()
try:
answer = input("enter answer : ")
except Exception:
print('pass\n')
answer = None
if answer != True: # it means if variable have somthing
t.cancel() # time_up will not execute(so, no skip)
input_with_timeout(5) # try this for five seconds
As it is self defined... run it in command line prompt , I hope you will get the answer
read this python doc you will be crystal clear what just happened in this code!!
A curses example which takes for a timed math test
#!/usr/bin/env python3
import curses
import curses.ascii
import time
#stdscr = curses.initscr() - Using curses.wrapper instead
def main(stdscr):
hd = 100 #Timeout in tenths of a second
answer = ''
stdscr.addstr('5+3=') #Your prompt text
s = time.time() #Timing function to show that solution is working properly
while True:
#curses.echo(False)
curses.halfdelay(hd)
start = time.time()
c = stdscr.getch()
if c == curses.ascii.NL: #Enter Press
break
elif c == -1: #Return on timer complete
break
elif c == curses.ascii.DEL: #Backspace key for corrections. Could add additional hooks for cursor movement
answer = answer[:-1]
y, x = curses.getsyx()
stdscr.delch(y, x-1)
elif curses.ascii.isdigit(c): #Filter because I only wanted digits accepted
answer += chr(c)
stdscr.addstr(chr(c))
hd -= int((time.time() - start) * 10) #Sets the new time on getch based on the time already used
stdscr.addstr('\n')
stdscr.addstr('Elapsed Time: %i\n'%(time.time() - s))
stdscr.addstr('This is the answer: %s\n'%answer)
#stdscr.refresh() ##implied with the call to getch
stdscr.addstr('Press any key to exit...')
curses.wrapper(main)
under linux one could use curses and getch function, its non blocking.
see getch()
https://docs.python.org/2/library/curses.html
function that waits for keyboard input for x seconds (you have to initialize a curses window (win1) first!
import time
def tastaturabfrage():
inittime = int(time.time()) # time now
waitingtime = 2.00 # time to wait in seconds
while inittime+waitingtime>int(time.time()):
key = win1.getch() #check if keyboard entry or screen resize
if key == curses.KEY_RESIZE:
empty()
resize()
key=0
if key == 118:
p(4,'KEY V Pressed')
yourfunction();
if key == 107:
p(4,'KEY K Pressed')
yourfunction();
if key == 99:
p(4,'KEY c Pressed')
yourfunction();
if key == 120:
p(4,'KEY x Pressed')
yourfunction();
else:
yourfunction
key=0
This is for newer python versions, but I believe it will still answer the question. What this does is it creates a message to the user that the time is up, then ends the code. I'm sure there's a way to make it skip the input rather than completely end the code, but either way, this should at least help...
import sys
import time
from threading import Thread
import pyautogui as pag
#imports the needed modules
xyz = 1 #for a reference call
choice1 = None #sets the starting status
def check():
time.sleep(15)#the time limit set on the message
global xyz
if choice1 != None: # if choice1 has input in it, than the time will not expire
return
if xyz == 1: # if no input has been made within the time limit, then this message
# will display
pag.confirm(text = 'Time is up!', title = 'Time is up!!!!!!!!!')
sys.exit()
Thread(target = check).start()#starts the timer
choice1 = input("Please Enter your choice: ")