Search code examples
pythonsignals

Stopping a python program when an arbitrary key was pressed while the program is running


I recently got to know about the python module signal. With that, we can capture a SIGINT and do what we want after capturing it. I used it as below. In that case I am just using SIGINT to print that program is going to be stopped and stop the program.

import signal  
import os
import time

def signalHandler(signalnumb, frame):  
    print("Signal Number:", signalnumb, " Frame: ", frame)
    print('Exiting the program...')
    os._exit(0)
 
signal.signal(signal.SIGINT, signalHandler)
 
c=0
# Loop infinite times using the while(1) which is always true
while 1:
    print(c)
    #sleep for 1 seconds using the sleep() function in time 
    time.sleep(1)
    c=c+1

Now I want to give any signal from keyboard(for example pressing 'q') and as soon as signal was recieved, the python program should be stopped. Has anyone got some experience on how to do that? Any other method rather than using signal module (for example using multithreading) is accepted.

Edit1- Later I tried to use pynput module as suggested in one of a similar kind of question. For sure I have done a mistake. It doesn't work as I expected. It means with a key press, I couldn't stop the for loop from running.

from pynput import keyboard
import time

def on_press(key):
    for i in range(100):
        print(i)
        time.sleep(1)
        if key == keyboard.Key.esc:
            return False  # stop listener
        try:
            k = key.char  # single-char keys
        except:
            k = key.name  # other keys
        if k in ['1', '2', 'left', 'right']:  # keys of interest
            # self.keys.append(k)  # store it in global-like variable
            print('Key pressed: ' + k)
            return False  # stop listener; remove this if want more keys

listener = keyboard.Listener(on_press=on_press)
listener.start()  # start to listen on a separate thread
listener.join()  # remove if main thread is polling self.keyspython

Can someone point out how to do it using pynput in correct way?


Solution

  • After carefully understanding about the threads and pynput module, I managed to stop a for loop (or any program which runs as a separate thread) using a key press callback.

    from pynput import keyboard
    import os
    import threading
    import time
    
    loop_running = False
    
    def on_press(key):
        print(dir(key))
        global loop_running
        #if key == keyboard.Key.delete and not loop_running:
        if ('char' in dir(key)) and (key.char == 's') and (not loop_running):
            t=threading.Thread(target=start_loop)
            t.start()
            
        #elif key==keyboard.Key.tab:   #if this is used, the attributes related to 'key' will be changed. you can see them since I have used a print(dir(key))
        elif key.char == 'q':
            loop_running=False
            
    
    def start_loop():
        global loop_running
        loop_running = True
        for i in range(100):
            if not loop_running:
                os._exit(0)                          
                
            print(i)
            time.sleep(1)
            
    with keyboard.Listener(on_press=on_press) as listner:
        listner.join()