aardappel / procrastitracker

a Windows time tracking application
http://strlen.com/procrastitracker/
500 stars 53 forks source link

Xbox Controller Connected detection #44

Closed nuzayets closed 6 years ago

nuzayets commented 6 years ago

Was thinking of implementing actually checking the controller state, but polling the controller at the sample frequency doesn't seem reliable. This works well for wireless controllers though.

aardappel commented 6 years ago

Thanks (will check code iab).. I fear that for many people the controller option will not be that useful, e.g. mine is always plugged in but I hardly use it. What is unreliable about polling it? I guess when a game wants to take exclusive control of it it stops working?

nuzayets commented 6 years ago

I don't expect Xinput to stop working just because someone else is polling it too ... the docs don't seem to indicate that ... but, for example, if we just track differences in controller state, we need to implement a deadzone (analog input can drift without anyone touching the controller) or ignore the sticks and triggers, and we need to poll far more frequently than the typical PT wake frequency (i.e. so we are running when the user is depressing a button). It leaves a lot up to chance. The other option is to wake far more frequently, like many times per second, to poll the controller which I don't think we would want to do that.

Basically a naive low-impact implementation will be prone to error by chance, and a thorough implementation for detecting controller activity will see this little app taking more CPU time than we'd like.

Though if I am bored and have time, I can look into testing a few different implementations of this. I only have 1 wired and 1 wireless Bluetooth controller though, definitely not the full gamut of Xinput devices.

aardappel commented 6 years ago

from https://docs.microsoft.com/en-us/windows/desktop/api/xinput/ns-xinput-_xinput_state

The dwPacketNumber member is incremented only if the status of the controller has changed since the controller was last polled.

So you should be able to just compare this number against the previous to see if the controller is active? You should be able to do this on the timer callback?

nuzayets commented 6 years ago

I saw that, and I thought about it, but I still think there would be jitter from the analog inputs.

nuzayets commented 6 years ago

... but, I tested it, and it doesn't seem to be an issue with either of my controllers. I will leave it disabled by default and commit the change.

nuzayets commented 6 years ago

OK, sorry for the spam ... Further testing shows that with an Xbox 360 controller plugged in, the packet number does increment occasionally without touching the controller. This method won't work.

edit: Try it yourself here https://github.com/nuzayets/procrastitracker/tree/xinput-activity-detection

aardappel commented 6 years ago

Hmm that's a shame. How often are the spurious inputs? I wonder if it is worth setting a threshold, e.g. input less than once a minute counts as idle? I'm just hoping there is a solution that works "ok" for most people, since it depending on the device being plugged in seems not that useful to me.

That said, if you feel there's no better solution I am fine merging this for the moment.

nuzayets commented 6 years ago

A lot of people have wireless controllers ;-)

The spurious inputs are device-dependent. My wired Xbox 360 is pretty good and it sees one every 20 seconds or so, but I have seen other controllers where if you leave it on an Xinput property page (Windows controller settings, etc, anything that displays the position of the analog inputs) the input dances around the center quite a lot, those will probably see a constant stream of spurious 'inputs'. There are lots of crappy XInput devices out there, especially devices connected with XInput emulator drivers -- that may be reading from a 1990s analog joystick.

I am thinking creating a polling thread that implements deadzones for analog inputs and updates a 'last activity tick' like your keyboard poll thread. Make polling frequency configurable. Polling thread starts only if controller is connected & option enabled, stops when disconnected. If thread is very lightweight, probably won't cost too much CPU time. Would work well enough at a low frequency, like 1-5Hz, because we don't care about a few false negatives, just need to capture a true positive within the set idle time. The most important thing is to avoid false positives and a generous deadzone will accomplish that.

But if I get around to that I'll put it in another PR, if you could merge this one please. I have a full time job where I would get funny looks if I brought in an Xbox Controller :)

aardappel commented 6 years ago

If 1hz would be sufficient (and I'd hope if you're playing a game then 300 samples at 1hz or so should catch at least one controller input before it goes idle) then you could also use an additional timer instead of a thread?

nuzayets commented 6 years ago

I was thinking a thread pool timer, best of both worlds. Avoids the message pump, yes?

aardappel commented 6 years ago

SGTM :)