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.

@krasmazov483
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).

@italoghost
Copy link

Hi, everyone! I am thinking about using this PR and I would like to know which is the best approach: install xpad with the patches from this PR or install the xpad-dkms-git from the AUR and patch the Kernel with @matoro's code. What would you suggest?

FWIW, I know that both approaches work. I do the former on my Gentoo desktop and the latter on my Arch laptop, and they both work.

Also, I used https://github.com/ava1ar/customizepkg for automatically applying the patch to xpad-dkms-git on rebuild on Arch. Gentoo supports applying patches natively.

Thanks! I took the approach taken by @rharish101 and it worked flawlessly! I just wanted to be able to remap the buttons in a easier way. Isn't there a option to make Steam recognize it as a Elite Controller?

@Jimbleton115
Copy link

I was using this for a while and I know for a fact that steam was detecting the back buttons, but I had to remap them manually by going through the controller config files as the configurator wasn't recognizing them. Now, however, steam doesn't detect the buttons at all... I know the driver is still working as the buttons show up in HTML gamepad tester, so i don't know what happened. Maybe a steam update borked it?

@martindmtrv
Copy link

FWIW I had forked @ahungry kernel module some time ago for vader 3 pro and got it to show up in steam as an xbox elite controller so the paddles can be remapped there

https://github.com/martindmtrv/vader3/tree/steamdeck

This does work for me I'm still using it today with my vader 3 pro on my steam deck

Still it's not the cleanest solution, I think we would need to map it into xpadneo to get all the features that they have there (like vibration and such)

The maintainer there gave some idea of how we can effectively do this,

ahungry/vader3#2 (comment)

We need to map the rawhid output from the controller to match what is expected for an xbox controller, then it could be supported in xpadneo

@martindmtrv
Copy link

Though, there are some weird things with this controller that don't work exactly. Getting the paddles to appear under linux involves using the controller in android mode, and android mode supposedly does not support vibration according to the discussion here from @kakra (xpadneo maintainer):

Yes, there is no rumble function in the descriptor. Report 1 is a report that sends data from the device to the computer. You cannot use it in the other direction. As you can see, the other docs have Output in the description, which describes data being sent from the computer to the device. Rumble reports could be detected by looking at the description of output values 0..100 repeated at least 2 times (main motor, weak motor, but left and right trigger motor is also supported) and 3 timings (attack, sustain, release in units of 10^-2 seconds). Also, it's defined in another usage page.

Is there anything that can be done (doing some offset in this report_id to the right area?) - or is this output indicative of a lack of support at the hardware level for rumble over bluetooth?

There's no such thing as a fantasy offset into the report. The report clearly defines report sizes (in bits) and report counts for different usages (buttons, axes, ...) and a communication direction (input to the host, output from the host). Each of those report usage definitions (sizes, counts) accounts for the offset into the report.

And yes, this means: no rumble for this controller in Bluetooth mode...

atar-axis/xpadneo#451 (comment)

@matoro
Copy link

matoro commented Aug 25, 2024

FWIW I had forked @ahungry kernel module some time ago for vader 3 pro and got it to show up in steam as an xbox elite controller so the paddles can be remapped there

https://github.com/martindmtrv/vader3/tree/steamdeck

This does work for me I'm still using it today with my vader 3 pro on my steam deck

Still it's not the cleanest solution, I think we would need to map it into xpadneo to get all the features that they have there (like vibration and such)

The maintainer there gave some idea of how we can effectively do this,

ahungry/vader3#2 (comment)

We need to map the rawhid output from the controller to match what is expected for an xbox controller, then it could be supported in xpadneo

All of this is for dinput mode right? The point of this PR is to get the extra buttons under xinput mode, so that we don't have to worry about losing vibration etc.

At least under xinput mode it looks like there is no way to distinguish the Vader from a wired 360 controller as it presents identically.

@italoghost
Copy link

I was testing some things with this PR and after searching I came across with this discussion on reddit which one of the participants probably is @ahungry.

They managed to make Steam recognize the buttons by forcefully setting a SDL_GAMECONTROLLERCONFIG after installing the drivers from this PR.

I tested myself, by putting the following environment variable on /etc/environment:

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

It worked for the paddles! Steam recognized them, but didn't let me remap them per game, so it wasn't the solution that I was expecting.

Then I found this tool called input-remapper. With it, I was able to remap all the additional buttons, even making combination of buttons!

Maybe it can be of some help for you!

@kakra
Copy link

kakra commented Aug 26, 2024

It might be worth adding an evemu-describe record to the SDL project issues so this device can be properly detected. Then after it has been integrated into SDL, SDL_GAMECONTROLLERCONFIG may not be needed any longer.

@matoro
Copy link

matoro commented Aug 26, 2024

It might be worth adding an evemu-describe record to the SDL project issues so this device can be properly detected. Then after it has been integrated into SDL, SDL_GAMECONTROLLERCONFIG may not be needed any longer.

This was actually a good clue. I thought that if it was identical to a 360 controller then that SDL_GAMECONTROLLERCONFIG GUID string would be the same, but it's not. Looking in the SDL source code, it seems they pull this out of udev, and udev seems to be correctly identifying all the information:

