698517be |
1 | /* |
2 | * (C) GraÅžvydas "notaz" Ignotas, 2008-2010 |
3 | * |
4 | * This work is licensed under the terms of any of these licenses |
5 | * (at your option): |
6 | * - GNU GPL, version 2 or later. |
7 | * - GNU LGPL, version 2.1 or later. |
8 | * See the COPYING file in the top-level directory. |
9 | */ |
10 | |
11 | #include <stdio.h> |
12 | #include <stdlib.h> |
13 | #include <string.h> |
14 | |
15 | #include "input.h" |
16 | #include "plat.h" |
17 | #include "lprintf.h" |
18 | |
19 | #ifdef IN_EVDEV |
20 | #include "../linux/in_evdev.h" |
21 | #endif |
22 | #ifdef IN_GP2X |
23 | #include "../gp2x/in_gp2x.h" |
24 | #endif |
25 | #ifdef IN_VK |
26 | #include "../win32/in_vk.h" |
27 | #endif |
28 | |
29 | typedef struct |
30 | { |
31 | int drv_id; |
32 | int drv_fd_hnd; |
33 | void *drv_data; |
34 | char *name; |
35 | int key_count; |
36 | int *binds; /* total = key_count * bindtypes * 2 */ |
37 | const char * const *key_names; |
38 | unsigned int probed:1; |
39 | unsigned int does_combos:1; |
40 | } in_dev_t; |
41 | |
42 | static in_drv_t in_drivers[IN_DRVID_COUNT]; |
43 | static in_dev_t in_devices[IN_MAX_DEVS]; |
44 | static int in_dev_count = 0; |
45 | static int in_have_async_devs = 0; |
46 | static int menu_key_state = 0; |
47 | static int menu_last_used_dev = 0; |
48 | |
49 | #define DRV(id) in_drivers[(unsigned)(id) < IN_DRVID_COUNT ? (id) : 0] |
50 | |
51 | |
52 | static int *in_alloc_binds(int drv_id, int key_count) |
53 | { |
54 | int *binds; |
55 | |
56 | binds = calloc(key_count * IN_BINDTYPE_COUNT * 2, sizeof(binds[0])); |
57 | if (binds == NULL) |
58 | return NULL; |
59 | |
60 | DRV(drv_id).get_def_binds(binds + key_count * IN_BINDTYPE_COUNT); |
61 | memcpy(binds, binds + key_count * IN_BINDTYPE_COUNT, |
62 | sizeof(binds[0]) * key_count * IN_BINDTYPE_COUNT); |
63 | |
64 | return binds; |
65 | } |
66 | |
67 | static void in_free(in_dev_t *dev) |
68 | { |
69 | if (dev->probed) |
70 | DRV(dev->drv_id).free(dev->drv_data); |
71 | dev->probed = 0; |
72 | dev->drv_data = NULL; |
73 | free(dev->name); |
74 | dev->name = NULL; |
75 | free(dev->binds); |
76 | dev->binds = NULL; |
77 | } |
78 | |
79 | /* to be called by drivers |
80 | * async devices must set drv_fd_hnd to -1 */ |
81 | void in_register(const char *nname, int drv_id, int drv_fd_hnd, void *drv_data, |
82 | int key_count, const char * const *key_names, int combos) |
83 | { |
84 | int i, ret, dupe_count = 0, *binds; |
85 | char name[256], *name_end, *tmp; |
86 | |
87 | strncpy(name, nname, sizeof(name)); |
88 | name[sizeof(name)-12] = 0; |
89 | name_end = name + strlen(name); |
90 | |
91 | for (i = 0; i < in_dev_count; i++) |
92 | { |
93 | if (in_devices[i].name == NULL) |
94 | continue; |
95 | if (strcmp(in_devices[i].name, name) == 0) |
96 | { |
97 | if (in_devices[i].probed) { |
98 | dupe_count++; |
99 | sprintf(name_end, " [%d]", dupe_count); |
100 | continue; |
101 | } |
102 | goto update; |
103 | } |
104 | } |
105 | |
106 | if (i >= IN_MAX_DEVS) |
107 | { |
108 | /* try to find unused device */ |
109 | for (i = 0; i < IN_MAX_DEVS; i++) |
110 | if (!in_devices[i].probed) break; |
111 | if (i >= IN_MAX_DEVS) { |
112 | lprintf("input: too many devices, can't add %s\n", name); |
113 | return; |
114 | } |
115 | in_free(&in_devices[i]); |
116 | } |
117 | |
118 | tmp = strdup(name); |
119 | if (tmp == NULL) |
120 | return; |
121 | |
122 | binds = in_alloc_binds(drv_id, key_count); |
123 | if (binds == NULL) { |
124 | free(tmp); |
125 | return; |
126 | } |
127 | |
128 | in_devices[i].name = tmp; |
129 | in_devices[i].binds = binds; |
130 | in_devices[i].key_count = key_count; |
131 | if (i + 1 > in_dev_count) |
132 | in_dev_count = i + 1; |
133 | |
134 | lprintf("input: new device #%d \"%s\"\n", i, name); |
135 | update: |
136 | in_devices[i].probed = 1; |
137 | in_devices[i].does_combos = combos; |
138 | in_devices[i].drv_id = drv_id; |
139 | in_devices[i].drv_fd_hnd = drv_fd_hnd; |
140 | in_devices[i].key_names = key_names; |
141 | in_devices[i].drv_data = drv_data; |
142 | |
143 | if (in_devices[i].binds != NULL) { |
144 | ret = DRV(drv_id).clean_binds(drv_data, in_devices[i].binds, |
145 | in_devices[i].binds + key_count * IN_BINDTYPE_COUNT); |
146 | if (ret == 0) { |
147 | /* no useable binds */ |
148 | free(in_devices[i].binds); |
149 | in_devices[i].binds = NULL; |
150 | } |
151 | } |
152 | } |
153 | |
154 | /* key combo handling, to be called by drivers that support it. |
155 | * Only care about IN_BINDTYPE_EMU */ |
156 | void in_combos_find(const int *binds, int last_key, int *combo_keys, int *combo_acts) |
157 | { |
158 | int act, u; |
159 | |
160 | *combo_keys = *combo_acts = 0; |
161 | for (act = 0; act < sizeof(binds[0]) * 8; act++) |
162 | { |
163 | int keyc = 0; |
164 | for (u = 0; u <= last_key; u++) |
165 | if (binds[IN_BIND_OFFS(u, IN_BINDTYPE_EMU)] & (1 << act)) |
166 | keyc++; |
167 | |
168 | if (keyc > 1) |
169 | { |
170 | // loop again and mark those keys and actions as combo |
171 | for (u = 0; u <= last_key; u++) |
172 | { |
173 | if (binds[IN_BIND_OFFS(u, IN_BINDTYPE_EMU)] & (1 << act)) { |
174 | *combo_keys |= 1 << u; |
175 | *combo_acts |= 1 << act; |
176 | } |
177 | } |
178 | } |
179 | } |
180 | } |
181 | |
182 | int in_combos_do(int keys, const int *binds, int last_key, int combo_keys, int combo_acts) |
183 | { |
184 | int i, ret = 0; |
185 | |
186 | for (i = 0; i <= last_key; i++) |
187 | { |
188 | int acts, acts_c, u; |
189 | |
190 | if (!(keys & (1 << i))) |
191 | continue; |
192 | |
193 | acts = binds[IN_BIND_OFFS(i, IN_BINDTYPE_EMU)]; |
194 | if (!acts) |
195 | continue; |
196 | |
197 | if (!(combo_keys & (1 << i))) { |
198 | ret |= acts; |
199 | continue; |
200 | } |
201 | |
202 | acts_c = acts & combo_acts; |
203 | u = last_key; |
204 | if (acts_c) { |
205 | // let's try to find the other one |
206 | for (u = i + 1; u <= last_key; u++) |
207 | if ( (keys & (1 << u)) && (binds[IN_BIND_OFFS(u, IN_BINDTYPE_EMU)] & acts_c) ) { |
208 | ret |= acts_c & binds[IN_BIND_OFFS(u, IN_BINDTYPE_EMU)]; |
209 | keys &= ~((1 << i) | (1 << u)); |
210 | break; |
211 | } |
212 | } |
213 | // add non-combo actions if combo ones were not found |
214 | if (u >= last_key) |
215 | ret |= acts & ~combo_acts; |
216 | } |
217 | |
218 | return ret; |
219 | } |
220 | |
221 | void in_probe(void) |
222 | { |
223 | int i; |
224 | |
225 | in_have_async_devs = 0; |
226 | for (i = 0; i < in_dev_count; i++) |
227 | in_devices[i].probed = 0; |
228 | |
229 | for (i = 1; i < IN_DRVID_COUNT; i++) |
230 | in_drivers[i].probe(); |
231 | |
232 | /* get rid of devs without binds and probes */ |
233 | for (i = 0; i < in_dev_count; i++) { |
234 | if (!in_devices[i].probed && in_devices[i].binds == NULL) { |
235 | in_dev_count--; |
236 | if (i < in_dev_count) { |
237 | free(in_devices[i].name); |
238 | memmove(&in_devices[i], &in_devices[i+1], |
239 | (in_dev_count - i) * sizeof(in_devices[0])); |
240 | } |
241 | |
242 | continue; |
243 | } |
244 | |
245 | if (in_devices[i].probed && in_devices[i].drv_fd_hnd == -1) |
246 | in_have_async_devs = 1; |
247 | } |
248 | |
249 | if (in_have_async_devs) |
250 | lprintf("input: async-only devices detected..\n"); |
251 | |
252 | in_debug_dump(); |
253 | } |
254 | |
255 | /* async update */ |
256 | int in_update(int *result) |
257 | { |
258 | int i, ret = 0; |
259 | |
260 | for (i = 0; i < in_dev_count; i++) { |
261 | in_dev_t *dev = &in_devices[i]; |
262 | if (dev->probed && dev->binds != NULL) { |
263 | // FIXME: this is stupid, make it indirect |
264 | switch (dev->drv_id) { |
265 | #ifdef IN_EVDEV |
266 | case IN_DRVID_EVDEV: |
267 | ret |= in_evdev_update(dev->drv_data, dev->binds, result); |
268 | break; |
269 | #endif |
270 | #ifdef IN_GP2X |
271 | case IN_DRVID_GP2X: |
272 | ret |= in_gp2x_update(dev->drv_data, dev->binds, result); |
273 | break; |
274 | #endif |
275 | #ifdef IN_VK |
276 | case IN_DRVID_VK: |
277 | ret |= in_vk_update(dev->drv_data, dev->binds, result); |
278 | break; |
279 | #endif |
280 | } |
281 | } |
282 | } |
283 | |
284 | return ret; |
285 | } |
286 | |
287 | static int in_update_kc_async(int *dev_id_out, int *is_down_out, int timeout_ms) |
288 | { |
289 | int i, is_down, result; |
290 | unsigned int ticks; |
291 | |
292 | ticks = plat_get_ticks_ms(); |
293 | |
294 | while (1) |
295 | { |
296 | for (i = 0; i < in_dev_count; i++) { |
297 | in_dev_t *d = &in_devices[i]; |
298 | if (!d->probed) |
299 | continue; |
300 | |
301 | result = DRV(d->drv_id).update_keycode(d->drv_data, &is_down); |
302 | if (result == -1) |
303 | continue; |
304 | |
305 | if (dev_id_out) |
306 | *dev_id_out = i; |
307 | if (is_down_out) |
308 | *is_down_out = is_down; |
309 | return result; |
310 | } |
311 | |
312 | if (timeout_ms >= 0 && (int)(plat_get_ticks_ms() - ticks) > timeout_ms) |
313 | break; |
314 | |
315 | plat_sleep_ms(10); |
316 | } |
317 | |
318 | return -1; |
319 | } |
320 | |
321 | /* |
322 | * wait for a press, always return some keycode or -1 on timeout or error |
323 | */ |
324 | int in_update_keycode(int *dev_id_out, int *is_down_out, int timeout_ms) |
325 | { |
326 | int result = -1, dev_id = 0, is_down, result_menu; |
327 | int fds_hnds[IN_MAX_DEVS]; |
328 | int i, ret, count = 0; |
329 | in_drv_t *drv = NULL; |
330 | unsigned int ticks; |
331 | |
332 | if (in_have_async_devs) { |
333 | result = in_update_kc_async(&dev_id, &is_down, timeout_ms); |
334 | if (result == -1) |
335 | return -1; |
336 | drv = &DRV(in_devices[dev_id].drv_id); |
337 | goto finish; |
338 | } |
339 | |
340 | ticks = plat_get_ticks_ms(); |
341 | |
342 | for (i = 0; i < in_dev_count; i++) { |
343 | if (in_devices[i].probed) |
344 | fds_hnds[count++] = in_devices[i].drv_fd_hnd; |
345 | } |
346 | |
347 | if (count == 0) { |
348 | /* don't deadlock, fail */ |
349 | lprintf("input: failed to find devices to read\n"); |
350 | exit(1); |
351 | } |
352 | |
353 | while (1) |
354 | { |
355 | ret = plat_wait_event(fds_hnds, count, timeout_ms); |
356 | if (ret < 0) |
357 | break; |
358 | |
359 | for (i = 0; i < in_dev_count; i++) { |
360 | if (in_devices[i].drv_fd_hnd == ret) { |
361 | dev_id = i; |
362 | break; |
363 | } |
364 | } |
365 | |
366 | drv = &DRV(in_devices[dev_id].drv_id); |
367 | result = drv->update_keycode(in_devices[dev_id].drv_data, &is_down); |
368 | if (result >= 0) |
369 | break; |
370 | |
371 | if (timeout_ms >= 0) { |
372 | unsigned int ticks2 = plat_get_ticks_ms(); |
373 | timeout_ms -= ticks2 - ticks; |
374 | ticks = ticks2; |
375 | if (timeout_ms <= 0) |
376 | break; |
377 | } |
378 | } |
379 | |
380 | if (result < 0) |
381 | return -1; |
382 | finish: |
383 | /* keep track of menu key state, to allow mixing |
384 | * in_update_keycode() and in_menu_wait_any() calls */ |
385 | result_menu = drv->menu_translate(in_devices[dev_id].drv_data, result); |
386 | if (result_menu != 0) { |
387 | if (is_down) |
388 | menu_key_state |= result_menu; |
389 | else |
390 | menu_key_state &= ~result_menu; |
391 | } |
392 | |
393 | if (dev_id_out != NULL) |
394 | *dev_id_out = dev_id; |
395 | if (is_down_out != NULL) |
396 | *is_down_out = is_down; |
397 | return result; |
398 | } |
399 | |
400 | /* same as above, only return bitfield of PBTN_* */ |
401 | int in_menu_wait_any(int timeout_ms) |
402 | { |
403 | int keys_old = menu_key_state; |
404 | |
405 | while (1) |
406 | { |
407 | int code, is_down = 0, dev_id = 0; |
408 | |
409 | code = in_update_keycode(&dev_id, &is_down, timeout_ms); |
410 | if (code < 0) |
411 | break; |
412 | |
413 | if (keys_old != menu_key_state) { |
414 | menu_last_used_dev = dev_id; |
415 | break; |
416 | } |
417 | } |
418 | |
419 | return menu_key_state; |
420 | } |
421 | |
422 | /* wait for menu input, do autorepeat */ |
423 | int in_menu_wait(int interesting, int autorep_delay_ms) |
424 | { |
425 | static int inp_prev = 0; |
426 | static int repeats = 0; |
427 | int ret, release = 0, wait = 450; |
428 | |
429 | if (repeats) |
430 | wait = autorep_delay_ms; |
431 | |
432 | ret = in_menu_wait_any(wait); |
433 | if (ret == inp_prev) |
434 | repeats++; |
435 | |
436 | while (!(ret & interesting)) { |
437 | ret = in_menu_wait_any(-1); |
438 | release = 1; |
439 | } |
440 | |
441 | if (release || ret != inp_prev) |
442 | repeats = 0; |
443 | |
444 | inp_prev = ret; |
445 | |
446 | /* we don't need diagonals in menus */ |
447 | if ((ret & PBTN_UP) && (ret & PBTN_LEFT)) ret &= ~PBTN_LEFT; |
448 | if ((ret & PBTN_UP) && (ret & PBTN_RIGHT)) ret &= ~PBTN_RIGHT; |
449 | if ((ret & PBTN_DOWN) && (ret & PBTN_LEFT)) ret &= ~PBTN_LEFT; |
450 | if ((ret & PBTN_DOWN) && (ret & PBTN_RIGHT)) ret &= ~PBTN_RIGHT; |
451 | |
452 | return ret; |
453 | } |
454 | |
455 | const int *in_get_dev_binds(int dev_id) |
456 | { |
457 | if (dev_id < 0 || dev_id >= IN_MAX_DEVS) |
458 | return NULL; |
459 | |
460 | return in_devices[dev_id].binds; |
461 | } |
462 | |
463 | const int *in_get_dev_def_binds(int dev_id) |
464 | { |
465 | if (dev_id < 0 || dev_id >= IN_MAX_DEVS) |
466 | return NULL; |
467 | |
468 | return in_devices[dev_id].binds + in_devices[dev_id].key_count * IN_BINDTYPE_COUNT; |
469 | } |
470 | |
471 | int in_get_config(int dev_id, int what, void *val) |
472 | { |
473 | int *ival = val; |
474 | in_dev_t *dev; |
475 | |
476 | if (dev_id < 0 || dev_id >= IN_MAX_DEVS || val == NULL) |
477 | return -1; |
478 | |
479 | dev = &in_devices[dev_id]; |
480 | switch (what) { |
481 | case IN_CFG_BIND_COUNT: |
482 | *ival = dev->key_count; |
483 | break; |
484 | case IN_CFG_DOES_COMBOS: |
485 | *ival = dev->does_combos; |
486 | break; |
487 | case IN_CFG_BLOCKING: |
488 | case IN_CFG_KEY_NAMES: |
489 | return -1; /* not implemented */ |
490 | default: |
491 | return DRV(dev->drv_id).get_config(dev->drv_data, what, ival); |
492 | } |
493 | |
494 | return 0; |
495 | } |
496 | |
497 | static int in_set_blocking(int is_blocking) |
498 | { |
499 | int i, ret; |
500 | |
501 | /* have_async_devs means we will have to do all reads async anyway.. */ |
502 | if (!in_have_async_devs) { |
503 | for (i = 0; i < in_dev_count; i++) { |
504 | if (in_devices[i].probed) |
505 | DRV(in_devices[i].drv_id).set_config(in_devices[i].drv_data, |
506 | IN_CFG_BLOCKING, is_blocking); |
507 | } |
508 | } |
509 | |
510 | menu_key_state = 0; |
511 | |
512 | /* flush events */ |
513 | do { |
514 | ret = in_update_keycode(NULL, NULL, 0); |
515 | } while (ret >= 0); |
516 | |
517 | return 0; |
518 | } |
519 | |
520 | int in_set_config(int dev_id, int what, const void *val, int size) |
521 | { |
522 | const int *ival = val; |
523 | in_dev_t *dev; |
524 | |
525 | if (what == IN_CFG_BLOCKING) |
526 | return in_set_blocking(*ival); |
527 | |
528 | if (dev_id < 0 || dev_id >= IN_MAX_DEVS) |
529 | return -1; |
530 | |
531 | dev = &in_devices[dev_id]; |
532 | if (what == IN_CFG_KEY_NAMES) { |
533 | const char * const *names = val; |
534 | int count = size / sizeof(names[0]); |
535 | |
536 | if (count < dev->key_count) { |
537 | lprintf("input: set_key_names: not enough keys\n"); |
538 | return -1; |
539 | } |
540 | |
541 | dev->key_names = names; |
542 | return 0; |
543 | } |
544 | |
545 | return DRV(dev->drv_id).set_config(dev->drv_data, what, *ival); |
546 | } |
547 | |
548 | const char *in_get_dev_name(int dev_id, int must_be_active, int skip_pfix) |
549 | { |
550 | const char *name, *tmp; |
551 | |
552 | if (dev_id < 0 || dev_id >= IN_MAX_DEVS) |
553 | return NULL; |
554 | |
555 | if (must_be_active && !in_devices[dev_id].probed) |
556 | return NULL; |
557 | |
558 | name = in_devices[dev_id].name; |
559 | if (name == NULL || !skip_pfix) |
560 | return name; |
561 | |
562 | /* skip prefix */ |
563 | tmp = strchr(name, ':'); |
564 | if (tmp != NULL) |
565 | name = tmp + 1; |
566 | |
567 | return name; |
568 | } |
569 | |
570 | int in_name_to_id(const char *dev_name) |
571 | { |
572 | int i; |
573 | |
574 | for (i = 0; i < in_dev_count; i++) |
575 | if (strcmp(dev_name, in_devices[i].name) == 0) |
576 | break; |
577 | |
578 | if (i >= in_dev_count) { |
579 | lprintf("input: in_name_to_id: no such device: %s\n", dev_name); |
580 | return -1; |
581 | } |
582 | |
583 | return i; |
584 | } |
585 | |
586 | /* never returns NULL */ |
587 | const char *in_get_key_name(int dev_id, int keycode) |
588 | { |
589 | const char *name = NULL; |
590 | static char xname[16]; |
591 | in_dev_t *dev; |
592 | |
593 | if (dev_id < 0) /* want last used dev? */ |
594 | dev_id = menu_last_used_dev; |
595 | |
596 | if (dev_id < 0 || dev_id >= IN_MAX_DEVS) |
597 | return "Unkn0"; |
598 | |
599 | dev = &in_devices[dev_id]; |
600 | if (keycode < 0) /* want name for menu key? */ |
601 | keycode = DRV(dev->drv_id).menu_translate(dev->drv_data, keycode); |
602 | |
603 | if (dev->key_names != NULL && 0 <= keycode && keycode < dev->key_count) |
604 | name = dev->key_names[keycode]; |
605 | if (name != NULL) |
606 | return name; |
607 | |
608 | name = DRV(dev->drv_id).get_key_name(keycode); |
609 | if (name != NULL) |
610 | return name; |
611 | |
612 | /* assume scancode */ |
613 | if ((keycode >= '0' && keycode <= '9') || (keycode >= 'a' && keycode <= 'z') |
614 | || (keycode >= 'A' && keycode <= 'Z')) |
615 | sprintf(xname, "%c", keycode); |
616 | else |
617 | sprintf(xname, "\\x%02X", keycode); |
618 | return xname; |
619 | } |
620 | |
621 | int in_get_key_code(int dev_id, const char *key_name) |
622 | { |
623 | in_dev_t *dev; |
624 | int i; |
625 | |
626 | if (dev_id < 0) /* want last used dev? */ |
627 | dev_id = menu_last_used_dev; |
628 | |
629 | if (dev_id < 0 || dev_id >= IN_MAX_DEVS) |
630 | return -1; |
631 | |
632 | dev = &in_devices[dev_id]; |
633 | if (dev->key_names == NULL) |
634 | return -1; |
635 | |
636 | for (i = 0; i < dev->key_count; i++) |
637 | if (dev->key_names[i] && strcasecmp(dev->key_names[i], key_name) == 0) |
638 | return i; |
639 | |
640 | return -1; |
641 | } |
642 | |
643 | int in_bind_key(int dev_id, int keycode, int mask, int bind_type, int force_unbind) |
644 | { |
645 | int ret, count; |
646 | in_dev_t *dev; |
647 | |
648 | if (dev_id < 0 || dev_id >= IN_MAX_DEVS || bind_type >= IN_BINDTYPE_COUNT) |
649 | return -1; |
650 | |
651 | dev = &in_devices[dev_id]; |
652 | count = dev->key_count; |
653 | |
654 | if (dev->binds == NULL) { |
655 | if (force_unbind) |
656 | return 0; |
657 | dev->binds = in_alloc_binds(dev->drv_id, count); |
658 | if (dev->binds == NULL) |
659 | return -1; |
660 | } |
661 | |
662 | if (keycode < 0 || keycode >= count) |
663 | return -1; |
664 | |
665 | if (force_unbind) |
666 | dev->binds[IN_BIND_OFFS(keycode, bind_type)] &= ~mask; |
667 | else |
668 | dev->binds[IN_BIND_OFFS(keycode, bind_type)] ^= mask; |
669 | |
670 | ret = DRV(dev->drv_id).clean_binds(dev->drv_data, dev->binds, |
671 | dev->binds + count * IN_BINDTYPE_COUNT); |
672 | if (ret == 0) { |
673 | free(dev->binds); |
674 | dev->binds = NULL; |
675 | } |
676 | |
677 | return 0; |
678 | } |
679 | |
680 | void in_unbind_all(int dev_id, int act_mask, int bind_type) |
681 | { |
682 | int i, count; |
683 | in_dev_t *dev; |
684 | |
685 | if (dev_id < 0 || dev_id >= IN_MAX_DEVS || bind_type >= IN_BINDTYPE_COUNT) |
686 | return; |
687 | |
688 | dev = &in_devices[dev_id]; |
689 | count = dev->key_count; |
690 | |
691 | if (dev->binds == NULL) |
692 | return; |
693 | |
694 | for (i = 0; i < count; i++) |
695 | dev->binds[IN_BIND_OFFS(i, bind_type)] &= ~act_mask; |
696 | } |
697 | |
698 | /* returns device id, or -1 on error */ |
699 | int in_config_parse_dev(const char *name) |
700 | { |
701 | int drv_id = -1, i; |
702 | |
703 | for (i = 0; i < IN_DRVID_COUNT; i++) { |
704 | int len = strlen(in_drivers[i].prefix); |
705 | if (strncmp(name, in_drivers[i].prefix, len) == 0) { |
706 | drv_id = i; |
707 | break; |
708 | } |
709 | } |
710 | |
711 | if (drv_id < 0) { |
712 | lprintf("input: missing driver for %s\n", name); |
713 | return -1; |
714 | } |
715 | |
716 | for (i = 0; i < in_dev_count; i++) |
717 | { |
718 | if (in_devices[i].name == NULL) |
719 | continue; |
720 | if (strcmp(in_devices[i].name, name) == 0) |
721 | return i; |
722 | } |
723 | |
724 | if (i >= IN_MAX_DEVS) |
725 | { |
726 | /* try to find unused device */ |
727 | for (i = 0; i < IN_MAX_DEVS; i++) |
728 | if (in_devices[i].name == NULL) break; |
729 | if (i >= IN_MAX_DEVS) { |
730 | lprintf("input: too many devices, can't add %s\n", name); |
731 | return -1; |
732 | } |
733 | } |
734 | |
735 | memset(&in_devices[i], 0, sizeof(in_devices[i])); |
736 | |
737 | in_devices[i].name = strdup(name); |
738 | if (in_devices[i].name == NULL) |
739 | return -1; |
740 | |
741 | in_devices[i].key_count = DRV(drv_id).get_bind_count(); |
742 | in_devices[i].drv_id = drv_id; |
743 | |
744 | if (i + 1 > in_dev_count) |
745 | in_dev_count = i + 1; |
746 | |
747 | return i; |
748 | } |
749 | |
750 | /* |
751 | * To reduce size of game specific configs, default binds are not saved. |
752 | * So we mark default binds in in_config_start(), override them in in_config_bind_key(), |
753 | * and restore whatever default binds are left in in_config_end(). |
754 | */ |
755 | void in_config_start(void) |
756 | { |
757 | int i; |
758 | |
759 | /* mark all default binds, so they get overwritten by func below */ |
760 | for (i = 0; i < IN_MAX_DEVS; i++) { |
761 | int n, count, *binds, *def_binds; |
762 | |
763 | binds = in_devices[i].binds; |
764 | if (binds == NULL) |
765 | continue; |
766 | |
767 | count = in_devices[i].key_count; |
768 | def_binds = binds + count * IN_BINDTYPE_COUNT; |
769 | |
770 | for (n = 0; n < count * IN_BINDTYPE_COUNT; n++) |
771 | if (binds[n] == def_binds[n]) |
772 | binds[n] = -1; |
773 | } |
774 | } |
775 | |
776 | int in_config_bind_key(int dev_id, const char *key, int acts, int bind_type) |
777 | { |
778 | in_dev_t *dev; |
779 | int i, offs, kc; |
780 | |
781 | if (dev_id < 0 || dev_id >= IN_MAX_DEVS || bind_type >= IN_BINDTYPE_COUNT) |
782 | return -1; |
783 | dev = &in_devices[dev_id]; |
784 | |
785 | /* maybe a raw code? */ |
786 | if (key[0] == '\\' && key[1] == 'x') { |
787 | char *p = NULL; |
788 | kc = (int)strtoul(key + 2, &p, 16); |
789 | if (p == NULL || *p != 0) |
790 | kc = -1; |
791 | } |
792 | else { |
793 | /* device specific key name */ |
794 | if (dev->binds == NULL) { |
795 | dev->binds = in_alloc_binds(dev->drv_id, dev->key_count); |
796 | if (dev->binds == NULL) |
797 | return -1; |
798 | in_config_start(); |
799 | } |
800 | |
801 | kc = -1; |
802 | if (dev->key_names != NULL) { |
803 | for (i = 0; i < dev->key_count; i++) { |
804 | const char *k = dev->key_names[i]; |
805 | if (k != NULL && strcasecmp(k, key) == 0) { |
806 | kc = i; |
807 | break; |
808 | } |
809 | } |
810 | } |
811 | |
812 | if (kc < 0) |
813 | kc = DRV(dev->drv_id).get_key_code(key); |
814 | if (kc < 0 && strlen(key) == 1) { |
815 | /* assume scancode */ |
816 | kc = key[0]; |
817 | } |
818 | } |
819 | |
820 | if (kc < 0 || kc >= dev->key_count) { |
821 | lprintf("input: bad key: %s\n", key); |
822 | return -1; |
823 | } |
824 | |
825 | if (bind_type == IN_BINDTYPE_NONE) { |
826 | for (i = 0; i < IN_BINDTYPE_COUNT; i++) |
827 | dev->binds[IN_BIND_OFFS(kc, i)] = 0; |
828 | return 0; |
829 | } |
830 | |
831 | offs = IN_BIND_OFFS(kc, bind_type); |
832 | if (dev->binds[offs] == -1) |
833 | dev->binds[offs] = 0; |
834 | dev->binds[offs] |= acts; |
835 | return 0; |
836 | } |
837 | |
838 | void in_config_end(void) |
839 | { |
840 | int i; |
841 | |
842 | for (i = 0; i < IN_MAX_DEVS; i++) { |
843 | int n, t, ret, count, *binds, *def_binds; |
844 | in_dev_t *dev = &in_devices[i]; |
845 | |
846 | if (dev->binds == NULL) |
847 | continue; |
848 | |
849 | count = dev->key_count; |
850 | binds = dev->binds; |
851 | def_binds = binds + count * IN_BINDTYPE_COUNT; |
852 | |
853 | for (n = 0; n < count; n++) { |
854 | int is_default = 1; |
855 | for (t = 0; t < IN_BINDTYPE_COUNT; t++) |
856 | if (binds[IN_BIND_OFFS(n, t)] == -1) |
857 | binds[IN_BIND_OFFS(n, t)] = 0; |
858 | else |
859 | is_default = 0; |
860 | |
861 | if (is_default) |
862 | for (t = 0; t < IN_BINDTYPE_COUNT; t++) |
863 | binds[IN_BIND_OFFS(n, t)] = def_binds[IN_BIND_OFFS(n, t)]; |
864 | } |
865 | |
866 | if (dev->drv_data == NULL) |
867 | continue; |
868 | |
869 | ret = DRV(dev->drv_id).clean_binds(dev->drv_data, binds, def_binds); |
870 | if (ret == 0) { |
871 | /* no useable binds */ |
872 | free(dev->binds); |
873 | dev->binds = NULL; |
874 | } |
875 | } |
876 | } |
877 | |
878 | void in_debug_dump(void) |
879 | { |
880 | int i; |
881 | |
882 | lprintf("# drv probed binds name\n"); |
883 | for (i = 0; i < IN_MAX_DEVS; i++) { |
884 | in_dev_t *d = &in_devices[i]; |
885 | if (!d->probed && d->name == NULL && d->binds == NULL) |
886 | continue; |
887 | lprintf("%d %3d %6c %5c %s\n", i, d->drv_id, d->probed ? 'y' : 'n', |
888 | d->binds ? 'y' : 'n', d->name); |
889 | } |
890 | } |
891 | |
892 | /* handlers for unknown/not_preset drivers */ |
893 | |
894 | static void in_def_probe(void) {} |
895 | static void in_def_free(void *drv_data) {} |
896 | static int in_def_get_bind_count(void) { return 0; } |
897 | static void in_def_get_def_binds(int *binds) {} |
898 | static int in_def_clean_binds(void *drv_data, int *b, int *db) { return 0; } |
899 | static int in_def_get_config(void *drv_data, int what, int *val) { return -1; } |
900 | static int in_def_set_config(void *drv_data, int what, int val) { return -1; } |
901 | static int in_def_update_keycode(void *drv_data, int *is_down) { return 0; } |
902 | static int in_def_menu_translate(void *drv_data, int keycode) { return keycode; } |
903 | static int in_def_get_key_code(const char *key_name) { return -1; } |
904 | static const char *in_def_get_key_name(int keycode) { return NULL; } |
905 | |
906 | void in_init(void) |
907 | { |
908 | int i; |
909 | |
910 | memset(in_drivers, 0, sizeof(in_drivers)); |
911 | memset(in_devices, 0, sizeof(in_devices)); |
912 | in_dev_count = 0; |
913 | |
914 | for (i = 0; i < IN_DRVID_COUNT; i++) { |
915 | in_drivers[i].prefix = "none:"; |
916 | in_drivers[i].probe = in_def_probe; |
917 | in_drivers[i].free = in_def_free; |
918 | in_drivers[i].get_bind_count = in_def_get_bind_count; |
919 | in_drivers[i].get_def_binds = in_def_get_def_binds; |
920 | in_drivers[i].clean_binds = in_def_clean_binds; |
921 | in_drivers[i].get_config = in_def_get_config; |
922 | in_drivers[i].set_config = in_def_set_config; |
923 | in_drivers[i].update_keycode = in_def_update_keycode; |
924 | in_drivers[i].menu_translate = in_def_menu_translate; |
925 | in_drivers[i].get_key_code = in_def_get_key_code; |
926 | in_drivers[i].get_key_name = in_def_get_key_name; |
927 | } |
928 | |
929 | #ifdef IN_GP2X |
930 | in_gp2x_init(&in_drivers[IN_DRVID_GP2X]); |
931 | #endif |
932 | #ifdef IN_EVDEV |
933 | in_evdev_init(&in_drivers[IN_DRVID_EVDEV]); |
934 | #endif |
935 | #ifdef IN_VK |
936 | in_vk_init(&in_drivers[IN_DRVID_VK]); |
937 | #endif |
938 | } |
939 | |
940 | #if 0 |
941 | int main(void) |
942 | { |
943 | int ret; |
944 | |
945 | in_init(); |
946 | in_probe(); |
947 | |
948 | in_set_blocking(1); |
949 | |
950 | #if 1 |
951 | while (1) { |
952 | int dev = 0, down; |
953 | ret = in_update_keycode(&dev, &down); |
954 | lprintf("#%i: %i %i (%s)\n", dev, down, ret, in_get_key_name(dev, ret)); |
955 | } |
956 | #else |
957 | while (1) { |
958 | ret = in_menu_wait_any(); |
959 | lprintf("%08x\n", ret); |
960 | } |
961 | #endif |
962 | |
963 | return 0; |
964 | } |
965 | #endif |