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

Successfully sending out the extra buttons #268

Open
wants to merge 21 commits into
base: master
Choose a base branch
from

Conversation

ahungry
Copy link

@ahungry ahungry commented Jan 14, 2024

No description provided.

dantob and others added 21 commits September 8, 2022 23:33
Signed-off-by: Daniel Tobias <[email protected]>
Signed-off-by: Jonathan <[email protected]>
Signed-off-by: Matt Sturgeon <[email protected]>
Many knockoff brands emulating the XBOX 360 controller do not properly
send data unless configured correctly. Examples include the Gamesir G3w
and the Fantech GP11 Shooter.

Protocol inspection of communication with other operating systems
reveals a sequence of control messages that can be used to initialize
the controllers sufficiently to send proper data.

Some of these controllers only require one and may break with further,
some may require all three. This change adds a quirks field that allows
specifying these initialization packets.

Note that it also removes an unused field from the controller type table.

Signed-off-by: Darvin Delgado <[email protected]>
Signed-off-by: Vicki Pfau <[email protected]>
only renames, no functional changes - even though some of the packets
we send are suspicious.
However, I dont have the hardware to verify they are truly superflous.
This allows to turn off the pad without having to release the Xbox (mode) button

Signed-off-by: Davide Garberi <[email protected]>
This occurs with MSI GC20 on Ubuntu 22.04.1 LTS.

Signed-off-by: Eldad Zack <[email protected]>
8BitDo Pro 2 Wired Controller shares the same USB identifier
(2dc8:3106) as a different device, so amend name to reflect that and
reduce confusion as the user might think the controller was misdetected.

