My code is as follows:
from tkinter import *
window = Tk()
print("What is 5 times 5?")
optionA = 25
optionB = 10
optionC = 3125
optionD = 55
print("A:", optionA)
print("B:", optionB)
print("C:", optionC)
print("D:", optionD)
def chooseA():
userAnswer = optionA
def chooseB():
userAnswer = optionB
def chooseC():
userAnswer = optionC
def chooseD():
userAnswer = optionD
window.bind("<Left>", chooseA)
window.bind("<Up>", chooseB)
window.bind("<Down>", chooseC)
window.bind("<Right>", chooseD)
if userAnswer == 25:
print("You correctly answered the question!")
My problem is that I get an error saying that userAnswer is not defined. This is because the code doesn't have a function that waits for the user to press one of the four arrow keys. Does anyone have a suggestion as to how to make the program wait for 1 of 4 key presses? Your answers are greatly appreciated!
(P.S. Using the keyboard.wait command from the keyboard module doesn't wait for multiple keys.)
Here is a solution, but perhaps not the best (there are probably modules just for this, but I like to practice coding with threads when I can).
from threading import Thread
from tkinter import *
def check_with_thread(): # make a function our thread can attach to
global userAnswer
local_check = userAnswer
while True:
if userAnswer != local_check: # user has selected a new value
if userAnswer == 25:
print("That's correct!")
break # have our thread break infinite loop and end it's execution
else:
print(userAnswer)
local_check = userAnswer # Make it able to detect changes in values
window = Tk() # Actually make a window! Why is this not in the OP???
print("What is 5 times 5?")
optionA = 25
optionB = 10
optionC = 3125
optionD = 55
print("A:", optionA)
print("B:", optionB)
print("C:", optionC)
print("D:", optionD)
def chooseA(event):
global userAnswer # we are modifying the global variable our thread is looking at
userAnswer = optionA
def chooseB(event):
global userAnswer
userAnswer = optionB
def chooseC(event): # the .bind() sends events, so these need a positional argument for them
global userAnswer
userAnswer = optionC
def chooseD(event):
global userAnswer
userAnswer = optionD
window.bind("<Left>", chooseA)
window.bind("<Up>", chooseB)
window.bind("<Down>", chooseC)
window.bind("<Right>", chooseD)
userAnswer = None
t = Thread(target=check_with_thread) # make a thread to check the input
t.start() # get our thread running before generating the window
window.mainloop()
How it works
First we define a function for our thread to execute (Threads are one of the methods that your program is able to literally do 2 things at once. This is needed because window.mainloop() will block our main thread of our script from doing anything else). We specify our function needs to read the global variable userAnswer with global userAnswer, otherwise it would expect that variable to be local (defined within the function, and forgotten when the function end unless it is returned). Then we initialize the local variable local_check to be whatever userAnswer happens to be when the function is called. Finally we enter an infinite loop. In this loop we will check if the user has updated their answer by comparing it to our previously created local_check. If the answer has been updated these values will be different! We will continue checking for new answers until they select the correct answer of 25 where we will call break to end our while loop (otherwise it would continue going forever). At this point we've reached the end of our function so the thread that is assigned to it will die off when it reaches this point. Next we will create userAnswers and assign it a value of None so that when our thread reaches the line local_check = userAnswer it will know what to do and won't encounter a NameError. Now all that is left is to make our thread. We do that with t = Thread(target=check_with_thread) and then immediately start it. The thread is now up and checking for changes to the input, and we can finally start window.mainloop() in the main thread of our script.
Why use a thread?
A thread is used because window.mainloop() is blocking. This means if we tried:
# stuff from previous script
window.mainloop()
thing = 5
print(thing)
We will not see anything printed until after the user closes our GUI. This means our bindings are no longer in effect, and cannot be used to change what the user has selected. Through using a thread we are able to have two infinite loops processing information simultaneously which is a very valuable trick to know for programmers (why I practice when I can)
Try adding:
window = tkinter.Tk()
st the top of your code, and
window.mainloop()
at the end. This will create a window that will stay open until you manually close it.
Related
Essentially, I have a GUI based program (Tkinter) and I am using multiple threads to update the values and do other stuff. With this, I have a global variable I want to share between threads, as one will update the changing value (thread1) and the other will use that same value to do its own thing in some loops in thread2. With thread2, I want this to run forever, constantly checking this value to the set number of <40 or >40. I've determined that the increase in memory comes from thread2, as commenting the thread out makes the program run without a significant memory increase. and it has nothing to do with the vlc objects, to me it seems like its the global variable or it being in an infinite loop.
Here is simplified code and the full code for thread2. I plan on running this on a rpi and over 2 minutes it gains about 1GB of consumed memory.
Any help is greatly appriciated. Thanks!!
(import vlc and others)
globalVar = 0.0
def Thread1():
global globalVar
#...modifies globalVar and GUI values
def Thread2():
nowPlaying = vlc.MediaPlayer("song1.mp3")
nowPlaying.play()
changePlaying = vlc.MediaPlayer("song2.mp3")
while True:
extra = 0
caseNum = random.randint(1,3)
if caseNum == 1:
eurobeat = vlc.MediaPlayer("song4.mp3")
elif caseNum == 2:
eurobeat = vlc.MediaPlayer("song5.mp3")
elif caseNum == 3:
eurobeat = vlc.MediaPlayer("song6.mp3")
while globalVar >= 40:
extra = extra + 1
nowPlaying.set_pause(1)
if (changePlaying.is_playing()) == 0:
changePlaying.play()
if extra > 2:
time.sleep(3)
time.sleep(3)
if globalVar < 40:
nowPlaying.set_pause(0)
changePlaying.stop()
changePlaying.stop()
thread1 = Thread(target=Thread1)
thread1.setDaemon(True)
thread1.start()
thread2 = Thread(target=Thread2)
thread2.setDaemon(True)
thread2.start()
(tkinter)
root.mainloop()
I participated in a local programming competition yesterday, where I was put on a team of four with members of varying skill levels. We were trying to make a text-based Zork style game, but since UI was one of the categories I was put on creating a GUI which I have no experience with in python. I used Tkinter and got everything mostly working inside the GUI itself, but can't figure out how to get the GUI to interact with the rest of the code.
I'm just including the relevant bits here, partially because the rest of the code is quite a mess, with no comments and lots of syntax errors, but I can post it if needed. Here's the code:
def pinput():
global e
player_input = e.get()
print(player_input)
def progress():
hallway_1()
def hallway_1():
global player_input
global prin
global e
prin.set("You are in a hallway. Yellow lockers line the sides of all walls and you see three doors. One leads into a Library, one to a History classroom, and one to a Math room. You can 1.) Search the hallway or 2.) Procede to one of the rooms.")
while player_input != "1" and player_input != "2": #Best guess at a way to get the code to wait for input, actually just causes code to freeze
pass
if player_input == "1": #Even if 1 is in the entry box beforehand, it never gets here
prin.set("You search through the lockers and find 1 health potion.\n Would you like to add it to your inventory? 1.) Yes 2.) No")
player_input = "999"
def player_attack():
global enemy_hp
enemy_hp -= player_strength
prin.set("You just attacked the " + enemy_name + "!")
def player_block():
global block
prin.set("You predict that your enemy is going to attack and decide to block")
block = 1
def player_use():
global player_item_use
global item_name
player_item_use = 100
prin.set("You decide to use one of your items. What do you use?")
while player_turn_input != 0 or 1 or 2 or 3 or 4 or 5 or 6 or 7 or 8 or 9 or 10 or 11 or 12 or 13 or 14 or 15 or 16 or 17 or 18 or 19 or 20 or 21 or 22 or 23 or 24 or 25 or 26:
player_item_use = e.get()
time.sleep(1)
item_name = Inventory[player_item_use]
item(item_name)
def run_away():
global player_hp
global lost_item_1
global lost_item_2
prin.set("You decide to run away from the " + enemy_name + "!\nThis causes you to lose 20 health points and two inventory items.")
player_hp -= 20
if backpack == True:
lost_item_1 = random.randint(1,27)
lost_item_2 = random.randint(1,27)
else:
lost_item_1 = random.randint(1,9)
lost_item_2 = random.randint(1,9)
RemoveInventory(lost_item_1)
RemoveInventory(lost_item_2)
library()
top = tk.Tk()
prin = tk.StringVar()
#path = "smalllibrary.png"
#tkimage = ImageTk.PhotoImage(Image.open(path))
#displayimage = tk.Label(top, image=tkimage).grid(row=0)
inv = tk.Text(top, width="24")
inv.grid(row=0, column=1)
for x in Inventory:
inv.insert("end", str(x) + str(invnum) + '\n')
invnum += 1
healthbar = tk.Label(top, text=("Health: " + str(player_hp))).grid(row=1, column=1)
text = tk.Label(top, bg="black", fg="white", textvariable=prin, justify="left", cursor="box_spiral").grid(row=1, sticky="w")
e = tk.Entry(top)
e.grid(row=2)
e.focus_set()
Attack = tk.Button(top, text ="Attack", activebackground="red", width="10", command = player_attack).grid(row=4, sticky="e")
Block = tk.Button(top, text ="Block", activebackground="red", width="10", command = player_block).grid(row=5, sticky="e")
Use = tk.Button(top, text ="Use Item", activebackground="red", width="10", command = player_use).grid(row=4, column=1, sticky="w")
Run = tk.Button(top, text ="Run", activebackground="red", width="10", command = run_away).grid(row=5, column=1, sticky="w")
Enter = tk.Button(top,text='Enter',command=pinput).grid(row=3)
Progress = tk.Button(top, text="Progress", activebackground="green",
prin.set("REDACTED")#This had my team's full names
top.mainloop()
So, there are a few problems. I added the "progress" button for testing purposes, ideally the game would start in Hallway 1. However, I couldn't figure out where to put the hallway_1() function for this to work. Before the top.mainloop() and the GUI wouldn't open. After it, and e.get() threw TCL errors.
So, I bound it to a button. However, now the code keeps getting stuck in the "while" loop even if 1 is inputted into the entry box before the code runs. I'm perplexed by this because Visual Studio reports player_input as being '1' in the Autos box, but it keeps running through the loop anyway.
You can't do a while loop like that in a GUI event handler. Until you return from the handler function, the GUI doesn't get to update its display, accept user input, or do anything else, which means player_input will never change once you get there. A handler function needs to do one thing, set up anything needed for future handlers, and return immediately.
It's hard to get your head around thinking in terms of the event loop and handler callbacks the first time you write a GUI, but it's absolutely essential; until you do, things seem bizarre and arbitrary.
So, the answer isn't to "wait for input", but to set up a handler that fires when that input is ready. (You can instead set up a handler on an after function so it fires every N milliseconds instead of firing on input, but that usually just makes things more complicated.)
One way to do this is to have the "Progress" button trigger "the next step", and keep track of some state that lets you determine what "the next step" is. An in fact, you already have that state: it's whether the player has already given correct input or not. So:
def pinput():
global player_input
player_input = e.get()
print(player_input)
def progress():
pinput()
if player_input != "1" and player_input != "2":
hallway_1_enter()
else:
hallway_1_doit()
def hallway_1_enter():
global player_input
global prin
global e
prin.set("You are in a hallway. Yellow lockers line the sides of all walls and you see three doors. One leads into a Library, one to a History classroom, and one to a Math room. You can 1.) Search the hallway or 2.) Procede to one of the rooms.")
def hallway_1_doit():
if player_input == "1": #Even if 1 is in the entry box beforehand, it never gets here
# etc.
This is obviously a bit of a clunky design, but it's the smallest change to your existing design that gets you past the first step. Once you get the hang of it, you should be able to improve it from there.
Also notice the global player_input I put in pinput. Your existing function didn't have that, so it was just creating a local variable with the same name, which then goes away immediately; the global never gets changed. Any function that wants to assign to a global needs the global statement.
I have a script that continually takes in text and outputs text (its a text based game)
I would like to run it through a tkinter GUI as opposed to the console
Python : Converting CLI to GUI
This question perfectly answers how to convert "print" into a GUI insert.
The problem is that my game obviously runs through a ton of loops, and that screws up the "app.mainloop()" because it either never runs (and then the GUI never shows up) or you run it first, and it doesn't let anything else run.
I suppose I could try and and stagger these loops somehow, but that seems very hackish. I could also try to modify my entire codebase to run inside the app.mainloop(), but what I really think I need is multiple threads. Problem is, I have no idea how to make that work.
There are a few other questions, but they either don't work or don't make much sense:
Tkinter with multiple threads
Run process with realtime output to a Tkinter GUI
Thanks.
Edit: extremely simplified code:
def moveNorth():
print('You have moved north')
def interpreter(command):
if command == 'go north':
moveNorth()
else:
print('invalid command')
def listener():
playerchoice = sys.stdin.readline().strip()
return playerchoice
if __name__ == '__main__':
print('Welcome')
while playing:
interpreter(listener())
I think you might be making it more complicated than it needs to be.
For Tkinter at least it is very simple change console interactions into a GUI interaction instead.
The simplest example I can give is to use an Entry field for user input and a Text widget for the output.
Here is a simple example of a console based game being moved to a GUI using Tkinter.
Console number guessing game:
import random
print("simple game")
print("-----------")
random_num = random.randint(1, 5)
print(random_num)
x = True
while x == True:
#Input for user guesses.
guess = input("Guess a number between 1 and 5: ")
if guess == str(random_num):
#Print answer to console.
print("You win!")
x = False
else:
print("Try again!")
Here is the Tkinter GUI example of the same game:
import tkinter as tk
import random
root = tk.Tk()
entry_label = tk.Label(root, text = "Guess a number between 1 and 5: ")
entry_label.grid(row = 0, column = 0)
#Entry field for user guesses.
user_entry = tk.Entry(root)
user_entry.grid(row = 0, column = 1)
text_box = tk.Text(root, width = 25, height = 2)
text_box.grid(row = 1, column = 0, columnspan = 2)
text_box.insert("end-1c", "simple guessing game!")
random_num = random.randint(1, 5)
def guess_number(event = None):
#Get the string of the user_entry widget
guess = user_entry.get()
if guess == str(random_num):
text_box.delete(1.0, "end-1c") # Clears the text box of data
text_box.insert("end-1c", "You win!") # adds text to text box
else:
text_box.delete(1.0, "end-1c")
text_box.insert("end-1c", "Try again!")
user_entry.delete(0, "end")
# binds the enter widget to the guess_number function
# while the focus/cursor is on the user_entry widget
user_entry.bind("<Return>", guess_number)
root.mainloop()
As you can see there is a bit more code for the GUI but most of that is the GUI design.
The main part that you need to change is the use of entry vs input for your answers and the use of insert vs print for your response. The rest is really just design stuff.
If you want to keep the questions on a continuous nature you can update the label with a new question or you could even use tkinters askstring function for each new question. There are many options.
the main thing is getting the value of the user answer, using that answer to test with the question, then printing the results to the text box.
I'm in the middle of making a small game involving hacking into people's computers, and stealing files and money in order to complete missions. Here is the code as of now:
#SICCr4k2: Broke
#
#
#
#Remember whenever you are printing a random ip address to add the "." in between each part of the ip (each random number)
## LAST LEFT ON HERE: MAKE BUTTONS FOR NODES
## MAKE FILES FOR NULL'S NODE
## SET THE CORRECT PLACEMENTS FOR ALL THE BUTTONS
## nullMain referenced before assignment
## make it so that you send a message through the prompt to get their ip, then it automatically puts the ip in the nodes
## window. Like you send the person a message, and then it gets the ip and puts it in the nodes window
## take away the buttons in the nodes window, just at labels where it points to the host's ip address.
import random
import time
import sys
import os
import tkinter as tk
from tkinter import *
#def nodes():
# nodeWindow = tk.Tk()
# frame = tk.Frame(nodeWindow, width=700, height=400)
# frame.grid_propagate(0)
# frame.grid()
# nodeWindow.title("||| Nodes |||")
# nullIp = tk.Label(nodeWindow, text="Ip: 221.153.52.216")
# nullIp.grid(row=0, column=0)
# nullMain = tk.Button(nodeWindow, text="Null", function=nullMainCallback())
# nullMain.config(height=1, width=100)
# nullMain.grid(row=0, column=0)
# def nullMainCallback():
# nullMain.destroy()
# nullIp = tk.Label(nodeWindow, text="Ip: 221.153.52.216")
# nullIp.grid(row=0, column=0)
#def commands():
def numbers():
number1 = random.randint(1, 99)
number2 = random.randint(1, 99)
print(number1)
if number1 != number2:
numbers()
if number1 == number2:
os.system('cls')
def ips():
nullIp = ('18.279.332')
def getIp():
x = random.randint(1, 222)
if x == 127:
x += 1
return '{}.{}.{}.{}'.format(
x,
random.randint(0, 255),
random.randint(0, 255),
random.randint(0, 255))
def commandInput():
CommandInput = input(">>> ")
if CommandInput == ("myNodes()"):
nodes()
else:
commandInput()
commandInput()
def usernameCreation():
username = input(">>> ")
print("'" + username + "' is that correct?")
usernameInput = input(">>> ")
if usernameInput == ("yes"):
print("Okay...")
if usernameInput ==("no"):
usernameCreation()
def game():
def tutorial():
print('Hello.')
time.sleep(3)
print('Welcome back.')
time.sleep(3)
print('How was it?')
time.sleep(3)
print('Being hacked for the first time?')
time.sleep(3)
print("You're probably wondering who I am.")
time.sleep(5)
print("Well, my name is Null.")
time.sleep(3)
print("Only because I am well known for nothing.")
time.sleep(3)
print("Other than not being alive.")
time.sleep(3)
os.system('cls')
print("First thing's first, what shall I call you?")
usernameCreation()
print("Let's give you a bit of movement.")
time.sleep(3)
print("""The first thing you will want to do would be to connect to my computer, but
to do that, you have to find my ip address. Here. I just uploaded new software to your computer.""")
time.sleep(3)
print("""You will now be able to access my ip, nad many other's with a simple command. The command is
getIp(). Input that command below, but inside the parenthesis, you type in the screen name. For instance: getIp(Null).
type that command in to get my ip.""")
input(">>> ")
if ("getIp(Null)"):
numbers()
print("""My ip was just added to your nodes, which you can access by typing myNodes().""")
game()
I just want to note that when I run the program, it doesn't list any errors or anything, it just doesn't execute at all... Any ideas????
You define the function tutorial inside game (which you shouldn't really do – there's no point in defining it that way) but never call tutorial.
Inside of game you want to call tutorial:
def game():
def tutorial():
# code for tutorial
tutorial()
A better way to structure your code, however, is to use a main method (which is the standard way to start the execution of a program` and keep every other function separate. There's no need to nest functions as you've done.
So, for example:
def main():
tutorial()
# all other function definitions
def tutorial():
# code for tutorial
if __name__ == "__main__":
main()
You never call tutorial() although you shouldn't nest functions like this.
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: ")