/* See LICENSE file for copyright and license details. */ #ifndef LIBGAMEPAD_H #define LIBGAMEPAD_H #include #include #include #include #include #include #include #include #include #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 */ 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 */ 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 */ 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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