/* 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>
#if defined(__GNUC__)
# define LIBGAMEPAD_PURE__ __attribute__((__pure__))
#else
# define LIBGAMEPAD_PURE__
#endif
/**
* Opaque structure for monitoring device attachment changes
*/
typedef struct libgamepad_attachment_monitor LIBGAMEPAD_ATTACHMENT_MONITOR;
/**
* Opaque structure for internal data in `struct libgamepad_device`
*/
typedef struct libgamepad_device_internals LIBGAMEPAD_DEVICE_INTERNALS;
/**
* Device attachment event type
*/
enum libgamepad_attachment_event_type {
/**
* Device has been added
*/
LIBGAMEPAD_ADDED,
/**
* Device has been removed
*/
LIBGAMEPAD_REMOVED
};
/**
* Device categorisation
*/
enum libgamepad_class {
/**
* Unknown category
*/
LIBGAMEPAD_CLASS_UNKNOWN,
/**
* Unlisted category
*/
LIBGAMEPAD_CLASS_OTHER,
/**
* Game controller
*/
LIBGAMEPAD_CLASS_GAME_CONTROLLER,
/**
* Joystick
*/
LIBGAMEPAD_CLASS_JOYSTICK,
/**
* Steering wheel
*/
LIBGAMEPAD_CLASS_STEERING_WHEEL,
/**
* TV remote controller
*/
LIBGAMEPAD_CLASS_TV_CONTROLLER,
/**
* 3D modelling mouse
*/
LIBGAMEPAD_CLASS_3D_MOUSE,
/**
* Motion sensor (typically camera)
*/
LIBGAMEPAD_CLASS_MOTION_SENSOR,
/**
* Piano or similar instrument
*/
LIBGAMEPAD_CLASS_PIANO,
/**
* Guitar
*/
LIBGAMEPAD_CLASS_GUITAR,
/**
* Drum set
*/
LIBGAMEPAD_CLASS_DRUMS,
/**
* Gun
*/
LIBGAMEPAD_CLASS_GUN,
/**
* Pen
*/
LIBGAMEPAD_CLASS_PEN,
/**
* Non-interactive sensor,
* e.g. accelerometer built into laptop
*/
LIBGAMEPAD_CLASS_SENSOR
};
/**
* Game controller profiles
*
* This list only contains well-known profiles, mainly
* the primary controllers from video gaming consoles
* and handheld gaming consoles
*/
enum libgamepad_game_controller {
/**
* Unknown controller profile
*/
LIBGAMEPAD_CONTROLLER_UNKNOWN,
/**
* Unlisted controller profile
*/
LIBGAMEPAD_CONTROLLER_OTHER,
/* TODO Document force feedback capabilities */
/**
* Amazon Luna Controller
*
* Released 2022-03-01 for Amazon Luna
*
* Layout:
* Clickable analogue stick at upper left thumb position
* Digital D-pad at lower left thumb position
* Clickable analogue stick at lower right thumb position
* 4 digital buttons at upper right thumb position:
* - North = "Y"
* - West = "X"
* - South = "A"
* - East = "B"
* Digital button "LB" at upper left index finger position
* Digital button "RB" at upper right index finger position
* Analogue button "LT" at lower left index finger position
* Analogue button "RT" at lower right index finger position
* Four buttons at upper centre position:
* - West = Home (icon: circle)
* - Centre = Action (icon: brand)
* - East = Menu (icon: three vertically stacked horizontal line)
* - South = Microphone (icon: microphone)
*
* Other features:
* - Built in microphone
* - Stereo headset port
* - Wireless via WiFi
* - Wireless via Bluetooth Low Energi 4.2
* - RGB LED on Action button (??)
*/
LIBGAMEPAD_CONTROLLER_AMAZON_LUNA,
/**
* DualSense
*
* Released 2020-11-12 for PlayStation 5
*
* 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
* - West = Square
* - South = Cross
* - East = Circle
* Digital button "L1" at upper left index finger position
* Digital button "R1" at upper right index finger position
* Analogue button "L2" at lower left index finger position
* Analogue button "R2" at lower right index finger position
* Digital Create (logo: \|/) button north east of D-pad
* Digital Options (logo: three vertically stacked horizontal line)
* button north west of upper right thumb position
* Two digital buttons between analogue stick:
* - North = PS (icon: brand)
* - South = Microphone mute (icon: NW-to-SE diagonally crossed out microphone)
* Clickable 2-point capacitive touchpad between upper thumb positions
*
* Other features:
* - Built in dual-microphone array
* - Built in single-channel speaker
* - Stereo headset port
* - Extension port
* - Wireless via WiFi
* - Wireless via Bluetooth 5.1
* - RGB LED
* - 5 digital LEDs
* - 3 axis accelerometer
* - 3 axis gyroscope
*/
LIBGAMEPAD_CONTROLLER_DUAL_SENSE,
/**
* Google Stadia Controller
*
* Released 2019-11-19 for Google Stadia
*
* 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 = "Y"
* - West = "X"
* - South = "A"
* - East = "B"
* Digital button "L1" at upper left index finger position
* Digital button "R1" at upper right index finger position
* Analogue button "L2" at lower left index finger position
* Analogue button "R2" at lower right index finger position
* Digital Stadia (icon: brand) button between analogue sticks
* 2 digital buttons at inner left thumb position:
* - North = Options (icon: three horizontally stacked dots)
* - East = Google Assistant (icon: four uniquely arrayed dots)
* 2 digital buttons at inner right thumb position:
* - North = Menu (icon: three vertically stacked horizontal lines)
* - West = Capture (icon: corners of a square)
*
* Other features:
* - Built in microphone (??)
* - Stereo headset port
* - Wireless via WiFi
* - Wireless via Bluetooth Low Energi 4.2
* - LED (unknown capabilities)
*/
LIBGAMEPAD_CONTROLLER_GOOGLE_STADIA,
/**
* Nintendo Switch Pro Controller
*
* Released 2017-03-03 for Nintendo Switch
*
* Layout:
* Clickable analogue stick at upper left thumb position
* Digital D-pad at lower left thumb position
* Clickable 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
* 2 digital buttons at inner left thumb position:
* - North = "−"
* - East = Capture (icon: circle; shape: square)
* 2 digital buttons at inner right thumb position:
* - North = "+"
* - West = Home (icon: house)
*
* Other features:
* - Wireless via Bluetooth
* - Wireless via NFC
* - Accelerometer (3 axis??)
* - Gyroscope (3 axis??)
* - 4 digital LEDs (??)
*
* Some versions seem to have additional features
*/
LIBGAMEPAD_CONTROLLER_NINTENDO_SWITCH_PRO,
/**
* Joy-Con L
*
* Released 2017-03-03 for Nintendo Switch
*
* Layout (when rotated 90 degrees counter-clockwise to become horizontal):
* Clickable analogue stick at left thumb position
* 4 digital directional buttons stick a bit inwards of right thumb position
* Digital "−" button north west of analogue stick
* Digital Capture (icon: circle; shape: square)
* button north east of directional buttons
* On front side (hidden when attached):
* Digital "SL" at left index finger position
* Digital "SR" at right index finger position
* Digital synchronisaton button left of "SR"
*
* Additional layout (described from attached state):
* Digital "L" button at upper left index finger position
* Digital "ZL" button at lower left index finger position
*
* Other features:
* - Wireless via Bluetooth 3.0
* - Accelerometer (3 axis??)
* - Gyroscope (3 axis??)
* - 4 digital LEDs, hidden when attached (??)
*/
LIBGAMEPAD_CONTROLLER_JOY_CON_L,
/**
* Joy-Con R
*
* Released 2017-03-03 for Nintendo Switch
*
* Layout (when rotated 90 degrees clockwise to become horizontal):
* Clickable analogue stick a bit inwards of left thumb position
* 4 digital buttons stick at right thumb position
* - North = "Y" ("X" when not rotated)
* - West = "B" ("Y" when not rotated)
* - South = "A" ("B" when not rotated)
* - East = "X" ("A" when not rotated)
* Digital "+" button north east of group of 4 digital buttons
* Digital Home (icon: house) button north west of analogue stick
* On front side (hidden when attached):
* Digital "SL" at left index finger position
* Digital "SR" at right index finger position
* Digital synchronisaton button left of "SR"
*
* Additional layout (described from attached state):
* Digital "R" button at upper right index finger position
* Digital "ZR" button at lower right index finger position
*
* Other features:
* - Wireless via Bluetooth 3.0
* - Wireless via NFC
* - Accelerometer (3 axis??)
* - Gyroscope (3 axis??)
* - 4 digital LEDs, hidden when attached (??)
* - Infrared depth camera for motion sensoring
*/
LIBGAMEPAD_CONTROLLER_JOY_CON_R,
/**
* Joy-Con
*
* Released 2017-03-03 for Nintendo Switch
*
* Joy-Con L and Joy-Con R together in attached state
*/
LIBGAMEPAD_CONTROLLER_JOY_CON,
/**
* Steam Controller
*
* Released 2015-11-10 for Steam
*
* TODO Document Steam Controller
*/
LIBGAMEPAD_CONTROLLER_STEAM,
/**
* Xbox Wireless Controller
*
* Released 2013-11-22 for Xbox One, also primary
* controller for Xbox Series X and Xbox Series S
*
* Layout:
* Clickable analogue stick at upper left thumb position
* Digital D-pad at lower left thumb position
* Clickable analogue stick at lower right thumb position
* 4 digital buttons at upper right thumb position
* - North = "Y" (colour: yellow)
* - West = "X" (colour: blue)
* - South = "A" (colour: green)
* - East = "B" (colour: red)
* 3 or 4 digital buttons at centre position
* - North = Xbox (icon: brand)
* - West = View (icon: two z-stacked windows)
* - East = Menu (icon: three vertically stacked horizontal lines)
*
* Other features:
* - Wireless via proprietary protocol
* - Wireless via Bluetooth 4.0 (second revision)
* - Stereo headset port (second revision)
* - Extension port
*
* Some versions have additional buttons.
* "Y", "X", "A", and "B" are not coloured on some versions.
*/
LIBGAMEPAD_CONTROLLER_XBOX_WIRELESS,
/**
* Xbox Wireless Controller, third revision
*
* Released 2020-11-10 for Xbox Series X and Xbox Series S
*
* Layout:
* Clickable analogue stick at upper left thumb position
* Digital D-pad at lower left thumb position
* Clickable analogue stick at lower right thumb position
* 4 digital buttons at upper right thumb position
* - North = "Y" (colour: yellow)
* - West = "X" (colour: blue)
* - South = "A" (colour: green)
* - East = "B" (colour: red)
* 3 or 4 digital buttons at centre position
* - North = Xbox (icon: brand)
* - West = View (icon: two z-stacked windows)
* - South = Share (icon: flat rectangle with upper edge replace with an up-arrow)
* - East = Menu (icon: three vertically stacked horizontal lines)
*
* Other features:
* - Wireless via proprietary protocol
* - Wireless via Bluetooth Low Energy
* - Stereo headset port
* - Extension port
*
* Some versions have additional buttons.
* "Y", "X", "A", and "B" are not coloured on some versions.
*/
LIBGAMEPAD_CONTROLLER_XBOX_WIRELESS_REV_3,
/**
* DualShock 4
*
* Released 2013-11-15 for PlayStation 4
*
* 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
* Analogue button "L2" at lower left index finger position
* Analogue button "R2" at lower right index finger position
* Digital "SHARE" button north east of D-pad
* Digital "OPTIONS" button north west of upper right thumb position
* Digital PS (icon: brand) button between analogue stick
* Clickable 2-point capacitive touchpad between upper thumb positions
*
* Other features:
* - Stereo headset port
* - Extension port
* - Wireless via Bluetooth 2.1+EDR
* - RGB LED
* - 3 axis accelerometer
* - 3 axis gyroscope
* - Built in single-channel speaker
*/
LIBGAMEPAD_CONTROLLER_DUAL_SHOCK_4,
/**
* Ouya controller
*
* Released 2013-06-25 for Ouya
*
* Layout:
* Clickable analogue stick at upper left thumb position
* Digital D-pad at lower left thumb position
* Clickable analogue stick at lower right thumb position
* 4 digital buttons at upper right thumb position:
* - North = "Y" (colour: orange–yellow)
* - West = "U" (colour: blue)
* - South = "O" (colour: lime)
* - East = "A" (colour: red)
* Digital Menu (icon: U inscribed in a ring) button between,
* but slightly below, the D-pad and right stick
* Touchpad (details missing) between upper thumb positions
* Digital button at upper left index finger position
* Digital button at upper right index finger position
* Analogue button at lower left index finger position
* Analogue button at lower right index finger position
*
* Other features:
* - Wireless via Bluetooth
*/
LIBGAMEPAD_CONTROLLER_OUYA,
/**
* Wii U Pro Controller
*
* Released 2012-11-18 for Wii U
*
* 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,
/**
* Wii U GamePad
*
* Released 2012-11-18 for Wii U
*
* TODO Document Wii U GamePad
*/
LIBGAMEPAD_CONTROLLER_WII_U,
/**
* PlayStation Move Navigation controller
*
* Released 2010-09-15 for PlayStation 3
*
* TODO Document PlayStation Move Navigation controller
*/
LIBGAMEPAD_CONTROLLER_PLAYSTATION_MOVE_NAVIGATION,
/**
* PlayStation Move
*
* Released 2010-09-15 for PlayStation 3
*
* TODO Document PlayStation Move
*/
LIBGAMEPAD_CONTROLLER_PLAYSTATION_MOVE,
/**
* Classic Controller Pro
*
* Released 2009-08-01 for Wii
*
* 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,
/**
* DualShock 3
*
* Released 2007-11-11 for PlayStation 3
*
* Adds rumble support to `LIBGAMEPAD_CONTROLLER_SIXAXIS`,
* no other differences
*/
LIBGAMEPAD_CONTROLLER_DUAL_SHOCK_3,
/**
* Classic Controller
*
* Released 2006-11-19 for Wii
*
* 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,
/**
* Nunchuk
*
* Released 2006-11-19 for Wii
*
* 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,
/**
* Wii Remote
*
* Released 2006-11-19 for Wii
*
* TODO Document Wii Remote
*/
LIBGAMEPAD_CONTROLLER_WII_REMOTE,
/**
* Wii Remote Plus
*
* 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,
/**
* Sixaxis
*
* Released 2006-11-11 for PlayStation 3
*
* Note:
* - Newer Linux drivers no longer report pressure on the D-pad, L1, and R1
* (reason: "there is no good way for reporting them", a standard is however defined)
* - Newer Linux drivers no longer report pressure Triangle, Square, Cross, or Circle
* (reason: "there is no good way for reporting them")
* - Newer Linux drivers no longer report gyroscope readings
* (reason: "very difficult to manage from within the driver even to get
* data, the sensor is inaccurate and the behavior is very
* different between hardware revisions")
* - Older Linux drivers failed to report left pressure on the D-pad
*
* Layout:
* Pressure-sensitive D-pad at upper left thumb position
* Clickable analogue stick at lower left thumb position
* Clickable analogue stick at lower right thumb position
* 4 Pressure-sensitive buttons at upper right thumb position:
* - North = Triangle (colour: green)
* - West = Square (colour: pink)
* - South = Cross (colour: blue)
* - East = Circle (colour: red)
* Pressure-sensitive button "L1" at upper left index finger position
* Pressure-sensitive button "R1" at upper right index finger position
* Analogue button "L2" at lower left index finger position
* Analogue button "R2" at lower right index finger position
* 3 digital buttons at centre position:
* - West = "SELECT" (shape: flat rectangle)
* - East = "START" (shape: flat play icon)
* - South = PS (icon: brand)
*
* Other features:
* - Stereo headset port
* - Extension port
* - Wireless via Bluetooth 2.1+EDR
* - 4 digital LEDs numbered 1 through 4
* - 3 axis accelerometer
* - 1 axis gyroscope
* - Built in single-channel speaker
*/
LIBGAMEPAD_CONTROLLER_SIXAXIS,
/**
* Xbox 360 Controller
*
* Released 2005-11-22 for Xbox 360
*
* TODO Document Xbox 360 Controller
*/
LIBGAMEPAD_CONTROLLER_XBOX_360,
/**
* Xbox Controller S
*
* Released 2002-??-?? for Xbox
*
* Layout:
* Clickable analogue stick at upper left thumb position
* Digital D-pad at lower left thumb position
* Clickable analogue stick at lower right thumb position
* 4 Pressure-sensitive buttons at upper right thumb position:
* - North = "Y" (colour: orange)
* - West = "X" (colour: blue)
* - South = "A" (colour: green)
* - East = "B" (colour: red)
* Digital button "L" at left index finger position
* Digital button "R" at right index finger position
* Analogue button "LT" at left long finger position
* Analogue button "RT" at right long finger position
* 2 digital buttons west of lower left thumb position
* - North = "BACK" (icon: mirrored play icon)
* - East = "START" (icon: play icon)
* 2 Pressure-sensitive buttons east of lower right thumb position
* - East = Black (colour: black)
* - South = White (colour: white)
*/
LIBGAMEPAD_CONTROLLER_XBOX_S,
/**
* Xbox Controller
*
* Released 2001-11-15 for Xbox
*
* Layout:
* Clickable analogue stick at upper left thumb position
* Digital D-pad at lower left thumb position
* Clickable analogue stick at lower right thumb position
* 6 Pressure-sensitive buttons at upper right thumb position:
* - North = "Y" (colour: orange)
* - West = "X" (colour: blue)
* - South = "A" (colour: green)
* - East = "B" (colour: red)
* - North east (slightly off) of "Y" = White (colour: white)
* - North east (slightly off) of "B" = Black (colour: black)
* Digital button "L" at left index finger position
* Digital button "R" at right index finger position
* Analogue button "LT" at left long finger position
* Analogue button "RT" at right long finger position
* 2 digital buttons at lower centre thumb position
* - East = "BACK"
* - West = "START"
*/
LIBGAMEPAD_CONTROLLER_XBOX,
/**
* Nintendo GameCube controller
*
* Released 2001-09-14 for Nintendo GameCube
*
* Layout:
* Analogue stick at upper left thumb position
* Digital D-pad at lower left thumb position
* Analogue "C" (colour: yellow) stick at lower right thumb position
* 4 digit buttons at upper right thumb position:
* - Centre = "A" (colour: green; extra large)
* - South west = "B" (colour: red)
* - North north west = "Y" (shape: circle arc)
* - North east east = "X" (shape: circle arc)
* Digital button "Z" (colour: blue) at upper right index finger position
* Analogue button "L" at lower left index finger position
* Analogue button "R" at lower right index finger position
* Digital "START/PAUSE" button at centre thumb position
*
* Other features:
* - "L" and "R" sends digital signal when fully depressed
*/
LIBGAMEPAD_CONTROLLER_NINTENDO_GAME_CUBE,
/**
* DualShock 2 Analog Controller
*
* Released 2000-03-04 for PlayStation 2
*
* Layout:
* Pressure-sensitive D-pad at upper left thumb position
* Clickable analogue stick at lower left thumb position
* Clickable analogue stick at lower right thumb position
* 4 Pressure-sensitive buttons at upper right thumb position:
* - North = Triangle (colour: green)
* - West = Square (colour: pink)
* - South = Cross (colour: blue)
* - East = Circle (colour: red)
* Pressure-sensitive button "L1" at upper left index finger position
* Pressure-sensitive button "R1" at upper right index finger position
* Pressure-sensitive button "L2" at lower left index finger position
* Pressure-sensitive 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)
*
* 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 DualShock 2 do?)
*/
LIBGAMEPAD_CONTROLLER_DUAL_SHOCK_2,
/**
* Dreamcast controller
*
* Released 1998-11-27 for Dreamcast
*
* Layout:
* Analogue stick at upper left thumb position
* Digital D-pad at lower left thumb position
* 4 digital buttons at upper right thumb position:
* - North = "Y" (colour: green)
* - West = "X" (colour: yellow)
* - South = "A" (colour: red)
* - East = "B" (colour: blue)
* Digital "START" (shape: up-pointing equilateral trangle)
* button at lower centre thumb position
*
* Other features:
* - 2 expansion sockets
*/
LIBGAMEPAD_CONTROLLER_DREAMCAST,
/**
* DualShock Analog Controller
*
* Released 1997-11-20 for PlayStation
*
* Adds rubble support to `LIBGAMEPAD_CONTROLLER_DUAL_ANALOG`
* (TODO What does digital mode on DualShock do?)
*/
LIBGAMEPAD_CONTROLLER_DUAL_SHOCK,
/**
* 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)
*
* 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,
/**
* 3D Pad
*
* Released 1996-07-05 for Sega Saturn
*
* TODO Document 3D Pad
*/
LIBGAMEPAD_CONTROLLER_3D_PAD,
/**
* Nintendo 64 controller
*
* Released 1996-06-23 for Nintendo 64
*
* Layout:
* M-shaped, allowing it to be hold one-handed as
* a gun or two-handed as a regular game controller
* Digital D-pad at left thumb position
* Analogue stick at middle thumb position
* 4 directional "C" (colour: yellow) buttons at right thumb position
* Digital "L" button at left index finger position
* Digital "Z" button at middle index finger position (we select BTN_TRIGGER_HAPPY1 for this one)
* Digital "R" button at right index finger position
* Digital "START" (colour: red) button north of middle thumb position
* 2 digital buttons south east of right thumb position
* - North = "B" (colour: green)
* - West = "A" (colour: blue)
*
* Other features:
* - Expension slot
*/
LIBGAMEPAD_CONTROLLER_NINTENDO_64,
/**
* Virtual Boy controller
*
* Released 1995-07-21 for Virtual Boy
*
* Layout:
* Digital D-pad at outer left thumb position
* Digital D-pad at outer right thumb position
* Digital "SELECT" button at middle left thumb position
* Digital "A" button at middle right thumb position
* Digital "START" button at inner left thumb position
* Digital "B" button at inner right thumb position
* Digital button at rear left index finger position
* Digital button at rear right index finger position
*/
LIBGAMEPAD_CONTROLLER_VIRTUAL_BOY,
/**
* PlayStation Controller
*
* Released 1994-12-03 for PlayStation
*
* Layout:
* Digital D-pad at left thumb position
* 4 digital buttons at 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)
*/
LIBGAMEPAD_CONTROLLER_PLAY_STATION,
/**
* Sega Saturn controller
*
* Released 1994-11-22 for Sega Saturn
*
* Layout:
* Digital D-pad at left thumb position
* 6 digital buttons at right thumb position:
* - Lower left = "A"
* - Lower middle = "B"
* - Lower right = "C"
* - Upper left = "X"
* - Upper middle = "Y"
* - Upper right = "Z"
* Digital button left index finger position
* Digital button right index finger position
* Digital "START" (shape: horizontal line) button at centre position
*/
LIBGAMEPAD_CONTROLLER_SEGA_SATURN,
/**
* 6-Button Arcade Pad
*
* Released 1993-??-?? for Sega Mega Drive
*
* Layout:
* Digital D-pad at left thumb position
* 6 digital buttons at right thumb position:
* - Lower left = "A"
* - Lower middle = "B"
* - Lower right = "C"
* - Upper left = "X"
* - Upper middle = "Y"
* - Upper right = "Z"
* Digital "MODE" button right index finger position
* Digital "START" (shape: horizontal line) button at centre position
*
* Conforming controllers:
* - Sega Nomad (however "MODE" is east of "START" which is far south east of "A")
*/
LIBGAMEPAD_CONTROLLER_6_BUTTON_ARCADE_PAD,
/**
* Gravis PC GamePad
*
* Released 1992-??-?? for PC
*
* Layout:
* Digital D-pad at left thumb position
* 4 digital buttons at right thumb position
* - North = blue
* - West = red
* - South = yellow
* - East = green
*
* Other features:
* - Has a switch for rotating the layout 180 degrees
* - Has a switch for turning two buttons into autofire versions of the other two
*/
LIBGAMEPAD_CONTROLLER_GRAVIS_PC,
/**
* SNES controller
*
* Released 1990-11-21 for SNES (Super Nintendo Entertainment System)
*
* Layout:
* Digital D-pad at left thumb position
* 4 digital buttons at right thumb position:
* - North = "X" (colour: blue)
* - West = "Y" (colour: green)
* - South = "B" (colour: yellow)
* - East = "A" (colour: red)
* Digital "L" button at left index finger position
* Digital "R" button at right index finger position
* 2 digital (/ shaped) buttons at centre thumb position:
* - East = "SELECT"
* - West = "START"
*
* The buttons are uncoloured on some versions
*/
LIBGAMEPAD_CONTROLLER_SNES,
/**
* Sega Mega Drive controller
*
* Released 1988-10-29 for Sega Mega Drive
*
* Layout:
* Digital D-pad at left thumb position
* 3 digital buttons at right thumb position:
* - Left = "A"
* - Middle = "B"
* - Right = "C"
* Digital "START" (shape: horizontal line) above "B"
*/
LIBGAMEPAD_CONTROLLER_SEGA_MEGA_DRIVE,
/**
* Master System controller
*
* Released 1986-09-?? for Master System
*
* Layout:
* Digital D-pad at left thumb position
* 2 digital buttons at right thumb position:
* - West = "1 START"
* - East = "2"
*/
LIBGAMEPAD_CONTROLLER_MASTER_SYSTEM,
/**
* NES controller
*
* Released 1983-07-15 for NES (Nintendo Entertainment System)
*
* Layout:
* Digital D-pad at left thumb position
* 2 digital buttons at right thumb position:
* - West = "B"
* - East = "A"
* 2 digital buttons (shape: horizontal line) at centre thumb position:
* - West = "SELECT"
* - East = "START"
*
* 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
* are with a / slant)
* - Mega Duck (however "SELECT" and "START" are south of "A" and "B")
*/
LIBGAMEPAD_CONTROLLER_NES,
/**
* Steam Deck
*
* Handheld gaming PC released 2022-02-25
*
* Layout:
* Digital D-pad at outer left thumb position
* Analogue stick with capacitive touch at natural left thumb position
* Analogue stick with capacitive touch at natural right thumb position
* 4 digital buttons at outer right thumb position:
* - North = "Y"
* - West = "X"
* - South = "A"
* - East = "B"
* Multi-touch trackpad at lower left thumb position
* Multi-touch trackpad at lower right thumb position
* Digital "L1" button at upper left index finger position
* Digital "R1" button at upper right index finger position
* Analogue "L2" button at lower left index finger position
* Analogue "R2" button at lower right index finger position
* Digital "L4" button at left long finger position
* Digital "R4" button at right long finger position
* Digital "L5" button at left ring finger position
* Digital "R5" button at right ring finger position
* Digital "STEAM" button beneath lower left thumb position
* Digital Quick Access (icon: three horizontally stacked dots)
* button beneath lower right thumb position
* Digital View (icon: two z-stacked windows) button
* north west of natural left thumb position
* Digital Menu (icon: three vertically stacked horizontal lines)
* button north east of natural right thumb position
* 2 digital buttons inward from upper left index finger position:
* - Outer = Volume "−"
* - Inner = Volume "+"
*
* Other features:
* - 3 axis accelerometer
* - 3 axis gyroscope
* - Ambient light sensor
*/
LIBGAMEPAD_CONTROLLER_STEAM_DECK,
/**
* Game Boy Advanced
*
* Handheld gaming console released 2001-03-21
*
* Layout:
* Digital D-pad at left thumb position
* 2 digital buttons at south south west of D-pad
* - North = "START"
* - South = "SELECT"
* 2 digital buttons at right thumb position:
* - West = "B"
* - East = "A"
* Digital "L" button at left index finger position
* Digital "R" button at right index finger position
*
* Conforming controllers:
* - Game King (however "SELECT" and "START" are north of D-pad,
* "SELECT" to east and "START to west)
*/
LIBGAMEPAD_CONTROLLER_GAME_BOY_ADVANCED,
/**
* Game Gear
*
* Handheld gaming console released 1990-10-06
*
* Layout:
* Digital D-pad at left thumb position
* 2 digital buttons at right thumb position:
* - West = "1"
* - North = "2"
* Digital "START" (colour: blue, shape: corda-cut circle)
* button north of right thumb position
*/
LIBGAMEPAD_CONTROLLER_GAME_GEAR,
/**
* Linux reference gamepad layout
*
* Version documented since Linux 4.12 in Documentation/input/gamepad
*
* Layout:
* Analogue ABS_HAT0X/ABS_HAT0Y/BTN_DPAD_* D-pad at upper left thumb position
* Clickable analogue BTN_THUMBL/ABS_X/ABS_Y stick at lower left thumb position
* Clickable analogue BTN_THUMBR/ABS_RX/ABS_RY stick at lower right thumb position
* 4 digital buttons at upper right thumb position:
* - North or upper left = BTN_NORTH (= BTN_X)
* - West or lower left = BTN_WEST (= BTN_Y)
* - South or lower right = BTN_SOUTH (= BTN_A)
* - East or upper right = BTN_EAST (= BTN_B)
* Analogue button BTN_TL/ABS_HAT1Y at upper left index finger position
* Analogue button BTN_TR/ABS_HAT1X at upper right index finger position
* Analogue button BTN_TL2/ABS_HAT2Y at lower left index finger position
* Analogue button BTN_TR2/ABS_HAT2X at lower right index finger position
* 3 digital button north of the centre
* - West = BTN_SELECT
* - East = BTN_START
* - South = BTN_MODE
*
* Applications shall be aware that kernel drivers, even written for
* specific controllers, do not always use the correct codes. For example
* the Sony drivers currently (Linux 5.18) use ABS_Z and ABS_RZ instead
* of ABS_HAT2Y and ABS_HAT2X respectively.
*
* There are multiple substandard, this one includes all features,
* however notably, there cannot be a BTN_SELECT without a BTN_START,
* and all gamepads must have at least 2 action buttons: BTN_SOUTH
* and BTN_EAST, and if there is a third action button, it is mapped
* to BTN_WEST. The action buttons, in the case that there is either
* 2 or 3 of them, ordered from left to right: BTN_WEST (if present),
* BTN_SOUTH, BTN_EAST, with the caveat that if they buttons are
* perfectly vertically aligned the order, is from bottom up, BTN_SOUTH,
* 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). 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,
/**
* libgamepad defined amended version of the 3-button subversion
* of `LIBGAMEPAD_CONTROLLER_LINUX_4_12`
*
* There are multiple substandard, this one includes all features
*
* The amended version flips the order of BTN_WEST, BTN_SOUTH, BTN_EAST
* (the action buttons) when they are perfectly vertically aligned. A
* layout that conforms to either `LIBGAMEPAD_CONTROLLER_LINUX_4_12` or
* `LIBGAMEPAD_CONTROLLER_LINUX_4_12_RECTIFIED_3BTN`, and has
* exactly 3 actions button that are not perfectly vertically aligned,
* conforms to both.
*
* Layout:
* Analogue ABS_HAT0X/ABS_HAT0Y/BTN_DPAD_* D-pad at upper left thumb position
* Clickable analogue BTN_THUMBL/ABS_X/ABS_Y stick at lower left thumb position
* Clickable analogue BTN_THUMBR/ABS_RX/ABS_RY stick at lower right thumb position
* 3 digital buttons at upper right thumb position:
* - Left/lower = BTN_WEST (= BTN_Y)
* - Middle = BTN_SOUTH (= BTN_A)
* - Right/upper = BTN_EAST (= BTN_B)
* Analogue button BTN_TL/ABS_HAT1Y at upper left index finger position
* Analogue button BTN_TR/ABS_HAT1X at upper right index finger position
* Analogue button BTN_TL2/ABS_HAT2Y at lower left index finger position
* Analogue button BTN_TR2/ABS_HAT2X at lower right index finger position
* 3 digital button north of the centre
* - West = BTN_SELECT
* - East = BTN_START
* - South = BTN_MODE
*
* Applications shall be aware that kernel drivers, even written for
* specific controllers, do not always use the correct codes. For example
* the Sony drivers currently (Linux 5.18) use ABS_Z and ABS_RZ instead
* of ABS_HAT2Y and ABS_HAT2X respectively.
*/
LIBGAMEPAD_CONTROLLER_LINUX_4_12_RECTIFIED_3BTN,
/**
* libgamepad defined 6-button extension of `LIBGAMEPAD_CONTROLLER_LINUX_4_12`
*
* There are multiple substandard, this one includes all features
*
* Layout:
* Analogue ABS_HAT0X/ABS_HAT0Y/BTN_DPAD_* D-pad at upper left thumb position
* Clickable analogue BTN_THUMBL/ABS_X/ABS_Y stick at lower left thumb position
* Clickable analogue BTN_THUMBR/ABS_RX/ABS_RY stick at lower right thumb position
* 6 digital buttons at upper right thumb position:
* - Upper right = BTN_X (= BTN_NORTH)
* - Upper middle = BTN_Y (= BTN_WEST)
* - Upper left = BTN_Z
* - Lower left = BTN_A (= BTN_SOUTH)
* - Lower middle = BTN_B (= BTN_EAST)
* - Lower right = BTN_C
* Analogue button BTN_TL/ABS_HAT1Y at upper left index finger position
* Analogue button BTN_TR/ABS_HAT1X at upper right index finger position
* Analogue button BTN_TL2/ABS_HAT2Y at lower left index finger position
* Analogue button BTN_TR2/ABS_HAT2X at lower right index finger position
* 3 digital button north of the centre
* - West = BTN_SELECT
* - East = BTN_START
* - South = BTN_MODE
*
* Applications shall be aware that kernel drivers, even written for
* specific controllers, do not always use the correct codes. For example
* the Sony drivers currently (Linux 5.18) use ABS_Z and ABS_RZ instead
* of ABS_HAT2Y and ABS_HAT2X respectively.
*/
LIBGAMEPAD_CONTROLLER_LINUX_4_12_6BTN_EXT
};
/**
* Joystick profiles
*
* This list only contains well-known profiles, mainly
* the primary controllers from video gaming consoles
*/
enum libgamepad_joystick {
/**
* Unknown joystick profile
*/
LIBGAMEPAD_JOYSTICK_UNKNOWN,
/**
* Unlisted joystick profile
*/
LIBGAMEPAD_JOYSTICK_OTHER,
/**
* Atari CX40 joystick
*
* Released 1978 for Atari 2600
*
* Layout:
* 8-directional digital joystick in centre
* Digital button at north east
*/
LIBGAMEPAD_JOYSTICK_ATARI_CX40
};
/**
* 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 {
/**
* Signals thatevents where dropped because
* the application did not read fast enough
*
* When received, the next call to `libgamepad_next_event`
* will drain the event queue and generate synchronisation
* events (which have the timestamp set to zero) to bring
* the applications state of the buttons/keys and absolute
* axes up to date
*/
LIBGAMEPAD_EVENT_DROP,
/**
* Signals that all previous events, from the
* last `LIBGAMEPAD_EVENT_END` or `LIBGAMEPAD_EVENT_DROP`
* where part of the same report from the input device
*
* This event will always be sent, however it may have
* been dropped when a `LIBGAMEPAD_EVENT_DROP` is sent
*/
LIBGAMEPAD_EVENT_END,
/**
* Button/key
*
* Expectation when `LIBGAMEPAD_EVENT_DROP` has been
* received: a full press and release, or release and
* press, may be missing the if read interval is longer
* than such an event would span
*/
LIBGAMEPAD_BUTTON,
/**
* Absolute axis
*
* Expectation when `LIBGAMEPAD_EVENT_DROP` has been
* received: less smooth transition between two states,
* and quick movements in one direction and back may
* be missing, but only such movements that are sorter
* than the read duration
*/
LIBGAMEPAD_ABSOLUTE_AXIS,
/**
* Relative axis
*
* Expectation when `LIBGAMEPAD_EVENT_DROP` has been
* received: movement details are lost and calculate
* position is off (it is possible that the driver
* sends synchronisations event to adjust for the
* position)
*/
LIBGAMEPAD_RELATIVE_AXIS
};
/**
* Subdevice input event structure
*/
struct libgamepad_input_event {
/**
* The affected input type
*/
enum libgamepad_input_type type;
/**
* The button/key or axis affected by the event
*
* Not set if `.type` is `LIBGAMEPAD_EVENT_DROP`
*/
uint16_t code;
/**
* The new value on the button/key or axis,
* or the delta if on a relative axis
*
* Not set if `.type` is `LIBGAMEPAD_EVENT_DROP`
*/
int32_t value;
/**
* Event timestamp
*
* Set to zero if not supported by the driver
* or if the event generated by the library
*/
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;
/**
* Specifies whether the library shall automatically call
* `libgamepad_generate_sync_events` if events are dropped
* or the event queue is manually drained
*/
int auto_sync;
/**
* 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;
/**
* Data for internal use
*/
LIBGAMEPAD_DEVICE_INTERNALS *internals;
/**
* Human-readable device (sub- or superdevice) name
*
* Empty if not available
*/
char *name;
/**
* ID that is supposted to be unique to the device
* (sub- or superdevice)
*
* Empty if not available
*/
char *unique_id;
/**
* The location if the device
*
* Empty if not available
*/
char *physical_location;
/**
* 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];
/**
* 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];
};
/* 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 *);
/**
* Search for sound devices built into or attached a device
*
* @param syspath The superdevice's path in /sys
* @param cardsp Output parameter for a list of sound card indices
* @return The number of found sound cards, -1 on failure
*/
ssize_t libgamepad_find_sound_devices(const char *, size_t **);
/**
* 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
*
* This function may temporarily modify the file status
* flags (which affects all duplicate file descriptors
* share the same open file descriptor) of `dirfd` if
* `path` is `NULL` or empty
*
* @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
* realloc(3), openat(3), ioctl(3), or read(3)
*/
int libgamepad_open_device(struct libgamepad_device *, int, const char *, int);
/**
* Close a subdevice
*
* @param device Device information and handles, may be `NULL`
* @return Normally 0, -1 if there was a deferred error
*/
int libgamepad_close_device(struct libgamepad_device *);
/**
* Get the next event on a subdevice
*
* This function may temporarily modify the file status
* flags of the open file decriptor it uses to access
* the device
*
* @param device Device to read an event from
* @param events Output buffer for the events (will be in order)
* @param max The number of elements `events` fit
* (may be 0 for error condition checking)
* @return The number of returned events (may be more or
* less than actually read), -1 on failure
*
* This function may fail for any reason specified for
* realloc(3) and read(3), including:
* - EAGAIN no more data currently available (non-blocking mode)
* - EINTR system call was interrupted, try again
* (may be deferred to `libgamepad_close_device`)
* - ENODEV device has been unplugged or access has been revoked
*/
ssize_t libgamepad_next_event(struct libgamepad_device *, struct libgamepad_input_event *, size_t);
/**
* Remove all events on a subdevice queued by kernel
* and queue synchronisation events so that the application
* will have (after reading them) up to date button/key and
* absolute axis states
*
* This function is normally used internally, but can be
* useful after calling `libgamepad_set_clock`
*
* This function may temporarily modify the file status
* flags of the open file decriptor it uses to access
* the device
*
* @param device Device to drain queue for
* @return 0 on success, -1 on failure
*
* This function may fail for any reason specified for
* realloc(3) and read(3), including:
* - ENODEV device has been unplugged or access has been revoked
* except for EINTR which is deferred to the next call to
* `libgamepad_next_event` or `libgamepad_close_device`
* (whichever comes first) for the same device, and EAGAIN
*/
int libgamepad_drain_events(struct libgamepad_device *);
/**
* Generates any events needed to keep the applications
* button/key and absolute axes states up to date
*
* This function is normally used internally, but can be
* useful after calling `libgamepad_drain_events` if
* automatic generation of synchronisation events have
* been disabled by modifying `device->auto_sync`
*
* This function may temporarily modify the file status
* flags of the open file decriptor it uses to access
* the device
*
* @param device Device to synchronise
* @return 0 on success, -1 on failure
*/
int libgamepad_generate_sync_events(struct libgamepad_device *);
/**
* Get the name of a button/key
*
* If `device` is `NULL`, the returned name will
* have a prefix , that does not include an underscore
* except (mandatorily) as the very last character
* in the prefix, however if the key/button is valid
* but does not have a name a numerical representation
* is given (currently "0x" prefixed upper case
* hexadecimal); there are currently two prefixes:
* "KEY_" and "BTN_"
*
* @param device If `NULL`, a generic name will be returned,
* otherwise the canonical name for the button/key
* on the specific device will be returned
* (`NULL` if not information is unavailable)
* @param code The button/key
* @return The button/key's name, `NULL` if not found
*/
LIBGAMEPAD_PURE__ const char *libgamepad_get_button_name(const struct libgamepad_device *, uint16_t);
/**
* Get the name of an absolute axis
*
* If `device` is `NULL`, the returned name will
* have a prefix , that does not include an underscore
* except (mandatorily) as the very last character
* in the prefix, however if the axis is valid but
* does not have a name a numerical representation
* is given (currently "0x" prefixed upper case
* hexadecimal); there is currently only one prefix:
* "ABS_"
*
* @param device If `NULL`, a generic name will be returned,
* otherwise the canonical name for the axis
* on the specific device will be returned
* (`NULL` if not information is unavailable)
* @param code The axis
* @return The axis' name, `NULL` if not found
*/
LIBGAMEPAD_PURE__ const char *libgamepad_get_absolute_axis_name(const struct libgamepad_device *, uint16_t);
/**
* Get the name of a relative axis
*
* If `device` is `NULL`, the returned name will
* have a prefix , that does not include an underscore
* except (mandatorily) as the very last character
* in the prefix, however if the axis is valid but
* does not have a name a numerical representation
* is given (currently "0x" prefixed upper case
* hexadecimal); there is currently only one prefix:
* "REL_"
*
* @param device If `NULL`, a generic name will be returned,
* otherwise the canonical name for the axis
* on the specific device will be returned
* (`NULL` if not information is unavailable)
* @param code The axis
* @return The axis' name, `NULL` if not found
*/
LIBGAMEPAD_PURE__ const char *libgamepad_get_relative_axis_name(const struct libgamepad_device *, uint16_t);
/**
* Get a button/key code from it's name
*
* @param name The button/key's name or textual
* representation of its code number
* @return The button/key, -1 if not found
*/
int16_t libgamepad_get_button_by_name(const char *);
/**
* Get an absolute axis code from it's name
*
* @param name The absolute axis' name or textual
* representation of its code number
* @return The absolute axis, -1 if not found
*/
int16_t libgamepad_get_absolute_axis_by_name(const char *);
/**
* Get a relative axis code from it's name
*
* @param name The relative axis' name or textual
* representation of its code number
* @return The relative axis, -1 if not found
*/
int16_t libgamepad_get_relative_axis_by_name(const char *);
/**
* Get whether a device has a specific button or key
*
* @param device The device
* @param code The button/key
* @return 1 if the button/key is reported as present, 0 otherwise
*/
inline int
libgamepad_get_device_has_button(const struct libgamepad_device *device, uint16_t code)
{
return code < sizeof(device->button_map) / sizeof(*device->button_map) &&
device->button_map[code] >= 0;
}
/**
* Get whether a device has a specific absolute axis
*
* @param device The device
* @param code The axis
* @return 1 if the axis is reported as present, 0 otherwise
*/
inline int
libgamepad_get_device_has_absolute_axis(const struct libgamepad_device *device, uint16_t code)
{
return code < sizeof(device->absolute_axis_map) / sizeof(*device->absolute_axis_map) &&
device->absolute_axis_map[code] >= 0;
}
/**
* Get whether a device has a specific relative axis
*
* @param device The device
* @param code The axis
* @return 1 if the axis is reported as present, 0 otherwise
*/
inline int
libgamepad_get_device_has_relative_axis(const struct libgamepad_device *device, uint16_t code)
{
return code < sizeof(device->relative_axis_map) / sizeof(*device->relative_axis_map) &&
device->relative_axis_map[code] >= 0;
}
/**
* Get whether a device has a specific force feedback effect
*
* @param device The device
* @param code The force feedback effect or waveform
* @return 1 if the axis is reported as present, 0 otherwise
*/
inline int
libgamepad_get_device_has_ff_effect(const struct libgamepad_device *device, uint16_t code)
{
return code < sizeof(device->force_feedback_support) * 8 &&
(1 & (device->force_feedback_support[code / (8 * sizeof(*device->force_feedback_support))] >>
(code % (8 * sizeof(*device->force_feedback_support)))));
}
/**
* 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.
*
* This information is not necessarily up to date
* before the first `LIBGAMEPAD_EVENT_END` has been
* reported
*
* @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
*/
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.
*
* The value of `.value` in the returned pointer is
* not necessarily up to date before the first
* `LIBGAMEPAD_EVENT_END` has been reported
*
* @param device The device to retrieve the information for
* @param code The axis
* @return Information about the axis; this is a pointer
* stored inside `device`, some function calls
* may alter the contents of invalidate the pointer,
* `libgamepad_close_device(device)` will always
* invalidate the pointer and it is expected that
* `libgamepad_next_event` often alters `.value`
*/
LIBGAMEPAD_PURE__ /* `struct input_absinfo` is defined in <linux/input.h> */
const struct input_absinfo *libgamepad_get_absolute_axis_info(struct libgamepad_device *, uint16_t);
/**
* 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
*
* If your application depends on new events using the
* selected clock (if any at all), call `libgamepad_drain_events`
* after this function
*
* Support clocks are (in Linux 5.18):
* - CLOCK_REALTIME
* - CLOCK_MONOTONIC
* - CLOCK_BOOTTIME
* As usual, CLOCK_MONOTONIC_RAW is not supported
*
* @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