chrippa/ds4drv

`PS` button raises RuntimeError('There is no current event loop in thread %r.'

SimonLammer opened this issue ยท 13 comments

I'm trying to create a keyboard/mouse setup for anki with my controller.

I start ds4drv --hidraw:

[info][controller 1] Created devices /dev/input/js0 (joystick) /dev/input/event21 (evdev)
[info][controller 1] Connected to Bluetooth Controller (A4:53:85:86:E2:AB hidraw4)
[info][hidraw] Scanning for devices
[info][controller 1] Battery: 62%

So far nothing happens when I push buttons on the controller (except PS).
Upon pressing the PS button however, the following Exceptions show up:

[info][controller 1] Switching to profile: kbmouse
Exception ignored in: <function InputDevice.__del__ at 0x7f80352723a0>
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/evdev/device.py", line 159, in __del__
    self.close()
  File "/usr/local/lib/python3.8/dist-packages/evdev/device.py", line 304, in close
    super().close()
  File "/usr/local/lib/python3.8/dist-packages/evdev/eventio_async.py", line 54, in close
    loop = asyncio.get_event_loop()
  File "/usr/lib/python3.8/asyncio/events.py", line 639, in get_event_loop
    raise RuntimeError('There is no current event loop in thread %r.'
RuntimeError: There is no current event loop in thread 'Thread-1'.
Exception ignored in: <function InputDevice.__del__ at 0x7f80352723a0>
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/evdev/device.py", line 159, in __del__
    self.close()
  File "/usr/local/lib/python3.8/dist-packages/evdev/device.py", line 304, in close
    super().close()
  File "/usr/local/lib/python3.8/dist-packages/evdev/eventio_async.py", line 54, in close
    loop = asyncio.get_event_loop()
  File "/usr/lib/python3.8/asyncio/events.py", line 639, in get_event_loop
    raise RuntimeError('There is no current event loop in thread %r.'
RuntimeError: There is no current event loop in thread 'Thread-1'.
Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.8/threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/__main__.py", line 109, in run
    self.loop.run()
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/eventloop.py", line 101, in run
    callback()
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/__main__.py", line 106, in read_report
    self.fire_event("device-report", report)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/__main__.py", line 38, in fire_event
    self.loop.fire_event(event, *args)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/eventloop.py", line 86, in fire_event
    self.process_events()
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/eventloop.py", line 92, in process_events
    callback(*args)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/action.py", line 73, in _handle_report
    self.handle_report(report)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/actions/binding.py", line 105, in handle_report
    binding.callback(report, *binding.args)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/actions/binding.py", line 62, in <lambda>
    lambda r: self.controller.next_profile())
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/__main__.py", line 61, in next_profile
    self.load_profile(self.profiles[next_index])
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/__main__.py", line 47, in load_profile
    self.load_options(profile_options)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/__main__.py", line 93, in load_options
    self.fire_event("load-options", options)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/__main__.py", line 38, in fire_event
    self.loop.fire_event(event, *args)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/eventloop.py", line 86, in fire_event
    self.process_events()
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/eventloop.py", line 92, in process_events
    callback(*args)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/actions/input.py", line 75, in load_options
    self.joystick.device.close()
  File "/usr/local/lib/python3.8/dist-packages/evdev/uinput.py", line 205, in close
    self.device.close()
  File "/usr/local/lib/python3.8/dist-packages/evdev/device.py", line 304, in close
    super().close()
  File "/usr/local/lib/python3.8/dist-packages/evdev/eventio_async.py", line 54, in close
    loop = asyncio.get_event_loop()
  File "/usr/lib/python3.8/asyncio/events.py", line 639, in get_event_loop
    raise RuntimeError('There is no current event loop in thread %r.'
RuntimeError: There is no current event loop in thread 'Thread-1'.

After that, no button presses on the controller do anything anymore (not even PS).


I also noticed, that when I start it with ds4drv --hidraw --mapping keyboard, I can move the mouse with the right stick, type wasd with the left stick and do some other things.

ds4drv --hidraw --mapping keyboard
[info][controller 1] Connected to Bluetooth Controller (A4:53:85:86:E2:AB hidraw4)
[info][hidraw] Scanning for devices
[info][controller 1] Battery: 62%

When I then press PS once, I can also use the trackpad to move the mouse, but the following error appears:

[info][controller 1] Switching to profile: kbmouse
Exception ignored in: <function InputDevice.__del__ at 0x7f9d612cc3a0>
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/evdev/device.py", line 159, in __del__
    self.close()
  File "/usr/local/lib/python3.8/dist-packages/evdev/device.py", line 304, in close
    super().close()
  File "/usr/local/lib/python3.8/dist-packages/evdev/eventio_async.py", line 54, in close
    loop = asyncio.get_event_loop()
  File "/usr/lib/python3.8/asyncio/events.py", line 639, in get_event_loop
    raise RuntimeError('There is no current event loop in thread %r.'
RuntimeError: There is no current event loop in thread 'Thread-1'.

If I hit PS again, the controller ceases that functionality with:

[info][controller 1] Switching to profile: xpad

And upon pressing PS yet again, the long Error we've already seen shows up:

[info][controller 1] Switching to profile: default
Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.8/threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/__main__.py", line 109, in run
    self.loop.run()
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/eventloop.py", line 101, in run
    callback()
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/__main__.py", line 106, in read_report
    self.fire_event("device-report", report)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/__main__.py", line 38, in fire_event
    self.loop.fire_event(event, *args)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/eventloop.py", line 86, in fire_event
    self.process_events()
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/eventloop.py", line 92, in process_events
    callback(*args)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/action.py", line 73, in _handle_report
    self.handle_report(report)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/actions/binding.py", line 105, in handle_report
    binding.callback(report, *binding.args)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/actions/binding.py", line 62, in <lambda>
    lambda r: self.controller.next_profile())
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/__main__.py", line 61, in next_profile
    self.load_profile(self.profiles[next_index])
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/__main__.py", line 47, in load_profile
    self.load_options(profile_options)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/__main__.py", line 93, in load_options
    self.fire_event("load-options", options)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/__main__.py", line 38, in fire_event
    self.loop.fire_event(event, *args)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/eventloop.py", line 86, in fire_event
    self.process_events()
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/eventloop.py", line 92, in process_events
    callback(*args)
  File "/usr/local/lib/python3.8/dist-packages/ds4drv/actions/input.py", line 75, in load_options
    self.joystick.device.close()
  File "/usr/local/lib/python3.8/dist-packages/evdev/uinput.py", line 205, in close
    self.device.close()
  File "/usr/local/lib/python3.8/dist-packages/evdev/device.py", line 304, in close
    super().close()
  File "/usr/local/lib/python3.8/dist-packages/evdev/eventio_async.py", line 54, in close
    loop = asyncio.get_event_loop()
  File "/usr/lib/python3.8/asyncio/events.py", line 639, in get_event_loop
    raise RuntimeError('There is no current event loop in thread %r.'
RuntimeError: There is no current event loop in thread 'Thread-1'.

No button pressing on the controller yields any reaction now.

My ~/.config/ds4drv.conf (copied from some sample configuration):

# Many of the settings used here are directly connected to their command line
# counterparts, see "ds4drv --help" for more information about available options.

##
# Global options
##
[ds4drv]
# Run ds4drv in background as a daemon
#daemon = true

# Location of the log file in daemon mode
#daemon-log = ~/.cache/ds4drv.log

# Location of the PID file in daemon mode
#daemon-pid = /tmp/ds4drv.pid

# Enable hidraw mode
#hidraw = true


##
# Controller settings
#
# This is the default profile for each controller.
# Multiple controllers slots are defined by increasing the number.
#
# Controller sections contain:
#  Key: A option, these are the same options that can used on the command line
#       but without the "--" prefix.
#  Value: The option's value, should be "true" if no value is needed.
#
# See "ds4drv --help" for a complete list of available options.
##sdwasawdwasdadawdsdadaw
[controller:1]
# Enables LED flash on low battery
#battery-flash = true

# Sets LED color
#led = 0000ff

# Enables profile switching
profile-toggle = PS

# Profiles to cycle through
profiles = kbmouse,xpad


##
# Profiles
#
# Profiles allows switching controller settings during runtime.
#
# Profile sections always require a name and are then enabled on a controller
# with "profiles = <profile1>[,<profile2>]".
#
# The same settings available for controllers are used here.
##
[profile:xpad]
led = ff0000
# Emulate the same button mapping as wired Xbox 360 controllers
emulate-xpad = true

[profile:kbmouse]
led = 00ff00
# Enable trackpad mouse
trackpad-mouse = true
# Custom button mapping
mapping = keyboard
# Custom action bindings
bindings = exec_stuff


##
# Mappings
#
# Mappings let you map buttons and sticks to mouse, key and joystick events.
#
# Mapping sections always require a name and are then enabled in a profile
# with "mapping = <name>".
#
# Mapping sections contain:
#  Key: A Linux input event, see /usr/include/linux/input-event-codes.h for a complete list
#  Value: Button on the DS4, use --dump-reports to see all the available buttons
##

[mapping:keyboard]
# General button to key mapping
KEY_UP = dpad_up
KEY_LEFT = dpad_left
KEY_DOWN = dpad_down
KEY_RIGHT = dpad_right
KEY_Z = button_cross
KEY_X = button_circle

# Turn analog stick directions into buttons
KEY_W = -left_analog_y
KEY_A = -left_analog_x
KEY_S = +left_analog_y
KEY_D = +left_analog_x

# Map relative mouse movement to a analog stick
REL_X = right_analog_x
REL_Y = right_analog_y

# Map mouse buttons
BTN_LEFT = button_r2
BTN_RIGHT = button_l2

# Emulate mouse wheel on r1 and l1
REL_WHEELUP = button_l1
REL_WHEELDOWN = button_r1

# Mouse settings
#mouse_sensitivity = 0.6
#mouse_deadzone = 5

# Scroll wheel emulation settings (values are in seconds)
#mouse_scroll_repeat_delay = 0.25 # How long to wait before continual scrolling
#mouse_scroll_delay = 0.05 # Lower this to scroll faster; raise to scroll slower


##
# Bindings
#
# Bindings let you bind button combos to special built-in actions.
#
# Binding sections can be defined with a name and are then enabled in a profile
# with "bindings = <name>".
#
# It's also possible to define a global bindings section that is enabled
# on all profiles.
#
# Sections contains:
#  Key: A button combo
#  Value: An action, see next section for valid actions.
#
#
# Valid actions:
#  next-profile                                  Loads the next profile
#  prev-profile                                  Loads the previous profile
#  load-profile <profile>                        Loads the specified profile
#  exec <command> [arg1] [arg2] ...              Executes the command with
#                                                specified arguments
#  exec-background <command> [arg1] [arg2] ...   Same as exec but launches in
#                                                the background
#
#
# Actions will be pre-processed and replace variables with real values.
#
# Valid variables:
#  $profile                The current profile
#  $name                   Pretty name of the current device
#  $device_addr            Bluetooth address of the device
#  $report.<attribute>     Replace <attribute> with a valid attribute,
#                          use --dump-reports to see which are available
##

[bindings]
# Cycle profiles
#PS+Right = next-profile
#PS+Left = prev-profile

# Go directly to specified profile
PS+Up = load-profile kbmouse
#PS+Down = load-profile default


[bindings:exec_stuff]
# Execute a command in the foreground, blocking until it has finished
PS+Cross = exec echo '$name'

# Execute a command in the background
PS+Triangle = exec-background sh -c 'echo "disconnect $device_addr" | bluetoothctl'

  1. Why do these errors show up and how do I fix them?
  2. The second example gets me to believe that the controller is a privileged paperweight in default profile - is that because my configuration is faulty? Is there some way to keep the controller from entering default profile, cycling only the others?
  3. Is there a way to start ds4drv with a specific profile (e.g. kbmouse) without having to switch profile using the controller?

I have the same issue here!
So basically, it is not because pressing the PS button, it is when we change the default mode. You just have the PS button set for changing this, I have another combo, but the same result.
According to the error message I have a feeling that this might be a python version issue, i.e., we are using too new python that handles this asyncio in a different way?

What is the recommenced python version which this driver works the best with?

cslev commented

I have the same issue with python 3.8. I have deleted ds4drv from the python3.8 paths, and reinstalled it via python2.7.
Now, it still crashes when changing mode, but now different error:

Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 754, in run
    self.__target(*self.__args, **self.__kwargs)
  File "build/bdist.linux-x86_64/egg/ds4drv/__main__.py", line 110, in run
    self.loop.run()
  File "build/bdist.linux-x86_64/egg/ds4drv/eventloop.py", line 105, in run
    callback()
  File "build/bdist.linux-x86_64/egg/ds4drv/__main__.py", line 107, in read_report
    self.fire_event("device-report", report)
  File "build/bdist.linux-x86_64/egg/ds4drv/__main__.py", line 39, in fire_event
    self.loop.fire_event(event, *args)
  File "build/bdist.linux-x86_64/egg/ds4drv/eventloop.py", line 90, in fire_event
    self.process_events()
  File "build/bdist.linux-x86_64/egg/ds4drv/eventloop.py", line 96, in process_events
    callback(*args)
  File "build/bdist.linux-x86_64/egg/ds4drv/action.py", line 73, in _handle_report
    self.handle_report(report)
  File "build/bdist.linux-x86_64/egg/ds4drv/actions/binding.py", line 105, in handle_report
    binding.callback(report, *binding.args)
  File "build/bdist.linux-x86_64/egg/ds4drv/actions/binding.py", line 62, in <lambda>
    lambda r: self.controller.next_profile())
  File "build/bdist.linux-x86_64/egg/ds4drv/__main__.py", line 62, in next_profile
    self.load_profile(self.profiles[next_index])
  File "build/bdist.linux-x86_64/egg/ds4drv/__main__.py", line 48, in load_profile
    self.load_options(profile_options)
  File "build/bdist.linux-x86_64/egg/ds4drv/__main__.py", line 94, in load_options
    self.fire_event("load-options", options)
  File "build/bdist.linux-x86_64/egg/ds4drv/__main__.py", line 39, in fire_event
    self.loop.fire_event(event, *args)
  File "build/bdist.linux-x86_64/egg/ds4drv/eventloop.py", line 90, in fire_event
    self.process_events()
  File "build/bdist.linux-x86_64/egg/ds4drv/eventloop.py", line 96, in process_events
    callback(*args)
  File "build/bdist.linux-x86_64/egg/ds4drv/actions/input.py", line 75, in load_options
    self.joystick.device.close()
  File "build/bdist.linux-x86_64/egg/evdev/uinput.py", line 205, in close
    self.device.close()
  File "build/bdist.linux-x86_64/egg/evdev/device.py", line 304, in close
    super().close()
TypeError: super() takes at least 1 argument (0 given)

Maybe the solution lies somewhere above python 3, but below 3.8 :D

cslev commented

I don't want to spam, just note that after nstalling python 3.5.3 from source, and then reinstalling ds4drv either from source or via pip3.5, switching mod to xpad works! However, after switching to the next profile (kbmouse), I encountered the following error:

[info][controller 1] Switching to profile: xpad
[info][controller 1] Switching to profile: kbmouse
Exception ignored in: <bound method InputDevice.__del__ of InputDevice('/dev/input/event29')>
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/site-packages/evdev-1.3.0-py3.5-linux-x86_64.egg/evdev/device.py", line 159, in __del__
  File "/usr/local/lib/python3.5/site-packages/evdev-1.3.0-py3.5-linux-x86_64.egg/evdev/device.py", line 304, in close
  File "/usr/local/lib/python3.5/site-packages/evdev-1.3.0-py3.5-linux-x86_64.egg/evdev/eventio_async.py", line 54, in close
  File "/usr/local/lib/python3.5/asyncio/events.py", line 671, in get_event_loop
    return get_event_loop_policy().get_event_loop()
  File "/usr/local/lib/python3.5/asyncio/events.py", line 583, in get_event_loop
    % threading.current_thread().name)
RuntimeError: There is no current event loop in thread 'Thread-1'.
Exception ignored in: <bound method InputDevice.__del__ of InputDevice('/dev/input/event30')>
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/site-packages/evdev-1.3.0-py3.5-linux-x86_64.egg/evdev/device.py", line 159, in __del__
  File "/usr/local/lib/python3.5/site-packages/evdev-1.3.0-py3.5-linux-x86_64.egg/evdev/device.py", line 304, in close
  File "/usr/local/lib/python3.5/site-packages/evdev-1.3.0-py3.5-linux-x86_64.egg/evdev/eventio_async.py", line 54, in close
  File "/usr/local/lib/python3.5/asyncio/events.py", line 671, in get_event_loop
    return get_event_loop_policy().get_event_loop()
  File "/usr/local/lib/python3.5/asyncio/events.py", line 583, in get_event_loop
    % threading.current_thread().name)
RuntimeError: There is no current event loop in thread 'Thread-1'.
Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/threading.py", line 914, in _bootstrap_inner
    self.run()
  File "/usr/local/lib/python3.5/threading.py", line 862, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/local/lib/python3.5/site-packages/ds4drv/__main__.py", line 109, in run
    self.loop.run()
  File "/usr/local/lib/python3.5/site-packages/ds4drv/eventloop.py", line 101, in run
    callback()
  File "/usr/local/lib/python3.5/site-packages/ds4drv/__main__.py", line 106, in read_report
    self.fire_event("device-report", report)
  File "/usr/local/lib/python3.5/site-packages/ds4drv/__main__.py", line 38, in fire_event
    self.loop.fire_event(event, *args)
  File "/usr/local/lib/python3.5/site-packages/ds4drv/eventloop.py", line 86, in fire_event
    self.process_events()
  File "/usr/local/lib/python3.5/site-packages/ds4drv/eventloop.py", line 92, in process_events
    callback(*args)
  File "/usr/local/lib/python3.5/site-packages/ds4drv/action.py", line 73, in _handle_report
    self.handle_report(report)
  File "/usr/local/lib/python3.5/site-packages/ds4drv/actions/binding.py", line 105, in handle_report
    binding.callback(report, *binding.args)
  File "/usr/local/lib/python3.5/site-packages/ds4drv/actions/binding.py", line 62, in <lambda>
    lambda r: self.controller.next_profile())
  File "/usr/local/lib/python3.5/site-packages/ds4drv/__main__.py", line 61, in next_profile
    self.load_profile(self.profiles[next_index])
  File "/usr/local/lib/python3.5/site-packages/ds4drv/__main__.py", line 47, in load_profile
    self.load_options(profile_options)
  File "/usr/local/lib/python3.5/site-packages/ds4drv/__main__.py", line 93, in load_options
    self.fire_event("load-options", options)
  File "/usr/local/lib/python3.5/site-packages/ds4drv/__main__.py", line 38, in fire_event
    self.loop.fire_event(event, *args)
  File "/usr/local/lib/python3.5/site-packages/ds4drv/eventloop.py", line 86, in fire_event
    self.process_events()
  File "/usr/local/lib/python3.5/site-packages/ds4drv/eventloop.py", line 92, in process_events
    callback(*args)
  File "/usr/local/lib/python3.5/site-packages/ds4drv/actions/input.py", line 75, in load_options
    self.joystick.device.close()
  File "/usr/local/lib/python3.5/site-packages/evdev-1.3.0-py3.5-linux-x86_64.egg/evdev/uinput.py", line 205, in close
    self.device.close()
  File "/usr/local/lib/python3.5/site-packages/evdev-1.3.0-py3.5-linux-x86_64.egg/evdev/device.py", line 304, in close
    super().close()
  File "/usr/local/lib/python3.5/site-packages/evdev-1.3.0-py3.5-linux-x86_64.egg/evdev/eventio_async.py", line 54, in close
    loop = asyncio.get_event_loop()
  File "/usr/local/lib/python3.5/asyncio/events.py", line 671, in get_event_loop
    return get_event_loop_policy().get_event_loop()
  File "/usr/local/lib/python3.5/asyncio/events.py", line 583, in get_event_loop
    % threading.current_thread().name)
