/* See LICENSE file for copyright and license details. */ #ifndef LIBGAMEPAD_H #define LIBGAMEPAD_H #include #include #include #include #include #include #include #include #include #include /** * 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 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 * Digital Stadia (icon: brand) button between analogue sticks * 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 * * TODO Document Wii U Pro Controller */ 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-??-?? for Wii * * TODO Document Classic Controller Pro */ 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 * * TODO Document Classic Controller */ LIBGAMEPAD_CONTROLLER_WII_CLASSIC, /** * Nunchuk * * Released 2006-11-19 for Wii * * TODO Document Nunchuk */ 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` */ 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 * * TODO Document DualShock Analog Controller */ LIBGAMEPAD_CONTROLLER_DUAL_SHOCK, /** * Dual Analog Controller * * Released 1997-04-25 for PlayStation * * TODO Document Dual Analog Controller */ 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 * 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 platforms: * - 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 platforms: * - 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 platforms: * - 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). */ 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 { /** * Button/key */ LIBGAMEPAD_BUTTON, /** * Absolute axis */ LIBGAMEPAD_ABSOLUTE_AXIS, /** * Relative axis */ LIBGAMEPAD_RELATIVE_AXIS }; /** * Subdevice input event structure */ struct libgamepad_input_event { /** * The affect input type */ enum libgamepad_input_type type; /** * Whether the event was polled in a * synchronisation read */ short int sync_event; /** * The button/key or axis affect by the event */ uint16_t code; /** * The new value on the button/key or axis, * or the delta if on a relative axis */ int32_t value; /** * Event timestamp */ struct timeval time; }; /** * Subdevice on a device * * For example a modern gamepad may be split into * a gamepad, computer mouse, and motion sensor * * Structure is always deallocated by the library * using free(3) */ struct libgamepad_subdevice { /** * Device type */ enum libgamepad_type type; /** * Device path */ char path[]; }; /** * Physical device * * Contents of structure is deallocated with * `libgamepad_close_superdevice` */ struct libgamepad_superdevice { /** * Device path in /sys */ char *syspath; /** * Number of subdevices */ size_t ndevices; /** * Subdevices */ struct libgamepad_subdevice **devices; /** * Number of LEDs */ size_t nleds; /** * Paths to LEDs */ char **leds; /** * Number of power supplies (batteries) */ size_t npower_supplies; /** * Paths of power supplies (batteries) */ char **power_supplies; }; /** * Subdevice structure for detailed information listening on input events */ struct libgamepad_device { /** * File descriptor to the device, the application * may use it to poll for read-readyness */ int fd; /** * Bus type the device is connect via, see BUS_-prefixed * constants in */ 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 */ const char *name; /** * ID that is supposted to be unique to the device * (sub- or superdevice) */ const char *unique_id; /** * The location if the device */ const char *physical_location; /** * Number of (digital) buttons/keys present * on the device */ size_t nbuttons; /** * Number of absolute axes present on the device */ size_t nabsolute_axes; /** * Number of relative axes present on the device */ size_t nrelative_axes; /** * Map from button/key indices to button/key codes */ uint16_t *buttons; /** * Map from absolute axis indices to absolute axis codes */ uint16_t *absolute_axes; /** * Map from relative axis indices to relative axis codes */ uint16_t *relative_axes; /** * Maps from button/key codes to button indices, * non-present buttons/keys map to -1, other * values are in [0, `.nbuttons`[. */ int16_t button_map[KEY_CNT]; /** * Maps from absolute axis codes to absolute axis * indices, non-present axes map to -1, other * values are in [0, `.nabsolute_axes`[. */ int16_t absolute_axis_map[ABS_CNT]; /** * Maps from relative axis codes to absolute axis * indices, non-present axes map to -1, other * values are in [0, `.nrelative_axes`[. */ int16_t relative_axis_map[REL_CNT]; /** * Bitmap of supported force feedback effects */ uint8_t force_feedback_support[(FF_CNT + 7) / 8]; }; /* FOR INTERNAL USE */ void libgamepad_construct_force_feedback_effect__(struct ff_effect *, const struct ff_effect *, double, uint16_t, uint16_t); /** * Get a list of all available physical devices * * @param devicesp Output parameter for the list of devices * @param ndevicesp Output parameter for the number of listed devices * @return 0 on success, -1 on failure * * This function may fail for any reason specified for * realloc(3), open(3), fdopendir(3), or readdir(3) */ int libgamepad_list_superdevices(char ***, size_t *); /** * Get information about a physical device * * @param devicep Output parameter for the device information, * allocated memory shall be deallocated with * `libgamepad_close_superdevice(devicep)` * @param syspath The path of the device, in /sys * @return 0 on success, -1 on failure * * This function may fail for any reason specified for * realloc(3), openat(3), fdopendir(3), or readdir(3) */ int libgamepad_open_superdevice(struct libgamepad_superdevice *, const char *); /** * Deallocate the contents of a `struct libgamepad_superdevice` * * @param device The structure whose nested memory allocations * shall be deallocated, may be `NULL` */ void libgamepad_close_superdevice(struct libgamepad_superdevice *); /** * 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 * * @param devicep Output parameter for the device information and handles; * deallocated with `libgamepad_close_device` * @param dirfd File descriptor to path that `path` is relative to * (unless it is an absolute path), or `AT_FDCWD` for the * current working directory * @param path The path to the device, if `NULL` or empty, `dirfd` * will be used as the file descriptor to the device, * in which case the application must keep it open until * the device is closed, and then close it manually, and * `mode` is ignored * @param mode Mode to open the device in, normally `O_RDONLY`, * `O_RDONLY|O_NONBLOCK`, `O_RDWR`, or `O_RDWR|O_NONBLOCK` * @return 0 on success, -1 on failure * * This function may fail for any reason specified for * malloc(3), openat(3) or libevdev_new_from_fd(3) */ int libgamepad_open_device(struct libgamepad_device *, int, const char *, int); /** * Close a subdevice * * @param device Device information and handles, may be `NULL` */ void libgamepad_close_device(struct libgamepad_device *); /** * Get the next event on a subdevice * * NB! events may be queued internally (by libevdev), therefore * an application must either call this function in a loop in * its own thread, or have the device opened in non-blocking * mode and even the poll the device's file descriptor for * read-readyness and when it is ready clal this function in * a loop until it sets `errno` to `EAGAIN`. * * @param device Device to read an event from * @param eventp Output parameter for the event * @return 1 if an event was returned, * 0 if no event was returned, * -1 on failure * * This function may fail for any reason specified for * libevdev_next_event(3), including: * - EAGAIN no more data currently available (non-blocking mode) * - EINTR system call was interrupted, try again * - ENODEV device has been unplugged or access has been revoked */ int libgamepad_next_event(struct libgamepad_device *, struct libgamepad_input_event *); /** * Get the name of a button/key * * 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 */ 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 */ 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 */ 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 button/key is pressed down or not * * @param device The device to retrieve the information for * @param code The button/key * @return 1 if the button/key is pressed down, * 0 otherwise */ int libgamepad_get_button_is_pressed(struct libgamepad_device *, uint16_t); /** * Get information about an absolute axis * * @param device The device to retrieve the information for * @param code The axis * @return Information about the axis */ const struct input_absinfo *libgamepad_get_absolute_axis_info(struct libgamepad_device *, uint16_t); /* `struct input_absinfo` is defined in */ /** * Grab a subdevice, if not already grabbed * * This is supposed to block out clients from * retrieving events for the device, but it * does not necessarily stop them from reading * the device state * * @param device The device to grab * @return 0 on success, -1 on failure * * In the event that the device is already grabbed by * via another open file descriptor (duplicates share * grab), this function will return -1 and set `errno` * to `EBUSY` */ inline int libgamepad_grab(struct libgamepad_device *device) { return ioctl(device->fd, EVIOCGRAB, (void *)1); } /** * Ungrab a subdevice, unless not currently grabbed * * @param device The device to ungrab * @return 0 on success, -1 on failure */ inline int libgamepad_ungrab(struct libgamepad_device *device) { return ioctl(device->fd, EVIOCGRAB, (void *)0); } /** * Set the clock that event timestamps shall be reported in * * @param device The device to configure * @param clockid The clock to use on event timestamps * @return 0 on success, -1 on failure */ inline int libgamepad_set_clock(struct libgamepad_device *device, clockid_t clockid) { return ioctl(device->fd, EVIOCSCLOCKID, &clockid); } /** * Install a force feedback effect that can be played back later * * @param device The device to configure * @param effect The effect to install; will be edited, specifically the ID * will be set (need not be set before calling this function) * @return 0 on success, -1 on failure */ inline int /* `struct ff_effect` is defined in */ 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