diff options
Diffstat (limited to 'libgamepad.h')
-rw-r--r-- | libgamepad.h | 566 |
1 files changed, 566 insertions, 0 deletions
diff --git a/libgamepad.h b/libgamepad.h new file mode 100644 index 0000000..627589a --- /dev/null +++ b/libgamepad.h @@ -0,0 +1,566 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBGAMEPAD_H +#define LIBGAMEPAD_H + +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stddef.h> +#include <time.h> + +#include <libevdev/libevdev.h> + + +/** + * Opaque structure for monitoring device attachment changes + */ +typedef struct libgamepad_attachment_monitor LIBGAMEPAD_ATTACHMENT_MONITOR; + + +/** + * Device attachment event type + */ +enum libgamepad_attachment_event_type { + /** + * Device has been added + */ + LIBGAMEPAD_ADDED, + + /** + * Device has been removed + */ + LIBGAMEPAD_REMOVED +}; + + +/** + * Device type + * + * A device can have any number of these applied to + * it, it may also have unknown types beyond these + */ +enum libgamepad_type { + /** + * Gamepad, joystick, steering wheel, or similar + */ + LIBGAMEPAD_GAMEPAD = 0x0001, + + /** + * Computer mouse + */ + LIBGAMEPAD_MOUSE = 0x0002 +}; + + +/** + * Gamepad input type + */ +enum libgamepad_input_type { + /** + * Button/key + */ + LIBGAMEPAD_BUTTON, + + /** + * Absolute axis + */ + LIBGAMEPAD_ABSOLUTE_AXIS, + + /** + * Relative axis + */ + LIBGAMEPAD_RELATIVE_AXIS +}; + + +/** + * Subdevice input event structure + */ +struct libgamepad_input_event { + /** + * The affect input type + */ + enum libgamepad_input_type type; + + /** + * Whether the event was polled in a + * synchronisation read + */ + short int sync_event; + + /** + * The button/key or axis affect by the event + */ + uint16_t code; + + /** + * The new value on the button/key or axis, + * or the delta if on a relative axis + */ + int32_t value; + + /** + * Event timestamp + */ + struct timeval time; +}; + + +/** + * Subdevice on a device + * + * For example a modern gamepad may be split into + * a gamepad, computer mouse, and motion sensor + * + * Structure is always deallocated by the library + * using free(3) + */ +struct libgamepad_subdevice { + /** + * Device type + */ + enum libgamepad_type type; + + /** + * Device path + */ + char path[]; +}; + + +/** + * Physical device + * + * Contents of structure is deallocated with + * `libgamepad_close_superdevice` + */ +struct libgamepad_superdevice { + /** + * Device path in /sys + */ + char *syspath; + + /** + * Number of subdevices + */ + size_t ndevices; + + /** + * Subdevices + */ + struct libgamepad_subdevice **devices; + + /** + * Number of LEDs + */ + size_t nleds; + + /** + * Paths to LEDs + */ + char **leds; + + /** + * Number of power supplies (batteries) + */ + size_t npower_supplies; + + /** + * Paths of power supplies (batteries) + */ + char **power_supplies; +}; + + +/** + * Subdevice structure for detailed information listening on input events + */ +struct libgamepad_device { + /** + * File descriptor to the device, the application + * may use it to poll for read-readyness + */ + int fd; + + /** + * Bus type the device is connect via, see BUS_-prefixed + * constants in <linux/input.h> + */ + int bus_type; + + /** + * Vendor ID for the device (sub- or superdevice) + */ + int vendor; + + /** + * Product ID for the device (sub- or superdevice) + */ + int product; + + /** + * Product version ID for the device (sub- or superdevice) + */ + int version; + + /** + * FOR INTERNAL USE + * + * Specifies whether `.fd` shall be closed with the device + */ + int close_fd; + + /** + * FOR INTERNAL USE + * + * Whether the device must be synchronised + */ + int require_sync; + + /** + * Human-readable device (sub- or superdevice) name + */ + const char *name; + + /** + * ID that is supposted to be unique to the device + * (sub- or superdevice) + */ + const char *unique_id; + + /** + * The location if the device + */ + const char *physical_location; + + /** + * libevdev instance for the device + */ + struct libevdev *dev; + + /** + * Number of (digital) buttons/keys present + * on the device + */ + size_t nbuttons; + + /** + * Number of absolute axes present on the device + */ + size_t nabsolute_axes; + + /** + * Number of relative axes present on the device + */ + size_t nrelative_axes; + + /** + * Maps from button/key codes to button indices, + * non-present buttons/keys map to -1, other + * values are in [0, `.nbuttons`[. + */ + int16_t button_map[KEY_CNT]; + + /** + * Maps from absolute axis codes to absolute axis + * indices, non-present axes map to -1, other + * values are in [0, `.nabsolute_axes`[. + */ + int16_t absolute_axis_map[ABS_CNT]; + + /** + * Maps from relative axis codes to absolute axis + * indices, non-present axes map to -1, other + * values are in [0, `.nrelative_axes`[. + */ + int16_t relative_axis_map[REL_CNT]; + + /** + * Map from button/key indices to button/key codes + */ + uint16_t *buttons; + + /** + * Map from absolute axis indices to absolute axis codes + */ + uint16_t *absolute_axes; + + /** + * Map from relative axis indices to relative axis codes + */ + uint16_t *relative_axes; +}; + + +/** + * Get a list of all available physical devices + * + * @param devicesp Output parameter for the list of devices + * @param ndevicesp Output parameter for the number of listed devices + * @return 0 on success, -1 on failure + * + * This function may fail for any reason specified for + * realloc(3), open(3), fdopendir(3), or readdir(3) + */ +int libgamepad_list_superdevices(char ***, size_t *); + +/** + * Get information about a physical device + * + * @param devicep Output parameter for the device information, + * allocated memory shall be deallocated with + * `libgamepad_close_superdevice(devicep)` + * @param syspath The path of the device, in /sys + * @return 0 on success, -1 on failure + * + * This function may fail for any reason specified for + * realloc(3), openat(3), fdopendir(3), or readdir(3) + */ +int libgamepad_open_superdevice(struct libgamepad_superdevice *, const char *); + +/** + * Deallocate the contents of a `struct libgamepad_superdevice` + * + * @param device The structure whose nested memory allocations + * shall be deallocated, may be `NULL` + */ +void libgamepad_close_superdevice(struct libgamepad_superdevice *); + + +/** + * Create a device attachment monitor + * + * The user shall poll the returned file descriptor + * for read-readiness, and whenever it is ready, + * call `libgamepad_get_attachment_event` + * + * @param monitorp Output parameter for the monitor, shall deallocated with + * `libgamepad_destroy_attachment_monitor` when no longer used + * @return A file descriptor on successful completion, -1 on failure + * + * This function may fail for any reason specified by + * malloc(3), udev_new(3), udev_monitor_new_from_netlink(3), or + * udev_monitor_enable_receiving(3) + */ +int libgamepad_create_attachment_monitor(LIBGAMEPAD_ATTACHMENT_MONITOR **); + +/** + * Deallocate a device attachment monitor + * + * @param monitor The monitor to deallocate; the file descriptor returned + * with it will also be closed and become invalid, may be `NULL` + */ +void libgamepad_destroy_attachment_monitor(LIBGAMEPAD_ATTACHMENT_MONITOR *); + +/** + * Get the next device attachment event + * + * @param monitor Monitor created with `libgamepad_create_attachment_monitor` + * @param syspathp Pointer to output buffer for the device's path in /sys; + * the buffer may be reallocated by the function + * @param sizep Pointer to the allocation size of `*syspath`; may be + * updated by the function + * @param typep Output parameter for the attachment event type; in the + * event that this value is set to `LIBGAMEPAD_REMOVED`, the + * device is not necessarily on supported by this library + * @return 1 on success, 0 if the received event was suppressed + * by the library, -1 on failure + * + * This function may fail for any reason specified for + * realloc(3) or udev_monitor_receive_device(3); notable, + * this function may set `errno` to `EAGAIN` or `EINTR` + */ +int libgamepad_get_attachment_event(LIBGAMEPAD_ATTACHMENT_MONITOR *, char **, size_t *, enum libgamepad_attachment_event_type *); + + +/** + * Open a subdevice + * + * @param devicep Output parameter for the device information and handles; + * deallocated with `libgamepad_close_device` + * @param dirfd File descriptor to path that `path` is relative to + * (unless it is an absolute path), or `AT_FDCWD` for the + * current working directory + * @param path The path to the device, if `NULL` or empty, `dirfd` + * will be used as the file descriptor to the device, + * in which case the application must keep it open until + * the device is closed, and then close it manually, and + * `mode` is ignored + * @param mode Mode to open the device in, normally `O_RDONLY`, + * `O_RDONLY|O_NONBLOCK`, `O_RDWR`, or `O_RDWR|O_NONBLOCK` + * @return 0 on success, -1 on failure + * + * This function may fail for any reason specified for + * malloc(3), openat(3) or libevdev_new_from_fd(3) + */ +int libgamepad_open_device(struct libgamepad_device *, int, const char *, int); + +/** + * Close a subdevice + * + * @param device Device information and handles, may be `NULL` + */ +void libgamepad_close_device(struct libgamepad_device *); + +/** + * Get the next event on a subdevice + * + * NB! events may be queued internally (by libevdev), therefore + * an application must either call this function in a loop in + * its own thread, or have the device opened in non-blocking + * mode and even the poll the device's file descriptor for + * read-readyness and when it is ready clal this function in + * a loop until it sets `errno` to `EAGAIN`. + * + * @param device Device to read an event from + * @param eventp Output parameter for the event + * @return 1 if an event was returned, + * 0 if no event was returned, + * -1 on failure + * + * This function may fail for any reason specified for + * libevdev_next_event(3), including: + * - EAGAIN no more data currently available (non-blocking mode) + * - EINTR system call was interrupted, try again + * - ENODEV device has been unplugged + */ +int libgamepad_next_event(struct libgamepad_device *, struct libgamepad_input_event *); + + +/** + * Get the name of a button/key + * + * @param code The button/key + * @return The button/key's name + */ +inline const char * +libgamepad_get_button_name(unsigned int code) +{ + return libevdev_event_code_get_name(EV_KEY, code); +} + +/** + * Get the name of an absolute axis + * + * @param code The axis + * @return The axis' name + */ +inline const char * +libgamepad_get_absolute_axis_name(unsigned int code) +{ + return libevdev_event_code_get_name(EV_ABS, code); +} + +/** + * Get the name of a relative axis + * + * @param code The axis + * @return The axis' name + */ +inline const char * +libgamepad_get_relative_axis_name(unsigned int code) +{ + return libevdev_event_code_get_name(EV_REL, code); +} + +/** + * Get whether a button/key is pressed down or not + * + * @param device The device to retrieve the information for + * @param code The button/key + * @return 1 if the button/key is pressed down, + * 0 otherwise + */ +inline int +libgamepad_get_button_is_pressed(struct libgamepad_device *device, unsigned int code) +{ + return libevdev_get_event_value(device->dev, EV_KEY, code); +} + +/** + * Get information about an absolute axis + * + * @param device The device to retrieve the information for + * @param code The axis + * @return Information about the axis + */ +inline const struct input_absinfo * /* `struct input_absinfo` is defined in <linux/input.h> */ +libgamepad_get_absolute_axis_info(struct libgamepad_device *device, unsigned int code) +{ + return libevdev_get_abs_info(device->dev, code); +} + + +/** + * Grab a subdevice, if not already grabbed + * + * This is supposed to block out clients from + * retrieving events for the device, but it + * does not necessarily stop them from reading + * the device state + * + * @param device The device to grab + * @return 0 on success, -1 on failure + * + * May fail for any reason specified for libevdev_grab(3) + * with LIBEVDEV_GRAB applied + * + * In the event that the device is already grabbed by + * via another file descriptor (duplicates do not share + * grab), this function will return -1 and set `errno` + * to `EBUSY` + */ +inline int +libgamepad_grab(struct libgamepad_device *device) +{ + int err = libevdev_grab(device->dev, LIBEVDEV_GRAB); + if (err < 0) { + errno = -err; + return -1; + } + return 0; +} + +/** + * Ungrab a subdevice, unless not currently grabbed + * + * @param device The device to ungrab + * @return 0 on success, -1 on failure + * + * May fail for any reason specified for libevdev_grab(3) + * with LIBEVDEV_UNGRAB applied + */ +inline int +libgamepad_ungrab(struct libgamepad_device *device) +{ + int err = libevdev_grab(device->dev, LIBEVDEV_UNGRAB); + if (err < 0) { + errno = -err; + return -1; + } + return 0; +} + + +/** + * Set the clock that event timestamps shall be reported in + * + * @param device The device to configure + * @param clockid The clock to use on event timestamps + * @return 0 on success, -1 on failure + * + * May fail for any reason specified for libevdev_set_clock_id(3) + */ +inline int +libgamepad_set_clock(struct libgamepad_device *device, clockid_t clockid) +{ + int err = libevdev_set_clock_id(device->dev, clockid); + if (err < 0) { + errno = -err; + return -1; + } + return 0; +} + + +#endif |