inputs
inputs copied to clipboard
get_gamepad seems to block
For my application it is crucial to check if there are new events but if not, proceed with the other code.
However: In order to check for new events I need to call get_gamepad
which calls internal read
on the device. This function seems to block until an event arrives.
It would be awesome to add a nonblocking read or an option to specify all reads as nonblocking!
As always: Thanks for your library!
why was the blocking parameter never added to inputs? I either need to run part of my input handling in a seperate thread or I need to edit inputs to be nonblocking. it reduces my programs fps from 3000 to about 200 with most of the time being spent waiting for inputs.get_gamepad()
@Sartek not sure. Maybe the author of this lib is short on time?
yeah, the more I use this library the more I find issues with it that make it really hard to use. even if I were to run it in a seperate thread it would still max out the cpu. if I try to call time.sleep() the input seems to slow down and play at a reduced speed.
I added this in the _character_device() in the InputDevice class:
self._character_file = io.open(
self._character_device_path, 'rb')
fd = self._character_file.fileno()
flag = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, flag | os.O_NONBLOCK)
And then calling this in my code:
events = devices.gamepads[0]._do_iter()
To bypass the while True loop in iter(). Not so pretty but hey, it worked for me!
I think adding this flag and also yeilding an empty array in iter() if there is no data would be a nice complete solution but I never tried it.
@ErikOrjehag when I get events like you events = devices.gamepads[0]._do_iter()
I get this error:
Exception in thread Thread-2:
Traceback (most recent call last):
File "/usr/lib/python3.6/threading.py", line 916, in _bootstrap_inner
self.run()
File "/home/louis/Documents/IUT/s3a_s01_demange_gsell_noel_nosal/src/pilotage.py", line 84, in run
for event in events:
TypeError: 'NoneType' object is not iterable
So I use events = get_gamepad()
and it works but CPU jump to 100%...
Also I'm new to python so I don't understand everything, I modified the class like that and addedd import fcntl
, is this correct ?
@property
def _character_device(self):
if not self._character_file:
if WIN:
self._character_file = io.BytesIO()
return self._character_file
try:
self._character_file = io.open(self._character_device_path, 'rb')
fd = self._character_file.fileno()
flag = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, flag | os.O_NONBLOCK)
except PermissionError:
# Python 3
raise PermissionError(PERMISSIONS_ERROR_TEXT)
except IOError as err:
# Python 2
if err.errno == 13:
raise PermissionError(PERMISSIONS_ERROR_TEXT)
else:
raise
return self._character_file
@Nekzuris Because _do_iter() returns None when there are no events you need to do it like this:
events = devices.gamepads[0]._do_iter()
if events is not None:
for event in events:
print(event)
Thanks! Since I read controller inputs in another thread I added this sleep to reduce load on the CPU
events = devices.gamepads[0]._do_iter()
if events == None:
time.sleep(0.0001)
else:
for event in events:
print(event)
For what it is worth, the following gist is a use case why this issue is valid and that @ErikOrjehag's patch works. The application shows two circles that can be moved independently with the two joysticks of a gamepad. It is written with the goocanvas within gtk. Without Erik's patch you can't integrate input.py into gtk's event loop:
See: https://gist.github.com/dov/696db3faa1cc702b5362fd0bbb201cad
Hey, thanks for this thread!
Total beginner at this, sorry if I'm missing something obvious.
I'm having issues too with the blocking aspect of get_gamepad()
. I was trying to implement your patch, but the _do_iter()
method seems to return only None
here.
Furthermore, the try
statement in the _character_device
definition seems to always fail.
I'm on windows 10, is this a Linux specific patch, and if yes, any idea how to implement in windows?
thanks a lot!
@chienMouille try the linked pr I wrote back then
@Fuzzyma thank you so much! That pretty much solves it.
I didn't want to patch, so I just used a thread: ` import inputs import threading
eventList = []
def monitorGamepad():
while True:
try:
for e in inputs.get_gamepad():
eventList.append(e)
except inputs.UnpluggedError:
time.sleep(0.5)
gamepadThread = threading.Thread(target=monitorGamepad)
gamepadThread.daemon = True
gamepadThread.start()
def gamepadEvents():
copy = eventList[:]
eventList.clear()
return copy
def haveGamepad():
return len(inputs.devices.gamepads)>0
`