RuntimeError: There is no current event loop in thread 'Thread-1'.

After retrying, it failed again at xpad. So, the error seems to be similar (if not the same)

cslev commented

Another Python version tested, so far, the followings are not working:

  • Python 2.7
  • Python 3.5.3
  • Python 3.7
  • Python 3.8
  • Python 3.9
cslev commented

It seems no one is really interested in this anymore, however, I found a solution with python 2.7 that has the following error:

...
  File "/usr/local/lib/python2.7/dist-packages/ds4drv/actions/input.py", line 75, in load_options
    self.joystick.device.close()
  File "/usr/local/lib/python2.7/dist-packages/evdev/uinput.py", line 205, in close
    self.device.close()
  File "/usr/local/lib/python2.7/dist-packages/evdev/device.py", line 304, in close
    super().close()
TypeError: super() takes at least 1 argument (0 given)

Just telling you to comment out a line in the source code would not look like a clever idea, so let me explain why it is indeed a viable path.

First of all, due to Python2.7 and Python3+, the error you can see above is related to how the super() functions should be used. Just open that file /usr/local/lib/python2.7/dist-packages/evdev/device.py and look for the close() function. You will see it indeed looks like as in the error message, however, for this version of python we need to pass the class' name as well as an argument, i.e., super(PARENT_CLASS). By looking at the main class definition of this device.py, we see it is an instance of the EventIO.
Now, let's check where does it come from! In the import section, we can see it can come from two sources:

