pythoncom crashes on KeyDown when used hooked to certain applications

后端 未结 3 403
自闭症患者
自闭症患者 2020-11-30 06:52

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

相关标签:
3条回答
  • 2020-11-30 07:24

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

    0 讨论(0)
  • 2020-11-30 07:39

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

    0 讨论(0)
  • 2020-11-30 07:41

    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.

    0 讨论(0)
提交回复
热议问题