diff --git a/README.md b/README.md index bcf0b9e5..870b51fe 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ **Solaar** is a Linux device manager for Logitech's -[Unifying Receiver](http://www.logitech.com/en-us/66/6079) peripherals. It is -able to pair/unpair devices to the receiver, and for some devices read battery +[Unifying Receiver](http://logitech.com/en-us/66/6079) peripherals. It is able +to pair/unpair devices to the receiver, and for some devices read battery status. It comes in two flavors, command-line and GUI. Both are able to list the @@ -16,7 +16,7 @@ device, it may be able to read its battery status. A few devices also have extended support, mostly because I was able to directly test on them: -* The [K750 Solar Keyboard](http://www.logitech.com/keyboards/keyboard/devices/7454) +* The [K750 Solar Keyboard](http://logitech.com/keyboards/keyboard/devices/7454) is also queried for its solar charge status. Pressing the Solar key on the keyboard will pop-up the application window and display the current lighting value (Lux) as reported by the keyboard, similar to Logitech's *Solar.app* for @@ -26,9 +26,10 @@ test on them: whether holding `FN` while pressing the function keys will generate the standard keycodes or the special function (yellow icons) keycodes. -* The [M705 Marathon Mouse](http://www.logitech.com/product/marathon-mouse-m705) - supports turning on/off Smooth Scrolling (higher sensitivity on vertical - scrolling with the wheel). +* The [M705 Marathon Mouse](http://logitech.com/product/marathon-mouse-m705) + and [Anywhere MX Mouse](http://logitech.com/product/anywhere-mouse-mx) support + turning on/off Smooth Scrolling (higher sensitivity on vertical scrolling with + the wheel). Extended support for other devices may be added in the future, depending on the documentation available, but the K750 keyboard and M705 mouse are the only @@ -70,8 +71,9 @@ required steps by hand, as the root user: particular system's configuration. If in doubt, replacing `GROUP="plugdev"` with `GROUP=""` should just work. -2. run `udevadm control --reload-rules` to let the udev daemon know about the new - rule +2. run `udevadm control --reload-rules` to let the udev daemon know about the + new rule + 3. physically remove the Unifying Receiver, wait 10 seconds and re-insert it ## Known Issues diff --git a/setup.py b/setup.py index 2248c3a7..bf078cb5 100755 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ from distutils.core import setup setup(name='Solaar', - version='0.8.4', + version='0.8.5', description='Linux devices manager for the Logitech Unifying Receiver.', long_description=''' Solaar is a Linux device manager for Logitech's Unifying Receiver peripherals. diff --git a/src/hidapi/hidconsole.py b/src/hidapi/hidconsole.py index d3228f9d..98f18aed 100644 --- a/src/hidapi/hidconsole.py +++ b/src/hidapi/hidconsole.py @@ -14,7 +14,7 @@ import hidapi # # no Python 3 support :( -read_packet = input +read_packet = raw_input interactive = os.isatty(0) prompt = '?? Input: ' if interactive else '' @@ -121,11 +121,11 @@ def _open(device, hidpp): if not handle: sys.exit("!! Failed to open %s, aborting." % device) - print (".. Opened handle %s, vendor %s product %s serial %s." % ( - repr(handle), - repr(hidapi.get_manufacturer(handle)), - repr(hidapi.get_product(handle)), - repr(hidapi.get_serial(handle)))) + print (".. Opened handle %r, vendor %r product %r serial %r." % ( + handle, + hidapi.get_manufacturer(handle), + hidapi.get_product(handle), + hidapi.get_serial(handle))) if hidpp: if hidapi.get_manufacturer(handle) != b'Logitech': sys.exit("!! Only Logitech devices support the HID++ protocol.") @@ -208,7 +208,7 @@ def main(): except Exception as e: print ('%s: %s' % (type(e).__name__, e)) - print (".. Closing handle", repr(handle)) + print (".. Closing handle %r" % handle) hidapi.close(handle) if interactive: readline.write_history_file(args.history) diff --git a/src/logitech/unifying_receiver/base.py b/src/logitech/unifying_receiver/base.py index b0d98bc6..cba17ddf 100644 --- a/src/logitech/unifying_receiver/base.py +++ b/src/logitech/unifying_receiver/base.py @@ -108,10 +108,10 @@ def close(handle): _hid.close(handle) else: handle.close() - # _log.info("closed receiver handle %s", repr(handle)) + # _log.info("closed receiver handle %r", handle) return True except: - # _log.exception("closing receiver handle %s", repr(handle)) + # _log.exception("closing receiver handle %r", handle) pass return False @@ -141,7 +141,7 @@ def write(handle, devnumber, data): try: _hid.write(int(handle), wdata) except Exception as reason: - _log.error("write failed, assuming handle %s no longer available", repr(handle)) + _log.error("write failed, assuming handle %r no longer available", handle) close(handle) raise NoReceiver(reason=reason) @@ -173,7 +173,7 @@ def _read(handle, timeout): try: data = _hid.read(int(handle), _MAX_READ_SIZE, timeout) except Exception as reason: - _log.error("read failed, assuming handle %s no longer available", repr(handle)) + _log.error("read failed, assuming handle %r no longer available", handle) close(handle) raise NoReceiver(reason=reason) diff --git a/src/logitech/unifying_receiver/common.py b/src/logitech/unifying_receiver/common.py index 622a5853..ab8c4615 100644 --- a/src/logitech/unifying_receiver/common.py +++ b/src/logitech/unifying_receiver/common.py @@ -17,7 +17,7 @@ class NamedInt(int): def __new__(cls, value, name): assert isinstance(name, str) or isinstance(name, unicode) obj = int.__new__(cls, value) - obj.name = name + obj.name = unicode(name) return obj def bytes(self, count=2): @@ -40,12 +40,11 @@ class NamedInt(int): return int(self) def __str__(self): - return str(self.name) - def __unicode__(self): - return unicode(self.name) + return self.name + __unicode__ = __str__ def __repr__(self): - return 'NamedInt(%d, %s)' % (int(self), repr(self.name)) + return 'NamedInt(%d, %r)' % (int(self), self.name) class NamedInts(object): diff --git a/src/logitech/unifying_receiver/descriptors.py b/src/logitech/unifying_receiver/descriptors.py index 73142c92..ef10ed6c 100644 --- a/src/logitech/unifying_receiver/descriptors.py +++ b/src/logitech/unifying_receiver/descriptors.py @@ -89,7 +89,11 @@ _D('Wireless Illuminated Keyboard K800') _D('Zone Touch Mouse T400') _D('Wireless Rechargeable Touchpad T650') _D('Logitech Cube', kind='mouse') -_D('Anywhere Mouse MX', codename='Anywhere MX') +_D('Anywhere Mouse MX', codename='Anywhere MX', + settings=[ + _register_smooth_scroll(0x01, true_value=0x40, mask=0x40), + ], + ) _D('Performance Mouse MX', codename='Performance MX', settings=[ _register_dpi(0x63, _NamedInts.range(0x81, 0x8F, lambda x: '_' + str((x - 0x80) * 100))), diff --git a/src/logitech/unifying_receiver/listener.py b/src/logitech/unifying_receiver/listener.py index dff59c73..9e6b4604 100644 --- a/src/logitech/unifying_receiver/listener.py +++ b/src/logitech/unifying_receiver/listener.py @@ -34,7 +34,7 @@ class ThreadedHandle(object): def __init__(self, initial_handle, path): assert initial_handle if type(initial_handle) != int: - raise TypeError('expected int as initial handle, got %s' % repr(initial_handle)) + raise TypeError('expected int as initial handle, got %r' % initial_handle) assert path self.path = path diff --git a/src/solaar/__init__.py b/src/solaar/__init__.py index e09402f6..b8f5e0e3 100644 --- a/src/solaar/__init__.py +++ b/src/solaar/__init__.py @@ -4,4 +4,4 @@ from __future__ import absolute_import, division, print_function, unicode_literals -__version__ = "0.8.4" +__version__ = "0.8.5" diff --git a/src/solaar/listener.py b/src/solaar/listener.py index e576142c..5f63b7f6 100644 --- a/src/solaar/listener.py +++ b/src/solaar/listener.py @@ -125,7 +125,7 @@ class ReceiverListener(_listener.EventsListener): dev = self.receiver[n.devnumber] if not dev: - _log.warn("received %s for invalid device %d: %s", n, n.devnumber, repr(dev)) + _log.warn("received %s for invalid device %d: %r", n, n.devnumber, dev) return if not already_known: diff --git a/tools/hidconsole b/tools/hidconsole index aed2ce5b..8ea39720 100755 --- a/tools/hidconsole +++ b/tools/hidconsole @@ -7,25 +7,21 @@ from __future__ import absolute_import import sys -def solaar_init(): +def init_paths(): + """Make the app work in the source tree.""" + import sys import os.path as _path - prefix = _path.dirname(_path.dirname(_path.realpath(_path.abspath(__file__)))) - - dist_lib = _path.join(prefix, 'share', 'solaar', 'lib') - src_lib = _path.join(prefix, 'src') - - for location in (dist_lib, src_lib): - init_py = _path.join(location, 'hidapi', '__init__.py') - if _path.exists(init_py): - sys.path.insert(1, location) - break + src_lib = _path.normpath(_path.join(_path.realpath(sys.path[0]), '..', 'src')) + init_py = _path.join(src_lib, 'hidapi', '__init__.py') + if _path.exists(init_py): + sys.path[0] = src_lib if __name__ == '__main__': if sys.version_info >= (2, 8): sys.exit("Python 3 is not supported by hidconsole.") - solaar_init() + init_paths() from hidapi import hidconsole hidconsole.main()