diff options
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | common.h | 16 | ||||
-rw-r--r-- | config.mk | 2 | ||||
-rw-r--r-- | libgamepad.h | 161 | ||||
-rw-r--r-- | libgamepad_close_device.c | 8 | ||||
-rw-r--r-- | libgamepad_get_absolute_axis_info.c | 4 | ||||
-rw-r--r-- | libgamepad_get_button_is_pressed.c | 11 | ||||
-rw-r--r-- | libgamepad_open_device.c | 289 | ||||
-rw-r--r-- | test-details.c | 2 |
9 files changed, 412 insertions, 83 deletions
@@ -3,7 +3,7 @@ Add support for profiles (conformation, button names/icons/colours, controller l Add support for quirks Add support for leds Add support for accelerometer and gyroscope -Add support for creating instance from a file descriptor Add man pages Add readme file Add force feedback tests +Fix error details in .h documentation @@ -18,10 +18,24 @@ #include <unistd.h> #include <libevdev/libevdev.h> +#include <libsha2.h> #include <libudev.h> +#if defined(__GNUC__) +# define LIBGAMEPAD_CONST__ __attribute__((__const__)) +#else +# define LIBGAMEPAD_CONST__ +#endif + + +#define READ_(ARR, I) ((ARR)[(I) / BITSOF(*(ARR))]) +#define SHIFT_(ARR, I) ((I) % BITSOF(*(ARR))) + #define ELEMSOF(A) (sizeof(A) / sizeof(*(A))) +#define BITSOF(T) (8 * sizeof(T)) +#define SETBIT(ARR, I) (READ_(ARR, I) |= 1 << SHIFT_(ARR, I)) +#define GETBIT(ARR, I) ((READ_(ARR, I) >> SHIFT_(ARR, I)) & 1) struct libgamepad_attachment_monitor { @@ -34,6 +48,8 @@ struct libgamepad_device_internals { int close_fd; int require_sync; struct libevdev *dev; + struct input_absinfo *absinfo; + uint8_t *buttons; }; @@ -9,6 +9,6 @@ CFLAGS = -Wall -g LDFLAGS = LIBS_CFLAGS = $$(pkg-config --cflags libevdev) -LIBS_LDFLAGS = $$(pkg-config --libs libevdev) -ludev -lm +LIBS_LDFLAGS = $$(pkg-config --libs libevdev) -ludev -lm -lsha2 INPUT_EVENT_CODES_H = /usr/include/linux/input-event-codes.h diff --git a/libgamepad.h b/libgamepad.h index b0efec4..e7abd6a 100644 --- a/libgamepad.h +++ b/libgamepad.h @@ -15,6 +15,13 @@ #include <libevdev/libevdev.h> +#if defined(__GNUC__) +# define LIBGAMEPAD_PURE__ __attribute__((__pure__)) +#else +# define LIBGAMEPAD_PURE__ +#endif + + /** * Opaque structure for monitoring device attachment changes */ @@ -265,7 +272,6 @@ enum libgamepad_game_controller { * Digital button "R" at upper right index finger position * Digital button "ZL" at lower left index finger position * Digital button "ZR" at lower right index finger position - * Digital Stadia (icon: brand) button between analogue sticks * 2 digital buttons at inner left thumb position: * - North = "−" * - East = Capture (icon: circle; shape: square) @@ -491,7 +497,30 @@ enum libgamepad_game_controller { * * Released 2012-11-18 for Wii U * - * TODO Document Wii U Pro Controller + * Layout: + * Clickable analogue stick at upper left thumb position + * Clickable analogue stick at upper right thumb position + * Digital D-pad at lower left thumb position + * 4 digital buttons at lower right thumb position: + * - North = "X" + * - West = "Y" + * - South = "B" + * - East = "A" + * Digital button "L" at upper left index finger position + * Digital button "R" at upper right index finger position + * Digital button "ZL" at lower left index finger position + * Digital button "ZR" at lower right index finger position + * 3 digital buttons at centre thumb position: + * - West = "SELECT" (icon: minus symbol) + * - Centre = "HOME" (icon: house) + * - East = "START" (icon: plus symbol) + * Digital "POWER" (icon: power symbol with the 1 over top + * of the 0, colour: red) button at lower center thumb position + * + * Other features: + * - Wireless via Bluetooth + * - 4 digital LEDs numbered 1 through 4 (??) + * - 1 digital LEDs labelled "BATTERY" (??) */ LIBGAMEPAD_CONTROLLER_WII_U_PRO, @@ -525,9 +554,25 @@ enum libgamepad_game_controller { /** * Classic Controller Pro * - * Released 2009-??-?? for Wii + * Released 2009-08-01 for Wii * - * TODO Document Classic Controller Pro + * Layout: + * Digital D-pad at upper left thumb position + * Analogue stick at lower left thumb position + * Analogue stick at lower right thumb position + * 4 digital buttons at upper right thumb position: + * - North = "x" + * - West = "y" + * - South = "b" + * - East = "a" + * Digital button "L" at upper left index finger position + * Digital button "R" at upper right index finger position + * Digital button "ZL" at lower left index finger position + * Digital button "ZR" at lower right index finger position + * 3 digital buttons at centre thumb position: + * - West = "SELECT" (icon: minus symbol) + * - Centre = "HOME" (icon: house, colour: blue) + * - East = "START" (icon: plus symbol) */ LIBGAMEPAD_CONTROLLER_WII_CLASSIC_PRO, @@ -546,7 +591,23 @@ enum libgamepad_game_controller { * * Released 2006-11-19 for Wii * - * TODO Document Classic Controller + * Layout: + * Digital D-pad at upper left thumb position + * Analogue stick at lower left thumb position + * Analogue stick at lower right thumb position + * 4 digital buttons at upper right thumb position: + * - North = "x" + * - West = "y" + * - South = "b" + * - East = "a" + * Analogue button "L" at left index finger position + * Analogue button "R" at right index finger position + * Digital button "ZL" inward from left index finger position + * Digital button "ZR" inward from right index finger position + * 3 digital buttons at centre thumb position: + * - West = "SELECT" (icon: minus symbol) + * - Centre = "HOME" (icon: house, colour: blue) + * - East = "START" (icon: plus symbol) */ LIBGAMEPAD_CONTROLLER_WII_CLASSIC, @@ -555,7 +616,14 @@ enum libgamepad_game_controller { * * Released 2006-11-19 for Wii * - * TODO Document Nunchuk + * Layout: + * Designed to be held in the user's dominant hand + * Analogue stick at thumb position + * Digital button "C" at upper index finger position + * Digital button "Z" at lower index finger position + * + * Other features: + * - Accelerometer */ LIBGAMEPAD_CONTROLLER_NUNCHUK, @@ -574,6 +642,9 @@ enum libgamepad_game_controller { * Released 2010-10-28 for Wii * * Adds (3 axis?) gyroscope to `LIBGAMEPAD_CONTROLLER_WII_REMOTE` + * + * Conforming controllers: + * - Wii Remote with Wii MotionPlus adapter */ LIBGAMEPAD_CONTROLLER_WII_REMOTE_PLUS, @@ -763,7 +834,8 @@ enum libgamepad_game_controller { * * Released 1997-11-20 for PlayStation * - * TODO Document DualShock Analog Controller + * Adds rubble support to `LIBGAMEPAD_CONTROLLER_DUAL_ANALOG` + * (TODO What does digital mode on DualShock do?) */ LIBGAMEPAD_CONTROLLER_DUAL_SHOCK, @@ -771,8 +843,32 @@ enum libgamepad_game_controller { * Dual Analog Controller * * Released 1997-04-25 for PlayStation + * + * The first Japanese version of this controller + * had rumble support and is therefore better + * reported as `LIBGAMEPAD_CONTROLLER_DUAL_SHOCK` + * + * Layout: + * Digital D-pad at upper left thumb position + * Clickable analogue stick at lower left thumb position + * Clickable analogue stick at lower right thumb position + * 4 digital buttons at upper right thumb position + * - North = Triangle (colour: green) + * - West = Square (colour: pink) + * - South = Cross (colour: blue) + * - East = Circle (colour: red) + * Digital button "L1" at upper left index finger position + * Digital button "R1" at upper right index finger position + * Digital button "L2" at lower left index finger position + * Digital button "R2" at lower right index finger position + * 2 digital buttons at centre position: + * - West = "SELECT" (shape: flat rectangle) + * - East = "START" (shape: flat play icon) * - * TODO Document Dual Analog Controller + * Other features: + * - LED-indicated digital "ANALOG" button at south part of center position + * for toggling between analogue and digital mode + * (TODO What does digital mode on Dual Analog do?) */ LIBGAMEPAD_CONTROLLER_DUAL_ANALOG, @@ -885,7 +981,7 @@ enum libgamepad_game_controller { * Digital "MODE" button right index finger position * Digital "START" (shape: horizontal line) button at centre position * - * Conforming platforms: + * Conforming controllers: * - Sega Nomad (however "MODE" is east of "START" which is far south east of "A") */ LIBGAMEPAD_CONTROLLER_6_BUTTON_ARCADE_PAD, @@ -973,7 +1069,7 @@ enum libgamepad_game_controller { * - West = "SELECT" * - East = "START" * - * Conforming platforms: + * Conforming controllers: * - Nintendo Game Boy * - Supervision (however "START" is also labelled "PAUSE" and the "SELECT" and "START" * buttons are horizontal and north (slightly east) for "A" and "B" which @@ -1040,7 +1136,7 @@ enum libgamepad_game_controller { * Digital "L" button at left index finger position * Digital "R" button at right index finger position * - * Conforming platforms: + * Conforming controllers: * - Game King (however "SELECT" and "START" are north of D-pad, * "SELECT" to east and "START to west) */ @@ -1100,7 +1196,10 @@ enum libgamepad_game_controller { * BTN_EAST if there are 2 action buttons but reversed if there are 3 * action buttons: (from bottom up) BTN_EAST, BTN_SOUTH, BTN_WEST * (`LIBGAMEPAD_CONTROLLER_LINUX_4_12_RECTIFIED_3BTN` is added to deal - * with this problem). + * with this problem). In the event that a controller has only one + * action button (and truly is a gamepad and not a joystick), it shall + * be reported as BTN_SOUTH as this one is designated as mandatory + * (BTN_GAMEPAD) is an alias of it. */ LIBGAMEPAD_CONTROLLER_LINUX_4_12, @@ -1383,18 +1482,18 @@ struct libgamepad_device { /** * Human-readable device (sub- or superdevice) name */ - const char *name; + char *name; /** * ID that is supposted to be unique to the device * (sub- or superdevice) */ - const char *unique_id; + char *unique_id; /** * The location if the device */ - const char *physical_location; + char *physical_location; /** * Number of (digital) buttons/keys present @@ -1452,6 +1551,18 @@ struct libgamepad_device { * Bitmap of supported force feedback effects */ uint8_t force_feedback_support[(FF_CNT + 7) / 8]; + + /** + * Device fingerprint that does not take `.unique_id` + * into account + */ + char fingerprint[65]; + + /** + * Device fingerprint that does take `.unique_id` + * into account + */ + char fingerprint_unique[65]; }; @@ -1697,6 +1808,15 @@ int16_t libgamepad_get_relative_axis_by_name(const char *); /** * Get whether a button/key is pressed down or not * + * libgamepad caches the last read button/key state, + * and will return the cached .state The underlaying + * ioctl(3) will has the ability to read a state + * even when the device is grabbed, but even if the + * device is not grabbed, the state may be out of + * that. Because the state may be out of date, + * libgamepad reads the current state when a device + * is opened. + * * @param device The device to retrieve the information for * @param code The button/key * @return 1 if the button/key is pressed down, @@ -1707,11 +1827,20 @@ int libgamepad_get_button_is_pressed(struct libgamepad_device *, uint16_t); /** * Get information about an absolute axis * + * libgamepad caches the last read axis value, and + * will return the cached value. The underlaying + * ioctl(3) will has the ability to read a value + * even when the device is grabbed, but even if the + * device is not grabbed, the value may be out of + * that. Because the value may be out of date, + * libgamepad reads the current state when a device + * is opened. + * * @param device The device to retrieve the information for * @param code The axis * @return Information about the axis */ -const struct input_absinfo *libgamepad_get_absolute_axis_info(struct libgamepad_device *, uint16_t); +LIBGAMEPAD_PURE__ const struct input_absinfo *libgamepad_get_absolute_axis_info(struct libgamepad_device *, uint16_t); /* `struct input_absinfo` is defined in <linux/input.h> */ diff --git a/libgamepad_close_device.c b/libgamepad_close_device.c index 3b00149..273c7f8 100644 --- a/libgamepad_close_device.c +++ b/libgamepad_close_device.c @@ -11,14 +11,22 @@ libgamepad_close_device(struct libgamepad_device *device) close(device->fd); if (device->internals->dev) libevdev_free(device->internals->dev); + free(device->internals->absinfo); + free(device->internals->buttons); free(device->internals); device->internals = NULL; } free(device->buttons); free(device->absolute_axes); free(device->relative_axes); + free(device->name); + free(device->unique_id); + free(device->physical_location); device->buttons = NULL; device->absolute_axes = NULL; device->relative_axes = NULL; + device->name = NULL; + device->unique_id = NULL; + device->physical_location = NULL; } } diff --git a/libgamepad_get_absolute_axis_info.c b/libgamepad_get_absolute_axis_info.c index a5aa4d5..ebd38fd 100644 --- a/libgamepad_get_absolute_axis_info.c +++ b/libgamepad_get_absolute_axis_info.c @@ -5,5 +5,7 @@ const struct input_absinfo * libgamepad_get_absolute_axis_info(struct libgamepad_device *device, uint16_t code) { - return libevdev_get_abs_info(device->internals->dev, (unsigned int)code); + if ((size_t)code >= ELEMSOF(device->absolute_axis_map) || device->absolute_axis_map[code] == -1) + return NULL; + return &device->internals->absinfo[device->absolute_axis_map[code]]; } diff --git a/libgamepad_get_button_is_pressed.c b/libgamepad_get_button_is_pressed.c index e3c0265..3c545c1 100644 --- a/libgamepad_get_button_is_pressed.c +++ b/libgamepad_get_button_is_pressed.c @@ -2,8 +2,17 @@ #include "common.h" +#if defined(__GNUC__) +# pragma GCC diagnostic ignored "-Wsuggest-attribute=pure" +#endif + + int libgamepad_get_button_is_pressed(struct libgamepad_device *device, uint16_t code) { - return libevdev_get_event_value(device->internals->dev, EV_KEY, (unsigned int)code); + int16_t i; + if ((size_t)code >= ELEMSOF(device->button_map)) + return 0; + i = device->button_map[code]; + return i >= 0 && (int)GETBIT(device->internals->buttons, (uint16_t)i); } diff --git a/libgamepad_open_device.c b/libgamepad_open_device.c index 3c2a751..22163a4 100644 --- a/libgamepad_open_device.c +++ b/libgamepad_open_device.c @@ -1,39 +1,165 @@ /* See LICENSE file for copyright and license details. */ #include "common.h" +#define ELEMS_REQUIRED(BITS, TYPE) ((BITS + BITSOF(TYPE) - 1) / BITSOF(TYPE)) +#define MAX2(A, B) ((A) > (B) ? (A) : (B)) +#define MAX4(A, B, C, D) (MAX2(MAX2(A, B), MAX2(C, D))) + + +static void +store_uint(uint64_t value, char *buf) +{ + buf[0] = (char)((value >> 0) & 255); + buf[1] = (char)((value >> 8) & 255); + buf[2] = (char)((value >> 16) & 255); + buf[3] = (char)((value >> 24) & 255); + buf[4] = (char)((value >> 32) & 255); + buf[5] = (char)((value >> 40) & 255); + buf[6] = (char)((value >> 48) & 255); + buf[7] = (char)((value >> 56) & 255); +} + + +LIBGAMEPAD_CONST__ +static size_t +popcount(uint8_t value) +{ + size_t n = 0; + for (; value; value >>= 1) + if (value & 1) + n += 1; + return n; +} + + +static int +get_fingerprint(struct libgamepad_device *device, char non_unique[65], char unique[65]) +{ + struct libsha2_state s, s2; + char buf[128]; + size_t i, n; + + if (libsha2_init(&s, LIBSHA2_256)) + return -1; + + libsha2_update(&s, device->name, 8 * strlen(device->name) + 8); + libsha2_update(&s, device->physical_location, 8 * strlen(device->physical_location) + 8); + + store_uint(device->vendor, &buf[0]); + store_uint(device->product, &buf[8]); + store_uint(device->version, &buf[16]); + libsha2_update(&s, buf, 3 * 64); + + store_uint(device->nbuttons, buf); + for (n = 8, i = 0; i < ELEMSOF(device->button_map); i++) { + if (device->button_map[i] >= 0) { + store_uint((uint64_t)i, &buf[n]); + n += 8; + if (n == sizeof(buf)) { + libsha2_update(&s, buf, 8 * n); + n = 0; + } + } + } + libsha2_update(&s, buf, 8 * n); + n = 0; + + store_uint(device->nabsolute_axes, buf); + for (n = 8, i = 0; i < ELEMSOF(device->absolute_axis_map); i++) { + if (device->absolute_axis_map[i] >= 0) { + store_uint((uint64_t)i, &buf[n]); + n += 8; + if (n == sizeof(buf)) { + libsha2_update(&s, buf, 8 * n); + n = 0; + } + } + } + libsha2_update(&s, buf, 8 * n); + n = 0; + + store_uint(device->nrelative_axes, buf); + for (n = 8, i = 0; i < ELEMSOF(device->relative_axis_map); i++) { + if (device->relative_axis_map[i] >= 0) { + store_uint((uint64_t)i, &buf[n]); + n += 8; + if (n == sizeof(buf)) { + libsha2_update(&s, buf, 8 * n); + n = 0; + } + } + } + libsha2_update(&s, buf, 8 * n); + n = 0; + + n = 0; + for (i = 0; i < ELEMSOF(device->force_feedback_support); i++) + if (device->force_feedback_support[i]) + n += popcount(device->force_feedback_support[i]); + store_uint((uint64_t)n, buf); + for (n = 8, i = 0; i < BITSOF(device->force_feedback_support); i++) { + if (GETBIT(device->force_feedback_support, i)) { + store_uint((uint64_t)i, &buf[n]); + n += 8; + if (n == sizeof(buf)) { + libsha2_update(&s, buf, 8 * n); + n = 0; + } + } + } + libsha2_update(&s, buf, 8 * n); + n = 0; + + memcpy(&s2, &s, sizeof(s)); + libsha2_update(&s2, device->unique_id, 8 * strlen(device->unique_id) + 8); + + libsha2_digest(&s, NULL, 0, buf); + libsha2_behex_lower(non_unique, buf, 32); + libsha2_digest(&s2, NULL, 0, buf); + libsha2_behex_lower(unique, buf, 32); + return 0; +} + int libgamepad_open_device(struct libgamepad_device *devicep, int dirfd, const char *path, int mode) { - int err; - unsigned int i; + unsigned long int bits[ELEMS_REQUIRED(MAX4(ELEMSOF(devicep->button_map), + ELEMSOF(devicep->absolute_axis_map), + ELEMSOF(devicep->relative_axis_map), + ELEMSOF(devicep->force_feedback_support)), long int)]; + int err, r; + int16_t j; uint16_t n; + unsigned int i, max; struct input_id id; + char *buf = NULL; + size_t bufsize = 0; + void *new; + memset(devicep, 0, sizeof(*devicep)); devicep->fd = dirfd; - devicep->internals = NULL; - devicep->buttons = NULL; - devicep->absolute_axes = NULL; - devicep->relative_axes = NULL; - memset(devicep->force_feedback_support, 0, sizeof(devicep->force_feedback_support)); devicep->internals = calloc(1, sizeof(*devicep->internals)); if (!devicep->internals) return -1; + if (path && *path) { devicep->fd = openat(dirfd, path, mode); - if (devicep->fd < 0) { - libgamepad_close_device(devicep); - return -1; - } + if (devicep->fd < 0) + goto fail; devicep->internals->close_fd = 1; } - if (ioctl(devicep->fd, EVIOCGID, &id)) { - libgamepad_close_device(devicep); - return -1; - } + + if (ioctl(devicep->fd, EVIOCGID, &id) < 0) + goto fail; + devicep->bus_type = (unsigned int)id.bustype; + devicep->vendor = (unsigned int)id.vendor; + devicep->product = (unsigned int)id.product; + devicep->version = (unsigned int)id.version; + err = libevdev_new_from_fd(devicep->fd, &devicep->internals->dev); if (err < 0) { @@ -42,68 +168,105 @@ libgamepad_open_device(struct libgamepad_device *devicep, int dirfd, const char return -1; } - devicep->name = libevdev_get_name(devicep->internals->dev); - devicep->unique_id = libevdev_get_uniq(devicep->internals->dev); - devicep->physical_location = libevdev_get_phys(devicep->internals->dev); - devicep->bus_type = (unsigned int)id.bustype; - devicep->vendor = (unsigned int)id.vendor; - devicep->product = (unsigned int)id.product; - devicep->version = (unsigned int)id.version; - - devicep->nbuttons = 0; - for (i = 0; i < KEY_CNT; i++) { - devicep->button_map[i] = -1; - if (libevdev_has_event_code(devicep->internals->dev, EV_KEY, i)) - devicep->button_map[i] = (int16_t)devicep->nbuttons++; - } - devicep->nabsolute_axes = 0; - for (i = 0; i < ABS_CNT; i++) { - devicep->absolute_axis_map[i] = -1; - if (libevdev_has_event_code(devicep->internals->dev, EV_ABS, i)) - devicep->absolute_axis_map[i] = (int16_t)devicep->nabsolute_axes++; - } +#define GET_STRING(EVIOCMACRO, OUTPUT)\ + do {\ + for (;;) {\ + r = ioctl(devicep->fd, EVIOCMACRO(bufsize), buf);\ + if (r < 0)\ + goto fail_free_buf;\ + if ((size_t)r < bufsize)\ + break;\ + new = realloc(buf, bufsize += 32);\ + if (!new)\ + goto fail_free_buf;\ + buf = new;\ + }\ + buf[r] = '\0';\ + *OUTPUT = strdup(buf);\ + if (!*OUTPUT)\ + goto fail_free_buf;\ + } while (0) + GET_STRING(EVIOCGNAME, &devicep->name); + GET_STRING(EVIOCGUNIQ, &devicep->unique_id); + GET_STRING(EVIOCGPHYS, &devicep->physical_location); + free(buf); - devicep->nrelative_axes = 0; - for (i = 0; i < REL_CNT; i++) { - devicep->relative_axis_map[i] = -1; - if (libevdev_has_event_code(devicep->internals->dev, EV_REL, i)) - devicep->relative_axis_map[i] = (int16_t)devicep->nrelative_axes++; - } - for (i = 0; i < FF_CNT; i++) - if (libevdev_has_event_code(devicep->internals->dev, EV_FF, i)) - devicep->force_feedback_support[i / 8] |= (uint8_t)(1 << (i & 7)); +#define CREATE_MAPS(EVENTS, SINGULAR, PLURAL)\ + do {\ + /* Code-to-index map */\ + r = ioctl(devicep->fd, EVIOCGBIT(EVENTS, sizeof(bits)), bits);\ + if (r < 0)\ + goto fail;\ + max = (unsigned int)r * 8;\ + devicep->n##PLURAL = 0;\ + for (i = 0; i < ELEMSOF(devicep->SINGULAR##_map); i++) {\ + devicep->SINGULAR##_map[i] = -1;\ + if (i < max && ((bits[i / BITSOF(*bits)] >> (i % BITSOF(*bits))) & 1))\ + devicep->SINGULAR##_map[i] = (int16_t)devicep->n##PLURAL++;\ + }\ + \ + /* Index-to-code map */\ + if (devicep->n##PLURAL) {\ + devicep->PLURAL = calloc(devicep->n##PLURAL, sizeof(*devicep->PLURAL));\ + if (!devicep->PLURAL)\ + goto fail;\ + for (i = 0, n = 0; i < ELEMSOF(devicep->SINGULAR##_map); i++)\ + if (devicep->SINGULAR##_map[i] >= 0)\ + devicep->PLURAL[n++] = (uint16_t)i;\ + }\ + } while (0) + + CREATE_MAPS(EV_KEY, button, buttons); + CREATE_MAPS(EV_ABS, absolute_axis, absolute_axes); + CREATE_MAPS(EV_REL, relative_axis, relative_axes); - if (devicep->nbuttons) { - devicep->buttons = calloc(devicep->nbuttons, sizeof(*devicep->buttons)); - if (!devicep->buttons) - goto fail; - for (i = 0, n = 0; i < KEY_CNT; i++) - if (devicep->button_map[i] >= 0) - devicep->buttons[n++] = (uint16_t)i; - } if (devicep->nabsolute_axes) { - devicep->absolute_axes = calloc(devicep->nabsolute_axes, sizeof(*devicep->absolute_axes)); - if (!devicep->absolute_axes) + devicep->internals->absinfo = calloc(devicep->nabsolute_axes, sizeof(*devicep->internals->absinfo)); + if (!devicep->internals->absinfo) goto fail; - for (i = 0, n = 0; i < ABS_CNT; i++) - if (devicep->absolute_axis_map[i] >= 0) - devicep->absolute_axes[n++] = (uint16_t)i; } + for (i = 0; i < devicep->nabsolute_axes; i++) + if (ioctl(devicep->fd, EVIOCGABS((unsigned int)devicep->absolute_axes[i]), &devicep->internals->absinfo[i]) < 0) + goto fail; + - if (devicep->nrelative_axes) { - devicep->relative_axes = calloc(devicep->nrelative_axes, sizeof(*devicep->relative_axes)); - if (!devicep->relative_axes) + if (devicep->nbuttons) { + devicep->internals->buttons = calloc((devicep->nbuttons + 7) / 8, sizeof(*devicep->internals->buttons)); + if (!devicep->internals->buttons) goto fail; - for (i = 0, n = 0; i < REL_CNT; i++) - if (devicep->relative_axis_map[i] >= 0) - devicep->relative_axes[n++] = (uint16_t)i; + r = ioctl(devicep->fd, EVIOCGKEY(sizeof(bits)), bits); + if (r < 0) + goto fail; + max = (unsigned int)r * 8; + for (i = 0; i < max && i < ELEMSOF(devicep->button_map); i++) { + j = devicep->button_map[i]; + if (j >= 0 && GETBIT(bits, i)) + SETBIT(devicep->internals->buttons, (uint16_t)j); + } } + + r = ioctl(devicep->fd, EVIOCGBIT(EV_FF, sizeof(bits)), bits); + if (r < 0) + goto fail; + max = (unsigned int)r * 8; + for (i = 0; i < BITSOF(devicep->force_feedback_support); i++) + if (i < max && ((bits[i / BITSOF(*bits)] >> (i % BITSOF(*bits))) & 1)) + SETBIT(devicep->force_feedback_support, i); + + + if (get_fingerprint(devicep, devicep->fingerprint, devicep->fingerprint_unique)) + goto fail; + + /* TODO get actual KEY/ABS state */ + return 0; +fail_free_buf: + free(buf); fail: libgamepad_close_device(devicep); return -1; diff --git a/test-details.c b/test-details.c index e834819..f8b2365 100644 --- a/test-details.c +++ b/test-details.c @@ -31,6 +31,8 @@ main(int argc, char *argv[]) printf("Name: %s\n", gamepad.name); printf("Unique id: %s\n", gamepad.unique_id); printf("Physical location: %s\n", gamepad.physical_location); + printf("Fingerprint: %s\n", gamepad.fingerprint); + printf("Unique fingerprint: %s\n", gamepad.fingerprint_unique); printf("Buttons:\n"); for (i = 0; i < gamepad.nbuttons; i++) { |