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

Flydigi Apex 4 support #208

Open
zany130 opened this issue Sep 30, 2024 · 4 comments
Open

Flydigi Apex 4 support #208

zany130 opened this issue Sep 30, 2024 · 4 comments
Labels
enhancement New feature or request hardware support This issue requests adding new hardware of fixing a bug with existing hardware

Comments

@zany130
Copy link

zany130 commented Sep 30, 2024

As previously discussed on discord, this is to track adding support to the Flydigi Apex 4 controller

Relevant discussions and dumps can be found here:

hhd-dev/hhd#73

libsdl-org/SDL#10161

https://github.com/zany130/hwinfo/tree/master/devices/Apex4

@ShadowApex ShadowApex added the enhancement New feature or request label Sep 30, 2024
@pastaq pastaq added the hardware support This issue requests adding new hardware of fixing a bug with existing hardware label Oct 1, 2024
@Fabianoshz
Copy link

@zany130 I don't know if this helps you but I've managed to make the back buttons of the flydigi work with a set of patches:

  • First I've patched xpad as described here with this code:
diff --git a/xpad.c b/xpad.c
index d5a016e..442809e 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 */
@@ -428,6 +442,13 @@ static const signed short xpad_common_btn[] = {
 	-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 */
+};
+
 /* original xbox controllers only */
 static const signed short xpad_btn[] = {
 	BTN_C, BTN_Z,		/* "analog" buttons */
@@ -1012,6 +1033,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 +2278,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 +2339,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 +2373,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;
  • Then I've patched inputplumber with this:
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))
                 }
  • After that I can use the the controller with:
# 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
# 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: []

@zany130
Copy link
Author

zany130 commented Dec 2, 2024

Oh, interesting! I'll try this out! So, basically, this is patching xpad to support the back buttons of the Apex 4 when in x-input mode and then using input plumber to emulate an elite controller so it shows in Steam?

The only thing missing with this would be gyro and the extra "circle button" (button next to home)

D-input is still probably the better mode to use on Linux. Everything except rumble is already exposed. So I guess the only thing that needs to be done is get input plumber to map everything to a dual sense edge or something

Though rumble would not work

@pastaq
Copy link
Contributor

pastaq commented Dec 2, 2024

What does the home button map to?
Is there another input device exposed for the circle button in xinput mode?
Is there an hidraw device that exposes the gyro events?

@zany130
Copy link
Author

zany130 commented Dec 2, 2024

No the circle button doesn't send anything in x-input mode

The home button maps to the xbox guide button on x-input mode.

on d-input I think it's BTN_GUIDE so guide button also

The rest is all d-input mode

In d-input the circle button sends the right trigger so it might not be possible to map it separately from the the right trigger thinking back on it

The only mode the circle button is sent as its own button is in dual sense mode (windows software only) and switch mode in bothe cases it's mapped to the share/capture button

Gyro is sent in two hidraws.

The flydigi fly mouse (gyro mouse actived by the circle button (in d-input it sends both the right trigger to the OS and internally it also activates the fly mouse) it sent in a separate hidraw from everything else . There are also mouse buttons on this hidraw mapped to two of the back buttons (I think it was the inner two)

There is also what seems to be raw gyro data on the main hidraw were all the other buttons and sticks are , but a gyro mapping (button combo to enable gyro aim in the windows software) has to be set in the software for it to show up. What buttons are mapped do not matter all that matters is that some type of mapping is set.

This should all be documented in handheld dameon doc fork I mentioned in the op

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request hardware support This issue requests adding new hardware of fixing a bug with existing hardware
Projects
None yet
Development

No branches or pull requests

4 participants