godot icon indicating copy to clipboard operation
godot copied to clipboard

Improve gamepad support on Linux

Open Rindbee opened this issue 1 year ago • 3 comments
trafficstars

Previously, the controller input mapping relied on core/input/gamecontrollerdb.txt, so if the device is newer, the device input mapping may be confused.

For gamepads not documented in this file, they are now simply mapped according to the enumeration semantics.

Reference: Linux Gamepad Specification and Input event codes.

Might help in closing #87112.

Keycode Mapping Table

JoyButton / JoyAxis input-event-codes.h
JoyButton.A BTN_A[^1] (BTN_SOUTH/BTN_GAMEPAD[^2])
JoyButton.B BTN_B[^1] (BTN_EAST)
JoyButton.X BTN_X[^1] (BTN_NORTH)
JoyButton.Y BTN_Y[^1] (BTN_WEST)
JoyButton.BACK BTN_SELECT
JoyButton.GUIDE BTN_MODE
JoyButton.START BTN_START
JoyButton.LEFT_STICK BTN_THUMBL
JoyButton.RIGHT_STICK BTN_THUMBR
JoyButton.LEFT_SHOULDER BTN_TL
JoyButton.RIGHT_SHOULDER BTN_TR
JoyButton.DPAD_UP BTN_DPAD_UP[^3]
JoyButton.DPAD_DOWN BTN_DPAD_DOWN[^3]
JoyButton.DPAD_LEFT BTN_DPAD_LEFT[^3.1]
JoyButton.DPAD_RIGHT BTN_DPAD_RIGHT[^3.1]
JoyButton.MISC1[^6] KEY_RECORD / BTN_Z[^4]
JoyButton.PADDLE1 [^5]
JoyButton.PADDLE2 [^5]
JoyButton.PADDLE3 [^5]
JoyButton.PADDLE4 [^5]
JoyButton.TOUCHPAD [^5]
JoyAxis.LEFT_X ABS_X
JoyAxis.LEFT_Y ABS_Y
JoyAxis.RIGHT_X[^6] ABS_RX / ABS_Z
JoyAxis.RIGHT_Y[^6] ABS_RY / ABS_RZ
JoyAxis.TRIGGER_LEFT[^6] ABS_BRAKE / ABS_Z / BTN_TL2
JoyAxis.TRIGGER_RIGHT[^6] ABS_GAS / ABS_RZ / BTN_TR2

[^1]: While the Linux Gamepad Specification recommends reporting events based on physical position, I don't have a gamepad that follows this convention. Perhaps reporting events by corresponding label name is a de facto convention. [^2]: BTN_GAMEPAD is used to identify a gamepad. See the Detection section of the Linux Gamepad Specification. Devices without this keycode will not be automatically mapped. [^3]: ~~These are the key codes for the digital buttons. But godot will automatically map the key codes (ABS_HAT0X/ABS_HAT0Y) for the analog buttons to these JoyButtons, and godot doesn't seem to detect the EV_SYN event, so a gamepad that reports both digital and analog buttons on one button might be a bit of a hassle. I don't have such a device.~~ Only mapped if ABS_HAT0Y is not present. [^3.1]: Only mapped if ABS_HAT0X is not present. [^4]: Not sure, there is only one unofficial device. [^5]: There is no such gamepad around me. But in order to prevent unexpected behavior, they are eventually mapped to JoyButton.INVALID. [^6]: There does not seem to be a consistent convention for these axes. If the analog-sticks that issue the key code do not exist, they will try the next.

Note: If the final mapped keycodes have no corresponding buttons/analog-sticks, they will be mapped to -1( JoyButton.INVALID/ JoyAxis.INVALID).

Rindbee avatar Aug 13 '24 13:08 Rindbee

Linux users are welcome to use various gamepads for testing (test project: Joypads (Gamepads) Demo).

Available binary executables (you may need to configure the C Sharp environment) are available from Github Action.

If any key mapping is incorrect or the values are abnormal, please provide feedback. Missing key codes are welcome to be added too. You can use the evtest/evemu-record command line tool to get the specific key code.

