improved support for the Nano receiver
This commit is contained in:
parent
cd33314d0b
commit
790fc7c04b
|
@ -57,9 +57,9 @@ def exit():
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _match(action, device, vendor_id=None, product_id=None, interface_number=None, driver=None):
|
def _match(action, device, vendor_id=None, product_id=None, interface_number=None, hid_driver=None):
|
||||||
usb_device = device.find_parent('usb', 'usb_device')
|
usb_device = device.find_parent('usb', 'usb_device')
|
||||||
# print (action, device, "usb:", usb_device)
|
# print ("* parent", action, device, "usb:", usb_device)
|
||||||
if not usb_device:
|
if not usb_device:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -71,15 +71,15 @@ def _match(action, device, vendor_id=None, product_id=None, interface_number=Non
|
||||||
|
|
||||||
if action == 'add':
|
if action == 'add':
|
||||||
hid_device = device.find_parent('hid')
|
hid_device = device.find_parent('hid')
|
||||||
# print (action, device, "hid:", usb_device)
|
# print ("** found hid", action, device, "hid:", hid_device, hid_device['DRIVER'])
|
||||||
if not hid_device:
|
if not hid_device:
|
||||||
return
|
return
|
||||||
hid_driver_name = hid_device['DRIVER']
|
hid_driver_name = hid_device['DRIVER']
|
||||||
if driver is not None and driver != hid_driver_name:
|
if hid_driver is not None and hid_driver != hid_driver_name:
|
||||||
return
|
return
|
||||||
|
|
||||||
intf_device = device.find_parent('usb', 'usb_interface')
|
intf_device = device.find_parent('usb', 'usb_interface')
|
||||||
# print (action, device, "usb_interface:", usb_device)
|
# print ("*** usb interface", action, device, "usb_interface:", intf_device)
|
||||||
if interface_number is None:
|
if interface_number is None:
|
||||||
usb_interface = None if intf_device is None else intf_device.attributes.asint('bInterfaceNumber')
|
usb_interface = None if intf_device is None else intf_device.attributes.asint('bInterfaceNumber')
|
||||||
else:
|
else:
|
||||||
|
@ -163,7 +163,7 @@ def monitor(callback, *device_filters):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
def enumerate(vendor_id=None, product_id=None, interface_number=None, driver=None):
|
def enumerate(vendor_id=None, product_id=None, interface_number=None, hid_driver=None):
|
||||||
"""Enumerate the HID Devices.
|
"""Enumerate the HID Devices.
|
||||||
|
|
||||||
List all the HID devices attached to the system, optionally filtering by
|
List all the HID devices attached to the system, optionally filtering by
|
||||||
|
@ -172,7 +172,7 @@ def enumerate(vendor_id=None, product_id=None, interface_number=None, driver=Non
|
||||||
:returns: a list of matching ``DeviceInfo`` tuples.
|
:returns: a list of matching ``DeviceInfo`` tuples.
|
||||||
"""
|
"""
|
||||||
for dev in _Context().list_devices(subsystem='hidraw'):
|
for dev in _Context().list_devices(subsystem='hidraw'):
|
||||||
dev_info = _match('add', dev, vendor_id, product_id, interface_number, driver)
|
dev_info = _match('add', dev, vendor_id, product_id, interface_number, hid_driver)
|
||||||
if dev_info:
|
if dev_info:
|
||||||
yield dev_info
|
yield dev_info
|
||||||
|
|
||||||
|
|
|
@ -66,10 +66,10 @@ class DeviceUnreachable(_KwException):
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
# vendor_id, product_id, interface number, driver
|
# vendor_id, product_id, usb interface number, hid driver
|
||||||
DEVICE_UNIFYING_RECEIVER = (0x046d, 0xc52b, 2, 'logitech-djreceiver')
|
DEVICE_UNIFYING_RECEIVER = (0x046d, 0xc52b, 2, 'logitech-djreceiver')
|
||||||
DEVICE_UNIFYING_RECEIVER_2 = (0x046d, 0xc532, 2, 'logitech-djreceiver')
|
DEVICE_UNIFYING_RECEIVER_2 = (0x046d, 0xc532, 2, 'logitech-djreceiver')
|
||||||
DEVICE_NANO_RECEIVER = (0x046d, 0xc526, 1, 'generic-usb')
|
DEVICE_NANO_RECEIVER = (0x046d, 0xc526, 1, 'hid-generic')
|
||||||
|
|
||||||
|
|
||||||
def receivers():
|
def receivers():
|
||||||
|
|
|
@ -33,14 +33,14 @@ class PairedDevice(object):
|
||||||
self.number = number
|
self.number = number
|
||||||
|
|
||||||
self._unifying = receiver.max_devices > 1
|
self._unifying = receiver.max_devices > 1
|
||||||
self._protocol = None
|
self._protocol = None if self._unifying else 1.0
|
||||||
self._wpid = None
|
self._wpid = None
|
||||||
self._power_switch = None
|
self._power_switch = None
|
||||||
self._polling_rate = None
|
self._polling_rate = None if self._unifying else 0
|
||||||
self._codename = None
|
self._codename = None
|
||||||
self._name = None
|
self._name = None
|
||||||
self._kind = None
|
self._kind = None
|
||||||
self._serial = None
|
self._serial = None if self._unifying else receiver.serial
|
||||||
self._firmware = None
|
self._firmware = None
|
||||||
self._keys = None
|
self._keys = None
|
||||||
|
|
||||||
|
@ -67,42 +67,49 @@ class PairedDevice(object):
|
||||||
self._kind = _hidpp10.DEVICE_KIND[kind]
|
self._kind = _hidpp10.DEVICE_KIND[kind]
|
||||||
if self._polling_rate is None:
|
if self._polling_rate is None:
|
||||||
self._polling_rate = ord(pair_info[2:3])
|
self._polling_rate = ord(pair_info[2:3])
|
||||||
# else:
|
else:
|
||||||
# device_info = self.receiver.request(0x83B5, 0x04)
|
# guesswork...
|
||||||
# self.wpid = _strhex(device_info[3:5])
|
device_info = self.receiver.request(0x83B5, 0x04)
|
||||||
|
self.wpid = _strhex(device_info[3:5])
|
||||||
return self._wpid
|
return self._wpid
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def polling_rate(self):
|
def polling_rate(self):
|
||||||
if self._polling_rate is None and self._unifying:
|
if self._polling_rate is None:
|
||||||
self.wpid, 0
|
if self._unifying:
|
||||||
|
self.wpid, 0
|
||||||
|
else:
|
||||||
|
self._polling_rate = 0
|
||||||
return self._polling_rate
|
return self._polling_rate
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def power_switch_location(self):
|
def power_switch_location(self):
|
||||||
if self._power_switch is None and self._unifying:
|
if self._power_switch is None:
|
||||||
ps = self.receiver.request(0x83B5, 0x30 + self.number - 1)
|
if self._unifying:
|
||||||
if ps:
|
ps = self.receiver.request(0x83B5, 0x30 + self.number - 1)
|
||||||
ps = ord(ps[9:10]) & 0x0F
|
if ps:
|
||||||
self._power_switch = _hidpp10.POWER_SWITCH_LOCATION[ps]
|
ps = ord(ps[9:10]) & 0x0F
|
||||||
|
self._power_switch = _hidpp10.POWER_SWITCH_LOCATION[ps]
|
||||||
return self._power_switch
|
return self._power_switch
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def codename(self):
|
def codename(self):
|
||||||
if self._codename is None and self._unifying:
|
if self._codename is None:
|
||||||
codename = self.receiver.request(0x83B5, 0x40 + self.number - 1)
|
if self._unifying:
|
||||||
if codename:
|
codename = self.receiver.request(0x83B5, 0x40 + self.number - 1)
|
||||||
self._codename = codename[2:].rstrip(b'\x00').decode('utf-8')
|
if codename:
|
||||||
# _log.debug("device %d codename %s", self.number, self._codename)
|
self._codename = codename[2:].rstrip(b'\x00').decode('utf-8')
|
||||||
|
# _log.debug("device %d codename %s", self.number, self._codename)
|
||||||
return self._codename
|
return self._codename
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
if self._name is None and self._unifying:
|
if self._name is None:
|
||||||
if self.codename in _descriptors.DEVICES:
|
if self._unifying:
|
||||||
self._name, self._kind = _descriptors.DEVICES[self._codename][:2]
|
if self.codename in _descriptors.DEVICES:
|
||||||
elif self.protocol >= 2.0:
|
self._name, self._kind = _descriptors.DEVICES[self._codename][:2]
|
||||||
self._name = _hidpp20.get_name(self)
|
elif self.protocol >= 2.0:
|
||||||
|
self._name = _hidpp20.get_name(self)
|
||||||
return self._name or self.codename or '?'
|
return self._name or self.codename or '?'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -132,14 +139,15 @@ class PairedDevice(object):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def serial(self):
|
def serial(self):
|
||||||
if self._serial is None and self._unifying:
|
if self._serial is None:
|
||||||
self._serial = _hidpp10.get_serial(self)
|
self._serial = _hidpp10.get_serial(self)
|
||||||
return self._serial or '?'
|
return self._serial or '?'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def keys(self):
|
def keys(self):
|
||||||
if self._keys is None and self._unifying:
|
if self._keys is None:
|
||||||
self._keys = _hidpp20.get_keys(self) or ()
|
if self._unifying:
|
||||||
|
self._keys = _hidpp20.get_keys(self) or ()
|
||||||
return self._keys
|
return self._keys
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -277,7 +285,8 @@ class Receiver(object):
|
||||||
if not self.handle:
|
if not self.handle:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
flag_bits = _hidpp10.NOTIFICATION_FLAG.all_bits() if enable else 0
|
# flag_bits = _hidpp10.NOTIFICATION_FLAG.all_bits() if enable else 0
|
||||||
|
flag_bits = 0xFFFFFF if enable else 0
|
||||||
ok = _hidpp10.set_notification_flags(self, flag_bits)
|
ok = _hidpp10.set_notification_flags(self, flag_bits)
|
||||||
|
|
||||||
flag_bits = _hidpp10.get_notification_flags(self)
|
flag_bits = _hidpp10.get_notification_flags(self)
|
||||||
|
@ -303,12 +312,12 @@ class Receiver(object):
|
||||||
# create a device object, but only use it if the receiver knows about it
|
# create a device object, but only use it if the receiver knows about it
|
||||||
|
|
||||||
# Nano receiver
|
# Nano receiver
|
||||||
#if self.max_devices == 1 and number == 1:
|
if self.max_devices == 1 and number == 1:
|
||||||
# # the Nano receiver does not provide the wpid
|
# the Nano receiver does not provide the wpid
|
||||||
# _log.info("%s: found Nano device %d (%s)", self, number, dev.serial)
|
_log.info("%s: found Nano device %d (%s)", self, number, dev.serial)
|
||||||
# # dev._wpid = self.serial + ':1'
|
# dev._wpid = self.serial + ':1'
|
||||||
# self._devices[number] = dev
|
self._devices[number] = dev
|
||||||
# return dev
|
return dev
|
||||||
|
|
||||||
if dev.wpid:
|
if dev.wpid:
|
||||||
_log.info("%s: found Unifying device %d (%s)", self, number, dev.wpid)
|
_log.info("%s: found Unifying device %d (%s)", self, number, dev.wpid)
|
||||||
|
|
|
@ -29,6 +29,7 @@ _MAX_DEVICES = 7
|
||||||
|
|
||||||
def _make_receiver_box(receiver):
|
def _make_receiver_box(receiver):
|
||||||
frame = Gtk.Frame()
|
frame = Gtk.Frame()
|
||||||
|
# frame.set_shadow_type(Gtk.ShadowType.NONE)
|
||||||
frame._device = receiver
|
frame._device = receiver
|
||||||
|
|
||||||
icon_set = _icons.device_icon_set(receiver.name)
|
icon_set = _icons.device_icon_set(receiver.name)
|
||||||
|
@ -92,8 +93,11 @@ def _make_receiver_box(receiver):
|
||||||
|
|
||||||
toggle_info_action = _action.make_toggle('dialog-information', 'Details', _toggle_info_label, frame)
|
toggle_info_action = _action.make_toggle('dialog-information', 'Details', _toggle_info_label, frame)
|
||||||
toolbar.insert(toggle_info_action.create_tool_item(), 0)
|
toolbar.insert(toggle_info_action.create_tool_item(), 0)
|
||||||
toolbar.insert(_action.pair(frame).create_tool_item(), -1)
|
pair_action = _action.pair(frame)
|
||||||
# toolbar.insert(ui.action.about.create_tool_item(), -1)
|
if receiver.max_devices == 1:
|
||||||
|
pair_action.set_sensitive(False)
|
||||||
|
pair_action.set_tooltip('Pairing not supported by this receiver')
|
||||||
|
toolbar.insert(pair_action.create_tool_item(), -1)
|
||||||
|
|
||||||
vbox = Gtk.VBox(homogeneous=False, spacing=2)
|
vbox = Gtk.VBox(homogeneous=False, spacing=2)
|
||||||
vbox.set_border_width(2)
|
vbox.set_border_width(2)
|
||||||
|
@ -137,7 +141,7 @@ def _make_device_box(index):
|
||||||
|
|
||||||
not_encrypted_icon = Gtk.Image.new_from_icon_name('security-low', _STATUS_ICON_SIZE)
|
not_encrypted_icon = Gtk.Image.new_from_icon_name('security-low', _STATUS_ICON_SIZE)
|
||||||
not_encrypted_icon.set_name('not-encrypted')
|
not_encrypted_icon.set_name('not-encrypted')
|
||||||
not_encrypted_icon.set_tooltip_text('The wireless link between this device and the Unifying Receiver is not encrypted.\n'
|
not_encrypted_icon.set_tooltip_text('The wireless link between this device and its receiver is not encrypted.\n'
|
||||||
'\n'
|
'\n'
|
||||||
'For pointing devices (mice, trackballs, trackpads), this is a minor security issue.\n'
|
'For pointing devices (mice, trackballs, trackpads), this is a minor security issue.\n'
|
||||||
'\n'
|
'\n'
|
||||||
|
@ -182,15 +186,16 @@ def _make_device_box(index):
|
||||||
device = f._device
|
device = f._device
|
||||||
assert device
|
assert device
|
||||||
|
|
||||||
items = [None, None, None, None, None, None, None, None, None]
|
items = [None] * 8
|
||||||
hid = device.protocol
|
hid = device.protocol
|
||||||
items[0] = ('Protocol', 'HID++ %1.1f' % hid if hid else 'unknown')
|
items[0] = ('Protocol', 'HID++ %1.1f' % hid if hid else 'unknown')
|
||||||
items[1] = ('Polling rate', '%d ms' % device.polling_rate)
|
items[1] = ('Polling rate', '%d ms' % device.polling_rate) if device.polling_rate else None
|
||||||
items[2] = ('Wireless PID', device.wpid)
|
items[2] = ('Wireless PID', device.wpid)
|
||||||
items[3] = ('Serial', device.serial)
|
items[3] = ('Serial', device.serial)
|
||||||
firmware = device.firmware
|
firmware = device.firmware
|
||||||
if firmware:
|
if firmware:
|
||||||
items[4:] = [(fw.kind, (fw.name + ' ' + fw.version).strip()) for fw in firmware]
|
firmware = [(fw.kind, (fw.name + ' ' + fw.version).strip()) for fw in firmware]
|
||||||
|
items[4:4+len(firmware)] = firmware
|
||||||
|
|
||||||
if device.status:
|
if device.status:
|
||||||
notification_flags = _hidpp10.get_notification_flags(device)
|
notification_flags = _hidpp10.get_notification_flags(device)
|
||||||
|
@ -417,6 +422,11 @@ def _update_device_box(frame, dev):
|
||||||
for i in frame._toolbar.get_children():
|
for i in frame._toolbar.get_children():
|
||||||
i.set_active(False)
|
i.set_active(False)
|
||||||
|
|
||||||
|
if dev.receiver.max_devices == 1:
|
||||||
|
unpair_button = frame.get_child().get_children()[-1]
|
||||||
|
unpair_button.set_sensitive(False)
|
||||||
|
unpair_button.set_tooltip_text('Unpairing not supported by this device')
|
||||||
|
|
||||||
battery_icon, battery_label, light_icon, light_label, not_encrypted_icon, _ = frame._status_icons
|
battery_icon, battery_label, light_icon, light_label, not_encrypted_icon, _ = frame._status_icons
|
||||||
battery_level = dev.status.get(_status.BATTERY_LEVEL)
|
battery_level = dev.status.get(_status.BATTERY_LEVEL)
|
||||||
|
|
||||||
|
@ -425,7 +435,7 @@ def _update_device_box(frame, dev):
|
||||||
|
|
||||||
if battery_level is None:
|
if battery_level is None:
|
||||||
battery_icon.set_sensitive(False)
|
battery_icon.set_sensitive(False)
|
||||||
battery_icon.set_from_icon_name(_icons.battery(-1), _STATUS_ICON_SIZE)
|
battery_icon.set_from_icon_name(_icons.battery(None), _STATUS_ICON_SIZE)
|
||||||
battery_label.set_markup('<small>no status</small>')
|
battery_label.set_markup('<small>no status</small>')
|
||||||
battery_label.set_sensitive(True)
|
battery_label.set_sensitive(True)
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Reference in New Issue