I have a main GUI app made out of Tkinter, which includes a button called "start" , which when pressed initiates the pynput.keyboard.listener
thread .
Its listens to the keystrokes all right .
But when I terminate the app (by clicking 'x') , the keystrokes listener thread also terminates .
I want the thread to be persistent and keep listening , even when the GUI is closed .
Here is the code .
counter.py
import pynput.keyboard
import threading
from threading import Event
import ctypes
class KeypressCounter(threading.Thread):
def __init__(self):
# import pynput.keyboard
# import threading
# from threading import Event
# import ctypes
super().__init__()
self.key_count = 0
self.stop_event = Event()
def run(self):
listener = pynput.keyboard.Listener(on_press=self.on_press,daemon=False)
listener.start()
def on_press(self, key):
self.key_count += 1
if key == pynput.keyboard.Key.esc:
print("esc pressed")
self.on_endsession()
print("counter:",self.key_count)
def on_endsession(self):
with open("key_count.txt", "w") as f:
print("writing to file")
f.write(str(self.key_count))
self.stop_event.set()
def main():
keypress_counter = KeypressCounter()
keypress_counter.start()
while True:
if keypress_counter.stop_event.is_set():
break
if __name__ == "__main__":
main()
The tkinter frame , app.py
from tkinter import *
from counter import KeypressCounter
def start() :
KeyCounter = KeypressCounter()
KeyCounter.start()
window_size = '1200x600'
# Create the root window
window = Tk()
window.geometry(window_size)
keyBoardFrame = Frame(window,width=100,height=100,bg='green')
button = Button(keyBoardFrame,text='start',bg='red',fg='white',command = start)
button.grid(row=0,column=0,sticky='nsew')
window.mainloop()
The counter is written to key_count.txt before it terminates(don't know how ) .
And after window is closed, nothing gets written to the key_count.txt .
but I want the thread to keep listening to all the keystrokes in the background .
Since the listener is a daemon thread, it will be terminated when the main thread terminates.
You can change the listener to a non-daemon thread so that the main thread will wait for it after closing the main window. Also KeypressCounter
does not need to inherit from threading.Thread
in this case:
class KeypressCounter:
def __init__(self):
self.key_count = 0
def start(self):
# change listener to self.listener so that it can be accessed in other class methods
self.listener = pynput.keyboard.Listener(on_press=self.on_press)
self.listener.daemon = False # set it to a non-daemon thread
self.listener.start()
def on_press(self, key):
self.key_count += 1
if key == pynput.keyboard.Key.esc:
print("esc pressed")
self.on_endsession()
print("counter:",self.key_count)
def on_endsession(self):
with open("key_count.txt", "w") as f:
print("writing to file")
f.write(str(self.key_count))
# terminate the listener
self.listener.stop()