1

I want to give a /dev/DEVICE path as input and get the device "human friendly" name as output.

I was having success getting the name from ID_MODEL_ENC, like in this snippet:

def dev_name(dev_path):
    from pyudev import Context
    for device in Context().list_devices(DEVNAME=dev_path):
        print device.get('ID_MODEL_ENC').decode('string_escape')

But it doesn't work with a bluetooth device. It seems that ID_MODEL_ENC is not so widely used.

In my application I'll use it only for joysticks, then the device path will be always /dev/input/js*.

Example 1: USB joystick is the js0

$ dev_name.py /dev/input/js0
Twin USB Joystick

Example 2: Bluetooth joystick is the js2

$ dev_name.py /dev/input/js2
Traceback (most recent call last):
  File "pyudev_get_js_name.py", line 9, in <module>
    dev_name(sys.argv[1])
  File "pyudev_get_js_name.py", line 7, in dev_name
    print '"'+ device.get('ID_MODEL_ENC').decode('string_escape') +'"'
AttributeError: 'NoneType' object has no attribute 'decode'

It obviously occurs because that device doesn't have the ID_MODEL_ENC attribute.

Just to make sure that the system knows the device's name we can do this directly in the shell prompt:

$ sys_dev_path="$(udevadm info --name=/dev/input/js2 | grep DEVPATH | cut -d= -f2)"
$ cat "/sys$(dirname $sys_dev_path)/name"
8Bitdo NES30 GamePad

I know I can make something similar with python and check the contents of /sys/devices/.../name file, but it looks like a makeshift. Is there a way to make pyudev give me the joystick name?

Note: I know it's pretty simple to get joystick names using pygame, but it's not an option here.

Thanks in advance.

meleu
  • 29
  • 1
  • 7

2 Answers2

0

I checked the device object created by pyudev with my controllers, and none of the members of the object held the descriptive name. As far as I could find, it doesn't mention it in the docs either. Anyways, this is how I implemented the name functionality. Like you said, I'm just pulling from the name file.

def get_devices():
    context = Context()
    ##devices = []
    #equivalent to "ls /dev/input | grep js"
    js_list = [d for d in os.listdir("/dev/input") if d.startswith("js")]
    for js in js_list:
        js_file = os.path.join("/dev/input", js)
        #different syntax to only get one item from Context()
        #.sys_path gives only the full system path
        js_path = Devices.from_device_file(context, js_file).sys_path
        #the name file should exist at this combined path
        name_path = os.path.join(js_path, "device", "name")
        #read the name from that file
        with open(name_path, "r") as buf:
            js_name = buf.read().strip()
        print("File: {}".format(js_path))
        print("Name: {}".format(js_name))
        ##devices.append(...)
    ##return devices
  • Yeah, I'm currently using a very simmilar approach. But still looking for a pythonic way Thanks! :-) – meleu May 02 '17 at 02:46
  • By the way, the way I'm currently using can be seen here: https://github.com/meleu/share/blob/master/joy2key_get_button_codes.py#L39 – meleu May 02 '17 at 02:51
0

If pyudev isn't giving you what you require, try evdev instead.

>>> from evdev import InputDevice,list_devices
>>> devices = [InputDevice(fn) for fn in list_devices()]
>>> for dev in devices:
...  print (dev.fn, dev.name)
... 
/dev/input/event12 HDA Intel PCH HDMI/DP,pcm=3
/dev/input/event11 HDA Intel PCH Front Headphone
/dev/input/event10 HDA Intel PCH Line Out
/dev/input/event9 HDA Intel PCH Rear Mic
/dev/input/event8 HDA Intel PCH Front Mic
/dev/input/event7 RDing FootSwitch3F1.
/dev/input/event6  USB OPTICAL MOUSE
/dev/input/event5 BTC USB Multimedia Keyboard
/dev/input/event4 BTC USB Multimedia Keyboard
/dev/input/event3 Video Bus
/dev/input/event2 Power Button
/dev/input/event1 Sleep Button
/dev/input/event0 Power Button

http://python-evdev.readthedocs.io/en/latest/

In response to your comment about joysticks only, the simple answer, is not directly but if you can find a capability that all joysticks have but that nothing else has, then that could be used to filter out all non-joystick devices. I had a similar requirement, in that I needed to identify only foot pedal devices. To achieve that, I created a file containing a list of the USB Vendor and Procuct Id's of all known foot pedals. Armed with that I simply checked the dev.info.vendor and dev.info.product items of each device, to see if I got a match. To allow for people with unknown devices, if I found no match, I presented all of the devices and asked them to identify their foot pedal (joystick), which I simply appended to the list and appended to the /lib/udev/rules.d/51-footswitch.rules file. Here is the checking code:

devices = [InputDevice(fn) for fn in list_devices()]
for dev in devices:
    vendor = "%x" % dev.info.vendor
    vendor = vendor.zfill(4)
    product = "%x" % dev.info.product
    product = product.zfill(4)
    check_pedal_string = vendor+":"+product
    event_id = dev.fn
    if check_pedal_string in known_devices:
        found_hid = event_id
        break
Rolf of Saxony
  • 21,661
  • 5
  • 39
  • 60
  • Yeah, the output is really nice, exactly what I want. But in my application I use names like `/dev/input/jsX` for joysticks, not `/dev/input/eventXY`. I will look the evdev docs to see if it accepts the input I want to give. Thanks man! – meleu May 02 '17 at 02:59
  • Is there a way to make `list_devices()` list the joysticks only? – meleu May 02 '17 at 03:08
  • @meleu I have updated my answer to include "a" method of filtering the devices – Rolf of Saxony May 02 '17 at 07:15