pyHook键盘记录器线程未结束

2 投票
2 回答
866 浏览
提问于 2025-04-18 05:39

我创建了一个线程,用来记录按键,同时还有另一个线程在播放声音(我想测量反应时间)。

不过,那个记录按键的线程一直没有结束,尽管我调用了killKey(),而且“调用了killKey()”这句话也被打印出来了。

我总是得到这个线程的状态是active(活跃)的,也就是thread.isActive() = true。

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()

更具体一点,ctypes.windll.user32.PostQuitMessage(0) 似乎没有任何作用。

我更倾向于使用一个外部的超时机制来调用killKey(),或者在这个线程中调用ctypes.windll.user32.PostQuitMessage(0)。

2 个回答

1

我觉得pbackup的解决方案不错。总结一下,我找到了一种方法,就是自己发送一个键,而不是等用户输入。这可能不是最好的办法,但在我的计时线程中,它是最快的,并且可以和其他计时程序同时进行。

    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()
2

要使用PostQuitMessage这个功能,必须在同一个线程中发送。为此,你需要引入一个全局变量 STOP_KEY_HANDLER。如果你想退出程序,只需在任何线程中将全局变量 STOP_KEY_HANDLER = True 设置为真,这样在下一个按键时程序就会退出。你的按键处理程序必须在主线程中运行。

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.

撰写回答