|
1 | 1 | #include <Python.h>
|
2 | 2 | #include <IOKit/IOKitLib.h>
|
| 3 | +#include <CoreFoundation/CFRunLoop.h> |
| 4 | + |
| 5 | +#include "foohid_types.h" |
| 6 | + |
| 7 | +#include <Python.h> |
3 | 8 |
|
4 | 9 | #define FOOHID_SERVICE "it_unbit_foohid"
|
5 | 10 |
|
6 | 11 | #define FOOHID_CREATE 0
|
7 | 12 | #define FOOHID_DESTROY 1
|
8 | 13 | #define FOOHID_SEND 2
|
9 | 14 | #define FOOHID_LIST 3
|
| 15 | +#define FOOHID_NOTIFY 4 |
| 16 | + |
| 17 | +CFRunLoopRef run_loop = NULL; |
| 18 | +IONotificationPortRef notification_port = NULL; |
| 19 | + |
| 20 | +static PyObject* pyfunc_event_handler = NULL; |
10 | 21 |
|
11 | 22 | static int foohid_connect(io_connect_t *conn) {
|
| 23 | + if (!PyEval_ThreadsInitialized()) { |
| 24 | + printf("will PyEval_InitThreads\n"); |
| 25 | + PyEval_InitThreads(); |
| 26 | + } |
| 27 | + printf("did PyEval_InitThreads\n"); |
| 28 | + |
12 | 29 | io_iterator_t iterator;
|
13 | 30 | io_service_t service;
|
14 | 31 | kern_return_t ret = IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching(FOOHID_SERVICE), &iterator);
|
@@ -113,6 +130,127 @@ static PyObject *foohid_send(PyObject *self, PyObject *args) {
|
113 | 130 | return Py_True;
|
114 | 131 | }
|
115 | 132 |
|
| 133 | +void callback(void *refcon, IOReturn result, io_user_reference_t* args, uint32_t numArgs) { |
| 134 | + foohid_report *report; |
| 135 | + |
| 136 | + printf("callback called.\n"); |
| 137 | + if (sizeof(io_user_reference_t) * numArgs != sizeof(foohid_report)) { |
| 138 | + printf("unexpected number of arguments.\n"); |
| 139 | + return; |
| 140 | + } |
| 141 | + |
| 142 | + report = (foohid_report *)args; |
| 143 | + printf("received report (%llu bytes).\n", report->size); |
| 144 | + |
| 145 | + PyGILState_STATE state = PyGILState_Ensure(); |
| 146 | + |
| 147 | + if (pyfunc_event_handler == NULL){ |
| 148 | + printf("pyfunc_event_handler == null!!!\n"); |
| 149 | + fflush(stdout); |
| 150 | + } |
| 151 | + |
| 152 | + PyObject* arglist = Py_BuildValue("(y#)", report->data, report->size); |
| 153 | + // 一定要 tuple... 不然 PyObject_CallFunctionObjArgs 會錯 |
| 154 | + |
| 155 | + if (arglist == NULL){ |
| 156 | + printf("arglist NULL\n"); |
| 157 | + fflush(stdout); |
| 158 | + } |
| 159 | + |
| 160 | + PyObject *pyobjresult = PyObject_CallObject(pyfunc_event_handler, arglist); |
| 161 | + |
| 162 | + if (pyobjresult == NULL){ |
| 163 | + printf("pyobjresult NULL\n"); |
| 164 | + fflush(stdout); |
| 165 | + } |
| 166 | + Py_DECREF(arglist); |
| 167 | + fflush(stdout); |
| 168 | + PyGILState_Release(state); |
| 169 | +} |
| 170 | + |
| 171 | + |
| 172 | +static PyObject *foohid_subscribe(PyObject *self, PyObject *args) { |
| 173 | + // set handler |
| 174 | + // PyObject *result = NULL; |
| 175 | + PyObject *temp; |
| 176 | + |
| 177 | + char *name; |
| 178 | + Py_ssize_t name_len; |
| 179 | + |
| 180 | + if (!PyArg_ParseTuple(args, "s#O:set_callback", &name, &name_len, &temp)) { |
| 181 | + return NULL; |
| 182 | + } |
| 183 | + // set handler |
| 184 | + if (!PyCallable_Check(temp)) { |
| 185 | + PyErr_SetString(PyExc_TypeError, "parameter must be a function"); |
| 186 | + return NULL; |
| 187 | + } |
| 188 | + Py_XINCREF(temp); /* Add a reference to new func */ |
| 189 | + Py_XDECREF(pyfunc_event_handler); /* Dispose of previous callback */ |
| 190 | + pyfunc_event_handler = temp; /* Remember new callback */ |
| 191 | + |
| 192 | + if (name_len == 0) { |
| 193 | + return PyErr_Format(PyExc_ValueError, "invalid values"); |
| 194 | + } |
| 195 | + |
| 196 | + io_connect_t conn; |
| 197 | + if (foohid_connect(&conn)) { |
| 198 | + return PyErr_Format(PyExc_SystemError, "unable to open " FOOHID_SERVICE " service"); |
| 199 | + } |
| 200 | + |
| 201 | + // from u2f.c |
| 202 | + mach_port_t mnotification_port; |
| 203 | + CFRunLoopSourceRef run_loop_source; |
| 204 | + io_async_ref64_t async_ref; |
| 205 | + kern_return_t ret; |
| 206 | + |
| 207 | + // Create port to listen for kernel notifications on. |
| 208 | + notification_port = IONotificationPortCreate(kIOMasterPortDefault); |
| 209 | + if (!notification_port) { |
| 210 | + printf("Error getting notification port.\n"); |
| 211 | + return PyErr_Format(PyExc_ValueError, "invalid notification_port"); |
| 212 | + } |
| 213 | + |
| 214 | + // Get lower level mach port from notification port. |
| 215 | + mnotification_port = IONotificationPortGetMachPort(notification_port); |
| 216 | + if (!mnotification_port) { |
| 217 | + printf("Error getting mach notification port.\n"); |
| 218 | + return PyErr_Format(PyExc_ValueError, "invalid mnotification_port"); |
| 219 | + } |
| 220 | + |
| 221 | + // Create a run loop source from our notification port so we can add the port to our run loop. |
| 222 | + run_loop_source = IONotificationPortGetRunLoopSource(notification_port); |
| 223 | + if (run_loop_source == NULL) { |
| 224 | + printf("Error getting run loop source.\n"); |
| 225 | + return PyErr_Format(PyExc_ValueError, "invalid run_loop_source"); |
| 226 | + } |
| 227 | + |
| 228 | + // Add the notification port and timer to the run loop. |
| 229 | + CFRunLoopAddSource(CFRunLoopGetCurrent(), run_loop_source, kCFRunLoopDefaultMode); |
| 230 | + |
| 231 | + // Params to pass to the kernel. |
| 232 | + async_ref[kIOAsyncCalloutFuncIndex] = (uint64_t)callback; |
| 233 | + async_ref[kIOAsyncCalloutRefconIndex] = 0; |
| 234 | + |
| 235 | + uint32_t input_count = 2; |
| 236 | + uint64_t input[input_count]; |
| 237 | + input[0] = (uint64_t) name; |
| 238 | + input[1] = (uint64_t) name_len; |
| 239 | + |
| 240 | + ret = IOConnectCallAsyncScalarMethod(conn, FOOHID_NOTIFY, mnotification_port, async_ref, kIOAsyncCalloutCount, input, input_count, NULL, 0); |
| 241 | + |
| 242 | + foohid_close(conn); |
| 243 | + |
| 244 | + if (ret != KERN_SUCCESS) { |
| 245 | + return PyErr_Format(PyExc_SystemError, "unable to subscribe hid message"); |
| 246 | + } |
| 247 | + |
| 248 | + run_loop = CFRunLoopGetCurrent(); |
| 249 | + |
| 250 | + Py_INCREF(Py_True); |
| 251 | + return Py_True; |
| 252 | +} |
| 253 | + |
116 | 254 | static PyObject *foohid_destroy(PyObject *self, PyObject *args) {
|
117 | 255 | char *name;
|
118 | 256 | Py_ssize_t name_len;
|
@@ -209,6 +347,8 @@ static PyMethodDef foohidMethods[] = {
|
209 | 347 | {"destroy", foohid_destroy, METH_VARARGS, "destroy a foohid device"},
|
210 | 348 | {"send", foohid_send, METH_VARARGS, "send a hid message to a foohid device"},
|
211 | 349 | {"list", foohid_list, METH_VARARGS, "list the currently available foohid devices"},
|
| 350 | + {"subscribe", foohid_subscribe, METH_VARARGS, "subscribe foohid devices"}, |
| 351 | + |
212 | 352 | {NULL, NULL, 0, NULL}
|
213 | 353 | };
|
214 | 354 |
|
|
0 commit comments