try:
    from evdev.eventio_async import EventIO, EvdevError
except ImportError:
    from evdev.eventio import EventIO, EvdevError

If we take a closer look at these sources (by finding the relevant source codes of either /usr/local/lib/python2.7/dist-packages/evdev/eventio.py or /usr/local/lib/python2.7/dist-packages/evdev/eventio_async.py, we can deduce the following.

eventio_async.py does not have a close() function, while eventio.py has an empty close() function, i.e.,

def close(self):
        pass

Therefore, actually calling properly this function makes not too much sense, so we can surely go to line 304 in /usr/local/lib/python2.7/dist-packages/evdev/device.py and comment out the function call super().close() or the already tried to change super(EventIO).close().

After doing this, ds4drv works as expected, at least in the terminal (did not have time to check with games yet) without crashing:

[info][controller 1] Battery: Fully charged
[info][controller 1] Switching to profile: xpad
[info][controller 1] Switching to profile: kbmouse
[info][controller 1] Switching to profile: default
[info][controller 1] Switching to profile: xpad
[info][controller 1] Switching to profile: kbmouse
[info][controller 1] Switching to profile: default
[info][controller 1] Switching to profile: xpad
[info][controller 1] Switching to profile: kbmouse
[info][controller 1] Switching to profile: default

I hope it helps everyone being in a huge need of PS4 controllers and Linux gaming :)
The solution might be a solution as well for other python versions complaining about the same problem by default.

