Reputation: 408
I created a thread for a keylogger that logs in parallel to another thread that produces some sounds ( I want to catch reaction times).
Unfortunately, the thread never finishes although i invoke killKey() and "invoked killkey()" is printed.
I allways get an thread.isActive() = true from this thread.
class KeyHandler(threading.Thread):
hm = pyHook.HookManager()
def __init__(self):
threading.Thread.__init__(self)
def OnKeyboardCharEvent(self,event):
print 'Key:', event.Key
if event.Key=='E':
...
return True
def killKey(self):
KeyHandler.hm.UnhookKeyboard()
ctypes.windll.user32.PostQuitMessage(0)
print "invoked killkey()"
def run(self):
print "keyHandlerstartetrunning"
KeyHandler.hm.KeyDown = self.OnKeyboardCharEvent
KeyHandler.hm.HookKeyboard()
#print "keyboardhooked"
pythoncom.PumpMessages()
to be more precise, ctypes.windll.user32.PostQuitMessage(0) does nothing
I would favor an external timeout to invoke killKey(), respective ctypes.windll.user32.PostQuitMessage(0) in this thread.
Upvotes: 2
Views: 871
Reputation: 408
I guess pbackup's solution is fine. Just to conclude I found a solution by simply sending a key myself instead of waiting for the user to input. It's proably not the best but was the fastest an goes parallel in my timing thread with the other timing routines.
STOP_KEY_HANDLER = True
# send key to kill handler - not pretty but works
for hwnd in get_hwnds_for_pid (GUIWINDOW_to_send_key_to.pid):
win32gui.PostMessage (hwnd, win32con.WM_KEYDOWN, win32con.VK_F5, 0)
# sleep to make sure processing is done
time.sleep(0.1)
# kill window
finished()
Upvotes: 1
Reputation: 5939
PostQuitMessage has to be posted from the same thread. To do so you need to introduce a global variable STOP_KEY_HANDLER
. If you want to quit then just set global STOP_KEY_HANDLER = True
from any thread you want and it will quit with the next keystroke. Your key handler has to run on the main thread.
STOP_KEY_HANDLER = False
def main():
pass # here do all you want
#bla bla
global STOP_KEY_HANDLER
STOP_KEY_HANDLER = True # This will kill KeyHandler
class KeyHandler:
hm = pyHook.HookManager()
def OnKeyboardCharEvent(self,event):
if STOP_KEY_HANDLER:
self.killKey()
print 'Key:', event.Key
if event.Key=='E':
pass
return True
def killKey(self):
global STOP_KEY_HANDLER
if not STOP_KEY_HANDLER:
STOP_KEY_HANDLER = True
return None
KeyHandler.hm.UnhookKeyboard()
ctypes.windll.user32.PostQuitMessage(0)
print "invoked killkey()"
def _timeout(self):
if self.timeout:
time.sleep(self.timeout)
self.killKey()
def run(self, timeout=False):
print "keyHandlerstartetrunning"
self.timeout = timeout
threading.Thread(target=self._timeout).start()
KeyHandler.hm.KeyDown = self.OnKeyboardCharEvent
KeyHandler.hm.HookKeyboard()
#print "keyboardhooked"
pythoncom.PumpMessages()
k=KeyHandler()
threading.Thread(target=main).start()
k.run(timeout=100) # You can specify the timeout in seconds or you can kill it directly by setting STOP_KEY_HANDLER to True.
Upvotes: 2