12

I wrote this code on to observe the event of a keydown motion. The problem appears to be that when this script is run, certain programs will crash this program, spitting out this error message:

TypeError: KeyboardSwitch() missing 8 required positional arguments: 'msg', 'vk_
code', 'scan_code', 'ascii', 'flags', 'time', 'hwnd', and 'win_name'

Some programs observed to crash are: Skype, Sublime Text 2

After a few trials at debugging it, the problem appears to be occurring on the final line but I can't seem to narrow it down. I also don't understand the meaning of KeyboardSwitch() as returned by the compiler...

I have also found that the program would alternately return this error message

Traceback (most recent call last):
  File "C:\Python34\lib\site-packages\pyHook\HookManager.py", line 351, in KeyboardSwitch
    return func(event)
  File "observe.py", line 6, in OnKeyboardEvent
    print ('MessageName:',event.MessageName)
TypeError: an integer is required (got type NoneType)

What is the cause and how do I fix this, especially since it only appears for only 1 in 2 keys pressed

import pyHook, pythoncom

def OnKeyboardEvent(event):
# Source: http://code.activestate.com/recipes/553270-using-pyhook-to-block-windows-keys/ 
    print ('MessageName:',event.MessageName)
    print ('Message:',event.Message)
    print ('Time:',event.Time)
    print ('Window:',event.Window)
    print ('WindowName:',event.WindowName)
    print ('Ascii:', event.Ascii, chr(event.Ascii))
    print ('Key:', event.Key)
    print ('KeyID:', event.KeyID)
    print ('ScanCode:', event.ScanCode)
    print ('Extended:', event.Extended)
    print ('Injected:', event.Injected)
    print ('Alt', event.Alt)
    print ('Transition', event.Transition)
    print ('---')

hooks_manager = pyHook.HookManager()
hooks_manager.KeyDown = OnKeyboardEvent
hooks_manager.HookKeyboard()
pythoncom.PumpMessages()

P.S. As a beginner, I'm not very familiar with the function of pythoncom and the online definitions appear to be rather vague. An explanation on the function of pythoncom and PumpMessages would be greatly appreciated.

Thanks

Kevin
  • 121
  • 1
  • 4

4 Answers4

9

I think the problem is that when pyHook gets called back by Windows, the first thing it does is get the window name for the window with focus.

PSTR win_name = NULL;
...
// grab the window name if possible
win_len = GetWindowTextLength(hwnd);
if(win_len > 0) {
  win_name = (PSTR) malloc(sizeof(char) * win_len + 1);
  GetWindowText(hwnd, win_name, win_len + 1);
}

So I think the problem here is that, even if GetWindowText is not returning wide characters, it can return non-ascii characters from an ANSI codepage. That won't fail, however, until we do this:

// pass the message on to the Python function
arglist = Py_BuildValue("(iiiiiiiz)", wParam, kbd->vkCode, kbd->scanCode, ascii,
                        kbd->flags, kbd->time, hwnd, win_name);

Here, because of the z in the format string, the data in the win_name variable is being converted to a unicode str with Py_BuildValue assuming it is ASCII. But it's not: and so it can trigger a UnicodeDecodeError. This then causes the arglist to be NULL and therefore your function to be called with no arguments.

So I'm not completely sure on the best fix here. But I just changed both bits of code to use wide characters and unicode instead of ascii, and rebuilt pyHook, and that seemed to fix it. I think it will only work in Python 3 versions, but for Python 2, I think the old pyHook still works anyway.

LPWSTR win_name = NULL;

...
// grab the window name if possible
win_len = GetWindowTextLengthW(hwnd);
if(win_len > 0) {
  win_name = (LPWSTR) malloc(sizeof(wchar_t) * win_len + 1);
  GetWindowTextW(hwnd, win_name, win_len + 1);
}

and

// pass the message on to the Python function
arglist = Py_BuildValue("(iiiiiiiu)", wParam, kbd->vkCode, kbd->scanCode, ascii,
                        kbd->flags, kbd->time, hwnd, win_name);

The problem occurs only with windows with non-ascii characters in their title: Skype is one.

strubbly
  • 3,347
  • 3
  • 24
  • 36
  • So this is a bug with PyHook. Did anyone report this to the project? – Martijn Pieters Feb 13 '16 at 08:56
  • How do I rebuild the python libary. See my full question [here](http://stackoverflow.com/questions/35471744/how-to-rebuild-a-python-module-libary) – staad Feb 18 '16 at 02:36
  • @MartijnPieters I've filed an issue on their [Sourceforge page](https://sourceforge.net/p/pyhook/bugs/7/). The last commit was in 2008 however, so I'm not sure what to expect. – erb Apr 12 '17 at 12:47
  • @erb Also I think the problem only affects Python 3 and PyHook was only ever developed for Python 2 - so bugs are to be expected, – strubbly Apr 12 '17 at 13:17
  • 1
    @strubbly You are right, but if a fix is this easy then it's worth integrating imo. FWIW, I found a fork which claims Python 3 support: https://pypi.python.org/pypi/PyHook3 – erb Apr 12 '17 at 14:16
0

If only 1 out of each 2 presses works, it's definetely a problem with missing return value. Try returning either True or False.

PiotrL
  • 307
  • 1
  • 2
  • 11
0

The TypeError: KeyboardSwitch() missing 8 required positional arguments: 'msg', 'vk_code', 'scan_code', 'ascii', 'flags', 'time', 'hwnd', and 'win_name' error message indicates that you are trying to call a function named KeyboardSwitch and have not provided values for all of the required arguments.

The error message lists the required arguments as 'msg', 'vk_code', 'scan_code', 'ascii', 'flags', 'time', 'hwnd', and 'win_name'. These are the names of the arguments that the KeyboardSwitch function expects to receive when it is called. You must provide a value for each of these arguments in the correct order when you call the function.

To fix this error, you will need to make sure that you are providing values for all of the required arguments when you call the KeyboardSwitch function. You may also want to check the documentation for the KeyboardSwitch function to make sure that you are using it correctly and understand what each of the required arguments represents.

-1

There's a pyhook for python3: https://github.com/Answeror/pyhook_py3k This bug has been fixed in this project.

Aka
  • 1