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

[Feature request] Support 3rd party controllers that have extra buttons + gyro #73

Open
yoyossef opened this issue Jun 19, 2024 · 47 comments

Comments

@yoyossef
Copy link

First of all thank you for doing all of this, it looks like a really neat project, I'm soon receiving my GPD Win Max 2 and I can't wait to use this in gamemode.

Unfortunately exposing gyro, and paddle inputs across Steam is not only an issue on the handhelds you guys support.
Controllers like the Flydigi Apex 4 have 4 paddles, and gyro support that can't be exploited on Linux under gamemode. Not only because the drivers aren't supporting everything but also because Steam isn't letting us exploiting it.

I know this is not necessarily the scope of the project but the aim goal seem really close to what I want to achieve, I'd imagine the drivers for all the handhelds don't support everything all at once, so fixing all of this in the userspace + mocking it as a Dualsense Edge and/or Xbox Elite controller is a superb solution.

Would you think it'd be possible? Any hints on where I should start looking to expose my controller to hhd to enable controller mocks?

Thanks.

@yoyossef yoyossef changed the title [Feature request] Support 3rd party controllers [Feature request] Support 3rd party controllers that have extra buttons + gyro Jun 19, 2024
@antheas
Copy link
Collaborator

antheas commented Jun 19, 2024

Check your controllers with hhd.contrib hidraw to see if you can see the gyro or paddles somewhere. Also try all different modes they have. For gyro, there's usually a switch mode that is switch only but you can trick it into activating.

@yoyossef
Copy link
Author

yoyossef commented Jun 19, 2024

@antheas So the Apex 4 has many modes, let's focus on the ones available when the controller is connected wired via USB: Switch and PC: XInput, DInput

Switch

hhd.contrib hidraw
/dev/hidraw8    057e:2009: Usage Page: 0x0009 Usage: 0x0001 Names 'Nintendo Co., Ltd.': 'Pro Controller'
[...]
   387:   3.0961 30ce91008000f11780f1178009dbfffafff10efbfffeff0200dbfffaffff0efaff0000fefff7fff3ff100ffbff0100ffff000000000000000000000000000000
   388:   3.1040 30d091008000f00780f007800a0400f9ff0f0ffdff0300ffff0700faff020ffaff00000300dbfffafff10efbfffeff0200000000000000000000000000000000
[...]
=> So many events captured maybe because of the gyro, the poll rate seems too high to read it. This mode on Steam is recognized as an actual Switch controller and the Gyro functions is working.
hhd.contrib evdev
device /dev/input/event25, name "Nintendo Co., Ltd. Pro Controller", phys "usb-0000:64:00.3-1.3.2.3/input0"

{('EV_SYN', 0): [('SYN_REPORT', 0), ('SYN_CONFIG', 1), ('SYN_DROPPED', 3), ('?', 21)], ('EV_KEY', 1): [(['BTN_A', 'BTN_GAMEPAD', 'BTN_SOUTH'], 304), (['BTN_B', 'BTN_EAST'], 305), (['BTN_NORTH', 'BTN_X'], 307), (['BTN_WEST', 'BTN_Y'], 308), ('BTN_Z', 309), ('BTN_TL', 310), ('BTN_TR', 311), ('BTN_TL2', 312), ('BTN_TR2', 313), ('BTN_SELECT', 314), ('BTN_START', 315), ('BTN_MODE', 316), ('BTN_THUMBL', 317), ('BTN_THUMBR', 318)], ('EV_ABS', 3): [(('ABS_X', 0), AbsInfo(value=-175, min=-32767, max=32767, fuzz=250, flat=500, resolution=0)), (('ABS_Y', 1), AbsInfo(value=0, min=-32767, max=32767, fuzz=250, flat=500, resolution=0)), (('ABS_RX', 3), AbsInfo(value=-175, min=-32767, max=32767, fuzz=250, flat=500, resolution=0)), (('ABS_RY', 4), AbsInfo(value=0, min=-32767, max=32767, fuzz=250, flat=500, resolution=0)), (('ABS_HAT0X', 16), AbsInfo(value=0, min=-1, max=1, fuzz=0, flat=0, resolution=0)), (('ABS_HAT0Y', 17), AbsInfo(value=0, min=-1, max=1, fuzz=0, flat=0, resolution=0))], ('EV_FF', 21): [(['FF_EFFECT_MIN', 'FF_RUMBLE'], 80), ('FF_PERIODIC', 81), (['FF_SQUARE', 'FF_WAVEFORM_MIN'], 88), ('FF_TRIANGLE', 89), ('FF_SINE', 90), (['FF_GAIN', 'FF_MAX_EFFECTS'], 96)]}

=> No paddle support but an extra button seems to work (309 button "BTN_Z")

XInput

hhd.contrib hidraw

No entry found so couldn't capture anything.

hhd.contrib evdev
└─╼ hhd.contrib evdev
Available Devices with the Current Permissions
device /dev/input/event25, name "Microsoft X-Box 360 pad", phys "usb-0000:64:00.3-1.3.2.3/input0"
Capabilities
{('EV_SYN', 0): [('SYN_REPORT', 0), ('SYN_CONFIG', 1), ('SYN_DROPPED', 3), ('?', 21)], ('EV_KEY', 1): [(['BTN_A', 'BTN_GAMEPAD', 'BTN_SOUTH'], 304), (['BTN_B', 'BTN_EAST'], 305), (['BTN_NORTH', 'BTN_X'], 307), (['BTN_WEST', 'BTN_Y'], 308), ('BTN_TL', 310), ('BTN_TR', 311), ('BTN_SELECT', 314), ('BTN_START', 315), ('BTN_MODE', 316), ('BTN_THUMBL', 317), ('BTN_THUMBR', 318)], ('EV_ABS', 3): [(('ABS_X', 0), AbsInfo(value=6, min=-32768, max=32767, fuzz=16, flat=128, resolution=0)), (('ABS_Y', 1), AbsInfo(value=5, min=-32768, max=32767, fuzz=16, flat=128, resolution=0)), (('ABS_Z', 2), AbsInfo(value=0, min=0, max=255, fuzz=0, flat=0, resolution=0)), (('ABS_RX', 3), AbsInfo(value=6, min=-32768, max=32767, fuzz=16, flat=128, resolution=0)), (('ABS_RY', 4), AbsInfo(value=-7, min=-32768, max=32767, fuzz=16, flat=128, resolution=0)), (('ABS_RZ', 5), AbsInfo(value=0, min=0, max=255, fuzz=0, flat=0, resolution=0)), (('ABS_HAT0X', 16), AbsInfo(value=0, min=-1, max=1, fuzz=0, flat=0, resolution=0)), (('ABS_HAT0Y', 17), AbsInfo(value=0, min=-1, max=1, fuzz=0, flat=0, resolution=0))], ('EV_FF', 21): [(['FF_EFFECT_MIN', 'FF_RUMBLE'], 80), ('FF_PERIODIC', 81), (['FF_SQUARE', 'FF_WAVEFORM_MIN'], 88), ('FF_TRIANGLE', 89), ('FF_SINE', 90), (['FF_GAIN', 'FF_MAX_EFFECTS'], 96)]}
=> As expected only the basic Xbox 360 buttons events are seen

