Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Flydigi): Add support for flydigi vader 3/4 pro #308

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Fabianoshz
Copy link

This should add support for both flydigi vader 3 and 4.

Fixes #208

@Fabianoshz Fabianoshz force-pushed the add-flydigi-vader-pro-support branch from 75aa6d7 to 4fac759 Compare March 5, 2025 10:38
@blindedone1458
Copy link
Contributor

@Fabianoshz I think instead of doing all those remappings in the InputPlumber CapabilityMap, the xpad patch you are using should be updated so the Flydigi paddles match the Xbox Elite paddle mappings.
I've been using a Vader 3 Pro with xpad and this patch below based on cprn's patch here: paroj/xpad#268 (comment)

diff --git a/xpad.c b/xpad.c
index d5a016e..0e8f73f 100644
--- a/xpad.c
+++ b/xpad.c
@@ -95,6 +95,7 @@
 #define MAP_SELECT_BUTTON		(1 << 3)
 #define MAP_PADDLES			(1 << 4)
 #define MAP_PROFILE_BUTTON		(1 << 5)
+#define MAP_FLYDIGI_BUTTONS		(1 << 6)
 
 #define DANCEPAD_MAP_CONFIG	(MAP_DPAD_TO_BUTTONS |			\
 				MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL)
@@ -421,6 +422,19 @@ static const struct xpad_device {
 	{ 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
 };
 
+// A "flavor" is an aftermarket variant of an existing model supporting
+// additional features.
+static const struct xpad_flavor {
+	u16 idVendor;
+	u16 idProduct;
+	char *product;
+	u8 mapping;
+} xpad_flavor[] = {
+	{ 0x045e, 0x028e, "Flydigi VADER3", MAP_PADDLES | MAP_FLYDIGI_BUTTONS },
+	{ 0x045e, 0x028e, "Flydigi VADER4", MAP_PADDLES | MAP_FLYDIGI_BUTTONS },
+	{ 0x0000, 0x0000, NULL, 0 }
+};
+
 /* buttons shared with xbox and xbox360 */
 static const signed short xpad_common_btn[] = {
 	BTN_A, BTN_B, BTN_X, BTN_Y,			/* "analog" buttons */
@@ -484,6 +498,13 @@ static const struct {int x; int y; } dpad_mapping[] = {
 	{0, 0}
 };
 
+/* used for extra buttons in addition to paddles on Flydigi Vader Pro 3*/
+static const signed short xpad_btn_extra[] = {
+	BTN_TRIGGER_HAPPY9, BTN_TRIGGER_HAPPY10, /* Z, C face buttons */
+	BTN_TRIGGER_HAPPY11,			/* circle */
+	-1						/* terminating entry */
+};
+
 /*
  * Xbox 360 has a vendor-specific class, so we cannot match it with only
  * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
@@ -940,6 +961,7 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
  *
  *	The used report descriptor was taken from:
  *		http://www.free60.org/wiki/Gamepad
+ *	Packet length for valid data is 20 bytes.
  */
 
 static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev,
@@ -1012,6 +1034,17 @@ static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev,
 		input_report_abs(dev, ABS_RZ, data[5]);
 	}
 
+	/* Additional buttons for Flydigi Vader Pro 3 presenting as 360 pad. */
+	if (xpad->mapping & MAP_FLYDIGI_BUTTONS) {
+		input_report_key(dev, BTN_TRIGGER_HAPPY10, data[19] & BIT(0));   // C
+		input_report_key(dev, BTN_TRIGGER_HAPPY9, data[19] & BIT(1));  // Z
+		input_report_key(dev, BTN_TRIGGER_HAPPY8, data[19] & BIT(3));   // Leftmost paddle (M2)
+		input_report_key(dev, BTN_TRIGGER_HAPPY7, data[19] & BIT(5));   // Second to leftmost (M4)
+		input_report_key(dev, BTN_TRIGGER_HAPPY5, data[19] & BIT(4));   // Second to rightmost (M3)
+		input_report_key(dev, BTN_TRIGGER_HAPPY6, data[19] & BIT(2));   // Rightmost paddle (M1)
+		input_report_key(dev, BTN_TRIGGER_HAPPY11, data[20] & BIT(0));  // Circle
+	}
+
 	input_sync(dev);
 
 	/* XBOX360W controllers can't be turned off without driver assistance */
@@ -2246,6 +2279,13 @@ static int xpad_init_input(struct usb_xpad *xpad)
 			input_set_capability(input_dev, EV_KEY, xpad_btn_paddles[i]);
 	}
 
