【问题标题】:pythoncom crashes on KeyDown when used hooked to certain applications与某些应用程序挂钩时,pythoncom 在 KeyDown 上崩溃
【发布时间】:2014-10-02 08:04:34
【问题描述】:

我写了这段代码来观察按键动作的事件。问题似乎是当这个脚本运行时,某些程序会崩溃这个程序,吐出这个错误信息:

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)

这是什么原因以及如何解决这个问题,特别是因为它只出现在 2 个按键中的 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()

附:作为初学者,我对pythoncom的功能不是很熟悉,网上的定义也比较模糊。非常感谢对 pythoncom 和 PumpMessages 功能的解释。

谢谢

【问题讨论】:

    标签: python python-3.x pyhook pythoncom


    【解决方案1】:

    我认为问题在于,当 pyHook 被 Windows 回调时,它所做的第一件事就是获取具有焦点的窗口的窗口名称。

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

    这里,由于格式字符串中的zwin_name 变量中的数据被转换为str 的unicode Py_BuildValue,假设它是ASCII。但它不是:所以它可以触发UnicodeDecodeError。这会导致 arglist 变为 NULL,因此您的函数将在没有参数的情况下被调用。

    所以我不完全确定这里的最佳解决方案。但是我只是将这两个代码都更改为使用宽字符和 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 字符的窗口才会出现此问题:Skype 就是其中之一。

    【讨论】:

    • 所以这是 PyHook 的一个错误。有人向项目报告此情况吗?
    • 如何重建 python 库。查看我的完整问题here
    • @MartijnPieters 我已经在他们的Sourceforge page 上提交了一个问题。然而,最后一次提交是在 2008 年,所以我不确定会发生什么。
    • @erb 另外,我认为这个问题只会影响 Python 3,而 PyHook 只是为 Python 2 开发的 - 所以会出现错误,
    • @strubbly 你是对的,但如果修复如此简单,那么值得集成 imo。 FWIW,我找到了一个声称支持 Python 3 的分支:pypi.python.org/pypi/PyHook3
    【解决方案2】:

    如果每 2 次印刷机中只有 1 次有效,则绝对是缺少返回值的问题。尝试返回 True 或 False。

    【讨论】:

      【解决方案3】:

      python3 有一个 pyhook:https://github.com/Answeror/pyhook_py3k 此项目已修复此错误。

      【讨论】:

      • 能把bug相关的链接也加进去吗
      • 我不再得到这个错误,而是我得到了 Process finished with exit code -1073740771 (0xC000041D)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-28
      • 2013-05-13
      • 2023-04-04
      • 2022-12-01
      • 1970-01-01
      • 2014-10-21
      相关资源
      最近更新 更多