quicker detection of matching receivers in udev
This commit is contained in:
parent
8fc45e5590
commit
0f80901bce
|
|
@ -57,66 +57,90 @@ def exit():
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _match(device, hid_dev, vendor_id=None, product_id=None, interface_number=None, driver=None):
|
def _match(action, device, vendor_id=None, product_id=None, interface_number=None, driver=None):
|
||||||
assert 'HID_ID' in hid_dev
|
usb_device = device.find_parent('usb', 'usb_device')
|
||||||
bus, vid, pid = hid_dev['HID_ID'].split(':')
|
if not usb_device:
|
||||||
driver_name = hid_dev['DRIVER']
|
return
|
||||||
|
|
||||||
if ((vendor_id is None or vendor_id == int(vid, 16)) and
|
vid = usb_device['ID_VENDOR_ID']
|
||||||
(product_id is None or product_id == int(pid, 16)) and
|
pid = usb_device['ID_MODEL_ID']
|
||||||
(driver is None or driver == driver_name)):
|
if not ((vendor_id is None or vendor_id == int(vid, 16)) and
|
||||||
|
(product_id is None or product_id == int(pid, 16))):
|
||||||
|
return
|
||||||
|
|
||||||
if bus == '0003': # USB
|
if action == 'add':
|
||||||
intf_dev = device.find_parent('usb', 'usb_interface')
|
hid_device = device.find_parent('hid')
|
||||||
if intf_dev:
|
if not hid_device:
|
||||||
interface = intf_dev.attributes.asint('bInterfaceNumber')
|
return
|
||||||
if interface_number is None or interface_number == interface:
|
hid_driver_name = hid_device['DRIVER']
|
||||||
usb_dev = device.find_parent('usb', 'usb_device')
|
if driver is not None and driver != hid_driver_name:
|
||||||
assert usb_dev
|
return
|
||||||
attrs = usb_dev.attributes
|
|
||||||
d_info = DeviceInfo(path=device.device_node,
|
|
||||||
vendor_id=vid[-4:],
|
|
||||||
product_id=pid[-4:],
|
|
||||||
serial=hid_dev.get('HID_UNIQ'),
|
|
||||||
release=attrs['bcdDevice'],
|
|
||||||
manufacturer=attrs['manufacturer'],
|
|
||||||
product=attrs['product'],
|
|
||||||
interface=interface,
|
|
||||||
driver=driver_name)
|
|
||||||
return d_info
|
|
||||||
|
|
||||||
elif bus == '0005': # BLUETOOTH
|
intf_device = device.find_parent('usb', 'usb_interface')
|
||||||
# TODO
|
if interface_number is None:
|
||||||
pass
|
usb_interface = None if intf_device is None else intf_device.attributes.asint('bInterfaceNumber')
|
||||||
|
else:
|
||||||
|
usb_interface = None if intf_device is None else intf_device.attributes.asint('bInterfaceNumber')
|
||||||
|
if usb_interface is None or interface_number != usb_interface:
|
||||||
|
return
|
||||||
|
|
||||||
|
attrs = usb_device.attributes
|
||||||
|
d_info = DeviceInfo(path=device.device_node,
|
||||||
|
vendor_id=vid[-4:],
|
||||||
|
product_id=pid[-4:],
|
||||||
|
serial=hid_device.get('HID_UNIQ'),
|
||||||
|
release=attrs['bcdDevice'],
|
||||||
|
manufacturer=attrs['manufacturer'],
|
||||||
|
product=attrs['product'],
|
||||||
|
interface=usb_interface,
|
||||||
|
driver=hid_driver_name)
|
||||||
|
return d_info
|
||||||
|
|
||||||
|
elif action == 'remove':
|
||||||
|
# print (dict(device), dict(usb_device))
|
||||||
|
|
||||||
|
d_info = DeviceInfo(path=device.device_node,
|
||||||
|
vendor_id=vid[-4:],
|
||||||
|
product_id=pid[-4:],
|
||||||
|
serial=None,
|
||||||
|
release=None,
|
||||||
|
manufacturer=None,
|
||||||
|
product=None,
|
||||||
|
interface=None,
|
||||||
|
driver=None)
|
||||||
|
return d_info
|
||||||
|
|
||||||
|
|
||||||
|
def monitor_async(callback, *device_filters):
|
||||||
|
from threading import Thread as _Thread
|
||||||
|
t = _Thread(name='monitor_async_' + callback.__name__,
|
||||||
|
target=monitor,
|
||||||
|
args=[callback] + list(device_filters))
|
||||||
|
t.daemon = True
|
||||||
|
t.start()
|
||||||
|
|
||||||
|
|
||||||
def monitor(callback, *device_filters):
|
def monitor(callback, *device_filters):
|
||||||
m = _Monitor.from_netlink(_Context())
|
c = _Context()
|
||||||
|
|
||||||
|
for device in c.list_devices(subsystem='hidraw'):
|
||||||
|
# print (device, dict(device), dict(device.attributes))
|
||||||
|
for filter in device_filters:
|
||||||
|
d_info = _match('add', device, *filter)
|
||||||
|
if d_info:
|
||||||
|
callback('add', d_info)
|
||||||
|
break
|
||||||
|
|
||||||
|
m = _Monitor.from_netlink(c)
|
||||||
m.filter_by(subsystem='hidraw')
|
m.filter_by(subsystem='hidraw')
|
||||||
for action, device in m:
|
for action, device in m:
|
||||||
if action == 'add':
|
# print ('----', action, device)
|
||||||
hid_dev = device.find_parent(subsystem='hid')
|
if action in ('add', 'remove'):
|
||||||
# print ("****", action, device, hid_dev)
|
for filter in device_filters:
|
||||||
if hid_dev:
|
d_info = _match(action, device, *filter)
|
||||||
for filter in device_filters:
|
if d_info:
|
||||||
d_info = _match(device, hid_dev, *filter)
|
callback(action, d_info)
|
||||||
if d_info:
|
break
|
||||||
callback(action, d_info)
|
|
||||||
break
|
|
||||||
elif action == 'remove':
|
|
||||||
# this is ugly, but... well.
|
|
||||||
# signal the callback for each removed device; it will have figure
|
|
||||||
# out for itself if it's a device it should handle
|
|
||||||
d_info = DeviceInfo(path=device.device_node,
|
|
||||||
vendor_id=None,
|
|
||||||
product_id=None,
|
|
||||||
serial=None,
|
|
||||||
release=None,
|
|
||||||
manufacturer=None,
|
|
||||||
product=None,
|
|
||||||
interface=None,
|
|
||||||
driver=None)
|
|
||||||
callback(action, d_info)
|
|
||||||
|
|
||||||
|
|
||||||
def enumerate(vendor_id=None, product_id=None, interface_number=None, driver=None):
|
def enumerate(vendor_id=None, product_id=None, interface_number=None, driver=None):
|
||||||
|
|
|
||||||
|
|
@ -76,20 +76,11 @@ def receivers():
|
||||||
|
|
||||||
def notify_on_receivers(callback):
|
def notify_on_receivers(callback):
|
||||||
"""Starts a thread that monitors receiver events from udev."""
|
"""Starts a thread that monitors receiver events from udev."""
|
||||||
from threading import Thread as _Thread
|
_hid.monitor_async(callback,
|
||||||
t = _Thread(name='receivers_monitor', target=_hid.monitor,
|
|
||||||
args=(callback,
|
|
||||||
DEVICE_UNIFYING_RECEIVER,
|
DEVICE_UNIFYING_RECEIVER,
|
||||||
DEVICE_UNIFYING_RECEIVER_2,
|
DEVICE_UNIFYING_RECEIVER_2,
|
||||||
# DEVICE_NANO_RECEIVER,
|
# DEVICE_NANO_RECEIVER,
|
||||||
))
|
)
|
||||||
t.daemon = True
|
|
||||||
t.start()
|
|
||||||
|
|
||||||
# the HID monitor will only send events when devices are added/removed,
|
|
||||||
# so we need to trigger the callback for all currently detected receivers
|
|
||||||
for r in receivers():
|
|
||||||
callback('add', r)
|
|
||||||
|
|
||||||
|
|
||||||
def open_path(path):
|
def open_path(path):
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue