improved support for the Nano receiver

This commit is contained in:
Daniel Pavel 2013-05-22 07:31:16 +03:00
parent cd33314d0b
commit 790fc7c04b
4 changed files with 68 additions and 49 deletions

View File

@ -57,9 +57,9 @@ def exit():
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')
# print (action, device, "usb:", usb_device)
# print ("* parent", action, device, "usb:", usb_device)
if not usb_device:
return
@ -71,15 +71,15 @@ def _match(action, device, vendor_id=None, product_id=None, interface_number=Non
if action == 'add':
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:
return
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
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:
usb_interface = None if intf_device is None else intf_device.attributes.asint('bInterfaceNumber')
else:
@ -163,7 +163,7 @@ def monitor(callback, *device_filters):
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.
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.
"""
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:
yield dev_info

View File

@ -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_2 = (0x046d, 0xc532, 2, 'logitech-djreceiver')
DEVICE_NANO_RECEIVER = (0x046d, 0xc526, 1, 'generic-usb')
DEVICE_NANO_RECEIVER = (0x046d, 0xc526, 1, 'hid-generic')
def receivers():

View File

@ -33,14 +33,14 @@ class PairedDevice(object):
self.number = number
self._unifying = receiver.max_devices > 1
self._protocol = None
self._protocol = None if self._unifying else 1.0
self._wpid = None
self._power_switch = None
self._polling_rate = None
self._polling_rate = None if self._unifying else 0
self._codename = None
self._name = None
self._kind = None
self._serial = None
self._serial = None if self._unifying else receiver.serial
self._firmware = None
self._keys = None
@ -67,42 +67,49 @@ class PairedDevice(object):
self._kind = _hidpp10.DEVICE_KIND[kind]
if self._polling_rate is None:
self._polling_rate = ord(pair_info[2:3])
# else:
# device_info = self.receiver.request(0x83B5, 0x04)
# self.wpid = _strhex(device_info[3:5])
else:
# guesswork...
device_info = self.receiver.request(0x83B5, 0x04)
self.wpid = _strhex(device_info[3:5])
return self._wpid
@property
def polling_rate(self):
if self._polling_rate is None and self._unifying:
self.wpid, 0
if self._polling_rate is None:
if self._unifying:
self.wpid, 0
else:
self._polling_rate = 0
return self._polling_rate
@property
def power_switch_location(self):
if self._power_switch is None and self._unifying:
ps = self.receiver.request(0x83B5, 0x30 + self.number - 1)
if ps:
ps = ord(ps[9:10]) & 0x0F
self._power_switch = _hidpp10.POWER_SWITCH_LOCATION[ps]
if self._power_switch is None:
if self._unifying:
ps = self.receiver.request(0x83B5, 0x30 + self.number - 1)
if ps:
ps = ord(ps[9:10]) & 0x0F
self._power_switch = _hidpp10.POWER_SWITCH_LOCATION[ps]
return self._power_switch
@property
def codename(self):
if self._codename is None and self._unifying:
codename = self.receiver.request(0x83B5, 0x40 + self.number - 1)
if codename:
self._codename = codename[2:].rstrip(b'\x00').decode('utf-8')
# _log.debug("device %d codename %s", self.number, self._codename)
if self._codename is None:
if self._unifying:
codename = self.receiver.request(0x83B5, 0x40 + self.number - 1)
if codename:
self._codename = codename[2:].rstrip(b'\x00').decode('utf-8')
# _log.debug("device %d codename %s", self.number, self._codename)
return self._codename
@property
def name(self):
if self._name is None and self._unifying:
if self.codename in _descriptors.DEVICES:
self._name, self._kind = _descriptors.DEVICES[self._codename][:2]
elif self.protocol >= 2.0:
self._name = _hidpp20.get_name(self)
if self._name is None:
if self._unifying:
if self.codename in _descriptors.DEVICES:
self._name, self._kind = _descriptors.DEVICES[self._codename][:2]
elif self.protocol >= 2.0:
self._name = _hidpp20.get_name(self)
return self._name or self.codename or '?'
@property
@ -132,14 +139,15 @@ class PairedDevice(object):
@property
def serial(self):
if self._serial is None and self._unifying:
if self._serial is None:
self._serial = _hidpp10.get_serial(self)
return self._serial or '?'
@property
def keys(self):
if self._keys is None and self._unifying:
self._keys = _hidpp20.get_keys(self) or ()
if self._keys is None:
if self._unifying:
self._keys = _hidpp20.get_keys(self) or ()
return self._keys
@property
@ -277,7 +285,8 @@ class Receiver(object):
if not self.handle:
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)
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
# Nano receiver
#if self.max_devices == 1 and number == 1:
# # the Nano receiver does not provide the wpid
# _log.info("%s: found Nano device %d (%s)", self, number, dev.serial)
# # dev._wpid = self.serial + ':1'
# self._devices[number] = dev
# return dev
if self.max_devices == 1 and number == 1:
# the Nano receiver does not provide the wpid
_log.info("%s: found Nano device %d (%s)", self, number, dev.serial)
# dev._wpid = self.serial + ':1'
self._devices[number] = dev
return dev
if dev.wpid:
_log.info("%s: found Unifying device %d (%s)", self, number, dev.wpid)

View File

@ -29,6 +29,7 @@ _MAX_DEVICES = 7
def _make_receiver_box(receiver):
frame = Gtk.Frame()
# frame.set_shadow_type(Gtk.ShadowType.NONE)
frame._device = receiver
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)
toolbar.insert(toggle_info_action.create_tool_item(), 0)
toolbar.insert(_action.pair(frame).create_tool_item(), -1)
# toolbar.insert(ui.action.about.create_tool_item(), -1)
pair_action = _action.pair(frame)
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.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.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'
'For pointing devices (mice, trackballs, trackpads), this is a minor security issue.\n'
'\n'
@ -182,15 +186,16 @@ def _make_device_box(index):
device = f._device
assert device
items = [None, None, None, None, None, None, None, None, None]
items = [None] * 8
hid = device.protocol
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[3] = ('Serial', device.serial)
firmware = device.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:
notification_flags = _hidpp10.get_notification_flags(device)
@ -417,6 +422,11 @@ def _update_device_box(frame, dev):
for i in frame._toolbar.get_children():
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_level = dev.status.get(_status.BATTERY_LEVEL)
@ -425,7 +435,7 @@ def _update_device_box(frame, dev):
if battery_level is None:
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_sensitive(True)
else: