Search code examples
pythonkeyboard-events

change KeyboardInterrupt to 'enter'


I have the following code:

import time

def run_indefinitely():
    while True:
        # code to run indefinitely goes here
        print("Running indefinitely...")
        time.sleep(1)  

try:
    
        # Run the code indefinitely until Enter key is pressed
        run_indefinitely()            

except KeyboardInterrupt:
    print("Loop interrupted by user")

Is there a way to break out of the while loop by hitting 'enter' instead of ctrl+C ?


Solution

  • This is surprisingly tricky to do in Python. The technique involves spawning a worker thread to interrupt us later.

    Using python-readchar:

    import os
    import signal
    import sys
    import time
    from threading import Timer
    
    from readchar import readkey  # pip install readchar
    
    def wait_for(key, timeout):
        """wait `timeout` seconds for user to press `key`"""
        pid = os.getpid()
        sig = signal.CTRL_C_EVENT if os.name == "nt" else signal.SIGINT
        timer = Timer(timeout, lambda: os.kill(pid, sig))
        timer.start()
        while True:
            k = readkey()
            print(f"received {k!r}")
            if k == key:
                timer.cancel()  # cancel the timer
                print("breaking")
                break
    
    def run_indefinitely():
        while True:
            print("Running indefinitely...")
            try:
                wait_for(key="\n", timeout=1)
            except KeyboardInterrupt:
                continue
            else:
                break
    
    run_indefinitely()
    print("Loop interrupted by user")
    

    Using pynput:

    import os
    import signal
    import time
    
    from pynput import keyboard  # pip install pynput
    
    pid = os.getpid()
    
    def on_press(key):
        if key is keyboard.Key["enter"]:
            sig = signal.CTRL_C_EVENT if os.name == "nt" else signal.SIGINT
            os.kill(pid, sig)
    
    with keyboard.Listener(on_press=on_press) as k:
        try:
            for i in range(10):
                print("Running indefinitely...")
                time.sleep(1)
        except KeyboardInterrupt:
            pass
    
    print("Loop interrupted by user")