more input wip
[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         int ignore:1;
16 } in_dev_t;
17
18 #define IN_MAX_DEVS 10
19
20 static in_dev_t in_devices[IN_MAX_DEVS];
21 static int in_dev_count = 0;
22
23 static int in_bind_count(int drv_id)
24 {
25         int count = 0;
26         switch (drv_id) {
27         case IN_DRVID_EVDEV:
28                 count = in_evdev_bind_count();
29                 break;
30         }
31         if (count <= 0)
32                 printf("input: failed to get bind count for drv %d\n", drv_id);
33
34         return count;
35 }
36
37 static int *in_alloc_binds(int drv_id)
38 {
39         int count, *ret;
40
41         count = in_bind_count(drv_id);
42         if (count <= 0) {
43                 printf("input: failed to get bind count for drv %d\n", drv_id);
44                 return NULL;
45         }
46
47         ret = malloc(count * sizeof(*ret));
48         return ret;
49 }
50
51 static void in_free(in_dev_t *dev)
52 {
53         if (dev->probed) {
54                 switch (dev->drv_id) {
55                 case IN_DRVID_EVDEV:
56                         in_evdev_free(dev->drv_data);
57                         break;
58                 }
59         }
60         dev->probed = 0;
61         dev->drv_data = NULL;
62         free(dev->name);
63         dev->name = NULL;
64         free(dev->binds);
65         dev->binds = NULL;
66 }
67
68 /* to be called by drivers */
69 void in_register(const char *nname, int drv_id, void *drv_data)
70 {
71         int i, dupe_count = 0, *binds;
72         char name[256], *name_end, *tmp;
73
74         strncpy(name, nname, sizeof(name));
75         name[sizeof(name)-12] = 0;
76         name_end = name + strlen(name);
77
78         for (i = 0; i < in_dev_count; i++)
79         {
80                 if (in_devices[i].name == NULL)
81                         continue;
82                 if (strcmp(in_devices[i].name, name) == 0)
83                 {
84                         if (in_devices[i].probed) {
85                                 dupe_count++;
86                                 sprintf(name_end, " [%d]", dupe_count);
87                                 continue;
88                         }
89                         goto update;
90                 }
91         }
92
93         if (i >= IN_MAX_DEVS)
94         {
95                 /* try to find unused device */
96                 for (i = 0; i < IN_MAX_DEVS; i++)
97                         if (!in_devices[i].probed) break;
98                 if (i >= IN_MAX_DEVS) {
99                         printf("input: too many devices, can't add %s\n", name);
100                         return;
101                 }
102                 in_free(&in_devices[i]);
103         }
104
105         tmp = strdup(name);
106         if (tmp == NULL)
107                 return;
108
109         binds = in_alloc_binds(drv_id);
110         if (binds == NULL) {
111                 free(tmp);
112                 return;
113         }
114
115         in_devices[i].name = tmp;
116         in_devices[i].binds = binds;
117         if (i + 1 > in_dev_count)
118                 in_dev_count = i + 1;
119
120         printf("input: new device #%d \"%s\"\n", i, name);
121 update:
122         in_devices[i].probed = 1;
123         in_devices[i].drv_id = drv_id;
124         in_devices[i].drv_data = drv_data;
125 }
126
127 void in_probe(void)
128 {
129         int i;
130         for (i = 0; i < in_dev_count; i++)
131                 in_devices[i].probed = 0;
132
133         in_evdev_probe();
134
135         /* get rid of devs without binds and probes */
136         for (i = 0; i < in_dev_count; i++) {
137                 if (!in_devices[i].probed && in_devices[i].binds == NULL) {
138                         in_dev_count--;
139                         if (i < in_dev_count) {
140                                 free(in_devices[i].name);
141                                 memmove(&in_devices[i], &in_devices[i+1],
142                                         (in_dev_count - i) * sizeof(in_devices[0]));
143                         }
144                 }
145         }
146 }
147
148 void in_clear_binds(const char *devname)
149 {
150 /*      int count;
151
152         count = in_bind_count(drv_id);
153         if (count <= 0) {
154                 printf("input: failed to get bind count for drv %d\n", dev->drv_id);
155                 return NULL;
156         }
157 */
158 }
159
160 int in_update(void)
161 {
162         int i, result = 0;
163
164         for (i = 0; i < in_dev_count; i++) {
165                 if (in_devices[i].probed && in_devices[i].binds != NULL) {
166                         switch (in_devices[i].drv_id) {
167                         case IN_DRVID_EVDEV:
168                                 result |= in_evdev_update(in_devices[i].drv_data, in_devices[i].binds);
169                                 break;
170                         }
171                 }
172         }
173
174         return result;
175 }
176
177 static void **in_collect_drvdata(int drv_id, int *count)
178 {
179         static void *data[IN_MAX_DEVS];
180         int i;
181
182         for (*count = i = 0; i < in_dev_count; i++) {
183                 if (in_devices[i].drv_id == drv_id && in_devices[i].probed)
184                         data[(*count)++] = in_devices[i].drv_data;
185         }
186
187         return data;
188 }
189
190 void in_set_blocking(int is_blocking)
191 {
192         int i;
193
194         for (i = 0; i < in_dev_count; i++) {
195                 if (in_devices[i].probed) {
196                         switch (in_devices[i].drv_id) {
197                         case IN_DRVID_EVDEV:
198                                 in_evdev_set_blocking(in_devices[i].drv_data, is_blocking);
199                                 break;
200                         }
201                 }
202         }
203 }
204
205 /* 
206  * update with wait for a press, return keycode
207  * only can use 1 drv here..
208  */
209 int in_update_keycode(int *dev_id, int *is_down)
210 {
211         int result = 0;
212 #ifdef IN_EVDEV
213         void **data;
214         int i, id = 0, count = 0;
215
216         data = in_collect_drvdata(IN_DRVID_EVDEV, &count);
217         if (count == 0) {
218                 /* don't deadlock, fail */
219                 printf("input: failed to find devices to read\n");
220                 exit(1);
221         }
222
223         result = in_evdev_update_keycode(data, count, &id, is_down);
224
225         if (dev_id != NULL) {
226                 for (i = id; i < in_dev_count; i++) {
227                         if (in_devices[i].drv_data == data[id]) {
228                                 *dev_id = i;
229                                 break;
230                         }
231                 }
232         }
233 #else
234 #error no menu read handlers
235 #endif
236
237         return result;
238 }
239
240 /* 
241  * same as above, only return bitfield of BTN_*
242  */
243 int in_update_menu(void)
244 {
245         static int keys_active = 0;
246         int keys_old = keys_active;
247
248         while (1)
249         {
250                 int code, is_down = 0;
251                 code = in_update_keycode(NULL, &is_down);
252 #ifdef IN_EVDEV
253                 code = in_evdev_menu_translate(code);
254 #endif
255                 if (code == 0) continue;
256
257                 if (is_down)
258                         keys_active |=  code;
259                 else
260                         keys_active &= ~code;
261
262                 if (keys_old != keys_active)
263                         break;
264         }
265
266         return keys_active;
267 }
268
269 const char *in_get_key_name(int dev_id, int keycode)
270 {
271         if (dev_id < 0 || dev_id >= IN_MAX_DEVS)
272                 return "Unkn0";
273         switch (in_devices[dev_id].drv_id) {
274         case IN_DRVID_EVDEV:
275                 return in_evdev_get_key_name(keycode);
276         }
277
278         return "Unkn1";
279 }
280
281 void in_init(void)
282 {
283         memset(in_devices, 0, sizeof(in_devices));
284         in_dev_count = 0;
285 }
286
287 int main(void)
288 {
289         int ret;
290
291         in_init();
292         in_probe();
293
294         in_set_blocking(1);
295
296 #if 1
297         while (1) {
298                 int dev = 0, down;
299                 ret = in_update_keycode(&dev, &down);
300                 printf("#%i: %i %i (%s)\n", dev, down, ret, in_get_key_name(dev, ret));
301         }
302 #else
303         while (1) {
304                 ret = in_update_menu();
305                 printf("%08x\n", ret);
306         }
307 #endif
308
309         return 0;
310 }
311