dInput

hhd.contrib hidraw
/dev/hidraw8    04b4:2412: Usage Page: 0x0001 Usage: 0x0005 Names 'Flydigi': 'Flydigi APEX 4'
/dev/hidraw9    04b4:2412: Usage Page: 0x0001 Usage: 0x0001 Names 'Flydigi': 'Flydigi APEX 4'
/dev/hidraw10   04b4:2412: Usage Page: 0xffa0 Usage: 0x0001 Names 'Flydigi': 'Flydigi APEX 4'
/dev/hidraw11   04b4:2412: Usage Page: 0xffef Usage: 0x0000 Names 'Flydigi': 'Flydigi APEX 4'

Enter device path (/dev/hidraw# or #): 8

Traceback (most recent call last):
  File "/usr/bin/hhd.contrib", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/usr/lib/python3.12/site-packages/hhd/contrib/main.py", line 27, in main
    hidraw()
  File "/usr/lib/python3.12/site-packages/hhd/contrib/dev.py", line 80, in hidraw
    d = Device(path=sel)
        ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/hhd/controller/lib/hid.py", line 193, in __init__
    raise HIDException("unable to open device")
hhd.controller.lib.hid.HIDException: unable to open device
=> None of the 4 devices can be read in hidraw for some reason.
hhd.contrib evdev
└─╼ hhd.contrib evdev
Available Devices with the Current Permissions
device /dev/input/event25, name "Flydigi Flydigi APEX 4", phys "usb-0000:64:00.3-1.3.2.3/input0"
Capabilities
{('EV_SYN', 0): [('SYN_REPORT', 0), ('SYN_CONFIG', 1), ('SYN_DROPPED', 3), ('?', 4)], ('EV_KEY', 1): [(['BTN_A', 'BTN_GAMEPAD', 'BTN_SOUTH'], 304), (['BTN_B', 'BTN_EAST'], 305), ('BTN_C', 306), (['BTN_NORTH', 'BTN_X'], 307), (['BTN_WEST', 'BTN_Y'], 308), ('BTN_Z', 309), ('BTN_TL', 310), ('BTN_TR', 311), ('BTN_TL2', 312), ('BTN_TR2', 313), ('BTN_SELECT', 314), ('BTN_START', 315), ('BTN_THUMBL', 317), ('BTN_THUMBR', 318), ('?', 319), ('KEY_RED', 398), (['BTN_TRIGGER_HAPPY', 'BTN_TRIGGER_HAPPY1'], 704), ('BTN_TRIGGER_HAPPY2', 705), ('BTN_TRIGGER_HAPPY3', 706), ('BTN_TRIGGER_HAPPY4', 707)], ('EV_ABS', 3): [(('ABS_X', 0), AbsInfo(value=127, min=0, max=255, fuzz=0, flat=15, resolution=0)), (('ABS_Y', 1), AbsInfo(value=127, min=0, max=255, fuzz=0, flat=15, resolution=0)), (('ABS_Z', 2), AbsInfo(value=127, min=0, max=255, fuzz=0, flat=15, resolution=0)), (('ABS_RZ', 5), AbsInfo(value=127, min=0, max=255, fuzz=0, flat=15, resolution=0)), (('ABS_GAS', 9), AbsInfo(value=0, min=0, max=255, fuzz=0, flat=15, resolution=0)), (('ABS_BRAKE', 10), AbsInfo(value=0, min=0, max=255, fuzz=0, flat=15, resolution=0)), (('ABS_HAT0X', 16), AbsInfo(value=0, min=-1, max=1, fuzz=0, flat=0, resolution=0)), (('ABS_HAT0Y', 17), AbsInfo(value=0, min=-1, max=1, fuzz=0, flat=0, resolution=0))], ('EV_MSC', 4): [('MSC_SCAN', 4)]}
=> All the extra buttons seem to work, BTN Z enables a mouse input controlled by the Gyro.

@antheas
Copy link
Collaborator

antheas commented Jun 19, 2024

Xinput does not appear in hidraw and only has the xbox 360 buttons. There is a chance there would be a manufacturer endpoint that shows the extra buttons in hidraw. Are you sure there arent any hidraw pages for xinput?

Dinput appears in hidraw in general. It should only have one node, so thats the only interesting one really.

Try running the command with sudo. Only controllers with rules in linux will work without.

As for switch, its good that gyro works out of the box. But if there are no manufacturer interfaces it will not work.

In general, usage pages starting with 0xff are vendor specific. If the company implements a controller tester for it, it's very likely it will list the buttons there for the tester to work.

@yoyossef
Copy link
Author

yoyossef commented Jun 19, 2024

@antheas

Are you sure there arent any hidraw pages for xinput?

Yes, even tried with sudo, those are the only pages I see when in xinput:

Available Devices with the Current Permissions
/dev/hidraw0    1ea7:0064: Usage Page: 0x0001 Usage: 0x0001 Names 'None': '2.4G Mouse'
/dev/hidraw1    04f3:3231: Usage Page: 0x000d Usage: 0x0022 Names '': 'ELAN06A0:00 04F3:3231'
/dev/hidraw2    056a:52e6: Usage Page: 0x0001 Usage: 0x0001 Names '': 'WACF2200:00 056A:52E6'
/dev/hidraw3    cdcd:8484: Usage Page: 0x0001 Usage: 0x0006 Names 'xiudi': 'XD84'
/dev/hidraw4    cdcd:8484: Usage Page: 0x0001 Usage: 0x0001 Names 'xiudi': 'XD84'
/dev/hidraw5    cdcd:8484: Usage Page: 0x000c Usage: 0x0001 Names 'xiudi': 'XD84'
/dev/hidraw6    cdcd:8484: Usage Page: 0xff31 Usage: 0x0074 Names 'xiudi': 'XD84'
/dev/hidraw7    cdcd:8484: Usage Page: 0x0001 Usage: 0x0006 Names 'xiudi': 'XD84'

Dinput appears in hidraw in general. It should only have one node, so thats the only interesting one really.

Try running the command with sudo. Only controllers with rules in linux will work without.

Okay it works with sudo, I'll put the output for each of the following pages:

/dev/hidraw8    04b4:2412: Usage Page: 0x0001 Usage: 0x0005 Names 'Flydigi': 'Flydigi APEX 4'
/dev/hidraw9    04b4:2412: Usage Page: 0x0001 Usage: 0x0001 Names 'Flydigi': 'Flydigi APEX 4'
/dev/hidraw10   04b4:2412: Usage Page: 0xffa0 Usage: 0x0001 Names 'Flydigi': 'Flydigi APEX 4'
/dev/hidraw11   04b4:2412: Usage Page: 0xffef Usage: 0x0000 Names 'Flydigi': 'Flydigi APEX 4'

Hidraw 8: Usage Page: 0x0001 Usage: 0x0005 500hz

11663:  24.3936 7f7c7f7f8002d80000
 11664:  24.3956 7f7c7f7f8002d80000
 11665:  24.3977 7f7c7f7f8002d80000
 11666:  24.3996 7f7c7f7f8002d80000
 11667:  24.4016 7f7c7f7f8002d80000
 11668:  24.4037 7f7c7f7f8002d80000
 11669:  24.4056 7f7c7f7f8002d80000
 11670:  24.4076 7f7c7f7f8002d80000
 11671:  24.4096 7f7c7f7f8002d80000
 11672:  24.4116 7f7c7f7f8002d80000
 11673:  24.4136 7f7c7f7f8002d80000
 11674:  24.4156 7f7c7f7f8002d80000
 11675:  24.4176 7f7c7f7f8002d80000
 11676:  24.4197 7f7c7f7f8002d80000

This is the page for the regular inputs + extra buttons to be read, all of them affect the value, the Z BTN is a toggle and does not reset its state as it enables the weird gyro mouse thing.

Hidraw 9: Usage Page: 0x0001 Usage: 0x0001 500hz

  5893:  52.5788 02800290ff0000
  5894:  52.5808 02800290ff0000
  5895:  52.5828 02800290ff0000
  5896:  52.5848 02800290ff0000
  5897:  52.5869 028001b0ff0000
  5898:  52.5888 028001b0ff0000
  5899:  52.5908 028001b0ff0000
  5900:  52.5929 028001b0ff0000
  5901:  52.5948 028001b0ff0000
  5902:  52.5968 02800100000000
  5903:  52.5988 02800100000000
  5904:  52.6008 02800100000000
  5905:  52.6028 02800100000000
  5906:  52.6048 02800100000000
  5907:  52.6068 02800010000000
  5908:  52.6088 02800010000000
  5909:  52.6109 02800010000000
  5910:  52.6128 02800010000000
  5911:  52.6148 02800010000000
  5912:  52.6168 02800050000000
  5913:  52.6188 02800050000000
  5914:  52.6208 02800050000000
  5915:  52.6228 02800050000000
  5916:  52.6248 02800050000000
  5917:  52.6268 02800050000000
  5918:  52.6288 02800050000000
  5919:  52.6308 02800050000000

This gives the value of the gyro when the Z BTN has been toggled, no other inputs are read

Hidraw 10: Usage Page: 0xffa0 Usage: 0x0001 500hz

 19458:  40.5988 04fe66000000000000000008000f001c037f007f007f7f000000000054000000
 19459:  40.6008 04fe66000000000000000008000f001c037f007f007f7f000000000054000000
 19460:  40.6028 04fe6600000000000000000c000d0022037f007f007f7f000000000054ffff00
 19461:  40.6048 04fe6600000000000000000c000d0022037f007f007f7f000000000054ffff00
 19462:  40.6068 04fe6600000000000000000c000d0022037f007f007f7f000000000054ffff00
 19463:  40.6088 04fe6600000000000000000c000d0022037f007f007f7f000000000054ffff00
 19464:  40.6108 04fe6600000000000000000c000d0022037f007f007f7f000000000054ffff00
 19465:  40.6128 04fe66000000000000000009000e001d037f007f007f7f000000000054000000
 19466:  40.6148 04fe66000000000000000009000e001d037f007f007f7f000000000054000000
 19467:  40.6168 04fe66000000000000000009000e001d037f007f007f7f000000000054000000
 19468:  40.6188 04fe66000000000000000009000e001d037f007f007f7f000000000054000000
 19469:  40.6208 04fe66000000000000000009000e001d037f007f007f7f000000000054000000
 19470:  40.6228 04fe6600000000000000000b000c0020037f007f007f7f000000000054000000
 19471:  40.6248 04fe6600000000000000000b000c0020037f007f007f7f000000000054000000
 19472:  40.6268 04fe6600000000000000000b000c0020037f007f007f7f000000000054000000
 19473:  40.6288 04fe6600000000000000000b000c0020037f007f007f7f000000000054000000
 19474:  40.6308 04fe6600000000000000000b000c0020037f007f007f7f000000000054000000
 19475:  40.6328 04fe6600000000000000000a000c001d037f007f007f7f000000000054000000
 19476:  40.6348 04fe6600000000000000000a000c001d037f007f007f7f000000000054000000
 19477:  40.6368 04fe6600000000000000000a000c001d037f007f007f7f000000000054000000
 19478:  40.6388 04fe6600000000000000000a000c001d037f007f007f7f000000000054000000
 19479:  40.6408 04fe6600000000000000000a000c001d037f007f007f7f000000000054000000
 19480:  40.6428 04fe6600000000000000000a000d001f037f007f007f7f000000000054000000
 19481:  40.6448 04fe6600000000000000000a000d001f037f007f007f7f000000000054000000
 19482:  40.6468 04fe6600000000000000000a000d001f037f007f007f7f000000000054000000
 19483:  40.6488 04fe6600000000000000000a000d001f037f007f007f7f000000000054000000
 19484:  40.6508 04fe6600000000000000000a000d001f037f007f007f7f000000000054000000
 19485:  40.6528 04fe6600000000000000000b000d001f037f007f007f7f000000000054000000
 19486:  40.6548 04fe6600000000000000000b000d001f037f007f007f7f000000000054000000
 19487:  40.6568 04fe6600000000000000000b000d001f037f007f007f7f000000000054000000
 19488:  40.6588 04fe6600000000000000000b000d001f037f007f007f7f000000000054000000
 19489:  40.6608 04fe6600000000000000000b000d001f037f007f007f7f000000000054000000
 19490:  40.6628 04fe66000000000000000009000c001d037f007f007f7f000000000054ffff00
 19491:  40.6648 04fe66000000000000000009000c001d037f007f007f7f000000000054ffff00
 19492:  40.6668 04fe66000000000000000009000c001d037f007f007f7f000000000054ffff00
 19493:  40.6688 04fe66000000000000000009000c001d037f007f007f7f000000000054ffff00

Looks like it's Hidraw 8 and 9 combined, could see the output for my button/stick inputs and the gyro when the "Z BTN" that enables mouse mode is toggled

Hidraw 11: Usage Page: 0xffef Usage: 0x0000 NA

Couldn't capture anything, idk what its purpose is, nothing logged no matter what I input.

Sidenote:
Also while retrying with sudo I saw another event to capture for DInput in evdev, so the Z BTN seems to enable a mouse mode and some buttons are transformed into mouse clicks (M3 becomes left click for example):

device /dev/input/event26, name "Flydigi Flydigi APEX 4", phys "usb-0000:64:00.3-1.3.2.3/input1"

Enter device path (/dev/input/event# or #): 26

Selected device `device /dev/input/event26, name "Flydigi Flydigi APEX 4", phys "usb-0000:64:00.3-1.3.2.3/input1"`.
Capabilities
{('EV_SYN', 0): [('SYN_REPORT', 0), ('SYN_CONFIG', 1), ('SYN_MT_REPORT', 2), ('?', 4)], ('EV_KEY', 1): [(['BTN_LEFT', 'BTN_MOUSE'], 272), ('BTN_RIGHT', 273), ('BTN_MIDDLE', 274), ('BTN_SIDE', 275), ('BTN_EXTRA', 276)], ('EV_REL', 2): [('REL_X', 0), ('REL_Y', 1), ('REL_WHEEL', 8), ('REL_WHEEL_HI_RES', 11)], ('EV_MSC', 4): [('MSC_SCAN', 4)]}

@antheas
Copy link
Collaborator

antheas commented Jun 19, 2024

For my convenience, what does the kernel register each hidraw as? I edited your comment to emphasize the usage pages.

Use sudo dmesg to find out.

@yoyossef
Copy link
Author

@antheas

[ 5778.995851] hid-generic 0003:04B4:2412.002F: input,hidraw8: USB HID v1.11 Gamepad [Flydigi Flydigi APEX 4] on usb-0000:64:00.3-1.3.2.3/input0
[ 5779.003020] hid-generic 0003:04B4:2412.0030: input,hidraw9: USB HID v1.11 Mouse [Flydigi Flydigi APEX 4] on usb-0000:64:00.3-1.3.2.3/input1
[ 5779.011733] hid-generic 0003:04B4:2412.0031: hiddev98,hidraw10: USB HID v1.11 Device [Flydigi Flydigi APEX 4] on usb-0000:64:00.3-1.3.2.3/input2
[ 5779.020982] hid-generic 0003:04B4:2412.0032: hiddev99,hidraw11: USB HID v1.11 Device [Flydigi Flydigi APEX 4] on usb-0000:64:00.3-1.3.2.3/input3
Full dmesg output
[ 5777.349019] usb 7-1.3.2.3: device descriptor read/64, error -71
[ 5777.606081] usb 7-1.3.2.3: New USB device found, idVendor=04b4, idProduct=2412, bcdDevice= 1.00
[ 5777.606088] usb 7-1.3.2.3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 5777.606092] usb 7-1.3.2.3: Product: Flydigi APEX 4
[ 5777.606094] usb 7-1.3.2.3: Manufacturer: Flydigi
[ 5777.816459] usbhid 7-1.3.2.3:1.0: can't add hid device: -71
[ 5777.837778] usbhid: probe of 7-1.3.2.3:1.0 failed with error -71
[ 5777.846263] usbhid 7-1.3.2.3:1.1: can't add hid device: -71
[ 5777.859488] usbhid: probe of 7-1.3.2.3:1.1 failed with error -71
[ 5777.868440] usbhid 7-1.3.2.3:1.2: can't add hid device: -71
[ 5777.881488] usbhid: probe of 7-1.3.2.3:1.2 failed with error -71
[ 5777.890312] usbhid 7-1.3.2.3:1.3: can't add hid device: -71
[ 5777.903487] usbhid: probe of 7-1.3.2.3:1.3 failed with error -71
[ 5777.905741] usb 7-1.3.2.3: USB disconnect, device number 48
[ 5778.686468] usb 7-1.3.2.3: new full-speed USB device number 49 using xhci_hcd
[ 5778.807075] usb 7-1.3.2.3: New USB device found, idVendor=04b4, idProduct=2412, bcdDevice= 1.00
[ 5778.807087] usb 7-1.3.2.3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 5778.807091] usb 7-1.3.2.3: Product: Flydigi APEX 4
[ 5778.807094] usb 7-1.3.2.3: Manufacturer: Flydigi
[ 5778.995390] input: Flydigi Flydigi APEX 4 as /devices/pci0000:00/0000:00:08.3/0000:64:00.3/usb7/7-1/7-1.3/7-1.3.2/7-1.3.2.3/7-1.3.2.3:1.0/0003:04B4:2412.002F/input/input72
[ 5778.995851] hid-generic 0003:04B4:2412.002F: input,hidraw8: USB HID v1.11 Gamepad [Flydigi Flydigi APEX 4] on usb-0000:64:00.3-1.3.2.3/input0
[ 5779.002720] input: Flydigi Flydigi APEX 4 as /devices/pci0000:00/0000:00:08.3/0000:64:00.3/usb7/7-1/7-1.3/7-1.3.2/7-1.3.2.3/7-1.3.2.3:1.1/0003:04B4:2412.0030/input/input73
[ 5779.003020] hid-generic 0003:04B4:2412.0030: input,hidraw9: USB HID v1.11 Mouse [Flydigi Flydigi APEX 4] on usb-0000:64:00.3-1.3.2.3/input1
[ 5779.011733] hid-generic 0003:04B4:2412.0031: hiddev98,hidraw10: USB HID v1.11 Device [Flydigi Flydigi APEX 4] on usb-0000:64:00.3-1.3.2.3/input2
[ 5779.020982] hid-generic 0003:04B4:2412.0032: hiddev99,hidraw11: USB HID v1.11 Device [Flydigi Flydigi APEX 4] on usb-0000:64:00.3-1.3.2.3/input3

