From f4d0d70c45006288c236bb33e82aa64e967bd66d Mon Sep 17 00:00:00 2001 From: "Brian S. Stephan" Date: Mon, 17 Jun 2024 11:42:13 -0500 Subject: [PATCH] Add a generic USB HID mode (#1061) * copy the existing HID driver to a PS3 driver the intent is to redo the HID driver as a generic, quirkless, expandable (!), and customizable (!!) driver so that we have a mode that is free of odd VID/PID dependencies, report layouts, and so on. to accomplish that, we want to retain the existing HID mode, which has some PS3 quirks, as a separate driver. configurations referring to this driver will continue to point at it in the future, as this is an internal rename and move (i.e. the new HID driver will be truly new, a different config entry and so on). the PS3 mode was tested in a gamepad tester in Linux, and via SSF2THDR and MvC2 on PS3 --- all seems well, including the analogs on MvC2 and the functionality of the PS button on both. * reimplement HID mode as a generic (non-PS-ian) gamepad this just covers the basics; 16 buttons (the last two don't work yet) + a hat. TODOs include getting the axes back, and then will begin some level of customization (be it by defines or protobuf), but that'll happen later. I also need to see how some devices (e.g. converters, maybe an Undamned USB decoder, maybe even an Analogue Pocket Dock) handle this, because this alone might be usable for those things. maybe. * enable and define up to 32 buttons for Generic mode this draws a direct line from GAMEPAD_MASK values to the HID report for Generic mode, including the dpad Up/Down/Left/Right values as buttons, and defining 12 "extra" buttons that are only used/output in this mode * add Generic HID mode to the settings and boot dropdowns * add analog emulation of L and R sticks to generic HID * pin mapping labels and things for Extra 1 -- 12 * relabel Extra buttons for specific consoles as "-" * just a couple trivial cleanups --- CMakeLists.txt | 1 + .../display/ui/screens/ButtonLayoutScreen.h | 5 +- headers/drivers/hid/HIDDescriptors.h | 216 +++++--------- headers/drivers/ps3/PS3Descriptors.h | 263 ++++++++++++++++++ headers/drivers/ps3/PS3Driver.h | 33 +++ headers/gamepad.h | 35 ++- headers/gamepad/GamepadState.h | 39 ++- headers/gp2040.h | 3 +- proto/enums.proto | 15 +- src/config_legacy.cpp | 4 +- src/config_utils.cpp | 2 +- src/display/ui/screens/ButtonLayoutScreen.cpp | 3 +- src/drivermanager.cpp | 10 +- src/drivers/hid/HIDDriver.cpp | 107 ++++--- src/drivers/ps3/PS3Driver.cpp | 159 +++++++++++ src/gamepad.cpp | 48 ++++ src/gp2040.cpp | 19 +- www/src/Data/Buttons.js | 99 ++++++- www/src/Data/Pins.ts | 12 + www/src/Locales/en/PinMapping.jsx | 12 + www/src/Locales/en/SettingsPage.jsx | 3 +- www/src/Pages/SettingsPage.jsx | 2 + 22 files changed, 842 insertions(+), 248 deletions(-) create mode 100644 headers/drivers/ps3/PS3Descriptors.h create mode 100644 headers/drivers/ps3/PS3Driver.h create mode 100644 src/drivers/ps3/PS3Driver.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e78431ad3..0455165e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -155,6 +155,7 @@ src/drivers/mdmini/MDMiniDriver.cpp src/drivers/neogeo/NeoGeoDriver.cpp src/drivers/net/NetDriver.cpp src/drivers/pcengine/PCEngineDriver.cpp +src/drivers/ps3/PS3Driver.cpp src/drivers/ps4/PS4Auth.cpp src/drivers/ps4/PS4AuthUSBListener.cpp src/drivers/ps4/PS4Driver.cpp diff --git a/headers/display/ui/screens/ButtonLayoutScreen.h b/headers/display/ui/screens/ButtonLayoutScreen.h index 828f13e10..1f15d88c5 100644 --- a/headers/display/ui/screens/ButtonLayoutScreen.h +++ b/headers/display/ui/screens/ButtonLayoutScreen.h @@ -140,7 +140,8 @@ class ButtonLayoutScreen : public GPScreen { void generateHeader(); const std::map displayModeLookup = { - {INPUT_MODE_HID, 0}, + {INPUT_MODE_PS3, 0}, + {INPUT_MODE_GENERIC, 0}, {INPUT_MODE_SWITCH, 1}, {INPUT_MODE_XINPUT, 2}, {INPUT_MODE_XBONE, 2}, @@ -194,4 +195,4 @@ class ButtonLayoutScreen : public GPScreen { bool pressedDownRight(); }; -#endif \ No newline at end of file +#endif diff --git a/headers/drivers/hid/HIDDescriptors.h b/headers/drivers/hid/HIDDescriptors.h index 239eac39f..fedb71a1b 100644 --- a/headers/drivers/hid/HIDDescriptors.h +++ b/headers/drivers/hid/HIDDescriptors.h @@ -22,8 +22,6 @@ * **************************************************************************/ -#define ENDPOINT0_SIZE 64 - #define GAMEPAD_INTERFACE 0 #define GAMEPAD_ENDPOINT 1 #define GAMEPAD_SIZE 64 @@ -42,22 +40,6 @@ #define HID_HAT_UPLEFT 0x07 #define HID_HAT_NOTHING 0x08 -// Button report (16 bits) -#define HID_MASK_SQUARE (1U << 0) -#define HID_MASK_CROSS (1U << 1) -#define HID_MASK_CIRCLE (1U << 2) -#define HID_MASK_TRIANGLE (1U << 3) -#define HID_MASK_L1 (1U << 4) -#define HID_MASK_R1 (1U << 5) -#define HID_MASK_L2 (1U << 6) -#define HID_MASK_R2 (1U << 7) -#define HID_MASK_SELECT (1U << 8) -#define HID_MASK_START (1U << 9) -#define HID_MASK_L3 (1U << 10) -#define HID_MASK_R3 (1U << 11) -#define HID_MASK_PS (1U << 12) -#define HID_MASK_TP (1U << 13) - // HID analog sticks only report 8 bits #define HID_JOYSTICK_MIN 0x00 #define HID_JOYSTICK_MID 0x80 @@ -66,64 +48,25 @@ typedef struct __attribute((packed, aligned(1))) { // digital buttons, 0 = off, 1 = on + uint32_t buttons; - uint8_t square_btn : 1; - uint8_t cross_btn : 1; - uint8_t circle_btn : 1; - uint8_t triangle_btn : 1; - - uint8_t l1_btn : 1; - uint8_t r1_btn : 1; - uint8_t l2_btn : 1; - uint8_t r2_btn : 1; - - uint8_t select_btn : 1; - uint8_t start_btn : 1; - uint8_t l3_btn : 1; - uint8_t r3_btn : 1; - - uint8_t ps_btn : 1; - uint8_t tp_btn : 1; -// uint8_t l2_btn_alt : 1; - -// uint8_t r2_btn_alt : 1; - uint8_t : 2; - - // digital direction, use the dir_* constants(enum) + // digital direction, use the dir_* constants(enum) as a hat // 8 = center, 0 = up, 1 = up/right, 2 = right, 3 = right/down // 4 = down, 5 = down/left, 6 = left, 7 = left/up + uint8_t direction : 4; + // four bits would fill this out... + uint8_t dummy : 4; - uint8_t direction; - - // left and right analog sticks, 0x00 left/up, 0x80 middle, 0xff right/down - + // analogs --- left stick x/y, right stick x/y uint8_t l_x_axis; uint8_t l_y_axis; uint8_t r_x_axis; uint8_t r_y_axis; - - // button analog values for the d-pad. - uint8_t right_axis; - uint8_t left_axis; - uint8_t up_axis; - uint8_t down_axis; - - // button axis, 0x00 = unpressed, 0xff = fully pressed - - uint8_t triangle_axis; - uint8_t circle_axis; - uint8_t cross_axis; - uint8_t square_axis; - - uint8_t l1_axis; - uint8_t r1_axis; - uint8_t l2_axis; - uint8_t r2_axis; } HIDReport; static const uint8_t hid_string_language[] = { 0x09, 0x04 }; static const uint8_t hid_string_manufacturer[] = "Open Stick Community"; -static const uint8_t hid_string_product[] = "GP2040-CE (D-Input)"; +static const uint8_t hid_string_product[] = "GP2040-CE (Generic)"; static const uint8_t hid_string_version[] = "1.0"; static const uint8_t *hid_string_descriptors[] __attribute__((unused)) = @@ -136,20 +79,20 @@ static const uint8_t *hid_string_descriptors[] __attribute__((unused)) = static const uint8_t hid_device_descriptor[] = { - 18, // bLength - 1, // bDescriptorType - 0x00, 0x02, // bcdUSB - 0, // bDeviceClass - 0, // bDeviceSubClass - 0, // bDeviceProtocol - ENDPOINT0_SIZE, // bMaxPacketSize0 - LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor - LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct - 0x00, 0x01, // bcdDevice - 1, // iManufacturer - 2, // iProduct - 0, // iSerialNumber - 1 // bNumConfigurations + 18, // bLength + 1, // bDescriptorType + 0x00, 0x02, // bcdUSB + 0, // bDeviceClass + 0, // bDeviceSubClass + 0, // bDeviceProtocol + HID_ENDPOINT_SIZE, // bMaxPacketSize0 + LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor + LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct + 0x00, 0x01, // bcdDevice + 1, // iManufacturer + 2, // iProduct + 0, // iSerialNumber + 1 // bNumConfigurations }; static const uint8_t hid_report_descriptor[] = @@ -157,29 +100,28 @@ static const uint8_t hid_report_descriptor[] = 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x05, // USAGE (Gamepad) 0xa1, 0x01, // COLLECTION (Application) + // 32 buttons + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x20, // USAGE_MAXIMUM (Button 32) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 0x35, 0x00, // PHYSICAL_MINIMUM (0) - 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x95, 0x20, // REPORT_COUNT (32) 0x75, 0x01, // REPORT_SIZE (1) - 0x95, 0x0e, // REPORT_COUNT (13) - 0x05, 0x09, // USAGE_PAGE (Button) - 0x19, 0x01, // USAGE_MINIMUM (Button 1) - 0x29, 0x0e, // USAGE_MAXIMUM (Button 13) 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x95, 0x02, // REPORT_COUNT (3) - 0x81, 0x01, // INPUT (Cnst,Ary,Abs) + // hat (dpad) 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x39, // USAGE (Hat switch) 0x25, 0x07, // LOGICAL_MAXIMUM (7) - 0x46, 0x3b, 0x01, // PHYSICAL_MAXIMUM (315) - 0x75, 0x04, // REPORT_SIZE (4) 0x95, 0x01, // REPORT_COUNT (1) - 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) - 0x09, 0x39, // USAGE (Hat switch) + 0x75, 0x04, // REPORT_SIZE (4) 0x81, 0x42, // INPUT (Data,Var,Abs,Null) - 0x65, 0x00, // UNIT (None) + // padding the hat 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x04, // REPORT_SIZE (4) 0x81, 0x01, // INPUT (Cnst,Ary,Abs) + // analogs + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255) 0x09, 0x30, // USAGE (X) @@ -187,77 +129,49 @@ static const uint8_t hid_report_descriptor[] = 0x09, 0x32, // USAGE (Z) 0x09, 0x35, // USAGE (Rz) 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x04, // REPORT_COUNT (6) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Specific) - 0x09, 0x20, // Unknown - 0x09, 0x21, // Unknown - 0x09, 0x22, // Unknown - 0x09, 0x23, // Unknown - 0x09, 0x24, // Unknown - 0x09, 0x25, // Unknown - 0x09, 0x26, // Unknown - 0x09, 0x27, // Unknown - 0x09, 0x28, // Unknown - 0x09, 0x29, // Unknown - 0x09, 0x2a, // Unknown - 0x09, 0x2b, // Unknown - 0x95, 0x0c, // REPORT_COUNT (12) + 0x95, 0x04, // REPORT_COUNT (4) 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x0a, 0x21, 0x26, // Unknown - 0x95, 0x08, // REPORT_COUNT (8) - 0xb1, 0x02, // FEATURE (Data,Var,Abs) + // done 0xc0 // END_COLLECTION }; -static const uint8_t hid_hid_descriptor[] = -{ - 0x09, // bLength - 0x21, // bDescriptorType (HID) - 0x11, 0x01, // bcdHID 1.11 - 0x00, // bCountryCode - 0x01, // bNumDescriptors - 0x22, // bDescriptorType[0] (HID) - sizeof(hid_report_descriptor), 0x00, // wDescriptorLength[0] 90 -}; - #define CONFIG1_DESC_SIZE (9+9+9+7) static const uint8_t hid_configuration_descriptor[] = { - // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 + // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 9, // bLength; 2, // bDescriptorType; - LSB(CONFIG1_DESC_SIZE), // wTotalLength + LSB(CONFIG1_DESC_SIZE), // wTotalLength MSB(CONFIG1_DESC_SIZE), - 1, // bNumInterfaces - 1, // bConfigurationValue - 0, // iConfiguration - 0x80, // bmAttributes - 50, // bMaxPower - // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 - 9, // bLength - 4, // bDescriptorType - GAMEPAD_INTERFACE, // bInterfaceNumber - 0, // bAlternateSetting - 1, // bNumEndpoints - 0x03, // bInterfaceClass (0x03 = HID) - 0x00, // bInterfaceSubClass (0x00 = No Boot) - 0x00, // bInterfaceProtocol (0x00 = No Protocol) - 0, // iInterface - // HID interface descriptor, HID 1.11 spec, section 6.2.1 - 9, // bLength - 0x21, // bDescriptorType - 0x11, 0x01, // bcdHID - 0, // bCountryCode - 1, // bNumDescriptors - 0x22, // bDescriptorType - sizeof(hid_report_descriptor), // wDescriptorLength + 1, // bNumInterfaces + 1, // bConfigurationValue + 0, // iConfiguration + 0x80, // bmAttributes + 50, // bMaxPower + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + GAMEPAD_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + 0x03, // bInterfaceClass (0x03 = HID) + 0x00, // bInterfaceSubClass (0x00 = No Boot) + 0x00, // bInterfaceProtocol (0x00 = No Protocol) + 0, // iInterface + // HID interface descriptor, HID 1.11 spec, section 6.2.1 + 9, // bLength + 0x21, // bDescriptorType + 0x11, 0x01, // bcdHID + 0, // bCountryCode + 1, // bNumDescriptors + 0x22, // bDescriptorType + sizeof(hid_report_descriptor), // wDescriptorLength 0, - // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 - 7, // bLength + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength 5, // bDescriptorType - GAMEPAD_ENDPOINT | 0x80, // bEndpointAddress - 0x03, // bmAttributes (0x03=intr) - GAMEPAD_SIZE, 0, // wMaxPacketSize + GAMEPAD_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + GAMEPAD_SIZE, 0, // wMaxPacketSize 1 // bInterval (1 ms) }; diff --git a/headers/drivers/ps3/PS3Descriptors.h b/headers/drivers/ps3/PS3Descriptors.h new file mode 100644 index 000000000..6d7ae2fa0 --- /dev/null +++ b/headers/drivers/ps3/PS3Descriptors.h @@ -0,0 +1,263 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com) + */ + +#pragma once + +#include + +#define PS3_ENDPOINT_SIZE 64 + +// Mac OS-X and Linux automatically load the correct drivers. On +// Windows, even though the driver is supplied by Microsoft, an +// INF file is needed to load the driver. These numbers need to +// match the INF file. +#define VENDOR_ID 0x10C4 +#define PRODUCT_ID 0x82C0 + +/************************************************************************** + * + * Endpoint Buffer Configuration + * + **************************************************************************/ + +#define ENDPOINT0_SIZE 64 + +#define GAMEPAD_INTERFACE 0 +#define GAMEPAD_ENDPOINT 1 +#define GAMEPAD_SIZE 64 + +#define LSB(n) (n & 255) +#define MSB(n) ((n >> 8) & 255) + +// HAT report (4 bits) +#define PS3_HAT_UP 0x00 +#define PS3_HAT_UPRIGHT 0x01 +#define PS3_HAT_RIGHT 0x02 +#define PS3_HAT_DOWNRIGHT 0x03 +#define PS3_HAT_DOWN 0x04 +#define PS3_HAT_DOWNLEFT 0x05 +#define PS3_HAT_LEFT 0x06 +#define PS3_HAT_UPLEFT 0x07 +#define PS3_HAT_NOTHING 0x08 + +// Button report (16 bits) +#define PS3_MASK_SQUARE (1U << 0) +#define PS3_MASK_CROSS (1U << 1) +#define PS3_MASK_CIRCLE (1U << 2) +#define PS3_MASK_TRIANGLE (1U << 3) +#define PS3_MASK_L1 (1U << 4) +#define PS3_MASK_R1 (1U << 5) +#define PS3_MASK_L2 (1U << 6) +#define PS3_MASK_R2 (1U << 7) +#define PS3_MASK_SELECT (1U << 8) +#define PS3_MASK_START (1U << 9) +#define PS3_MASK_L3 (1U << 10) +#define PS3_MASK_R3 (1U << 11) +#define PS3_MASK_PS (1U << 12) +#define PS3_MASK_TP (1U << 13) + +// HID analog sticks only report 8 bits +#define PS3_JOYSTICK_MIN 0x00 +#define PS3_JOYSTICK_MID 0x80 +#define PS3_JOYSTICK_MAX 0xFF + +typedef struct __attribute((packed, aligned(1))) +{ + // digital buttons, 0 = off, 1 = on + + uint8_t square_btn : 1; + uint8_t cross_btn : 1; + uint8_t circle_btn : 1; + uint8_t triangle_btn : 1; + + uint8_t l1_btn : 1; + uint8_t r1_btn : 1; + uint8_t l2_btn : 1; + uint8_t r2_btn : 1; + + uint8_t select_btn : 1; + uint8_t start_btn : 1; + uint8_t l3_btn : 1; + uint8_t r3_btn : 1; + + uint8_t ps_btn : 1; + uint8_t tp_btn : 1; +// uint8_t l2_btn_alt : 1; + +// uint8_t r2_btn_alt : 1; + uint8_t : 2; + + // digital direction, use the dir_* constants(enum) + // 8 = center, 0 = up, 1 = up/right, 2 = right, 3 = right/down + // 4 = down, 5 = down/left, 6 = left, 7 = left/up + + uint8_t direction; + + // left and right analog sticks, 0x00 left/up, 0x80 middle, 0xff right/down + + uint8_t l_x_axis; + uint8_t l_y_axis; + uint8_t r_x_axis; + uint8_t r_y_axis; + + // button analog values for the d-pad. + uint8_t right_axis; + uint8_t left_axis; + uint8_t up_axis; + uint8_t down_axis; + + // button axis, 0x00 = unpressed, 0xff = fully pressed + + uint8_t triangle_axis; + uint8_t circle_axis; + uint8_t cross_axis; + uint8_t square_axis; + + uint8_t l1_axis; + uint8_t r1_axis; + uint8_t l2_axis; + uint8_t r2_axis; +} PS3Report; + +static const uint8_t ps3_string_language[] = { 0x09, 0x04 }; +static const uint8_t ps3_string_manufacturer[] = "Open Stick Community"; +static const uint8_t ps3_string_product[] = "GP2040-CE (PS3)"; +static const uint8_t ps3_string_version[] = "1.0"; + +static const uint8_t *ps3_string_descriptors[] __attribute__((unused)) = +{ + ps3_string_language, + ps3_string_manufacturer, + ps3_string_product, + ps3_string_version +}; + +static const uint8_t ps3_device_descriptor[] = +{ + 18, // bLength + 1, // bDescriptorType + 0x00, 0x02, // bcdUSB + 0, // bDeviceClass + 0, // bDeviceSubClass + 0, // bDeviceProtocol + ENDPOINT0_SIZE, // bMaxPacketSize0 + LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor + LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct + 0x00, 0x01, // bcdDevice + 1, // iManufacturer + 2, // iProduct + 0, // iSerialNumber + 1 // bNumConfigurations +}; + +static const uint8_t ps3_report_descriptor[] = +{ + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x05, // USAGE (Gamepad) + 0xa1, 0x01, // COLLECTION (Application) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x0e, // REPORT_COUNT (13) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x0e, // USAGE_MAXIMUM (Button 13) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x02, // REPORT_COUNT (3) + 0x81, 0x01, // INPUT (Cnst,Ary,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x25, 0x07, // LOGICAL_MAXIMUM (7) + 0x46, 0x3b, 0x01, // PHYSICAL_MAXIMUM (315) + 0x75, 0x04, // REPORT_SIZE (4) + 0x95, 0x01, // REPORT_COUNT (1) + 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) + 0x09, 0x39, // USAGE (Hat switch) + 0x81, 0x42, // INPUT (Data,Var,Abs,Null) + 0x65, 0x00, // UNIT (None) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x01, // INPUT (Cnst,Ary,Abs) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x09, 0x32, // USAGE (Z) + 0x09, 0x35, // USAGE (Rz) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x04, // REPORT_COUNT (6) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Specific) + 0x09, 0x20, // Unknown + 0x09, 0x21, // Unknown + 0x09, 0x22, // Unknown + 0x09, 0x23, // Unknown + 0x09, 0x24, // Unknown + 0x09, 0x25, // Unknown + 0x09, 0x26, // Unknown + 0x09, 0x27, // Unknown + 0x09, 0x28, // Unknown + 0x09, 0x29, // Unknown + 0x09, 0x2a, // Unknown + 0x09, 0x2b, // Unknown + 0x95, 0x0c, // REPORT_COUNT (12) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x0a, 0x21, 0x26, // Unknown + 0x95, 0x08, // REPORT_COUNT (8) + 0xb1, 0x02, // FEATURE (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; + +static const uint8_t ps3_hid_descriptor[] = +{ + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x11, 0x01, // bcdHID 1.11 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + sizeof(ps3_report_descriptor), 0x00, // wDescriptorLength[0] 90 +}; + +#define CONFIG1_DESC_SIZE (9+9+9+7) +static const uint8_t ps3_configuration_descriptor[] = +{ + // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 + 9, // bLength; + 2, // bDescriptorType; + LSB(CONFIG1_DESC_SIZE), // wTotalLength + MSB(CONFIG1_DESC_SIZE), + 1, // bNumInterfaces + 1, // bConfigurationValue + 0, // iConfiguration + 0x80, // bmAttributes + 50, // bMaxPower + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + GAMEPAD_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + 0x03, // bInterfaceClass (0x03 = HID) + 0x00, // bInterfaceSubClass (0x00 = No Boot) + 0x00, // bInterfaceProtocol (0x00 = No Protocol) + 0, // iInterface + // HID interface descriptor, HID 1.11 spec, section 6.2.1 + 9, // bLength + 0x21, // bDescriptorType + 0x11, 0x01, // bcdHID + 0, // bCountryCode + 1, // bNumDescriptors + 0x22, // bDescriptorType + sizeof(ps3_report_descriptor), // wDescriptorLength + 0, + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + GAMEPAD_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + GAMEPAD_SIZE, 0, // wMaxPacketSize + 1 // bInterval (1 ms) +}; diff --git a/headers/drivers/ps3/PS3Driver.h b/headers/drivers/ps3/PS3Driver.h new file mode 100644 index 000000000..9c32deeee --- /dev/null +++ b/headers/drivers/ps3/PS3Driver.h @@ -0,0 +1,33 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#ifndef _PS3_DRIVER_H_ +#define _PS3_DRIVER_H_ + +#include "gpdriver.h" +#include "drivers/ps3/PS3Descriptors.h" + +class PS3Driver : public GPDriver { +public: + virtual void initialize(); + virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual void initializeAux() {} + virtual void processAux() {} + virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); + virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize); + virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); + virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid); + virtual const uint8_t * get_descriptor_device_cb(); + virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ; + virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index); + virtual const uint8_t * get_descriptor_device_qualifier_cb(); + virtual uint16_t GetJoystickMidValue(); + virtual USBListener * get_usb_auth_listener() { return nullptr; } +private: + uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; + PS3Report ps3Report; +}; + +#endif // _PS3_DRIVER_H_ diff --git a/headers/gamepad.h b/headers/gamepad.h index 4d86ebf65..4a37346c1 100644 --- a/headers/gamepad.h +++ b/headers/gamepad.h @@ -16,8 +16,6 @@ extern uint32_t getMillis(); extern uint64_t getMicro(); -#define GAMEPAD_FEATURE_REPORT_SIZE 32 - struct GamepadButtonMapping { GamepadButtonMapping(Mask_t bm) : @@ -26,11 +24,9 @@ struct GamepadButtonMapping {} uint32_t pinMask; - const uint16_t buttonMask; + const uint32_t buttonMask; }; -#define GAMEPAD_DIGITAL_INPUT_COUNT 18 // Total number of buttons, including D-pad - class Gamepad { public: Gamepad(); @@ -62,7 +58,7 @@ class Gamepad { /** * @brief Check for a button press. Used by `pressed[Button]` helper methods. */ - inline bool __attribute__((always_inline)) pressedButton(const uint16_t mask) { + inline bool __attribute__((always_inline)) pressedButton(const uint32_t mask) { return (state.buttons & mask) == mask; } @@ -117,6 +113,18 @@ class Gamepad { inline bool __attribute__((always_inline)) pressedA2() { return pressedButton(GAMEPAD_MASK_A2); } inline bool __attribute__((always_inline)) pressedA3() { return pressedButton(GAMEPAD_MASK_A3); } inline bool __attribute__((always_inline)) pressedA4() { return pressedButton(GAMEPAD_MASK_A4); } + inline bool __attribute__((always_inline)) pressedE1() { return pressedButton(GAMEPAD_MASK_E1); } + inline bool __attribute__((always_inline)) pressedE2() { return pressedButton(GAMEPAD_MASK_E2); } + inline bool __attribute__((always_inline)) pressedE3() { return pressedButton(GAMEPAD_MASK_E3); } + inline bool __attribute__((always_inline)) pressedE4() { return pressedButton(GAMEPAD_MASK_E4); } + inline bool __attribute__((always_inline)) pressedE5() { return pressedButton(GAMEPAD_MASK_E5); } + inline bool __attribute__((always_inline)) pressedE6() { return pressedButton(GAMEPAD_MASK_E6); } + inline bool __attribute__((always_inline)) pressedE7() { return pressedButton(GAMEPAD_MASK_E7); } + inline bool __attribute__((always_inline)) pressedE8() { return pressedButton(GAMEPAD_MASK_E8); } + inline bool __attribute__((always_inline)) pressedE9() { return pressedButton(GAMEPAD_MASK_E9); } + inline bool __attribute__((always_inline)) pressedE10() { return pressedButton(GAMEPAD_MASK_E10); } + inline bool __attribute__((always_inline)) pressedE11() { return pressedButton(GAMEPAD_MASK_E11); } + inline bool __attribute__((always_inline)) pressedE12() { return pressedButton(GAMEPAD_MASK_E12); } const GamepadOptions& getOptions() const { return options; } @@ -147,6 +155,18 @@ class Gamepad { GamepadButtonMapping *mapButtonA2; GamepadButtonMapping *mapButtonA3; GamepadButtonMapping *mapButtonA4; + GamepadButtonMapping *mapButtonE1; + GamepadButtonMapping *mapButtonE2; + GamepadButtonMapping *mapButtonE3; + GamepadButtonMapping *mapButtonE4; + GamepadButtonMapping *mapButtonE5; + GamepadButtonMapping *mapButtonE6; + GamepadButtonMapping *mapButtonE7; + GamepadButtonMapping *mapButtonE8; + GamepadButtonMapping *mapButtonE9; + GamepadButtonMapping *mapButtonE10; + GamepadButtonMapping *mapButtonE11; + GamepadButtonMapping *mapButtonE12; GamepadButtonMapping *mapButtonFn; // gamepad specific proxy of debounced buttons --- 1 = active (inverse of the raw GPIO) @@ -158,7 +178,8 @@ class Gamepad { // These are special to SOCD inline static const SOCDMode resolveSOCDMode(const GamepadOptions& options) { return (options.socdMode == SOCD_MODE_BYPASS && - (options.inputMode == INPUT_MODE_HID || + (options.inputMode == INPUT_MODE_PS3 || + options.inputMode == INPUT_MODE_GENERIC || options.inputMode == INPUT_MODE_SWITCH || options.inputMode == INPUT_MODE_NEOGEO || options.inputMode == INPUT_MODE_PS4)) ? diff --git a/headers/gamepad/GamepadState.h b/headers/gamepad/GamepadState.h index 7d4b6bffe..b3249edfa 100644 --- a/headers/gamepad/GamepadState.h +++ b/headers/gamepad/GamepadState.h @@ -12,8 +12,6 @@ using namespace std; #include "enums.pb.h" -#define GAMEPAD_BUTTON_COUNT 14 - /* Gamepad button mapping table: @@ -66,12 +64,21 @@ using namespace std; #define GAMEPAD_MASK_DL (1UL << 18) #define GAMEPAD_MASK_DR (1UL << 19) -// For detecting analog sticks as buttons - -#define GAMEPAD_MASK_LX (1UL << 20) -#define GAMEPAD_MASK_LY (1UL << 21) -#define GAMEPAD_MASK_RX (1UL << 22) -#define GAMEPAD_MASK_RY (1UL << 23) +// extra buttons (no particular host expectation for these, unlike 0..13 above +// which have predetermined functions for consoles or whatever) + +#define GAMEPAD_MASK_E1 (1UL << 20) +#define GAMEPAD_MASK_E2 (1UL << 21) +#define GAMEPAD_MASK_E3 (1UL << 22) +#define GAMEPAD_MASK_E4 (1UL << 23) +#define GAMEPAD_MASK_E5 (1UL << 24) +#define GAMEPAD_MASK_E6 (1UL << 25) +#define GAMEPAD_MASK_E7 (1UL << 26) +#define GAMEPAD_MASK_E8 (1UL << 27) +#define GAMEPAD_MASK_E9 (1UL << 28) +#define GAMEPAD_MASK_E10 (1UL << 29) +#define GAMEPAD_MASK_E11 (1UL << 30) +#define GAMEPAD_MASK_E12 (1UL << 31) #define GAMEPAD_MASK_DPAD (GAMEPAD_MASK_UP | GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT | GAMEPAD_MASK_RIGHT) @@ -96,7 +103,7 @@ const uint8_t dpadMasks[] = GAMEPAD_MASK_RIGHT, }; -const uint16_t buttonMasks[] = +const uint32_t buttonMasks[] = { GAMEPAD_MASK_B1, GAMEPAD_MASK_B2, @@ -112,12 +119,24 @@ const uint16_t buttonMasks[] = GAMEPAD_MASK_R3, GAMEPAD_MASK_A1, GAMEPAD_MASK_A2, + GAMEPAD_MASK_E1, + GAMEPAD_MASK_E2, + GAMEPAD_MASK_E3, + GAMEPAD_MASK_E4, + GAMEPAD_MASK_E5, + GAMEPAD_MASK_E6, + GAMEPAD_MASK_E7, + GAMEPAD_MASK_E8, + GAMEPAD_MASK_E9, + GAMEPAD_MASK_E10, + GAMEPAD_MASK_E11, + GAMEPAD_MASK_E12, }; struct GamepadState { uint8_t dpad {0}; - uint16_t buttons {0}; + uint32_t buttons {0}; uint16_t aux {0}; uint16_t lx {GAMEPAD_JOYSTICK_MID}; uint16_t ly {GAMEPAD_JOYSTICK_MID}; diff --git a/headers/gp2040.h b/headers/gp2040.h index 8945f8949..5519267c2 100644 --- a/headers/gp2040.h +++ b/headers/gp2040.h @@ -46,10 +46,11 @@ class GP2040 { NONE, ENTER_WEBCONFIG_MODE, ENTER_USB_MODE, - SET_INPUT_MODE_HID, SET_INPUT_MODE_SWITCH, SET_INPUT_MODE_XINPUT, SET_INPUT_MODE_KEYBOARD, + SET_INPUT_MODE_GENERIC, + SET_INPUT_MODE_PS3, SET_INPUT_MODE_PS4, SET_INPUT_MODE_PS5, SET_INPUT_MODE_XBONE, diff --git a/proto/enums.proto b/proto/enums.proto index f2bf0a20e..868ee532d 100644 --- a/proto/enums.proto +++ b/proto/enums.proto @@ -122,7 +122,7 @@ enum InputMode INPUT_MODE_XINPUT = 0; INPUT_MODE_SWITCH = 1; - INPUT_MODE_HID = 2; + INPUT_MODE_PS3 = 2; INPUT_MODE_KEYBOARD = 3; INPUT_MODE_PS4 = 4; INPUT_MODE_XBONE = 5; @@ -134,6 +134,7 @@ enum InputMode INPUT_MODE_PSCLASSIC = 11; INPUT_MODE_XBOXORIGINAL = 12; INPUT_MODE_PS5 = 13; + INPUT_MODE_GENERIC = 14; INPUT_MODE_CONFIG = 255; } @@ -228,6 +229,18 @@ enum GpioAction CUSTOM_BUTTON_COMBO = 40; BUTTON_PRESS_A3 = 41; BUTTON_PRESS_A4 = 42; + BUTTON_PRESS_E1 = 43; + BUTTON_PRESS_E2 = 44; + BUTTON_PRESS_E3 = 45; + BUTTON_PRESS_E4 = 46; + BUTTON_PRESS_E5 = 47; + BUTTON_PRESS_E6 = 48; + BUTTON_PRESS_E7 = 49; + BUTTON_PRESS_E8 = 50; + BUTTON_PRESS_E9 = 51; + BUTTON_PRESS_E10 = 52; + BUTTON_PRESS_E11 = 53; + BUTTON_PRESS_E12 = 54; } enum GpioDirection diff --git a/src/config_legacy.cpp b/src/config_legacy.cpp index 9d69c8842..c19db6f86 100644 --- a/src/config_legacy.cpp +++ b/src/config_legacy.cpp @@ -32,7 +32,7 @@ namespace ConfigLegacy { INPUT_MODE_XINPUT, INPUT_MODE_SWITCH, - INPUT_MODE_HID, + INPUT_MODE_PS3, INPUT_MODE_KEYBOARD, INPUT_MODE_PS4, INPUT_MODE_CONFIG = 255, @@ -483,7 +483,7 @@ static bool isValidInputMode(ConfigLegacy::InputMode inputMode) { case INPUT_MODE_XINPUT: case INPUT_MODE_SWITCH: - case INPUT_MODE_HID: + case INPUT_MODE_PS3: case INPUT_MODE_KEYBOARD: case INPUT_MODE_PS4: return true; diff --git a/src/config_utils.cpp b/src/config_utils.cpp index 4ebbbf8e7..bca144e41 100644 --- a/src/config_utils.cpp +++ b/src/config_utils.cpp @@ -86,7 +86,7 @@ #define DEFAULT_INPUT_MODE_B2 INPUT_MODE_XINPUT #endif #ifndef DEFAULT_INPUT_MODE_B3 - #define DEFAULT_INPUT_MODE_B3 INPUT_MODE_HID + #define DEFAULT_INPUT_MODE_B3 INPUT_MODE_PS3 #endif #ifndef DEFAULT_INPUT_MODE_B4 #define DEFAULT_INPUT_MODE_B4 INPUT_MODE_PS4 diff --git a/src/display/ui/screens/ButtonLayoutScreen.cpp b/src/display/ui/screens/ButtonLayoutScreen.cpp index c4b8ca01f..3e716cf3e 100644 --- a/src/display/ui/screens/ButtonLayoutScreen.cpp +++ b/src/display/ui/screens/ButtonLayoutScreen.cpp @@ -129,7 +129,8 @@ void ButtonLayoutScreen::generateHeader() { // Display standard header switch (inputMode) { - case INPUT_MODE_HID: statusBar += "DINPUT"; break; + case INPUT_MODE_PS3: statusBar += "PS3"; break; + case INPUT_MODE_GENERIC: statusBar += "USBHID"; break; case INPUT_MODE_SWITCH: statusBar += "SWITCH"; break; case INPUT_MODE_XINPUT: statusBar += "XINPUT"; break; case INPUT_MODE_MDMINI: statusBar += "GEN/MD"; break; diff --git a/src/drivermanager.cpp b/src/drivermanager.cpp index f03bbd0e0..fd764c155 100644 --- a/src/drivermanager.cpp +++ b/src/drivermanager.cpp @@ -9,6 +9,7 @@ #include "drivers/neogeo/NeoGeoDriver.h" #include "drivers/pcengine/PCEngineDriver.h" #include "drivers/psclassic/PSClassicDriver.h" +#include "drivers/ps3/PS3Driver.h" #include "drivers/ps4/PS4Driver.h" #include "drivers/switch/SwitchDriver.h" #include "drivers/xbone/XBOneDriver.h" @@ -28,12 +29,12 @@ void DriverManager::setup(InputMode mode) { case INPUT_MODE_EGRET: driver = new EgretDriver(); break; - case INPUT_MODE_HID: - driver = new HIDDriver(); - break; case INPUT_MODE_KEYBOARD: driver = new KeyboardDriver(); break; + case INPUT_MODE_GENERIC: + driver = new HIDDriver(); + break; case INPUT_MODE_MDMINI: driver = new MDMiniDriver(); break; @@ -46,6 +47,9 @@ void DriverManager::setup(InputMode mode) { case INPUT_MODE_PCEMINI: driver = new PCEngineDriver(); break; + case INPUT_MODE_PS3: + driver = new PS3Driver(); + break; case INPUT_MODE_PS4: driver = new PS4Driver(PS4_CONTROLLER); break; diff --git a/src/drivers/hid/HIDDriver.cpp b/src/drivers/hid/HIDDriver.cpp index 0633f2b2b..1f666c60f 100644 --- a/src/drivers/hid/HIDDriver.cpp +++ b/src/drivers/hid/HIDDriver.cpp @@ -7,33 +7,17 @@ #include "drivers/hid/HIDDescriptors.h" #include "drivers/shared/driverhelper.h" -// Magic byte sequence to enable PS button on PS3 -static const uint8_t ps3_magic_init_bytes[8] = {0x21, 0x26, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00}; - static bool hid_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) { - if ( request->bmRequestType == 0xA1 && - request->bRequest == HID_REQ_CONTROL_GET_REPORT && - request->wValue == 0x0300 ) { - return tud_control_xfer(rhport, request, (void *) ps3_magic_init_bytes, sizeof(ps3_magic_init_bytes)); - } else { - return hidd_control_xfer_cb(rhport, stage, request); - } + return hidd_control_xfer_cb(rhport, stage, request); } void HIDDriver::initialize() { hidReport = { - .square_btn = 0, .cross_btn = 0, .circle_btn = 0, .triangle_btn = 0, - .l1_btn = 0, .r1_btn = 0, .l2_btn = 0, .r2_btn = 0, - .select_btn = 0, .start_btn = 0, .l3_btn = 0, .r3_btn = 0, .ps_btn = 0, .tp_btn = 0, - .direction = 0x08, - .l_x_axis = HID_JOYSTICK_MID, - .l_y_axis = HID_JOYSTICK_MID, - .r_x_axis = HID_JOYSTICK_MID, - .r_y_axis = HID_JOYSTICK_MID, - .right_axis = 0x00, .left_axis = 0x00, .up_axis = 0x00, .down_axis = 0x00, - .triangle_axis = 0x00, .circle_axis = 0x00, .cross_axis = 0x00, .square_axis = 0x00, - .l1_axis = 0x00, .r1_axis = 0x00, .l2_axis = 0x00, .r2_axis = 0x00 + .buttons = 0, + .direction = HID_HAT_NOTHING, + .l_x_axis = HID_JOYSTICK_MID, .l_y_axis = HID_JOYSTICK_MID, + .r_x_axis = HID_JOYSTICK_MID, .r_y_axis = HID_JOYSTICK_MID, }; class_driver = { @@ -64,45 +48,48 @@ void HIDDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { default: hidReport.direction = HID_HAT_NOTHING; break; } - hidReport.cross_btn = gamepad->pressedB1(); - hidReport.circle_btn = gamepad->pressedB2(); - hidReport.square_btn = gamepad->pressedB3(); - hidReport.triangle_btn = gamepad->pressedB4(); - hidReport.l1_btn = gamepad->pressedL1(); - hidReport.r1_btn = gamepad->pressedR1(); - hidReport.l2_btn = gamepad->pressedL2(); - hidReport.r2_btn = gamepad->pressedR2(); - hidReport.select_btn = gamepad->pressedS1(); - hidReport.start_btn = gamepad->pressedS2(); - hidReport.l3_btn = gamepad->pressedL3(); - hidReport.r3_btn = gamepad->pressedR3(); - hidReport.ps_btn = gamepad->pressedA1(); - hidReport.tp_btn = gamepad->pressedA2(); - hidReport.l_x_axis = static_cast(gamepad->state.lx >> 8); hidReport.l_y_axis = static_cast(gamepad->state.ly >> 8); hidReport.r_x_axis = static_cast(gamepad->state.rx >> 8); hidReport.r_y_axis = static_cast(gamepad->state.ry >> 8); - if (gamepad->hasAnalogTriggers) - { - hidReport.l2_axis = gamepad->state.lt; - hidReport.r2_axis = gamepad->state.rt; - } else { - hidReport.l2_axis = gamepad->pressedL2() ? 0xFF : 0; - hidReport.r2_axis = gamepad->pressedR2() ? 0xFF : 0; - } - - hidReport.triangle_axis = gamepad->pressedB4() ? 0xFF : 0; - hidReport.circle_axis = gamepad->pressedB2() ? 0xFF : 0; - hidReport.cross_axis = gamepad->pressedB1() ? 0xFF : 0; - hidReport.square_axis = gamepad->pressedB3() ? 0xFF : 0; - hidReport.l1_axis = gamepad->pressedL1() ? 0xFF : 0; - hidReport.r1_axis = gamepad->pressedR1() ? 0xFF : 0; - hidReport.right_axis = gamepad->state.dpad & GAMEPAD_MASK_RIGHT ? 0xFF : 0; - hidReport.left_axis = gamepad->state.dpad & GAMEPAD_MASK_LEFT ? 0xFF : 0; - hidReport.up_axis = gamepad->state.dpad & GAMEPAD_MASK_UP ? 0xFF : 0; - hidReport.down_axis = gamepad->state.dpad & GAMEPAD_MASK_DOWN ? 0xFF : 0; + // these first three buttons are in this unintuitive order to be compatible with + // expectations, e.g. both PS3/4/5 modes and Switch modes map to HID as + // B3 B4 == 1 4 + // B1 B2 == 2 3 + hidReport.buttons = 0 + | (gamepad->pressedB1() ? GAMEPAD_MASK_B2 : 0) + | (gamepad->pressedB2() ? GAMEPAD_MASK_B3 : 0) + | (gamepad->pressedB3() ? GAMEPAD_MASK_B1 : 0) + | (gamepad->pressedB4() ? GAMEPAD_MASK_B4 : 0) + | (gamepad->pressedL1() ? GAMEPAD_MASK_L1 : 0) + | (gamepad->pressedR1() ? GAMEPAD_MASK_R1 : 0) + | (gamepad->pressedL2() ? GAMEPAD_MASK_L2 : 0) + | (gamepad->pressedR2() ? GAMEPAD_MASK_R2 : 0) + | (gamepad->pressedS1() ? GAMEPAD_MASK_S1 : 0) + | (gamepad->pressedS2() ? GAMEPAD_MASK_S2 : 0) + | (gamepad->pressedL3() ? GAMEPAD_MASK_L3 : 0) + | (gamepad->pressedR3() ? GAMEPAD_MASK_R3 : 0) + | (gamepad->pressedA1() ? GAMEPAD_MASK_A1 : 0) + | (gamepad->pressedA2() ? GAMEPAD_MASK_A2 : 0) + // buttons 15 and 16 are reserved for future expansion + | (gamepad->pressedUp() ? GAMEPAD_MASK_DU : 0) + | (gamepad->pressedDown() ? GAMEPAD_MASK_DD : 0) + | (gamepad->pressedLeft() ? GAMEPAD_MASK_DL : 0) + | (gamepad->pressedRight() ? GAMEPAD_MASK_DR : 0) + | (gamepad->pressedE1() ? GAMEPAD_MASK_E1 : 0) + | (gamepad->pressedE2() ? GAMEPAD_MASK_E2 : 0) + | (gamepad->pressedE3() ? GAMEPAD_MASK_E3 : 0) + | (gamepad->pressedE4() ? GAMEPAD_MASK_E4 : 0) + | (gamepad->pressedE5() ? GAMEPAD_MASK_E5 : 0) + | (gamepad->pressedE6() ? GAMEPAD_MASK_E6 : 0) + | (gamepad->pressedE7() ? GAMEPAD_MASK_E7 : 0) + | (gamepad->pressedE8() ? GAMEPAD_MASK_E8 : 0) + | (gamepad->pressedE9() ? GAMEPAD_MASK_E9 : 0) + | (gamepad->pressedE10() ? GAMEPAD_MASK_E10 : 0) + | (gamepad->pressedE11() ? GAMEPAD_MASK_E11 : 0) + | (gamepad->pressedE12() ? GAMEPAD_MASK_E12 : 0) + ; // Wake up TinyUSB device if (tud_suspended()) @@ -121,7 +108,7 @@ void HIDDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { // tud_hid_get_report_cb uint16_t HIDDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { - memcpy(buffer, &hidReport, sizeof(HIDReport)); + memcpy(buffer, &hidReport, sizeof(HIDReport)); return sizeof(HIDReport); } @@ -130,7 +117,7 @@ void HIDDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uin // Only XboxOG and Xbox One use vendor control xfer cb bool HIDDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { - return false; + return false; } const uint16_t * HIDDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { @@ -139,15 +126,15 @@ const uint16_t * HIDDriver::get_descriptor_string_cb(uint8_t index, uint16_t lan } const uint8_t * HIDDriver::get_descriptor_device_cb() { - return hid_device_descriptor; + return hid_device_descriptor; } const uint8_t * HIDDriver::get_hid_descriptor_report_cb(uint8_t itf) { - return hid_report_descriptor; + return hid_report_descriptor; } const uint8_t * HIDDriver::get_descriptor_configuration_cb(uint8_t index) { - return hid_configuration_descriptor; + return hid_configuration_descriptor; } const uint8_t * HIDDriver::get_descriptor_device_qualifier_cb() { diff --git a/src/drivers/ps3/PS3Driver.cpp b/src/drivers/ps3/PS3Driver.cpp new file mode 100644 index 000000000..5377f5677 --- /dev/null +++ b/src/drivers/ps3/PS3Driver.cpp @@ -0,0 +1,159 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#include "drivers/ps3/PS3Driver.h" +#include "drivers/ps3/PS3Descriptors.h" +#include "drivers/shared/driverhelper.h" + +// Magic byte sequence to enable PS button on PS3 +static const uint8_t ps3_magic_init_bytes[8] = {0x21, 0x26, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00}; + +static bool ps3_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + if ( request->bmRequestType == 0xA1 && + request->bRequest == HID_REQ_CONTROL_GET_REPORT && + request->wValue == 0x0300 ) { + return tud_control_xfer(rhport, request, (void *) ps3_magic_init_bytes, sizeof(ps3_magic_init_bytes)); + } else { + return hidd_control_xfer_cb(rhport, stage, request); + } +} + +void PS3Driver::initialize() { + ps3Report = { + .square_btn = 0, .cross_btn = 0, .circle_btn = 0, .triangle_btn = 0, + .l1_btn = 0, .r1_btn = 0, .l2_btn = 0, .r2_btn = 0, + .select_btn = 0, .start_btn = 0, .l3_btn = 0, .r3_btn = 0, .ps_btn = 0, .tp_btn = 0, + .direction = 0x08, + .l_x_axis = PS3_JOYSTICK_MID, + .l_y_axis = PS3_JOYSTICK_MID, + .r_x_axis = PS3_JOYSTICK_MID, + .r_y_axis = PS3_JOYSTICK_MID, + .right_axis = 0x00, .left_axis = 0x00, .up_axis = 0x00, .down_axis = 0x00, + .triangle_axis = 0x00, .circle_axis = 0x00, .cross_axis = 0x00, .square_axis = 0x00, + .l1_axis = 0x00, .r1_axis = 0x00, .l2_axis = 0x00, .r2_axis = 0x00 + }; + + class_driver = { + #if CFG_TUSB_DEBUG >= 2 + .name = "PS3", + #endif + .init = hidd_init, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = ps3_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }; +} + +// Generate PS3 report from gamepad and send to TUSB Device +void PS3Driver::process(Gamepad * gamepad, uint8_t * outBuffer) { + switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD) + { + case GAMEPAD_MASK_UP: ps3Report.direction = PS3_HAT_UP; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: ps3Report.direction = PS3_HAT_UPRIGHT; break; + case GAMEPAD_MASK_RIGHT: ps3Report.direction = PS3_HAT_RIGHT; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: ps3Report.direction = PS3_HAT_DOWNRIGHT; break; + case GAMEPAD_MASK_DOWN: ps3Report.direction = PS3_HAT_DOWN; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: ps3Report.direction = PS3_HAT_DOWNLEFT; break; + case GAMEPAD_MASK_LEFT: ps3Report.direction = PS3_HAT_LEFT; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: ps3Report.direction = PS3_HAT_UPLEFT; break; + default: ps3Report.direction = PS3_HAT_NOTHING; break; + } + + ps3Report.cross_btn = gamepad->pressedB1(); + ps3Report.circle_btn = gamepad->pressedB2(); + ps3Report.square_btn = gamepad->pressedB3(); + ps3Report.triangle_btn = gamepad->pressedB4(); + ps3Report.l1_btn = gamepad->pressedL1(); + ps3Report.r1_btn = gamepad->pressedR1(); + ps3Report.l2_btn = gamepad->pressedL2(); + ps3Report.r2_btn = gamepad->pressedR2(); + ps3Report.select_btn = gamepad->pressedS1(); + ps3Report.start_btn = gamepad->pressedS2(); + ps3Report.l3_btn = gamepad->pressedL3(); + ps3Report.r3_btn = gamepad->pressedR3(); + ps3Report.ps_btn = gamepad->pressedA1(); + ps3Report.tp_btn = gamepad->pressedA2(); + + ps3Report.l_x_axis = static_cast(gamepad->state.lx >> 8); + ps3Report.l_y_axis = static_cast(gamepad->state.ly >> 8); + ps3Report.r_x_axis = static_cast(gamepad->state.rx >> 8); + ps3Report.r_y_axis = static_cast(gamepad->state.ry >> 8); + + if (gamepad->hasAnalogTriggers) + { + ps3Report.l2_axis = gamepad->state.lt; + ps3Report.r2_axis = gamepad->state.rt; + } else { + ps3Report.l2_axis = gamepad->pressedL2() ? 0xFF : 0; + ps3Report.r2_axis = gamepad->pressedR2() ? 0xFF : 0; + } + + ps3Report.triangle_axis = gamepad->pressedB4() ? 0xFF : 0; + ps3Report.circle_axis = gamepad->pressedB2() ? 0xFF : 0; + ps3Report.cross_axis = gamepad->pressedB1() ? 0xFF : 0; + ps3Report.square_axis = gamepad->pressedB3() ? 0xFF : 0; + ps3Report.l1_axis = gamepad->pressedL1() ? 0xFF : 0; + ps3Report.r1_axis = gamepad->pressedR1() ? 0xFF : 0; + ps3Report.right_axis = gamepad->state.dpad & GAMEPAD_MASK_RIGHT ? 0xFF : 0; + ps3Report.left_axis = gamepad->state.dpad & GAMEPAD_MASK_LEFT ? 0xFF : 0; + ps3Report.up_axis = gamepad->state.dpad & GAMEPAD_MASK_UP ? 0xFF : 0; + ps3Report.down_axis = gamepad->state.dpad & GAMEPAD_MASK_DOWN ? 0xFF : 0; + + // Wake up TinyUSB device + if (tud_suspended()) + tud_remote_wakeup(); + + void * report = &ps3Report; + uint16_t report_size = sizeof(ps3Report); + if (memcmp(last_report, report, report_size) != 0) + { + // HID ready + report sent, copy previous report + if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) { + memcpy(last_report, report, report_size); + } + } +} + +// tud_hid_get_report_cb +uint16_t PS3Driver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { + memcpy(buffer, &ps3Report, sizeof(PS3Report)); + return sizeof(PS3Report); +} + +// Only PS4 does anything with set report +void PS3Driver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {} + +// Only XboxOG and Xbox One use vendor control xfer cb +bool PS3Driver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + return false; +} + +const uint16_t * PS3Driver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { + const char *value = (const char *)ps3_string_descriptors[index]; + return getStringDescriptor(value, index); // getStringDescriptor returns a static array +} + +const uint8_t * PS3Driver::get_descriptor_device_cb() { + return ps3_device_descriptor; +} + +const uint8_t * PS3Driver::get_hid_descriptor_report_cb(uint8_t itf) { + return ps3_report_descriptor; +} + +const uint8_t * PS3Driver::get_descriptor_configuration_cb(uint8_t index) { + return ps3_configuration_descriptor; +} + +const uint8_t * PS3Driver::get_descriptor_device_qualifier_cb() { + return nullptr; +} + +uint16_t PS3Driver::GetJoystickMidValue() { + return PS3_JOYSTICK_MID << 8; +} diff --git a/src/gamepad.cpp b/src/gamepad.cpp index 5c076858d..b57a36630 100644 --- a/src/gamepad.cpp +++ b/src/gamepad.cpp @@ -55,6 +55,18 @@ void Gamepad::setup() mapButtonA2 = new GamepadButtonMapping(GAMEPAD_MASK_A2); mapButtonA3 = new GamepadButtonMapping(GAMEPAD_MASK_A3); mapButtonA4 = new GamepadButtonMapping(GAMEPAD_MASK_A4); + mapButtonE1 = new GamepadButtonMapping(GAMEPAD_MASK_E1); + mapButtonE2 = new GamepadButtonMapping(GAMEPAD_MASK_E2); + mapButtonE3 = new GamepadButtonMapping(GAMEPAD_MASK_E3); + mapButtonE4 = new GamepadButtonMapping(GAMEPAD_MASK_E4); + mapButtonE5 = new GamepadButtonMapping(GAMEPAD_MASK_E5); + mapButtonE6 = new GamepadButtonMapping(GAMEPAD_MASK_E6); + mapButtonE7 = new GamepadButtonMapping(GAMEPAD_MASK_E7); + mapButtonE8 = new GamepadButtonMapping(GAMEPAD_MASK_E8); + mapButtonE9 = new GamepadButtonMapping(GAMEPAD_MASK_E9); + mapButtonE10 = new GamepadButtonMapping(GAMEPAD_MASK_E10); + mapButtonE11 = new GamepadButtonMapping(GAMEPAD_MASK_E11); + mapButtonE12 = new GamepadButtonMapping(GAMEPAD_MASK_E12); mapButtonFn = new GamepadButtonMapping(AUX_MASK_FUNCTION); const auto assignCustomMappingToMaps = [&](GpioMappingInfo mapInfo, Pin_t pin) -> void { @@ -101,6 +113,18 @@ void Gamepad::setup() case GpioAction::BUTTON_PRESS_A2: mapButtonA2->pinMask |= 1 << pin; break; case GpioAction::BUTTON_PRESS_A3: mapButtonA3->pinMask |= 1 << pin; break; case GpioAction::BUTTON_PRESS_A4: mapButtonA4->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E1: mapButtonE1->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E2: mapButtonE2->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E3: mapButtonE3->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E4: mapButtonE4->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E5: mapButtonE5->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E6: mapButtonE6->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E7: mapButtonE7->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E8: mapButtonE8->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E9: mapButtonE9->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E10: mapButtonE10->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E11: mapButtonE11->pinMask |= 1 << pin; break; + case GpioAction::BUTTON_PRESS_E12: mapButtonE12->pinMask |= 1 << pin; break; case GpioAction::BUTTON_PRESS_FN: mapButtonFn->pinMask |= 1 << pin; break; case GpioAction::CUSTOM_BUTTON_COMBO: assignCustomMappingToMaps(pinMappings[pin], pin); break; default: break; @@ -134,6 +158,18 @@ void Gamepad::reinit() delete mapButtonA2; delete mapButtonA3; delete mapButtonA4; + delete mapButtonE1; + delete mapButtonE2; + delete mapButtonE3; + delete mapButtonE4; + delete mapButtonE5; + delete mapButtonE6; + delete mapButtonE7; + delete mapButtonE8; + delete mapButtonE9; + delete mapButtonE10; + delete mapButtonE11; + delete mapButtonE12; delete mapButtonFn; // reinitialize pin mappings @@ -250,6 +286,18 @@ void Gamepad::read() | ((values & mapButtonA2->pinMask) ? mapButtonA2->buttonMask : 0) | ((values & mapButtonA3->pinMask) ? mapButtonA3->buttonMask : 0) | ((values & mapButtonA4->pinMask) ? mapButtonA4->buttonMask : 0) + | ((values & mapButtonE1->pinMask) ? mapButtonE1->buttonMask : 0) + | ((values & mapButtonE2->pinMask) ? mapButtonE2->buttonMask : 0) + | ((values & mapButtonE3->pinMask) ? mapButtonE3->buttonMask : 0) + | ((values & mapButtonE4->pinMask) ? mapButtonE4->buttonMask : 0) + | ((values & mapButtonE5->pinMask) ? mapButtonE5->buttonMask : 0) + | ((values & mapButtonE6->pinMask) ? mapButtonE6->buttonMask : 0) + | ((values & mapButtonE7->pinMask) ? mapButtonE7->buttonMask : 0) + | ((values & mapButtonE8->pinMask) ? mapButtonE8->buttonMask : 0) + | ((values & mapButtonE9->pinMask) ? mapButtonE9->buttonMask : 0) + | ((values & mapButtonE10->pinMask) ? mapButtonE10->buttonMask : 0) + | ((values & mapButtonE11->pinMask) ? mapButtonE11->buttonMask : 0) + | ((values & mapButtonE12->pinMask) ? mapButtonE12->buttonMask : 0) ; state.lx = joystickMid; diff --git a/src/gp2040.cpp b/src/gp2040.cpp index 55275bf40..6665a6f46 100644 --- a/src/gp2040.cpp +++ b/src/gp2040.cpp @@ -123,15 +123,15 @@ void GP2040::setup() { case BootAction::ENTER_USB_MODE: reset_usb_boot(0, 0); return; - case BootAction::SET_INPUT_MODE_HID: // HID drivers - inputMode = INPUT_MODE_HID; - break; case BootAction::SET_INPUT_MODE_SWITCH: inputMode = INPUT_MODE_SWITCH; break; case BootAction::SET_INPUT_MODE_KEYBOARD: inputMode = INPUT_MODE_KEYBOARD; break; + case BootAction::SET_INPUT_MODE_GENERIC: + inputMode = INPUT_MODE_GENERIC; + break; case BootAction::SET_INPUT_MODE_NEOGEO: inputMode = INPUT_MODE_NEOGEO; break; @@ -153,6 +153,9 @@ void GP2040::setup() { case BootAction::SET_INPUT_MODE_XINPUT: // X-Input Driver inputMode = INPUT_MODE_XINPUT; break; + case BootAction::SET_INPUT_MODE_PS3: // PS3 (HID with quirks) driver + inputMode = INPUT_MODE_PS3; + break; case BootAction::SET_INPUT_MODE_PS4: // PS4 / PS5 Driver inputMode = INPUT_MODE_PS4; break; @@ -377,10 +380,12 @@ GP2040::BootAction GP2040::getBootAction() { return BootAction::SET_INPUT_MODE_XINPUT; case INPUT_MODE_SWITCH: return BootAction::SET_INPUT_MODE_SWITCH; - case INPUT_MODE_HID: - return BootAction::SET_INPUT_MODE_HID; case INPUT_MODE_KEYBOARD: return BootAction::SET_INPUT_MODE_KEYBOARD; + case INPUT_MODE_GENERIC: + return BootAction::SET_INPUT_MODE_GENERIC; + case INPUT_MODE_PS3: + return BootAction::SET_INPUT_MODE_PS3; case INPUT_MODE_PS4: return BootAction::SET_INPUT_MODE_PS4; case INPUT_MODE_PS5: @@ -399,8 +404,8 @@ GP2040::BootAction GP2040::getBootAction() { return BootAction::SET_INPUT_MODE_PSCLASSIC; case INPUT_MODE_XBOXORIGINAL: return BootAction::SET_INPUT_MODE_XBOXORIGINAL; - case INPUT_MODE_XBONE: - return BootAction::SET_INPUT_MODE_XBONE; + case INPUT_MODE_XBONE: + return BootAction::SET_INPUT_MODE_XBONE; default: return BootAction::NONE; } diff --git a/www/src/Data/Buttons.js b/www/src/Data/Buttons.js index 3e235937c..873674168 100644 --- a/www/src/Data/Buttons.js +++ b/www/src/Data/Buttons.js @@ -22,6 +22,18 @@ export const BUTTONS = { A2: 'A2', A3: 'A3', A4: 'A4', + E1: 'Extra 1', + E2: 'Extra 2', + E3: 'Extra 3', + E4: 'Extra 4', + E5: 'Extra 5', + E6: 'Extra 6', + E7: 'Extra 7', + E8: 'Extra 8', + E9: 'Extra 9', + E10: 'Extra 10', + E11: 'Extra 11', + E12: 'Extra 12', Fn: 'Function', }, arcade: { @@ -47,6 +59,18 @@ export const BUTTONS = { A2: '-', A3: '-', A4: '-', + E1: 'Extra 1', + E2: 'Extra 2', + E3: 'Extra 3', + E4: 'Extra 4', + E5: 'Extra 5', + E6: 'Extra 6', + E7: 'Extra 7', + E8: 'Extra 8', + E9: 'Extra 9', + E10: 'Extra 10', + E11: 'Extra 11', + E12: 'Extra 12', Fn: 'Function', }, xinput: { @@ -72,6 +96,18 @@ export const BUTTONS = { A2: '-', A3: '-', A4: '-', + E1: '-', + E2: '-', + E3: '-', + E4: '-', + E5: '-', + E6: '-', + E7: '-', + E8: '-', + E9: '-', + E10: '-', + E11: '-', + E12: '-', Fn: 'Function', }, switch: { @@ -97,6 +133,18 @@ export const BUTTONS = { A2: 'Capture', A3: '-', A4: '-', + E1: '-', + E2: '-', + E3: '-', + E4: '-', + E5: '-', + E6: '-', + E7: '-', + E8: '-', + E9: '-', + E10: '-', + E11: '-', + E12: '-', Fn: 'Function', }, ps3: { @@ -122,6 +170,18 @@ export const BUTTONS = { A2: '-', A3: '-', A4: '-', + E1: '-', + E2: '-', + E3: '-', + E4: '-', + E5: '-', + E6: '-', + E7: '-', + E8: '-', + E9: '-', + E10: '-', + E11: '-', + E12: '-', Fn: 'Function', }, ps4: { @@ -147,10 +207,23 @@ export const BUTTONS = { A2: 'Touchpad Center', A3: 'Touchpad Left', A4: 'Touchpad Right', + A2: 'Touchpad', + E1: '-', + E2: '-', + E3: '-', + E4: '-', + E5: '-', + E6: '-', + E7: '-', + E8: '-', + E9: '-', + E10: '-', + E11: '-', + E12: '-', Fn: 'Function', }, dinput: { - label: 'DInput', + label: 'Generic', value: 'dinput', Up: 'Up', Down: 'Down', @@ -172,6 +245,18 @@ export const BUTTONS = { A2: '14', A3: '15', A4: '16', + E1: '21', + E2: '22', + E3: '23', + E4: '24', + E5: '25', + E6: '26', + E7: '27', + E8: '28', + E9: '29', + E10: '30', + E11: '31', + E12: '32', Fn: 'Function', }, }; @@ -429,6 +514,18 @@ export const BUTTON_MASKS_OPTIONS = [ { label: 'Down', value: 1 << 17 }, { label: 'Left', value: 1 << 18 }, { label: 'Right', value: 1 << 19 }, + { label: 'E1', value: 1 << 20 }, + { label: 'E2', value: 1 << 21 }, + { label: 'E3', value: 1 << 22 }, + { label: 'E4', value: 1 << 23 }, + { label: 'E5', value: 1 << 24 }, + { label: 'E6', value: 1 << 25 }, + { label: 'E7', value: 1 << 26 }, + { label: 'E8', value: 1 << 27 }, + { label: 'E9', value: 1 << 28 }, + { label: 'E10', value: 1 << 29 }, + { label: 'E11', value: 1 << 30 }, + { label: 'E12', value: 1 << 31 }, ]; export const ANALOG_PINS = [26, 27, 28, 29]; diff --git a/www/src/Data/Pins.ts b/www/src/Data/Pins.ts index 7c6a82652..cc46abe6e 100644 --- a/www/src/Data/Pins.ts +++ b/www/src/Data/Pins.ts @@ -45,6 +45,18 @@ export const BUTTON_ACTIONS = { CUSTOM_BUTTON_COMBO: 40, BUTTON_PRESS_A3: 41, BUTTON_PRESS_A4: 42, + BUTTON_PRESS_E1: 43, + BUTTON_PRESS_E2: 44, + BUTTON_PRESS_E3: 45, + BUTTON_PRESS_E4: 46, + BUTTON_PRESS_E5: 47, + BUTTON_PRESS_E6: 48, + BUTTON_PRESS_E7: 49, + BUTTON_PRESS_E8: 50, + BUTTON_PRESS_E9: 51, + BUTTON_PRESS_E10: 52, + BUTTON_PRESS_E11: 53, + BUTTON_PRESS_E12: 54, } as const; export const PIN_DIRECTIONS = { diff --git a/www/src/Locales/en/PinMapping.jsx b/www/src/Locales/en/PinMapping.jsx index 3a86a4d9e..021ed211e 100644 --- a/www/src/Locales/en/PinMapping.jsx +++ b/www/src/Locales/en/PinMapping.jsx @@ -62,5 +62,17 @@ export default { BUTTON_PRESS_MACRO_5: 'Macro 5', BUTTON_PRESS_MACRO_6: 'Macro 6', CUSTOM_BUTTON_COMBO: 'Assigned to multi mapping', + BUTTON_PRESS_E1: 'Extra 1', + BUTTON_PRESS_E2: 'Extra 2', + BUTTON_PRESS_E3: 'Extra 3', + BUTTON_PRESS_E4: 'Extra 4', + BUTTON_PRESS_E5: 'Extra 5', + BUTTON_PRESS_E6: 'Extra 6', + BUTTON_PRESS_E7: 'Extra 7', + BUTTON_PRESS_E8: 'Extra 8', + BUTTON_PRESS_E9: 'Extra 9', + BUTTON_PRESS_E10: 'Extra 10', + BUTTON_PRESS_E11: 'Extra 11', + BUTTON_PRESS_E12: 'Extra 12', }, }; diff --git a/www/src/Locales/en/SettingsPage.jsx b/www/src/Locales/en/SettingsPage.jsx index 09c1a2cd7..1bb789e46 100644 --- a/www/src/Locales/en/SettingsPage.jsx +++ b/www/src/Locales/en/SettingsPage.jsx @@ -10,7 +10,8 @@ export default { none: 'No Mode Selected', xinput: 'XInput', 'nintendo-switch': 'Nintendo Switch', - ps3: 'PS3/DirectInput', + ps3: 'PS3', + generic: 'Generic HID', keyboard: 'Keyboard', ps4: 'PS4', ps5: 'PS5', diff --git a/www/src/Pages/SettingsPage.jsx b/www/src/Pages/SettingsPage.jsx index c17035d06..2d588aa2f 100644 --- a/www/src/Pages/SettingsPage.jsx +++ b/www/src/Pages/SettingsPage.jsx @@ -147,6 +147,7 @@ const INPUT_MODES = [ group: 'primary', required: ['usb'], }, + { labelKey: 'input-mode-options.generic', value: 14, group: 'primary' }, { labelKey: 'input-mode-options.mdmini', value: 6, group: 'mini' }, { labelKey: 'input-mode-options.neogeo', value: 7, group: 'mini' }, { labelKey: 'input-mode-options.pcemini', value: 8, group: 'mini' }, @@ -184,6 +185,7 @@ const INPUT_BOOT_MODES = [ group: 'primary', required: ['usb'], }, + { labelKey: 'input-mode-options.generic', value: 14, group: 'primary' }, { labelKey: 'input-mode-options.mdmini', value: 6, group: 'mini' }, { labelKey: 'input-mode-options.neogeo', value: 7, group: 'mini' }, { labelKey: 'input-mode-options.pcemini', value: 8, group: 'mini' },