input layer mostly complete
[libpicofe.git] / common / input.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "input.h"
6 #include "../linux/in_evdev.h"
7
8 typedef struct
9 {
10         int drv_id;
11         void *drv_data;
12         int *binds;
13         char *name;
14         int probed:1;
15 } in_dev_t;
16
17 static in_drv_t in_drivers[IN_DRVID_COUNT];
18 static in_dev_t in_devices[IN_MAX_DEVS];
19 static int in_dev_count = 0;
20
21 #define DRV(id) in_drivers[(unsigned)(id) < IN_DRVID_COUNT ? (id) : 0]
22
23 static int in_bind_count(int drv_id)
24 {
25         int count = DRV(drv_id).get_bind_count();
26         if (count <= 0)
27                 printf("input: failed to get bind count for drv %d\n", drv_id);
28
29         return count;
30 }
31
32 static int *in_alloc_binds(int drv_id)
33 {
34         int count, *binds;
35
36         count = in_bind_count(drv_id);
37         if (count <= 0)
38                 return NULL;
39
40         binds = calloc(count * 2, sizeof(binds[0]));
41         if (binds == NULL)
42                 return NULL;
43
44         DRV(drv_id).get_def_binds(binds + count);
45         memcpy(binds, binds + count, count * sizeof(binds[0]));
46
47         return binds;
48 }
49
50 static void in_free(in_dev_t *dev)
51 {
52         if (dev->probed)
53                 DRV(dev->drv_id).free(dev->drv_data);
54         dev->probed = 0;
55         dev->drv_data = NULL;
56         free(dev->name);
57         dev->name = NULL;
58         free(dev->binds);
59         dev->binds = NULL;
60 }
61
62 /* to be called by drivers */
63 void in_register(const char *nname, int drv_id, void *drv_data)
64 {
65         int i, ret, dupe_count = 0, *binds;
66         char name[256], *name_end, *tmp;
67
68         strncpy(name, nname, sizeof(name));
69         name[sizeof(name)-12] = 0;
70         name_end = name + strlen(name);
71
72         for (i = 0; i < in_dev_count; i++)
73         {
74                 if (in_devices[i].name == NULL)
75                         continue;
76                 if (strcmp(in_devices[i].name, name) == 0)
77                 {
78                         if (in_devices[i].probed) {
79                                 dupe_count++;
80                                 sprintf(name_end, " [%d]", dupe_count);
81                                 continue;
82                         }
83                         goto update;
84                 }
85         }
86
87         if (i >= IN_MAX_DEVS)
88         {
89                 /* try to find unused device */
90                 for (i = 0; i < IN_MAX_DEVS; i++)
91                         if (!in_devices[i].probed) break;
92                 if (i >= IN_MAX_DEVS) {
93                         printf("input: too many devices, can't add %s\n", name);
94                         return;
95                 }
96                 in_free(&in_devices[i]);
97         }
98
99         tmp = strdup(name);
100         if (tmp == NULL)
101                 return;
102
103         binds = in_alloc_binds(drv_id);
104         if (binds == NULL) {
105                 free(tmp);
106                 return;
107         }
108
109         in_devices[i].name = tmp;
110         in_devices[i].binds = binds;
111         if (i + 1 > in_dev_count)
112                 in_dev_count = i + 1;
113
114         printf("input: new device #%d \"%s\"\n", i, name);
115 update:
116         in_devices[i].probed = 1;
117         in_devices[i].drv_id = drv_id;
118         in_devices[i].drv_data = drv_data;
119
120         if (in_devices[i].binds != NULL) {
121                 ret = DRV(drv_id).clean_binds(drv_data, in_devices[i].binds);
122                 if (ret == 0) {
123                         /* no useable binds */
124                         free(in_devices[i].binds);
125                         in_devices[i].binds = NULL;
126                 }
127         }
128 }
129
130 void in_probe(void)
131 {
132         int i;
133         for (i = 0; i < in_dev_count; i++)
134                 in_devices[i].probed = 0;
135
136         for (i = 1; i < IN_DRVID_COUNT; i++)
137                 in_drivers[i].probe();
138
139         /* get rid of devs without binds and probes */
140         for (i = 0; i < in_dev_count; i++) {
141                 if (!in_devices[i].probed && in_devices[i].binds == NULL) {
142                         in_dev_count--;
143                         if (i < in_dev_count) {
144                                 free(in_devices[i].name);
145                                 memmove(&in_devices[i], &in_devices[i+1],
146                                         (in_dev_count - i) * sizeof(in_devices[0]));
147                         }
148                 }
149         }
150 }
151
152 int in_update(void)
153 {
154         int i, result = 0;
155
156         for (i = 0; i < in_dev_count; i++) {
157                 if (in_devices[i].probed && in_devices[i].binds != NULL) {
158                         switch (in_devices[i].drv_id) {
159 #ifdef IN_EVDEV
160                         case IN_DRVID_EVDEV:
161                                 result |= in_evdev_update(in_devices[i].drv_data, in_devices[i].binds);
162                                 break;
163 #endif
164                         }
165                 }
166         }
167
168         return result;
169 }
170
171 static void **in_collect_drvdata(int drv_id, int *count)
172 {
173         static void *data[IN_MAX_DEVS];
174         int i;
175
176         for (*count = i = 0; i < in_dev_count; i++) {
177                 if (in_devices[i].drv_id == drv_id && in_devices[i].probed)
178                         data[(*count)++] = in_devices[i].drv_data;
179         }
180
181         return data;
182 }
183
184 void in_set_blocking(int is_blocking)
185 {
186         int i;
187
188         for (i = 0; i < in_dev_count; i++) {
189                 if (in_devices[i].probed)
190                         DRV(in_devices[i].drv_id).set_blocking(in_devices[i].drv_data, is_blocking);
191         }
192 }
193
194 /* 
195  * update with wait for a press, return keycode
196  * only can use 1 drv here..
197  */
198 int in_update_keycode(int *dev_id, int *is_down)
199 {
200         int result = 0;
201 #ifdef IN_EVDEV
202         void **data;
203         int i, id = 0, count = 0;
204
205         data = in_collect_drvdata(IN_DRVID_EVDEV, &count);
206         if (count == 0) {
207                 /* don't deadlock, fail */
208                 printf("input: failed to find devices to read\n");
209                 exit(1);
210         }
211
212         result = in_evdev_update_keycode(data, count, &id, is_down);
213
214         if (dev_id != NULL) {
215                 for (i = id; i < in_dev_count; i++) {
216                         if (in_devices[i].drv_data == data[id]) {
217                                 *dev_id = i;
218                                 break;
219                         }
220                 }
221         }
222 #else
223 #error no menu read handlers
224 #endif
225
226         return result;
227 }
228
229 /* 
230  * same as above, only return bitfield of BTN_*
231  */
232 int in_update_menu(void)
233 {
234         static int keys_active = 0;
235         int keys_old = keys_active;
236
237         while (1)
238         {
239                 int code, is_down = 0, dev_id = 0;
240                 code = in_update_keycode(&dev_id, &is_down);
241                 code = DRV(in_devices[dev_id].drv_id).menu_translate(code);
242                 if (code == 0) continue;
243
244                 if (is_down)
245                         keys_active |=  code;
246                 else
247                         keys_active &= ~code;
248
249                 if (keys_old != keys_active)
250                         break;
251         }
252
253         return keys_active;
254 }
255
256 const int *in_get_dev_binds(int dev_id)
257 {
258         if (dev_id < 0 || dev_id >= IN_MAX_DEVS)
259                 return NULL;
260
261         return in_devices[dev_id].binds;
262 }
263
264 const int *in_get_dev_def_binds(int dev_id)
265 {
266         int count;
267
268         if (dev_id < 0 || dev_id >= IN_MAX_DEVS)
269                 return NULL;
270
271         count = in_bind_count(in_devices[dev_id].drv_id);
272         return in_devices[dev_id].binds + count;
273 }
274
275 int in_get_dev_bind_count(int dev_id)
276 {
277         if (dev_id < 0 || dev_id >= IN_MAX_DEVS)
278                 return 0;
279
280         return in_bind_count(in_devices[dev_id].drv_id);
281 }
282
283 const char *in_get_dev_name(int dev_id)
284 {
285         if (dev_id < 0 || dev_id >= IN_MAX_DEVS)
286                 return NULL;
287
288         return in_devices[dev_id].name;
289 }
290
291 const char *in_get_key_name(int dev_id, int keycode)
292 {
293         if (dev_id < 0 || dev_id >= IN_MAX_DEVS)
294                 return "Unkn0";
295
296         return DRV(in_devices[dev_id].drv_id).get_key_name(keycode);
297 }
298
299 /* returns device id, or -1 on error */
300 int in_config_parse_dev(const char *name)
301 {
302         int drv_id = -1, i;
303
304         for (i = 0; i < IN_DRVID_COUNT; i++) {
305                 int len = strlen(in_drivers[i].prefix);
306                 if (strncmp(name, in_drivers[i].prefix, len) == 0) {
307                         drv_id = i;
308                         break;
309                 }
310         }
311
312         if (drv_id < 0) {
313                 printf("input: missing driver for %s\n", name);
314                 return -1;
315         }
316
317         for (i = 0; i < in_dev_count; i++)
318         {
319                 if (in_devices[i].name == NULL)
320                         continue;
321                 if (strcmp(in_devices[i].name, name) == 0)
322                         return i;
323         }
324
325         if (i >= IN_MAX_DEVS)
326         {
327                 /* try to find unused device */
328                 for (i = 0; i < IN_MAX_DEVS; i++)
329                         if (in_devices[i].name == NULL) break;
330                 if (i >= IN_MAX_DEVS) {
331                         printf("input: too many devices, can't add %s\n", name);
332                         return -1;
333                 }
334         }
335
336         memset(&in_devices[i], 0, sizeof(in_devices[i]));
337
338         in_devices[i].name = strdup(name);
339         if (in_devices[i].name == NULL)
340                 return -1;
341
342         if (i + 1 > in_dev_count)
343                 in_dev_count = i + 1;
344         in_devices[i].drv_id = drv_id;
345
346         return i;
347 }
348
349 void in_config_start(void)
350 {
351         int i;
352
353         /* mark all default binds, so they get overwritten by func below */
354         for (i = 0; i < IN_MAX_DEVS; i++) {
355                 int n, count, *binds, *def_binds;
356
357                 if (in_devices[i].binds == NULL)
358                         continue;
359
360                 count = in_bind_count(in_devices[i].drv_id);
361                 binds = in_devices[i].binds;
362                 def_binds = binds + count;
363
364                 for (n = 0; n < count; n++)
365                         if (binds[n] == def_binds[n])
366                                 binds[n] = -1;
367         }
368 }
369
370 int in_config_bind_key(int dev_id, const char *key, int binds)
371 {
372         int kc;
373
374         if (dev_id < 0 || dev_id >= IN_MAX_DEVS)
375                 return -1;
376
377         if (in_devices[dev_id].binds == NULL) {
378                 in_devices[dev_id].binds = in_alloc_binds(in_devices[dev_id].drv_id);
379                 if (in_devices[dev_id].binds == NULL)
380                         return -1;
381                 in_config_start();
382         }
383
384         kc = DRV(in_devices[dev_id].drv_id).get_key_code(key);
385         if (kc < 0) {
386                 printf("input: bad key: %s\n", key);
387                 return -1;
388         }
389
390         if (in_devices[dev_id].binds[kc] == -1)
391                 in_devices[dev_id].binds[kc] = 0;
392         in_devices[dev_id].binds[kc] |= binds;
393
394         return 0;
395 }
396
397 void in_config_end(void)
398 {
399         int i;
400
401         for (i = 0; i < IN_MAX_DEVS; i++) {
402                 int n, ret, count, *binds, *def_binds;
403
404                 if (in_devices[i].binds == NULL)
405                         continue;
406
407                 count = in_bind_count(in_devices[i].drv_id);
408                 binds = in_devices[i].binds;
409                 def_binds = binds + count;
410
411                 for (n = 0; n < count; n++)
412                         if (binds[n] == -1)
413                                 binds[n] = def_binds[n];
414
415                 if (in_devices[i].drv_data == NULL)
416                         continue;
417
418                 ret = DRV(in_devices[i].drv_id).clean_binds(in_devices[i].drv_data, binds);
419                 if (ret == 0) {
420                         /* no useable binds */
421                         free(binds);
422                         in_devices[i].binds = NULL;
423                 }
424         }
425 }
426
427 void in_debug_dump(void)
428 {
429         int i;
430
431         printf("# drv probed binds name\n");
432         for (i = 0; i < IN_MAX_DEVS; i++) {
433                 in_dev_t *d = &in_devices[i];
434                 if (!d->probed && d->name == NULL && d->binds == NULL)
435                         continue;
436                 printf("%d %3d %6c %5c %s\n", i, d->drv_id, d->probed ? 'y' : 'n',
437                         d->binds ? 'y' : 'n', d->name);
438         }
439 }
440
441 /* handlers for unknown/not_preset drivers */
442
443 static void in_def_probe(void) {}
444 static void in_def_free(void *drv_data) {}
445 static int  in_def_get_bind_count(void) { return 0; }
446 static void in_def_get_def_binds(int *binds) {}
447 static int  in_def_clean_binds(void *drv_data, int *binds) { return 0; }
448 static void in_def_set_blocking(void *data, int y) {}
449 static int  in_def_menu_translate(int keycode) { return keycode; }
450 static int  in_def_get_key_code(const char *key_name) { return 0; }
451 static const char *in_def_get_key_name(int keycode) { return NULL; }
452
453 void in_init(void)
454 {
455         int i;
456
457         memset(in_drivers, 0, sizeof(in_drivers));
458         memset(in_devices, 0, sizeof(in_devices));
459         in_dev_count = 0;
460
461         for (i = 0; i < IN_DRVID_COUNT; i++) {
462                 in_drivers[i].prefix = "none:";
463                 in_drivers[i].probe = in_def_probe;
464                 in_drivers[i].free = in_def_free;
465                 in_drivers[i].get_bind_count = in_def_get_bind_count;
466                 in_drivers[i].get_def_binds = in_def_get_def_binds;
467                 in_drivers[i].clean_binds = in_def_clean_binds;
468                 in_drivers[i].set_blocking = in_def_set_blocking;
469                 in_drivers[i].menu_translate = in_def_menu_translate;
470                 in_drivers[i].get_key_code = in_def_get_key_code;
471                 in_drivers[i].get_key_name = in_def_get_key_name;
472         }
473
474 #ifdef IN_EVDEV
475         in_evdev_init(&in_drivers[IN_DRVID_EVDEV]);
476 #endif
477 }
478
479 #if 0
480 int main(void)
481 {
482         int ret;
483
484         in_init();
485         in_probe();
486
487         in_set_blocking(1);
488
489 #if 1
490         while (1) {
491                 int dev = 0, down;
492                 ret = in_update_keycode(&dev, &down);
493                 printf("#%i: %i %i (%s)\n", dev, down, ret, in_get_key_name(dev, ret));
494         }
495 #else
496         while (1) {
497                 ret = in_update_menu();
498                 printf("%08x\n", ret);
499         }
500 #endif
501
502         return 0;
503 }
504 #endif