Ejemplo n.º 1
0
    def __init__(self, receiver, number, link_notification=None, info=None):
        assert receiver or info
        self.receiver = receiver
        self.may_unpair = False
        self.isDevice = True  # some devices act as receiver so we need a property to distinguish them
        self.handle = None
        self.path = None
        self.product_id = None

        if receiver:
            assert number > 0 and number <= receiver.max_devices
        self.number = number  # will be None at this point for directly connected devices
        # 'device active' flag; requires manual management.
        self.online = None

        # the Wireless PID is unique per device model
        self.wpid = None
        self.descriptor = None
        # Bluetooth connections need long messages
        self.bluetooth = False
        # mouse, keyboard, etc (see _hidpp10.DEVICE_KIND)
        self._kind = None
        # Unifying peripherals report a codename.
        self._codename = None
        # the full name of the model
        self._name = None
        # HID++ protocol version, 1.0 or 2.0
        self._protocol = None
        # serial number (an 8-char hex string)
        self._serial = None
        # unit id (distinguishes within a model - the same as serial)
        self._unitId = None
        # model id (contains identifiers for the transports of the device)
        self._modelId = None
        # map from transports to product identifiers
        self._tid_map = None
        # persister holds settings
        self._persister = None

        self._firmware = None
        self._keys = None
        self._remap_keys = None
        self._gestures = None
        self._gestures_lock = _threading.Lock()
        self._registers = None
        self._settings = None
        self._feature_settings_checked = False
        self._settings_lock = _threading.Lock()

        # Misc stuff that's irrelevant to any functionality, but may be
        # displayed in the UI and caching it here helps.
        self._polling_rate = None
        self._power_switch = None

        # See `add_notification_handler`
        self._notification_handlers = {}

        # if _log.isEnabledFor(_DEBUG):
        #     _log.debug("new Device(%s, %s, %s)", receiver, number, link_notification)

        if receiver:
            if link_notification is not None:
                self.online = not bool(ord(link_notification.data[0:1]) & 0x40)
                self.wpid = _strhex(link_notification.data[2:3] +
                                    link_notification.data[1:2])
                # assert link_notification.address == (0x04 if unifying else 0x03)
                kind = ord(link_notification.data[0:1]) & 0x0F
                # get 27Mhz wpid and set kind based on index
                if receiver.ex100_27mhz_wpid_fix:  # 27 Mhz receiver
                    self.wpid = '00' + _strhex(link_notification.data[2:3])
                    kind = self.get_kind_from_index(number, receiver)
                self._kind = _hidpp10.DEVICE_KIND[kind]
            else:
                # Not a notification, force a reading of the wpid
                self.online = True
                self.update_pairing_information()

            # the wpid is necessary to properly identify wireless link on/off
            # notifications also it gets set to None on this object when the
            # device is unpaired
            assert self.wpid is not None, 'failed to read wpid: device %d of %s' % (
                number, receiver)

            self.path = _hid.find_paired_node(receiver.path, number, 1)
            try:
                self.handle = _hid.open_path(self.path) if self.path else None
            except Exception:  # maybe the device wasn't set up
                try:
                    import time
                    time.sleep(1)
                    self.handle = _hid.open_path(self.path)
                except Exception:  # give up
                    self.handle = None

            self.descriptor = _descriptors.get_wpid(self.wpid)
            if self.descriptor is None:
                # Last chance to correctly identify the device; many Nano receivers do not support this call.
                codename = self.receiver.device_codename(self.number)
                if codename:
                    self._codename = codename
                    self.descriptor = _descriptors.get_codename(self._codename)
        else:
            self.path = info.path
            self.handle = _hid.open_path(self.path)
            self.online = None  # a direct connected device might not be online (as reported by user)
            self.product_id = info.product_id
            self.bluetooth = info.bus_id == 0x0005
            self.descriptor = _descriptors.get_btid(self.product_id) if self.bluetooth else \
                _descriptors.get_usbid(self.product_id)
            if self.number is None:  # for direct-connected devices get 'number' from descriptor protocol else use 0xFF
                self.number = 0x00 if self.descriptor and self.descriptor.protocol and self.descriptor.protocol < 2.0 else 0xFF

        if self.descriptor:
            self._name = self.descriptor.name
            if self.descriptor.protocol:
                self._protocol = self.descriptor.protocol
            if self._codename is None:
                self._codename = self.descriptor.codename
            if self._kind is None:
                self._kind = self.descriptor.kind

        if self._protocol is not None:
            self.features = None if self._protocol < 2.0 else _hidpp20.FeaturesArray(
                self)
        else:
            # may be a 2.0 device; if not, it will fix itself later
            self.features = _hidpp20.FeaturesArray(self)
