jgeumlek / MoltenGamepad

Flexible Linux input device translator, geared for gamepads
MIT License
277 stars 43 forks source link

[Feature Request] Press (or hold for x seconds) start if underlying gamepad disappears #33

Open TiZ-HugLife opened 7 years ago

TiZ-HugLife commented 7 years ago

Hiya. I've been happily playing games through MG without any problems so I haven't had anything to report for a while. Though I did have an idea.

I'm not doing anything to check the battery life of my DualShock 4s, so they periodically just die while I'm in the middle of gameplay. Right now, what seems to happen is that the last input that occurred when the controller died just persists, which could result in you killing yourself in some silly manner before you can hook up another one. It'd be better for inputs to just be totally cleared and for the controller to do nothing, but it'd be even better still if the game paused automatically after losing a controller. Since nearly every game that exists treats start as pause, all we'd have to do is press start if a controller disappears. Some games require you to hold it for x seconds to prevent accidental pauses, so maybe that could be a config option.

What do you think?

jgeumlek commented 7 years ago

That sounds like a good idea. I've thought about this before, as MoltenGamepad effectively removes any in-game support for detecting disconnected controllers.

There are two features I see here:

1) Clear output events when disconnected. This should be doable, triggered only when an output slot has its last input source removed. Sounds like a reasonable default, and likely doesn't need to be configurable.

2) Send a "pause" event when disconnected. This is hackish, but likely the best we can do for games that break when controllers disconnect. I think this should be a config option, and probably off by default. (disconnect in a menu and it might do the wrong thing...)

I hadn't thought about games filtering out short presses. I guess we should expose the press length as an option, perhaps in milliseconds? Might also need to expose an option for exactly what event gets sent too.

We should also differentiate between between sending a pause event when any output slot becomes empty, or only when all output slots become empty. Otherwise disconnecting controllers at a local-multiplayer player select screen could get messy...

ghost commented 7 years ago

Another option could be to emulate the way ds4drv handles this - it blinks the LED light, warning you in advance that the battery is nearly empty. Obviously this would require being able to determine it's charge level, not sure this is within the scope of MG.

What would also be cool is to change the color of the LED light. Ds4drv can do this as well. Maybe a dedicated driver could be provided for inclusion at compile time, like the WiiMote one?

TiZ-HugLife commented 7 years ago

Sorry for taking so long to reply, man. I more or less agree with everything you've suggested, @jgeumlek. Some games do indeed filter out short presses mainly to prevent accidental pauses in competitive play; the two that come to mind first are Skullgirls (mandatory) and TowerFall (optional). I'm pretty sure they both require two-second holds but a millisecond based option would still be good.

@RalfVB, I do like the idea, but MG is currently mostly agnostic about what it assumes about underlying controllers, at least in terms of the gendev ones. I don't know a lot about what sort of info is exposed about event devices, like if you can find the corresponding upower battery or sysfs LEDs.

I do have a script right over here that makes changing the lightbar easier without having to resort to a userspace driver, and also enables write access for regular users. The main thing that's a bummer about it is that with MG in the middle, games that can use the lightbar--TowerFall and Transistor are the two that I know--don't know that there are DS4s with writable LEDs around. The two games I mentioned are FNA games; I don't know if FNA checks specifically to see if they are DS4s, or just looks to see if they have writable RGB LEDs. (EDIT: I actually checked because I was curious; FNA specifically checks for DS4s.) If the latter, MG could theoretically provide an indirection layer in the form of its own virtual RGB LEDs, which just do nothing if the underlying controller doesn't have real ones... but now we are talking way outside the scope of this particular issue. Theorycrafting is fun, though.

To get back to your particular suggestion, if I can find a way to monitor particular upower battery levels and associate it with a particular LED set, I could improve that script I linked with a background process that would start blinking the lightbar if battery dropped below a certain level. MG is responsible for controlling what userspace applications see, so I think your particular suggestion is better handled outside of it since it's about specific devices and their state independent of what applications are or are not looking at them.

jgeumlek commented 7 years ago

Hello. Real life has been busy, and will continue to be for a couple weeks.

Here's just a quick update on my thoughts/plans here.

LED blinking for low power

Not a bad feature, but unlikely to be a focus for development. Currently MG doesn't track battery levels, and both battery and LED stuff is outside of the Linux input layer where MG resides. (Pedantic note: the input layer does have EV_LED events, but they aren't used for game pads. There is no defined standard for player indicators, and this interface doesn't map well to RGB leds...)

An external solution like what TiZ-EX1 linked is likely the best path.

DS4 built in driver

This would be necessary for any fancy LED features. I haven't written it as I have limited interest: the generic driver does what I need for now. If anyone wants to tackle it, I'll gladly include it and help out.

Until some battery tracking/LED setting features are added to MG, there won't be much gain from shifting away from generic.

Letting games use the lightbar