I have personally tested it and I can confirm that Pro 2 Wired will also
not work in XTYPE_XBOXONE mode (buton presses won't register), therefore
XTYPE_XBOX360 remains appropriate.

Signed-off-by: Leonardo Brondani Schenkel <[email protected]>
This controller is a "Series S|X": it has the "share" button below the
big Xbox button. However, it reports the status of that button in a
different offset than the official controller.

The button is still recognized by official Microsoft driver in Windows,
so it looks like that both offsets are used in the wild.

Signed-off-by: Leonardo Brondani Schenkel <[email protected]>
@ahungry
Copy link
Author

ahungry commented Jan 14, 2024

Is it possible to incorporate this third party controller? It's identification crosses over into the domain of first party controllers, however it ships with 8 additional buttons, which, while mapped via a special app, still seem to send the distinct button data - I was going to make a thin driver for it (I just did for bluetooth, and wanted to make one for dongle, which this PR works with) - however xpad makes it difficult to have my driver take precedence due to the colliding vendor id/product ids.

I think I might be able to form a workaround using something like:

cat /etc/depmod.d/xpad.conf
override xpad * updates

but I'm not entirely sure of the syntax (I found this snippet for having a source installed dkms xpad take greater precedence than the built in one, but in this case, I would want a module named something like "vader3d" to take precedence over xpad).

@ahungry
Copy link
Author

ahungry commented Jan 14, 2024

Actually, I don't think depmod can allow differently named modules to supersede each other (only same name ones).

What's interesting is this works perfect (extra buttons + rumble) if the module name is "xpad" - if I change the module name to something like "vader3d" the rumble stops working ("Function not implemented" in fftest) - does anyone know if "fftest" has some hard coded exceptions to force rumble data if the driver is xpad?

I've diffed the files, and they are identical (other than the .name in the driver data) - and it only reliably rumbles if the name is "xpad", despite everything else being the same.

@RondoRevolution
Copy link

Currently the best way this PR works as it is inside Steam is by downloading controller configurations made by other users for controllers with pads, like Xbox Elite or Steam Deck configs. This way the paddles work correctly, but you can't remap it yourself in the UI.

Maybe mocking a Xbox Elite controller in xpad could enable the back buttons to be remapped in Steam? Since it seems to work according to this issue on your Bluetooth driver for the controller: ahungry/vader3#2

It would probably need to match the paddles to the same BTN_TRIGGER_HAPPY used by the Elite controller. Also, if it ends up being a good option, wouldn't it be better to do this in xone instead of xpad?

@matoro
Copy link

matoro commented Jul 30, 2024

Hey, I took a copy of this PR and applied it to the in-tree xpad driver just out of curiosity and it indeed surprisingly works. For the back paddles M1-M4, I also changed them to map to the same BTN_TRIGGER_HAPPY values that the Elite controller uses, as recommended.

However, it seems that the custom buttons submit both their custom codes AND the standard buttons they are mapped to, e.g. pressing C submits both C and L3. Did you clear the custom mappings in the proprietary software before using this patch?

I was scratching my head about how to work around this in the code, but couldn't come up with anything that doesn't assume specific mappings. For example, if I modified it to ignore all other keypresses when pressing a custom button, then I believe that would prevent e.g. walking forward while pressing C.

@ahungry
Copy link
Author

ahungry commented Jul 31, 2024

Yes, I believe I cleared my Flydigi Space Station mappings before using it as you note (due to the duplicate key presses) - though it's been awhile since I used the dongle 😆

@matoro
Copy link

matoro commented Aug 1, 2024

Yes, I believe I cleared my Flydigi Space Station mappings before using it as you note (due to the duplicate key presses) - though it's been awhile since I used the dongle 😆

Thank you, I installed Space Station in a VM and passed my controller through to it, cleared the mappings, and double presses are gone now.

First I found a very old patch from 2007 that appears not to have made it in confirming that all valid packets have a length of 20 bytes, so it is always safe to access byte 19. I rebased this patch and added it in as an additional validity check.

Then I tweaked the patch a little bit to use some more modern kernel functions, mainly BIT() macro and input_set_capability().

Next I changed the addition of the extra buttons to be an opt-in module paramater called extra_buttons. This way the new behavior is strictly non-default. Possibly this might make it more amenable to upstream kernel maintainers.

Lastly I limited the additional button count to 3 (C, Z, and circle). The second circle button seems to overlap with the Guide button and this does not seem to be configurable in Space Station, so I left it out.

Here is my overall patch, which applies to upstream 6.10. I'm not sure if this is suitable for upstreaming, but if you'd like to submit it to the mailing list, it can't hurt.

diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 2b8370ecf42a..21fb1c5ffddc 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -120,6 +120,10 @@ static bool auto_poweroff = true;
 module_param(auto_poweroff, bool, S_IWUSR | S_IRUGO);
 MODULE_PARM_DESC(auto_poweroff, "Power off wireless controllers on suspend");
 
+static bool extra_buttons = false;
+module_param(extra_buttons, bool, S_IRUGO);
+MODULE_PARM_DESC(extra_buttons, "Enable 3 extra buttons for Flydigi Vader Pro 3");
+
 static const struct xpad_device {
 	u16 idVendor;
 	u16 idProduct;
@@ -444,6 +448,13 @@ static const signed short xpad_btn_paddles[] = {
 	-1						/* terminating entry */
 };
 
+/* 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, /* C, Z 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
@@ -826,6 +837,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,
@@ -834,6 +846,8 @@ static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev,
 	/* valid pad data */
 	if (data[0] != 0x00)
 		return;
+	if (data[1] < 20)
+		return;
 
 	/* digital pad */
 	if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
@@ -898,6 +912,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 (extra_buttons) {
+		input_report_key(dev, BTN_TRIGGER_HAPPY9, data[19] & BIT(0));   // C
+		input_report_key(dev, BTN_TRIGGER_HAPPY10, data[19] & BIT(1));  // Z
+		input_report_key(dev, BTN_TRIGGER_HAPPY5, data[19] & BIT(3));   // Leftmost paddle (M2)
+		input_report_key(dev, BTN_TRIGGER_HAPPY6, data[19] & BIT(5));   // Second to leftmost (M4)
+		input_report_key(dev, BTN_TRIGGER_HAPPY7, data[19] & BIT(4));   // Second to rightmost (M3)
+		input_report_key(dev, BTN_TRIGGER_HAPPY8, 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 */
@@ -1953,11 +1978,18 @@ static int xpad_init_input(struct usb_xpad *xpad)
 	}
 
 	/* set up paddles if the controller has them */
-	if (xpad->mapping & MAP_PADDLES) {
+	if ((xpad->mapping & MAP_PADDLES) || extra_buttons) {
 		for (i = 0; xpad_btn_paddles[i] >= 0; i++)
 			input_set_capability(input_dev, EV_KEY, xpad_btn_paddles[i]);
 	}
 
+	/* set up extra buttons when enabled as module param */
+	if (extra_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

@rharish101
Copy link

Would this also work with the Vader 4 Pro? I'm considering buying one, and if I do, I'm willing to test it on this branch/patchset.

@matoro
Copy link

matoro commented Aug 1, 2024

Would this also work with the Vader 4 Pro? I'm considering buying one, and if I do, I'm willing to test it on this branch/patchset.

No idea, I also considered it but went with the 3 specifically because of this PR. If it does that would be great; let me know and I will update the comments.

It's very annoying that they decided to steal the official X360 USB ID instead of creating their own, so there is no way to autodetect the difference easily. I do still have an old official controller, so I might dig into it later to see if I can identify any subtle differences that might distinguish them.

Overall I'm very happy with this. I've already written up a small script using python-evdev to add macros for Elden Ring and it works great!

@rharish101
Copy link

Sounds great! I don't plan on getting the Vader 3 (because it looks ugly IMO), so it'll probably be the Vader 4. I also have an official Xbox 360 wireless controller (with the USB dongle), so I could also help with distinguishing them. I'll post here once I buy it (or decide not to).

@matoro
Copy link

matoro commented Aug 31, 2024

Done. Here is a v2 version of my patch which autodetects the Flydigi controllers and sets them up, but leaves original controllers alone. This gets rid of the whole extra_buttons param nonsense. I do not know for sure if the product name is as I assumed on the Vader 4, so would appreciate a test from someone.

diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 2b8370ecf42a..3d0e0b95f691 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -83,6 +83,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)
@@ -387,6 +388,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 */
@@ -444,6 +458,13 @@ static const signed short xpad_btn_paddles[] = {
 	-1						/* terminating entry */
 };
 
+/* 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, /* C, Z 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
@@ -826,6 +847,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,
@@ -834,6 +856,8 @@ static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev,
 	/* valid pad data */
 	if (data[0] != 0x00)
 		return;
+	if (data[1] < 20)
+		return;
 
 	/* digital pad */
 	if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
@@ -898,6 +922,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_HAPPY9, data[19] & BIT(0));   // C
+		input_report_key(dev, BTN_TRIGGER_HAPPY10, data[19] & BIT(1));  // Z
+		input_report_key(dev, BTN_TRIGGER_HAPPY5, data[19] & BIT(3));   // Leftmost paddle (M2)
+		input_report_key(dev, BTN_TRIGGER_HAPPY6, data[19] & BIT(5));   // Second to leftmost (M4)
+		input_report_key(dev, BTN_TRIGGER_HAPPY7, data[19] & BIT(4));   // Second to rightmost (M3)
+		input_report_key(dev, BTN_TRIGGER_HAPPY8, 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 */
@@ -1958,6 +1993,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
@@ -2012,7 +2054,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;
@@ -2046,6 +2088,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->packet_type = PKT_XB;

To test this, I plugged in both my Vader 3 and a wired 360 controller at the same time, and confirmed that the former gets the extra buttons set up and they still work, but the latter doesn't:

$ sdl2-jstest --list
Found 2 joystick(s)

Joystick Name:     'Xbox 360 Controller'
Joystick GUID:     030081b85e0400008e02000004010000
Joystick Number:    0
Number of Axes:     6
Number of Buttons: 18
Number of Hats:     1
Number of Balls:    0
GameControllerConfig:
  Name:    'Microsoft Xbox 360'
  Mapping: '030081b85e0400008e02000004010000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,'

Joystick Name:     'Xbox 360 Controller'
Joystick GUID:     030081b85e0400008e02000014010000
Joystick Number:    1
Number of Axes:     6
Number of Buttons: 11
Number of Hats:     1
Number of Balls:    0
GameControllerConfig:
  Name:    'Xbox 360 Controller'
  Mapping: '030081b85e0400008e02000014010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,'

I actually think that this might actually pass kernel approval, but I can't submit this under my real name. @ahungry would you be willing to put your name on this and send it upstream? You did all the hard work; I just prettied it up. If you haven't submitted a kernel patch before I can assist.

@rharish101
Copy link

Done. Here is a v2 version of my patch which autodetects the Flydigi controllers and sets them up, but leaves original controllers alone. This gets rid of the whole extra_buttons param nonsense. I do not know for sure if the product name is as I assumed on the Vader 4, so would appreciate a test from someone.

Can confirm that it works on the Vader 4.

@italoghost
Copy link

@matoro with this update, were you able to make Steam recognize the buttons?I see from you sdl2-jstest that it is being recognized as with 18 buttons (which is nice!).

@rharish101 have you updated the patch for xpad-dkms-git? If so, could you share?

@rharish101
Copy link

@rharish101 have you updated the patch for xpad-dkms-git? If so, could you share?

Here's the diff for the xpad-dkms-git PKGBUILD (w.r.t. the original PKGBUILD, not the previous edit):

diff --git a/PKGBUILD b/PKGBUILD
index 8fc9745..fa47ce9 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -14,14 +14,20 @@ makedepends=('git')
 conflicts=("${_pkgname}-dkms")
 source=("${pkgname}::git+https://github.com/paroj/xpad.git"
         "xpad.conf"
-        "${pkgname}.install")
+        "${pkgname}.install"
+        "flydigi-vader-3.patch")
 md5sums=('SKIP'
          '4218c9543d551377825392295544c3c2'
-         '75cad51dc48d8fa879f926432beabf66')
+         '75cad51dc48d8fa879f926432beabf66'
+         '9ce95cc700844f9040fc02b1ada98aa3')
 pkgver() {
   cd "$pkgname"
   printf "0.4.%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short=7 HEAD)"
 }
+prepare() {
+    cd "$pkgname"
+    patch -p1 -i ../flydigi-vader-3.patch
+}
 package() {
     # install depmod config file so our driver gets higher priority than the intree module
     install -dm 755 "$pkgdir/etc/depmod.d"

And here is the flydigi-vader-3.patch file:

diff '--color=auto' -ura package.orig/xpad.c package.new/xpad.c
--- package.orig/xpad.c	2024-09-01 11:37:56.038131642 +0200
+++ package.new/xpad.c	2024-09-01 11:43:02.030156284 +0200
@@ -87,6 +87,9 @@
 #define MAP_STICKS_TO_NULL		(1 << 2)
 #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)
 
@@ -393,6 +396,19 @@
 	{ 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 */
@@ -456,6 +472,13 @@
 	{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, /* C, Z 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
@@ -893,6 +916,7 @@
  *
  *	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,
@@ -901,6 +925,8 @@
 	/* valid pad data */
 	if (data[0] != 0x00)
 		return;
+	if (data[1] < 20)
+		return;
 
 	/* digital pad */
 	if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
@@ -965,6 +991,17 @@
 		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_HAPPY9, data[19] & BIT(0));   // C
+		input_report_key(dev, BTN_TRIGGER_HAPPY10, data[19] & BIT(1));  // Z
+		input_report_key(dev, BTN_TRIGGER_HAPPY5, data[19] & BIT(3));   // Leftmost paddle (M2)
+		input_report_key(dev, BTN_TRIGGER_HAPPY6, data[19] & BIT(5));   // Second to leftmost (M4)
+		input_report_key(dev, BTN_TRIGGER_HAPPY7, data[19] & BIT(4));   // Second to rightmost (M3)
+		input_report_key(dev, BTN_TRIGGER_HAPPY8, 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 */
@@ -2155,6 +2192,13 @@
 			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
@@ -2205,7 +2249,7 @@
 	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;
@@ -2239,6 +2283,16 @@
 	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;

@italoghost
Copy link

@rharish101 thank you!

@rharish101
Copy link

rharish101 commented Sep 2, 2024

@matoro I tested these patches with the Xbox 360 wireless controller, and they don't work. Specifically, if I use this repo with the master branch, I'm able to detect presses on both the Vader 4 and the 360 wireless with evtest, whereas with the both the latest and the previous (the one with extra_buttons=1) patches, the 360 wireless is shown, but no events are detected at all, while the Vader 4 fully works. In other words, this breaks support for the Xbox 360 wireless controller.

@matoro
Copy link

matoro commented Sep 2, 2024

@matoro I tested these patches with the Xbox 360 wireless controller, and they don't work. Specifically, if I use this repo with the master branch, I'm able to detect presses on both the Vader 4 and the 360 wireless with evtest, whereas with the both the latest and the previous (the one with extra_buttons=1) patches, the 360 wireless is shown, but no events are detected at all, while the Vader 4 fully works. In other words, this breaks support for the Xbox 360 wireless controller.

Hmmm, that's disappointing - I only have a 360 wired controller, and I just tested - when plugging them both in I still get the correct events from both controllers. I tested switching the order that I plugged them in, and I also tested both on my Gentoo system (where I directly patch the kernel) and my Arch system (where I patch this DKMS module), and I was still able to read events from both controllers correctly on both systems.

The only part I can imagine might be a problem would be:

+	if (data[1] < 20)
+		return;

According to the code, the 360 wireless supposedly uses a completely different codepath, but maybe that's obsolete? Can you try removing that snippet and see if it fixes it?

@rharish101
Copy link

rharish101 commented Sep 4, 2024

The only part I can imagine might be a problem would be:

+	if (data[1] < 20)
+		return;

According to the code, the 360 wireless supposedly uses a completely different codepath, but maybe that's obsolete? Can you try removing that snippet and see if it fixes it?

Yup, that fixed it! Thanks @matoro.

For anyone patching xpad-dkms-git, here's the updated flydigi-vader-3.patch file:

diff '--color=auto' -ura package.orig/xpad.c package.new/xpad.c
--- package.orig/xpad.c	2024-09-01 11:37:56.038131642 +0200
+++ package.new/xpad.c	2024-09-01 11:43:02.030156284 +0200
@@ -87,6 +87,9 @@
 #define MAP_STICKS_TO_NULL		(1 << 2)
 #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)
 
@@ -393,6 +396,19 @@
 	{ 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 */
@@ -456,6 +472,13 @@
 	{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, /* C, Z 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
@@ -893,6 +916,7 @@
  *
  *	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,
@@ -965,6 +991,17 @@
 		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_HAPPY9, data[19] & BIT(0));   // C
+		input_report_key(dev, BTN_TRIGGER_HAPPY10, data[19] & BIT(1));  // Z
+		input_report_key(dev, BTN_TRIGGER_HAPPY5, data[19] & BIT(3));   // Leftmost paddle (M2)
+		input_report_key(dev, BTN_TRIGGER_HAPPY6, data[19] & BIT(5));   // Second to leftmost (M4)
+		input_report_key(dev, BTN_TRIGGER_HAPPY7, data[19] & BIT(4));   // Second to rightmost (M3)
+		input_report_key(dev, BTN_TRIGGER_HAPPY8, 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 */
@@ -2155,6 +2192,13 @@
 			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
@@ -2205,7 +2249,7 @@
 	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;
@@ -2239,6 +2283,16 @@
 	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;

And here's the diff for the PKGBUILD:

diff --git a/PKGBUILD b/PKGBUILD
index 8fc9745..7f04d5b 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -14,14 +14,20 @@ makedepends=('git')
 conflicts=("${_pkgname}-dkms")
 source=("${pkgname}::git+https://github.com/paroj/xpad.git"
         "xpad.conf"
-        "${pkgname}.install")
+        "${pkgname}.install"
+        "flydigi-vader-3.patch")
 md5sums=('SKIP'
          '4218c9543d551377825392295544c3c2'
-         '75cad51dc48d8fa879f926432beabf66')
+         '75cad51dc48d8fa879f926432beabf66'
+         'ca0b0def477d96bf772ee7cde86931e5')
 pkgver() {
   cd "$pkgname"
   printf "0.4.%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short=7 HEAD)"
 }
+prepare() {
+    cd "$pkgname"
+    patch -p1 -i ../flydigi-vader-3.patch
+}
 package() {
     # install depmod config file so our driver gets higher priority than the intree module
     install -dm 755 "$pkgdir/etc/depmod.d"

@matoro
Copy link

matoro commented Sep 5, 2024

Okay, thanks. Let's drop that commit then; clearly the claim it made (that valid packets are always at least 20 bytes) is wrong.

After some research I have gotten the paddles recognized in Steam in the input test at least, though I can't really find any meaningful way to remap them, but this may just be my unfamiliarity with how Steam does remapping. The menus are confusing.

To add it, take the mapping string you get from sdl2-jstest --list and add the following string to it: paddle1:b13,paddle2:b11,paddle3:b14,paddle4:b12, and set that as the SDL_GAMECONTROLLERCONFIG environment variable. For example, for Vader 3, will need to adjust for Vader 4:

SDL_GAMECONTROLLERCONFIG="030081b85e0400008e02000004010000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,paddle1:b13,paddle2:b11,paddle3:b14,paddle4:b12,platform:Linux,"

After that Steam calls the back paddles L4, L5, R4, R5 respectively. I looked into the face buttons as well, but it seems in SDL2 there's literally no room for them. You can map one to misc1 I guess, and maybe one to the touchpad, but that's the best you're gonna get:

/**
 * The list of buttons available from a controller
 */
typedef enum SDL_GameControllerButton
{
    SDL_CONTROLLER_BUTTON_INVALID = -1,
    SDL_CONTROLLER_BUTTON_A,
    SDL_CONTROLLER_BUTTON_B,
    SDL_CONTROLLER_BUTTON_X,
    SDL_CONTROLLER_BUTTON_Y,
    SDL_CONTROLLER_BUTTON_BACK,
    SDL_CONTROLLER_BUTTON_GUIDE,
    SDL_CONTROLLER_BUTTON_START,
    SDL_CONTROLLER_BUTTON_LEFTSTICK,
    SDL_CONTROLLER_BUTTON_RIGHTSTICK,
    SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
    SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
    SDL_CONTROLLER_BUTTON_DPAD_UP,
    SDL_CONTROLLER_BUTTON_DPAD_DOWN,
    SDL_CONTROLLER_BUTTON_DPAD_LEFT,
    SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
    SDL_CONTROLLER_BUTTON_MISC1,    /* Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button */
    SDL_CONTROLLER_BUTTON_PADDLE1,  /* Xbox Elite paddle P1 (upper left, facing the back) */
    SDL_CONTROLLER_BUTTON_PADDLE2,  /* Xbox Elite paddle P3 (upper right, facing the back) */
    SDL_CONTROLLER_BUTTON_PADDLE3,  /* Xbox Elite paddle P2 (lower left, facing the back) */
    SDL_CONTROLLER_BUTTON_PADDLE4,  /* Xbox Elite paddle P4 (lower right, facing the back) */
    SDL_CONTROLLER_BUTTON_TOUCHPAD, /* PS4/PS5 touchpad button */
    SDL_CONTROLLER_BUTTON_MAX
} SDL_GameControllerButton;

It looks like upstream they have added many more misc buttons starting in libsdl-org/SDL@cb70e97 , but it's not backported, i.e. these will only be available in SDL3, which is not released yet, might never will be, and even if it is most apps will never move to it. So hopeless essentially.

@zer0exia
Copy link

Thank you for the patch @matoro and others who helped here. Can't really help since I'm not a dev, but I'll be following the thread by providing feedback and reports. Shame to hear about the extra misc button. However, I can see that the extra CZ face buttons are detected in Input-Remapper, but Steam Input and AntiMicroX didn't detect them. I'm not sure what's different.

After some research I have gotten the paddles recognized in Steam in the input test at least, though I can't really find any meaningful way to remap them, but this may just be my unfamiliarity with how Steam does remapping. The menus are confusing.

It's not you, it's the same problem Elite controller users had in the past, (I'm not entirely how was it resolved). For example : ValveSoftware/steam-for-linux#9310

Comparing the screenshots in that issue thread and vader 3 pro here :

steaminput1
Paddle buttons can be used if it's already mapped to something by a template

steaminput2
We can't map the buttons themselves since the UI isn't there

Unfortunately since this problem is probably from SteamInput's side, the only solution like @krasmazov483 mentioned above is either by using existing premade configs by other users or wait until Valve allows the extra buttons remapping for non-official third party controllers.

intel-lab-lkp pushed a commit to intel-lab-lkp/linux that referenced this pull request Oct 21, 2024
This adds a framework for supporting additional features on devices
piggybacking an existing USB vendor/product ID but distinguishing
themselves via the idProduct field.  This is necessary because the
Flydigi Vader Pro series controllers reuse the same vendor/product ID as
orginal Microsoft Xbox 360 controllers.

The MAP_FLYDIGI_BUTTONS is a new mapping for the C, Z, and Circle face
buttons on Flydigi 360-compatible controllers.  It has been tested on
the Vader 3 Pro and Vader 4 Pro.

These controllers additionally have 4 back paddles, same as the Xbox
Elite controller, so it is included in the extra feature list.

Thanks-to: Matthew Carter <[email protected]>
See: paroj/xpad#268
Signed-off-by: Matoro Mahri <[email protected]>
@cprn
Copy link

cprn commented Nov 26, 2024

Updated patch files for current xpad-dkms-git AUR package below (only 1st chunk changed, MAP_PROFILE_BUTTON is declared in master now).

PKGBUILD.patch:

diff --git a/PKGBUILD b/PKGBUILD
index 8fc9745..7f04d5b 100644
--- a/xpad-dkms-git/PKGBUILD
+++ b/xpad-dkms-git/PKGBUILD
@@ -14,14 +14,20 @@ makedepends=('git')
 conflicts=("${_pkgname}-dkms")
 source=("${pkgname}::git+https://github.com/paroj/xpad.git"
         "xpad.conf"
-        "${pkgname}.install")
+        "${pkgname}.install"
+        "flydigi-vader-3.patch")
 md5sums=('SKIP'
          '4218c9543d551377825392295544c3c2'
-         '75cad51dc48d8fa879f926432beabf66')
+         '75cad51dc48d8fa879f926432beabf66'
+         '14e711b57a33d915d3dd2a96a49a9ec5')
 pkgver() {
   cd "$pkgname"
   printf "0.4.%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short=7 HEAD)"
 }
+prepare() {
+    cd "$pkgname"
+    patch -p1 -i ../flydigi-vader-3.patch
+}
 package() {
     # install depmod config file so our driver gets higher priority than the intree module
     install -dm 755 "$pkgdir/etc/depmod.d"

flydigi-vader-3.patch:

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, /* C, Z 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_HAPPY9, data[19] & BIT(0));   // C
+		input_report_key(dev, BTN_TRIGGER_HAPPY10, data[19] & BIT(1));  // Z
+		input_report_key(dev, BTN_TRIGGER_HAPPY5, data[19] & BIT(3));   // Leftmost paddle (M2)
+		input_report_key(dev, BTN_TRIGGER_HAPPY6, data[19] & BIT(5));   // Second to leftmost (M4)
+		input_report_key(dev, BTN_TRIGGER_HAPPY7, data[19] & BIT(4));   // Second to rightmost (M3)
+		input_report_key(dev, BTN_TRIGGER_HAPPY8, 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;

@Fabianoshz
Copy link

In case anyone want to be able to map the back buttons directly on steam I've been "faking" the vader pro 4 as a xbox elite for the past few weeks.

I've used this incredible project: https://github.com/ShadowBlip/InputPlumber

All I had to do was add this patch to it:

diff --git a/src/input/event/evdev.rs b/src/input/event/evdev.rs
index 534373a..ea57e98 100644
--- a/src/input/event/evdev.rs
+++ b/src/input/event/evdev.rs
@@ -160,6 +160,12 @@ impl EvdevEvent {
                 KeyCode::BTN_START => Capability::Gamepad(Gamepad::Button(GamepadButton::Start)),
                 KeyCode::BTN_SELECT => Capability::Gamepad(Gamepad::Button(GamepadButton::Select)),
                 KeyCode::BTN_MODE => Capability::Gamepad(Gamepad::Button(GamepadButton::Guide)),
+                KeyCode::BTN_TRIGGER_HAPPY5 => Capability::Gamepad(Gamepad::Button(GamepadButton::LeftPaddle2)),
+                KeyCode::BTN_TRIGGER_HAPPY6 => Capability::Gamepad(Gamepad::Button(GamepadButton::LeftPaddle1)),
+                KeyCode::BTN_TRIGGER_HAPPY7 => Capability::Gamepad(Gamepad::Button(GamepadButton::RightPaddle1)),
+                KeyCode::BTN_TRIGGER_HAPPY8 => Capability::Gamepad(Gamepad::Button(GamepadButton::RightPaddle2)),
+                KeyCode::BTN_TRIGGER_HAPPY9 => Capability::Gamepad(Gamepad::Button(GamepadButton::LeftPaddle3)),
+                KeyCode::BTN_TRIGGER_HAPPY10 => Capability::Gamepad(Gamepad::Button(GamepadButton::RightPaddle3)),
                 KeyCode::BTN_THUMBL => {
                     Capability::Gamepad(Gamepad::Button(GamepadButton::LeftStick))
                 }

Then I can configure it to create a virtual device simulating the xbox elite for me with these configs:

Device:

# yaml-language-server: $schema=https://raw.githubusercontent.com/ShadowBlip/InputPlumber/main/rootfs/usr/share/inputplumber/schema/composite_device_v1.json
# Schema version number
version: 1

# The type of configuration schema
kind: CompositeDevice

# Name of the composite device mapping
name: flydigi-vader-4-pro

# Only use this profile if *any* of the given matches matches. If this list is
# empty,then the source devices will *always* be checked.
# /sys/class/dmi/id/product_name
matches: []

# Only allow a single source device per composite device of this type.
single_source: true

# One or more source devices to combine into a single virtual device. The events
# from these devices will be watched and translated according to the key map.
source_devices:
  - group: gamepad
    unique: true
    evdev:
      vendor_id: "045e"
      product_id: "028e"
      handler: event*

# The target input device(s) that the virtual device profile can use
target_devices:
  - xbox-elite

capability_map_id: flydigi-vader-4-pro

options:
  auto_manage: true

Capability map:

# yaml-language-server: $schema=https://raw.githubusercontent.com/ShadowBlip/InputPlumber/main/rootfs/usr/share/inputplumber/schema/capability_map_v1.json
# Schema version number
version: 1

# The type of configuration schema
kind: CapabilityMap

# Name for the device event map
name: flydigi-vader-4-pro

# Unique identifier of the capability mapping
id: flydigi-vader-4-pro

# List of mapped events that are activated by a specific set of activation keys.
mapping:

# List of events to filter from the source devices
filtered_events: []

This will make steam see 2 controllers, a xbox 360 and a xbox elite but only the elite will work, you can hide the xbox 360 from steam by adding the text below to ~/.local/share/Steam/config/config.vdf inside the main {} block:

"controller_blacklist"          "045e/028e"

But keep in mind that if you do this Steam will no longe see any other xbox 360 controller.

@paroj paroj force-pushed the master branch 4 times, most recently from b27afdf to 65a9164 Compare January 5, 2025 19:20
@izaac
Copy link

izaac commented Feb 27, 2025

This is amazing, thanks for the effort guys.

@kaibagley
Copy link

Hey everyone, this is the first time patching a package, and I'm unable to get my 4 Pro extra buttons working...

  1. Clone the xpad-dkms-git aur package
  2. Add the most recent PKGBUILD.patch and flydigi-vader-3.patch to the base dir of the cloned repo
  3. Run patch -Np1 -i PKGBUILD.patch and apply it to PKGBUILD
  4. Update checksums using updpkgsums to ensure the checksums int PKGBUILD are correct
  5. Build and install using makepkg -si
  6. sudo modprobe xpad
  7. jstest /dev/inputs/js0 doesn't show any of the paddle buttons working

Sorry if I'm missing something obvious here, and thanks for the help

@matoro
Copy link

matoro commented Mar 1, 2025

Hey everyone, this is the first time patching a package, and I'm unable to get my 4 Pro extra buttons working...

1. Clone the `xpad-dkms-git` aur package

2. Add the most recent `PKGBUILD.patch` and `flydigi-vader-3.patch` to the base dir of the cloned repo

3. Run `patch -Np1 -i PKGBUILD.patch` and apply it to `PKGBUILD`

4. Update checksums using `updpkgsums` to ensure the checksums int `PKGBUILD` are correct

5. Build and install using `makepkg -si`

6. `sudo modprobe xpad`

7. `jstest /dev/inputs/js0` doesn't show any of the paddle buttons working

Sorry if I'm missing something obvious here, and thanks for the help

Are the extra buttons registered, but not responding to keypresses? Or do they not show up at all? What about after a reboot?

@kaibagley
Copy link

kaibagley commented Mar 1, 2025

Thanks for the reply, I re-did the process above and rebooted, and now it's all working fine.. I must've botched a step somewhere. Sorry to bother you!

Now that the buttons register, how should I be binding them? Games don't seem to pick the paddles up. I know this is off-topic for the PR, but you guys are very knowledgeable. Thanks for any help you can give

@matoro
Copy link

matoro commented Mar 1, 2025

Thanks for the reply, I re-did the process above and rebooted, and now it's all working fine.. I must've botched a step somewhere. Sorry to bother you!

Now that the buttons register, how should I be binding them? Games don't seem to pick the paddles up. I know this is off-topic for the PR, but you guys are very knowledgeable. Thanks for any help you can give

python-evdev is my tool of choice! You can use my macros for Elden Ring to get an idea of how to use it: https://gist.github.com/matoro/f741bca73b7a9ff94abc0c4af5065d58

@kaibagley
Copy link

python-evdev is my tool of choice! You can use my macros for Elden Ring to get an idea of how to use it: https://gist.github.com/matoro/f741bca73b7a9ff94abc0c4af5065d58

Is it possible to have the paddle buttons appear as a separate input in games? Rather than having them act as macros?

@Gotolei
Copy link

Gotolei commented Mar 2, 2025

Is it possible to have the paddle buttons appear as a separate input in games? Rather than having them act as macros?

Python-evdev looks flexible enough to just do normal button presses as well, but for something a lot simpler to set up I've been using qjoypad.

@kaibagley
Copy link

Cool, can get the paddle buttons remapped to mouse or keyboard inputs which work fine. Thanks guys!

Going by the messages in this PR, I'm guessing there's still no way to have Steam recognise them as seperate gamepad inputs? They appear in the controller settings menus, but I can't map them to anything that a Proton game will recognise

@Fabianoshz
Copy link

@kaibagley you can create a virtual controller simulating a xbox elite controller, I'm using InputPlumber for that. I've created a PR here so it should work OOTB when they merge it. You can also follow these instructions to add the necessary config files in case you don't want to wait.

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.