atar-axis / xpadneo

Advanced Linux Driver for Xbox One Wireless Controller (shipped with Xbox One S)
https://atar-axis.github.io/xpadneo/
GNU General Public License v3.0
1.92k stars 111 forks source link

System goes to sleep without using keyboard/mouse just using Xbox One controller #158

Closed ipkpjersi closed 4 years ago

ipkpjersi commented 4 years ago

Describe the bug When I use the Xbox One controller, it does not count as an input. If I don't move my mouse or use my keyboard, my PC automatically goes to the screensaver and then goes to sleep as if the Xbox One controller was not a device at all. If I use my mouse or keyboard whilst I am also playing a game my PC does not go to screensaver and then sleep.

To Reproduce Use Ubuntu 18.04 LTS with the Xfce DE and Xscreensaver 5.36:

Expected behavior I expect using the Xbox One controller to count as input and not let the system go to screensaver and then sleep.

If you require any additional details please let me know.

atar-axis commented 4 years ago

That's a good point - will add that as soon as I can (I fear it will take some time, too busy at the moment).

ipkpjersi commented 4 years ago

Is there any additional information or debugging I can provide that would help with this task or do you generally know exactly how it would work?

kakra commented 4 years ago

Usually, games should inhibit the screensaver themselves while in-game. What types of games are affected? Proton games should work afair: Their Wine version should have a patch that inhibits the screensaver while a fullscreen game is running.

The problem may be that the game controller does not count as a keyboard or mouse, so it may be ignored by Xorg. Or, other option: The game controller does not generate events of type EV_KEY and thus it's ignored. Could you try v0.7? It has remapped the Xbox logo button to a keyboard event. Please check if you can stop the screensaver by pressing that button after the screensaver kicked in. If that works, we may synthesize some key events every once in a while.

ipkpjersi commented 4 years ago

It did still go to sleep/screensaver with 0.7, and pressing the xbox logo button (and I think even just the start button) woke it up. I'm not sure if phantom/synthetic key events would work - would that get detected as "game input" or is it just done at the OS-level? I'm not really sure how this works.

Edit: just tested more, the start button and all buttons "worked" as I could hear the menu in the game, but the only button that woke up the screen was the Xbox guide button.

kakra commented 4 years ago

Okay, so all we need is sending a keyboard event of type EV_KEY once in a while. That would actually generate a real keypress so we should find a key that usually does nothing in Linux or the usual desktop environments. Here's a list of available codes we could synthesize:

https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/input-event-codes.h#L177

(every KEY_* entry could work)

ipkpjersi commented 4 years ago

Just tested this with 0.6 again, the guide button does not wake up the screen even though the other buttons still work and I can still hear the menu in the game. 0.7 is definitely an improvement and it's already halfway solved this issue.

I have no idea what a good key to send would be so I probably can't help with that, sadly.

kakra commented 4 years ago

The guide button sent a game controller event in v0.6, that isn't picked up by anything on the desktop usually. Thus, I converted it to KEY_HOME. When your browser has focus, the guide button will switch to your homepage. If nothing else grabs this event, usually Steam will pick it up and show up. Pressing it a second time will then fire up its tenfoot launcher (Steam Big Picture mode). In theory, it should also open the Steam overlay while in a game. I didn't test it yet, and I'm not sure if KEY_HOME is really the correct event or if Steam could also work with another key event. I'm not completely happy with it because browsers can grab the key.

ipkpjersi commented 4 years ago

I forgot to mention that regardless of how this is implemented, I feel like it should probably either be able to be toggled on or toggled off as a module parameter in case it doesn't work as expected or doesn't work for everyone etc.

kakra commented 4 years ago

I came to the conclusion that this is not the fault of the driver and thus should not be fixed there. User space needs to watch input devices to inhibit the screen saver but game controllers are not treated as such. Even Windows does not, tho when watching Wine logs closely, you'll see that games send an API command to Windows to explicitly inhibit the screen saver. Native Linux games should do the same, desktop environments should already have an API for that (most media players already do that). If your report is about games running in Wine (or Proton), you should report there: The API call for inhibiting the screen saver needs to be propagated up to Xorg or the desktop environment.

In KDE you can work around it by defining a desktop activity which disables the screen saver and binding the Steam window to that activity. KDE will then switch to that activity when launching. This is how I've used it since years. I'm not sure how Gnome or other DEs handle it, tho.

You may also have luck by adding your controller as an input device to Xorg. Tho, how to do that is beyond the scope of this project. It also may have side effects like moving the mouse cursor or other unwanted inputs in applications that should not react to this:

