ValveSoftware / Proton

Compatibility tool for Steam Play based on Wine and additional components
Other
24.39k stars 1.07k forks source link

Prevent joysticks from being seen as gamepads #4579

Open kakra opened 3 years ago

kakra commented 3 years ago

Feature Request

I confirm:

Description

Currently, joysticks (e.g., my HOTAS with stick, throttle and paddles) is detected as a gamepad. Several games become confused by this, e.g. Batman Arkham Knight only allows the first gamepad detected to be used, so this is usually my HOTAS. Other games just turn the player wildly around because some throttle is offset from an imaginary center point (which a throttle doesn't have). Additionally, the joystick cannot even be used properly as a gamepad input because BTN_{A,B,X,Y} does not exist on those.

Maybe we could add an environment variable which allows to blacklist joysticks per game, or they should generally not be available as xinput devices at all (Proton could detect that by looking if there's a BTN_GAMEPAD event key code in the mapping). This is probably an SDL2 thing, and I'm not sure if Proton could even tell a gamepad from a joystick with SDL2 because it probably only reports axes and buttons but not their original evdev symbolic names.

The core problem is probably that SDL2 treat joysticks and gamepads as the same type of device although they are vastly different input devices. So a proper fix is probably to flag the devices properly in SDL2.

I think there's SDL_GAMECONTROLLER_IGNORE_DEVICES=0xVVVV/0xPPPP,... to do this, I will try that. But Proton could probably make that easier by either automating this or curate a list of devices so that we could easily fix it with a one shot variable, e.g. PROTON_NO_JOYSTICKS=1 %command%.

Justification [optional]

Usage of SDL2 for xinput is probably not even part of Wine, so it's a Proton thing.

Risks [optional]

References [optional]

Related but different use-case: https://github.com/ValveSoftware/Proton/issues/3288

kakra commented 3 years ago

I'm currently using the following snippet in my launcher wrapper script to hide the joysticks from all games by default except I set PROTON_USE_JOYSTICK=1:

[ "${PROTON_USE_JOYSTICK}" -eq "1" ] || export SDL_GAMECONTROLLER_IGNORE_DEVICES=0x044F/0xB10A,0x044F/0xB687

Maybe it helps someone. The VID/PID codes are for the Thrustmaster 16000 HOTAS.

berniyh commented 1 year ago

I support this. This is especially annoying, if you actually want to use a joystick (so deactivating it like above is not a solution). However, it being seen as a gamepad can result in problems, e.g. if some of the axis are not centered by default (think of a throttle or brake). If gamepad mode is activated for such a device, it will be used for navigation in the menus rendering the whole thing useless, since navigation is practically impossible. The best solution I could find so far was to define a specific axis map for the gamepad to remap the x and y axis to something else (e.g. rx and ry), so that they are not used for navigation anymore. A better solution would be greatly appreciated.

berniyh commented 1 year ago

This is getting more and more annoying if you have a joystick device that is affected by this problem and you can't properly use it. Before, I was just switching back to Proton 7.0, but now some games (e.g. American Truck Simulator) won't work with that anymore and you need 8.0+ With 8.0+ however, the pedals misbehave in the menus and always navigate to the upper left corner, because those axis on that pedals joystick are not centered by default (it's not a gamepad …). So please add a Variable IS_NOT_A_GAMEPAD or something like that to prevent this false detection as a gamepad.

This bug/regression basically renders my pedals useless …

kakra commented 1 year ago

It should work by setting:

PROTON_ENABLE_HIDRAW=0xVID/0xPID

with VID/PID being a upper case 4-digit hex value, and your user must have read access to the hidraw device (can be done via udev).

E.g. I'm using:

PROTON_ENABLE_HIDRAW=0x044F/0xB10A,0x044F/0xB687,0x231D/0x0200,0x231D/0x0201

to ignore my VKB and Thrustmaster from being detected as a gamepad but still being detected as a joystick. You may currently need to clear the prefix due to driver caching issues in the registry (the registry may still link those devices to the xinput driver). You can also selectively remove all references to the vid/pid from system.reg.

See also:

berniyh commented 1 year ago

Thanks for the suggestion, I already know about the variable PROTON_ENABLE_HIDRAW variable. Was actually there when it was created. ;) Unfortunately, enabling that brings some other issues with it. Sim racing pedals often need manual calibration, either via dedicated software or via a tool like DXView. The latter doesn't work for me with current wine versions, it'll say that it failed to set a property if I try to set a calibration for the device. I don't know of any other way to calibrate an hidraw device, so this isn't going to work either.

Anyways, even if hidraw would be working, it would still be just a workaround. The current SDL implementation they have in Steam is clearly misbehaving and doing something that it should not do. It'd be ok if there would be a variable to disable that behavior or even better a switch in the controller menu of Steam, but there isn't. If Steam decides your non-gamepad controller is a gamepad, you're in trouble.

berniyh commented 1 year ago

btw, the original Wine does have this implemented: https://wiki.winehq.org/Useful_Registry_Keys

HKEY_LOCAL_MACHINE
|
+-System
   |
   +-CurrentControlSet
      |
      +-Services
         |
         +-WineBus
            |
            +->Map Controllers
                [DWORD value (REG_DWORD): Enable (0x1, default) or disable (0x0) conversion from
                 SDL controllers to XInput-compatible gamepads. Only applies to SDL backend.]

But of course I've tried that and it doesn't work with Proton's implementation.

kakra commented 1 year ago

But of course I've tried that and it doesn't work with Proton's implementation.

Proton doesn't use SDL in this case, the joysticks are detected via udev and hidraw. If you revoke hidraw permissions, that setting might apply.

berniyh commented 1 year ago

But of course I've tried that and it doesn't work with Proton's implementation.

Proton doesn't use SDL in this case, the joysticks are detected via udev and hidraw. If you revoke hidraw permissions, that setting might apply.

This is not one of the devices that uses hidraw per default, so I think it would need to be enabled using the PROTON_ENABLE_HIDRAW variable, which I did not (or rather I removed that before testing). Nevertheless, I got it working somehow and now that registry setting seems to be respected and it's recognized as a joystick. I'm not quite sure what I did that it works now, but it does, still trying to find out what the difference between before and now is. What I did find however, and I'm surprised that I didn't notice this before is this:

Oct 15 16:04:10 draco kernel: input: Heusinkveld Engineering HE SIM PEDALS as /devices/pci0000:00/0000:00:08.1/0000:0d:00.3/usb7/7-2/7-2.4/7-2.4.2/7-2.4.2:1.0/0003:10C4:8B02.001C/input/input49
Oct 15 16:04:10 draco kernel: hid-generic 0003:10C4:8B02.001C: input,hidraw16: USB HID v1.11 Gamepad [Heusinkveld Engineering HE SIM PEDALS] on usb-0000:0d:00.3-2.4.2/input0

So this device, for some reason, gets detected by the kernel as a "gamepad", while all the others are getting detected as "joystick". Looking at the hid descriptor, I found that it does indeed report as a gamepad:

0x00,              // Unknown (bTag: 0x00, bType: 0x00)
0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
0x09, 0x05,        // Usage (Game Pad)
0xA1, 0x01,        // Collection (Application)
...

No idea, why that is, but I guess it's not Proton's or SDL's fault that it's wrongly detected then.

kakra commented 1 year ago

Technically, for user space to identify a device, it should look at the keymap: If the device has BTN_GAMEPAD, it's a gamepad. If it has BTN_JOYSTICK, it's a joystick. But for wheels this becomes trickier. This should usually be a joystick under the hood (except it is made for Xbox), and then user-space should look at presence of some axes, I think. Pedals are even more weird, because they don't have buttons at all. Identification is only defined by the presence of buttons in the bitmap.

See: https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h

There's a BTN_WHEEL which should be used for wheels. But this may need special drivers which properly map their key codes to that range - unless the usage page identifies as a wheel. Wheels often have more buttons than just a button, gear up, and gear down. And so they become joysticks or gamepads in HID.

Linux often just uses generic HID drivers for input devices - and this works in most cases. But it doesn't work in some cases. The best is probably to enable PROTON_ENABLE_HIDRAW for those devices and let Proton implement the logic to identify devices properly via hard-coding.

It may also be useful to submit evemu-describe results to SDL, examples: https://github.com/libsdl-org/SDL/issues?q=is%3Aissue+evemu-describe

berniyh commented 1 year ago

Pedals are even more weird, because they don't have buttons at all. Identification is only defined by the presence of buttons in the bitmap.

Be careful with that. It really depends on the implementation. The controller of my pedals has pins available that can be used to connect buttons to it. So yeah, it'll report a number of buttons, even though I have nothing connected to them at this point. I do however use that functionality on my handbrake, which uses more or less the same controller. There I connected shifter paddles.

Linux often just uses generic HID drivers for input devices - and this works in most cases. But it doesn't work in some cases. The best is probably to enable PROTON_ENABLE_HIDRAW for those devices and let Proton implement the logic to identify devices properly via hard-coding.

I'm more than happy to use hidraw for these devices, if you tell me how to calibrate them using wine. ;) In general, it would also be quite annoying to have to calibrate them again for each proton prefix (and whenever proton decides for whatever reason that the current prefix is not usable anymore and silently creates a new one). It's much more convenient to just do it once via udev hwdb and then forget about it.

It may also be useful to submit evemu-describe results to SDL, examples: https://github.com/libsdl-org/SDL/issues?q=is%3Aissue+evemu-describe

Will investigate, thanks.

twhitehead commented 11 months ago

I put together a patch to still use udev for device classification even if in a container. If anyone want to try it, I rebuilt libSDL2 for all the current steam runtimes. You can get them here (see the README.txt file for how to install them).

Note that this may not effect all programs. You can check what libSDL2 a program is using by running

lsof -p <PID> | fgrep libSDL2

where <PID> is the process id obtained from looking the program up with ps -HU $USER. On my system, for example, while Proton uses the steam runtime libSDL2.so, steam itself uses my OS libSDL2.so.

ChaosRifle commented 2 months ago

Still an issue: My virpil devices, namely joysticks, are detected as xbox controllers. Virpil stuff has dynamic names, VID, PID, and buttons/axis as the end user can tune all of these. They should all have a VID of 3344 but technically a user could change this.

twhitehead commented 2 months ago

As of August 28 2004 (today) the steam general availability release is only on SDL 2.30.2. This is not a recent enough version as it is missing this commit. Try the public beta as it is SDL 2.30.6, which has everything.

twhitehead commented 2 months ago

To be clear, this this will only address you issue if you device is classified properly in udev and the steam container is running such that it has access to your udev classification (i.e., not it flatpack).