aboutsummaryrefslogtreecommitdiffstats
path: root/libgamepad_next_event.c
diff options
context:
space:
mode:
Diffstat (limited to 'libgamepad_next_event.c')
-rw-r--r--libgamepad_next_event.c145
1 files changed, 107 insertions, 38 deletions
diff --git a/libgamepad_next_event.c b/libgamepad_next_event.c
index c74d641..b9d8986 100644
--- a/libgamepad_next_event.c
+++ b/libgamepad_next_event.c
@@ -2,56 +2,125 @@
#include "common.h"
-int
-libgamepad_next_event(struct libgamepad_device *device, struct libgamepad_input_event *eventp)
+static int
+update_button(struct libgamepad_device *device, uint16_t code, int32_t value)
{
- int r;
- struct input_event ev;
+ int16_t index;
+ if (code > ELEMSOF(device->button_map))
+ return 0;
+ index = device->button_map[code];
+ if (index < 0 || GETBIT(device->internals->buttons, (size_t)index) == value)
+ return 1;
+ XORBIT(device->internals->buttons, (size_t)index);
+ return 1;
+}
+
+
+static int
+update_absolute_axis(struct libgamepad_device *device, uint16_t code, int32_t value)
+{
+ int16_t index;
+ if (code > ELEMSOF(device->absolute_axis_map))
+ return 0;
+ index = device->absolute_axis_map[code];
+ if (index < 0 || device->internals->absinfo[index].value == value)
+ return 0;
+ device->internals->absinfo[index].value = value;
+ return 1;
+}
+
+
+ssize_t
+libgamepad_next_event(struct libgamepad_device *device, struct libgamepad_input_event *events, size_t max)
+{
+ size_t i, dequeued = 0;
+ void *new;
+ ssize_t r;
+ struct input_event *ev;
+
+ if (device->internals->deferred_error) {
+ errno = device->internals->deferred_error;
+ device->internals->deferred_error = 0;
+ return -1;
+ }
+
+ if (device->internals->require_sync)
+ if (libgamepad_drain_events(device))
+ return -1;
- if (!device->internals->require_sync) {
- r = libevdev_next_event(device->internals->dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
- if (r < 0) {
- errno = -r;
+ if (max > device->internals->evbuf_size) {
+ if (max > SIZE_MAX / sizeof(*device->internals->evbuf)) {
+ errno = ENOMEM;
return -1;
}
- } else {
- r = libevdev_next_event(device->internals->dev, LIBEVDEV_READ_FLAG_SYNC, &ev);
- if (r == -EAGAIN) {
- device->internals->require_sync = 0; /* yes, this is how it is document */
- return 0;
- } else if (r < 0) {
- errno = -r;
+ new = realloc(device->internals->evbuf, max * sizeof(*device->internals->evbuf));
+ if (!new)
+ return -1;
+ device->internals->evbuf = new;
+ device->internals->evbuf_size = max;
+ }
+
+ dequeued = device->internals->ev_queued < max ? device->internals->ev_queued : max;
+ if (!dequeued || dequeued < max) {
+ r = read(device->fd, &device->internals->evbuf[dequeued], (max - dequeued) * sizeof(*device->internals->evbuf));
+ if (r <= 0) {
+ if (!r && (max - dequeued))
+ errno = ENODEV;
+ return -1;
+ } else if ((size_t)r % sizeof(*device->internals->evbuf)) {
+ errno = EBADF;
return -1;
}
- if (r != LIBEVDEV_READ_STATUS_SYNC) /* just to be safe */
- device->internals->require_sync = 0;
+ } else {
+ r = 0;
}
+ r += (ssize_t)(dequeued * sizeof(*device->internals->evbuf));
- eventp->sync_event = (r == LIBEVDEV_READ_STATUS_SYNC);
- eventp->code = ev.code;
- eventp->value = ev.value;
- eventp->time.tv_sec = ev.input_event_sec;
- eventp->time.tv_usec = ev.input_event_usec;
+ i = 0;
+ for (ev = device->internals->evbuf; r; r -= (ssize_t)sizeof(*device->internals->evbuf), ev++) {
+ events[i].code = ev->code;
+ events[i].value = ev->value;
+ events[i].time.tv_sec = ev->input_event_sec;
+ events[i].time.tv_usec = ev->input_event_usec;
- switch (ev.type) {
- case EV_KEY:
- eventp->type = LIBGAMEPAD_BUTTON;
- return 1;
+ switch (ev->type) {
+ case EV_SYN:
+ events[i].code = 0;
+ events[i].value = 0;
+ if (ev->code == SYN_REPORT) {
+ events[i++].type = LIBGAMEPAD_EVENT_END;
+ } else if (ev->code == SYN_DROPPED) {
+ device->internals->require_sync = device->auto_sync;
+ events[i++].type = LIBGAMEPAD_EVENT_DROP;
+ goto out;
+ }
+ break;
- case EV_ABS:
- eventp->type = LIBGAMEPAD_ABSOLUTE_AXIS;
- return 1;
+ case EV_KEY:
+ ev->value = !!ev->value;
+ if (update_button(device, ev->code, ev->value))
+ events[i++].type = LIBGAMEPAD_BUTTON;
+ break;
- case EV_REL:
- eventp->type = LIBGAMEPAD_RELATIVE_AXIS;
- return 1;
+ case EV_REL:
+ events[i++].type = LIBGAMEPAD_RELATIVE_AXIS;
+ break;
- case EV_SYN:
- if (ev.code == SYN_DROPPED)
- device->internals->require_sync = 1;
- return 0;
+ case EV_ABS:
+ if (update_absolute_axis(device, ev->code, ev->value))
+ events[i++].type = LIBGAMEPAD_ABSOLUTE_AXIS;
+ break;
- default:
- return 0;
+ default:
+ break;
+ }
+ }
+
+out:
+ if (dequeued) {
+ device->internals->ev_queued -= dequeued;
+ memmove(&device->internals->evbuf[0], &device->internals->evbuf[dequeued],
+ device->internals->ev_queued * sizeof(*device->internals->evbuf));
}
+ return (ssize_t)i;
}