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