/* See LICENSE file for copyright and license details. */
#ifndef LIBGAMEPAD_H
#define LIBGAMEPAD_H
#include <linux/input.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <time.h>
#include <unistd.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>
*/
unsigned int bus_type;
/**
* Vendor ID for the device (sub- or superdevice)
*/
unsigned int vendor;
/**
* Product ID for the device (sub- or superdevice)
*/
unsigned int product;
/**
* Product version ID for the device (sub- or superdevice)
*/
unsigned 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;
/**
* 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;
/**
* 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];
/**
* Bitmap of supported force feedback effects
*/
uint8_t force_feedback_support[(FF_CNT + 7) / 8];
};
/* FOR INTERNAL USE */
void libgamepad_construct_force_feedback_effect__(struct ff_effect *, const struct ff_effect *, double, uint16_t, uint16_t);
/**
* 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 or access has been revoked
*/
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(uint16_t code)
{
return libevdev_event_code_get_name(EV_KEY, (unsigned int)code);
}
/**
* Get the name of an absolute axis
*
* @param code The axis
* @return The axis' name
*/
inline const char *
libgamepad_get_absolute_axis_name(uint16_t code)
{
return libevdev_event_code_get_name(EV_ABS, (unsigned int)code);
}
/**
* Get the name of a relative axis
*
* @param code The axis
* @return The axis' name
*/
inline const char *
libgamepad_get_relative_axis_name(uint16_t code)
{
return libevdev_event_code_get_name(EV_REL, (unsigned int)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, uint16_t code)
{
return libevdev_get_event_value(device->dev, EV_KEY, (unsigned int)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, uint16_t code)
{
return libevdev_get_abs_info(device->dev, (unsigned int)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
*
* In the event that the device is already grabbed by
* via another open file descriptor (duplicates share
* grab), this function will return -1 and set `errno`
* to `EBUSY`
*/
inline int
libgamepad_grab(struct libgamepad_device *device)
{
return ioctl(device->fd, EVIOCGRAB, (void *)1);
}
/**
* Ungrab a subdevice, unless not currently grabbed
*
* @param device The device to ungrab
* @return 0 on success, -1 on failure
*/
inline int
libgamepad_ungrab(struct libgamepad_device *device)
{
return ioctl(device->fd, EVIOCGRAB, (void *)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
*/
inline int
libgamepad_set_clock(struct libgamepad_device *device, clockid_t clockid)
{
return ioctl(device->fd, EVIOCSCLOCKID, &clockid);
}
/**
* Install a force feedback effect that can be played back later
*
* @param device The device to configure
* @param effect The effect to install; will be edited, specifically the ID
* will be set (need not be set before calling this function)
* @return 0 on success, -1 on failure
*/
inline int /* `struct ff_effect` is defined in <linux/input.h> */
libgamepad_install_force_feedback_effect(struct libgamepad_device *device, struct ff_effect *effect)
{
effect->id = -1;
return ioctl(device->fd, EVIOCSFF, effect);
}
/**
* Reconfigure an already installed force feedback effect
*
* @param device The device to configure
* @param effect The effect to update, the ID must be set to the ID of a
* previously installed effect
* @return 0 on success, -1 on failure
*/
inline int
libgamepad_update_force_feedback_effect(struct libgamepad_device *device, struct ff_effect *effect)
{
return ioctl(device->fd, EVIOCSFF, effect);
}
/**
* Uninstall an installed force feedback effect
*
* @param device The device to configure
* @param effect The effect to remove, the ID must be set to the ID of a
* previously installed effect and will be reset
* @return 0 on success, -1 on failure
*/
inline int
libgamepad_uninstall_force_feedback_effect(struct libgamepad_device *device, struct ff_effect *effect)
{
int ret = ioctl(device->fd, EVIOCRMFF, effect);
effect->id = -1;
return ret;
}
/**
* Get the number of force feedback effects that can be played concurrently
*
* @param device The device to configure
* @return The number of maximum number concurrent effects, -1 on failure
*/
inline int
libgamepad_get_force_feedback_max_concurrency(struct libgamepad_device *device)
{
int num;
return ioctl(device->fd, EVIOCGEFFECTS, &num) ? -1 : num;
}
/**
* Play a force feedback effect
*
* @param device The device to play the force feedback effect on
* @param effect The force feedback effect to play, must already be installed
* with `libgamepad_install_force_feedback_effect`
* @return 0 on success, -1 on failure
*/
inline int
libgamepad_play_force_feedback_effect(struct libgamepad_device *device, const struct ff_effect *effect)
{
struct input_event message;
message.type = EV_FF;
message.code = (uint16_t)effect->id;
message.value = 1;
return write(device->fd, &message, sizeof(message)) < 0 ? -1 : 0;
}
/**
* Stop playing a force feedback effect
*
* @param device The device playing the force feedback effect on
* @param effect The force feedback effect to play, must already be installed
* with `libgamepad_install_force_feedback_effect`
* @return 0 on success, -1 on failure
*/
inline int
libgamepad_stop_force_feedback_effect(struct libgamepad_device *device, const struct ff_effect *effect)
{
struct input_event message;
message.type = EV_FF;
message.code = (uint16_t)effect->id;
message.value = 0;
return write(device->fd, &message, sizeof(message)) < 0 ? -1 : 0;
}
/**
* Check if a force feedback effect or waveform is supported
*
* @param device The device to check force feedback support on
* @param effect The force feedback effect or waveform
* @return 1 if the effect/waveform is supported, 0 otherwise
*/
inline int
libgamepad_is_force_feedback_effect_supported(struct libgamepad_device *device, uint16_t effect)
{
return effect < sizeof(device->force_feedback_support) * 8 &&
((device->force_feedback_support[effect / 8] >> (effect % 8)) & 1);
}
/**
* Set the force feedback master gain on a device
*
* Requires support for `FF_GAIN` (check with
* `libgamepad_is_force_feedback_effect_supported`)
*
* @param device The device to configure
* @param gain The master gain, shall be a value in [0, 0xFFFF]
* @return 0 on success, -1 on failure
*/
inline int
libgamepad_set_force_feedback_master_gain(struct libgamepad_device *device, uint16_t gain)
{
struct input_event message;
message.type = EV_FF;
message.code = FF_GAIN;
message.value = (int16_t)gain;
return write(device->fd, &message, sizeof(message)) < 0 ? -1 : 0;
}
/**
* Set the autocenter force feedback on a device
*
* Requires support for `FF_AUTOCENTER` (check with
* `libgamepad_is_force_feedback_effect_supported`)
*
* @param device The device to configure
* @param autocenter Autocenter strength, shall be a value in [0, 0xFFFF], select 0 to
* disable (you can also use `libgamepad_disable_force_feedback_autocenter`)
* @return 0 on success, -1 on failure
*/
inline int
libgamepad_set_force_feedback_autocenter(struct libgamepad_device *device, uint16_t autocenter)
{
struct input_event message;
message.type = EV_FF;
message.code = FF_AUTOCENTER;
message.value = (int16_t)autocenter;
return write(device->fd, &message, sizeof(message)) < 0 ? -1 : 0;
}
/**
* Disable the autocenter force feedback on a device
*
* Requires support for `FF_AUTOCENTER` (check with
* `libgamepad_is_force_feedback_effect_supported`)
*
* @param device device to configure
* @return 0 on success, -1 on failure
*/
inline int
libgamepad_disable_force_feedback_autocenter(struct libgamepad_device *device)
{
struct input_event message;
message.type = EV_FF;
message.code = FF_AUTOCENTER;
message.value = 0;
return write(device->fd, &message, sizeof(message)) < 0 ? -1 : 0;
}
/**
* Construct a rumble force-feedback effect
*
* Requires support for `FF_RUMBLE` (check with
* `libgamepad_is_force_feedback_effect_supported`)
*
* This function will set the following values to
* zero if `from` is `NULL`, see <linux/input.h>
* for more details:
* - effectp->trigger.button
* - effectp->trigger.interval
* - effectp->replay.delay
*
* @param effectp Output parameter for the effect
* @param from Effect to reconfigure, `NULL` to create a new effect
* @param direction The direction of the force feedback (if directional), where
* values are measure clockwise and both 0 and 1 are upwards
* @param length The number of milliseconds the effect is played
* @param effect Effect specific details:
* - .strong_magnitude Heavy motor strength, unsigned 16-bit integer
* - .weak_magnitude Light motor strength, unsigned 16-bit integer
*/
inline void
libgamepad_construct_rumble_force_feedback_effect(struct ff_effect *effectp, const struct ff_effect *from,
double direction, uint16_t length, const struct ff_rumble_effect *effect)
{
libgamepad_construct_force_feedback_effect__(effectp, from, direction, length, FF_RUMBLE);
memcpy(&effectp->u.rumble, effect, sizeof(effectp->u.rumble));
}
/**
* Construct a constant force-feedback effect
*
* Requires support for `FF_CONSTANT` (check with
* `libgamepad_is_force_feedback_effect_supported`)
*
* This function will set the following values to
* zero if `from` is `NULL`, see <linux/input.h>
* for more details:
* - effectp->trigger.button
* - effectp->trigger.interval
* - effectp->replay.delay
*
* @param effectp Output parameter for the effect
* @param from Effect to reconfigure, `NULL` to create a new effect
* @param direction The direction of the force feedback (if directional), where
* values are measure clockwise and both 0 and 1 are upwards
* @param length The number of milliseconds the effect is played
* @param effect Effect specific details:
* - .level Strength, signed 16-bit integer
* - .envelope.attack_strength Strength at beginning, unsigned 16-bit integer
* - .envelope.fade_strength Strength at end, unsigned 16-bit integer
* - .envelope.attack_length The number of milliseconds the strength shall
* transition from `.envelope.attack_strength`
* to `.level`, unsigned 16-bit integer
* - .envelope.fade_length The number of milliseconds the strength shall
* transition to `.envelope.fade_strength`
* from `.level`, unsigned 16-bit integer
*/
inline void
libgamepad_construct_constant_force_feedback_effect(struct ff_effect *effectp, const struct ff_effect *from,
double direction, uint16_t length, const struct ff_constant_effect *effect)
{
libgamepad_construct_force_feedback_effect__(effectp, from, direction, length, FF_CONSTANT);
memcpy(&effectp->u.constant, effect, sizeof(effectp->u.constant));
}
/**
* Construct a ramp force-feedback effect
*
* Requires support for `FF_RAMP` (check with
* `libgamepad_is_force_feedback_effect_supported`)
*
* This function will set the following values to
* zero if `from` is `NULL`, see <linux/input.h>
* for more details:
* - effectp->trigger.button
* - effectp->trigger.interval
* - effectp->replay.delay
*
* @param effectp Output parameter for the effect
* @param from Effect to reconfigure, `NULL` to create a new effect
* @param direction The direction of the force feedback (if directional), where
* values are measure clockwise and both 0 and 1 are upwards
* @param length The number of milliseconds the effect is played
* @param effect Effect specific details:
* - .start_level Strength at beginning, signed 16-bit integer
* - .end_level Strength at end, signed 16-bit integer
* - .envelope.attack_strength Strength at beginning, unsigned 16-bit integer
* - .envelope.fade_strength Strength at end, unsigned 16-bit integer
* - .envelope.attack_length The number of milliseconds the strength shall
* transition from `.envelope.attack_strength`,
* unsigned 16-bit integer
* - .envelope.fade_length The number of milliseconds the strength shall
* transition to `.envelope.fade_strength`,
* unsigned 16-bit integer
*/
inline void
libgamepad_construct_ramp_force_feedback_effect(struct ff_effect *effectp, const struct ff_effect *from,
double direction, uint16_t length, const struct ff_ramp_effect *effect)
{
libgamepad_construct_force_feedback_effect__(effectp, from, direction, length, FF_RUMBLE);
memcpy(&effectp->u.ramp, effect, sizeof(effectp->u.ramp));
}
/**
* Construct a periodic force-feedback effect
*
* Requires support for `FF_PERIODIC` and the selected waveform
* (check with `libgamepad_is_force_feedback_effect_supported`)
*
* This function will set the following values to
* zero if `from` is `NULL`, see <linux/input.h>
* for more details:
* - effectp->trigger.button
* - effectp->trigger.interval
* - effectp->replay.delay
*
* @param effectp Output parameter for the effect
* @param from Effect to reconfigure, `NULL` to create a new effect
* @param direction The direction of the force feedback (if directional), where
* values are measure clockwise and both 0 and 1 are upwards
* @param length The number of milliseconds the effect is played
* @param effect Effect specific details:
* - .waveform `FF_SQUARE`, `FF_TRIANGLE`, `FF_SINE`, `FF_SAW_UP`,
* `FF_SAW_DOWN`, or `FF_CUSTOM`
* - .period The period of the wave, in milliseconds (unsigned 16-bit integer)
* - .magnitude The peak value, signed 16-bit integer
* - .offset The rough mean value, signed 16-bit integer
* - .phase Horiztonal wave-shift, in milliseconds (unsigned 16-bit integer)
* - .envelope.attack_strength Strength at beginning, unsigned 16-bit integer
* - .envelope.fade_strength Strength at end, unsigned 16-bit integer
* - .envelope.attack_length The number of milliseconds the strength shall
* transition from `.envelope.attack_strength`,
* unsigned 16-bit integer
* - .envelope.fade_length The number of milliseconds the strength shall
* transition to `.envelope.fade_strength`,
* unsigned 16-bit integer
* - .custom_len Set to zero unless you are using (`FF_CUSTOM`)
* - .custom_data Set to `NULL` unless you are using (`FF_CUSTOM`)
*/
inline void
libgamepad_construct_periodic_force_feedback_effect(struct ff_effect *effectp, const struct ff_effect *from,
double direction, uint16_t length, const struct ff_periodic_effect *effect)
{
libgamepad_construct_force_feedback_effect__(effectp, from, direction, length, FF_PERIODIC);
memcpy(&effectp->u.periodic, effect, sizeof(effectp->u.periodic));
}
/**
* Construct a spring force-feedback effect
*
* Requires support for `FF_SPRING` (check with
* `libgamepad_is_force_feedback_effect_supported`)
*
* This function will set the following values to
* zero if `from` is `NULL`, see <linux/input.h>
* for more details:
* - effectp->trigger.button
* - effectp->trigger.interval
* - effectp->replay.delay
*
* @param effectp Output parameter for the effect
* @param from Effect to reconfigure, `NULL` to create a new effect
* @param direction The direction of the force feedback (if directional), where
* values are measure clockwise and both 0 and 1 are upwards
* @param length The number of milliseconds the effect is played
* @param effect Effect specific details (one of each axis):
* - .right_saturation Maximum level at end of axis, unsigned 16-bit integer
* - .left_saturation Maximum level at beginning of axis, unsigned 16-bit integer
* - .right_coeff Growth coefficient after the dead zone, signed 16-bit integer
* - .left_coeff Growth coefficient before the dead zone, signed 16-bit integer
* - .deadband Size of the dead zone
* - .center The position of the center of the dead zone
*/
inline void
libgamepad_construct_spring_force_feedback_effect(struct ff_effect *effectp, const struct ff_effect *from,
double direction, uint16_t length, const struct ff_condition_effect effect[2])
{
libgamepad_construct_force_feedback_effect__(effectp, from, direction, length, FF_SPRING);
memcpy(effectp->u.condition, effect, sizeof(effectp->u.condition));
}
/**
* Construct a friction force-feedback effect
*
* Requires support for `FF_FRICTION` (check with
* `libgamepad_is_force_feedback_effect_supported`)
*
* This function will set the following values to
* zero if `from` is `NULL`, see <linux/input.h>
* for more details:
* - effectp->trigger.button
* - effectp->trigger.interval
* - effectp->replay.delay
*
* @param effectp Output parameter for the effect
* @param from Effect to reconfigure, `NULL` to create a new effect
* @param direction The direction of the force feedback (if directional), where
* values are measure clockwise and both 0 and 1 are upwards
* @param length The number of milliseconds the effect is played
* @param effect Effect specific details (one of each axis):
* - .right_saturation Maximum level at end of axis, unsigned 16-bit integer
* - .left_saturation Maximum level at beginning of axis, unsigned 16-bit integer
* - .right_coeff Growth coefficient after the dead zone, signed 16-bit integer
* - .left_coeff Growth coefficient before the dead zone, signed 16-bit integer
* - .deadband Size of the dead zone
* - .center The position of the center of the dead zone
*/
inline void
libgamepad_construct_friction_force_feedback_effect(struct ff_effect *effectp, const struct ff_effect *from,
double direction, uint16_t length, const struct ff_condition_effect effect[2])
{
libgamepad_construct_force_feedback_effect__(effectp, from, direction, length, FF_FRICTION);
memcpy(effectp->u.condition, effect, sizeof(effectp->u.condition));
}
/**
* Construct a damper force-feedback effect
*
* Requires support for `FF_DAMPER` (check with
* `libgamepad_is_force_feedback_effect_supported`)
*
* This function will set the following values to
* zero if `from` is `NULL`, see <linux/input.h>
* for more details:
* - effectp->trigger.button
* - effectp->trigger.interval
* - effectp->replay.delay
*
* @param effectp Output parameter for the effect
* @param from Effect to reconfigure, `NULL` to create a new effect
* @param direction The direction of the force feedback (if directional), where
* values are measure clockwise and both 0 and 1 are upwards
* @param length The number of milliseconds the effect is played
* @param effect Effect specific details (one of each axis):
* - .right_saturation Maximum level at end of axis, unsigned 16-bit integer
* - .left_saturation Maximum level at beginning of axis, unsigned 16-bit integer
* - .right_coeff Growth coefficient after the dead zone, signed 16-bit integer
* - .left_coeff Growth coefficient before the dead zone, signed 16-bit integer
* - .deadband Size of the dead zone
* - .center The position of the center of the dead zone
*/
inline void
libgamepad_construct_damper_force_feedback_effect(struct ff_effect *effectp, const struct ff_effect *from,
double direction, uint16_t length, const struct ff_condition_effect effect[2])
{
libgamepad_construct_force_feedback_effect__(effectp, from, direction, length, FF_DAMPER);
memcpy(effectp->u.condition, effect, sizeof(effectp->u.condition));
}
/**
* Construct a inertia force-feedback effect
*
* Requires support for `FF_INERTIA` (check with
* `libgamepad_is_force_feedback_effect_supported`)
*
* This function will set the following values to
* zero if `from` is `NULL`, see <linux/input.h>
* for more details:
* - effectp->trigger.button
* - effectp->trigger.interval
* - effectp->replay.delay
*
* @param effectp Output parameter for the effect
* @param from Effect to reconfigure, `NULL` to create a new effect
* @param direction The direction of the force feedback (if directional), where
* values are measure clockwise and both 0 and 1 are upwards
* @param length The number of milliseconds the effect is played
* @param effect Effect specific details (one of each axis):
* - .right_saturation Maximum level at end of axis, unsigned 16-bit integer
* - .left_saturation Maximum level at beginning of axis, unsigned 16-bit integer
* - .right_coeff Growth coefficient after the dead zone, signed 16-bit integer
* - .left_coeff Growth coefficient before the dead zone, signed 16-bit integer
* - .deadband Size of the dead zone
* - .center The position of the center of the dead zone
*/
inline void
libgamepad_construct_inertia_force_feedback_effect(struct ff_effect *effectp, const struct ff_effect *from,
double direction, uint16_t length, const struct ff_condition_effect effect[2])
{
libgamepad_construct_force_feedback_effect__(effectp, from, direction, length, FF_INERTIA);
memcpy(effectp->u.condition, effect, sizeof(effectp->u.condition));
}
#endif