예제 #1
0
파일: hidconsole.py 프로젝트: uhle/solaar
def _open(args):
    device = args.device
    if args.hidpp and not device:
        for d in _hid.enumerate(vendor_id=0x046d):
            if d.driver == 'logitech-djreceiver':
                device = d.path
                break
        if not device:
            sys.exit("!! No HID++ receiver found.")
    if not device:
        sys.exit("!! Device path required.")

    print(".. Opening device", device)
    handle = _hid.open_path(device)
    if not handle:
        sys.exit("!! Failed to open %s, aborting." % device)

    print(".. Opened handle %r, vendor %r product %r serial %r." %
          (handle, _hid.get_manufacturer(handle), _hid.get_product(handle),
           _hid.get_serial(handle)))
    if args.hidpp:
        if _hid.get_manufacturer(handle) != b'Logitech':
            sys.exit("!! Only Logitech devices support the HID++ protocol.")
        print(".. HID++ validation enabled.")
    else:
        if (_hid.get_manufacturer(handle) == b'Logitech'
                and b'Receiver' in _hid.get_product(handle)):
            args.hidpp = True
            print(".. Logitech receiver detected, HID++ validation enabled.")

    return handle
예제 #2
0
파일: hidconsole.py 프로젝트: Nek-/Solaar
def _open(device, hidpp):
	if hidpp and not device:
		for d in hidapi.enumerate(vendor_id=0x046d):
			if d.driver == 'logitech-djreceiver':
				device = d.path
				break
		if not device:
			sys.exit("!! No HID++ receiver found.")
	if not device:
		sys.exit("!! Device path required.")

	print (".. Opening device", device)
	handle = hidapi.open_path(device)
	if not handle:
		sys.exit("!! Failed to open %s, aborting." % device)

	print (".. Opened handle %r, vendor %r product %r serial %r." % (
					handle,
					hidapi.get_manufacturer(handle),
					hidapi.get_product(handle),
					hidapi.get_serial(handle)))
	if hidpp:
		if hidapi.get_manufacturer(handle) != b'Logitech':
			sys.exit("!! Only Logitech devices support the HID++ protocol.")
		print (".. HID++ validation enabled.")

	return handle
예제 #3
0
파일: base.py 프로젝트: yunpub/Solaar
def open_path(path):
    """Checks if the given Linux device path points to the right UR device.

    :param path: the Linux device path.

    The UR physical device may expose multiple linux devices with the same
    interface, so we have to check for the right one. At this moment the only
    way to distinguish betheen them is to do a test ping on an invalid
    (attached) device number (i.e., 0), expecting a 'ping failed' reply.

    :returns: an open receiver handle if this is the right Linux device, or
    ``None``.
    """
    return _hid.open_path(path)
예제 #4
0
파일: base.py 프로젝트: 3v1n0/Solaar
def open_path(path):
	"""Checks if the given Linux device path points to the right UR device.

	:param path: the Linux device path.

	The UR physical device may expose multiple linux devices with the same
	interface, so we have to check for the right one. At this moment the only
	way to distinguish betheen them is to do a test ping on an invalid
	(attached) device number (i.e., 0), expecting a 'ping failed' reply.

	:returns: an open receiver handle if this is the right Linux device, or
	``None``.
	"""
	return _hid.open_path(path)
예제 #5
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)
예제 #6
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)
예제 #7
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)