[286962.214] (II) event21 - Xbox Wireless Controller: is tagged by udev as: Keyboard Joystick
[286962.214] (II) event21 - Xbox Wireless Controller: device is a keyboard
[286962.289] (II) config/udev: Adding input device Xbox Wireless Controller (/dev/input/js1)
[286962.289] (**) Xbox Wireless Controller: Applying InputClass "joystick-all"
[286962.289] (**) Xbox Wireless Controller: Applying InputClass "system-keyboard"
[286962.289] (II) No input driver specified, ignoring this device.
[286962.289] (II) This device may have been added with another device file.
[286985.958] (EE) libinput bug: Event for missing capability CAP_POINTER on device "Xbox Wireless Controller"
...
[287033.321] (EE) libinput bug: Event for missing capability CAP_POINTER on device "Xbox Wireless Controller"
[287936.638] (II) config/udev: removing device Xbox Wireless Controller
[287936.638] (II) event21 - Xbox Wireless Controller: device removed
[287936.655] (II) UnloadModule: "libinput"

This is from my log, Xorg already sees the device but discards it. The only thing that's left is the "keyboard" part by exposing the Xbox button as a keyboard event.

ipkpjersi commented 4 years ago

Well that's slightly disappointing to hear, it would have been nice if the driver could have fixed this. It would have been a huge enhancement to have my PC not go to sleep while I'm in the middle of gaming. After all, this driver has enhanced functionality beyond that found in Windows.

I'd love a workaround for this for Xfce, not sure if that's even possible, but I always have Steam open but still want my PC to go to sleep even with Steam open, just not when games are open.

I feel like there's not going to be an easy solution whatsoever for me to accomplish this.

I haven't had this problem on Windows as far as I can remember so this is definitely unfortunate.

kakra commented 4 years ago

I'll keep the idea in mind... Maybe when I've got time to work on Proton again. But the driver is clearly the wrong place to implement this.

Until then, I suggest to use a script like this as a starting point (untested):

#!/bin/bash
: ${1?:needs a parameter to execute}
xset s off
"$@"
xset s on

Put it in /usr/local/bin/inhibit-screensaver and then add it to your games launch options in Steam:

inhibit-screensaver %command%
ipkpjersi commented 4 years ago

I tried xset which didn't work but I did find a couple other good solutions. :+1:

I tried xset with a bunch of params, unfortunately none of them worked (either all in the same script, or only with one of them one at a time):

#!/bin/bash
xset s off 
xset s noblank
xset s -dpms
"$@"

However, I was recommended a couple bash applications/scripts that both seemed to do the trick so hopefully mentioning them here may help anyone else who runs into this issue. The first one I tried was joystickwake, a Python3 script which you can use to send commands (to prevent screensavers) when joystick activity is detected:

joystickwake [15:15:11] DEBUG js0 activity
joystickwake [15:15:11] INFO waking the screen
joystickwake [15:15:11] DEBUG X settings waker running command: xset dpms force on s reset
joystickwake [15:15:11] DEBUG XScreenSaver waker running command: xscreensaver-command -deactivate
joystickwake [15:15:11] DEBUG custom waker running command: xscreensaver-command -deactivate
joystickwake [15:15:11] DEBUG X settings waker succeeded
joystickwake [15:15:11] DEBUG js0 activity
xscreensaver-command: not active: idle timer reset.
joystickwake [15:15:11] DEBUG XScreenSaver waker succeeded

The second one is GameMode by the awesome Linux-friendly company Feral Interactive, it can disable the screensaver outright when running via Steam launch options gamemoderun %command%

Hopefully this information helps anyone else who runs into this issue. This is a huge improvement for me.

edit: Feral Interactive's GameMode still had my system go to sleep, maybe it's something weird with my setup (perhaps the same issue with xset not working properly for me, I opened an issue on their repository, but at least joystickwake is working perfectly for me. :+1:

kakra commented 4 years ago

Thanks for the heads-up.

Yes, I know gamemode, I contributed the Proton/Wine detection routines to it and some other stuff. The Wine detection is (in parts) still a PR. It should usually work for you but maybe you're using something that invokes xscreensaver by other means than Xorg itself?

Apparently, we cannot run user space programs like xscreensaver-command from within the driver. But your solution may be useful in the docs. I wonder what the performance cost of this is, tho. Does it run the commands on each joystick activity? That could be quite a lot in a short time...

ipkpjersi commented 4 years ago

For joystickwake it only issues the screensaver-command and/or similar commands every X number of seconds, I think the default is 30 seconds, but you can pass an interval parameter to it to specify how often you want it to run, I like specifying 60 seconds. Doesn't seem to affect performance and seems to work really well, plus it uses Python 3 instead of Python 2 so that's nice for future-proofing/forward-compatibility.

kakra commented 4 years ago

If you'd like to have that added to the documentation, feel free to open a PR with updated instructions about the driver.