+	/* set up extra face buttons if the controller has them */
+	if (xpad->mapping & MAP_FLYDIGI_BUTTONS) {
+		for (i = 0; xpad_btn_extra[i] >= 0; i++) {
+			input_set_capability(input_dev, EV_KEY, xpad_btn_extra[i]);
+		}
+	}
+
 	/*
 	 * This should be a simple else block. However historically
 	 * xbox360w has mapped DPAD to buttons while xbox360 did not. This
@@ -2300,7 +2340,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
 	struct usb_device *udev = interface_to_usbdev(intf);
 	struct usb_xpad *xpad;
 	struct usb_endpoint_descriptor *ep_irq_in, *ep_irq_out;
-	int i, error;
+	int i, j, error;
 
 	if (intf->cur_altsetting->desc.bNumEndpoints != 2)
 		return -ENODEV;
@@ -2334,6 +2374,16 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
 	xpad->udev = udev;
 	xpad->intf = intf;
 	xpad->mapping = xpad_device[i].mapping;
+
+	if (udev->product) {
+		for(j = 0; xpad_flavor[j].idVendor; j++) {
+			if (!strcmp(udev->product, xpad_flavor[j].product)) {
+				xpad->mapping |= xpad_flavor[j].mapping;
+				break;
+			}
+		}
+	}
+
 	xpad->xtype = xpad_device[i].xtype;
 	xpad->name = xpad_device[i].name;
 	xpad->quirks = xpad_device[i].quirks;

@belozer
Copy link

belozer commented Mar 5, 2025

@blindedone1458 Thanks, with this patch, I see that the paddle buttons is working (via steam). Apex 4

But what to do about the Share button? Because Series controllers have it.

@Fabianoshz
Copy link
Author

@blindedone1458 tbh I've set this up months ago and didn't bothered after that, having them being recognized a xbox elite could be good but it depends on ends up being merged on xpad.

My guess is that if you patch works we could maybe close this in favor of that and people can revisit this in the future in case the original patch gets merged for whatever reason.

@blindedone1458
Copy link
Contributor

For the Share button, are you referring to the Circle button? I honestly hadn't even considered the button as something that could be mapped originally (since it wasn't really doing much beyond controller functions) without Flydigi mapping software. I just made a change to the xpad patch to map it to a Share button:

diff --git a/xpad.c b/xpad.c
index d5a016e..0e8f73f 100644
--- a/xpad.c
+++ b/xpad.c
@@ -95,6 +95,7 @@
 #define MAP_SELECT_BUTTON		(1 << 3)
 #define MAP_PADDLES			(1 << 4)
 #define MAP_PROFILE_BUTTON		(1 << 5)
+#define MAP_FLYDIGI_BUTTONS		(1 << 6)
 
 #define DANCEPAD_MAP_CONFIG	(MAP_DPAD_TO_BUTTONS |			\
 				MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL)
@@ -421,6 +422,19 @@ static const struct xpad_device {
 	{ 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
 };
 
+// A "flavor" is an aftermarket variant of an existing model supporting
+// additional features.
+static const struct xpad_flavor {
+	u16 idVendor;
+	u16 idProduct;
+	char *product;
+	u8 mapping;
+} xpad_flavor[] = {
+	{ 0x045e, 0x028e, "Flydigi VADER3", MAP_PADDLES | MAP_FLYDIGI_BUTTONS },
+	{ 0x045e, 0x028e, "Flydigi VADER4", MAP_PADDLES | MAP_FLYDIGI_BUTTONS },
+	{ 0x0000, 0x0000, NULL, 0 }
+};
+
 /* buttons shared with xbox and xbox360 */
 static const signed short xpad_common_btn[] = {
 	BTN_A, BTN_B, BTN_X, BTN_Y,			/* "analog" buttons */
@@ -484,6 +498,13 @@ static const struct {int x; int y; } dpad_mapping[] = {
 	{0, 0}
 };
 
+/* used for extra buttons in addition to paddles on Flydigi Vader Pro 3*/
+static const signed short xpad_btn_extra[] = {
+	BTN_TRIGGER_HAPPY9, BTN_TRIGGER_HAPPY10, /* Z, C face buttons */
+	KEY_RECORD,			/* circle */
+	-1						/* terminating entry */
+};
+
 /*
  * Xbox 360 has a vendor-specific class, so we cannot match it with only
  * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
@@ -940,6 +961,7 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
  *
  *	The used report descriptor was taken from:
  *		http://www.free60.org/wiki/Gamepad
+ *	Packet length for valid data is 20 bytes.
  */
 
 static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev,
@@ -1012,6 +1034,17 @@ static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev,
 		input_report_abs(dev, ABS_RZ, data[5]);
 	}
 
+	/* Additional buttons for Flydigi Vader Pro 3 presenting as 360 pad. */
+	if (xpad->mapping & MAP_FLYDIGI_BUTTONS) {
+		input_report_key(dev, BTN_TRIGGER_HAPPY10, data[19] & BIT(0));   // C
+		input_report_key(dev, BTN_TRIGGER_HAPPY9, data[19] & BIT(1));  // Z
+		input_report_key(dev, BTN_TRIGGER_HAPPY8, data[19] & BIT(3));   // Leftmost paddle (M2)
+		input_report_key(dev, BTN_TRIGGER_HAPPY7, data[19] & BIT(5));   // Second to leftmost (M4)
+		input_report_key(dev, BTN_TRIGGER_HAPPY5, data[19] & BIT(4));   // Second to rightmost (M3)
+		input_report_key(dev, BTN_TRIGGER_HAPPY6, data[19] & BIT(2));   // Rightmost paddle (M1)
+		input_report_key(dev, KEY_RECORD, data[20] & BIT(0));  // Circle
+	}
+
 	input_sync(dev);
 
 	/* XBOX360W controllers can't be turned off without driver assistance */
