Pythoncom在挂钩到某些应用程序时,按键时会崩溃

12

我编写了这段代码来观察按下键盘按键的事件。问题似乎是,当运行此脚本时,特定程序将导致此程序崩溃,并输出以下错误消息:

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

一些经常崩溃的程序有:Skype,Sublime Text 2。

经过几次尝试调试后,问题似乎出现在最后一行,但我似乎无法缩小范围。我也不明白编译器返回的KeyboardSwitch()的含义...

我还发现该程序会交替返回此错误消息

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)

是什么原因导致的?如何修复它,特别是因为只有每按两个键中的1个才会出现?

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. 作为一个初学者,我对 pythoncom 的功能不是很熟悉,而在线的定义似乎相当模糊。若能解释一下 pythoncom 和 PumpMessages 的功能,将不胜感激。

谢谢

4个回答

9

我认为问题在于当Windows回调pyHook时,它首先要做的就是获取拥有焦点窗口的窗口名称。

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);
}

我认为这里的问题在于,即使GetWindowText没有返回宽字符,它仍然可以从ANSI代码页返回非ASCII字符。这不会失败,直到我们执行以下操作:

// 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);

在这里,由于格式字符串中的“z”,假设它是ASCII码,Py_BuildValuewin_name变量中的数据转换为Unicode str。但实际上它不是ASCII码,因此会触发一个UnicodeDecodeError。这会导致arglist为空,从而导致没有参数调用您的函数。
所以我不确定最佳解决方案是什么。但我刚刚更改了代码的两个部分,使用了宽字符和Unicode代替ASCII,并重新构建了pyHook,这似乎解决了问题。我认为它只适用于Python 3版本,但对于Python 2,我认为旧版的pyHook仍然可以工作。
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);
}

并且

// 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);

该问题仅出现在标题包含非ASCII字符的Windows窗口上:Skype是其中之一。


这是PyHook的一个bug。有人向项目报告了吗? - Martijn Pieters
我该如何重建Python库?请查看我的完整问题这里 - staad
@MartijnPieters 我已在他们的Sourceforge页面上提交了一个问题。然而,最后一次提交是在2008年,所以我不确定会发生什么。 - erb
@erb 我认为这个问题只影响Python 3,而PyHook只开发用于Python 2 - 所以应该预料到会有错误。 - strubbly
1
@strubbly 你是对的,但如果修复如此容易,那么我认为它值得集成。顺便说一句,我找到了一个声称支持Python 3的分支:https://pypi.python.org/pypi/PyHook3 - erb

0
如果每2次按键只有1次有效,那么肯定是缺少返回值的问题。尝试返回True或False。

0

TypeError: KeyboardSwitch()缺少8个必需的位置参数:'msg'、'vk_code'、'scan_code'、'ascii'、'flags'、'time'、'hwnd'和'win_name'错误信息表明,您试图调用一个名为KeyboardSwitch的函数,但没有为所有必需的参数提供值。

错误消息将所需的参数列出为'msg'、'vk_code'、'scan_code'、'ascii'、'flags'、'time'、'hwnd'和'win_name'。这些是KeyboardSwitch函数在调用时期望接收的参数名称。当您调用该函数时,必须按正确的顺序为每个参数提供一个值。

要解决此错误,您需要确保在调用KeyboardSwitch函数时为所有必需的参数提供值。您还可以查看KeyboardSwitch函数的文档,以确保正确使用它并了解每个必需参数代表的含义。


实际上,我说的是:下载KeyboardSwitch库。就这样 :) - Frostube Frostubes

-1

你能同时添加与该Bug相关的链接吗? - v.coder
我不再遇到这个错误了,但是现在我得到的是进程以退出代码-1073740771(0xC000041D)结束。 - Heriberto Juarez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接