schellingb / dosbox-pure

DOSBox Pure is a new fork of DOSBox built for RetroArch/Libretro aiming for simplicity and ease of use.
GNU General Public License v2.0
731 stars 61 forks source link

Add support for analog buttons (i.e. L2/R2 triggers) #447

Closed InterClaw closed 6 months ago

InterClaw commented 6 months ago

I also mentioned it here, but this should really be separate I think.

I discovered that in 0.9.8 the L2/R2 triggers are always only digital, even if I map one of the four axes to them (Joystick 1/2 X/Y). This was not the case under 0.9.7.

I didn't find another issue reported on this.

schellingb commented 6 months ago

This hasn't changed in 0.9.8. The core has always treated L2/R2 as digital buttons.

Though when using RetroArch you can map L2/R2 to one of the analog stick directions and then RetroArch can treat the triggers as analog and the core doesn't actually see L2/R2 getting pressed, instead RetroArch will tell it the analog stick is being moved. I think this is what you've been seeing as working, and this still works in 0.9.8.

InterClaw commented 6 months ago

Ah okay, but I'm not sure I understand how you mean it's still possible. Should I first set it up in the gamepad mapper and then override it in the RA menues somehow?

This is how I have it set up in the gamepad mapper. Screenshot 2023-12-16 232658

Just to clarify, I only intend to map half the range to L2. The problem is that it goes from the center point of the axis to the maximum value in one step, digitally, about halfway through depressing the trigger.

R2 is intentionally just a digital button in this setup, but mapping it to "Joy 2 Up" makes no difference (R2 takes it from the center point to the minimum value digitally).

This is how it looks in the RA menues. Device type shows as "Unknown" and the list of options are just the ones I've set in the gamepad mapper. Screenshot 2023-12-16 232739

Is there something in addition I need to do to make it work as an analog trigger under 0.9.8?

schellingb commented 6 months ago

If the core checks L2 it will be a digital check only. What you can do (and could do in 0.9.7) is to assign an analog stick direction to an analog function (like joystick or mouse movement) in the in-core Gamepad Mapper and then assign an analog button like L2/R2 on that axis direction in RetroArch's Controls settings. For me to get it work (in both 0.9.7 as well as 0.9.8) I needed to fiddle with the "Analog to Digital Type" setting (not sure why or what that affects really).

InterClaw commented 6 months ago

Okay I think I see what you mean now. Let me see if I've gotten this straight. Just spelling it out for myself mostly. 🙂

Whenever you're using the gamepad mapper inside the core (even prior to 0.9.8), the core is looking directly at the controller. If it detects me pushing the L2 trigger, it's always going to treat that analog input digitally, even if I have L2 bound to a joystick axis in the gamepad mapper. The result is that the core will change the control's value from the center point to the full value in an instant. It's the same behaviour as if I would have mapped the joystick axis to something truly digital, like L1. The core itself doesn't care if L2 is a digital button (like on an old PlayStation controller), or an analog axis; The control itself is always treated as something digital. Period.

The reason it works differently for me in 0.9.7 is that, up until then, you don't have to use the core's internal gamepad mapper. Instead, you can use the RetroArch input bindings. So if I on a per-game basis, on the quick menu, map L2 to "Stick 2 Vertical +" (which is what it's called there), the core is not actually detecting me physically pressing L2. It rather believes that the right stick is being pulled down and acts accordingly. L2 is not part of the equation here from the core's perspective.

Sadly this is not an option anymore in 0.9.8, so there is a limitation here in what you can accomplish with the physical L2/R2 triggers, putting it all together. But, yeah, we're discussing it here also. 😃

I was trying to figure out what you meant on how to work around it in your latest message and I think I get what you mean one has to do to still make it work in 0.9.8 (or with the gamepad mapper really I should say). One has to reconfigure how the controller itself is laid out by changing the config of it under "Settings > Input > RetroPad Binds" and physically put one stick axis on L2/R2. In my case I would have to put right stick down on L2 instead. Then the gamepad mapper (looking directly at the controller) will not know it's actually L2 I'm pressing, but instead just see the right stick being pulled and, if that is mapped to "Joy 2 down" in the gamepad mapper, give me analog input on the second DOS joystick in-game.

I'm of course not going to do this, since it will have implications for everything else and I can't set it on a per-game basis. That's the whole point of the controls on the quick menu. Changing how the controller is physically set up is not an option for me.

But now I get it (I hope)! Setting my hopes on continuing to be able to use the RetroArch controller configs in 0.9.8+ then to "trick" the core in what is being pressed! 👍

schellingb commented 6 months ago

To be fair, the libretro interface actually allows reading any button as analog values and that would allow us to correctly deal with this as expected with just using the gamepad mapper. But, I just didn't think about "analog buttons" at all when writing the original code many years ago. If I had thought about this while preparing this version I think I would have done some things differently to support that. So the request is a good one, I would like to do this properly. It's just not that simple with how some things are hard-wired as of now...

Edit: Sorry, looks like I was completely mistaken. The libretro API does not support reading anything but two analog sticks in an analog fashion. So no, we actually can't support analog L2/R2 triggers within the core. The only way to do this will be via custom remapping in RetroArch.

InterClaw commented 6 months ago

I guess there aren't that many old systems that even had the Z axis (if we call it that). But it's still a strange limitation to not expose all of the features of the modern controller (referring to the API). Even if they can't all effectively be put to use simultaneously in an analog way in the cores.

Sounds like this is a no-go then under the current circumstances. 😢

schellingb commented 6 months ago

Now I actually looked up the documentation instead of trying to make sense of the source code and it looks like this actually is possible, although it means every check for a button press needs two checks to have a fallback for frontends that don't support this. https://github.com/libretro/docs/blob/master/docs/development/input-api.md#analog-retropad

I tag this issue with "enhancement", maybe one day

schellingb commented 6 months ago

I actually implemented this now. I realized that we don't need to check all buttons for analog input, only the ones that are bound to an analog function (like joystick axis or mouse movement) which only happens if the user customized the control so it is very rarely needed. You can give it a shot in the new 0.9.9 release. Please report back, thanks.

InterClaw commented 6 months ago

It now works as expected. Thank you for fixing this! Now it's possible to map everything you want in just one mapping using "Custom Mapping" in the Gamepad Mapper. No exuse to still use my complicated setup using two RetroPad ports. 😊