Ejemplo n.º 2
0
    def __init__(self, receiver, number, link_notification=None, info=None):
        assert receiver or info
        self.receiver = receiver
        self.may_unpair = False
        self.isDevice = True  # some devices act as receiver so we need a property to distinguish them

        if receiver:
            assert number > 0 and number <= receiver.max_devices
        else:
            assert number == 0
        # Device number, 1..6 for unifying devices, 1 otherwise.
        self.number = number
        # 'device active' flag; requires manual management.
        self.online = None

        # the Wireless PID is unique per device model
        self.wpid = None
        self.descriptor = None
        # Bluetooth connections need long messages
        self.bluetooth = False
        # mouse, keyboard, etc (see _hidpp10.DEVICE_KIND)
        self._kind = None
        # Unifying peripherals report a codename.
        self._codename = None
        # the full name of the model
        self._name = None
        # HID++ protocol version, 1.0 or 2.0
        self._protocol = None
        # serial number (an 8-char hex string)
        self._serial = None
        # unit id (distinguishes within a model - the same as serial)
        self._unitId = None
        # model id (contains identifiers for the transports of the device)
        self._modelId = None
        # map from transports to product identifiers
        self._tid_map = None
        # persister holds settings
        self._persister = None

        self._firmware = None
        self._keys = None
        self._gestures = None
        self._registers = None
        self._settings = None
        self._feature_settings_checked = False

        # Misc stuff that's irrelevant to any functionality, but may be
        # displayed in the UI and caching it here helps.
        self._polling_rate = None
        self._power_switch = None

        # See `add_notification_handler`
        self._notification_handlers = {}

        self.handle = None
        self.path = None
        self.product_id = None

        # if _log.isEnabledFor(_DEBUG):
        #     _log.debug("new Device(%s, %s, %s)", receiver, number, link_notification)

        if receiver:
            if link_notification is not None:
                self.online = not bool(ord(link_notification.data[0:1]) & 0x40)
                self.wpid = _strhex(link_notification.data[2:3] +
                                    link_notification.data[1:2])
                # assert link_notification.address == (0x04 if unifying else 0x03)
                kind = ord(link_notification.data[0:1]) & 0x0F
                # get 27Mhz wpid and set kind based on index
                if receiver.ex100_27mhz_wpid_fix:  # 27 Mhz receiver
                    self.wpid = '00' + _strhex(link_notification.data[2:3])
                    kind = self.get_kind_from_index(number, receiver)
                self._kind = _hidpp10.DEVICE_KIND[kind]
            else:
                # Not a notification, force a reading of the wpid
                pair_info = self.receiver.read_register(
                    _R.receiver_info, 0x20 + number - 1)
                if pair_info:
                    # may be either a Unifying receiver, or an Unifying-ready
                    # receiver
                    self.wpid = _strhex(pair_info[3:5])
                    kind = ord(pair_info[7:8]) & 0x0F
                    self._kind = _hidpp10.DEVICE_KIND[kind]
                elif receiver.ex100_27mhz_wpid_fix:
                    # 27Mhz receiver, fill extracting WPID from udev path
                    self.wpid = _hid.find_paired_node_wpid(
                        receiver.path, number)
                    if not self.wpid:
                        _log.error(
                            'Unable to get wpid from udev for device %d of %s',
                            number, receiver)
                        raise _base.NoSuchDevice(
                            number=number,
                            receiver=receiver,
                            error='Not present 27Mhz device')
                    kind = self.get_kind_from_index(number, receiver)
                    self._kind = _hidpp10.DEVICE_KIND[kind]
                else:
                    # unifying protocol not supported, must be a Nano receiver
                    device_info = self.receiver.read_register(
                        _R.receiver_info, 0x04)
                    if device_info is None:
                        _log.error(
                            'failed to read Nano wpid for device %d of %s',
                            number, receiver)
                        raise _base.NoSuchDevice(number=number,
                                                 receiver=receiver,
                                                 error='read Nano wpid')
                    self.wpid = _strhex(device_info[3:5])
                    self._power_switch = '(' + _('unknown') + ')'

            # the wpid is necessary to properly identify wireless link on/off
            # notifications also it gets set to None on this object when the
            # device is unpaired
            assert self.wpid is not None, 'failed to read wpid: device %d of %s' % (
                number, receiver)

            self.path = _hid.find_paired_node(receiver.path, number,
                                              _base.DEFAULT_TIMEOUT)
            try:
                self.handle = _hid.open_path(self.path) if self.path else None
            except Exception:  # maybe the device wasn't set up
                try:
                    import time
                    time.sleep(1)
                    self.handle = _hid.open_path(self.path)
                except Exception:  # give up
                    self.handle = None

            self.descriptor = _descriptors.get_wpid(self.wpid)
            if self.descriptor is None:
                # Last chance to correctly identify the device; many Nano
                # receivers do not support this call.
                codename = self.receiver.read_register(_R.receiver_info,
                                                       0x40 + self.number - 1)
                if codename:
                    codename_length = ord(codename[1:2])
                    codename = codename[2:2 + codename_length]
                    self._codename = codename.decode('ascii')
                    self.descriptor = _descriptors.get_codename(self._codename)
        else:
            self.path = info.path
            self.handle = _hid.open_path(self.path)
            self.online = True
            self.product_id = info.product_id
            self.bluetooth = info.bus_id == 0x0005
            self.descriptor = _descriptors.get_btid(
                self.product_id) if self.bluetooth else _descriptors.get_usbid(
                    self.product_id)

        if self.descriptor:
            self._name = self.descriptor.name
            if self.descriptor.protocol:
                self._protocol = self.descriptor.protocol
            if self._codename is None:
                self._codename = self.descriptor.codename
            if self._kind is None:
                self._kind = self.descriptor.kind

        if self._protocol is not None:
            self.features = None if self._protocol < 2.0 else _hidpp20.FeaturesArray(
                self)
        else:
            # may be a 2.0 device; if not, it will fix itself later
            self.features = _hidpp20.FeaturesArray(self)
