Merge branch 'master' into packaging
This commit is contained in:
commit
a0c8646923
18
README.md
18
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="<your username>"` 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
|
||||
|
|
2
setup.py
2
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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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))),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
__version__ = "0.8.4"
|
||||
__version__ = "0.8.5"
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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')
|
||||
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.insert(1, location)
|
||||
break
|
||||
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()
|
||||
|
|
Loading…
Reference in New Issue