cslev commented

Note, I have installed ds4drv via pip, or more precisely, pip2.7.
To install python2.7 and the corresponding pip in newer systems, refer to this site.

Then, install further libs:

sudo apt-get install python-dev
pip install pyudev
sudo pip install evdev

Then, install ds4drv:

sudo pip install ds4drv

@cslev Thanks! This solution works for Python 3.8 under Arch Linux

cslev commented

Good to hear!
Btw., I stopped using this driver and use the built-in Bluetooth device manager (in PopOS). It works totally fine, and with SDL controller mapping, most games (on Lutris) that support Bluetooth controllers work well! Furthermore, I do even have rumble feature, i.e., the controller vibrates.
Good luck with this, though :)

Good to hear!
Btw., I stopped using this driver and use the built-in Bluetooth device manager (in PopOS). It works totally fine, and with SDL controller mapping, most games (on Lutris) that support Bluetooth controllers work well! Furthermore, I do even have rumble feature, i.e., the controller vibrates.
Good luck with this, though :)

Sorry, would you mind expanding a bit about this SDL mapping? I'm not familiar.

I've been using this driver without any issues for a while, but, since it's unmaintained, if there's an alternative out there that works just as well I'll be happy to learn about it.

cslev commented

Follow this tutorial: https://askubuntu.com/questions/875353/dualshock-4-v2-vibration-rumble.
However, when I created my own SDL mapping, I realized that the GUI was working odd, and it might take my inputs twice, so I always had to go back and remap every second button (hard to explain, you will see this if this happens.)
So, in this case, even though going back and remap every time, the mapping will not be good and will be useless.