Ejemplo n.º 3
0
    def __init__(self, receiver, number, link_notification=None, info=None):
        assert receiver or info
        self.receiver = receiver

        if receiver:
            assert number > 0 and number <= receiver.max_devices
        else:
            assert number == 0
        # Device number, 1..6 for unifying devices, 1 otherwise.
        self.number = number
        # 'device active' flag; requires manual management.
        self.online = None

        # the Wireless PID is unique per device model
        self.wpid = None
        self.descriptor = None

        # mouse, keyboard, etc (see _hidpp10.DEVICE_KIND)
        self._kind = None
        # Unifying peripherals report a codename.
        self._codename = None
        # the full name of the model
        self._name = None
        # HID++ protocol version, 1.0 or 2.0
        self._protocol = None
        # serial number (an 8-char hex string)
        self._serial = None

        self._firmware = None
        self._keys = None
        self._gestures = None
        self._registers = None
        self._settings = None
        self._feature_settings_checked = False

        # Misc stuff that's irrelevant to any functionality, but may be
        # displayed in the UI and caching it here helps.
        self._polling_rate = None
        self._power_switch = None

        self.handle = None
        self.path = None
        self.product_id = None

        # if _log.isEnabledFor(_DEBUG):
        #     _log.debug("new Device(%s, %s, %s)", receiver, number, link_notification)

        if receiver:
            if link_notification is not None:
                self.online = not bool(ord(link_notification.data[0:1]) & 0x40)
                self.wpid = _strhex(link_notification.data[2:3] +
                                    link_notification.data[1:2])
                # assert link_notification.address == (0x04 if unifying else 0x03)
                kind = ord(link_notification.data[0:1]) & 0x0F
                self._kind = _hidpp10.DEVICE_KIND[kind]
            else:
                # force a reading of the wpid
                pair_info = self.receiver.read_register(
                    _R.receiver_info, 0x20 + number - 1)
                if pair_info:
                    # may be either a Unifying receiver, or an Unifying-ready
                    # receiver
                    self.wpid = _strhex(pair_info[3:5])
                    kind = ord(pair_info[7:8]) & 0x0F
                    self._kind = _hidpp10.DEVICE_KIND[kind]
                elif receiver.ex100_wpid_fix:
                    # ex100 receiver, fill fake device_info with known wpid's
                    # accordingly to drivers/hid/hid-logitech-dj.c
                    # index 1 or 2 always mouse, index 3 always the keyboard,
                    # index 4 is used for an optional separate numpad
                    if number == 1:  # mouse
                        self.wpid = '3F00'
                        self._kind = _hidpp10.DEVICE_KIND[2]
                    elif number == 3:  # keyboard
                        self.wpid = '6500'
                        self._kind = _hidpp10.DEVICE_KIND[1]
                    else:  # unknown device number on EX100
                        _log.error(
                            'failed to set fake EX100 wpid for device %d of %s',
                            number, receiver)
                        raise _base.NoSuchDevice(number=number,
                                                 receiver=receiver,
                                                 error='Unknown EX100 device')
                else:
                    # unifying protocol not supported, must be a Nano receiver
                    device_info = self.receiver.read_register(
                        _R.receiver_info, 0x04)
                    if device_info is None:
                        _log.error(
                            'failed to read Nano wpid for device %d of %s',
                            number, receiver)
                        raise _base.NoSuchDevice(number=number,
                                                 receiver=receiver,
                                                 error='read Nano wpid')

                    self.wpid = _strhex(device_info[3:5])
                    self._power_switch = '(' + _('unknown') + ')'

            # the wpid is necessary to properly identify wireless link on/off
            # notifications also it gets set to None on this object when the
            # device is unpaired
            assert self.wpid is not None, 'failed to read wpid: device %d of %s' % (
                number, receiver)

            self.path = _hid.find_paired_node(receiver.path, number,
                                              _base.DEFAULT_TIMEOUT)
            self.handle = _hid.open_path(self.path) if self.path else None

            self.descriptor = _DESCRIPTORS.get(self.wpid)
            if self.descriptor is None:
                # Last chance to correctly identify the device; many Nano
                # receivers do not support this call.
                codename = self.receiver.read_register(_R.receiver_info,
                                                       0x40 + self.number - 1)
                if codename:
                    codename_length = ord(codename[1:2])
                    codename = codename[2:2 + codename_length]
                    self._codename = codename.decode('ascii')
                    self.descriptor = _DESCRIPTORS.get(self._codename)

            if self.descriptor:
                self._name = self.descriptor.name
                self._protocol = self.descriptor.protocol
                if self._codename is None:
                    self._codename = self.descriptor.codename
                if self._kind is None:
                    self._kind = self.descriptor.kind
        else:
            self.path = info.path
            self.handle = _hid.open_path(self.path)
            self.product_id = info.product_id
            self._serial = ''.join(info.serial.split('-')).upper()

        if self._protocol is not None:
            self.features = None if self._protocol < 2.0 else _hidpp20.FeaturesArray(
                self)
        else:
            # may be a 2.0 device; if not, it will fix itself later
            self.features = _hidpp20.FeaturesArray(self)