@@ -2246,6 +2279,13 @@ static int xpad_init_input(struct usb_xpad *xpad)
 			input_set_capability(input_dev, EV_KEY, xpad_btn_paddles[i]);
 	}
 
+	/* set up extra face buttons if the controller has them */
+	if (xpad->mapping & MAP_FLYDIGI_BUTTONS) {
+		for (i = 0; xpad_btn_extra[i] >= 0; i++) {
+			input_set_capability(input_dev, EV_KEY, xpad_btn_extra[i]);
+		}
+	}
+
 	/*
 	 * This should be a simple else block. However historically
 	 * xbox360w has mapped DPAD to buttons while xbox360 did not. This
@@ -2300,7 +2340,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
 	struct usb_device *udev = interface_to_usbdev(intf);
 	struct usb_xpad *xpad;
 	struct usb_endpoint_descriptor *ep_irq_in, *ep_irq_out;
-	int i, error;
+	int i, j, error;
 
 	if (intf->cur_altsetting->desc.bNumEndpoints != 2)
 		return -ENODEV;
@@ -2334,6 +2374,16 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
 	xpad->udev = udev;
 	xpad->intf = intf;
 	xpad->mapping = xpad_device[i].mapping;
+
+	if (udev->product) {
+		for(j = 0; xpad_flavor[j].idVendor; j++) {
+			if (!strcmp(udev->product, xpad_flavor[j].product)) {
+				xpad->mapping |= xpad_flavor[j].mapping;
+				break;
+			}
+		}
+	}
+
 	xpad->xtype = xpad_device[i].xtype;
 	xpad->name = xpad_device[i].name;
 	xpad->quirks = xpad_device[i].quirks;

@blindedone1458
Copy link
Contributor

As for your PR, I think it is good to have but just that the CapabilityMap doesn't need all those Mappings in it. Could have a basic mapping in it for the C and Z buttons since the Xbox Elite / Series controllers don't have a C or Z:

mapping:
  - name: C Button
    target_event:
      gamepad:
        button: LeftStick
    source_events:
      - gamepad:
          button: LeftPaddle3
  - name: Z Button
    target_event:
      gamepad:
        button: RightStick
    source_events:
      - gamepad:
          button: RightPaddle3

@pastaq
Copy link
Contributor

pastaq commented Mar 5, 2025

Can someone post a picture of the controller with all the buttons labeled for context?

@belozer
Copy link

belozer commented Mar 5, 2025

For the Share button, are you referring to the Circle button

@blindedone1458 Yes, that's correct. Circle is the FN button. I didn't think that data was also transmitted. But I saw
KEY_RECORD (BTN_TRIGGER_HAPPY11 in first version) in your patch.

I think we need to try mapping it to the "Share" button.

cc @pastaq

Apex 4
image

Vader 4
image

This is necessary for taking screenshots and full mapping of the Xbox Elite controller.
image

@belozer
Copy link

belozer commented Mar 5, 2025

Ohh... I forgot. The "Share" button only exists on the Xbox Series controller. On the Xbox Elite 2 controller, this button switches profiles. I have not used the controller in a long time...

But at the same time, when you look at the Steam interface you can see this button.

image

Xbox Series
image

Xbox Elite 2
image

But will cool mapping FN to it if possible.

@belozer
Copy link

belozer commented Mar 5, 2025

@blindedone1458 thanks! It works #308 (comment)

Now Steam recognizes FN as the Screenshot/Share button, tested on Flydigi Apex 4. Paddle Buttons also works and recognized in Steam (by using InputPlumber).

@belozer
Copy link

belozer commented Mar 6, 2025

@pastaq a gamepad with paddle button layout for context. I have marked it in orange.

Flydigi Vader 3/4 (Apex 4 the same)
image

@pastaq
Copy link
Contributor

pastaq commented Mar 6, 2025

Interesting.

Buttons C and Z are going to be a challenge as there isn't a normal function for them on modern controllers. They are part of the original dinput spec and produce valid codes (BTN_C/BTN_Z). The original Xbox controller has them as well as things like the sidewinder and the Sega Saturn controller. They have fallen out of favor since the 360 came out. It feels incorrect to map them to happy trigger. We also haven't fully decided what to do with them in InputPlumber as they fit into a weird spot where they aren't really a standard capability or button like abxy are, despite being an extension of that.

@belozer
Copy link

belozer commented Mar 10, 2025

It seems that these buttons (C, Z) need to be connected to keyboard events in the current situation.

E.g.

Home, End
Page Up, Page Down
Left Alt, Right Alt

@belozer
Copy link

belozer commented Mar 10, 2025

The current solution for Apex 4 meets 90% of the needs. The remaining 10% is the gyroscope.

Also ability to change at least the backlight color, but that's another story.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Flydigi Apex 4 support
4 participants