From 819ef02513ff0611df7f917125e9e6f5c67305e3 Mon Sep 17 00:00:00 2001 From: notaz Date: Thu, 1 Jan 2009 22:35:33 +0000 Subject: [PATCH] input layer mostly complete git-svn-id: file:///home/notaz/opt/svn/PicoDrive@626 be3aeb3a-fb24-0410-a615-afba39da0efa --- platform/common/input.c | 299 +++++++++++++++++++++++++++++++------- platform/common/input.h | 31 +++- platform/linux/in_evdev.c | 115 ++++++++++++--- platform/linux/in_evdev.h | 24 +-- 4 files changed, 374 insertions(+), 95 deletions(-) diff --git a/platform/common/input.c b/platform/common/input.c index 48e3c0af..2fd38d8b 100644 --- a/platform/common/input.c +++ b/platform/common/input.c @@ -12,22 +12,17 @@ typedef struct int *binds; char *name; int probed:1; - int ignore:1; } in_dev_t; -#define IN_MAX_DEVS 10 - +static in_drv_t in_drivers[IN_DRVID_COUNT]; static in_dev_t in_devices[IN_MAX_DEVS]; static int in_dev_count = 0; +#define DRV(id) in_drivers[(unsigned)(id) < IN_DRVID_COUNT ? (id) : 0] + static int in_bind_count(int drv_id) { - int count = 0; - switch (drv_id) { - case IN_DRVID_EVDEV: - count = in_evdev_bind_count(); - break; - } + int count = DRV(drv_id).get_bind_count(); if (count <= 0) printf("input: failed to get bind count for drv %d\n", drv_id); @@ -36,27 +31,26 @@ static int in_bind_count(int drv_id) static int *in_alloc_binds(int drv_id) { - int count, *ret; + int count, *binds; count = in_bind_count(drv_id); - if (count <= 0) { - printf("input: failed to get bind count for drv %d\n", drv_id); + if (count <= 0) return NULL; - } - ret = malloc(count * sizeof(*ret)); - return ret; + binds = calloc(count * 2, sizeof(binds[0])); + if (binds == NULL) + return NULL; + + DRV(drv_id).get_def_binds(binds + count); + memcpy(binds, binds + count, count * sizeof(binds[0])); + + return binds; } static void in_free(in_dev_t *dev) { - if (dev->probed) { - switch (dev->drv_id) { - case IN_DRVID_EVDEV: - in_evdev_free(dev->drv_data); - break; - } - } + if (dev->probed) + DRV(dev->drv_id).free(dev->drv_data); dev->probed = 0; dev->drv_data = NULL; free(dev->name); @@ -68,7 +62,7 @@ static void in_free(in_dev_t *dev) /* to be called by drivers */ void in_register(const char *nname, int drv_id, void *drv_data) { - int i, dupe_count = 0, *binds; + int i, ret, dupe_count = 0, *binds; char name[256], *name_end, *tmp; strncpy(name, nname, sizeof(name)); @@ -122,6 +116,15 @@ update: in_devices[i].probed = 1; in_devices[i].drv_id = drv_id; in_devices[i].drv_data = drv_data; + + if (in_devices[i].binds != NULL) { + ret = DRV(drv_id).clean_binds(drv_data, in_devices[i].binds); + if (ret == 0) { + /* no useable binds */ + free(in_devices[i].binds); + in_devices[i].binds = NULL; + } + } } void in_probe(void) @@ -130,7 +133,8 @@ void in_probe(void) for (i = 0; i < in_dev_count; i++) in_devices[i].probed = 0; - in_evdev_probe(); + for (i = 1; i < IN_DRVID_COUNT; i++) + in_drivers[i].probe(); /* get rid of devs without binds and probes */ for (i = 0; i < in_dev_count; i++) { @@ -145,18 +149,6 @@ void in_probe(void) } } -void in_clear_binds(const char *devname) -{ -/* int count; - - count = in_bind_count(drv_id); - if (count <= 0) { - printf("input: failed to get bind count for drv %d\n", dev->drv_id); - return NULL; - } -*/ -} - int in_update(void) { int i, result = 0; @@ -164,9 +156,11 @@ int in_update(void) for (i = 0; i < in_dev_count; i++) { if (in_devices[i].probed && in_devices[i].binds != NULL) { switch (in_devices[i].drv_id) { +#ifdef IN_EVDEV case IN_DRVID_EVDEV: result |= in_evdev_update(in_devices[i].drv_data, in_devices[i].binds); break; +#endif } } } @@ -192,13 +186,8 @@ void in_set_blocking(int is_blocking) int i; for (i = 0; i < in_dev_count; i++) { - if (in_devices[i].probed) { - switch (in_devices[i].drv_id) { - case IN_DRVID_EVDEV: - in_evdev_set_blocking(in_devices[i].drv_data, is_blocking); - break; - } - } + if (in_devices[i].probed) + DRV(in_devices[i].drv_id).set_blocking(in_devices[i].drv_data, is_blocking); } } @@ -247,11 +236,9 @@ int in_update_menu(void) while (1) { - int code, is_down = 0; - code = in_update_keycode(NULL, &is_down); -#ifdef IN_EVDEV - code = in_evdev_menu_translate(code); -#endif + int code, is_down = 0, dev_id = 0; + code = in_update_keycode(&dev_id, &is_down); + code = DRV(in_devices[dev_id].drv_id).menu_translate(code); if (code == 0) continue; if (is_down) @@ -266,24 +253,230 @@ int in_update_menu(void) return keys_active; } +const int *in_get_dev_binds(int dev_id) +{ + if (dev_id < 0 || dev_id >= IN_MAX_DEVS) + return NULL; + + return in_devices[dev_id].binds; +} + +const int *in_get_dev_def_binds(int dev_id) +{ + int count; + + if (dev_id < 0 || dev_id >= IN_MAX_DEVS) + return NULL; + + count = in_bind_count(in_devices[dev_id].drv_id); + return in_devices[dev_id].binds + count; +} + +int in_get_dev_bind_count(int dev_id) +{ + if (dev_id < 0 || dev_id >= IN_MAX_DEVS) + return 0; + + return in_bind_count(in_devices[dev_id].drv_id); +} + +const char *in_get_dev_name(int dev_id) +{ + if (dev_id < 0 || dev_id >= IN_MAX_DEVS) + return NULL; + + return in_devices[dev_id].name; +} + const char *in_get_key_name(int dev_id, int keycode) { if (dev_id < 0 || dev_id >= IN_MAX_DEVS) return "Unkn0"; - switch (in_devices[dev_id].drv_id) { - case IN_DRVID_EVDEV: - return in_evdev_get_key_name(keycode); + + return DRV(in_devices[dev_id].drv_id).get_key_name(keycode); +} + +/* returns device id, or -1 on error */ +int in_config_parse_dev(const char *name) +{ + int drv_id = -1, i; + + for (i = 0; i < IN_DRVID_COUNT; i++) { + int len = strlen(in_drivers[i].prefix); + if (strncmp(name, in_drivers[i].prefix, len) == 0) { + drv_id = i; + break; + } + } + + if (drv_id < 0) { + printf("input: missing driver for %s\n", name); + return -1; + } + + for (i = 0; i < in_dev_count; i++) + { + if (in_devices[i].name == NULL) + continue; + if (strcmp(in_devices[i].name, name) == 0) + return i; + } + + if (i >= IN_MAX_DEVS) + { + /* try to find unused device */ + for (i = 0; i < IN_MAX_DEVS; i++) + if (in_devices[i].name == NULL) break; + if (i >= IN_MAX_DEVS) { + printf("input: too many devices, can't add %s\n", name); + return -1; + } + } + + memset(&in_devices[i], 0, sizeof(in_devices[i])); + + in_devices[i].name = strdup(name); + if (in_devices[i].name == NULL) + return -1; + + if (i + 1 > in_dev_count) + in_dev_count = i + 1; + in_devices[i].drv_id = drv_id; + + return i; +} + +void in_config_start(void) +{ + int i; + + /* mark all default binds, so they get overwritten by func below */ + for (i = 0; i < IN_MAX_DEVS; i++) { + int n, count, *binds, *def_binds; + + if (in_devices[i].binds == NULL) + continue; + + count = in_bind_count(in_devices[i].drv_id); + binds = in_devices[i].binds; + def_binds = binds + count; + + for (n = 0; n < count; n++) + if (binds[n] == def_binds[n]) + binds[n] = -1; + } +} + +int in_config_bind_key(int dev_id, const char *key, int binds) +{ + int kc; + + if (dev_id < 0 || dev_id >= IN_MAX_DEVS) + return -1; + + if (in_devices[dev_id].binds == NULL) { + in_devices[dev_id].binds = in_alloc_binds(in_devices[dev_id].drv_id); + if (in_devices[dev_id].binds == NULL) + return -1; + in_config_start(); + } + + kc = DRV(in_devices[dev_id].drv_id).get_key_code(key); + if (kc < 0) { + printf("input: bad key: %s\n", key); + return -1; } - return "Unkn1"; + if (in_devices[dev_id].binds[kc] == -1) + in_devices[dev_id].binds[kc] = 0; + in_devices[dev_id].binds[kc] |= binds; + + return 0; +} + +void in_config_end(void) +{ + int i; + + for (i = 0; i < IN_MAX_DEVS; i++) { + int n, ret, count, *binds, *def_binds; + + if (in_devices[i].binds == NULL) + continue; + + count = in_bind_count(in_devices[i].drv_id); + binds = in_devices[i].binds; + def_binds = binds + count; + + for (n = 0; n < count; n++) + if (binds[n] == -1) + binds[n] = def_binds[n]; + + if (in_devices[i].drv_data == NULL) + continue; + + ret = DRV(in_devices[i].drv_id).clean_binds(in_devices[i].drv_data, binds); + if (ret == 0) { + /* no useable binds */ + free(binds); + in_devices[i].binds = NULL; + } + } } +void in_debug_dump(void) +{ + int i; + + printf("# drv probed binds name\n"); + for (i = 0; i < IN_MAX_DEVS; i++) { + in_dev_t *d = &in_devices[i]; + if (!d->probed && d->name == NULL && d->binds == NULL) + continue; + printf("%d %3d %6c %5c %s\n", i, d->drv_id, d->probed ? 'y' : 'n', + d->binds ? 'y' : 'n', d->name); + } +} + +/* handlers for unknown/not_preset drivers */ + +static void in_def_probe(void) {} +static void in_def_free(void *drv_data) {} +static int in_def_get_bind_count(void) { return 0; } +static void in_def_get_def_binds(int *binds) {} +static int in_def_clean_binds(void *drv_data, int *binds) { return 0; } +static void in_def_set_blocking(void *data, int y) {} +static int in_def_menu_translate(int keycode) { return keycode; } +static int in_def_get_key_code(const char *key_name) { return 0; } +static const char *in_def_get_key_name(int keycode) { return NULL; } + void in_init(void) { + int i; + + memset(in_drivers, 0, sizeof(in_drivers)); memset(in_devices, 0, sizeof(in_devices)); in_dev_count = 0; + + for (i = 0; i < IN_DRVID_COUNT; i++) { + in_drivers[i].prefix = "none:"; + in_drivers[i].probe = in_def_probe; + in_drivers[i].free = in_def_free; + in_drivers[i].get_bind_count = in_def_get_bind_count; + in_drivers[i].get_def_binds = in_def_get_def_binds; + in_drivers[i].clean_binds = in_def_clean_binds; + in_drivers[i].set_blocking = in_def_set_blocking; + in_drivers[i].menu_translate = in_def_menu_translate; + in_drivers[i].get_key_code = in_def_get_key_code; + in_drivers[i].get_key_name = in_def_get_key_name; + } + +#ifdef IN_EVDEV + in_evdev_init(&in_drivers[IN_DRVID_EVDEV]); +#endif } +#if 0 int main(void) { int ret; @@ -308,4 +501,4 @@ int main(void) return 0; } - +#endif diff --git a/platform/common/input.h b/platform/common/input.h index 5f0fa179..848012d4 100644 --- a/platform/common/input.h +++ b/platform/common/input.h @@ -1,7 +1,25 @@ +#define IN_MAX_DEVS 10 + enum { - IN_DRVID_EVDEV = 1, + IN_DRVID_UNKNOWN = 0, + IN_DRVID_EVDEV, + IN_DRVID_COUNT }; +typedef struct { + const char *prefix; + void (*probe)(void); + void (*free)(void *drv_data); + int (*get_bind_count)(void); + void (*get_def_binds)(int *binds); + int (*clean_binds)(void *drv_data, int *binds); + void (*set_blocking)(void *data, int y); + int (*menu_translate)(int keycode); + int (*get_key_code)(const char *key_name); + const char * (*get_key_name)(int keycode); +} in_drv_t; + + /* to be called by drivers */ void in_register(const char *nname, int drv_id, void *drv_data); @@ -11,4 +29,15 @@ int in_update(void); void in_set_blocking(int is_blocking); int in_update_keycode(int *dev_id, int *is_down); int in_update_menu(void); +int in_get_dev_bind_count(int dev_id); +void in_config_start(void); +int in_config_parse_dev(const char *dev_name); +int in_config_bind_key(int dev_id, const char *key, int mask); +void in_config_end(void); +int in_bind_key(int dev_id, int keycode, int mask); +void in_debug_dump(void); + +const int *in_get_dev_binds(int dev_id); +const int *in_get_dev_def_binds(int dev_id); +const char *in_get_dev_name(int dev_id); const char *in_get_key_name(int dev_id, int keycode); diff --git a/platform/linux/in_evdev.c b/platform/linux/in_evdev.c index fe4a8860..cfb31b6c 100644 --- a/platform/linux/in_evdev.c +++ b/platform/linux/in_evdev.c @@ -12,10 +12,11 @@ #include "../common/input.h" #include "in_evdev.h" -#define BIT(x) (keybits[(x)/sizeof(keybits[0])/8] & \ +#define KEYBITS_BIT(x) (keybits[(x)/sizeof(keybits[0])/8] & \ (1 << ((x) & (sizeof(keybits[0])*8-1)))) -static const char *in_evdev_keys[KEY_MAX + 1] = { +static const char * const in_evdev_prefix = "evdev:"; +static const char * const in_evdev_keys[KEY_MAX + 1] = { [0 ... KEY_MAX] = NULL, [KEY_RESERVED] = "Reserved", [KEY_ESC] = "Esc", [KEY_1] = "1", [KEY_2] = "2", @@ -102,13 +103,13 @@ static const char *in_evdev_keys[KEY_MAX + 1] = { }; -int in_evdev_probe(void) +static void in_evdev_probe(void) { int i; for (i = 0;; i++) { - int u, ret, fd, keybits[KEY_MAX/sizeof(int)]; + int u, ret, fd, keybits[(KEY_MAX+1)/sizeof(int)]; int support = 0, count = 0; char name[64]; @@ -134,15 +135,15 @@ int in_evdev_probe(void) } /* check for interesting keys */ - for (u = 0; u < KEY_MAX; u++) { - if (BIT(u) && u != KEY_POWER && u != KEY_SLEEP) + for (u = 0; u < KEY_MAX + 1; u++) { + if (KEYBITS_BIT(u) && u != KEY_POWER && u != KEY_SLEEP) count++; } if (count == 0) goto skip; - strcpy(name, "evdev:"); + strcpy(name, in_evdev_prefix); ioctl(fd, EVIOCGNAME(sizeof(name)-6), name+6); printf("in_evdev: found \"%s\" with %d events (type %08x)\n", name+6, count, support); @@ -152,24 +153,22 @@ int in_evdev_probe(void) skip: close(fd); } - - return 0; } -void in_evdev_free(void *drv_data) +static void in_evdev_free(void *drv_data) { close((int)drv_data); } -int in_evdev_bind_count(void) +static int in_evdev_get_bind_count(void) { - return 512; + return KEY_MAX + 1; } int in_evdev_update(void *drv_data, int *binds) { struct input_event ev[16]; - int keybits[KEY_MAX/sizeof(int)]; + int keybits[(KEY_MAX+1)/sizeof(int)]; int fd = (int)drv_data; int result = 0, changed = 0; int rd, ret, u; @@ -196,8 +195,8 @@ int in_evdev_update(void *drv_data, int *binds) } printf("#%d: ", fd); - for (u = 0; u < KEY_MAX; u++) { - if (BIT(u)) { + for (u = 0; u < KEY_MAX + 1; u++) { + if (KEYBITS_BIT(u)) { printf(" %d", u); result |= binds[u]; } @@ -207,7 +206,7 @@ int in_evdev_update(void *drv_data, int *binds) return result; } -void in_evdev_set_blocking(void *data, int y) +static void in_evdev_set_blocking(void *data, int y) { long flags; int ret; @@ -275,7 +274,7 @@ int in_evdev_update_keycode(void **data, int dcount, int *which, int *is_down) } } -int in_evdev_menu_translate(int keycode) +static int in_evdev_menu_translate(int keycode) { switch (keycode) { /* keyboards */ @@ -289,10 +288,24 @@ int in_evdev_menu_translate(int keycode) } } -const char *in_evdev_get_key_name(int keycode) +static int in_evdev_get_key_code(const char *key_name) +{ + int i; + + for (i = 0; i < KEY_MAX + 1; i++) { + const char *k = in_evdev_keys[i]; + if (k != NULL && k[0] == key_name[0] && + strcasecmp(k, key_name) == 0) + return i; + } + + return -1; +} + +static const char *in_evdev_get_key_name(int keycode) { const char *name = NULL; - if (keycode >= 0 && keycode < KEY_MAX) + if (keycode >= 0 && keycode <= KEY_MAX) name = in_evdev_keys[keycode]; if (name == NULL) name = "Unkn"; @@ -300,3 +313,67 @@ const char *in_evdev_get_key_name(int keycode) return name; } +static const struct { + short code; + short bit; +} in_evdev_def_binds[] = +{ + /* MXYZ SACB RLDU */ + { KEY_UP, 0 }, + { KEY_DOWN, 1 }, + { KEY_LEFT, 2 }, + { KEY_RIGHT, 3 }, + { KEY_S, 4 }, /* B */ + { KEY_D, 5 }, /* C */ + { KEY_A, 6 }, /* A */ + { KEY_ENTER, 7 }, +}; + +#define DEF_BIND_COUNT (sizeof(in_evdev_def_binds) / sizeof(in_evdev_def_binds[0])) + +static void in_evdev_get_def_binds(int *binds) +{ + int i; + + for (i = 0; i < DEF_BIND_COUNT; i++) + binds[in_evdev_def_binds[i].code] = 1 << in_evdev_def_binds[i].bit; +} + +/* remove bad binds, count good ones */ +static int in_evdev_clean_binds(void *drv_data, int *binds) +{ + int keybits[(KEY_MAX+1)/sizeof(int)]; + int i, ret, count = 0; + + ret = ioctl((int)drv_data, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits); + if (ret == -1) { + perror("in_evdev: ioctl failed"); + memset(keybits, 0xff, sizeof(keybits)); /* mark all as good */ + } + + for (i = 0; i < KEY_MAX + 1; i++) { + if (!KEYBITS_BIT(i)) + binds[i] = binds[i + KEY_MAX + 1] = 0; + if (binds[i]) + count++; + } + + return count; +} + +void in_evdev_init(void *vdrv) +{ + in_drv_t *drv = vdrv; + + drv->prefix = in_evdev_prefix; + drv->probe = in_evdev_probe; + drv->free = in_evdev_free; + drv->get_bind_count = in_evdev_get_bind_count; + drv->get_def_binds = in_evdev_get_def_binds; + drv->clean_binds = in_evdev_clean_binds; + drv->set_blocking = in_evdev_set_blocking; + drv->menu_translate = in_evdev_menu_translate; + drv->get_key_code = in_evdev_get_key_code; + drv->get_key_name = in_evdev_get_key_name; +} + diff --git a/platform/linux/in_evdev.h b/platform/linux/in_evdev.h index a7a7925c..0219c7e9 100644 --- a/platform/linux/in_evdev.h +++ b/platform/linux/in_evdev.h @@ -1,25 +1,5 @@ -#ifdef IN_EVDEV - -int in_evdev_probe(void); -void in_evdev_free(void *drv_data); -int in_evdev_bind_count(void); int in_evdev_update(void *drv_data, int *binds); -void in_evdev_set_blocking(void *data, int y); -int in_evdev_menu_translate(int keycode); -const char *in_evdev_get_key_name(int keycode); - -#else - -#define in_evdev_probe() -1 -#define in_evdev_free(x) -#define in_evdev_bind_count() 0 -#define in_evdev_update(x,y) 0 -#define in_evdev_set_blocking(x,y) -#define in_evdev_menu_translate 0 -#define in_evdev_get_key_name "Unkn" - -#endif - -int in_evdev_update_keycode(void **data, int count, int *which, int *is_down); +int in_evdev_update_keycode(void **data, int count, int *which, int *is_down); +void in_evdev_init(void *vdrv); -- 2.39.5