Как реализовать Windows-хук клавиатуры в расширении C для Python - PullRequest
0 голосов
/ 18 июня 2019

Я хочу создать расширение ac для python, в котором есть одна функция, доступная для python, которая принимает функцию обратного вызова в качестве параметра.Эта функция c установит глобальный хук в окнах для отслеживания нажатий клавиш, а клавиатурный крючок вызовет функцию python для обработки при нажатии клавиши.

Обратный вызов будет работать только в том случае, если есть функция окна сообщения между местом выполнения строки PyObject_CallObject и концом этого метода.Я использовал окно сообщения, чтобы увидеть, что делает код, так как у меня нет командной строки.Программа python завершается с кодом выхода -1073741819 без функции окна сообщения.Почему это происходит?Также не работает клавиатурный хук, я не уверен, нужен ли цикл сообщений или нет, просто я попробовал еще одну вещь.

//the c extension
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <windows.h>
#include <io.h>

PyObject* call(char theKey);
static PyObject* setHook(PyObject* dummy, PyObject *args);
static PyObject* callback = NULL;
static PyObject* SpamError;
HHOOK keyboardHook;

static PyMethodDef callPythonMethods[] = {
    {"setHook",  setHook, METH_VARARGS,
     "Set the hook and callback method"},
    {NULL, NULL, 0, NULL}        /* Sentinel */
};

static struct PyModuleDef callPythonModule = {
    PyModuleDef_HEAD_INIT,
    "CallPython",
    NULL,
    -1,
    callPythonMethods
};

PyMODINIT_FUNC
PyInit_CallPython(void)
{
    PyObject* m;
    m = PyModule_Create(&callPythonModule);
    if (m == NULL)
        return NULL;

    SpamError = PyErr_NewException("spam.error", NULL, NULL);
    Py_INCREF(SpamError);
    PyModule_AddObject(m, "error", SpamError);
    return m;
}

int
main(int argc, char* argv[])
{
    wchar_t* program = Py_DecodeLocale(argv[0], NULL);
    if (program == NULL) {
        fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
        exit(1);
    }

    /* Add a built-in module, before Py_Initialize */
    PyImport_AppendInittab("CallPython", PyInit_CallPython);

    /* Pass argv[0] to the Python interpreter */
    Py_SetProgramName(program);

    /* Initialize the Python interpreter.  Required. */
    Py_Initialize();

    /* Optionally import the module; alternatively,
       import can be deferred until the embedded script
       imports it. */
    PyImport_ImportModule("CallPython");

        PyMem_RawFree(program);
    return 0;
}


LRESULT CALLBACK keyBoardHookProc(
    _In_ int    code,
    _In_ WPARAM wParam,
    _In_ LPARAM lParam)
{
    MessageBox(NULL, "well it worked", "Logging", MB_OK);
    PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
    char* test = "it worked";
    // If key is being pressed
    if (wParam == WM_KEYDOWN) {
        switch (p->vkCode) {
            // Invisible Keys
        default:
            //call((char*)tolower(p->vkCode));
            call(test);
        }
    }

    return CallNextHookEx(keyboardHook, code, wParam, lParam);
}



static PyObject* setHook(PyObject* dummy, PyObject* args) {

    PyObject* result = NULL;
    PyObject* temp;

    if (PyArg_ParseTuple(args, "O:set_callback", &temp)) {
        if (!PyCallable_Check(temp)) {
            PyErr_SetString(PyExc_TypeError, "parameter must be callable");
            return NULL;
        }
        Py_XINCREF(temp);
        Py_XDECREF(callback);
        callback = temp;

        Py_INCREF(Py_None);
        result = Py_None;
    }

    keyboardHook = SetWindowsHookEx(
        WH_KEYBOARD_LL,
        keyBoardHookProc,
        NULL,
        0
    );
    MessageBox(NULL, "we loggin boyz", "Logging", MB_OK);
    char* fine = "i";

    call(fine);
    MessageBox(NULL, "called fine", "Logging", MB_OK);

    MSG msg;
    while (!GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
        MessageBox(NULL, "got and dispatched messages", "Logging", MB_OK);
    }
    return result;
}

PyObject* call(char* theKey)
{
    PyObject* arglist;
    PyObject* result;

    arglist = Py_BuildValue("(s)", theKey);
    result = PyObject_CallObject(callback, arglist);


    Py_DECREF(arglist);

    if (result == NULL) {
        MessageBox(NULL, "result is null :/", "Logging", MB_OK);
        return NULL;
    }
    Py_DECREF(result);
}
//the python script
from CallPython import setHook
import threading


def call_from_C(theKey):
    print("oy ello there mate " + theKey)


def startHook():
    setHook((call_from_C))
    while True:
        None

print("creating thread")
thread = threading.Thread(target=startHook, args=())
print("starting thread...")
thread.start()
print("started the logging thread")

print("hmm")
while True:
    None

call (отлично);должен вызывать функцию обратного вызова в Python правильно с или без функции messagebox.Нужен ли цикл сообщений?Кроме того, если требуется цикл, должен ли этот цикл выполняться в другом потоке, чтобы функция, вызываемая из python, возвращалась обратно в python?

...