evtest example output
$ evtest
No device specified, trying to scan all of /dev/input/event*
Not running as root, no devices may be available.
Available devices:
/dev/input/event24:	Zikway HID gamepad
Select the device event number [0-24]: 24
Input driver version is 1.0.1
Input device ID: bus 0x3 vendor 0x3537 product 0x1041 version 0x111
Input device name: "Zikway HID gamepad"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 114 (KEY_VOLUMEDOWN)
    Event code 115 (KEY_VOLUMEUP)
    Event code 116 (KEY_POWER)
    Event code 304 (BTN_SOUTH)
    Event code 305 (BTN_EAST)
    Event code 306 (BTN_C)
    Event code 307 (BTN_NORTH)
    Event code 308 (BTN_WEST)
    Event code 309 (BTN_Z)
    Event code 310 (BTN_TL)
    Event code 311 (BTN_TR)
    Event code 312 (BTN_TL2)
    Event code 313 (BTN_TR2)
    Event code 314 (BTN_SELECT)
    Event code 315 (BTN_START)
    Event code 316 (BTN_MODE)
    Event code 317 (BTN_THUMBL)
    Event code 318 (BTN_THUMBR)
    Event code 319 (?)
  Event type 3 (EV_ABS)
    Event code 0 (ABS_X)
      Value    128
      Min        0
      Max      255
      Flat      15
    Event code 1 (ABS_Y)
      Value    128
      Min        0
      Max      255
      Flat      15
    Event code 2 (ABS_Z)
      Value    128
      Min        0
      Max      255
      Flat      15
    Event code 5 (ABS_RZ)
      Value    128
      Min        0
      Max      255
      Flat      15
    Event code 9 (ABS_GAS)
      Value      0
      Min        0
      Max      255
      Flat      15
    Event code 10 (ABS_BRAKE)
      Value      0
      Min        0
      Max      255
      Flat      15
    Event code 16 (ABS_HAT0X)
      Value      0
      Min       -1
      Max        1
    Event code 17 (ABS_HAT0Y)
      Value      0
      Min       -1
      Max        1
  Event type 4 (EV_MSC)
    Event code 4 (MSC_SCAN)
Properties:
Testing ... (interrupt to exit)
Event: time 1723648532.480617, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90001
Event: time 1723648532.480617, type 1 (EV_KEY), code 304 (BTN_SOUTH), value 1
Event: time 1723648532.480617, -------------- SYN_REPORT ------------
Event: time 1723648532.580616, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90001
Event: time 1723648532.580616, type 1 (EV_KEY), code 304 (BTN_SOUTH), value 0
Event: time 1723648532.580616, -------------- SYN_REPORT ------------
Event: time 1723648533.956625, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90002
Event: time 1723648533.956625, type 1 (EV_KEY), code 305 (BTN_EAST), value 1
Event: time 1723648533.956625, -------------- SYN_REPORT ------------
Event: time 1723648534.078621, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90002
Event: time 1723648534.078621, type 1 (EV_KEY), code 305 (BTN_EAST), value 0
Event: time 1723648534.078621, -------------- SYN_REPORT ------------
Event: time 1723648534.761624, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90004
Event: time 1723648534.761624, type 1 (EV_KEY), code 307 (BTN_NORTH), value 1
Event: time 1723648534.761624, -------------- SYN_REPORT ------------
Event: time 1723648534.878625, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90004
Event: time 1723648534.878625, type 1 (EV_KEY), code 307 (BTN_NORTH), value 0
Event: time 1723648534.878625, -------------- SYN_REPORT ------------

Rindbee avatar Aug 14 '24 15:08 Rindbee

In the case where there are two events for a key press (device specific), we use the primary event and hide the secondary event.

It may work better for devices that follow the Linux Gamepad Specification, but may not work for devices that don't.

Rindbee avatar Aug 18 '24 12:08 Rindbee

According to hidinput_configure_usage(), obtain the corresponding UsagePage/Usage codes (in HID Usage Tables) of some macros (in input-event-codes.h).