Solution: download the gamecontrollerdb.txt file and use it (this file actually contains mappings for almost all possible controllers worldwide.
This file can be obtained from the SDL Github: https://github.com/gabomdq/SDL_GameControllerDB

Once you have this file, you take Lutris, and in the settings field (of a game), you can define the SDL settings to this file. You can also set it globally in Lutris, then every game you ever install, we have this setting on by default.
Preferences (top right corner, three lines icon) -> System options -> SDL2 gamepad mapping, and you set the path to the controller db file.

Since the topic of mapping to SDL has been brought up, time to shill a project of mine. I made a GUI utility for mapping an evdev controller to the SDL GameController spec. The program was made as a replacement for the proprietary SDL2 Gamepad Tool and it offers feature parity. The app is written in Qt using Qt Quick/QML for the GUI. There is an AppImage available that has been tested on Fedora 32 and Ubuntu 20.04; I don't think it has ever been tested on Fedora 33 so I should do that sometime.

Latest release page: https://gitlab.com/ryochan7/sdl2-gamepad-mapper/-/releases/v0.0.3

SDL2_Gamepad_Mapper-0.0.3-x86_64.AppImage:
https://drive.google.com/file/d/12CtYjPbP8YLN7dCIJiKX5EcNdf4PIz4g/view?usp=sharing

Repo: https://gitlab.com/ryochan7/sdl2-gamepad-mapper

Follow this tutorial: https://askubuntu.com/questions/875353/dualshock-4-v2-vibration-rumble.
However, when I created my own SDL mapping, I realized that the GUI was working odd, and it might take my inputs twice, so I always had to go back and remap every second button (hard to explain, you will see this if this happens.)
So, in this case, even though going back and remap every time, the mapping will not be good and will be useless.

Solution: download the gamecontrollerdb.txt file and use it (this file actually contains mappings for almost all possible controllers worldwide.
This file can be obtained from the SDL Github: https://github.com/gabomdq/SDL_GameControllerDB

Once you have this file, you take Lutris, and in the settings field (of a game), you can define the SDL settings to this file. You can also set it globally in Lutris, then every game you ever install, we have this setting on by default.
Preferences (top right corner, three lines icon) -> System options -> SDL2 gamepad mapping, and you set the path to the controller db file.

Thank you!!!

Since the topic of mapping to SDL has been brought up, time to shill a project of mine. I made a GUI utility for mapping an evdev controller to the SDL GameController spec. The program was made as a replacement for the proprietary SDL2 Gamepad Tool and it offers feature parity. The app is written in Qt using Qt Quick/QML for the GUI. There is an AppImage available that has been tested on Fedora 32 and Ubuntu 20.04; I don't think it has ever been tested on Fedora 33 so I should do that sometime.

Latest release page: https://gitlab.com/ryochan7/sdl2-gamepad-mapper/-/releases/v0.0.3

SDL2_Gamepad_Mapper-0.0.3-x86_64.AppImage:
https://drive.google.com/file/d/12CtYjPbP8YLN7dCIJiKX5EcNdf4PIz4g/view?usp=sharing

Repo: https://gitlab.com/ryochan7/sdl2-gamepad-mapper

Working fine on latest manjaro, really neat tool!

The only issue seems to be a grayed out "Set Mapping as Environmental Variable" button.

As issue this doesn't look much helpful. Probably as wiki some comments are useful. I suggest to close this