Python wait x secs for a key and continue execution if not pressed
Asked Answered
P

5

13

I'm looking for a code snippet/sample which performs the following:

  • Display a message like "Press any key to configure or wait X seconds to continue"
  • Wait, for example, 5 seconds and continue execution, or enter a configure() subroutine if a key is pressed.
Perihelion answered 30/5, 2011 at 18:20 Comment(0)
T
25

If you're on Unix/Linux then the select module will help you.

import sys
from select import select

print "Press any key to configure or wait 5 seconds..."
timeout = 5
rlist, wlist, xlist = select([sys.stdin], [], [], timeout)

if rlist:
    print "Config selected..."
else:
    print "Timed out..."

If you're on Windows, then look into the msvcrt module. (Note this doesn't work in IDLE, but will in cmd prompt)

import sys, time, msvcrt

timeout = 5
startTime = time.time()
inp = None

print "Press any key to configure or wait 5 seconds... "
while True:
    if msvcrt.kbhit():
        inp = msvcrt.getch()
        break
    elif time.time() - startTime > timeout:
        break

if inp:
    print "Config selected..."
else:
    print "Timed out..."
Thiamine answered 30/5, 2011 at 18:47 Comment(2)
about the windows part: I'd strongly suggest to insert a time.sleep(0.5) at the end of the while-loop, because otherwise the process will waste quite some processor time while waiting...Grubby
For a cross-platform solution (same code works on macOS/Linux/Windows) check here: https://mcmap.net/q/904035/-shorten-sleep-time-on-user-inputMoultrie
C
2

Python doesn't have any standard way to catch this, it gets keyboard input only through input() and raw_input().

If you really want this you could use Tkinter or pygame to catch the keystrokes as "events". There are also some platform-specific solutions like pyHook. But if it's not absolutely vital to your program, I suggest you make it work another way.

Congregational answered 30/5, 2011 at 18:52 Comment(0)
B
2

If you combine time.sleep, threading.Thread, and sys.stdin.read you can easily wait for a specified amount of time for input and then continue.

t = threading.Thread(target=sys.stdin.read(1) args=(1,))
t.start()
time.sleep(5)
t.join()
Bicarb answered 31/7, 2015 at 19:43 Comment(0)
J
1

Here's how I did it:

import threading
import time
import sys


class MyThread(threading.Thread):
    def __init__(self, threadID, name, counter, f):
        super().__init__()
        self.threadID = threadID
        self.name = name
        self.counter = counter
        self.func = f

    def run(self):
        self.func()

class KeyboardMonitor:
    def __init__(self):
        # Setting a boolean flag is atomic in Python.
        # It's hard to imagine a boolean being 
        # anything else, with or without the GIL.
        # If inter-thread communication is anything more complicated than
        # a couple of flags, you should replace low level variables with 
        # a thread safe buffer.
        self.keepGoing = True

    def wait4KeyEntry(self):
        while self.keepGoing:
            s = input("Type q to quit: ")
            if s == "q":
                self.keepGoing = False

    def mainThread(self, f, *args, **kwargs):
        """Pass in some main function you want to run, and this will run it
        until keepGoing = False. The first argument of function f must be 
        this class, so that that function can check the keepGoing flag and 
        quit when keepGoing is false."""
        keyboardThread = MyThread(1, "keyboard_thread", 0, self.wait4KeyEntry)
        keyboardThread.start()
        while self.keepGoing:
            f(self, *args, **kwargs)

def main(keyMonitorInst, *args, **kwargs):
    while keyMonitorInst.keepGoing:
        print("Running again...")
        time.sleep(1)

if __name__ == "__main__":
    uut = KeyboardMonitor()
    uut.mainThread(main)

Rather than make a blocking call time out, my approach is to start a thread that waits for the user to enter input, while another thread does something else. The two processes communicate through a small number of atomic operations: in this case, setting a boolean flag. For anything more complicated than atomic operations, obviously you should replace the atomic variable with a threadsafe buffer of some kind.

Jim answered 10/6, 2020 at 19:2 Comment(0)
F
0

Based on idea from https://note.nkmk.me/en/python-while-usage/, and from elsewhere.

Program will stop if CTRL-C is pressed withing 5 seconds, otherwise will continue.

Works on Python 3, does not need any external (pip install ...) libraries.

Should work on Linux and Windows.

If you wish for program to check user input more often, comment print function before time.sleep(), and change time.sleep(1) to time.sleep(0.1). You would probably use top print function, too.

import time

def fn_wait_for_user_input(seconds_to_wait,message):
    #print('waiting for',seconds_to_wait, 'seconds ...' )
    print (message, seconds_to_wait)
    start_time = time.time()
    try:
        while (time.time() - start_time ) < seconds_to_wait:
            '''
            parenthesis, from inside out:
            time.time() which is current time    - start time, if it is more than 10 seconds, time's up :)
            int ; so we don't count 10 -1,02=8; instead we will count 10-1 = 9, meaning 9 seconds remaining, not 8
            seconds to wait - everything else ; so we get reverse count from 10 to 1, not from 1 to 10
            '''
            print("%d" %  (  seconds_to_wait -   int(  (time.time() - start_time )   )    )    ) 
            time.sleep(1)
        print('No keypress detected.')
        return 1 #no interrupt after x seconds
    except KeyboardInterrupt:
        print('Keypress detected - exiting.')
        return 0 #interrupted
        
    


if fn_wait_for_user_input(5, "program will continue if you don't press CTRL-C within seconds:" )  == 1:
    print('continuing ....')
else:
    print('not continuing.')



note:

use this to print all in one line:

print("%d" %  (  seconds_to_wait -   int(  (time.time() - start_time )   )    ), end=' ', flush=True   ) #needs flush inside loop...buffered

use this to continue inside a function:

if fn_wait_for_user_input(5, "program will continue if you don't press CTRL-C within seconds:" )  == 1:
    #print('continuing ....')
    pass
else:
    #print('not continuing.')
    #exit function
    return

Foist answered 22/9, 2023 at 18:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.