X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=platform%2Flinux%2Fin_evdev.c;h=df4036831cf56967381267dcc70d6e825f8d5fc8;hb=d08e73261434dd37ec156d37094be98ceb6944c0;hp=80038e42f865953601e930598d84004b36166dfa;hpb=d1faa779b0630b22a89a9ba9481c33d7ddc5e8c2;p=picodrive.git diff --git a/platform/linux/in_evdev.c b/platform/linux/in_evdev.c index 80038e4..df40368 100644 --- a/platform/linux/in_evdev.c +++ b/platform/linux/in_evdev.c @@ -14,6 +14,7 @@ typedef struct { int fd; + int *kbits; int abs_lzone; int abs_rzone; int abs_tzone; @@ -32,6 +33,9 @@ typedef struct { #define KEYBITS_BIT_SET(x) (keybits[(x)/sizeof(keybits[0])/8] |= \ (1 << ((x) & (sizeof(keybits[0])*8-1)))) +#define KEYBITS_BIT_CLEAR(x) (keybits[(x)/sizeof(keybits[0])/8] &= \ + ~(1 << ((x) & (sizeof(keybits[0])*8-1)))) + static const char * const in_evdev_prefix = "evdev:"; static const char * const in_evdev_keys[KEY_CNT] = { [0 ... KEY_MAX] = NULL, @@ -122,11 +126,17 @@ static const char * const in_evdev_keys[KEY_CNT] = { static void in_evdev_probe(void) { + long keybits[KEY_CNT / sizeof(long) / 8]; + long absbits[(ABS_MAX+1) / sizeof(long) / 8]; int i; + // the kernel might support and return less keys then we know about, + // so make sure the buffers are clear. + memset(keybits, 0, sizeof(keybits)); + memset(absbits, 0, sizeof(absbits)); + for (i = 0;; i++) { - int keybits[KEY_CNT / sizeof(int)], absbits[(ABS_MAX+1)/sizeof(int)]; int support = 0, count = 0; in_evdev_t *dev; int u, ret, fd; @@ -158,7 +168,8 @@ static void in_evdev_probe(void) /* check for interesting keys */ for (u = 0; u < KEY_CNT; u++) { - if (KEYBITS_BIT(u) && u != KEY_POWER && u != KEY_SLEEP && u != BTN_TOUCH) + if (KEYBITS_BIT(u) && u != KEY_POWER && + u != KEY_SLEEP && u != BTN_TOUCH) count++; } @@ -169,6 +180,16 @@ static void in_evdev_probe(void) if (dev == NULL) goto skip; + ret = ioctl(fd, EVIOCGKEY(sizeof(keybits)), keybits); + if (ret == -1) { + printf("Warning: EVIOCGKEY not supported, will have to track state\n"); + dev->kbits = calloc(KEY_CNT, sizeof(int)); + if (dev->kbits == NULL) { + free(dev); + goto skip; + } + } + /* check for abs too */ if (support & (1 << EV_ABS)) { struct input_absinfo ainfo; @@ -235,23 +256,36 @@ int in_evdev_update(void *drv_data, const int *binds, int *result) { struct input_event ev[16]; struct input_absinfo ainfo; - int keybits[KEY_CNT / sizeof(int)]; + int keybits_[KEY_CNT / sizeof(int)]; + int *keybits = keybits_; in_evdev_t *dev = drv_data; int rd, ret, u; - while (1) { - rd = read(dev->fd, ev, sizeof(ev)); - if (rd < (int)sizeof(ev[0])) { - if (errno != EAGAIN) - perror("in_evdev: read failed"); - break; + if (dev->kbits == NULL) { + ret = ioctl(dev->fd, EVIOCGKEY(sizeof(keybits_)), keybits_); + if (ret == -1) { + perror("in_evdev: ioctl failed"); + return -1; } } - - ret = ioctl(dev->fd, EVIOCGKEY(sizeof(keybits)), keybits); - if (ret == -1) { - perror("in_evdev: ioctl failed"); - return -1; + else { + keybits = dev->kbits; + while (1) { + rd = read(dev->fd, ev, sizeof(ev)); + if (rd < (int)sizeof(ev[0])) { + if (errno != EAGAIN) + perror("in_evdev: read failed"); + break; + } + for (u = 0; u < rd / sizeof(ev[0]); u++) { + if (ev[u].type != EV_KEY) + continue; + else if (ev[u].value == 1) + KEYBITS_BIT_SET(ev[u].code); + else if (ev[u].value == 0) + KEYBITS_BIT_CLEAR(ev[u].code); + } + } } for (u = 0; u < KEY_CNT; u++) { @@ -289,6 +323,16 @@ static void in_evdev_set_blocking(void *drv_data, int y) perror("in_evdev: F_GETFL fcntl failed"); return; } + + if (flags & O_NONBLOCK) { + /* flush the event queue */ + struct input_event ev; + do { + ret = read(dev->fd, &ev, sizeof(ev)); + } + while (ret == sizeof(ev)); + } + if (y) flags &= ~O_NONBLOCK; else