// defined so that we get the stable ABI from 3.2 onwards - means we don't have to // recompile this module for every new python version. #define Py_LIMITED_API // has to be included first #include "Python.h" #include struct Modifier { WORD vk; bool set; }; static void sendCtrlV() { INPUT ctrlV[] = {{0},{0},{0},{0}}; ctrlV[0].type = INPUT_KEYBOARD; ctrlV[0].ki.wVk = VK_LCONTROL; ctrlV[1].type = INPUT_KEYBOARD; ctrlV[1].ki.wVk = 'V'; ctrlV[2].type = INPUT_KEYBOARD; ctrlV[2].ki.wVk = 'V'; ctrlV[2].ki.dwFlags = KEYEVENTF_KEYUP; ctrlV[3].type = INPUT_KEYBOARD; ctrlV[3].ki.wVk = VK_LCONTROL; ctrlV[3].ki.dwFlags = KEYEVENTF_KEYUP; SendInput(sizeof(ctrlV)/sizeof(INPUT), ctrlV, sizeof(INPUT)); } static void sendEvent(WORD vk, DWORD flags) { INPUT in = {0}; in.type = INPUT_KEYBOARD; in.ki.wVk = vk; in.ki.dwFlags = flags; SendInput(1, &in, sizeof(INPUT)); } /* Works as following: First record which control keys are down, make sure they are up, then send the ctrl-v command, then reinstate original state. If we don't do this we may get interesting results, i.e.: Ctrl+Alt+V instead of Ctrl-v won't do what we want. */ static PyObject* sendPasteCommand(PyObject *self, PyObject *args) { Modifier modifiers[] = { {VK_MENU, 0}, /* alt key*/ {VK_CONTROL, 0}, {VK_SHIFT, 0}, {VK_LWIN, 0}, {VK_RWIN, 0}, }; for (int i = 0; i < sizeof(modifiers)/sizeof(Modifier); i++) { Modifier& mod = modifiers[i]; if (GetAsyncKeyState(mod.vk) < 0) { mod.set = true; sendEvent(mod.vk, KEYEVENTF_KEYUP); } } sendCtrlV(); for (int i = 0; i < sizeof(modifiers)/sizeof(Modifier); i++) { Modifier& mod = modifiers[i]; if (mod.set) sendEvent(mod.vk, 0 /* key down */); } Py_RETURN_NONE; } /* This only works correctly when the shortcut itself is something like ctrl-, but is faster, simpler and should work better in such situations. */ static PyObject* sendV(PyObject *self, PyObject *args) { INPUT inputs[] = {{0}, {0}}; inputs[0].type = INPUT_KEYBOARD; inputs[0].ki.wVk = 'V'; inputs[1].type = INPUT_KEYBOARD; inputs[1].ki.wVk = 'V'; inputs[1].ki.dwFlags = KEYEVENTF_KEYUP; SendInput(sizeof(inputs) / sizeof(INPUT), inputs, sizeof(INPUT)); Py_RETURN_NONE; } static PyMethodDef methods[] = { /* see http://docs.python.org/py3k/c-api/structures.html#PyMethodDef */ {"send_paste", /* name of python function in module */ sendPasteCommand, /* pointer to c function */ METH_VARARGS, /* parameters are provided as tuple, if METH_VARARGS | METH_KEYWORDS is specified as a third parameter a dictionary of keywords is passed */ "sends ctrl-v to current application" }, {"send_paste_simple", sendV, METH_VARARGS, "sends baiscally only a 'v' to the application. This is much simpler and faster " "than the complete version (so should work better), but also only works if the shortcut " "is only ctrl-something" }, {NULL, NULL, 0, NULL} /* guard */ }; static struct PyModuleDef sendpastemodule = { PyModuleDef_HEAD_INIT, "sendpaste", /* name of module */ "", /* doc string */ -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. state can be accessed by PyModule_GetState() */ methods, NULL, /* m_reload: unused, should be null */ NULL, /* m_traverse: A traversal function to call during GC traversal of the module object, or NULL if not needed. */ NULL, /* m_clear: A clear function to call during GC clearing of the module object, or NULL if not needed. */ NULL /* m_free: A function to call during deallocation of the module object, or NULL if not needed. */ }; PyMODINIT_FUNC PyInit_sendpaste() { return PyModule_Create(&sendpastemodule); }