input-event-codes.h HUT
Macro Value UsagePage Usage
BTN_A (BTN_SOUTH/BTN_GAMEPAD) 0x130 0x09 0x01
BTN_B(BTN_EAST) 0x131 0x09 0x02
BTN_C 0x132 0x09 0x03
BTN_X (BTN_NORTH) 0x133 0x09 0x04
BTN_Y (BTN_WEST) 0x134 0x09 0x05
BTN_Z 0x135 0x09 0x06
BTN_TL 0x136 0x09 0x07
BTN_TR 0x137 0x09 0x08
BTN_TL2 0x138 0x09 0x09
BTN_TR2 0x139 0x09 0x0A
BTN_SELECT 0x13A 0x01/0x09 0x3E/0x0B
BTN_START 0x13B 0x01/0x09 0x3D/0x0C
BTN_MODE 0x13C 0x09 0x0D
BTN_THUMBL 0x13D 0x09 0x0E
BTN_THUMBR 0x13E 0x09 0x0F
BTN_DPAD_UP 0x220 0x01 0x90
BTN_DPAD_DOWN 0x221 0x01 0x91
BTN_DPAD_LEFT 0x222 0x01 0x93
BTN_DPAD_RIGHT 0x223 0x01 0x92
ABS_X 0x00 0x01 0x30
ABS_Y 0x01 0x01 0x31
ABS_Z 0x02 0x01 0x32
ABS_RX 0x03 0x01 0x33
ABS_RY 0x04 0x01 0x34
ABS_RZ 0x05 0x01 0x35
ABS_THROTTLE 0x06 0x02 0xBB
ABS_RUDDER 0x07 0x02 0xBA
ABS_WHEEL 0x08 0x02 0xC8
ABS_GAS 0x09 0x02 0xC4
ABS_BRAKE 0x0A 0x02 0xC5
ABS_HAT0X 0x10 0x01 0x39

Perhaps these mappings can be applied to dinput devices on Windows based on the device's UsagePage/Usage.

Rindbee avatar Dec 04 '24 07:12 Rindbee

This PR would fix this issue: https://github.com/godotengine/godot/issues/101215

xsellier avatar Jan 08 '25 07:01 xsellier

Retested it with removed mappings, with DualSense and XBoxOne controllers and mapping seems to be off for both (buttons completely random, triggers mixed with right hat). Not sure what changed, previous time I have tested it, it was OK.

bruvzg avatar Jan 08 '25 10:01 bruvzg

Retested it with removed mappings, with DualSense and XBoxOne controllers and mapping seems to be off for both (buttons completely random, triggers mixed with right hat). Not sure what changed, previous time I have tested it, it was OK.

For devices that have been recorded, after removing the old mapping, you need to disconnect the device and reconnect it to generate a new mapping.

Rindbee avatar Jan 08 '25 10:01 Rindbee

For devices that have been recorded, after removing the old mapping, you need to disconnect the device and reconnect it to generate a new mapping.

All were connected after removing mapping this time, but I do not remember whether it was the case during the previous test.

bruvzg avatar Jan 08 '25 10:01 bruvzg

All were connected after removing mapping this time, but I do not remember whether it was the case during the previous test.

During your last test, did you modify the project settings input_devices/gamepad/unknown_gamepad_auto_mapped?

I compiled and it worked as expected.

joypads.zip

The modified project can indicate whether it is enabled in the command line and UI.

Rindbee avatar Jan 08 '25 11:01 Rindbee

Ok, retested it again with a clean build, and it seems to be working correctly now, so I either messed up the previous build or it's some strange quirk of quickly switching controllers between mac and pc, sorry for confusion.

The only issue I have noticed, triangle and square buttons on the DualSense controller are swapped, everything else seems to be fine

bruvzg avatar Jan 08 '25 13:01 bruvzg

The only issue I have noticed, triangle and square buttons on the DualSense controller are swapped, everything else seems to be fine

Although the Linux Gamepad Specification specifies key codes by position, their aliases do not conform to either the Xbox Series layout or the Switch/NS layout. Here it follows the Xbox layout. So devices that follow the Switch/NS layout may need to swap X/Y, A/B.

Rindbee avatar Jan 08 '25 14:01 Rindbee

This may have been addressed already, but I'm confused about the BTN_NORTH and BTN_WEST mappings shown in the description:

Selection_257

If A is south, and B is east, then this is an XBox-style layout, and so shouldn't X be west, and Y be north?

If B was south, and A was east, then it'd be a Nintendo-style layout, and the X and Y positions on the table would make sense to me.

But the current mapping seems like it's a mix of the two?

dsnopek avatar Jan 08 '25 14:01 dsnopek

But the current mapping seems like it's a mix of the two?

