aboutsummaryrefslogtreecommitdiffstats
path: root/libgamepad.h
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2022-07-23 14:39:44 +0200
committerMattias Andrée <maandree@kth.se>2022-07-23 14:40:11 +0200
commitd49393b339c47733c2eda207b8ba03d61db0a5a3 (patch)
treebc609622c3cabe1dc6b59970cb8a9a8364a561a7 /libgamepad.h
downloadlibgamepad-d49393b339c47733c2eda207b8ba03d61db0a5a3.tar.gz
libgamepad-d49393b339c47733c2eda207b8ba03d61db0a5a3.tar.bz2
libgamepad-d49393b339c47733c2eda207b8ba03d61db0a5a3.tar.xz
First commit
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to 'libgamepad.h')
-rw-r--r--libgamepad.h566
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