blob: 97a2bebe340e601ba372482383de375993c6f85a (
plain) (
tree)
|
|
/* See LICENSE file for copyright and license details. */
#include "common.h"
#define DEFER_EINTR(ERROR_CONDITION, GOTO_ON_FAILURE)\
DEFER_EINTR_(device, ERROR_CONDITION, GOTO_ON_FAILURE)
static int
require_evbuf_size(struct libgamepad_device *device, size_t n)
{
void *new;
if (n < device->internals->evbuf_size)
return 0;
if (n > SIZE_MAX / sizeof(*device->internals->evbuf)) {
errno = ENOMEM;
return -1;
}
new = realloc(device->internals->evbuf, n * sizeof(*device->internals->evbuf));
if (!new)
return -1;
device->internals->evbuf = new;
device->internals->evbuf_size = n;
return 0;
}
int
libgamepad_generate_sync_events(struct libgamepad_device *device)
{
unsigned long int bits[ELEMS_REQUIRED(ELEMSOF(device->button_map), long int)];
struct input_absinfo abs;
size_t queued = device->internals->ev_queued;
int16_t j;
unsigned int i, max;
int r, saved_errno = errno;
if (device->internals->deferred_error) {
errno = device->internals->deferred_error;
device->internals->deferred_error = 0;
return -1;
}
if (device->nbuttons) {
DEFER_EINTR((r = ioctl(device->fd, EVIOCGKEY(sizeof(bits)), bits)) < 0, fail);
max = (unsigned int)r * 8;
for (i = 0; i < max && i < ELEMSOF(device->button_map); i++) {
j = device->button_map[i];
if (j >= 0 && GETBIT(bits, i) != GETBIT(device->internals->buttons, (uint16_t)j)) {
if (require_evbuf_size(device, queued + 1))
goto fail;
device->internals->evbuf[queued].input_event_sec = 0;
device->internals->evbuf[queued].input_event_usec = 0;
device->internals->evbuf[queued].type = EV_KEY;
device->internals->evbuf[queued].code = (uint16_t)i;
device->internals->evbuf[queued].value = (int32_t)GETBIT(bits, i);
queued += 1;
}
}
}
for (i = 0; i < device->nabsolute_axes; i++) {
DEFER_EINTR(ioctl(device->fd, EVIOCGABS((unsigned int)device->absolute_axes[i]), &abs) < 0, fail);
if (device->internals->absinfo[i].value != abs.value) {
if (require_evbuf_size(device, queued + 1))
goto fail;
device->internals->evbuf[queued].input_event_sec = 0;
device->internals->evbuf[queued].input_event_usec = 0;
device->internals->evbuf[queued].type = EV_ABS;
device->internals->evbuf[queued].code = device->absolute_axes[i];
device->internals->evbuf[queued].value = abs.value;
queued += 1;
}
}
/* TODO synchronise multitouch state */
if (queued > device->internals->ev_queued) {
if (require_evbuf_size(device, queued + 1))
goto fail;
device->internals->evbuf[queued].input_event_sec = 0;
device->internals->evbuf[queued].input_event_usec = 0;
device->internals->evbuf[queued].type = EV_SYN;
device->internals->evbuf[queued].code = SYN_REPORT;
device->internals->evbuf[queued].value = 0;
queued += 1;
}
device->internals->require_sync = 0;
device->internals->ev_queued = queued;
errno = saved_errno;
return 0;
fail:
return -1;
}
|