$ udevadm info --no-pager /dev/input/by-id/usb-Flydigi_Flydigi_VADER3_Flydigi_VADER3-joystick
P: /devices/pci0000:00/0000:00:01.2/0000:02:00.0/0000:03:08.0/0000:08:00.1/usb1/1-1/1-1:1.0/input/input110/js0
M: js0
R: 0
U: input
D: c 13:0
N: input/js0
L: 0
S: input/by-path/pci-0000:08:00.1-usbv2-0:1:1.0-joystick
S: input/by-id/usb-Flydigi_Flydigi_VADER3_Flydigi_VADER3-joystick
S: input/by-path/pci-0000:08:00.1-usb-0:1:1.0-joystick
E: DEVPATH=/devices/pci0000:00/0000:00:01.2/0000:02:00.0/0000:03:08.0/0000:08:00.1/usb1/1-1/1-1:1.0/input/input110/js0
E: DEVNAME=/dev/input/js0
E: MAJOR=13
E: MINOR=0
E: SUBSYSTEM=input
E: USEC_INITIALIZED=425423507609
E: ID_INPUT=1
E: ID_INPUT_JOYSTICK=1
E: ID_BUS=usb
E: ID_MODEL=Flydigi_VADER3
E: ID_MODEL_ENC=Flydigi\x20VADER3
E: ID_MODEL_ID=028e
E: ID_SERIAL=Flydigi_Flydigi_VADER3_Flydigi_VADER3
E: ID_SERIAL_SHORT=Flydigi_VADER3
E: ID_VENDOR=Flydigi
E: ID_VENDOR_ENC=Flydigi
E: ID_VENDOR_ID=045e
E: ID_REVISION=0104
E: ID_TYPE=generic
E: ID_USB_MODEL=Flydigi_VADER3
E: ID_USB_MODEL_ENC=Flydigi\x20VADER3
E: ID_USB_MODEL_ID=028e
E: ID_USB_SERIAL=Flydigi_Flydigi_VADER3_Flydigi_VADER3
E: ID_USB_SERIAL_SHORT=Flydigi_VADER3
E: ID_USB_VENDOR=Flydigi
E: ID_USB_VENDOR_ENC=Flydigi
E: ID_USB_VENDOR_ID=045e
E: ID_USB_REVISION=0104
E: ID_USB_TYPE=generic
E: ID_USB_INTERFACES=:ff5d01:ff5d03:ff5d02:fffd13:
E: ID_USB_INTERFACE_NUM=00
E: ID_USB_DRIVER=xpad
E: ID_PATH_WITH_USB_REVISION=pci-0000:08:00.1-usbv2-0:1:1.0
E: ID_PATH=pci-0000:08:00.1-usb-0:1:1.0
E: ID_PATH_TAG=pci-0000_08_00_1-usb-0_1_1_0
E: ID_FOR_SEAT=input-pci-0000_08_00_1-usb-0_1_1_0
E: DEVLINKS=/dev/input/by-path/pci-0000:08:00.1-usbv2-0:1:1.0-joystick /dev/input/by-id/usb-Flydigi_Flydigi_VADER3_Flydigi_VADER3-joystick /dev/input/by-path/pci-0000:08:00.1-usb-0:1:1.0-joystick
E: TAGS=:seat:uaccess:
E: CURRENT_TAGS=:seat:uaccess:

I do not understand how udev is able to get this information, but e.g. lsusb is not.

@Jimbleton115
Copy link

I was testing some things with this PR and after searching I came across with this discussion on reddit which one of the participants probably is @ahungry.

They managed to make Steam recognize the buttons by forcefully setting a SDL_GAMECONTROLLERCONFIG after installing the drivers from this PR.

I tested myself, by putting the following environment variable on /etc/environment:

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

It worked for the paddles! Steam recognized them, but didn't let me remap them per game, so it wasn't the solution that I was expecting.

Then I found this tool called input-remapper. With it, I was able to remap all the additional buttons, even making combination of buttons!

Maybe it can be of some help for you!

this is what i originally did to allow me to map the extra buttons in steam. i figured out what my particular issue was from this, though; turns out that steam was now recognizing the controller under the name Atari Xbox 360 Game Controller, so my previous SDL_GAMECONTROLLERCONFIG wasn't working. After some editing and rebooting it fixed it right up! I might check out input-remapper anyway though, as manually editing steam controller configs is pretty annoying.

@matoro
Copy link

matoro commented Aug 26, 2024

Found out where this is coming from. Seem that in the USB spec, there is a "vendor" field and "manufacturer" field which do not have to be the same. The Vader spoofs Microsoft for the former, but properly populates the latter:

$ lsusb -v -d 045e:028e

Bus 001 Device 061: ID 045e:028e Microsoft Corp. Xbox360 Controller
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass          255 Vendor Specific Class
  bDeviceSubClass       255 Vendor Specific Subclass
  bDeviceProtocol       255 Vendor Specific Protocol
  bMaxPacketSize0         8
  idVendor           0x045e Microsoft Corp.
  idProduct          0x028e Xbox360 Controller
  bcdDevice            1.04
  iManufacturer           1 Flydigi
  iProduct                2 Flydigi VADER3
  iSerial                 3 Flydigi VADER3
  bNumConfigurations      1

It's possible this may allow us to autodetect it and submit a proper upstream patch. I'm looking into it some more.

@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
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.