Search code examples
pythonkeypressprompt

Python: detect specific key press and prompt the user


I need to print out sentence "Hello World" every 10 seconds. However, if the user either 'c' or 'Enter', the program should stop printing the sentence and prompt the user to provide with the another sentence. The user-provided sentence is checked and if the sentence contains any digits, a message shows up: "cannot contain digits". Otherwise a message shows up: "correct sentence". After displaying either of the messages, the program continues printing "Hello World".

Here is the code I have strated with. Any hints on how to continue further would be greatly appreciated. Thanks!

import threading

def looping():
    threading.Timer(10.0, looping).start()
    print("Hello World!")

looping()

Solution

  • From my understanding of your assignment's instructions, it looks like you're on the right track with using a timer to print "Hello World"! I'd like to upvote Irmen de Jong's comment on your question with regard to the statement "threads and console input/output don't work nicely together", since I've experienced this myself in C programming.

    Once you have the timer going, the text it prints to the screen shouldn't have an effect on responding to keyboard input. If it's really required to respond directly to a keypress of 'c' (not followed by 'Enter', as one would normally have to do when reading input from the keyboard with input()), I recommend following one of the solutions in Python method for reading keypress? to figure out how you would like to implement that.

    EDIT: Implementing a solution using a thread-based timer is a bit more tricky than I thought.

    As you may have found in your research on this problem, the threading.Timer object has both start() and stop() methods that you can use to control the execution of individual thread timers if you've saved a reference to the timer in a variable (e.g. doing my_timer = threading.Timer(10.0, looping) then calling my_timer.start() to start the timer). If you do this, you may be able to call my_timer.stop() to pause the looping, provided you've kept a proper reference to the current timer instance that you need to stop at that point in time.

    To make things a bit easier, I chose to create a global variable PAUSE_LOOPING that, when set to False, will stop a new timer instance from being started when looping is called, thereby halting all further repetitions of the function until PAUSE_LOOPING is set back to True and looping() is called again:

    import threading
    from msvcrt import getch
    
    PAUSE_LOOPING = False
    
    def looping():
        global PAUSE_LOOPING
        if not PAUSE_LOOPING:
            threading.Timer(10.0, looping).start()
            print("Hello World!")
    
    looping()
    
    while True:
        # key = ord(getch())
        # if key == 13:  # Enter
        #     PAUSE_LOOPING = True
        input_string = input()
        if input_string == "":
            PAUSE_LOOPING = True
        else:
            PAUSE_LOOPING = False
            looping()
    

    Commented out in the last code block is one way to grab a key press directly (without needing to press the 'Enter' key as is required by input()) taken from the stackoverflow question I linked to earlier in my answer. This should work as long as you're using Python for Windows (so you have the MS VC++ runtime library msvcrt installed), but to make the script stop when pressing 'Enter' you can use the standard input() function. In my example, typing any other string of characters before pressing 'Enter' will resume looping after it's been paused.

    NOTE: Beware of using Python's IDLE to run this code. It won't work. Instead, you must run it from the command line.