-
Notifications
You must be signed in to change notification settings - Fork 6
/
foohid.c
230 lines (191 loc) · 6.5 KB
/
foohid.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
#include <Python.h>
#include <IOKit/IOKitLib.h>
#define FOOHID_SERVICE "it_unbit_foohid"
#define FOOHID_CREATE 0
#define FOOHID_DESTROY 1
#define FOOHID_SEND 2
#define FOOHID_LIST 3
static int foohid_connect(io_connect_t *conn) {
io_iterator_t iterator;
io_service_t service;
kern_return_t ret = IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching(FOOHID_SERVICE), &iterator);
if (ret != KERN_SUCCESS) return -1;
while ((service = IOIteratorNext(iterator)) != IO_OBJECT_NULL) {
ret = IOServiceOpen(service, mach_task_self(), 0, conn);
IOObjectRelease(service);
if (ret == KERN_SUCCESS) {
IOObjectRelease(iterator);
return 0;
}
}
IOObjectRelease(iterator);
return -1;
}
static void foohid_close(io_connect_t conn) {
IOServiceClose(conn);
}
static PyObject *foohid_create(PyObject *self, PyObject *args) {
char *name;
Py_ssize_t name_len;
char *descriptor;
Py_ssize_t descriptor_len;
char *serial;
Py_ssize_t serial_len;
unsigned int vendor_id;
unsigned int device_id;
if (!PyArg_ParseTuple(args, "s#s#s#II", &name, &name_len, &descriptor, &descriptor_len, &serial, &serial_len, &vendor_id, &device_id)) {
return NULL;
}
if (name_len == 0 || descriptor_len == 0 || serial_len == 0) {
return PyErr_Format(PyExc_ValueError, "invalid values");
}
io_connect_t conn;
if (foohid_connect(&conn)) {
return PyErr_Format(PyExc_SystemError, "unable to open " FOOHID_SERVICE " service");
}
uint32_t input_count = 8;
uint64_t input[input_count];
input[0] = (uint64_t) name;
input[1] = (uint64_t) name_len;
input[2] = (uint64_t) descriptor;
input[3] = (uint64_t) descriptor_len;
input[4] = (uint64_t) serial;
input[5] = (uint64_t) serial_len;
input[6] = (uint64_t) vendor_id;
input[7] = (uint64_t) device_id;
kern_return_t ret = IOConnectCallScalarMethod(conn, FOOHID_CREATE, input, input_count, NULL, 0);
foohid_close(conn);
if (ret != KERN_SUCCESS) {
return PyErr_Format(PyExc_SystemError, "unable to create device");
}
Py_INCREF(Py_True);
return Py_True;
}
static PyObject *foohid_send(PyObject *self, PyObject *args) {
char *name;
Py_ssize_t name_len;
char *report;
Py_ssize_t report_len;
if (!PyArg_ParseTuple(args, "s#s#", &name, &name_len, &report, &report_len)) {
return NULL;
}
if (name_len == 0 || report_len == 0) {
return PyErr_Format(PyExc_ValueError, "invalid values");
}
io_connect_t conn;
if (foohid_connect(&conn)) {
return PyErr_Format(PyExc_SystemError, "unable to open " FOOHID_SERVICE " service");
}
uint32_t input_count = 4;
uint64_t input[input_count];
input[0] = (uint64_t) name;
input[1] = (uint64_t) name_len;
input[2] = (uint64_t) report;
input[3] = (uint64_t) report_len;
kern_return_t ret = IOConnectCallScalarMethod(conn, FOOHID_SEND, input, input_count, NULL, 0);
foohid_close(conn);
if (ret != KERN_SUCCESS) {
return PyErr_Format(PyExc_SystemError, "unable to send hid message");
}
Py_INCREF(Py_True);
return Py_True;
}
static PyObject *foohid_destroy(PyObject *self, PyObject *args) {
char *name;
Py_ssize_t name_len;
if (!PyArg_ParseTuple(args, "s#", &name, &name_len)) {
return NULL;
}
if (name_len == 0) {
return PyErr_Format(PyExc_ValueError, "invalid name");
}
io_connect_t conn;
if (foohid_connect(&conn)) {
return PyErr_Format(PyExc_SystemError, "unable to open " FOOHID_SERVICE " service");
}
uint32_t input_count = 2;
uint64_t input[input_count];
input[0] = (uint64_t) name;
input[1] = (uint64_t) name_len;
kern_return_t ret = IOConnectCallScalarMethod(conn, FOOHID_DESTROY, input, input_count, NULL, 0);
foohid_close(conn);
if (ret != KERN_SUCCESS) {
return PyErr_Format(PyExc_SystemError, "unable to destroy hid device");
}
Py_INCREF(Py_True);
return Py_True;
}
static PyObject *foohid_list(PyObject *self, PyObject *args) {
if (!PyArg_ParseTuple(args, "")) {
return NULL;
}
io_connect_t conn;
if (foohid_connect(&conn)) {
return PyErr_Format(PyExc_SystemError, "unable to open " FOOHID_SERVICE " service");
}
uint32_t output_count = 2;
uint64_t output[2] = {0, 0};
uint16_t buf_len = 4096;
char *buf = malloc(buf_len);
if (!buf) {
return PyErr_Format(PyExc_MemoryError, "unable to allocate memory");
}
uint64_t input[2];
for(;;) {
input[0] = (uint64_t) buf;
input[1] = (uint64_t) buf_len;
kern_return_t ret = IOConnectCallScalarMethod(conn, FOOHID_LIST, input, 2, output, &output_count);
foohid_close(conn);
if (ret != KERN_SUCCESS) {
free(buf);
return PyErr_Format(PyExc_SystemError, "unable to list hid devices");
}
// all is fine
if (output[0] == 0) {
PyObject *ret = PyTuple_New(output[1]);
uint64_t i;
char *ptr = buf;
for(i = 0; i < output[1]; i++) {
#if PY_MAJOR_VERSION >= 3
PyTuple_SetItem(ret, i, PyUnicode_FromString(ptr));
#else
PyTuple_SetItem(ret, i, PyString_FromString(ptr));
#endif
ptr += strlen(ptr) + 1;
}
free(buf);
return ret;
}
// realloc memory
buf_len = output[0];
char *tmp = realloc(buf, buf_len);
if (!tmp) {
free(buf);
return PyErr_Format(PyExc_MemoryError, "unable to allocate memory");
}
buf = tmp;
}
}
static PyMethodDef foohidMethods[] = {
{"create", foohid_create, METH_VARARGS, "create a new foohid device"},
{"destroy", foohid_destroy, METH_VARARGS, "destroy a foohid device"},
{"send", foohid_send, METH_VARARGS, "send a hid message to a foohid device"},
{"list", foohid_list, METH_VARARGS, "list the currently available foohid devices"},
{NULL, NULL, 0, NULL}
};
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef foodhidModule = {
PyModuleDef_HEAD_INIT,
"foohid",
"python wrapper for foohid",
-1,
foohidMethods
};
PyMODINIT_FUNC PyInit_foohid(void) {
return PyModule_Create(&foodhidModule);
}
#else
PyMODINIT_FUNC initfoohid(void) {
Py_InitModule3("foohid", foohidMethods, "python wrapper for foohid");
}
#endif