This is a different alias for the same value. Direction is the standard recommended way of positioning, but its alias does not follow the layout of Xbox and Switch/NS. Following it will likely result in both Xbox and Switch requiring swap buttons.

Rindbee avatar Jan 08 '25 14:01 Rindbee

I can't comment on the fallbacks, because they're not documented by the linux kernel, but I assume they are chosen based on experience

Most of the buttons are pretty much the same as the Linux Gamepad Specification, with the exception of the A/B/X/Y buttons. Note the image and the abbreviations labeled on it. 001

The axises and triggers are based on experience.

Rindbee avatar Jan 08 '25 14:01 Rindbee

But the current mapping seems like it's a mix of the two?

This is a different alias for the same value. Direction is the standard recommended way of positioning, but its alias does not follow the layout of Xbox and Switch/NS. Following it will likely result in both Xbox and Switch requiring swap buttons.

Well, if we should trust the direction (ie BTN_WEST) more than the name alias (ie BTN_Y), then I think the mappings for X and Y should be flipped. Taking a brief peek at the specification that's linked in the description, it does seem like we should trust the direction more.

In which case:

  • A = BTN_SOUTH
  • B = BTN_EAST
  • X = BTN_WEST
  • Y = BTN_NORTH

dsnopek avatar Jan 08 '25 15:01 dsnopek

In which case:

* A = `BTN_SOUTH`

* B = `BTN_EAST`

* X = `BTN_WEST`

* Y = `BTN_NORTH`

This is an ideal state, but the one defined on Linux is not compatible with Xbox and Switch/NS.

https://github.com/torvalds/linux/blob/09a0fa92e5b45e99cf435b2fbf5ebcf889cf8780/include/uapi/linux/input-event-codes.h#L380-L389

I feel like instead of using the direction alias that is incompatible with both, I'd rather use the ABXY alias that is compatible with Xbox.

Rindbee avatar Jan 08 '25 15:01 Rindbee