It is a shame that MG prevents this by making games unaware that the DS4 exists. When I played through Transistor, I simply stopped MG whenever I played.

I don't really know how best to fake the LED files in sysfs. Might be able to get away with inotify to tell when the game writes to it. Probably needs root to create the files though? Unfortunately we only have uinput, not uhid or something to fake the controller at a lower level.

My best idea on this: let a MG driver enter "passthrough" mode, where devices claimed by the driver don't become input sources for MG, they just get chmod'd with more permissions. This would make the original DS4 usable by games even if MG was installed as a system user.

Syntax for the automatic pausing

The obvious location is to add more options to the slot manager. There are already a couple if you check print options slots.

So two options. One for whether the feature is enabled, and one for the length.

What should the name of these options be? autopause? disconnect_start_press?

The option to enable it should likely control whether we do it for any empty controller, or only on the last controller. That's three states, so I'm thinking this option should be a string with three possible values.

Proposal:

# can be set to "all", "last", or "none"
press_start_on_disconnect = "all"
press_start_on_disconnect_ms = 2000

MG's support for string-type options is there, but mostly untested. Got to be careful about what happens if it is set to a string that isn't one of the three choices.

TiZ-HugLife commented 7 years ago

Hey fam, I feel you on real life being busy, don't sweat it.

DS4 LED blinking on low power

Don't sweat this one, man. I'll just take care of it by amending and improving the ds4-lightbar script. I have a similar xpad-led script that stops the light from blinking. People are using userspace drivers like ds4dev and xboxdrv to fix these problems right now, and I want to make sure those two scripts are as good as possible so I can get people away from the userspace drivers.

DS4 built in driver

It's true that right now, the DualShock 4 is the only controller that exposes a colored LED. That could change in the future, though. FNA has coded against that assumption and been burned for it before when flibit had to update for the GUID of the second model DS4. That's why I wanted to advocate for MG exposing its own virtual LEDs that could be connected to optional, real LEDs through the gendev driver. While it is true that right now, everything would ignore MG's hypothetical LEDs, we could poke flibit to change that in FNA.

Letting games use the lightbar

Something that bothers me about the thought of a passthrough mode is that I'm afraid a race condition could occur between MG and udev on system setups. I imagine we could find a way to work around this if udev is given enough information from MG at the time a device is plugged in. I think this would be a good stopgap.

But something I'd rather actually have is the ability for MG to imitate multiple controllers and change between them at runtime. Right now you can either imitate a custom hypothetical controller called MoltenGamepad, or you can imitate a first party 360 controller. My setup works pretty well with that, save for one thing; when I'm teaching other people how to play games, I often have to tell them "imagine that dualshock 4 you're holding is actually an xbox controller" because the game is showing Xbox button prompts, and people who aren't gaming minded have trouble with that. Some games have the ability to change their button prompts if they detect that the controller in use is a PS3 or PS4 controller. If MG imitated a PS4 controller for games that we know can change its prompts, it'd be a better user experience for PS2/3/4 controllers as well as some Logitech models.

You might be thinking, "if games know how to handle PS4 controllers, why are you even sticking MG in the middle?" Well, MG provides more benefits than just imitating other controllers. It creates a virtual mice and keyboard to provide antimicro-like functionality at the event device level. It allows you to remap controls at the event device level (there are a lot of games that should respect the dpad and don't; I can force them to do that!). It allows you to provide hotplugging for games that don't handle it especially well or freak out if controllers aren't arranged contiguously in /dev/input (looking at you, Unity). Just having MG around makes controllers more sane and more customizable, so I'm not planning to kick it even though 4.10 changed the DS4's mappings to match 360 controllers as part of a "Linux standard gamepad" initiative (which reminds me, I gotta make a PR against MG-Files to fix that for you before more people get 4.10.)

This kind of thing merits a separate issue in the tracker. I'll open that up later.

Syntax for automatic pausing

Yes good I like that.

...yep, that's all for this one.

Okay, never mind I've got one more thing: When I'm dealing with string options, when I encounter an invalid one, I write a warning to stderr and fall back to the default.

jgeumlek commented 7 years ago

I agree that the race condition for controller passthrough is a problem -- the user would have to avoid hotplugging in game (which sucks, but isn't the end of the world). A better solution could be done via udev, as it does permit running arbitrary programs in its decision making.

It would be nice to let MG simulate other controllers. DS4's have a lot more going on than a 360 controller, but chances are just creating an event device that resembles it would be enough for most uses.

We could add a "--mimic-ds4" option, but that would just create the opposite problem. This ties in with issue #31. MG currently assumes its uinput virtual controllers exist for the entire lifespan of MG, and that assumption will take some work to change. If we get that fixed, than supporting changing the virtual controllers at runtime will be feasible too. With #31, we could also add some settings to make the virtual controller automatically try to match the input source that requested the slot.