@antheas
Copy link
Collaborator

antheas commented Jun 19, 2024

Seems like Hidraw 9: Usage Page: 0x0001 Usage: 0x0001 500hz is a mouse for the weird thing.

Hidraw 8: Usage Page: 0x0001 Usage: 0x0005 500hz is the dinput controller with all the buttons. Nice of them to include all of them. Unlike other manufacturers.

Then, I can only assume here and say that 10 is the vendor interface for the app and 11 is for firmware updates. To know more youd have to dump the hid descriptors with https://github.com/hhd-dev/hid-tools

Gyro and mouse are different though. Can you see the gyro values in one of the reports always?

@antheas
Copy link
Collaborator

antheas commented Jun 19, 2024

eg if hidraw 10 always outputs gyro we are in business. Otherwise, you'll have to choose between buttons and gyro

@antheas
Copy link
Collaborator

antheas commented Jun 19, 2024

Actually scratch that. We can just mute the mouse thing and it will be fine.

@yoyossef
Copy link
Author

yoyossef commented Jun 19, 2024

@antheas hidraw 10 always outputs gyro once the mouse thing has been toggled.

It reports both the gyro (when enabled) and all the buttons/sticks/triggers/paddles (from what I've tested so far), in both mouse and gamepad mode.

If the mouse mode toggle isn't on, it doesn't output the gyro values.

@antheas
Copy link
Collaborator

antheas commented Jun 19, 2024

Yes. Your device is a candidate for both hhd and a kernel driver.

I would steer towards a kernel driver, for the lower CPU utilization and the fact that it can be upstreamed and such.

That driver would just black list the first 2 hidraws while active and read the one with everything

But it would not be too hard to add support for it in hhd. Perhaps as a proof of concept for the kernel driver. Much easier than a kernel driver for sure.

The only problem right now is that hhd does not support plugin autodetection. But I had planned ahead when I made it so that is not that big of a deal.

@antheas
Copy link
Collaborator

antheas commented Jun 19, 2024

If the device has a windows application, open it up with wireshark and do some dumps. Theres a chance we can control gyro and the activation of other devices from it, as well as RGB if it has it.

https://github.com/hhd-dev/hwinfo

@yoyossef
Copy link
Author

yoyossef commented Jun 19, 2024

Superb news, yeah the Windows application has a lot of fancy features, the controller even has an OLED screen you can display your favorite GIF on loop, as well as LEDs customization.

Some of the configuration can be done on the OLED display directly, switching saved profiles for example, but lots of customization is done through the Windows app.

I'll try to do some dumps later in the evening.

@zany130
Copy link

zany130 commented Jun 20, 2024

Since I also have the controller, I went ahead and did the wireshark dumps (sorry @yoyossef hope you don't mind). you can see them here https://github.com/zany130/hwinfo/tree/master/devices/Apex4/peripherals/windows

I tried to match what I saw for some other devices, but if I being honest I have no clue what I am doing, lol (not even sure if I captured it right I did filter to the device (showed up as an xbox controller))

I probably should have separated some of the caps. For example, in RGB, I just switched through all the profiles and then finally off. Maybe I should have separated it by profile?

Same with the joystick dump, I just went through all the options on that page (maybe I should have separated joystick mapping and joystick sensitivity)

As you can see from the names of my captures, the controller has adaptive triggers (just like the Sony DualSense) and can even emulate the DualSense to get dual sense adaptive trigger effects in games. Unfortunately, I don't have any of the supported games, so I could only capture the toggle (a.

@antheas
Copy link
Collaborator

antheas commented Jun 20, 2024

How do you switch to dualsense?

You can select the USB device before entering the capture through the gear

Then while capturing you can do filters to focus in on what's going on

https://github.com/hhd-dev/hwinfo/tree/master/devices/legion_go/peripherals#introduction

@yoyossef
Copy link
Author

Dualsense mode seems to be d-input that is activated only for a few selected exes from their software (like Overwatch and a few others), and it enables Adaptive Trigger and/or gyro support.

Steam also happens to consider it as being a proper Dualsense when that mode is on it looks like, exes can be spoofed according to reddit: https://www.reddit.com/r/Controller/comments/1bez2vn/flydigi_apex_4_how_to_force_ds_mode_on_any_game/

@antheas
Copy link
Collaborator

antheas commented Jun 20, 2024

D input in general uses the HID protocol

The dualsense controller presents at least two interfaces: one HID device for the controller itself. Hhd can emulate that.

And a multi channel audio device for the adaptive triggers. Hhd cannot, and there is no plans for it. However, if we can get the controller to do it that's that.

The dualsense edge controller is exactly the same as the normal variant. The only additional part is when you press the back buttons, they appear on the report.

If that's the case, there's potential for adding support for back buttons in steam together with gyro without needing any driver. And getting adaptive triggers as a bonus.

They only activate when the controller uses the edge vid pid in sdl and steam, so you won't see them right now. But they will be in the report.

@antheas
Copy link
Collaborator

antheas commented Jun 20, 2024

Sorry I mispoke its morning

Adaptive triggers are part of the hid report

The audio is for the fancy rumble

@yoyossef
Copy link
Author

No worries, the difference with the dualsense is the lack of trackpad and lack of fancy haptic feedback (in fact I've heard that in d-input the vibration motors are completely off, I'd have to verify this), so we would have to capture and understand the events when that special Dualsense mode is on.

I can do it over the week-end unless zany does/did it.

@antheas
Copy link
Collaborator

antheas commented Jun 20, 2024

The dualsense protocol is well documented

You just need to capture whether the back buttons work in that mode. Probably not. And if the audio devices exist

Doing rumble in dualsense mode is a bit complex but quite standard. Including rgb.

But maybe they skipped that whole receiving part and just do some emulation for the triggers. Since you can still see the original controller

Edit: actually if they support the triggers they did the receiving part. So its probably a bug I would say

@antheas
Copy link
Collaborator

antheas commented Jun 20, 2024

As for a bit of context on rumble: while the dualsense audio device is active the dualsense is replaying the audio as rumble

In parallel, the games that send audio to the controller also send a compatibility rumble in the configuration report that is classic rumble. The dualsense is supposed to ignore this

Unless the disable audio effects bit is set. Steam, proton, the kernel and games that do not support the special effects, turn that but on. So genuine controllers always have rumble

We had to figure that out to get rumble working in death stranding that uses the audio rumble and has that bit off

The led effects on that are also quite special and they work under hhd. Unfortunately not for GPD

There are also 2 types of dualsense rumble: one they had on release and is a bit jarring, and one they added later that is much more similar to Xbox 360. They use different bits on the report and are scaled differently

@zany130
Copy link

zany130 commented Jun 20, 2024

How do you switch to dualsense?

Unfortunately, you can only do this in the software

see https://github.com/zany130/hwinfo/blob/master/devices/Apex4/peripherals/windows/adaptive_trigger_milesmorales.png

Then while capturing you can do filters to focus in on what's going on

hhd-dev/hwinfo@master/devices/legion_go/peripherals#introduction

Oh, I didn't see that.

So, should I redo the dumps with filters?

@antheas
Copy link
Collaborator

antheas commented Jun 20, 2024

Filters do not affect the dump. Selecting the USB device does.

If the files are not too big, no. If they are yes. Also, some sensitive info might have snuck through.

@yoyossef
Copy link
Author

zany130/hwinfo#1

I've captured some traffic in said "DS Mode" by spoofing the Overwatch 2 exe with Chrome (like in the reddit example I had linked above).

@zany130
Copy link

zany130 commented Jun 20, 2024

zany130/hwinfo#1

I've captured some traffic in said "DS Mode" by spoofing the Overwatch 2 exe with Chrome (like in the reddit example I had linked above).

Nice thanks. Does overwatch have "standard" or "DS mode" adaptive triggers ? I'm guessing since you said "DS Mode" it has that. I ask because I remember a lot of the games on the adaptive trigger list only having "standard" adaptive triggers

Filters do not affect the dump. Selecting the USB device does.

If the files are not too big, no. If they are yes. Also, some sensitive info might have snuck through.

ok then my dumps should be fine the biggest one was like 10mb and most where under 5mb

EDIT: I wonder if it would be possible to get into this "DS Mode" with Linux by running the flydigi app on WINE...

The furthest I got with that is the app running but unable to detect the controller...

@yoyossef
Copy link
Author

yoyossef commented Jun 20, 2024

I've also captured traffic for the GIF upload thing (sidenote: the screen is always on with the GIF looping so having an option to upload a black GIF to turn it off could be a nice feature to have).

But for some reason the flydigi app requires to switch to Xinput, I've captured it anyway, I won't PR it yet as it's quite a big file, I should filter it once I can reliably identify which traces are what.

Does overwatch have "standard" or "DS mode" adaptive triggers ?

Overwatch only offers DS mode.

EDIT:

I wonder if it would be possible to get into this "DS Mode" with Linux by running the flydigi app on WINE...
The furthest I got with that is the app running but unable to detect the controller...

I wouldn't count on it, the app itself is quite unstable on Windows already

@zany130
Copy link

zany130 commented Jun 20, 2024

I've also captured traffic for the GIF upload thing (sidenote: the screen is always on with the GIF looping so having an option to upload a black GIF to turn it off could be a nice feature to have).

But for some reason, the flydigi app requires to switch to Xinput (updates is another one, I believe); I've captured it anyway; I won't PR it yet as it's quite a big file; I should filter it once I can reliably identify which traces are what.

Yeah a lot of the features of the app require the controller to be in xinput mode. I should mention all my captures where done in xinput mode.

the reason being it will sometimes randomly switch you to xinput mode if your on dinput

@yoyossef
Copy link
Author

yoyossef commented Jun 20, 2024

The app does reset itself and sets the pad to xinput quite randomly (bugs?) but I wouldn't say that xinput is required to change those settings necessarily, except for the screen GIF settings where it says it explicitly, the app pops out a warning alert that xinput is required.

My guess is that we should capture as much dinput traffic as possible, what do you think @antheas ?

(Also curious if you're seeing interesting stuff in my DS mode captures)

@antheas
Copy link
Collaborator

antheas commented Jun 20, 2024

Xinput is probably required because as you said the app is unstable. So for the app to detect the controller, the controller has to be in xinput mode. No need for them to have it working with all modes.

@antheas
Copy link
Collaborator

antheas commented Jun 20, 2024

My guess is that we should capture as much dinput traffic as possible, what do you think @antheas ?

My next move would be to start finding commands and move over to linux. Try to find the commands that make it change modes, then you can run them with hhd.controller.lib.hid and make it switch modes in linux and study it there.

@zany130
Copy link

zany130 commented Jun 27, 2024

found this https://github.com/ahungry/vader3/tree/master

While not the Apex 4 controller, it is still a Flydigi controller. If you're still looking at this, @yoyossef, it may be useful?

EDIT: another interesting tool doesn't seem to work with the apex 4 https://github.com/pipe01/flydigictl

@antheas
Copy link
Collaborator

antheas commented Jun 27, 2024

you can add support to steam for back buttons and gyro if the driver picks up the buttons and gyro

@antheas
Copy link
Collaborator

antheas commented Jun 27, 2024

Only dualsense and switch controllers support gyro, so youll get one of those glyphs

At least until this releases:
https://hori.jp/products/hpc/hpc-055/

@zany130
Copy link

zany130 commented Jun 28, 2024

Interesting updates: apparently, Gyro sort of works in xinput mode on Linux.

when configured like this

image

I have the power-on button set to LB (no idea why its showing blank). This actually works on Linux (ie holding LB moves the left joystick according to the gyro)

I wonder if there is some way to grab the gyro output, ignore the joystick movement, and then use that as a gyro in Steam.

since this is xinput mode vibration also works (vibration does not work in dinput even in Windows with the software running, nor does it work in "DS mode")

EDIT:

also another interesting thing I found is if you get the controller into "DS mode" in a virtual machine and then remove the controller from the VM (Do not unplug the controller) it will achtally seemingly stay in "DS mode" but as far as I can tell there is no difference between this and dinput mode on linux.

maybe all the magic happens in the software?

@zany130
Copy link

zany130 commented Jun 29, 2024

Added some more hid report dumps into https://github.com/zany130/hwinfo/tree/master/devices/Apex4/peripherals/hid

sorry if some of this is redundant, as @yoyossef already did most of this, but ...

interestingly, I found that the 3rd hidraw device in dinput mode actually does outputs the gyro without the mouse when you have the mouse toggle off (circle button next to home)

so the hidraw devices are as follows

1st. All controller inputs plus mouse gyro and buttons when mouse mode is toggled (circle button)
2nd. only mouse gyro and buttons (when mouse mode is on)
3rd. All controller inputs plus gyro when mouse mode is off. When on, gyro mouse and mouse buttons
4th. firmware updates or something?

like I said above, I didn't notice any difference in the hidraw reports, between normal dinput mode and getting the controller to go into "DS mode" through a Windows virtual machine

@zany130
Copy link

zany130 commented Jun 30, 2024

Found a really nice app to test the controller on windows https://powgames.itch.io/game-controller-tester

and found out some interesting things

  1. in dualsense mode, the controller is advertised as having all the buttons of a dualsense and no more. so no back buttons, but the original input controller is still connected and that does still send inputs from the back buttons so I guess both devices could be combined? All dualsense buttons work except the mute button (touch pad press is mapped to Circle button next to home no touchpad swipes)
  2. There is no vibration in dinput or dualsense mode. Vibration support is advertised in dualsense mode ,but does not work
  3. As I expected, dinput mode does have an accelerometer and gyro sensors! steam just doesn't recognize it from some reason on linux or even on windows

so in summary it should be possible to have dinput mode expose both gyro and accelerometer sensors aswell as the extra back buttons and the extra circle button to steam, but we may not be able to get rumble working

no real need investigating dualsense mode I think well maybe for adaptive trigger support?

the controller already exposes everything we want (except vibration) in dinput on linux its just a matter of getting steam to recognize it

@zany130
Copy link

zany130 commented Jun 30, 2024

got steam to recognize the extra buttons with this env

SDL_GAMECONTROLLERCONFIG="0300fe68b40400001224000011010000,Flydigi APEX 4,a:b0,b:b1,x:b3,y:b4,back:b10,guide:a4,start:b11,leftstick:b12,rightstick:b13,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft: h0.8,dpright:h0.2,leftx:a0,lefty:a1,misc1:b15,paddle1:b14,paddle2:b16,paddle3:b17,paddle4:b18,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux,

I switched guide to a4 and misc1 to b15 to have the guide button be the circle button and the misc button be home. this works better, I think, because holding home triggers the on-screen menu, making it difficult to perform steam chorded inputs like guide + a for the quick-access menu

no idea how to hide the gyro mouse on circle button or how to map the gyro though...

EDIT: couple problems I have to look into

1. triggers are digital now (where analog before)
2. right trigger also activates guide for some reason

So, the reason the triggers became digital is because I was mapping to the trigger button instead of the trigger axis

second a4 actually corresponds to both the right trigger AND the circle button. That why the right trigger was also activating guide

so the correct env becomes

SDL_GAMECONTROLLERCONFIG="0300fe68b40400001224000011010000,Flydigi APEX 4,a:b0,b:b1,back:b10,dpdown:h0.4,d
pleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1
,paddle1:b14,paddle2:b16,paddle3:b17,paddle4:b18,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2
,righty:a3,start:b11,x:b3,y:b4,platform:Linux,"

also disabled the gyro mouse with the following udev rule

File: /etc/udev/rules.d/01-FlyDigi.rules
# Flydigi Apex 4 Dinput Controller blacklist mouse
SUBSYSTEM=="usb", ATTR{bInterfaceNumber}=="01", ATTRS{product}=="Flydigi APEX 4", ATTR{authorized}="0"

the controller without gyro is on interface 00

the mouse gyro is on interface 01

and the controller with gyro is on interface 02

I tried blacklisting interface 00 as well to see if I could get Steam to see the controller with gyro, but no luck, no device gets mapped to /dev/input/

@antheas
Copy link
Collaborator

antheas commented Jul 1, 2024

Except vibration is a strong statement. Maybe the driver does not know how to make the controller vibrate

But from what you're saying this is a kernel driver candidate

Mind the fact that the only kernel drivers that support gyro are the steam deck, playstation and Nintendo ones

So you'll need to do some copying around

@zany130
Copy link

zany130 commented Jul 1, 2024

Except vibration is a strong statement. Maybe the driver does not know how to make the controller vibrate

I was basing the lack of vibration more on the fact that even on Windows, there is no vibration when in either dinput mode or "DS mode" (which I think is just dinput mode with the product and vendor ID of the dualsense?).

Is the best path forward to copy Windows software "DS mode" and bind the controller to the kernel PlayStation hid driver?

That way we may also be able to get per-game adaptive triggers

Unfortunately, this is beyond my ability. I just know how to do basic tinkering lol 😅

but it does look like what prevents steam from "seeing" the gyro in dinput mode is lack of gyro support by usbhid driver? (I think that's what get used)

Stupid question but would it be possible to force it to use the PlayStation hid driver?

@antheas
Copy link
Collaborator

antheas commented Jul 1, 2024

Adaptive triggers are not part of the playstation driver. Linux has poor support for adaptive triggers so I don't think it's very worthwhile. Also back buttons which are more important would be missed.

The best plan forward is to first document the dinput protocol, and then either make a patch to SDL or the kernel.

Steam uses the SDL library which is maintained by valve for controller support. The SDL library supports the kernel drivers for gyro and all buttons, if they are exposed as the Nintendo and Playstation drivers expose them.

SDL also has a large number of hand built drivers that connect to controllers directly through hid. And through that it supports touchpads, gyro, and RGB for most Microsoft, Nintendo, and Sony controllers.

As far as steam is concerned, SDL contains a set of functions that receive a pid and vid and return if the controller is a Dualsense Edge controller, Dualsense, Nintendo, etc.

Steam input calls those functions and depending on which one returns yes activates a different profile.

Then, provided that Sdl has loaded the controller properly, those features work. However, you can have cases where say SDL cannot access the raw hid device. In that case, it falls back to the kernel driver which has a subset of features. So for example, a dualsense edge controller would still show up as if it has back button and RGB support but those features would not work.

@antheas
Copy link
Collaborator

antheas commented Jul 1, 2024

Which is a roundabout way of saying that if you want back buttons without valve's blessing, your controller has to identify as Xbox elite, Dualsense edge, or a joycon pair

And if you want gyro, it needs to identify as a Dualsense edge or Nintendo controller. It is not possible to get steam input to support gyro without weird glyphs.

You will also be able to see that when gyro or RGB works, they will be in the advanced controller settings in Steam. But if there's not a case for them in SDL, Steam Input will not let you use them

@zany130
Copy link

zany130 commented Jul 2, 2024

Again, I may be completely out of my depth here and wrong, but wouldn't it be possible for some userspace driver application like Xboxdrv or SC-controller (and I am assuming hhd works similarly) to grab the Hidraw device that has gyro and everything and expose it as a controller, preferably a dual-sense controller?

The problem is that I think Xboxdrv and sc-controller don't support Gyro.
The Vader 3 driver I found doesn't seem to support Gyro either (though I think the Vader 3 also has Gyro?)

I know the ideal solution would be to deal with the controller upstream, but this could be POC or something.

I already got the back buttons sort of working on Steam with the SDL mapping. However, as you said, since it's not identified as a DualSense Edge or any of the other known controllers that have paddle support, it doesn't activate the right profile for Steam input, meaning. At the same time, they are detected in the controller tester however, you can't map them.

though interestingly I found if you apply a steam input profile from a known supported controller with paddles (like the deck or dual sense edge) you can get buttons mapped to the back paddles

Just tried this with Persona 3 reload and I was able to get some actions mapped to the back buttons

@antheas
Copy link
Collaborator

antheas commented Jul 2, 2024

Oh didn't know about that workaround or I guess steam bug. Yes of course you can even remap the dinput controller into a dualsense edge with hhd.

Hhd has support for dinput, xinput, and hidraw. If dinput works properly use that.

Hidraw at 1000hz would use around 10% of a single core. If you do dinput that drops to 0 unless you're using the sticks. In which case you're looking at 7-10% again. Only while you're moving the sticks.

Id look for a way of spoofing the vid/pid of the controller so steam thinks it's a dualsense edge out of the gate and you don't eat the CPU cost.

Reminder we only do this hack for handheld devices because certain buttons come from a separate device and it's not possible to merge them in the kernel.

Also, open an issue on SDL and reference this issue. I'm sure they would be happy to help and maybe steam gets support for this controller.

@antheas
Copy link
Collaborator

antheas commented Jul 2, 2024

I also benchmarked hhd yesterday and you would be happy to know it only adds .1ms to .5ms of latency depending on how the kernel feels about waking up the threads.

@zany130
Copy link

zany130 commented Jul 2, 2024

Also, open an issue on SDL and reference this issue. I'm sure they would be happy to help and maybe steam gets support for this controller.

I will do that. Ideally, it gets fixed there. Honestly, it sounds like the same amount of effort would need to be made to add it here or Steam/SDL. Sorry if I was bugging you or anything, but like I said, I've actually had zero experience with all this.

Thanks for pointing me and @yoyossef in the right direction!

@antheas
Copy link
Collaborator

antheas commented Jul 2, 2024

No problem guys, getting better controller support is a win win for everyone.

@zany130
Copy link

zany130 commented Sep 26, 2024

Just to give an update, it seems that with what we know of the controller right now, it won't be feasible to add support in SDL.

I am still considering documenting the controller when I have time. I have just been really busy lately.

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

No branches or pull requests

3 participants