diff --git a/bin/solaar-cli b/bin/solaar-cli index cb0784a8..50b8d0ac 100755 --- a/bin/solaar-cli +++ b/bin/solaar-cli @@ -37,9 +37,7 @@ def init_paths(): if __name__ == '__main__': - print( - 'WARNING: solaar-cli is deprecated; use solaar with the usual arguments' - ) + print('WARNING: solaar-cli is deprecated; use solaar with the usual arguments') init_paths() import solaar.cli solaar.cli.run() diff --git a/lib/hidapi/hidconsole.py b/lib/hidapi/hidconsole.py index d2264272..53bdc6e1 100644 --- a/lib/hidapi/hidconsole.py +++ b/lib/hidapi/hidconsole.py @@ -72,8 +72,7 @@ def _print(marker, data, scroll=False): s = marker + ' ' + data else: hexs = strhex(data) - s = '%s (% 8.3f) [%s %s %s %s] %s' % (marker, t, hexs[0:2], hexs[2:4], - hexs[4:8], hexs[8:], repr(data)) + s = '%s (% 8.3f) [%s %s %s %s] %s' % (marker, t, hexs[0:2], hexs[2:4], hexs[4:8], hexs[8:], repr(data)) with print_lock: # allow only one thread at a time to write to the console, otherwise @@ -130,23 +129,17 @@ def _validate_input(line, hidpp=False): _error('Invalid HID++ request: first byte must be 0x10 or 0x11') return None if data[1:2] not in b'\xFF\x01\x02\x03\x04\x05\x06': - _error( - 'Invalid HID++ request: second byte must be 0xFF or one of 0x01..0x06' - ) + _error('Invalid HID++ request: second byte must be 0xFF or one of 0x01..0x06') return None if data[:1] == b'\x10': if len(data) > 7: - _error( - 'Invalid HID++ request: maximum length of a 0x10 request is 7 bytes' - ) + _error('Invalid HID++ request: maximum length of a 0x10 request is 7 bytes') return None while len(data) < 7: data = (data + b'\x00' * 7)[:7] elif data[:1] == b'\x11': if len(data) > 20: - _error( - 'Invalid HID++ request: maximum length of a 0x11 request is 20 bytes' - ) + _error('Invalid HID++ request: maximum length of a 0x11 request is 20 bytes') return None while len(data) < 20: data = (data + b'\x00' * 20)[:20] @@ -172,15 +165,13 @@ def _open(args): 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))) + (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)): + 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.') @@ -195,17 +186,12 @@ def _open(args): def _parse_arguments(): import argparse arg_parser = argparse.ArgumentParser() - arg_parser.add_argument( - '--history', help='history file (default ~/.hidconsole-history)') - arg_parser.add_argument('--hidpp', - action='store_true', - help='ensure input data is a valid HID++ request') - arg_parser.add_argument( - 'device', - nargs='?', - help='linux device to connect to (/dev/hidrawX); ' - 'may be omitted if --hidpp is given, in which case it looks for the first Logitech receiver' - ) + arg_parser.add_argument('--history', help='history file (default ~/.hidconsole-history)') + arg_parser.add_argument('--hidpp', action='store_true', help='ensure input data is a valid HID++ request') + arg_parser.add_argument('device', + nargs='?', + help='linux device to connect to (/dev/hidrawX); ' + 'may be omitted if --hidpp is given, in which case it looks for the first Logitech receiver') return arg_parser.parse_args() @@ -214,15 +200,12 @@ def main(): handle = _open(args) if interactive: - print( - '.. Press ^C/^D to exit, or type hex bytes to write to the device.' - ) + print('.. Press ^C/^D to exit, or type hex bytes to write to the device.') import readline if args.history is None: import os.path - args.history = os.path.join(os.path.expanduser('~'), - '.hidconsole-history') + args.history = os.path.join(os.path.expanduser('~'), '.hidconsole-history') try: readline.read_history_file(args.history) except Exception: @@ -237,8 +220,7 @@ def main(): if interactive: # move the cursor at the bottom of the screen - sys.stdout.write( - '\033[300B') # move cusor at most 300 lines down, don't scroll + sys.stdout.write('\033[300B') # move cusor at most 300 lines down, don't scroll while t.is_alive(): line = read_packet(prompt) diff --git a/lib/hidapi/udev.py b/lib/hidapi/udev.py index 903d5773..3dfb82fb 100644 --- a/lib/hidapi/udev.py +++ b/lib/hidapi/udev.py @@ -95,8 +95,7 @@ def _match(action, device, filter): pid = usb_device.get('ID_MODEL_ID') if vid is None or pid is None: return # there are reports that sometimes the usb_device isn't set up right so be defensive - if not ((vendor_id is None or vendor_id == int(vid, 16)) and - (product_id is None or product_id == int(pid, 16))): + 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 action == 'add': @@ -115,11 +114,9 @@ def _match(action, device, filter): intf_device = device.find_parent('usb', 'usb_interface') # 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') + 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') + 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 @@ -186,18 +183,15 @@ def monitor_glib(callback, *device_filters): try: # io_add_watch_full may not be available... - GLib.io_add_watch_full(m, GLib.PRIORITY_LOW, GLib.IO_IN, - _process_udev_event, callback, device_filters) + GLib.io_add_watch_full(m, GLib.PRIORITY_LOW, GLib.IO_IN, _process_udev_event, callback, device_filters) # print ("did io_add_watch_full") except AttributeError: try: # and the priority parameter appeared later in the API - GLib.io_add_watch(m, GLib.PRIORITY_LOW, GLib.IO_IN, - _process_udev_event, callback, device_filters) + GLib.io_add_watch(m, GLib.PRIORITY_LOW, GLib.IO_IN, _process_udev_event, callback, device_filters) # print ("did io_add_watch with priority") except Exception: - GLib.io_add_watch(m, GLib.IO_IN, _process_udev_event, callback, - device_filters) + GLib.io_add_watch(m, GLib.IO_IN, _process_udev_event, callback, device_filters) # print ("did io_add_watch") m.start() @@ -288,9 +282,7 @@ def write(device_handle, data): else: break if bytes_written != len(data): - raise IOError( - _errno.EIO, - 'written %d bytes out of expected %d' % (bytes_written, len(data))) + raise IOError(_errno.EIO, 'written %d bytes out of expected %d' % (bytes_written, len(data))) def read(device_handle, bytes_count, timeout_ms=-1): @@ -311,13 +303,11 @@ def read(device_handle, bytes_count, timeout_ms=-1): """ assert device_handle timeout = None if timeout_ms < 0 else timeout_ms / 1000.0 - rlist, wlist, xlist = _select([device_handle], [], [device_handle], - timeout) + rlist, wlist, xlist = _select([device_handle], [], [device_handle], timeout) if xlist: assert xlist == [device_handle] - raise IOError(_errno.EIO, - 'exception on file descriptor %d' % device_handle) + raise IOError(_errno.EIO, 'exception on file descriptor %d' % device_handle) if rlist: assert rlist == [device_handle] diff --git a/lib/logitech_receiver/base.py b/lib/logitech_receiver/base.py index 8fece732..41319b56 100644 --- a/lib/logitech_receiver/base.py +++ b/lib/logitech_receiver/base.py @@ -50,12 +50,7 @@ _MEDIUM_MESSAGE_SIZE = 15 _MAX_READ_SIZE = 32 # mapping from report_id to message length -report_lengths = { - 0x10: _SHORT_MESSAGE_SIZE, - 0x11: _LONG_MESSAGE_SIZE, - 0x20: _MEDIUM_MESSAGE_SIZE, - 0x21: _MAX_READ_SIZE -} +report_lengths = {0x10: _SHORT_MESSAGE_SIZE, 0x11: _LONG_MESSAGE_SIZE, 0x20: _MEDIUM_MESSAGE_SIZE, 0x21: _MAX_READ_SIZE} """Default timeout on read (in seconds).""" DEFAULT_TIMEOUT = 4 # the receiver itself should reply very fast, within 500ms @@ -176,14 +171,12 @@ def write(handle, devnumber, data): else: wdata = _pack('!BB5s', 0x10, devnumber, data) if _log.isEnabledFor(_DEBUG): - _log.debug('(%s) <= w[%02X %02X %s %s]', handle, ord(wdata[:1]), - devnumber, _strhex(wdata[2:4]), _strhex(wdata[4:])) + _log.debug('(%s) <= w[%02X %02X %s %s]', handle, ord(wdata[:1]), devnumber, _strhex(wdata[2:4]), _strhex(wdata[4:])) try: _hid.write(int(handle), wdata) except Exception as reason: - _log.error('write failed, assuming handle %r no longer available', - handle) + _log.error('write failed, assuming handle %r no longer available', handle) close(handle) raise NoReceiver(reason=reason) @@ -214,8 +207,7 @@ def check_message(data): if report_lengths.get(report_id) == len(data): return True else: - _log.warn('unexpected message size: report_id %02X message %s' % - (report_id, _strhex(data))) + _log.warn('unexpected message size: report_id %02X message %s' % (report_id, _strhex(data))) return False @@ -233,8 +225,7 @@ def _read(handle, timeout): timeout = int(timeout * 1000) data = _hid.read(int(handle), _MAX_READ_SIZE, timeout) except Exception as reason: - _log.error('read failed, assuming handle %r no longer available', - handle) + _log.error('read failed, assuming handle %r no longer available', handle) close(handle) raise NoReceiver(reason=reason) @@ -243,8 +234,7 @@ def _read(handle, timeout): devnumber = ord(data[1:2]) if _log.isEnabledFor(_DEBUG): - _log.debug('(%s) => r[%02X %02X %s %s]', handle, report_id, - devnumber, _strhex(data[2:4]), _strhex(data[4:])) + _log.debug('(%s) => r[%02X %02X %s %s]', handle, report_id, devnumber, _strhex(data[2:4]), _strhex(data[4:])) return report_id, devnumber, data[2:] @@ -265,8 +255,7 @@ def _skip_incoming(handle, ihandle, notifications_hook): # read whatever is already in the buffer, if any data = _hid.read(ihandle, _MAX_READ_SIZE, 0) except Exception as reason: - _log.error('read failed, assuming receiver %s no longer available', - handle) + _log.error('read failed, assuming receiver %s no longer available', handle) close(handle) raise NoReceiver(reason=reason) @@ -309,10 +298,9 @@ def make_notification(devnumber, data): return _HIDPP_Notification(devnumber, sub_id, address, data[2:]) -_HIDPP_Notification = namedtuple('_HIDPP_Notification', - ('devnumber', 'sub_id', 'address', 'data')) -_HIDPP_Notification.__str__ = lambda self: 'Notification(%d,%02X,%02X,%s)' % ( - self.devnumber, self.sub_id, self.address, _strhex(self.data)) +_HIDPP_Notification = namedtuple('_HIDPP_Notification', ('devnumber', 'sub_id', 'address', 'data')) +_HIDPP_Notification.__str__ = lambda self: 'Notification(%d,%02X,%02X,%s)' % (self.devnumber, self.sub_id, self.address, + _strhex(self.data)) _HIDPP_Notification.__unicode__ = _HIDPP_Notification.__str__ DJ_NOTIFICATION_LENGTH = _MEDIUM_MESSAGE_SIZE - 4 # to allow easy distinguishing of DJ notifications del namedtuple @@ -352,8 +340,7 @@ def request(handle, devnumber, request_id, *params): timeout *= 2 if params: - params = b''.join( - _pack('B', p) if isinstance(p, int) else p for p in params) + params = b''.join(_pack('B', p) if isinstance(p, int) else p for p in params) else: params = b'' # if _log.isEnabledFor(_DEBUG): @@ -375,8 +362,7 @@ def request(handle, devnumber, request_id, *params): if reply: report_id, reply_devnumber, reply_data = reply if reply_devnumber == devnumber: - if report_id == 0x10 and reply_data[:1] == b'\x8F' and reply_data[ - 1:3] == request_data[:2]: + if report_id == 0x10 and reply_data[:1] == b'\x8F' and reply_data[1:3] == request_data[:2]: error = ord(reply_data[3:4]) # if error == _hidpp10.ERROR.resource_error: # device unreachable @@ -388,24 +374,16 @@ def request(handle, devnumber, request_id, *params): # raise NoSuchDevice(number=devnumber, request=request_id) if _log.isEnabledFor(_DEBUG): - _log.debug( - '(%s) device 0x%02X error on request {%04X}: %d = %s', - handle, devnumber, request_id, error, - _hidpp10.ERROR[error]) + _log.debug('(%s) device 0x%02X error on request {%04X}: %d = %s', handle, devnumber, request_id, error, + _hidpp10.ERROR[error]) return - if reply_data[:1] == b'\xFF' and reply_data[ - 1:3] == request_data[:2]: + if reply_data[:1] == b'\xFF' and reply_data[1:3] == request_data[:2]: # a HID++ 2.0 feature call returned with an error error = ord(reply_data[3:4]) - _log.error( - '(%s) device %d error on feature request {%04X}: %d = %s', - handle, devnumber, request_id, error, - _hidpp20.ERROR[error]) - raise _hidpp20.FeatureCallError(number=devnumber, - request=request_id, - error=error, - params=params) + _log.error('(%s) device %d error on feature request {%04X}: %d = %s', handle, devnumber, request_id, error, + _hidpp20.ERROR[error]) + raise _hidpp20.FeatureCallError(number=devnumber, request=request_id, error=error, params=params) if reply_data[:2] == request_data[:2]: if request_id & 0xFE00 == 0x8200: @@ -445,8 +423,8 @@ def request(handle, devnumber, request_id, *params): # if _log.isEnabledFor(_DEBUG): # _log.debug("(%s) still waiting for reply, delta %f", handle, delta) - _log.warn('timeout (%0.2f/%0.2f) on device %d request {%04X} params [%s]', - delta, timeout, devnumber, request_id, _strhex(params)) + _log.warn('timeout (%0.2f/%0.2f) on device %d request {%04X} params [%s]', delta, timeout, devnumber, request_id, + _strhex(params)) # raise DeviceUnreachable(number=devnumber, request=request_id) @@ -486,13 +464,11 @@ def ping(handle, devnumber): if reply: report_id, reply_devnumber, reply_data = reply if reply_devnumber == devnumber: - if reply_data[:2] == request_data[:2] and reply_data[ - 4:5] == request_data[-1:]: + if reply_data[:2] == request_data[:2] and reply_data[4:5] == request_data[-1:]: # HID++ 2.0+ device, currently connected return ord(reply_data[2:3]) + ord(reply_data[3:4]) / 10.0 - if report_id == 0x10 and reply_data[:1] == b'\x8F' and reply_data[ - 1:3] == request_data[:2]: + if report_id == 0x10 and reply_data[:1] == b'\x8F' and reply_data[1:3] == request_data[:2]: assert reply_data[-1:] == b'\x00' error = ord(reply_data[3:4]) @@ -503,11 +479,8 @@ def ping(handle, devnumber): return if error == _hidpp10.ERROR.unknown_device: # no paired device with that number - _log.error( - '(%s) device %d error on ping request: unknown device', - handle, devnumber) - raise NoSuchDevice(number=devnumber, - request=request_id) + _log.error('(%s) device %d error on ping request: unknown device', handle, devnumber) + raise NoSuchDevice(number=devnumber, request=request_id) if notifications_hook: n = make_notification(reply_devnumber, reply_data) @@ -518,6 +491,5 @@ def ping(handle, devnumber): delta = _timestamp() - request_started - _log.warn('(%s) timeout (%0.2f/%0.2f) on device %d ping', handle, delta, - _PING_TIMEOUT, devnumber) + _log.warn('(%s) timeout (%0.2f/%0.2f) on device %d ping', handle, delta, _PING_TIMEOUT, devnumber) # raise DeviceUnreachable(number=devnumber, request=request_id) diff --git a/lib/logitech_receiver/common.py b/lib/logitech_receiver/common.py index 4a059641..1a37c4d9 100644 --- a/lib/logitech_receiver/common.py +++ b/lib/logitech_receiver/common.py @@ -107,15 +107,11 @@ class NamedInts(object): def __init__(self, **kwargs): def _readable_name(n): if not is_string(n): - raise TypeError('expected (unicode) string, got ' + - str(type(n))) + raise TypeError('expected (unicode) string, got ' + str(type(n))) return n.replace('__', '/').replace('_', ' ') # print (repr(kwargs)) - values = { - k: NamedInt(v, _readable_name(k)) - for (k, v) in kwargs.items() - } + values = {k: NamedInt(v, _readable_name(k)) for (k, v) in kwargs.items()} self.__dict__ = values self._values = sorted(list(values.values())) self._indexed = {int(v): v for v in self._values} @@ -129,15 +125,8 @@ class NamedInts(object): return NamedInts(**values) @classmethod - def range(cls, - from_value, - to_value, - name_generator=lambda x: str(x), - step=1): - values = { - name_generator(x): x - for x in range(from_value, to_value + 1, step) - } + def range(cls, from_value, to_value, name_generator=lambda x: str(x), step=1): + values = {name_generator(x): x for x in range(from_value, to_value + 1, step)} return NamedInts(**values) def flag_names(self, value): @@ -169,13 +158,10 @@ class NamedInts(object): if index.start is None and index.stop is None: return self._values[:] - v_start = int(self._values[0]) if index.start is None else int( - index.start) - v_stop = (self._values[-1] + - 1) if index.stop is None else int(index.stop) + v_start = int(self._values[0]) if index.start is None else int(index.start) + v_stop = (self._values[-1] + 1) if index.stop is None else int(index.stop) - if v_start > v_stop or v_start > self._values[ - -1] or v_stop <= self._values[0]: + if v_start > v_stop or v_start > self._values[-1] or v_stop <= self._values[0]: return [] if v_start <= self._values[0] and v_stop > self._values[-1]: @@ -282,14 +268,11 @@ class KwException(Exception): """Firmware information.""" -FirmwareInfo = namedtuple('FirmwareInfo', - ['kind', 'name', 'version', 'extras']) +FirmwareInfo = namedtuple('FirmwareInfo', ['kind', 'name', 'version', 'extras']) """Reprogrammable keys information.""" -ReprogrammableKeyInfo = namedtuple('ReprogrammableKeyInfo', - ['index', 'key', 'task', 'flags']) +ReprogrammableKeyInfo = namedtuple('ReprogrammableKeyInfo', ['index', 'key', 'task', 'flags']) -ReprogrammableKeyInfoV4 = namedtuple('ReprogrammableKeyInfoV4', [ - 'index', 'key', 'task', 'flags', 'pos', 'group', 'group_mask', 'remapped' -]) +ReprogrammableKeyInfoV4 = namedtuple('ReprogrammableKeyInfoV4', + ['index', 'key', 'task', 'flags', 'pos', 'group', 'group_mask', 'remapped']) del namedtuple diff --git a/lib/logitech_receiver/descriptors.py b/lib/logitech_receiver/descriptors.py index 6ae6fcc8..b79799c6 100644 --- a/lib/logitech_receiver/descriptors.py +++ b/lib/logitech_receiver/descriptors.py @@ -32,28 +32,18 @@ from .settings_templates import RegisterSettings as _RS # _DeviceDescriptor = namedtuple('_DeviceDescriptor', - ('name', 'kind', 'wpid', 'codename', 'protocol', - 'registers', 'settings', 'persister')) + ('name', 'kind', 'wpid', 'codename', 'protocol', 'registers', 'settings', 'persister')) del namedtuple DEVICES = {} -def _D(name, - codename=None, - kind=None, - wpid=None, - protocol=None, - registers=None, - settings=None, - persister=None): +def _D(name, codename=None, kind=None, wpid=None, protocol=None, registers=None, settings=None, persister=None): assert name if kind is None: - kind = (_DK.mouse if 'Mouse' in name else - _DK.keyboard if 'Keyboard' in name else _DK.numpad - if 'Number Pad' in name else _DK.touchpad if 'Touchpad' in - name else _DK.trackball if 'Trackball' in name else None) + kind = (_DK.mouse if 'Mouse' in name else _DK.keyboard if 'Keyboard' in name else _DK.numpad if 'Number Pad' in name + else _DK.touchpad if 'Touchpad' in name else _DK.trackball if 'Trackball' in name else None) assert kind is not None, 'descriptor for %s does not have kind set' % name # heuristic: the codename is the last word in the device name @@ -73,17 +63,12 @@ def _D(name, if wpid: for w in wpid if isinstance(wpid, tuple) else (wpid, ): if protocol > 1.0: - assert w[0:1] == '4', '%s has protocol %0.1f, wpid %s' % ( - name, protocol, w) + assert w[0:1] == '4', '%s has protocol %0.1f, wpid %s' % (name, protocol, w) else: if w[0:1] == '1': - assert kind == _DK.mouse, '%s has protocol %0.1f, wpid %s' % ( - name, protocol, w) + assert kind == _DK.mouse, '%s has protocol %0.1f, wpid %s' % (name, protocol, w) elif w[0:1] == '2': - assert kind in ( - _DK.keyboard, - _DK.numpad), '%s has protocol %0.1f, wpid %s' % ( - name, protocol, w) + assert kind in (_DK.keyboard, _DK.numpad), '%s has protocol %0.1f, wpid %s' % (name, protocol, w) device_descriptor = _DeviceDescriptor(name=name, kind=kind, @@ -94,8 +79,7 @@ def _D(name, settings=settings, persister=persister) - assert codename not in DEVICES, 'duplicate codename in device descriptors: %s' % ( - DEVICES[codename], ) + assert codename not in DEVICES, 'duplicate codename in device descriptors: %s' % (DEVICES[codename], ) DEVICES[codename] = device_descriptor if wpid: @@ -103,8 +87,7 @@ def _D(name, wpid = (wpid, ) for w in wpid: - assert w not in DEVICES, 'duplicate wpid in device descriptors: %s' % ( - DEVICES[w], ) + assert w not in DEVICES, 'duplicate wpid in device descriptors: %s' % (DEVICES[w], ) DEVICES[w] = device_descriptor @@ -112,8 +95,7 @@ def _D(name, # # -_PERFORMANCE_MX_DPIS = _NamedInts.range(0x81, 0x8F, lambda x: str( - (x - 0x80) * 100)) +_PERFORMANCE_MX_DPIS = _NamedInts.range(0x81, 0x8F, lambda x: str((x - 0x80) * 100)) # # @@ -349,12 +331,9 @@ _D( ) _D('Wireless Mouse M315') _D('Wireless Mouse M317') -_D('Wireless Mouse M325', - protocol=2.0, - wpid='400A', - settings=[ - _FS.hi_res_scroll(), - ]) +_D('Wireless Mouse M325', protocol=2.0, wpid='400A', settings=[ + _FS.hi_res_scroll(), +]) _D('Wireless Mouse M345', protocol=2.0, wpid='4017') _D( 'Wireless Mouse M350', @@ -384,13 +363,9 @@ _D( _RS.side_scroll(), ], ) -_D('Wireless Mouse M510', - codename='M510v2', - protocol=2.0, - wpid='4051', - settings=[ - _FS.lowres_smooth_scroll(), - ]) +_D('Wireless Mouse M510', codename='M510v2', protocol=2.0, wpid='4051', settings=[ + _FS.lowres_smooth_scroll(), +]) _D('Couch Mouse M515', protocol=2.0, wpid='4007') _D('Wireless Mouse M525', protocol=2.0, wpid='4013') _D( @@ -486,10 +461,7 @@ _D( ], ) -_D('Wireless Mouse MX Vertical', - codename='MX Vertical', - protocol=4.5, - wpid='407B') +_D('Wireless Mouse MX Vertical', codename='MX Vertical', protocol=4.5, wpid='407B') _D( 'G7 Cordless Laser Mouse', diff --git a/lib/logitech_receiver/hidpp10.py b/lib/logitech_receiver/hidpp10.py index 727eb601..4ab20ebd 100644 --- a/lib/logitech_receiver/hidpp10.py +++ b/lib/logitech_receiver/hidpp10.py @@ -36,12 +36,7 @@ del getLogger # documentation, some of them guessed. # -DEVICE_KIND = _NamedInts(keyboard=0x01, - mouse=0x02, - numpad=0x03, - presenter=0x04, - trackball=0x08, - touchpad=0x09) +DEVICE_KIND = _NamedInts(keyboard=0x01, mouse=0x02, numpad=0x03, presenter=0x04, trackball=0x08, touchpad=0x09) POWER_SWITCH_LOCATION = _NamedInts(base=0x01, top_case=0x02, @@ -70,12 +65,10 @@ POWER_SWITCH_LOCATION = _NamedInts(base=0x01, NOTIFICATION_FLAG = _NamedInts( battery_status=0x100000, # send battery charge notifications (0x07 or 0x0D) keyboard_sleep_raw=0x020000, # system control keys such as Sleep - keyboard_multimedia_raw= - 0x010000, # consumer controls such as Mute and Calculator + keyboard_multimedia_raw=0x010000, # consumer controls such as Mute and Calculator # reserved_r1b4= 0x001000, # unknown, seen on a unifying receiver software_present=0x000800, # .. no idea - keyboard_illumination= - 0x000200, # illumination brightness level changes (by pressing keys) + keyboard_illumination=0x000200, # illumination brightness level changes (by pressing keys) wireless=0x000100, # notify when the device wireless goes on/off-line ) @@ -92,10 +85,7 @@ ERROR = _NamedInts(invalid_SubID__command=0x01, unsupported_parameter_value=0x0B, wrong_pin_code=0x0C) -PAIRING_ERRORS = _NamedInts(device_timeout=0x01, - device_not_supported=0x02, - too_many_devices=0x03, - sequence_timeout=0x06) +PAIRING_ERRORS = _NamedInts(device_timeout=0x01, device_not_supported=0x02, too_many_devices=0x03, sequence_timeout=0x06) BATTERY_APPOX = _NamedInts(empty=0, critical=5, low=20, good=50, full=90) """Known registers. @@ -129,16 +119,14 @@ REGISTERS = _NamedInts( def read_register(device, register_number, *params): - assert device, 'tried to read register %02X from invalid device %s' % ( - register_number, device) + assert device, 'tried to read register %02X from invalid device %s' % (register_number, device) # support long registers by adding a 2 in front of the register number request_id = 0x8100 | (int(register_number) & 0x2FF) return device.request(request_id, *params) def write_register(device, register_number, *value): - assert device, 'tried to write register %02X to invalid device %s' % ( - register_number, device) + assert device, 'tried to write register %02X to invalid device %s' % (register_number, device) # support long registers by adding a 2 in front of the register number request_id = 0x8000 | (int(register_number) & 0x2FF) return device.request(request_id, *value) @@ -179,9 +167,8 @@ def parse_battery_status(register, reply): if register == REGISTERS.battery_charge: charge = ord(reply[:1]) status_byte = ord(reply[2:3]) & 0xF0 - status_text = (BATTERY_STATUS.discharging if status_byte == 0x30 else - BATTERY_STATUS.recharging if status_byte == 0x50 else - BATTERY_STATUS.full if status_byte == 0x90 else None) + status_text = (BATTERY_STATUS.discharging if status_byte == 0x30 else BATTERY_STATUS.recharging + if status_byte == 0x50 else BATTERY_STATUS.full if status_byte == 0x90 else None) return charge, status_text, None if register == REGISTERS.battery_status: @@ -202,8 +189,7 @@ def parse_battery_status(register, reply): elif charging_byte & 0x22 == 0x22: status_text = BATTERY_STATUS.full else: - _log.warn('could not parse 0x07 battery status: %02X (level %02X)', - charging_byte, status_byte) + _log.warn('could not parse 0x07 battery status: %02X (level %02X)', charging_byte, status_byte) status_text = None if charging_byte & 0x03 and status_byte == 0: @@ -321,6 +307,5 @@ def set_notification_flags(device, *flag_bits): flag_bits = sum(int(b) for b in flag_bits) assert flag_bits & 0x00FFFFFF == flag_bits - result = write_register(device, REGISTERS.notifications, - _int2bytes(flag_bits, 3)) + result = write_register(device, REGISTERS.notifications, _int2bytes(flag_bits, 3)) return result is not None diff --git a/lib/logitech_receiver/hidpp20.py b/lib/logitech_receiver/hidpp20.py index 888b2b87..e38da9fa 100644 --- a/lib/logitech_receiver/hidpp20.py +++ b/lib/logitech_receiver/hidpp20.py @@ -169,13 +169,9 @@ DEVICE_KIND = _NamedInts(keyboard=0x00, presenter=0x06, receiver=0x07) -FIRMWARE_KIND = _NamedInts(Firmware=0x00, - Bootloader=0x01, - Hardware=0x02, - Other=0x03) +FIRMWARE_KIND = _NamedInts(Firmware=0x00, Bootloader=0x01, Hardware=0x02, Other=0x03) -BATTERY_OK = lambda status: status not in (BATTERY_STATUS.invalid_battery, - BATTERY_STATUS.thermal_error) +BATTERY_OK = lambda status: status not in (BATTERY_STATUS.invalid_battery, BATTERY_STATUS.thermal_error) BATTERY_STATUS = _NamedInts(discharging=0x00, recharging=0x01, @@ -185,10 +181,7 @@ BATTERY_STATUS = _NamedInts(discharging=0x00, invalid_battery=0x05, thermal_error=0x06) -CHARGE_STATUS = _NamedInts(charging=0x00, - full=0x01, - not_charging=0x02, - error=0x07) +CHARGE_STATUS = _NamedInts(charging=0x00, full=0x01, not_charging=0x02, error=0x07) CHARGE_LEVEL = _NamedInts(average=50, full=90, critical=5) @@ -259,8 +252,7 @@ class FeaturesArray(object): self.device = None return False - reply = self.device.request(0x0000, _pack('!H', - FEATURE.FEATURE_SET)) + reply = self.device.request(0x0000, _pack('!H', FEATURE.FEATURE_SET)) if reply is None: self.supported = False else: @@ -268,9 +260,7 @@ class FeaturesArray(object): if fs_index: count = self.device.request(fs_index << 8) if count is None: - _log.warn( - 'FEATURE_SET found, but failed to read features count' - ) + _log.warn('FEATURE_SET found, but failed to read features count') # most likely the device is unavailable return False else: @@ -294,8 +284,7 @@ class FeaturesArray(object): raise IndexError(index) if self.features[index] is None: - feature = self.device.feature_request( - FEATURE.FEATURE_SET, 0x10, index) + feature = self.device.feature_request(FEATURE.FEATURE_SET, 0x10, index) if feature: feature, = _unpack('!H', feature[:2]) self.features[index] = FEATURE[feature] @@ -386,30 +375,23 @@ class KeysArray(object): # TODO: add here additional variants for other REPROG_CONTROLS if self.keys[index] is None: - keydata = feature_request(self.device, FEATURE.REPROG_CONTROLS, - 0x10, index) + keydata = feature_request(self.device, FEATURE.REPROG_CONTROLS, 0x10, index) self.keyversion = 1 if keydata is None: - keydata = feature_request(self.device, - FEATURE.REPROG_CONTROLS_V4, 0x10, - index) + keydata = feature_request(self.device, FEATURE.REPROG_CONTROLS_V4, 0x10, index) self.keyversion = 4 if keydata: - key, key_task, flags, pos, group, gmask = _unpack( - '!HHBBBB', keydata[:8]) + key, key_task, flags, pos, group, gmask = _unpack('!HHBBBB', keydata[:8]) ctrl_id_text = special_keys.CONTROL[key] ctrl_task_text = special_keys.TASK[key_task] if self.keyversion == 1: - self.keys[index] = _ReprogrammableKeyInfo( - index, ctrl_id_text, ctrl_task_text, flags) + self.keys[index] = _ReprogrammableKeyInfo(index, ctrl_id_text, ctrl_task_text, flags) if self.keyversion == 4: try: - mapped_data = feature_request( - self.device, FEATURE.REPROG_CONTROLS_V4, 0x20, - key & 0xff00, key & 0xff) + mapped_data = feature_request(self.device, FEATURE.REPROG_CONTROLS_V4, 0x20, key & 0xff00, + key & 0xff) if mapped_data: - remap_key, remap_flag, remapped = _unpack( - '!HBH', mapped_data[:5]) + remap_key, remap_flag, remapped = _unpack('!HBH', mapped_data[:5]) # if key not mapped map it to itself for display if remapped == 0: remapped = key @@ -419,9 +401,8 @@ class KeysArray(object): # remap_flag = 0 remapped_text = special_keys.CONTROL[remapped] - self.keys[index] = _ReprogrammableKeyInfoV4( - index, ctrl_id_text, ctrl_task_text, flags, pos, - group, gmask, remapped_text) + self.keys[index] = _ReprogrammableKeyInfoV4(index, ctrl_id_text, ctrl_task_text, flags, pos, group, + gmask, remapped_text) return self.keys[index] @@ -457,8 +438,7 @@ def feature_request(device, feature, function=0x00, *params): if device.online and device.features: if feature in device.features: feature_index = device.features.index(int(feature)) - return device.request((feature_index << 8) + (function & 0xFF), - *params) + return device.request((feature_index << 8) + (function & 0xFF), *params) def get_firmware(device): @@ -472,23 +452,18 @@ def get_firmware(device): fw = [] for index in range(0, count): - fw_info = feature_request(device, FEATURE.DEVICE_FW_VERSION, 0x10, - index) + fw_info = feature_request(device, FEATURE.DEVICE_FW_VERSION, 0x10, index) if fw_info: level = ord(fw_info[:1]) & 0x0F if level == 0 or level == 1: - name, version_major, version_minor, build = _unpack( - '!3sBBH', fw_info[1:8]) + name, version_major, version_minor, build = _unpack('!3sBBH', fw_info[1:8]) version = '%02X.%02X' % (version_major, version_minor) if build: version += '.B%04X' % build extras = fw_info[9:].rstrip(b'\x00') or None - fw_info = _FirmwareInfo(FIRMWARE_KIND[level], - name.decode('ascii'), version, - extras) + fw_info = _FirmwareInfo(FIRMWARE_KIND[level], name.decode('ascii'), version, extras) elif level == FIRMWARE_KIND.Hardware: - fw_info = _FirmwareInfo(FIRMWARE_KIND.Hardware, '', - str(ord(fw_info[1:2])), None) + fw_info = _FirmwareInfo(FIRMWARE_KIND.Hardware, '', str(ord(fw_info[1:2])), None) else: fw_info = _FirmwareInfo(FIRMWARE_KIND.Other, '', '', None) @@ -525,14 +500,11 @@ def get_name(device): name = b'' while len(name) < name_length: - fragment = feature_request(device, FEATURE.DEVICE_NAME, 0x10, - len(name)) + fragment = feature_request(device, FEATURE.DEVICE_NAME, 0x10, len(name)) if fragment: name += fragment[:name_length - len(name)] else: - _log.error( - 'failed to read whole name of %s (expected %d chars)', - device, name_length) + _log.error('failed to read whole name of %s (expected %d chars)', device, name_length) return None return name.decode('ascii') @@ -545,10 +517,8 @@ def get_battery(device): discharge, dischargeNext, status = _unpack('!BBB', battery[:3]) discharge = None if discharge == 0 else discharge if _log.isEnabledFor(_DEBUG): - _log.debug( - 'device %d battery %d%% charged, next level %d%% charge, status %d = %s', - device.number, discharge, dischargeNext, status, - BATTERY_STATUS[status]) + _log.debug('device %d battery %d%% charged, next level %d%% charge, status %d = %s', device.number, discharge, + dischargeNext, status, BATTERY_STATUS[status]) return discharge, BATTERY_STATUS[status], dischargeNext @@ -614,12 +584,10 @@ def get_mouse_pointer_info(device): def get_vertical_scrolling_info(device): - vertical_scrolling_info = feature_request(device, - FEATURE.VERTICAL_SCROLLING) + vertical_scrolling_info = feature_request(device, FEATURE.VERTICAL_SCROLLING) if vertical_scrolling_info: roller, ratchet, lines = _unpack('!BBB', vertical_scrolling_info[:3]) - roller_type = ('reserved', 'standard', 'reserved', '3G', 'micro', - 'normal touch pad', 'inverted touch pad', + roller_type = ('reserved', 'standard', 'reserved', '3G', 'micro', 'normal touch pad', 'inverted touch pad', 'reserved')[roller] return {'roller': roller_type, 'ratchet': ratchet, 'lines': lines} diff --git a/lib/logitech_receiver/listener.py b/lib/logitech_receiver/listener.py index aa62c9f4..c48d1903 100644 --- a/lib/logitech_receiver/listener.py +++ b/lib/logitech_receiver/listener.py @@ -142,8 +142,7 @@ class EventsListener(_threading.Thread): Incoming packets will be passed to the callback function in sequence. """ def __init__(self, receiver, notifications_callback): - super(EventsListener, self).__init__(name=self.__class__.__name__ + - ':' + receiver.path.split('/')[2]) + super(EventsListener, self).__init__(name=self.__class__.__name__ + ':' + receiver.path.split('/')[2]) self.daemon = True self._active = False @@ -158,8 +157,7 @@ class EventsListener(_threading.Thread): self._active = True # replace the handle with a threaded one - self.receiver.handle = _ThreadedHandle(self, self.receiver.path, - self.receiver.handle) + self.receiver.handle = _ThreadedHandle(self, self.receiver.path, self.receiver.handle) # get the right low-level handle for this thread ihandle = int(self.receiver.handle) if _log.isEnabledFor(_INFO): diff --git a/lib/logitech_receiver/notifications.py b/lib/logitech_receiver/notifications.py index 0c0c526f..df3740e0 100644 --- a/lib/logitech_receiver/notifications.py +++ b/lib/logitech_receiver/notifications.py @@ -72,8 +72,7 @@ def _process_receiver_notification(receiver, status, n): # pairing lock notification if n.sub_id == 0x4A: status.lock_open = bool(n.address & 0x01) - reason = (_('pairing lock is open') - if status.lock_open else _('pairing lock is closed')) + reason = (_('pairing lock is open') if status.lock_open else _('pairing lock is closed')) if _log.isEnabledFor(_INFO): _log.info('%s: %s', receiver, reason) @@ -83,8 +82,7 @@ def _process_receiver_notification(receiver, status, n): pair_error = ord(n.data[:1]) if pair_error: - status[ - _K.ERROR] = error_string = _hidpp10.PAIRING_ERRORS[pair_error] + status[_K.ERROR] = error_string = _hidpp10.PAIRING_ERRORS[pair_error] status.new_device = None _log.warn('pairing error %d: %s', pair_error, error_string) @@ -124,8 +122,7 @@ def _process_device_notification(device, status, n): try: feature = device.features[n.sub_id] except IndexError: - _log.warn('%s: notification from invalid feature index %02X: %s', - device, n.sub_id, n) + _log.warn('%s: notification from invalid feature index %02X: %s', device, n.sub_id, n) return False return _process_feature_notification(device, status, n, feature) @@ -157,8 +154,7 @@ def _process_dj_notification(device, status, n): def _process_hidpp10_custom_notification(device, status, n): if _log.isEnabledFor(_DEBUG): - _log.debug('%s (%s) custom notification %s', device, device.protocol, - n) + _log.debug('%s (%s) custom notification %s', device, device.protocol, n) if n.sub_id in (_R.battery_status, _R.battery_charge): # message layout: 10 ix <00> @@ -188,31 +184,22 @@ def _process_hidpp10_notification(device, status, n): device.status = None if device.number in device.receiver: del device.receiver[device.number] - status.changed(active=False, - alert=_ALERT.ALL, - reason=_('unpaired')) + status.changed(active=False, alert=_ALERT.ALL, reason=_('unpaired')) else: - _log.warn('%s: disconnection with unknown type %02X: %s', device, - n.address, n) + _log.warn('%s: disconnection with unknown type %02X: %s', device, n.address, n) return True # wireless link notification if n.sub_id == 0x41: - protocol_name = ( - 'Bluetooth' if n.address == 0x01 else '27 MHz' - if n.address == 0x02 else 'QUAD or eQUAD' if n.address == 0x03 else - 'eQUAD step 4 DJ' if n.address == 0x04 else 'DFU Lite' if n. - address == 0x05 else 'eQUAD step 4 Lite' if n.address == - 0x06 else 'eQUAD step 4 Gaming' if n.address == - 0x07 else 'eQUAD step 4 for gamepads' if n.address == - 0x08 else 'eQUAD nano Lite' if n.address == - 0x0A else 'Lightspeed 1' if n.address == - 0x0C else 'Lightspeed 1_1' if n.address == 0x0D else None) + protocol_name = ('Bluetooth' if n.address == 0x01 else '27 MHz' if n.address == 0x02 else 'QUAD or eQUAD' + if n.address == 0x03 else 'eQUAD step 4 DJ' if n.address == 0x04 else 'DFU Lite' if n.address == + 0x05 else 'eQUAD step 4 Lite' if n.address == 0x06 else 'eQUAD step 4 Gaming' if n.address == + 0x07 else 'eQUAD step 4 for gamepads' if n.address == 0x08 else 'eQUAD nano Lite' if n.address == + 0x0A else 'Lightspeed 1' if n.address == 0x0C else 'Lightspeed 1_1' if n.address == 0x0D else None) if protocol_name: if _log.isEnabledFor(_DEBUG): wpid = _strhex(n.data[2:3] + n.data[1:2]) - assert wpid == device.wpid, '%s wpid mismatch, got %s' % ( - device, wpid) + assert wpid == device.wpid, '%s wpid mismatch, got %s' % (device, wpid) flags = ord(n.data[:1]) & 0xF0 link_encrypted = bool(flags & 0x20) @@ -220,16 +207,12 @@ def _process_hidpp10_notification(device, status, n): if _log.isEnabledFor(_DEBUG): sw_present = bool(flags & 0x10) has_payload = bool(flags & 0x80) - _log.debug( - '%s: %s connection notification: software=%s, encrypted=%s, link=%s, payload=%s', - device, protocol_name, sw_present, link_encrypted, - link_established, has_payload) + _log.debug('%s: %s connection notification: software=%s, encrypted=%s, link=%s, payload=%s', device, + protocol_name, sw_present, link_encrypted, link_established, has_payload) status[_K.LINK_ENCRYPTED] = link_encrypted status.changed(active=link_established) else: - _log.warn( - '%s: connection notification with unknown protocol %02X: %s', - device.number, n.address, n) + _log.warn('%s: connection notification with unknown protocol %02X: %s', device.number, n.address, n) return True @@ -246,9 +229,7 @@ def _process_hidpp10_notification(device, status, n): if _log.isEnabledFor(_DEBUG): _log.debug('%s: device powered on', device) reason = status.to_string() or _('powered on') - status.changed(active=True, - alert=_ALERT.NOTIFICATION, - reason=reason) + status.changed(active=True, alert=_ALERT.NOTIFICATION, reason=reason) else: _log.warn('%s: unknown %s', device, n) return True @@ -263,17 +244,14 @@ def _process_feature_notification(device, status, n, feature): discharge_level = None if discharge_level == 0 else discharge_level discharge_next_level = ord(n.data[1:2]) battery_status = ord(n.data[2:3]) - status.set_battery_info(discharge_level, - _hidpp20.BATTERY_STATUS[battery_status], - discharge_next_level) + status.set_battery_info(discharge_level, _hidpp20.BATTERY_STATUS[battery_status], discharge_next_level) else: _log.warn('%s: unknown BATTERY %s', device, n) return True if feature == _F.BATTERY_VOLTAGE: if n.address == 0x00: - level, status, voltage, _ignore, _ignore = _hidpp20.decipher_voltage( - n.data) + level, status, voltage, _ignore, _ignore = _hidpp20.decipher_voltage(n.data) status.set_battery_info(level, status, None, voltage) else: _log.warn('%s: unknown VOLTAGE %s', device, n) @@ -293,9 +271,7 @@ def _process_feature_notification(device, status, n, feature): if _log.isEnabledFor(_DEBUG): _log.debug('wireless status: %s', n) if n.data[0:3] == b'\x01\x01\x01': - status.changed(active=True, - alert=_ALERT.NOTIFICATION, - reason='powered on') + status.changed(active=True, alert=_ALERT.NOTIFICATION, reason='powered on') else: _log.warn('%s: unknown WIRELESS %s', device, n) else: @@ -326,8 +302,7 @@ def _process_feature_notification(device, status, n, feature): # trigger a new report chain reports_count = 15 reports_period = 2 # seconds - device.feature_request(_F.SOLAR_DASHBOARD, 0x00, reports_count, - reports_period) + device.feature_request(_F.SOLAR_DASHBOARD, 0x00, reports_count, reports_period) else: _log.warn('%s: unknown SOLAR CHARGE %s', device, n) else: @@ -343,9 +318,7 @@ def _process_feature_notification(device, status, n, feature): button_down = bool(touch & 0x02) mouse_lifted = bool(touch & 0x01) if _log.isEnabledFor(_INFO): - _log.info( - '%s: TOUCH MOUSE status: button_down=%s mouse_lifted=%s', - device, button_down, mouse_lifted) + _log.info('%s: TOUCH MOUSE status: button_down=%s mouse_lifted=%s', device, button_down, mouse_lifted) else: _log.warn('%s: unknown TOUCH MOUSE %s', device, n) return True @@ -356,8 +329,7 @@ def _process_feature_notification(device, status, n, feature): flags, delta_v = _unpack('>bh', n.data[:3]) high_res = (flags & 0x10) != 0 periods = flags & 0x0f - _log.info('%s: WHEEL: res: %d periods: %d delta V:%-3d', - device, high_res, periods, delta_v) + _log.info('%s: WHEEL: res: %d periods: %d delta V:%-3d', device, high_res, periods, delta_v) return True elif (n.address == 0x10): if _log.isEnabledFor(_INFO): @@ -369,5 +341,4 @@ def _process_feature_notification(device, status, n, feature): _log.warn('%s: unknown WHEEL %s', device, n) return True - _log.warn('%s: unrecognized %s for feature %s (index %02X)', device, n, - feature, n.sub_id) + _log.warn('%s: unrecognized %s for feature %s (index %02X)', device, n, feature, n.sub_id) diff --git a/lib/logitech_receiver/receiver.py b/lib/logitech_receiver/receiver.py index a7fdf8e2..f6b5fa21 100644 --- a/lib/logitech_receiver/receiver.py +++ b/lib/logitech_receiver/receiver.py @@ -85,15 +85,13 @@ class PairedDevice(object): 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]) + 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 = receiver.read_register(_R.receiver_info, - 0x20 + number - 1) + pair_info = 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]) @@ -103,14 +101,10 @@ class PairedDevice(object): else: # unifying protocol not supported, must be a Nano receiver - device_info = self.receiver.read_register( - _R.receiver_info, 0x04) + 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') + _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._polling_rate = 0 @@ -118,15 +112,13 @@ class PairedDevice(object): # 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) + assert self.wpid is not None, 'failed to read wpid: device %d of %s' % (number, receiver) 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) + 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] @@ -142,8 +134,7 @@ class PairedDevice(object): self._kind = self.descriptor.kind if self._protocol is not None: - self.features = None if self._protocol < 2.0 else _hidpp20.FeaturesArray( - self) + 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) @@ -162,8 +153,7 @@ class PairedDevice(object): @property def codename(self): if self._codename is None: - codename = self.receiver.read_register(_R.receiver_info, - 0x40 + self.number - 1) + 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] @@ -184,8 +174,7 @@ class PairedDevice(object): @property def kind(self): if self._kind is None: - pair_info = self.receiver.read_register(_R.receiver_info, - 0x20 + self.number - 1) + pair_info = self.receiver.read_register(_R.receiver_info, 0x20 + self.number - 1) if pair_info: kind = ord(pair_info[7:8]) & 0x0F self._kind = _hidpp10.DEVICE_KIND[kind] @@ -206,8 +195,7 @@ class PairedDevice(object): @property def serial(self): if self._serial is None: - serial = self.receiver.read_register(_R.receiver_info, - 0x30 + self.number - 1) + serial = self.receiver.read_register(_R.receiver_info, 0x30 + self.number - 1) if serial: ps = ord(serial[9:10]) & 0x0F self._power_switch = _hidpp10.POWER_SWITCH_LOCATION[ps] @@ -225,8 +213,7 @@ class PairedDevice(object): @property def power_switch_location(self): if self._power_switch is None: - ps = self.receiver.read_register(_R.receiver_info, - 0x30 + self.number - 1) + ps = self.receiver.read_register(_R.receiver_info, 0x30 + self.number - 1) if ps is not None: ps = ord(ps[9:10]) & 0x0F self._power_switch = _hidpp10.POWER_SWITCH_LOCATION[ps] @@ -237,8 +224,7 @@ class PairedDevice(object): @property def polling_rate(self): if self._polling_rate is None: - pair_info = self.receiver.read_register(_R.receiver_info, - 0x20 + self.number - 1) + pair_info = self.receiver.read_register(_R.receiver_info, 0x20 + self.number - 1) if pair_info: self._polling_rate = ord(pair_info[2:3]) else: @@ -270,8 +256,7 @@ class PairedDevice(object): else: self._settings = [] if not self._feature_settings_checked: - self._feature_settings_checked = _check_feature_settings( - self, self._settings) + self._feature_settings_checked = _check_feature_settings(self, self._settings) return self._settings def enable_notifications(self, enable=True): @@ -289,20 +274,16 @@ class PairedDevice(object): set_flag_bits = 0 ok = _hidpp10.set_notification_flags(self, set_flag_bits) if ok is None: - _log.warn('%s: failed to %s device notifications', self, - 'enable' if enable else 'disable') + _log.warn('%s: failed to %s device notifications', self, 'enable' if enable else 'disable') flag_bits = _hidpp10.get_notification_flags(self) - flag_names = None if flag_bits is None else tuple( - _hidpp10.NOTIFICATION_FLAG.flag_names(flag_bits)) + flag_names = None if flag_bits is None else tuple(_hidpp10.NOTIFICATION_FLAG.flag_names(flag_bits)) if _log.isEnabledFor(_INFO): - _log.info('%s: device notifications %s %s', self, - 'enabled' if enable else 'disabled', flag_names) + _log.info('%s: device notifications %s %s', self, 'enabled' if enable else 'disabled', flag_names) return flag_bits if ok else None def request(self, request_id, *params): - return _base.request(self.receiver.handle, self.number, request_id, - *params) + return _base.request(self.receiver.handle, self.number, request_id, *params) read_register = _hidpp10.read_register write_register = _hidpp10.write_register @@ -336,8 +317,7 @@ class PairedDevice(object): __bool__ = __nonzero__ = lambda self: self.wpid is not None and self.number in self.receiver def __str__(self): - return '' % ( - self.number, self.wpid, self.codename or '?', self.serial) + return '' % (self.number, self.wpid, self.codename or '?', self.serial) __unicode__ = __repr__ = __str__ @@ -382,8 +362,7 @@ class Receiver(object): self.name = product_info.get('name', '') self.re_pairs = product_info.get('re_pairs', False) self._str = '<%s(%s,%s%s)>' % (self.name.replace( - ' ', ''), self.path, '' if isinstance(self.handle, int) else 'T', - self.handle) + ' ', ''), self.path, '' if isinstance(self.handle, int) else 'T', self.handle) self._firmware = None self._devices = {} @@ -426,29 +405,24 @@ class Receiver(object): set_flag_bits = 0 ok = _hidpp10.set_notification_flags(self, set_flag_bits) if ok is None: - _log.warn('%s: failed to %s receiver notifications', self, - 'enable' if enable else 'disable') + _log.warn('%s: failed to %s receiver notifications', self, 'enable' if enable else 'disable') return None flag_bits = _hidpp10.get_notification_flags(self) - flag_names = None if flag_bits is None else tuple( - _hidpp10.NOTIFICATION_FLAG.flag_names(flag_bits)) + flag_names = None if flag_bits is None else tuple(_hidpp10.NOTIFICATION_FLAG.flag_names(flag_bits)) if _log.isEnabledFor(_INFO): - _log.info('%s: receiver notifications %s => %s', self, - 'enabled' if enable else 'disabled', flag_names) + _log.info('%s: receiver notifications %s => %s', self, 'enabled' if enable else 'disabled', flag_names) return flag_bits def notify_devices(self): """Scan all devices.""" if self.handle: if not self.write_register(_R.receiver_connection, 0x02): - _log.warn('%s: failed to trigger device link notifications', - self) + _log.warn('%s: failed to trigger device link notifications', self) def register_new_device(self, number, notification=None): if self._devices.get(number) is not None: - raise IndexError('%s: device number %d already registered' % - (self, number)) + raise IndexError('%s: device number %d already registered' % (self, number)) assert notification is None or notification.devnumber == number assert notification is None or notification.sub_id == 0x41 @@ -457,8 +431,7 @@ class Receiver(object): dev = PairedDevice(self, number, notification) assert dev.wpid if _log.isEnabledFor(_INFO): - _log.info('%s: found new device %d (%s)', self, number, - dev.wpid) + _log.info('%s: found new device %d (%s)', self, number, dev.wpid) self._devices[number] = dev return dev except _base.NoSuchDevice: @@ -470,12 +443,10 @@ class Receiver(object): def set_lock(self, lock_closed=True, device=0, timeout=0): if self.handle: action = 0x02 if lock_closed else 0x01 - reply = self.write_register(_R.receiver_pairing, action, device, - timeout) + reply = self.write_register(_R.receiver_pairing, action, device, timeout) if reply: return True - _log.warn('%s: failed to %s the receiver lock', self, - 'close' if lock_closed else 'open') + _log.warn('%s: failed to %s the receiver lock', self, 'close' if lock_closed else 'open') def count(self): count = self.read_register(_R.receiver_connection) diff --git a/lib/logitech_receiver/settings.py b/lib/logitech_receiver/settings.py index 80964e85..6c14c737 100644 --- a/lib/logitech_receiver/settings.py +++ b/lib/logitech_receiver/settings.py @@ -37,28 +37,15 @@ del getLogger # # -KIND = _NamedInts(toggle=0x01, - choice=0x02, - range=0x04, - map_choice=0x0A, - multiple_toggle=0x10) +KIND = _NamedInts(toggle=0x01, choice=0x02, range=0x04, map_choice=0x0A, multiple_toggle=0x10) class Setting(object): """A setting descriptor. Needs to be instantiated for each specific device.""" - __slots__ = ('name', 'label', 'description', 'kind', 'device_kind', - 'feature', '_rw', '_validator', '_device', '_value') + __slots__ = ('name', 'label', 'description', 'kind', 'device_kind', 'feature', '_rw', '_validator', '_device', '_value') - def __init__(self, - name, - rw, - validator, - kind=None, - label=None, - description=None, - device_kind=None, - feature=None): + def __init__(self, name, rw, validator, kind=None, label=None, description=None, device_kind=None, feature=None): assert name self.name = name self.label = label or name @@ -109,8 +96,7 @@ class Setting(object): assert hasattr(self, '_device') if _log.isEnabledFor(_DEBUG): - _log.debug('%s: settings read %r from %s', self.name, self._value, - self._device) + _log.debug('%s: settings read %r from %s', self.name, self._value, self._device) if self._value is None and self._device.persister: # We haven't read a value from the device yet, @@ -140,8 +126,7 @@ class Setting(object): assert value is not None if _log.isEnabledFor(_DEBUG): - _log.debug('%s: settings write %r to %s', self.name, value, - self._device) + _log.debug('%s: settings write %r to %s', self.name, value, self._device) if self._device.online: # Remember the value we're trying to set, even if the write fails. @@ -159,8 +144,7 @@ class Setting(object): data_bytes = self._validator.prepare_write(value, current_value) if data_bytes is not None: if _log.isEnabledFor(_DEBUG): - _log.debug('%s: settings prepare write(%s) => %r', - self.name, value, data_bytes) + _log.debug('%s: settings prepare write(%s) => %r', self.name, value, data_bytes) reply = self._rw.write(self._device, data_bytes) if not reply: @@ -174,8 +158,7 @@ class Setting(object): assert hasattr(self, '_device') if _log.isEnabledFor(_DEBUG): - _log.debug('%s: apply %s (%s)', self.name, self._value, - self._device) + _log.debug('%s: apply %s (%s)', self.name, self._value, self._device) value = self.read() if value is not None: @@ -184,11 +167,9 @@ class Setting(object): def __str__(self): if hasattr(self, '_value'): assert hasattr(self, '_device') - return '' % ( - self._rw.kind, self._validator.kind, self._device.codename, - self.name, self._value) - return '' % (self._rw.kind, self._validator.kind, - self.name) + return '' % (self._rw.kind, self._validator.kind, self._device.codename, self.name, + self._value) + return '' % (self._rw.kind, self._validator.kind, self.name) __unicode__ = __repr__ = __str__ @@ -201,8 +182,7 @@ class Settings(Setting): assert hasattr(self, '_device') if _log.isEnabledFor(_DEBUG): - _log.debug('%s: settings read %r from %s', self.name, self._value, - self._device) + _log.debug('%s: settings read %r from %s', self.name, self._value, self._device) if self._value is None and getattr(self._device, 'persister', None): # We haven't read a value from the device yet, @@ -210,8 +190,7 @@ class Settings(Setting): self._value = self._device.persister.get(self.name) if cached and self._value is not None: - if getattr(self._device, 'persister', - None) and self.name not in self._device.persister: + if getattr(self._device, 'persister', None) and self.name not in self._device.persister: # If this is a new device (or a new setting for an old device), # make sure to save its current value for the next time. self._device.persister[self.name] = self._value @@ -224,11 +203,9 @@ class Settings(Setting): if reply: # keys are ints, because that is what the device uses, # encoded into strings because JSON requires strings as keys - reply_map[str(int(key))] = self._validator.validate_read( - reply, key) + reply_map[str(int(key))] = self._validator.validate_read(reply, key) self._value = reply_map - if getattr(self._device, 'persister', - None) and self.name not in self._device.persister: + if getattr(self._device, 'persister', None) and self.name not in self._device.persister: # Don't update the persister if it already has a value, # otherwise the first read might overwrite the value we wanted. self._device.persister[self.name] = self._value @@ -240,25 +217,21 @@ class Settings(Setting): assert key is not None if _log.isEnabledFor(_DEBUG): - _log.debug('%s: settings read %r key %r from %s', self.name, - self._value, key, self._device) + _log.debug('%s: settings read %r key %r from %s', self.name, self._value, key, self._device) if self._value is None and getattr(self._device, 'persister', None): self._value = self._device.persister.get(self.name) if cached and self._value is not None: - if getattr(self._device, 'persister', - None) and self.name not in self._device.persister: + if getattr(self._device, 'persister', None) and self.name not in self._device.persister: self._device.persister[self.name] = self._value return self._value[str(int(key))] if self._device.online: reply = self._rw.read(self._device, key) if reply: - self._value[str(int(key))] = self._validator.validate_read( - reply, key) - if getattr(self._device, 'persister', - None) and self.name not in self._device.persister: + self._value[str(int(key))] = self._validator.validate_read(reply, key) + if getattr(self._device, 'persister', None) and self.name not in self._device.persister: self._device.persister[self.name] = self._value return self._value[str(int(key))] @@ -268,8 +241,7 @@ class Settings(Setting): assert map is not None if _log.isEnabledFor(_DEBUG): - _log.debug('%s: settings write %r to %s', self.name, map, - self._device) + _log.debug('%s: settings write %r to %s', self.name, map, self._device) if self._device.online: # Remember the value we're trying to set, even if the write fails. @@ -283,9 +255,7 @@ class Settings(Setting): data_bytes = self._validator.prepare_write(int(key), value) if data_bytes is not None: if _log.isEnabledFor(_DEBUG): - _log.debug( - '%s: settings prepare map write(%s,%s) => %r', - self.name, key, value, data_bytes) + _log.debug('%s: settings prepare map write(%s,%s) => %r', self.name, key, value, data_bytes) reply = self._rw.write(self._device, int(key), data_bytes) if not reply: return None @@ -299,8 +269,7 @@ class Settings(Setting): assert value is not None if _log.isEnabledFor(_DEBUG): - _log.debug('%s: settings write key %r value %r to %s', self.name, - key, value, self._device) + _log.debug('%s: settings write key %r value %r to %s', self.name, key, value, self._device) if self._device.online: # Remember the value we're trying to set, even if the write fails. @@ -313,9 +282,7 @@ class Settings(Setting): data_bytes = self._validator.prepare_write(int(key), value) if data_bytes is not None: if _log.isEnabledFor(_DEBUG): - _log.debug( - '%s: settings prepare key value write(%s,%s) => %r', - self.name, key, value, data_bytes) + _log.debug('%s: settings prepare key value write(%s,%s) => %r', self.name, key, value, data_bytes) reply = self._rw.write(self._device, int(key), data_bytes) if not reply: # tell whomever is calling that the write failed @@ -332,8 +299,7 @@ class BitFieldSetting(Setting): assert hasattr(self, '_device') if _log.isEnabledFor(_DEBUG): - _log.debug('%s: settings read %r from %s', self.name, self._value, - self._device) + _log.debug('%s: settings read %r from %s', self.name, self._value, self._device) if self._value is None and getattr(self._device, 'persister', None): # We haven't read a value from the device yet, @@ -341,8 +307,7 @@ class BitFieldSetting(Setting): self._value = self._device.persister.get(self.name) if cached and self._value is not None: - if getattr(self._device, 'persister', - None) and self.name not in self._device.persister: + if getattr(self._device, 'persister', None) and self.name not in self._device.persister: # If this is a new device (or a new setting for an old device), # make sure to save its current value for the next time. self._device.persister[self.name] = self._value @@ -356,8 +321,7 @@ class BitFieldSetting(Setting): # encoded into strings because JSON requires strings as keys reply_map = self._validator.validate_read(reply) self._value = reply_map - if getattr(self._device, 'persister', - None) and self.name not in self._device.persister: + if getattr(self._device, 'persister', None) and self.name not in self._device.persister: # Don't update the persister if it already has a value, # otherwise the first read might overwrite the value we wanted. self._device.persister[self.name] = self._value @@ -369,15 +333,13 @@ class BitFieldSetting(Setting): assert key is not None if _log.isEnabledFor(_DEBUG): - _log.debug('%s: settings read %r key %r from %s', self.name, - self._value, key, self._device) + _log.debug('%s: settings read %r key %r from %s', self.name, self._value, key, self._device) if self._value is None and getattr(self._device, 'persister', None): self._value = self._device.persister.get(self.name) if cached and self._value is not None: - if getattr(self._device, 'persister', - None) and self.name not in self._device.persister: + if getattr(self._device, 'persister', None) and self.name not in self._device.persister: self._device.persister[self.name] = self._value return self._value[str(int(key))] @@ -385,8 +347,7 @@ class BitFieldSetting(Setting): reply = self._rw.read(self._device, key) if reply: self._value = self._validator.validate_read(reply) - if getattr(self._device, 'persister', - None) and self.name not in self._device.persister: + if getattr(self._device, 'persister', None) and self.name not in self._device.persister: self._device.persister[self.name] = self._value return self._value[str(int(key))] @@ -396,8 +357,7 @@ class BitFieldSetting(Setting): assert map is not None if _log.isEnabledFor(_DEBUG): - _log.debug('%s: settings write %r to %s', self.name, map, - self._device) + _log.debug('%s: settings write %r to %s', self.name, map, self._device) if self._device.online: # Remember the value we're trying to set, even if the write fails. @@ -409,8 +369,7 @@ class BitFieldSetting(Setting): data_bytes = self._validator.prepare_write(self._value) if data_bytes is not None: if _log.isEnabledFor(_DEBUG): - _log.debug('%s: settings prepare map write(%s) => %r', - self.name, self._value, data_bytes) + _log.debug('%s: settings prepare map write(%s) => %r', self.name, self._value, data_bytes) reply = self._rw.write(self._device, data_bytes) if not reply: return None @@ -423,8 +382,7 @@ class BitFieldSetting(Setting): assert value is not None if _log.isEnabledFor(_DEBUG): - _log.debug('%s: settings write key %r value %r to %s', self.name, - key, value, self._device) + _log.debug('%s: settings write key %r value %r to %s', self.name, key, value, self._device) if self._device.online: # Remember the value we're trying to set, even if the write fails. @@ -438,9 +396,7 @@ class BitFieldSetting(Setting): data_bytes = self._validator.prepare_write(self._value) if data_bytes is not None: if _log.isEnabledFor(_DEBUG): - _log.debug( - '%s: settings prepare key value write(%s,%s) => %r', - self.name, key, str(value), data_bytes) + _log.debug('%s: settings prepare key value write(%s,%s) => %r', self.name, key, str(value), data_bytes) reply = self._rw.write(self._device, data_bytes) if not reply: # tell whomever is calling that the write failed @@ -477,10 +433,7 @@ class FeatureRW(object): default_read_fnid = 0x00 default_write_fnid = 0x10 - def __init__(self, - feature, - read_fnid=default_read_fnid, - write_fnid=default_write_fnid): + def __init__(self, feature, read_fnid=default_read_fnid, write_fnid=default_write_fnid): assert isinstance(feature, _NamedInt) self.feature = feature self.read_fnid = read_fnid @@ -492,8 +445,7 @@ class FeatureRW(object): def write(self, device, data_bytes): assert self.feature is not None - return device.feature_request(self.feature, self.write_fnid, - data_bytes) + return device.feature_request(self.feature, self.write_fnid, data_bytes) class FeatureRWMap(FeatureRW): @@ -502,11 +454,7 @@ class FeatureRWMap(FeatureRW): default_write_fnid = 0x10 default_key_bytes = 1 - def __init__(self, - feature, - read_fnid=default_read_fnid, - write_fnid=default_write_fnid, - key_bytes=default_key_bytes): + def __init__(self, feature, read_fnid=default_read_fnid, write_fnid=default_write_fnid, key_bytes=default_key_bytes): assert isinstance(feature, _NamedInt) self.feature = feature self.read_fnid = read_fnid @@ -521,8 +469,7 @@ class FeatureRWMap(FeatureRW): def write(self, device, key, data_bytes): assert self.feature is not None key_bytes = _int2bytes(key, self.key_bytes) - return device.feature_request(self.feature, self.write_fnid, key_bytes, - data_bytes) + return device.feature_request(self.feature, self.write_fnid, key_bytes, data_bytes) # @@ -540,10 +487,7 @@ class BooleanValidator(object): # mask specifies all the affected bits in the value default_mask = 0xFF - def __init__(self, - true_value=default_true, - false_value=default_false, - mask=default_mask): + def __init__(self, true_value=default_true, false_value=default_false, mask=default_mask): if isinstance(true_value, int): assert isinstance(false_value, int) if mask is None: @@ -582,14 +526,12 @@ class BooleanValidator(object): if isinstance(self.mask, int): reply_value = ord(reply_bytes[:1]) & self.mask if _log.isEnabledFor(_DEBUG): - _log.debug('BooleanValidator: validate read %r => %02X', - reply_bytes, reply_value) + _log.debug('BooleanValidator: validate read %r => %02X', reply_bytes, reply_value) if reply_value == self.true_value: return True if reply_value == self.false_value: return False - _log.warn('BooleanValidator: reply %02X mismatched %02X/%02X/%02X', - reply_value, self.true_value, self.false_value, + _log.warn('BooleanValidator: reply %02X mismatched %02X/%02X/%02X', reply_value, self.true_value, self.false_value, self.mask) return False @@ -605,8 +547,7 @@ class BooleanValidator(object): if reply_value == false_value: return False - _log.warn('BooleanValidator: reply %r mismatched %r/%r/%r', - reply_bytes, self.true_value, self.false_value, self.mask) + _log.warn('BooleanValidator: reply %r mismatched %r/%r/%r', reply_bytes, self.true_value, self.false_value, self.mask) return False def prepare_write(self, new_value, current_value=None): @@ -620,8 +561,7 @@ class BooleanValidator(object): if isinstance(self.mask, int): if current_value is not None and self.needs_current_value: to_write |= ord(current_value[:1]) & (0xFF ^ self.mask) - if current_value is not None and to_write == ord( - current_value[:1]): + if current_value is not None and to_write == ord(current_value[:1]): return None else: to_write = bytearray(to_write) @@ -636,13 +576,11 @@ class BooleanValidator(object): to_write[i] = b to_write = bytes(to_write) - if current_value is not None and to_write == current_value[:len( - to_write)]: + if current_value is not None and to_write == current_value[:len(to_write)]: return None if _log.isEnabledFor(_DEBUG): - _log.debug('BooleanValidator: prepare_write(%s, %s) => %r', - new_value, current_value, to_write) + _log.debug('BooleanValidator: prepare_write(%s, %s) => %r', new_value, current_value, to_write) return to_write @@ -657,8 +595,7 @@ class BitFieldValidator(object): self.options = options self.byte_count = (max(x.bit_length() for x in options) + 7) // 8 if byte_count: - assert (isinstance(byte_count, int) - and byte_count >= self.byte_count) + assert (isinstance(byte_count, int) and byte_count >= self.byte_count) self.byte_count = byte_count def validate_read(self, reply_bytes): @@ -705,8 +642,7 @@ class ChoicesValidator(object): def validate_read(self, reply_bytes): reply_value = _bytes2int(reply_bytes[:self._bytes_count]) valid_value = self.choices[reply_value] - assert valid_value is not None, '%s: failed to validate read value %02X' % ( - self.__class__.__name__, reply_value) + assert valid_value is not None, '%s: failed to validate read value %02X' % (self.__class__.__name__, reply_value) return valid_value def prepare_write(self, new_value, current_value=None): @@ -731,12 +667,7 @@ class ChoicesValidator(object): class ChoicesMapValidator(ChoicesValidator): kind = KIND.map_choice - def __init__(self, - choices_map, - key_bytes_count=None, - skip_bytes_count=None, - value_bytes_count=None, - extra_default=None): + def __init__(self, choices_map, key_bytes_count=None, skip_bytes_count=None, value_bytes_count=None, extra_default=None): assert choices_map is not None assert isinstance(choices_map, dict) max_key_bits = 0 @@ -770,22 +701,19 @@ class ChoicesMapValidator(ChoicesValidator): # reprogrammable keys starts out as 0, which is not a choice, so don't use assert here if self.extra_default is not None and self.extra_default == reply_value: return int(self.choices[key][0]) - assert reply_value in self.choices[ - key], '%s: failed to validate read value %02X' % ( - self.__class__.__name__, reply_value) + assert reply_value in self.choices[key], '%s: failed to validate read value %02X' % (self.__class__.__name__, + reply_value) return reply_value def prepare_write(self, key, new_value): choices = self.choices[key] if new_value not in choices and new_value != self.extra_default: raise ValueError('invalid choice %r' % new_value) - return _int2bytes(new_value, - self._skip_bytes_count + self._value_bytes_count) + return _int2bytes(new_value, self._skip_bytes_count + self._value_bytes_count) class RangeValidator(object): - __slots__ = ('min_value', 'max_value', 'flag', '_bytes_count', - 'needs_current_value') + __slots__ = ('min_value', 'max_value', 'flag', '_bytes_count', 'needs_current_value') kind = KIND.range """Translates between integers and a byte sequence. @@ -807,10 +735,8 @@ class RangeValidator(object): def validate_read(self, reply_bytes): reply_value = _bytes2int(reply_bytes[:self._bytes_count]) - assert reply_value >= self.min_value, '%s: failed to validate read value %02X' % ( - self.__class__.__name__, reply_value) - assert reply_value <= self.max_value, '%s: failed to validate read value %02X' % ( - self.__class__.__name__, reply_value) + assert reply_value >= self.min_value, '%s: failed to validate read value %02X' % (self.__class__.__name__, reply_value) + assert reply_value <= self.max_value, '%s: failed to validate read value %02X' % (self.__class__.__name__, reply_value) return reply_value def prepare_write(self, new_value, current_value=None): diff --git a/lib/logitech_receiver/settings_templates.py b/lib/logitech_receiver/settings_templates.py index d870abd1..3c6682a9 100644 --- a/lib/logitech_receiver/settings_templates.py +++ b/lib/logitech_receiver/settings_templates.py @@ -65,35 +65,16 @@ def register_toggle(name, label=None, description=None, device_kind=None): - validator = _BooleanV(true_value=true_value, - false_value=false_value, - mask=mask) + validator = _BooleanV(true_value=true_value, false_value=false_value, mask=mask) rw = _RegisterRW(register) - return _Setting(name, - rw, - validator, - label=label, - description=description, - device_kind=device_kind) + return _Setting(name, rw, validator, label=label, description=description, device_kind=device_kind) -def register_choices(name, - register, - choices, - kind=_KIND.choice, - label=None, - description=None, - device_kind=None): +def register_choices(name, register, choices, kind=_KIND.choice, label=None, description=None, device_kind=None): assert choices validator = _ChoicesV(choices) rw = _RegisterRW(register) - return _Setting(name, - rw, - validator, - kind=kind, - label=label, - description=description, - device_kind=device_kind) + return _Setting(name, rw, validator, kind=kind, label=label, description=description, device_kind=device_kind) def feature_toggle(name, @@ -106,17 +87,9 @@ def feature_toggle(name, label=None, description=None, device_kind=None): - validator = _BooleanV(true_value=true_value, - false_value=false_value, - mask=mask) + validator = _BooleanV(true_value=true_value, false_value=false_value, mask=mask) rw = _FeatureRW(feature, read_function_id, write_function_id) - return _Setting(name, - rw, - validator, - feature=feature, - label=label, - description=description, - device_kind=device_kind) + return _Setting(name, rw, validator, feature=feature, label=label, description=description, device_kind=device_kind) def feature_bitfield_toggle(name, @@ -139,15 +112,14 @@ def feature_bitfield_toggle(name, device_kind=device_kind) -def feature_bitfield_toggle_dynamic( - name, - feature, - options_callback, - read_function_id=_FeatureRW.default_read_fnid, - write_function_id=_FeatureRW.default_write_fnid, - label=None, - description=None, - device_kind=None): +def feature_bitfield_toggle_dynamic(name, + feature, + options_callback, + read_function_id=_FeatureRW.default_read_fnid, + write_function_id=_FeatureRW.default_write_fnid, + label=None, + description=None, + device_kind=None): def instantiate(device): options = options_callback(device) setting = feature_bitfield_toggle(name, @@ -235,10 +207,7 @@ def feature_map_choices(name, skip_bytes_count=skip_bytes_count, value_bytes_count=value_bytes_count, extra_default=extra_default) - rw = _FeatureRWMap(feature, - read_function_id, - write_function_id, - key_bytes=key_bytes_count) + rw = _FeatureRWMap(feature, read_function_id, write_function_id, key_bytes=key_bytes_count) return _Settings(name, rw, validator, @@ -312,49 +281,33 @@ def feature_range(name, # common strings for settings - name, string to display in main window, tool tip for main window # -_HAND_DETECTION = ( - 'hand-detection', _('Hand Detection'), - _('Turn on illumination when the hands hover over the keyboard.')) -_SMOOTH_SCROLL = ( - 'smooth-scroll', _('Smooth Scrolling'), - _('High-sensitivity mode for vertical scroll with the wheel.')) -_SIDE_SCROLL = ( - 'side-scroll', _('Side Scrolling'), - _('When disabled, pushing the wheel sideways sends custom button events\n' - 'instead of the standard side-scrolling events.')) -_HI_RES_SCROLL = ( - 'hi-res-scroll', _('High Resolution Scrolling'), - _('High-sensitivity mode for vertical scroll with the wheel.')) -_LOW_RES_SCROLL = ('lowres-smooth-scroll', _('HID++ Scrolling'), - _('HID++ mode for vertical scroll with the wheel.') + '\n' + +_HAND_DETECTION = ('hand-detection', _('Hand Detection'), _('Turn on illumination when the hands hover over the keyboard.')) +_SMOOTH_SCROLL = ('smooth-scroll', _('Smooth Scrolling'), _('High-sensitivity mode for vertical scroll with the wheel.')) +_SIDE_SCROLL = ('side-scroll', _('Side Scrolling'), + _('When disabled, pushing the wheel sideways sends custom button events\n' + 'instead of the standard side-scrolling events.')) +_HI_RES_SCROLL = ('hi-res-scroll', _('High Resolution Scrolling'), + _('High-sensitivity mode for vertical scroll with the wheel.')) +_LOW_RES_SCROLL = ('lowres-smooth-scroll', _('HID++ Scrolling'), _('HID++ mode for vertical scroll with the wheel.') + '\n' + _('Effectively turns off wheel scrolling in Linux.')) _HIRES_INV = ('hires-smooth-invert', _('High Resolution Wheel Invert'), _('High-sensitivity wheel invert mode for vertical scroll.')) -_HIRES_RES = ('hires-smooth-resolution', _('Wheel Resolution'), - _('High-sensitivity mode for vertical scroll with the wheel.')) -_FN_SWAP = ( - 'fn-swap', _('Swap Fx function'), - _('When set, the F1..F12 keys will activate their special function,\n' - 'and you must hold the FN key to activate their standard function.') + - '\n\n' + - _('When unset, the F1..F12 keys will activate their standard function,\n' - 'and you must hold the FN key to activate their special function.')) +_HIRES_RES = ('hires-smooth-resolution', _('Wheel Resolution'), _('High-sensitivity mode for vertical scroll with the wheel.')) +_FN_SWAP = ('fn-swap', _('Swap Fx function'), + _('When set, the F1..F12 keys will activate their special function,\n' + 'and you must hold the FN key to activate their standard function.') + '\n\n' + + _('When unset, the F1..F12 keys will activate their standard function,\n' + 'and you must hold the FN key to activate their special function.')) _DPI = ('dpi', _('Sensitivity (DPI)'), None) _POINTER_SPEED = ('pointer_speed', _('Sensitivity (Pointer Speed)'), _('Speed multiplier for mouse (256 is normal multiplier).')) -_SMART_SHIFT = ( - 'smart-shift', _('Smart Shift'), - _('Automatically switch the mouse wheel between ratchet and freespin mode.\n' - 'The mouse wheel is always free at 0, and always locked at 50')) -_BACKLIGHT = ('backlight', _('Backlight'), - _('Turn illumination on or off on keyboard.')) -_REPROGRAMMABLE_KEYS = ('reprogrammable-keys', _( - 'Actions' -), _('Change the action for the key or button.') + '\n' + _( - 'Changing important actions (such as for the left mouse button) can result in an unusable system.' -)) -_DISABLE_KEYS = ('disable-keyboard-keys', _('Disable keys'), - _('Disable specific keyboard keys.')) +_SMART_SHIFT = ('smart-shift', _('Smart Shift'), + _('Automatically switch the mouse wheel between ratchet and freespin mode.\n' + 'The mouse wheel is always free at 0, and always locked at 50')) +_BACKLIGHT = ('backlight', _('Backlight'), _('Turn illumination on or off on keyboard.')) +_REPROGRAMMABLE_KEYS = ('reprogrammable-keys', _('Actions'), _('Change the action for the key or button.') + '\n' + + _('Changing important actions (such as for the left mouse button) can result in an unusable system.')) +_DISABLE_KEYS = ('disable-keyboard-keys', _('Disable keys'), _('Disable specific keyboard keys.')) # # @@ -374,9 +327,7 @@ def _register_hand_detection(register=_R.keyboard_hand_detection, device_kind=(_DK.keyboard, )) -def _register_fn_swap(register=_R.keyboard_fn_swap, - true_value=b'\x00\x01', - mask=b'\x00\x01'): +def _register_fn_swap(register=_R.keyboard_fn_swap, true_value=b'\x00\x01', mask=b'\x00\x01'): return register_toggle(_FN_SWAP[0], register, true_value=true_value, @@ -386,9 +337,7 @@ def _register_fn_swap(register=_R.keyboard_fn_swap, device_kind=(_DK.keyboard, )) -def _register_smooth_scroll(register=_R.mouse_button_flags, - true_value=0x40, - mask=0x40): +def _register_smooth_scroll(register=_R.mouse_button_flags, true_value=0x40, mask=0x40): return register_toggle(_SMOOTH_SCROLL[0], register, true_value=true_value, @@ -398,9 +347,7 @@ def _register_smooth_scroll(register=_R.mouse_button_flags, device_kind=(_DK.mouse, _DK.trackball)) -def _register_side_scroll(register=_R.mouse_button_flags, - true_value=0x02, - mask=0x02): +def _register_side_scroll(register=_R.mouse_button_flags, true_value=0x02, mask=0x02): return register_toggle(_SIDE_SCROLL[0], register, true_value=true_value, @@ -525,8 +472,7 @@ def _feature_smart_shift(): if threshold == _MAX_SMART_SHIFT_VALUE: threshold = 255 - data = _int2bytes(mode, - count=1) + _int2bytes(threshold, count=1) * 2 + data = _int2bytes(mode, count=1) + _int2bytes(threshold, count=1) * 2 return super(_SmartShiftRW, self).write(device, data) return feature_range(_SMART_SHIFT[0], @@ -607,20 +553,15 @@ def _feature_reprogrammable_keys_choices(device): choices = {} for i in range(0, count): # get the data for each key record on device keydata = device.feature_request(_F.REPROG_CONTROLS_V4, 0x10, i) - key, key_task, flags, pos, group, gmask = _unpack( - '!HHBBBB', keydata[:8]) + key, key_task, flags, pos, group, gmask = _unpack('!HHBBBB', keydata[:8]) action = _NamedInt(key, str(_special_keys.TASK[key_task])) keys[i] = (_special_keys.CONTROL[key], action, flags, gmask) groups[group].append(action) for k in keys: # if k[2] & _special_keys.KEY_FLAG.reprogrammable: # this flag is only to show in UI, ignore in Solaar if k[3]: # only keys with a non-zero gmask are remappable - key_choices = [ - k[1] - ] # it should always be possible to map the key to itself - for g in range( - 1, 9 - ): # group 0 and gmask 0 (k[3]) does not indicate remappability so don't consider group 0 + key_choices = [k[1]] # it should always be possible to map the key to itself + for g in range(1, 9): # group 0 and gmask 0 (k[3]) does not indicate remappability so don't consider group 0 if (k[3] == 0 if g == 0 else k[3] & 2**(g - 1)): for gm in groups[g]: if int(gm) != int(k[0]): # don't put itself in twice @@ -647,22 +588,19 @@ def _feature_reprogrammable_keys(): def _feature_disable_keyboard_keys_key_list(device): mask = device.feature_request(_F.KEYBOARD_DISABLE_KEYS)[0] - options = [ - _special_keys.DISABLE[1 << i] for i in range(8) if mask & (1 << i) - ] + options = [_special_keys.DISABLE[1 << i] for i in range(8) if mask & (1 << i)] return options def _feature_disable_keyboard_keys(): - return feature_bitfield_toggle_dynamic( - _DISABLE_KEYS[0], - _F.KEYBOARD_DISABLE_KEYS, - _feature_disable_keyboard_keys_key_list, - read_function_id=0x10, - write_function_id=0x20, - label=_DISABLE_KEYS[1], - description=_DISABLE_KEYS[2], - device_kind=(_DK.keyboard, )) + return feature_bitfield_toggle_dynamic(_DISABLE_KEYS[0], + _F.KEYBOARD_DISABLE_KEYS, + _feature_disable_keyboard_keys_key_list, + read_function_id=0x10, + write_function_id=0x20, + label=_DISABLE_KEYS[1], + description=_DISABLE_KEYS[2], + device_kind=(_DK.keyboard, )) # @@ -671,8 +609,7 @@ def _feature_disable_keyboard_keys(): def _S(name, featureID=None, featureFn=None, registerFn=None, identifier=None): - return (name, featureID, featureFn, registerFn, - identifier if identifier else name.replace('-', '_')) + return (name, featureID, featureFn, registerFn, identifier if identifier else name.replace('-', '_')) _SETTINGS_TABLE = [ @@ -683,29 +620,15 @@ _SETTINGS_TABLE = [ _S(_LOW_RES_SCROLL[0], _F.LOWRES_WHEEL, _feature_lowres_smooth_scroll), _S(_HIRES_INV[0], _F.HIRES_WHEEL, _feature_hires_smooth_invert), _S(_HIRES_RES[0], _F.HIRES_WHEEL, _feature_hires_smooth_resolution), - _S(_FN_SWAP[0], - _F.FN_INVERSION, - _feature_fn_swap, - registerFn=_register_fn_swap), - _S(_FN_SWAP[0], - _F.NEW_FN_INVERSION, - _feature_new_fn_swap, - identifier='new_fn_swap'), - _S(_FN_SWAP[0], - _F.K375S_FN_INVERSION, - _feature_k375s_fn_swap, - identifier='k375s_fn_swap'), - _S(_DPI[0], - _F.ADJUSTABLE_DPI, - _feature_adjustable_dpi, - registerFn=_register_dpi), + _S(_FN_SWAP[0], _F.FN_INVERSION, _feature_fn_swap, registerFn=_register_fn_swap), + _S(_FN_SWAP[0], _F.NEW_FN_INVERSION, _feature_new_fn_swap, identifier='new_fn_swap'), + _S(_FN_SWAP[0], _F.K375S_FN_INVERSION, _feature_k375s_fn_swap, identifier='k375s_fn_swap'), + _S(_DPI[0], _F.ADJUSTABLE_DPI, _feature_adjustable_dpi, registerFn=_register_dpi), _S(_POINTER_SPEED[0], _F.POINTER_SPEED, _feature_pointer_speed), _S(_SMART_SHIFT[0], _F.SMART_SHIFT, _feature_smart_shift), _S(_BACKLIGHT[0], _F.BACKLIGHT2, _feature_backlight2), - _S(_REPROGRAMMABLE_KEYS[0], _F.REPROG_CONTROLS_V4, - _feature_reprogrammable_keys), - _S(_DISABLE_KEYS[0], _F.KEYBOARD_DISABLE_KEYS, - _feature_disable_keyboard_keys), + _S(_REPROGRAMMABLE_KEYS[0], _F.REPROG_CONTROLS_V4, _feature_reprogrammable_keys), + _S(_DISABLE_KEYS[0], _F.KEYBOARD_DISABLE_KEYS, _feature_disable_keyboard_keys), ] _SETTINGS_LIST = namedtuple('_SETTINGS_LIST', [s[4] for s in _SETTINGS_TABLE]) @@ -741,13 +664,11 @@ def check_feature_settings(device, already_known): try: detected = featureFn()(device) if _log.isEnabledFor(_DEBUG): - _log.debug('check_feature[%s] detected %s', featureId, - detected) + _log.debug('check_feature[%s] detected %s', featureId, detected) if detected: already_known.append(detected) except Exception as reason: - _log.error('check_feature[%s] inconsistent feature %s', featureId, - reason) + _log.error('check_feature[%s] inconsistent feature %s', featureId, reason) for name, featureId, featureFn, __, __ in _SETTINGS_TABLE: if featureId and featureFn: diff --git a/lib/logitech_receiver/special_keys.py b/lib/logitech_receiver/special_keys.py index 780b49b9..7ed34ee5 100644 --- a/lib/logitech_receiver/special_keys.py +++ b/lib/logitech_receiver/special_keys.py @@ -67,8 +67,7 @@ CONTROL = _NamedInts( MINIMIZE_AS_WIN_M=0x0027, MEDIA_PLAYER=0x0028, MEDIA_CENTER_LOGI=0x0029, - MEDIA_CENTER_MSFT= - 0x002A, # Should not be used as it is not reprogrammable under Windows + MEDIA_CENTER_MSFT=0x002A, # Should not be used as it is not reprogrammable under Windows CUSTOM_MENU=0x002B, MESSENGER=0x002C, MY_DOCUMENTS=0x002D, @@ -237,8 +236,7 @@ CONTROL = _NamedInts( F_Lock=0x00DE, Switch_Highlight=0x00DF, Mission_Control__Task_View=0x00E0, # Switch_Workspaces on Craft Keyboard - Dashboard_Launchpad__Action_Center= - 0x00E1, # Application_Launcher on Craft Keyboard + Dashboard_Launchpad__Action_Center=0x00E1, # Application_Launcher on Craft Keyboard Backlight_Down=0x00E2, Backlight_Up=0x00E3, Previous_Fn=0x00E4, # Reprogrammable_Previous_Track / on Craft Keyboard @@ -463,8 +461,7 @@ TASK = _NamedInts( Fast_Backward=0x00BD, Switch_Highlighting=0x00BE, Mission_Control__Task_View=0x00BF, # Switch_Workspace on Craft Keyboard - Dashboard_Launchpad__Action_Center= - 0x00C0, # Application_Launcher on Craft Keyboard + Dashboard_Launchpad__Action_Center=0x00C0, # Application_Launcher on Craft Keyboard Backlight_Down=0x00C1, # Backlight_Down_FW_internal_function Backlight_Up=0x00C2, # Backlight_Up_FW_internal_function Right_Click__App_Contextual_Menu=0x00C3, # Context_Menu on Craft Keyboard diff --git a/lib/logitech_receiver/status.py b/lib/logitech_receiver/status.py index 872b2907..27d21d7d 100644 --- a/lib/logitech_receiver/status.py +++ b/lib/logitech_receiver/status.py @@ -38,11 +38,7 @@ _R = _hidpp10.REGISTERS # # -ALERT = _NamedInts(NONE=0x00, - NOTIFICATION=0x01, - SHOW_WINDOW=0x02, - ATTENTION=0x04, - ALL=0xFF) +ALERT = _NamedInts(NONE=0x00, NOTIFICATION=0x01, SHOW_WINDOW=0x02, ATTENTION=0x04, ALL=0xFF) KEYS = _NamedInts( BATTERY_LEVEL=1, @@ -106,10 +102,10 @@ class ReceiverStatus(dict): def __str__(self): count = len(self._receiver) - return (_('No paired devices.') if count == 0 else ngettext( - '%(count)s paired device.', '%(count)s paired devices.', count) % { - 'count': count - }) + return (_('No paired devices.') + if count == 0 else ngettext('%(count)s paired device.', '%(count)s paired devices.', count) % { + 'count': count + }) __unicode__ = __str__ @@ -161,13 +157,9 @@ class DeviceStatus(dict): battery_level = self.get(KEYS.BATTERY_LEVEL) if battery_level is not None: if isinstance(battery_level, _NamedInt): - yield _('Battery: %(level)s') % { - 'level': _(str(battery_level)) - } + yield _('Battery: %(level)s') % {'level': _(str(battery_level))} else: - yield _('Battery: %(percent)d%%') % { - 'percent': battery_level - } + yield _('Battery: %(percent)d%%') % {'percent': battery_level} battery_status = self.get(KEYS.BATTERY_STATUS) if battery_status is not None: @@ -184,20 +176,14 @@ class DeviceStatus(dict): return ''.join(i for i in _items()) def __repr__(self): - return '{' + ', '.join('\'%s\': %r' % (k, v) - for k, v in self.items()) + '}' + return '{' + ', '.join('\'%s\': %r' % (k, v) for k, v in self.items()) + '}' def __bool__(self): return bool(self._active) __nonzero__ = __bool__ - def set_battery_info(self, - level, - status, - nextLevel=None, - voltage=None, - timestamp=None): + def set_battery_info(self, level, status, nextLevel=None, voltage=None, timestamp=None): if _log.isEnabledFor(_DEBUG): _log.debug('%s: battery %s, %s', self._device, level, status) @@ -207,8 +193,7 @@ class DeviceStatus(dict): # It is not always possible to do this well if status == _hidpp20.BATTERY_STATUS.full: level = _hidpp10.BATTERY_APPOX.full - elif status in (_hidpp20.BATTERY_STATUS.almost_full, - _hidpp20.BATTERY_STATUS.recharging): + elif status in (_hidpp20.BATTERY_STATUS.almost_full, _hidpp20.BATTERY_STATUS.recharging): level = _hidpp10.BATTERY_APPOX.good elif status == _hidpp20.BATTERY_STATUS.slow_recharge: level = _hidpp10.BATTERY_APPOX.low @@ -218,55 +203,36 @@ class DeviceStatus(dict): assert isinstance(level, int) # TODO: this is also executed when pressing Fn+F7 on K800. - old_level, self[KEYS.BATTERY_LEVEL] = self.get( - KEYS.BATTERY_LEVEL), level - old_status, self[KEYS.BATTERY_STATUS] = self.get( - KEYS.BATTERY_STATUS), status + old_level, self[KEYS.BATTERY_LEVEL] = self.get(KEYS.BATTERY_LEVEL), level + old_status, self[KEYS.BATTERY_STATUS] = self.get(KEYS.BATTERY_STATUS), status self[KEYS.BATTERY_NEXT_LEVEL] = nextLevel if voltage is not None: self[KEYS.BATTERY_VOLTAGE] = voltage - charging = status in (_hidpp20.BATTERY_STATUS.recharging, - _hidpp20.BATTERY_STATUS.almost_full, - _hidpp20.BATTERY_STATUS.full, - _hidpp20.BATTERY_STATUS.slow_recharge) - old_charging, self[KEYS.BATTERY_CHARGING] = self.get( - KEYS.BATTERY_CHARGING), charging + charging = status in (_hidpp20.BATTERY_STATUS.recharging, _hidpp20.BATTERY_STATUS.almost_full, + _hidpp20.BATTERY_STATUS.full, _hidpp20.BATTERY_STATUS.slow_recharge) + old_charging, self[KEYS.BATTERY_CHARGING] = self.get(KEYS.BATTERY_CHARGING), charging changed = old_level != level or old_status != status or old_charging != charging alert, reason = ALERT.NONE, None - if _hidpp20.BATTERY_OK(status) and (level is None or - level > _BATTERY_ATTENTION_LEVEL): + if _hidpp20.BATTERY_OK(status) and (level is None or level > _BATTERY_ATTENTION_LEVEL): self[KEYS.ERROR] = None else: - _log.warn('%s: battery %d%%, ALERT %s', self._device, level, - status) + _log.warn('%s: battery %d%%, ALERT %s', self._device, level, status) if self.get(KEYS.ERROR) != status: self[KEYS.ERROR] = status # only show the notification once alert = ALERT.NOTIFICATION | ALERT.ATTENTION if isinstance(level, _NamedInt): - reason = _('Battery: %(level)s (%(status)s)') % { - 'level': _(level), - 'status': _(status) - } + reason = _('Battery: %(level)s (%(status)s)') % {'level': _(level), 'status': _(status)} else: - reason = _('Battery: %(percent)d%% (%(status)s)') % { - 'percent': level, - 'status': status.name - } + reason = _('Battery: %(percent)d%% (%(status)s)') % {'percent': level, 'status': status.name} if changed or reason: # update the leds on the device, if any - _hidpp10.set_3leds(self._device, - level, - charging=charging, - warning=bool(alert)) - self.changed(active=True, - alert=alert, - reason=reason, - timestamp=timestamp) + _hidpp10.set_3leds(self._device, level, charging=charging, warning=bool(alert)) + self.changed(active=True, alert=alert, reason=reason, timestamp=timestamp) # Retrieve and regularize battery status def read_battery(self, timestamp=None): @@ -305,11 +271,7 @@ class DeviceStatus(dict): self[KEYS.BATTERY_CHARGING] = None self.changed() - def changed(self, - active=None, - alert=ALERT.NONE, - reason=None, - timestamp=None): + def changed(self, active=None, alert=ALERT.NONE, reason=None, timestamp=None): assert self._changed_callback d = self._device # assert d # may be invalid when processing the 'unpaired' notification @@ -324,8 +286,7 @@ class DeviceStatus(dict): # get cleared when the device is turned off (but not when the device # goes idle, and we can't tell the difference right now). if d.protocol < 2.0: - self[KEYS.NOTIFICATION_FLAGS] = d.enable_notifications( - ) + self[KEYS.NOTIFICATION_FLAGS] = d.enable_notifications() # If we've been inactive for a long time, forget anything # about the battery. @@ -337,8 +298,7 @@ class DeviceStatus(dict): # Devices lose configuration when they are turned off, # make sure they're up-to-date. if _log.isEnabledFor(_DEBUG): - _log.debug('%s pushing device settings %s', d, - d.settings) + _log.debug('%s pushing device settings %s', d, d.settings) for s in d.settings: s.apply() diff --git a/lib/solaar/cli/__init__.py b/lib/solaar/cli/__init__.py index bb66d4ce..faed4756 100644 --- a/lib/solaar/cli/__init__.py +++ b/lib/solaar/cli/__init__.py @@ -36,65 +36,43 @@ del getLogger def _create_parser(): - parser = _argparse.ArgumentParser( - prog=NAME.lower(), - add_help=False, - epilog='For details on individual actions, run `%s --help`.' % - NAME.lower()) - subparsers = parser.add_subparsers(title='actions', - help='optional action to perform') + parser = _argparse.ArgumentParser(prog=NAME.lower(), + add_help=False, + epilog='For details on individual actions, run `%s --help`.' % NAME.lower()) + subparsers = parser.add_subparsers(title='actions', help='optional action to perform') sp = subparsers.add_parser('show', help='show information about devices') - sp.add_argument( - 'device', - nargs='?', - default='all', - help= - 'device to show information about; may be a device number (1..6), a serial, ' - 'a substring of a device\'s name, or "all" (the default)') + sp.add_argument('device', + nargs='?', + default='all', + help='device to show information about; may be a device number (1..6), a serial, ' + 'a substring of a device\'s name, or "all" (the default)') sp.set_defaults(action='show') - sp = subparsers.add_parser('probe', - help='probe a receiver (debugging use only)') - sp.add_argument( - 'receiver', - nargs='?', - help='select a certain receiver when more than one is present') + sp = subparsers.add_parser('probe', help='probe a receiver (debugging use only)') + sp.add_argument('receiver', nargs='?', help='select a certain receiver when more than one is present') sp.set_defaults(action='probe') - sp = subparsers.add_parser( - 'config', - help='read/write device-specific settings', - epilog='Please note that configuration only works on active devices.') - sp.add_argument( - 'device', - help= - 'device to configure; may be a device number (1..6), a device serial, ' - 'or at least 3 characters of a device\'s name') - sp.add_argument( - 'setting', - nargs='?', - help='device-specific setting; leave empty to list available settings') + sp = subparsers.add_parser('config', + help='read/write device-specific settings', + epilog='Please note that configuration only works on active devices.') + sp.add_argument('device', + help='device to configure; may be a device number (1..6), a device serial, ' + 'or at least 3 characters of a device\'s name') + sp.add_argument('setting', nargs='?', help='device-specific setting; leave empty to list available settings') sp.add_argument('value', nargs='?', help='new value for the setting') sp.set_defaults(action='config') - sp = subparsers.add_parser( - 'pair', - help='pair a new device', - epilog= - 'The Logitech Unifying Receiver supports up to 6 paired devices at the same time.' - ) - sp.add_argument( - 'receiver', - nargs='?', - help='select a certain receiver when more than one is present') + sp = subparsers.add_parser('pair', + help='pair a new device', + epilog='The Logitech Unifying Receiver supports up to 6 paired devices at the same time.') + sp.add_argument('receiver', nargs='?', help='select a certain receiver when more than one is present') sp.set_defaults(action='pair') sp = subparsers.add_parser('unpair', help='unpair a device') - sp.add_argument( - 'device', - help='device to unpair; may be a device number (1..6), a serial, ' - 'or a substring of a device\'s name.') + sp.add_argument('device', + help='device to unpair; may be a device number (1..6), a serial, ' + 'or a substring of a device\'s name.') sp.set_defaults(action='unpair') return parser, subparsers.choices @@ -126,8 +104,7 @@ def _find_receiver(receivers, name): assert name for r in receivers: - if name in r.name.lower() or (r.serial is not None - and name == r.serial.lower()): + if name in r.name.lower() or (r.serial is not None and name == r.serial.lower()): return r @@ -153,8 +130,7 @@ def _find_device(receivers, name): return dev for dev in r: - if (name == dev.serial.lower() or name == dev.codename.lower() - or name == str(dev.kind).lower() + if (name == dev.serial.lower() or name == dev.codename.lower() or name == str(dev.kind).lower() or name in dev.name.lower()): return dev diff --git a/lib/solaar/cli/config.py b/lib/solaar/cli/config.py index 5eed1351..238930dd 100644 --- a/lib/solaar/cli/config.py +++ b/lib/solaar/cli/config.py @@ -29,11 +29,9 @@ def _print_setting(s, verbose=True): if s.description: print('#', s.description.replace('\n', ' ')) if s.kind == _settings.KIND.toggle: - print( - '# possible values: on/true/t/yes/y/1 or off/false/f/no/n/0') + print('# possible values: on/true/t/yes/y/1 or off/false/f/no/n/0') elif s.choices: - print('# possible values: one of [', - ', '.join(str(v) for v in s.choices), + print('# possible values: one of [', ', '.join(str(v) for v in s.choices), '], or higher/lower/highest/max/lowest/min') else: # wtf? @@ -90,8 +88,7 @@ def run(receivers, args, find_receiver, find_device): elif value.lower() in ('false', 'no', 'off', 'f', 'n'): value = False else: - raise Exception("don't know how to interpret '%s' as boolean" % - value) + raise Exception("don't know how to interpret '%s' as boolean" % value) elif setting.choices: value = args.value.lower() @@ -99,25 +96,20 @@ def run(receivers, args, find_receiver, find_device): if value in ('higher', 'lower'): old_value = setting.read() if old_value is None: - raise Exception("could not read current value of '%s'" % - setting.name) + raise Exception("could not read current value of '%s'" % setting.name) if value == 'lower': lower_values = setting.choices[:old_value] - value = lower_values[ - -1] if lower_values else setting.choices[:][0] + value = lower_values[-1] if lower_values else setting.choices[:][0] elif value == 'higher': higher_values = setting.choices[old_value + 1:] - value = higher_values[ - 0] if higher_values else setting.choices[:][-1] + value = higher_values[0] if higher_values else setting.choices[:][-1] elif value in ('highest', 'max'): value = setting.choices[:][-1] elif value in ('lowest', 'min'): value = setting.choices[:][0] elif value not in setting.choices: - raise Exception( - "possible values for '%s' are: [%s]" % - (setting.name, ', '.join(str(v) for v in setting.choices))) + raise Exception("possible values for '%s' are: [%s]" % (setting.name, ', '.join(str(v) for v in setting.choices))) value = setting.choices[value] elif setting.kind == _settings.KIND.range: @@ -131,6 +123,5 @@ def run(receivers, args, find_receiver, find_device): result = setting.write(value) if result is None: - raise Exception("failed to set '%s' = '%s' [%r]" % - (setting.name, str(value), value)) + raise Exception("failed to set '%s' = '%s' [%r]" % (setting.name, str(value), value)) _print_setting(setting, False) diff --git a/lib/solaar/cli/pair.py b/lib/solaar/cli/pair.py index 69ca7285..24bbeace 100644 --- a/lib/solaar/cli/pair.py +++ b/lib/solaar/cli/pair.py @@ -39,15 +39,12 @@ def run(receivers, args, find_receiver, _ignore): receiver = receivers[0] assert receiver - receiver.status = _status.ReceiverStatus(receiver, - lambda *args, **kwargs: None) + receiver.status = _status.ReceiverStatus(receiver, lambda *args, **kwargs: None) # check if it's necessary to set the notification flags old_notification_flags = _hidpp10.get_notification_flags(receiver) or 0 if not (old_notification_flags & _hidpp10.NOTIFICATION_FLAG.wireless): - _hidpp10.set_notification_flags( - receiver, - old_notification_flags | _hidpp10.NOTIFICATION_FLAG.wireless) + _hidpp10.set_notification_flags(receiver, old_notification_flags | _hidpp10.NOTIFICATION_FLAG.wireless) # get all current devices known_devices = [dev.number for dev in receiver] @@ -61,17 +58,14 @@ def run(receivers, args, find_receiver, _ignore): if n.devnumber not in known_devices: receiver.status.new_device = receiver[n.devnumber] elif receiver.re_pairs: - del receiver[ - n. - devnumber] # get rid of information on device re-paired away + del receiver[n.devnumber] # get rid of information on device re-paired away receiver.status.new_device = receiver[n.devnumber] timeout = 20 # seconds receiver.handle = _HandleWithNotificationHook(receiver.handle) receiver.set_lock(False, timeout=timeout) - print('Pairing: turn your new device on (timing out in', timeout, - 'seconds).') + print('Pairing: turn your new device on (timing out in', timeout, 'seconds).') # the lock-open notification may come slightly later, wait for it a bit pairing_start = _timestamp() @@ -91,8 +85,7 @@ def run(receivers, args, find_receiver, _ignore): if receiver.status.new_device: dev = receiver.status.new_device - print('Paired device %d: %s (%s) [%s:%s]' % - (dev.number, dev.name, dev.codename, dev.wpid, dev.serial)) + print('Paired device %d: %s (%s) [%s:%s]' % (dev.number, dev.name, dev.codename, dev.wpid, dev.serial)) else: error = receiver.status.get(_status.KEYS.ERROR) if error: diff --git a/lib/solaar/cli/probe.py b/lib/solaar/cli/probe.py index 2cf4391c..75f99123 100644 --- a/lib/solaar/cli/probe.py +++ b/lib/solaar/cli/probe.py @@ -43,32 +43,24 @@ def run(receivers, args, find_receiver, _ignore): print(' Register Dump') register = receiver.read_register(_R.notifications) - print(' Notification Register %#04x: %s' % - (_R.notifications % 0x100, - '0x' + _strhex(register) if register else 'None')) + print(' Notification Register %#04x: %s' % (_R.notifications % 0x100, '0x' + _strhex(register) if register else 'None')) register = receiver.read_register(_R.receiver_connection) print(' Connection State %#04x: %s' % - (_R.receiver_connection % 0x100, - '0x' + _strhex(register) if register else 'None')) + (_R.receiver_connection % 0x100, '0x' + _strhex(register) if register else 'None')) register = receiver.read_register(_R.devices_activity) print(' Device Activity %#04x: %s' % - (_R.devices_activity % 0x100, - '0x' + _strhex(register) if register else 'None')) + (_R.devices_activity % 0x100, '0x' + _strhex(register) if register else 'None')) for device in range(0, 6): for sub_reg in [0x0, 0x10, 0x20, 0x30]: - register = receiver.read_register(_R.receiver_info, - sub_reg + device) + register = receiver.read_register(_R.receiver_info, sub_reg + device) print(' Pairing Register %#04x %#04x: %s' % - (_R.receiver_info % 0x100, sub_reg + device, - '0x' + _strhex(register) if register else 'None')) + (_R.receiver_info % 0x100, sub_reg + device, '0x' + _strhex(register) if register else 'None')) register = receiver.read_register(_R.receiver_info, 0x40 + device) print(' Pairing Name %#04x %#02x: %s' % - (_R.receiver_info % 0x100, 0x40 + device, - register[2:2 + ord(register[1:2])] if register else 'None')) + (_R.receiver_info % 0x100, 0x40 + device, register[2:2 + ord(register[1:2])] if register else 'None')) for sub_reg in range(0, 5): register = receiver.read_register(_R.firmware, sub_reg) print(' Firmware %#04x %#04x: %s' % - (_R.firmware % 0x100, sub_reg, - '0x' + _strhex(register) if register else 'None')) + (_R.firmware % 0x100, sub_reg, '0x' + _strhex(register) if register else 'None')) diff --git a/lib/solaar/cli/show.py b/lib/solaar/cli/show.py index 2151d58b..948b272a 100644 --- a/lib/solaar/cli/show.py +++ b/lib/solaar/cli/show.py @@ -37,28 +37,22 @@ def _print_receiver(receiver): for f in receiver.firmware: print(' %-11s: %s' % (f.kind, f.version)) - print(' Has', paired_count, - 'paired device(s) out of a maximum of %d.' % receiver.max_devices) + print(' Has', paired_count, 'paired device(s) out of a maximum of %d.' % receiver.max_devices) if receiver.remaining_pairings() and receiver.remaining_pairings() >= 0: - print(' Has %d successful pairing(s) remaining.' % - receiver.remaining_pairings()) + print(' Has %d successful pairing(s) remaining.' % receiver.remaining_pairings()) notification_flags = _hidpp10.get_notification_flags(receiver) if notification_flags is not None: if notification_flags: - notification_names = _hidpp10.NOTIFICATION_FLAG.flag_names( - notification_flags) - print(' Notifications: %s (0x%06X)' % - (', '.join(notification_names), notification_flags)) + notification_names = _hidpp10.NOTIFICATION_FLAG.flag_names(notification_flags) + print(' Notifications: %s (0x%06X)' % (', '.join(notification_names), notification_flags)) else: print(' Notifications: (none)') activity = receiver.read_register(_hidpp10.REGISTERS.devices_activity) if activity: - activity = [(d, ord(activity[d - 1:d])) - for d in range(1, receiver.max_devices)] - activity_text = ', '.join( - ('%d=%d' % (d, a)) for d, a in activity if a > 0) + activity = [(d, ord(activity[d - 1:d])) for d in range(1, receiver.max_devices)] + activity_text = ', '.join(('%d=%d' % (d, a)) for d, a in activity if a > 0) print(' Device activity counters:', activity_text or '(empty)') @@ -85,26 +79,21 @@ def _print_device(dev): else: print(' Protocol : unknown (device is offline)') if dev.polling_rate: - print(' Polling rate :', dev.polling_rate, - 'ms (%dHz)' % (1000 // dev.polling_rate)) + print(' Polling rate :', dev.polling_rate, 'ms (%dHz)' % (1000 // dev.polling_rate)) print(' Serial number:', dev.serial) if dev.firmware: for fw in dev.firmware: - print(' %11s:' % fw.kind, - (fw.name + ' ' + fw.version).strip()) + print(' %11s:' % fw.kind, (fw.name + ' ' + fw.version).strip()) if dev.power_switch_location: - print(' The power switch is located on the %s.' % - dev.power_switch_location) + print(' The power switch is located on the %s.' % dev.power_switch_location) if dev.online: notification_flags = _hidpp10.get_notification_flags(dev) if notification_flags is not None: if notification_flags: - notification_names = _hidpp10.NOTIFICATION_FLAG.flag_names( - notification_flags) - print(' Notifications: %s (0x%06X).' % - (', '.join(notification_names), notification_flags)) + notification_names = _hidpp10.NOTIFICATION_FLAG.flag_names(notification_flags) + print(' Notifications: %s (0x%06X).' % (', '.join(notification_names), notification_flags)) else: print(' Notifications: (none).') @@ -118,8 +107,7 @@ def _print_device(dev): flags = dev.request(0x0000, feature.bytes(2)) flags = 0 if flags is None else ord(flags[1:2]) flags = _hidpp20.FEATURE_FLAG.flag_names(flags) - print(' %2d: %-22s {%04X} %s' % - (index, feature, feature, ', '.join(flags))) + print(' %2d: %-22s {%04X} %s' % (index, feature, feature, ', '.join(flags))) if feature == _hidpp20.FEATURE.HIRES_WHEEL: wheel = _hidpp20.get_hires_wheel(dev) if wheel: @@ -149,8 +137,7 @@ def _print_device(dev): mouse_pointer = _hidpp20.get_mouse_pointer_info(dev) if mouse_pointer: print(' DPI: %s' % mouse_pointer['dpi']) - print(' Acceleration: %s' % - mouse_pointer['acceleration']) + print(' Acceleration: %s' % mouse_pointer['acceleration']) if mouse_pointer['suggest_os_ballistics']: print(' Use OS ballistics') else: @@ -160,25 +147,19 @@ def _print_device(dev): else: print(' No vertical tuning, standard mice') if feature == _hidpp20.FEATURE.VERTICAL_SCROLLING: - vertical_scrolling_info = _hidpp20.get_vertical_scrolling_info( - dev) + vertical_scrolling_info = _hidpp20.get_vertical_scrolling_info(dev) if vertical_scrolling_info: - print(' Roller type: %s' % - vertical_scrolling_info['roller']) - print(' Ratchet per turn: %s' % - vertical_scrolling_info['ratchet']) - print(' Scroll lines: %s' % - vertical_scrolling_info['lines']) + print(' Roller type: %s' % vertical_scrolling_info['roller']) + print(' Ratchet per turn: %s' % vertical_scrolling_info['ratchet']) + print(' Scroll lines: %s' % vertical_scrolling_info['lines']) elif feature == _hidpp20.FEATURE.HI_RES_SCROLLING: - scrolling_mode, scrolling_resolution = _hidpp20.get_hi_res_scrolling_info( - dev) + scrolling_mode, scrolling_resolution = _hidpp20.get_hi_res_scrolling_info(dev) if scrolling_mode: print(' Hi-res scrolling enabled') else: print(' Hi-res scrolling disabled') if scrolling_resolution: - print(' Hi-res scrolling multiplier: %s' % - scrolling_resolution) + print(' Hi-res scrolling multiplier: %s' % scrolling_resolution) elif feature == _hidpp20.FEATURE.POINTER_SPEED: pointer_speed = _hidpp20.get_pointer_speed_info(dev) if pointer_speed: @@ -189,10 +170,8 @@ def _print_device(dev): print(' Wheel Reports: %s' % wheel_status) elif feature == _hidpp20.FEATURE.NEW_FN_INVERSION: inverted, default_inverted = _hidpp20.get_new_fn_inversion(dev) - print(' Fn-swap:', - 'enabled' if inverted else 'disabled') - print(' Fn-swap default:', - 'enabled' if default_inverted else 'disabled') + print(' Fn-swap:', 'enabled' if inverted else 'disabled') + print(' Fn-swap default:', 'enabled' if default_inverted else 'disabled') for setting in dev_settings: if setting.feature == feature: v = setting.read(False) @@ -204,13 +183,10 @@ def _print_device(dev): flags = _special_keys.KEY_FLAG.flag_names(k.flags) # TODO: add here additional variants for other REPROG_CONTROLS if dev.keys.keyversion == 1: - print(' %2d: %-26s => %-27s %s' % - (k.index, k.key, k.task, ', '.join(flags))) + print(' %2d: %-26s => %-27s %s' % (k.index, k.key, k.task, ', '.join(flags))) if dev.keys.keyversion == 4: - print(' %2d: %-26s, default: %-27s => %-26s' % - (k.index, k.key, k.task, k.remapped)) - print(' %s, pos:%d, group:%1d, gmask:%d' % - (', '.join(flags), k.pos, k.group, k.group_mask)) + print(' %2d: %-26s, default: %-27s => %-26s' % (k.index, k.key, k.task, k.remapped)) + print(' %s, pos:%d, group:%1d, gmask:%d' % (', '.join(flags), k.pos, k.group, k.group_mask)) if dev.online: battery = _hidpp20.get_battery(dev) if battery is None: @@ -218,14 +194,12 @@ def _print_device(dev): if battery is not None: level, status, nextLevel = battery text = _battery_text(level) - nextText = '' if nextLevel is None else ', next level ' + _battery_text( - nextLevel) + nextText = '' if nextLevel is None else ', next level ' + _battery_text(nextLevel) print(' Battery: %s, %s%s.' % (text, status, nextText)) else: battery_voltage = _hidpp20.get_voltage(dev) if battery_voltage: - (level, status, voltage, charge_sts, - charge_type) = battery_voltage + (level, status, voltage, charge_sts, charge_type) = battery_voltage print(' Battery: %smV, %s, %s.' % (voltage, status, level)) else: print(' Battery status unavailable.') diff --git a/lib/solaar/cli/unpair.py b/lib/solaar/cli/unpair.py index fcb6ef2d..7ec89acb 100644 --- a/lib/solaar/cli/unpair.py +++ b/lib/solaar/cli/unpair.py @@ -28,15 +28,12 @@ def run(receivers, args, find_receiver, find_device): dev = find_device(receivers, device_name) if not dev.receiver.may_unpair: - print( - 'Receiver for %s [%s:%s] does not unpair, but attempting anyway' % - (dev.name, dev.wpid, dev.serial)) + print('Receiver for %s [%s:%s] does not unpair, but attempting anyway' % (dev.name, dev.wpid, dev.serial)) try: # query these now, it's last chance to get them number, codename, wpid, serial = dev.number, dev.codename, dev.wpid, dev.serial dev.receiver._unpair_device(number, True) # force an unpair - print('Unpaired %d: %s (%s) [%s:%s]' % - (number, dev.name, codename, wpid, serial)) + print('Unpaired %d: %s (%s) [%s:%s]' % (number, dev.name, codename, wpid, serial)) except Exception as e: raise Exception('failed to unpair device %s: %s' % (dev.name, e)) diff --git a/lib/solaar/configuration.py b/lib/solaar/configuration.py index 77ec7fbf..2cb64730 100644 --- a/lib/solaar/configuration.py +++ b/lib/solaar/configuration.py @@ -31,8 +31,7 @@ from solaar import __version__ _log = getLogger(__name__) del getLogger -_XDG_CONFIG_HOME = _os.environ.get('XDG_CONFIG_HOME') or _path.expanduser( - _path.join('~', '.config')) +_XDG_CONFIG_HOME = _os.environ.get('XDG_CONFIG_HOME') or _path.expanduser(_path.join('~', '.config')) _file_path = _path.join(_XDG_CONFIG_HOME, 'solaar', 'config.json') _KEY_VERSION = '_version' @@ -78,11 +77,7 @@ def save(): try: with open(_file_path, 'w') as config_file: - _json_save(_configuration, - config_file, - skipkeys=True, - indent=2, - sort_keys=True) + _json_save(_configuration, config_file, skipkeys=True, indent=2, sort_keys=True) if _log.isEnabledFor(_INFO): _log.info('saved %s to %s', _configuration, _file_path) diff --git a/lib/solaar/gtk.py b/lib/solaar/gtk.py index d6a66e44..d5abb1ca 100755 --- a/lib/solaar/gtk.py +++ b/lib/solaar/gtk.py @@ -48,47 +48,26 @@ prefer_symbolic_battery_icons = False def _parse_arguments(): import argparse arg_parser = argparse.ArgumentParser(prog=NAME.lower()) - arg_parser.add_argument( - '-d', - '--debug', - action='count', - default=0, - help= - 'print logging messages, for debugging purposes (may be repeated for extra verbosity)' - ) - arg_parser.add_argument( - '-D', - '--hidraw', - action='store', - dest='hidraw_path', - metavar='PATH', - help= - 'unifying receiver to use; the first detected receiver if unspecified. Example: /dev/hidraw2' - ) - arg_parser.add_argument( - '--restart-on-wake-up', - action='store_true', - help='restart Solaar on sleep wake-up (experimental)') - arg_parser.add_argument( - '-w', - '--window', - choices=('show', 'hide', 'only'), - help='start with window showing / hidden / only (no tray icon)') - arg_parser.add_argument('-b', - '--battery-icons', - choices=('regular', 'symbolic'), - help='prefer regular / symbolic icons') - arg_parser.add_argument('-V', - '--version', - action='version', - version='%(prog)s ' + __version__) - arg_parser.add_argument('--help-actions', - action='store_true', - help='print help for the optional actions') - arg_parser.add_argument('action', - nargs=argparse.REMAINDER, - choices=_cli.actions, - help='optional actions to perform') + arg_parser.add_argument('-d', + '--debug', + action='count', + default=0, + help='print logging messages, for debugging purposes (may be repeated for extra verbosity)') + arg_parser.add_argument('-D', + '--hidraw', + action='store', + dest='hidraw_path', + metavar='PATH', + help='unifying receiver to use; the first detected receiver if unspecified. Example: /dev/hidraw2') + arg_parser.add_argument('--restart-on-wake-up', action='store_true', help='restart Solaar on sleep wake-up (experimental)') + arg_parser.add_argument('-w', + '--window', + choices=('show', 'hide', 'only'), + help='start with window showing / hidden / only (no tray icon)') + arg_parser.add_argument('-b', '--battery-icons', choices=('regular', 'symbolic'), help='prefer regular / symbolic icons') + arg_parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__) + arg_parser.add_argument('--help-actions', action='store_true', help='print help for the optional actions') + arg_parser.add_argument('action', nargs=argparse.REMAINDER, choices=_cli.actions, help='optional actions to perform') args = arg_parser.parse_args() @@ -106,17 +85,14 @@ def _parse_arguments(): if args.debug > 0: log_level = logging.WARNING - 10 * args.debug log_format = '%(asctime)s,%(msecs)03d %(levelname)8s [%(threadName)s] %(name)s: %(message)s' - logging.basicConfig(level=max(log_level, logging.DEBUG), - format=log_format, - datefmt='%H:%M:%S') + logging.basicConfig(level=max(log_level, logging.DEBUG), format=log_format, datefmt='%H:%M:%S') else: logging.root.addHandler(logging.NullHandler()) logging.root.setLevel(logging.ERROR) if not args.action: if logging.root.isEnabledFor(logging.INFO): - logging.info('language %s (%s), translations path %s', - _i18n.language, _i18n.encoding, _i18n.path) + logging.info('language %s (%s), translations path %s', _i18n.language, _i18n.encoding, _i18n.path) return args diff --git a/lib/solaar/i18n.py b/lib/solaar/i18n.py index c066f8bd..7cea6ba0 100644 --- a/lib/solaar/i18n.py +++ b/lib/solaar/i18n.py @@ -33,18 +33,14 @@ def _find_locale_path(lc_domain): import os.path as _path import sys as _sys - prefix_share = _path.normpath( - _path.join(_path.realpath(_sys.path[0]), '..')) - src_share = _path.normpath( - _path.join(_path.realpath(_sys.path[0]), '..', 'share')) + prefix_share = _path.normpath(_path.join(_path.realpath(_sys.path[0]), '..')) + src_share = _path.normpath(_path.join(_path.realpath(_sys.path[0]), '..', 'share')) del _sys from glob import glob as _glob for location in prefix_share, src_share: - mo_files = _glob( - _path.join(location, 'locale', '*', 'LC_MESSAGES', - lc_domain + '.mo')) + mo_files = _glob(_path.join(location, 'locale', '*', 'LC_MESSAGES', lc_domain + '.mo')) if mo_files: return _path.join(location, 'locale') diff --git a/lib/solaar/listener.py b/lib/solaar/listener.py index a2c784e5..1744a2c3 100644 --- a/lib/solaar/listener.py +++ b/lib/solaar/listener.py @@ -42,9 +42,7 @@ del getLogger # # -_GHOST_DEVICE = namedtuple( - '_GHOST_DEVICE', - ('receiver', 'number', 'name', 'kind', 'status', 'online')) +_GHOST_DEVICE = namedtuple('_GHOST_DEVICE', ('receiver', 'number', 'name', 'kind', 'status', 'online')) _GHOST_DEVICE.__bool__ = lambda self: False _GHOST_DEVICE.__nonzero__ = _GHOST_DEVICE.__bool__ del namedtuple @@ -72,8 +70,7 @@ class ReceiverListener(_listener.EventsListener): """Keeps the status of a Receiver. """ def __init__(self, receiver, status_changed_callback): - super(ReceiverListener, self).__init__(receiver, - self._notifications_handler) + super(ReceiverListener, self).__init__(receiver, self._notifications_handler) # no reason to enable polling yet # self.tick_period = _POLL_TICK # self._last_tick = 0 @@ -84,11 +81,9 @@ class ReceiverListener(_listener.EventsListener): def has_started(self): if _log.isEnabledFor(_INFO): - _log.info('%s: notifications listener has started (%s)', - self.receiver, self.receiver.handle) + _log.info('%s: notifications listener has started (%s)', self.receiver, self.receiver.handle) notification_flags = self.receiver.enable_notifications() - self.receiver.status[ - _status.KEYS.NOTIFICATION_FLAGS] = notification_flags + self.receiver.status[_status.KEYS.NOTIFICATION_FLAGS] = notification_flags self.receiver.notify_devices() self._status_changed(self.receiver) # , _status.ALERT.NOTIFICATION) @@ -151,14 +146,11 @@ class ReceiverListener(_listener.EventsListener): assert device is not None if _log.isEnabledFor(_INFO): if device.kind is None: - _log.info('status_changed %s: %s, %s (%X) %s', device, - 'present' if bool(device) else 'removed', - device.status, alert, reason or '') + _log.info('status_changed %s: %s, %s (%X) %s', device, 'present' if bool(device) else 'removed', device.status, + alert, reason or '') else: - _log.info('status_changed %s: %s %s, %s (%X) %s', device, - 'paired' if bool(device) else 'unpaired', - 'online' if device.online else 'offline', - device.status, alert, reason or '') + _log.info('status_changed %s: %s %s, %s (%X) %s', device, 'paired' if bool(device) else 'unpaired', + 'online' if device.online else 'offline', device.status, alert, reason or '') if device.kind is None: assert device == self.receiver @@ -193,9 +185,7 @@ class ReceiverListener(_listener.EventsListener): # a device notification if not (0 < n.devnumber <= self.receiver.max_devices): if _log.isEnabledFor(_WARNING): - _log.warning( - _('Unexpected device number (%s) in notification %s.' % - (n.devnumber, n))) + _log.warning(_('Unexpected device number (%s) in notification %s.' % (n.devnumber, n))) return already_known = n.devnumber in self.receiver @@ -215,14 +205,10 @@ class ReceiverListener(_listener.EventsListener): if n.sub_id == 0x41: if not already_known: dev = self.receiver.register_new_device(n.devnumber, n) - elif self.receiver.status.lock_open and self.receiver.re_pairs and not ord( - n.data[0:1]) & 0x40: + elif self.receiver.status.lock_open and self.receiver.re_pairs and not ord(n.data[0:1]) & 0x40: dev = self.receiver[n.devnumber] - del self.receiver[ - n. - devnumber] # get rid of information on device re-paired away - self._status_changed( - dev) # signal that this device has changed + del self.receiver[n.devnumber] # get rid of information on device re-paired away + self._status_changed(dev) # signal that this device has changed dev = self.receiver.register_new_device(n.devnumber, n) self.receiver.status.new_device = self.receiver[n.devnumber] else: @@ -231,8 +217,7 @@ class ReceiverListener(_listener.EventsListener): dev = self.receiver[n.devnumber] if not dev: - _log.warn('%s: received %s for invalid device %d: %r', - self.receiver, n, n.devnumber, dev) + _log.warn('%s: received %s for invalid device %d: %r', self.receiver, n, n.devnumber, dev) return # Apply settings every time the device connects @@ -259,8 +244,7 @@ class ReceiverListener(_listener.EventsListener): dev.ping() def __str__(self): - return '' % (self.receiver.path, - self.receiver.handle) + return '' % (self.receiver.path, self.receiver.handle) __unicode__ = __str__ @@ -372,8 +356,7 @@ def _process_receiver_event(action, device_info): try: import subprocess import re - output = subprocess.check_output( - ['/usr/bin/getfacl', '-p', device_info.path]) + output = subprocess.check_output(['/usr/bin/getfacl', '-p', device_info.path]) if not re.search(b'user:.+:', output): _error_callback('permissions', device_info.path) except Exception: diff --git a/lib/solaar/ui/__init__.py b/lib/solaar/ui/__init__.py index 43c1b831..6f989103 100644 --- a/lib/solaar/ui/__init__.py +++ b/lib/solaar/ui/__init__.py @@ -54,14 +54,12 @@ def _error_dialog(reason, object): text = (_('Failed to unpair %{device} from %{receiver}.').format(device=object.name, receiver=object.receiver.name) + '\n\n' + _('The receiver returned an error, with no further details.')) else: - raise Exception("ui.error_dialog: don't know how to handle (%s, %s)", - reason, object) + raise Exception("ui.error_dialog: don't know how to handle (%s, %s)", reason, object) assert title assert text - m = Gtk.MessageDialog(None, Gtk.DialogFlags.MODAL, Gtk.MessageType.ERROR, - Gtk.ButtonsType.CLOSE, text) + m = Gtk.MessageDialog(None, Gtk.DialogFlags.MODAL, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, text) m.set_title(title) m.run() m.destroy() @@ -93,8 +91,7 @@ from . import notify, tray, window # isort:skip # noqa: E402 def _startup(app, startup_hook, use_tray, show_window): if _log.isEnabledFor(_DEBUG): - _log.debug('startup registered=%s, remote=%s', app.get_is_registered(), - app.get_is_remote()) + _log.debug('startup registered=%s, remote=%s', app.get_is_registered(), app.get_is_remote()) from solaar.tasks import TaskRunner as _TaskRunner global _task_runner @@ -144,12 +141,9 @@ def run_loop(startup_hook, shutdown_hook, use_tray, show_window, args=None): assert use_tray or show_window, 'need either tray or visible window' # from gi.repository.Gio import ApplicationFlags as _ApplicationFlags APP_ID = 'io.github.pwr.solaar' - application = Gtk.Application.new( - APP_ID, 0) # _ApplicationFlags.HANDLES_COMMAND_LINE) + application = Gtk.Application.new(APP_ID, 0) # _ApplicationFlags.HANDLES_COMMAND_LINE) - application.connect( - 'startup', lambda app, startup_hook: _startup( - app, startup_hook, use_tray, show_window), startup_hook) + application.connect('startup', lambda app, startup_hook: _startup(app, startup_hook, use_tray, show_window), startup_hook) application.connect('command-line', _command_line) application.connect('activate', _activate) application.connect('shutdown', _shutdown, shutdown_hook) diff --git a/lib/solaar/ui/about.py b/lib/solaar/ui/about.py index 5212671d..c290137b 100644 --- a/lib/solaar/ui/about.py +++ b/lib/solaar/ui/about.py @@ -35,9 +35,7 @@ def _create(): about.set_program_name(NAME) about.set_version(__version__) - about.set_comments( - _('Shows status of devices connected\nthrough wireless Logitech receivers.' - )) + about.set_comments(_('Shows status of devices connected\nthrough wireless Logitech receivers.')) about.set_logo_icon_name(NAME.lower()) @@ -46,8 +44,7 @@ def _create(): about.set_authors(('Daniel Pavel http://github.com/pwr', )) try: - about.add_credit_section(_('GUI design'), - ('Julien Gascard', 'Daniel Pavel')) + about.add_credit_section(_('GUI design'), ('Julien Gascard', 'Daniel Pavel')) about.add_credit_section(_('Testing'), ( 'Douglas Wagner', 'Julien Gascard', diff --git a/lib/solaar/ui/action.py b/lib/solaar/ui/action.py index 315364ef..dfd52372 100644 --- a/lib/solaar/ui/action.py +++ b/lib/solaar/ui/action.py @@ -67,10 +67,7 @@ def make_toggle(name, label, function, stock_id=None, *args): # action.set_sensitive(notify.available) # toggle_notifications = make_toggle('notifications', 'Notifications', _toggle_notifications) -about = make('help-about', - _('About') + ' ' + NAME, - _show_about_window, - stock_id=Gtk.STOCK_ABOUT) +about = make('help-about', _('About') + ' ' + NAME, _show_about_window, stock_id=Gtk.STOCK_ABOUT) # # @@ -94,8 +91,7 @@ def unpair(window, device): assert device assert device.kind is not None - qdialog = Gtk.MessageDialog(window, 0, Gtk.MessageType.QUESTION, - Gtk.ButtonsType.NONE, + qdialog = Gtk.MessageDialog(window, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.NONE, _('Unpair') + ' ' + device.name + ' ?') qdialog.set_icon_name('remove') qdialog.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL) diff --git a/lib/solaar/ui/config_panel.py b/lib/solaar/ui/config_panel.py index 508dc23a..df52442c 100644 --- a/lib/solaar/ui/config_panel.py +++ b/lib/solaar/ui/config_panel.py @@ -106,20 +106,15 @@ def _create_map_choice_control(setting): def _map_value_notify_value(cbbox, s): setting, keyBox = s key_choice = keyBox.get_active_id() - if key_choice is not None and cbbox.get_sensitive( - ) and cbbox.get_active_id(): + if key_choice is not None and cbbox.get_sensitive() and cbbox.get_active_id(): if setting._value.get(key_choice) != int(cbbox.get_active_id()): setting._value[key_choice] = int(cbbox.get_active_id()) - _write_async_key_value(setting, key_choice, - setting._value[key_choice], - cbbox.get_parent().get_parent()) + _write_async_key_value(setting, key_choice, setting._value[key_choice], cbbox.get_parent().get_parent()) def _map_populate_value_box(valueBox, setting, key_choice): choices = None choices = setting.choices[key_choice] - current = setting._value.get( - str(key_choice - )) # just in case the persisted value is missing some keys + current = setting._value.get(str(key_choice)) # just in case the persisted value is missing some keys if choices: # TODO i18n text entries for choice in choices: @@ -155,12 +150,10 @@ def _create_slider_control(setting): self.gtk_range.set_round_digits(0) self.gtk_range.set_digits(0) self.gtk_range.set_increments(1, 5) - self.gtk_range.connect('value-changed', lambda _, c: c._changed(), - self) + self.gtk_range.connect('value-changed', lambda _, c: c._changed(), self) def _write(self): - _write_async(self.setting, int(self.gtk_range.get_value()), - self.gtk_range.get_parent()) + _write_async(self.setting, int(self.gtk_range.get_value()), self.gtk_range.get_parent()) self.timer.cancel() def _changed(self): @@ -186,8 +179,7 @@ def _create_sbox(s): spinner = Gtk.Spinner() spinner.set_tooltip_text(_('Working') + '...') - failed = Gtk.Image.new_from_icon_name('dialog-warning', - Gtk.IconSize.SMALL_TOOLBAR) + failed = Gtk.Image.new_from_icon_name('dialog-warning', Gtk.IconSize.SMALL_TOOLBAR) failed.set_tooltip_text(_('Read/write operation failed.')) if s.kind == _SETTING_KIND.toggle: @@ -237,8 +229,7 @@ def _create_sbox(s): def _update_setting_item(sbox, value, is_online=True): - _ignore, failed, spinner, control = sbox.get_children( - ) # depends on box layout + _ignore, failed, spinner, control = sbox.get_children() # depends on box layout spinner.set_visible(False) spinner.stop() diff --git a/lib/solaar/ui/icons.py b/lib/solaar/ui/icons.py index 87cec21f..e2dc8cf7 100644 --- a/lib/solaar/ui/icons.py +++ b/lib/solaar/ui/icons.py @@ -55,23 +55,16 @@ def _look_for_application_icons(): import sys as _sys if _log.isEnabledFor(_DEBUG): _log.debug('sys.path[0] = %s', _sys.path[0]) - prefix_share = _path.normpath( - _path.join(_path.realpath(_sys.path[0]), '..')) - src_share = _path.normpath( - _path.join(_path.realpath(_sys.path[0]), '..', 'share')) - local_share = _environ.get( - 'XDG_DATA_HOME', _path.expanduser(_path.join('~', '.local', 'share'))) + prefix_share = _path.normpath(_path.join(_path.realpath(_sys.path[0]), '..')) + src_share = _path.normpath(_path.join(_path.realpath(_sys.path[0]), '..', 'share')) + local_share = _environ.get('XDG_DATA_HOME', _path.expanduser(_path.join('~', '.local', 'share'))) data_dirs = _environ.get('XDG_DATA_DIRS', '/usr/local/share:/usr/share') - repo_share = _path.normpath( - _path.join(_path.dirname(__file__), '..', '..', '..', 'share')) - setuptools_share = _path.normpath( - _path.join(_path.dirname(__file__), '..', '..', 'share')) + repo_share = _path.normpath(_path.join(_path.dirname(__file__), '..', '..', '..', 'share')) + setuptools_share = _path.normpath(_path.join(_path.dirname(__file__), '..', '..', 'share')) del _sys share_solaar = [prefix_share] + list( - _path.join(x, 'solaar') - for x in [src_share, local_share, setuptools_share, repo_share] + - data_dirs.split(':')) + _path.join(x, 'solaar') for x in [src_share, local_share, setuptools_share, repo_share] + data_dirs.split(':')) for location in share_solaar: location = _path.join(location, 'icons') if _log.isEnabledFor(_DEBUG): @@ -137,10 +130,8 @@ def _battery_icon_name(level, charging): if level is None or level < 0: return 'battery-missing' + ('-symbolic' if _use_symbolic_icons else '') - level_name = _first_res(level, ((90, 'full'), (50, 'good'), (20, 'low'), - (5, 'caution'), (0, 'empty'))) - return 'battery-%s%s%s' % (level_name, '-charging' if charging else '', - '-symbolic' if _use_symbolic_icons else '') + level_name = _first_res(level, ((90, 'full'), (50, 'good'), (20, 'low'), (5, 'caution'), (0, 'empty'))) + return 'battery-%s%s%s' % (level_name, '-charging' if charging else '', '-symbolic' if _use_symbolic_icons else '') # diff --git a/lib/solaar/ui/pair_window.py b/lib/solaar/ui/pair_window.py index 2de089db..8ad28b85 100644 --- a/lib/solaar/ui/pair_window.py +++ b/lib/solaar/ui/pair_window.py @@ -87,8 +87,7 @@ def _check_lock_state(assistant, receiver, count=2): if count > 0: # the actual device notification may arrive after the lock was paired, # so have a little patience - GLib.timeout_add(_STATUS_CHECK, _check_lock_state, assistant, - receiver, count - 1) + GLib.timeout_add(_STATUS_CHECK, _check_lock_state, assistant, receiver, count - 1) else: _pairing_failed(assistant, receiver, 'failed to open pairing lock') return False @@ -107,12 +106,10 @@ def _prepare(assistant, page, receiver): assert receiver.status.get(_K.ERROR) is None spinner = page.get_children()[-1] spinner.start() - GLib.timeout_add(_STATUS_CHECK, _check_lock_state, assistant, - receiver) + GLib.timeout_add(_STATUS_CHECK, _check_lock_state, assistant, receiver) assistant.set_page_complete(page, True) else: - GLib.idle_add(_pairing_failed, assistant, receiver, - 'the pairing lock did not open') + GLib.idle_add(_pairing_failed, assistant, receiver, 'the pairing lock did not open') else: assistant.remove_page(0) @@ -136,19 +133,14 @@ def _pairing_failed(assistant, receiver, error): header = _('Pairing failed') + ': ' + _(str(error)) + '.' if 'timeout' in str(error): - text = _( - 'Make sure your device is within range, and has a decent battery charge.' - ) + text = _('Make sure your device is within range, and has a decent battery charge.') elif str(error) == 'device not supported': - text = _( - 'A new device was detected, but it is not compatible with this receiver.' - ) + text = _('A new device was detected, but it is not compatible with this receiver.') elif 'many' in str(error): text = _('The receiver only supports %d paired device(s).') else: text = _('No further details are available about the error.') - _create_page(assistant, Gtk.AssistantPageType.SUMMARY, header, - 'dialog-error', text) + _create_page(assistant, Gtk.AssistantPageType.SUMMARY, header, 'dialog-error', text) assistant.next_page() assistant.commit() @@ -204,24 +196,19 @@ def create(receiver): assert receiver.kind is None assistant = Gtk.Assistant() - assistant.set_title( - _('%(receiver_name)s: pair new device') % - {'receiver_name': receiver.name}) + assistant.set_title(_('%(receiver_name)s: pair new device') % {'receiver_name': receiver.name}) assistant.set_icon_name('list-add') assistant.set_size_request(400, 240) assistant.set_resizable(False) assistant.set_role('pair-device') - page_text = _( - 'If the device is already turned on, turn if off and on again.') + page_text = _('If the device is already turned on, turn if off and on again.') if receiver.remaining_pairings() and receiver.remaining_pairings() >= 0: - page_text += _('\n\nThis receiver has %d pairing(s) remaining.' - ) % receiver.remaining_pairings() + page_text += _('\n\nThis receiver has %d pairing(s) remaining.') % receiver.remaining_pairings() page_text += _('\nCancelling at this point will not use up a pairing.') - page_intro = _create_page(assistant, Gtk.AssistantPageType.PROGRESS, - _('Turn on the device you want to pair.'), + page_intro = _create_page(assistant, Gtk.AssistantPageType.PROGRESS, _('Turn on the device you want to pair.'), 'preferences-desktop-peripherals', page_text) spinner = Gtk.Spinner() spinner.set_visible(True) diff --git a/lib/solaar/ui/tray.py b/lib/solaar/ui/tray.py index 3e36e91f..a56993de 100644 --- a/lib/solaar/ui/tray.py +++ b/lib/solaar/ui/tray.py @@ -63,11 +63,7 @@ def _create_menu(quit_handler): from .action import about, make menu.append(about.create_menu_item()) - menu.append( - make('application-exit', - _('Quit'), - quit_handler, - stock_id=Gtk.STOCK_QUIT).create_menu_item()) + menu.append(make('application-exit', _('Quit'), quit_handler, stock_id=Gtk.STOCK_QUIT).create_menu_item()) del about, make menu.show_all() @@ -172,24 +168,21 @@ try: from gi.repository import AppIndicator3 if _log.isEnabledFor(_DEBUG): - _log.debug('using %sAppIndicator3' % - ('Ayatana ' if ayatana_appindicator_found else '')) + _log.debug('using %sAppIndicator3' % ('Ayatana ' if ayatana_appindicator_found else '')) # Defense against AppIndicator3 bug that treats files in current directory as icon files # https://bugs.launchpad.net/ubuntu/+source/libappindicator/+bug/1363277 def _icon_file(icon_name): if not os.path.isfile(icon_name): return icon_name - icon_info = Gtk.IconTheme.get_default().lookup_icon( - icon_name, _TRAY_ICON_SIZE, 0) + icon_info = Gtk.IconTheme.get_default().lookup_icon(icon_name, _TRAY_ICON_SIZE, 0) return icon_info.get_filename() if icon_info else icon_name def _create(menu): theme_paths = Gtk.IconTheme.get_default().get_search_path() - ind = AppIndicator3.Indicator.new_with_path( - 'indicator-solaar', _icon_file(_icons.TRAY_INIT), - AppIndicator3.IndicatorCategory.HARDWARE, ':'.join(theme_paths)) + ind = AppIndicator3.Indicator.new_with_path('indicator-solaar', _icon_file(_icons.TRAY_INIT), + AppIndicator3.IndicatorCategory.HARDWARE, ':'.join(theme_paths)) ind.set_title(NAME) ind.set_status(AppIndicator3.IndicatorStatus.ACTIVE) ind.set_attention_icon_full(_icon_file(_icons.TRAY_ATTENTION), '') @@ -229,11 +222,9 @@ try: def attention(reason=None): if _icon.get_status() != AppIndicator3.IndicatorStatus.ATTENTION: - _icon.set_attention_icon_full(_icon_file(_icons.TRAY_ATTENTION), - reason or '') + _icon.set_attention_icon_full(_icon_file(_icons.TRAY_ATTENTION), reason or '') _icon.set_status(AppIndicator3.IndicatorStatus.ATTENTION) - GLib.timeout_add(10 * 1000, _icon.set_status, - AppIndicator3.IndicatorStatus.ACTIVE) + GLib.timeout_add(10 * 1000, _icon.set_status, AppIndicator3.IndicatorStatus.ACTIVE) except ImportError: @@ -247,9 +238,7 @@ except ImportError: icon.set_tooltip_text(NAME) icon.connect('activate', _window_toggle) icon.connect('scroll-event', _scroll) - icon.connect( - 'popup-menu', lambda icon, button, time: menu.popup( - None, None, icon.position_menu, icon, button, time)) + icon.connect('popup-menu', lambda icon, button, time: menu.popup(None, None, icon.position_menu, icon, button, time)) return icon @@ -326,8 +315,7 @@ def _generate_description_lines(): yield '\t%s (' % p + _('offline') + ')' else: if status: - yield '%s (' % name + _( - 'no status') + ')' + yield '%s (' % name + _('no status') + ')' else: yield '%s (' % name + _('offline') + ')' yield '' @@ -385,20 +373,17 @@ def _add_device(device): break index = index + 1 - new_device_info = (receiver_path, device.number, device.name, - device.status) + new_device_info = (receiver_path, device.number, device.name, device.status) assert len(new_device_info) == len(_RECEIVER_SEPARATOR) _devices_info.insert(index, new_device_info) # label_prefix = b'\xE2\x94\x84 '.decode('utf-8') label_prefix = ' ' - new_menu_item = Gtk.ImageMenuItem.new_with_label(label_prefix + - device.name) + new_menu_item = Gtk.ImageMenuItem.new_with_label(label_prefix + device.name) new_menu_item.set_image(Gtk.Image()) new_menu_item.show_all() - new_menu_item.connect('activate', _window_popup, receiver_path, - device.number) + new_menu_item.connect('activate', _window_popup, receiver_path, device.number) _menu.insert(new_menu_item, index) return index @@ -427,8 +412,7 @@ def _add_receiver(receiver): new_menu_item = Gtk.ImageMenuItem.new_with_label(receiver.name) _menu.insert(new_menu_item, index) icon_set = _icons.device_icon_set(receiver.name) - new_menu_item.set_image(Gtk.Image().new_from_icon_set( - icon_set, _MENU_ICON_SIZE)) + new_menu_item.set_image(Gtk.Image().new_from_icon_set(icon_set, _MENU_ICON_SIZE)) new_menu_item.show_all() new_menu_item.connect('activate', _window_popup, receiver.path) @@ -521,8 +505,7 @@ def update(device=None): receiver_path = device.path if is_alive: index = None - for idx, (path, _ignore, _ignore, - _ignore) in enumerate(_devices_info): + for idx, (path, _ignore, _ignore, _ignore) in enumerate(_devices_info): if path == receiver_path: index = idx break @@ -537,8 +520,7 @@ def update(device=None): is_paired = bool(device) receiver_path = device.receiver.path index = None - for idx, (path, number, _ignore, - _ignore) in enumerate(_devices_info): + for idx, (path, number, _ignore, _ignore) in enumerate(_devices_info): if path == receiver_path and number == device.number: index = idx @@ -557,8 +539,7 @@ def update(device=None): menu_items[no_receivers_index + 1].set_visible(not _devices_info) global _picked_device - if (not _picked_device or _last_scroll - == 0) and device is not None and device.kind is not None: + if (not _picked_device or _last_scroll == 0) and device is not None and device.kind is not None: # if it's just a receiver update, it's unlikely the picked device would change _picked_device = _pick_device_with_lowest_battery() diff --git a/lib/solaar/ui/window.py b/lib/solaar/ui/window.py index 6dc322f0..5250e2ab 100644 --- a/lib/solaar/ui/window.py +++ b/lib/solaar/ui/window.py @@ -58,14 +58,7 @@ except (ValueError, AttributeError): _CAN_SET_ROW_NONE = '' # tree model columns -_COLUMN = _NamedInts(PATH=0, - NUMBER=1, - ACTIVE=2, - NAME=3, - ICON=4, - STATUS_TEXT=5, - STATUS_ICON=6, - DEVICE=7) +_COLUMN = _NamedInts(PATH=0, NUMBER=1, ACTIVE=2, NAME=3, ICON=4, STATUS_TEXT=5, STATUS_ICON=6, DEVICE=7) _COLUMN_TYPES = (str, int, bool, str, str, str, str, TYPE_PYOBJECT) _TREE_SEPATATOR = (None, 0, False, None, None, None, None, None) assert len(_TREE_SEPATATOR) == len(_COLUMN_TYPES) @@ -76,12 +69,7 @@ assert len(_COLUMN_TYPES) == len(_COLUMN) # -def _new_button(label, - icon_name=None, - icon_size=_NORMAL_BUTTON_ICON_SIZE, - tooltip=None, - toggle=False, - clicked=None): +def _new_button(label, icon_name=None, icon_size=_NORMAL_BUTTON_ICON_SIZE, tooltip=None, toggle=False, clicked=None): if toggle: b = Gtk.ToggleButton() else: @@ -198,9 +186,7 @@ def _create_buttons_box(): assert receiver.kind is None _action.pair(_window, receiver) - bb._pair = _new_button(_('Pair new device'), - 'list-add', - clicked=_pair_new_device) + bb._pair = _new_button(_('Pair new device'), 'list-add', clicked=_pair_new_device) bb.add(bb._pair) def _unpair_current_device(trigger): @@ -211,9 +197,7 @@ def _create_buttons_box(): assert device.kind is not None _action.unpair(_window, device) - bb._unpair = _new_button(_('Unpair'), - 'edit-delete', - clicked=_unpair_current_device) + bb._unpair = _new_button(_('Unpair'), 'edit-delete', clicked=_unpair_current_device) bb.add(bb._unpair) return bb @@ -239,8 +223,7 @@ def _create_info_panel(): b1.pack_start(p._icon, False, False, 0) p.pack_start(b1, False, False, 0) - p.pack_start(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL), False, False, - 0) # spacer + p.pack_start(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL), False, False, 0) # spacer p._receiver = _create_receiver_panel() p.pack_start(p._receiver, True, True, 0) @@ -248,8 +231,7 @@ def _create_info_panel(): p._device = _create_device_panel() p.pack_start(p._device, True, True, 0) - p.pack_start(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL), False, False, - 0) # spacer + p.pack_start(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL), False, False, 0) # spacer p._buttons = _create_buttons_box() p.pack_end(p._buttons, False, False, 0) @@ -293,20 +275,16 @@ def _create_tree(model): status_cell_renderer.set_property('scale', 0.85) status_cell_renderer.set_property('xalign', 1) status_column = Gtk.TreeViewColumn('status text', status_cell_renderer) - status_column.add_attribute(status_cell_renderer, 'sensitive', - _COLUMN.ACTIVE) - status_column.add_attribute(status_cell_renderer, 'text', - _COLUMN.STATUS_TEXT) + status_column.add_attribute(status_cell_renderer, 'sensitive', _COLUMN.ACTIVE) + status_column.add_attribute(status_cell_renderer, 'text', _COLUMN.STATUS_TEXT) status_column.set_expand(True) tree.append_column(status_column) battery_cell_renderer = Gtk.CellRendererPixbuf() battery_cell_renderer.set_property('stock-size', _TREE_ICON_SIZE) battery_column = Gtk.TreeViewColumn('status icon', battery_cell_renderer) - battery_column.add_attribute(battery_cell_renderer, 'sensitive', - _COLUMN.ACTIVE) - battery_column.add_attribute(battery_cell_renderer, 'icon-name', - _COLUMN.STATUS_ICON) + battery_column.add_attribute(battery_cell_renderer, 'sensitive', _COLUMN.ACTIVE) + battery_column.add_attribute(battery_cell_renderer, 'icon-name', _COLUMN.STATUS_ICON) tree.append_column(battery_column) return tree @@ -339,10 +317,7 @@ def _create_window_layout(): bottom_buttons_box = Gtk.ButtonBox(Gtk.Orientation.HORIZONTAL) bottom_buttons_box.set_layout(Gtk.ButtonBoxStyle.START) bottom_buttons_box.set_spacing(20) - quit_button = _new_button(_('Quit') + ' ' + NAME, - 'application-exit', - icon_size=_SMALL_BUTTON_ICON_SIZE, - clicked=destroy) + quit_button = _new_button(_('Quit') + ' ' + NAME, 'application-exit', icon_size=_SMALL_BUTTON_ICON_SIZE, clicked=destroy) bottom_buttons_box.add(quit_button) about_button = _new_button(_('About') + ' ' + NAME, 'help-about', @@ -406,8 +381,7 @@ def _find_selected_device_id(): selection = _tree.get_selection() model, item = selection.get_selected() if item: - return _model.get_value(item, _COLUMN.PATH), _model.get_value( - item, _COLUMN.NUMBER) + return _model.get_value(item, _COLUMN.PATH), _model.get_value(item, _COLUMN.NUMBER) # triggered by changing selection in the tree @@ -440,8 +414,7 @@ def _receiver_row(receiver_path, receiver=None): icon_name = _icons.device_icon_name(receiver.name) status_text = None status_icon = None - row_data = (receiver_path, 0, True, receiver.name, icon_name, - status_text, status_icon, receiver) + row_data = (receiver_path, 0, True, receiver.name, icon_name, status_text, status_icon, receiver) assert len(row_data) == len(_TREE_SEPATATOR) if _log.isEnabledFor(_DEBUG): _log.debug('new receiver row %s', row_data) @@ -456,8 +429,7 @@ def _device_row(receiver_path, device_number, device=None): assert receiver_path assert device_number is not None - receiver_row = _receiver_row(receiver_path, - None if device is None else device.receiver) + receiver_row = _receiver_row(receiver_path, None if device is None else device.receiver) item = _model.iter_children(receiver_row) new_child_index = 0 while item: @@ -475,13 +447,11 @@ def _device_row(receiver_path, device_number, device=None): icon_name = _icons.device_icon_name(device.name, device.kind) status_text = None status_icon = None - row_data = (receiver_path, device_number, bool(device.online), - device.codename, icon_name, status_text, status_icon, + row_data = (receiver_path, device_number, bool(device.online), device.codename, icon_name, status_text, status_icon, device) assert len(row_data) == len(_TREE_SEPATATOR) if _log.isEnabledFor(_DEBUG): - _log.debug('new device row %s at index %d', row_data, - new_child_index) + _log.debug('new device row %s at index %d', row_data, new_child_index) item = _model.insert(receiver_row, new_child_index, row_data) return item or None @@ -503,8 +473,7 @@ def select(receiver_path, device_number=None): selection = _tree.get_selection() selection.select_iter(item) else: - _log.warn('select(%s, %s) failed to find an item', receiver_path, - device_number) + _log.warn('select(%s, %s) failed to find an item', receiver_path, device_number) def _hide(w, _ignore=None): @@ -562,14 +531,12 @@ def _update_details(button): yield (_('Index'), device.number) yield (_('Wireless PID'), device.wpid) hid_version = device.protocol - yield (_('Protocol'), 'HID++ %1.1f' % - hid_version if hid_version else _('Unknown')) + yield (_('Protocol'), 'HID++ %1.1f' % hid_version if hid_version else _('Unknown')) if read_all and device.polling_rate: - yield (_('Polling rate'), - _('%(rate)d ms (%(rate_hz)dHz)') % { - 'rate': device.polling_rate, - 'rate_hz': 1000 // device.polling_rate - }) + yield (_('Polling rate'), _('%(rate)d ms (%(rate_hz)dHz)') % { + 'rate': device.polling_rate, + 'rate_hz': 1000 // device.polling_rate + }) if read_all or not device.online: yield (_('Serial'), device.serial) @@ -579,17 +546,13 @@ def _update_details(button): if read_all: if device.firmware: for fw in list(device.firmware): - yield (' ' + _(str(fw.kind)), - (fw.name + ' ' + fw.version).strip()) + yield (' ' + _(str(fw.kind)), (fw.name + ' ' + fw.version).strip()) elif device.kind is None or device.online: yield (' %s' % _('Firmware'), '...') flag_bits = device.status.get(_K.NOTIFICATION_FLAGS) if flag_bits is not None: - flag_names = ( - '(%s)' % _('none'), - ) if flag_bits == 0 else _hidpp10.NOTIFICATION_FLAG.flag_names( - flag_bits) + flag_names = ('(%s)' % _('none'), ) if flag_bits == 0 else _hidpp10.NOTIFICATION_FLAG.flag_names(flag_bits) yield (_('Notifications'), ('\n%15s' % ' ').join(flag_names)) def _set_details(text): @@ -626,26 +589,22 @@ def _update_receiver_panel(receiver, panel, buttons, full=False): devices_count = len(receiver) - paired_text = _('No device paired.') if devices_count == 0 else ngettext( - '%(count)s paired device.', '%(count)s paired devices.', - devices_count) % { - 'count': devices_count - } + paired_text = _('No device paired.') if devices_count == 0 else ngettext('%(count)s paired device.', + '%(count)s paired devices.', devices_count) % { + 'count': devices_count + } if (receiver.max_devices > 0): - paired_text += '\n\n%s' % ngettext( - 'Up to %(max_count)s device can be paired to this receiver.', - 'Up to %(max_count)s devices can be paired to this receiver.', - receiver.max_devices) % { - 'max_count': receiver.max_devices - } + paired_text += '\n\n%s' % ngettext('Up to %(max_count)s device can be paired to this receiver.', + 'Up to %(max_count)s devices can be paired to this receiver.', + receiver.max_devices) % { + 'max_count': receiver.max_devices + } elif devices_count > 0: - paired_text += '\n\n%s' % _( - 'Only one device can be paired to this receiver.') + paired_text += '\n\n%s' % _('Only one device can be paired to this receiver.') pairings = receiver.remaining_pairings(False) if (pairings is not None and pairings >= 0): - paired_text += '\n%s' % _( - 'This receiver has %d pairing(s) remaining.') % pairings + paired_text += '\n%s' % _('This receiver has %d pairing(s) remaining.') % pairings panel._count.set_markup(paired_text) @@ -669,11 +628,8 @@ def _update_receiver_panel(receiver, panel, buttons, full=False): if (receiver.may_unpair or receiver.re_pairs) and not is_pairing and \ (receiver.remaining_pairings() is None or receiver.remaining_pairings() != 0): if not receiver.re_pairs and devices_count >= receiver.max_devices: - paired_devices = tuple(n - for n in range(1, receiver.max_devices + 1) - if n in receiver) - buttons._pair.set_sensitive( - len(paired_devices) < receiver.max_devices) + paired_devices = tuple(n for n in range(1, receiver.max_devices + 1) if n in receiver) + buttons._pair.set_sensitive(len(paired_devices) < receiver.max_devices) else: buttons._pair.set_sensitive(True) else: @@ -704,20 +660,16 @@ def _update_device_panel(device, panel, buttons, full=False): panel._battery._icon.set_sensitive(True) if battery_voltage is not None: - text = '%(battery_voltage)dmV' % { - 'battery_voltage': battery_voltage - } + text = '%(battery_voltage)dmV' % {'battery_voltage': battery_voltage} elif isinstance(battery_level, _NamedInt): text = _(str(battery_level)) else: text = '%(battery_percent)d%%' % {'battery_percent': battery_level} if battery_next_level is not None: if isinstance(battery_next_level, _NamedInt): - text += ' (' + _('next ') + _( - str(battery_next_level)) + ')' + text += ' (' + _('next ') + _(str(battery_next_level)) + ')' else: - text += ' (' + _('next ') + ( - '%d%%' % battery_next_level) + ')' + text += ' (' + _('next ') + ('%d%%' % battery_next_level) + ')' if is_online: if charging: text += ' (%s)' % _('charging') @@ -730,23 +682,18 @@ def _update_device_panel(device, panel, buttons, full=False): not_secure = device.status.get(_K.LINK_ENCRYPTED) is False if not_secure: panel._secure._text.set_text(_('not encrypted')) - panel._secure._icon.set_from_icon_name('security-low', - _INFO_ICON_SIZE) + panel._secure._icon.set_from_icon_name('security-low', _INFO_ICON_SIZE) panel._secure.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' 'It is, however, a major security issue for text-input devices (keyboards, numpads),\n' - 'because typed text can be sniffed inconspicuously by 3rd parties within range.' - )) + 'because typed text can be sniffed inconspicuously by 3rd parties within range.')) else: panel._secure._text.set_text(_('encrypted')) - panel._secure._icon.set_from_icon_name('security-high', - _INFO_ICON_SIZE) - panel._secure.set_tooltip_text( - _('The wireless link between this device and its receiver is encrypted.' - )) + panel._secure._icon.set_from_icon_name('security-high', _INFO_ICON_SIZE) + panel._secure.set_tooltip_text(_('The wireless link between this device and its receiver is encrypted.')) panel._secure._icon.set_visible(True) else: panel._secure._text.set_markup('%s' % _('offline')) @@ -758,10 +705,8 @@ def _update_device_panel(device, panel, buttons, full=False): if light_level is None: panel._lux.set_visible(False) else: - panel._lux._icon.set_from_icon_name(_icons.lux(light_level), - _INFO_ICON_SIZE) - panel._lux._text.set_text( - _('%(light_level)d lux') % {'light_level': light_level}) + panel._lux._icon.set_from_icon_name(_icons.lux(light_level), _INFO_ICON_SIZE) + panel._lux._text.set_text(_('%(light_level)d lux') % {'light_level': light_level}) panel._lux.set_visible(True) else: panel._lux.set_visible(False) @@ -880,9 +825,7 @@ def update(device, need_popup=False): if is_alive and item: was_pairing = bool(_model.get_value(item, _COLUMN.STATUS_ICON)) is_pairing = bool(device.status.lock_open) - _model.set_value( - item, _COLUMN.STATUS_ICON, - 'network-wireless' if is_pairing else _CAN_SET_ROW_NONE) + _model.set_value(item, _COLUMN.STATUS_ICON, 'network-wireless' if is_pairing else _CAN_SET_ROW_NONE) if selected_device_id == (device.path, 0): full_update = need_popup or was_pairing != is_pairing @@ -898,10 +841,8 @@ def update(device, need_popup=False): # peripheral is_paired = bool(device) assert device.receiver - assert device.number is not None and device.number > 0, 'invalid device number' + str( - device.number) - item = _device_row(device.receiver.path, device.number, - device if is_paired else None) + assert device.number is not None and device.number > 0, 'invalid device number' + str(device.number) + item = _device_row(device.receiver.path, device.number, device if is_paired else None) if is_paired and item: was_online = _model.get_value(item, _COLUMN.ACTIVE) @@ -915,15 +856,11 @@ def update(device, need_popup=False): _model.set_value(item, _COLUMN.STATUS_ICON, _CAN_SET_ROW_NONE) else: if battery_voltage is not None: - status_text = '%(battery_voltage)dmV' % { - 'battery_voltage': battery_voltage - } + status_text = '%(battery_voltage)dmV' % {'battery_voltage': battery_voltage} elif isinstance(battery_level, _NamedInt): status_text = _(str(battery_level)) else: - status_text = '%(battery_percent)d%%' % { - 'battery_percent': battery_level - } + status_text = '%(battery_percent)d%%' % {'battery_percent': battery_level} _model.set_value(item, _COLUMN.STATUS_TEXT, status_text) charging = device.status.get(_K.BATTERY_CHARGING) diff --git a/lib/solaar/upower.py b/lib/solaar/upower.py index 309aca12..57cf753f 100644 --- a/lib/solaar/upower.py +++ b/lib/solaar/upower.py @@ -76,24 +76,14 @@ try: bus = dbus.SystemBus() assert bus - bus.add_signal_receiver(_suspend, - signal_name='Sleeping', - dbus_interface=_UPOWER_INTERFACE, - bus_name=_UPOWER_BUS) + bus.add_signal_receiver(_suspend, signal_name='Sleeping', dbus_interface=_UPOWER_INTERFACE, bus_name=_UPOWER_BUS) - bus.add_signal_receiver(_resume, - signal_name='Resuming', - dbus_interface=_UPOWER_INTERFACE, - bus_name=_UPOWER_BUS) + bus.add_signal_receiver(_resume, signal_name='Resuming', dbus_interface=_UPOWER_INTERFACE, bus_name=_UPOWER_BUS) - bus.add_signal_receiver(_suspend_or_resume, - 'PrepareForSleep', - dbus_interface=_LOGIND_INTERFACE, - bus_name=_LOGIND_BUS) + bus.add_signal_receiver(_suspend_or_resume, 'PrepareForSleep', dbus_interface=_LOGIND_INTERFACE, bus_name=_LOGIND_BUS) if _log.isEnabledFor(_INFO): - _log.info( - 'connected to system dbus, watching for suspend/resume events') + _log.info('connected to system dbus, watching for suspend/resume events') except Exception: # Either: diff --git a/setup.cfg b/setup.cfg index a345100c..c2c2f570 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,6 +3,9 @@ max-line-length = 127 extend-ignore = E266,E731,E741 min-python-version = 3.5 +[yapf] +column_limit = 127 + [isort] line_length = 127 lines_between_types = 1 diff --git a/setup.py b/setup.py index 38fb9981..7888eb47 100755 --- a/setup.py +++ b/setup.py @@ -19,9 +19,7 @@ def _data_files(): yield 'share/solaar/icons', _glob('share/solaar/icons/solaar*.svg') yield 'share/solaar/icons', _glob('share/solaar/icons/light_*.png') - yield 'share/icons/hicolor/scalable/apps', [ - 'share/solaar/icons/solaar.svg' - ] + yield 'share/icons/hicolor/scalable/apps', ['share/solaar/icons/solaar.svg'] for mo in _glob('share/locale/*/LC_MESSAGES/solaar.mo'): yield _dirname(mo), [mo] @@ -67,9 +65,7 @@ battery status, and show and modify some of the modifiable features of devices. 'pyudev (>= 0.13)', ], package_dir={'': 'lib'}, - packages=[ - 'hidapi', 'logitech_receiver', 'solaar', 'solaar.ui', 'solaar.cli' - ], + packages=['hidapi', 'logitech_receiver', 'solaar', 'solaar.ui', 'solaar.cli'], data_files=list(_data_files()), scripts=_glob('bin/*'), ) diff --git a/tools/hidconsole b/tools/hidconsole index a497aa1b..7d494b01 100755 --- a/tools/hidconsole +++ b/tools/hidconsole @@ -10,8 +10,7 @@ def init_paths(): import sys import os.path as _path - src_lib = _path.normpath( - _path.join(_path.realpath(sys.path[0]), '..', 'lib')) + src_lib = _path.normpath(_path.join(_path.realpath(sys.path[0]), '..', 'lib')) init_py = _path.join(src_lib, 'hidapi', '__init__.py') if _path.exists(init_py): sys.path[0] = src_lib diff --git a/tools/monitor.py b/tools/monitor.py index d336426d..741385c4 100644 --- a/tools/monitor.py +++ b/tools/monitor.py @@ -16,5 +16,4 @@ def print_event(action, device): print('~~~~ device [%s] %s' % (action, device)) -hidapi.monitor(print_event, DEVICE_UNIFYING_RECEIVER, - DEVICE_UNIFYING_RECEIVER_2, DEVICE_NANO_RECEIVER) +hidapi.monitor(print_event, DEVICE_UNIFYING_RECEIVER, DEVICE_UNIFYING_RECEIVER_2, DEVICE_NANO_RECEIVER)