I emptied out core/input/gamecontrollerdb.txt (so I'd always get the automapping) and tested with almost all the different controllers I have access to, using the joypads demo:

  • A "modern" XBox controller from an XBox Series S (Microsoft Xbox Series S|X Controller - 030000005e040000120b00000f050000): everything correct
  • XBox 360 (Microsoft X-Box 360 pad - 030000005e0400008e02000010010000): everything correct
  • MOGA (it's a knockoff XBox controller - BDA MOGA XP5-X Plus - 03000000c62400001b890000110100): everything correct
  • DualShock 4 (Sony Computer Entertainment Wireless Controller - 030000004c050000c405000011810000): correct, except the X (square) and Y (triangle) are swapped
  • Logitech Dual Action (Logitech Logitech Dual Action - 030000006d04000016c2000010010000): correct, except the face buttons are all wrong except for Y (I end up with A = B, B = X, X = A)

I wish I had more controllers that weren't some variation of an XBox controller

This is an ideal state, but the one defined on Linux is not compatible with Xbox and Switch/NS.

https://github.com/torvalds/linux/blob/09a0fa92e5b45e99cf435b2fbf5ebcf889cf8780/include/uapi/linux/input-event-codes.h#L380-L389

I feel like instead of using the direction alias that is incompatible with both, I'd rather use the ABXY alias that is compatible with Xbox.

Ok, I guess that makes sense! Thanks for the explanation :-)

dsnopek avatar Jan 08 '25 15:01 dsnopek

Hi, I've removed both gamecontrollerdb.txt and godotcontrollerdb.txt, recompiled and tried the joystick demo with all the controllers I could find.

Devices tested, from best to worst results:

  • Xbox 360 Wireless Receiver (XBOX): works perfectly;
  • Genuine Pro Controller: works perfectly, although x and y are switched. That's fine;
  • Genuine Joy-Con (R): works as in, evdev side it reports keys as if it were half of a bigger joystick, instead of an horizontal single joycon. Remapping is working perfectly here though so that's fine;
  • USB Gamepad (sketchy xbox360-shaped ps2 controller): evtest reports the weirdest keys. We're talking BTN_TOP, BTN_PINKIE, BTN_BASE and other weird stuff. I'm really not sure there's anything that we can do here. Maybe that's what the linux docs meant when it said "Legacy drivers often don’t comply to these rules.";
  • Genuine Joy-Con (L): The battery went flat mid-testing. Works "vertically" like the right joycon but remapping is broken. evtest reports that BTN_DPAD_* is actually being sent but the dpad gets remapped to the "action" buttons (a, b, x, y) instead;

I'm also attaching evtest info for each device below.

joycon-l.txt joycon-r.txt usb-gamepad.txt xbox-wireless-receiver.txt

deralmas avatar Jan 09 '25 10:01 deralmas

I'm also attaching evtest info for each device below.

joycon-l.txt joycon-r.txt usb-gamepad.txt xbox-wireless-receiver.txt

Thanks for testing and reporting. First of all, this PR is only for devices that are recognized as gamepads by Linux. The device needs to be able to send BTN_SOUTH events.

002

Although Godot doesn't differentiate between gamepads and joysticks, there is still a distinction here.

"Joy-Con (R)" and "Xbox 360 Wireless Receiver (XBOX)" meet this condition. This PR will work.

This "USB Gamepad" would be recognized as a Joystick by Linux (BTN_TRIGGER).

Joy-Con (L) Non-gamepad not working is expected.

Rindbee avatar Jan 09 '25 10:01 Rindbee

The project provided in https://github.com/godotengine/godot/pull/95486#issuecomment-2577423026 can clearly show whether the current mapping is automatically generated. It is modified based on https://github.com/godotengine/godot-demo-projects/tree/master/misc/joypads.

Additionally, @Riteo is BTN_TRIGGER_HAPPY supposed to correspond to JoyButton::PADDLE?

Rindbee avatar Jan 09 '25 10:01 Rindbee

Additionally, @Riteo is BTN_TRIGGER_HAPPY supposed to correspond to JoyButton::PADDLE?

I was a bit confused by that keycode too. From what I could tell, it's supposed to be one of many "wildcard" extra id, as eventually the previous extra button group was not enough. See https://unix.stackexchange.com/questions/301962/what-is-btn-trigger-happy

I don't think it has any well-defined meaning.

deralmas avatar Jan 09 '25 11:01 deralmas

Yes, gamepads/joysticks on Linux generally have up to 16 main buttons. And, main buttons with a keycode difference of 16 on the gamepad and joystick have the same UsagePage/Usage in HID Usage Tables . See https://github.com/torvalds/linux/blob/feffde684ac29a3b7aec82d2df850fbdbdee55e4/drivers/hid/hid-input.c#L743-L754

~~Is it possible to generate a mapping for the joystick according to the UsagePage/Usage rules of the gamepad? That is, the joystick button keycode plus 16, which does conform to the rules in https://github.com/godotengine/godot/pull/95486#issue-2463357762. I don't have such a typical joystick device. So I haven't tested it.~~ The two would not have the same mapping.

Rindbee avatar Jan 09 '25 11:01 Rindbee

Hi, I'm back with new data.

I was going to say how the virtual joycond device worked fine but actually I stumbled onto two bugs.

The biggest one is that, when there's no vendor/product/version available it will auto remap with the original uid, instead of using the new custom uidname (with which it registers), putting a stray mapping into mapdb and effectively doing nothing.

The other one is the fact that I even got into that code branch. The virtual controller (of which info I'll attach below as usual) includes indeed vendor/product/version data, 057e/2008/0000 to be exact, but since the check is inpid.vendor && inpid.product && inpid.version, a zero version skips the whole check.

I'm quite sure that we can assume a version field equal to zero. I looked around but unfortunately I could not find hard proof about that - I'd still skip that part of the condition though.

With those two changes, the virtual combined Joy-Con gamepad works perfectly.

I'll suggest through GitHub's feature the two fixes I found for both issues for convenience.

Edit: oops forgot to upload the info :sweat_smile:

combined.txt

Edit2: I see that the version thing does not come from this PR, so it's out of the diff!

I'd change the line from here: https://github.com/godotengine/godot/blob/0257995616a0afa9686ddca40f2e858c341b8256/platform/linuxbsd/joypad_linux.cpp#L405

to:

 if (inpid.vendor && inpid.product) {

A few more things: I could not test the horizontal Joy-Con mode as joycond never got the remapping feature implemented, passing through just like the lone vertical controller. Bummer :(

The shady PS2-xbox-clone thing won't get autoremapped anyways as it does not have a BTN_GAMEPAD. I guess that doubly confirms that this uses some very old non-standard scheme or something and not a proper modern linux gamepad.

To end things up, the modified demo does not properly report the auto state in the UI as on process the big label gets overridden every time. Here's a patch for fixing that, if anybody needs it:

--- a/joypads.gd	2024-12-20 18:54:44.000000000 +0100
+++ b/joypads.gd	2025-01-09 17:44:32.447661127 +0100
@@ -36,7 +36,7 @@
 	if joy_num != cur_joy:
 		cur_joy = joy_num
 		if Input.get_joy_name(joy_num) != "":
-			set_joypad_name(Input.get_joy_name(joy_num), Input.get_joy_guid(joy_num))
+			set_joypad_name(Input.get_joy_name(joy_num) + (" [Auto]" if Input.call("is_joy_auto_mapped", joy_num) else ""), Input.get_joy_guid(joy_num))
 		else:
 			clear_joypad_name()

deralmas avatar Jan 09 '25 18:01 deralmas

I'm quite sure that we can assume a version field equal to zero. I looked around but unfortunately I could not find hard proof about that - I'd still skip that part of the condition though.

...

combined.txt

There are also many devices with Version 0 in /proc/bus/input/devices. But I'm not clear why, maybe because it's virtual?

Edit:

Maybe used similar code as in the example to set up the virtual device without setting id.version.

Rindbee avatar Jan 09 '25 23:01 Rindbee

Added a method Input::set_joy_button_need_reshow() to restore hidden button events. If it's just the ABXY buttons that are confused, use Input::remove_joy_mapping() to remove and then add the modified mapping. But if the situation is worse or some buttons can't be found, use this method to restore the gamepad to its raw state. This allows users to write and use their own mappings.

Rindbee avatar Jan 10 '25 03:01 Rindbee

There are also many devices with Version 0 in /proc/bus/input/devices. But I'm not clear why, maybe because it's virtual?

Edit:

Maybe used similar code as in the example to set up the virtual device without setting id.version.

The code is here: https://github.com/DanielOgorchock/joycond/blob/master/src/virt_ctlr_combined.cpp

It looks like it manually sets the version to 0.

I mean, I don't see why that should be wrong; from all documentation it looks like the version is, if I understand correctly, completely vendor-defined. If it were related to bcdDevice (I'm not entirely sure) then it would still be valid as the BCD of 0 is 0b0.

I personally think it was just a wrong assumption from the "alternate" uid generation code (see the uidname thread).

deralmas avatar Jan 10 '25 08:01 deralmas

The code is here: https://github.com/DanielOgorchock/joycond/blob/master/src/virt_ctlr_combined.cpp

It looks like it manually sets the version to 0.

I mean, I don't see why that should be wrong; from all documentation it looks like the version is, if I understand correctly, completely vendor-defined. If it were related to bcdDevice (I'm not entirely sure) then it would still be valid as the BCD of 0 is 0b0.

I personally think it was just a wrong assumption from the "alternate" uid generation code (see the uidname thread).

Thanks for the explanation. If it's to be fixed, I'd prefer to address it in another PR. Like #95698, it is actually a bug fix.

Rindbee avatar Jan 10 '25 08:01 Rindbee

Thanks for the explanation. If it's to be fixed, I'd prefer to address it in another PR. Like https://github.com/godotengine/godot/pull/95698, it is actually a bug fix.

Yeah fair.

deralmas avatar Jan 10 '25 09:01 deralmas

Add more comments for cases where the Linux Gamepad Specification is not followed.

Rindbee avatar Jan 21 '25 03:01 Rindbee

@Rindbee: can you please add to the description that this PR fixes https://github.com/godotengine/godot/issues/101215 (so that github can make the connection)? thanks

MJacred avatar Apr 15 '25 12:04 MJacred

Superseded by #106218.

https://github.com/godotengine/godot/blob/30456ba095c425d5ecde320a96a763afb93bbcb0/thirdparty/sdl/joystick/linux/SDL_sysjoystick.c#L2227-L2233

The above method provides better mapping rules, ~~but it seems that there are still some things to do to enable it.~~

Rindbee avatar Jun 25 '25 11:06 Rindbee