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
|
**Solaar** is a Linux device manager for Logitech's
|
||||||
[Unifying Receiver](http://www.logitech.com/en-us/66/6079) peripherals. It is
|
[Unifying Receiver](http://logitech.com/en-us/66/6079) peripherals. It is able
|
||||||
able to pair/unpair devices to the receiver, and for some devices read battery
|
to pair/unpair devices to the receiver, and for some devices read battery
|
||||||
status.
|
status.
|
||||||
|
|
||||||
It comes in two flavors, command-line and GUI. Both are able to list the
|
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
|
A few devices also have extended support, mostly because I was able to directly
|
||||||
test on them:
|
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
|
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
|
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
|
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
|
whether holding `FN` while pressing the function keys will generate the
|
||||||
standard keycodes or the special function (yellow icons) keycodes.
|
standard keycodes or the special function (yellow icons) keycodes.
|
||||||
|
|
||||||
* The [M705 Marathon Mouse](http://www.logitech.com/product/marathon-mouse-m705)
|
* The [M705 Marathon Mouse](http://logitech.com/product/marathon-mouse-m705)
|
||||||
supports turning on/off Smooth Scrolling (higher sensitivity on vertical
|
and [Anywhere MX Mouse](http://logitech.com/product/anywhere-mouse-mx) support
|
||||||
scrolling with the wheel).
|
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
|
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
|
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"`
|
particular system's configuration. If in doubt, replacing `GROUP="plugdev"`
|
||||||
with `GROUP="<your username>"` should just work.
|
with `GROUP="<your username>"` should just work.
|
||||||
|
|
||||||
2. run `udevadm control --reload-rules` to let the udev daemon know about the new
|
2. run `udevadm control --reload-rules` to let the udev daemon know about the
|
||||||
rule
|
new rule
|
||||||
|
|
||||||
3. physically remove the Unifying Receiver, wait 10 seconds and re-insert it
|
3. physically remove the Unifying Receiver, wait 10 seconds and re-insert it
|
||||||
|
|
||||||
## Known Issues
|
## Known Issues
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -5,7 +5,7 @@ from distutils.core import setup
|
||||||
|
|
||||||
|
|
||||||
setup(name='Solaar',
|
setup(name='Solaar',
|
||||||
version='0.8.4',
|
version='0.8.5',
|
||||||
description='Linux devices manager for the Logitech Unifying Receiver.',
|
description='Linux devices manager for the Logitech Unifying Receiver.',
|
||||||
long_description='''
|
long_description='''
|
||||||
Solaar is a Linux device manager for Logitech's Unifying Receiver peripherals.
|
Solaar is a Linux device manager for Logitech's Unifying Receiver peripherals.
|
||||||
|
|
|
@ -14,7 +14,7 @@ import hidapi
|
||||||
#
|
#
|
||||||
|
|
||||||
# no Python 3 support :(
|
# no Python 3 support :(
|
||||||
read_packet = input
|
read_packet = raw_input
|
||||||
interactive = os.isatty(0)
|
interactive = os.isatty(0)
|
||||||
prompt = '?? Input: ' if interactive else ''
|
prompt = '?? Input: ' if interactive else ''
|
||||||
|
|
||||||
|
@ -121,11 +121,11 @@ def _open(device, hidpp):
|
||||||
if not handle:
|
if not handle:
|
||||||
sys.exit("!! Failed to open %s, aborting." % device)
|
sys.exit("!! Failed to open %s, aborting." % device)
|
||||||
|
|
||||||
print (".. Opened handle %s, vendor %s product %s serial %s." % (
|
print (".. Opened handle %r, vendor %r product %r serial %r." % (
|
||||||
repr(handle),
|
handle,
|
||||||
repr(hidapi.get_manufacturer(handle)),
|
hidapi.get_manufacturer(handle),
|
||||||
repr(hidapi.get_product(handle)),
|
hidapi.get_product(handle),
|
||||||
repr(hidapi.get_serial(handle))))
|
hidapi.get_serial(handle)))
|
||||||
if hidpp:
|
if hidpp:
|
||||||
if hidapi.get_manufacturer(handle) != b'Logitech':
|
if hidapi.get_manufacturer(handle) != b'Logitech':
|
||||||
sys.exit("!! Only Logitech devices support the HID++ protocol.")
|
sys.exit("!! Only Logitech devices support the HID++ protocol.")
|
||||||
|
@ -208,7 +208,7 @@ def main():
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print ('%s: %s' % (type(e).__name__, e))
|
print ('%s: %s' % (type(e).__name__, e))
|
||||||
|
|
||||||
print (".. Closing handle", repr(handle))
|
print (".. Closing handle %r" % handle)
|
||||||
hidapi.close(handle)
|
hidapi.close(handle)
|
||||||
if interactive:
|
if interactive:
|
||||||
readline.write_history_file(args.history)
|
readline.write_history_file(args.history)
|
||||||
|
|
|
@ -108,10 +108,10 @@ def close(handle):
|
||||||
_hid.close(handle)
|
_hid.close(handle)
|
||||||
else:
|
else:
|
||||||
handle.close()
|
handle.close()
|
||||||
# _log.info("closed receiver handle %s", repr(handle))
|
# _log.info("closed receiver handle %r", handle)
|
||||||
return True
|
return True
|
||||||
except:
|
except:
|
||||||
# _log.exception("closing receiver handle %s", repr(handle))
|
# _log.exception("closing receiver handle %r", handle)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
@ -141,7 +141,7 @@ def write(handle, devnumber, data):
|
||||||
try:
|
try:
|
||||||
_hid.write(int(handle), wdata)
|
_hid.write(int(handle), wdata)
|
||||||
except Exception as reason:
|
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)
|
close(handle)
|
||||||
raise NoReceiver(reason=reason)
|
raise NoReceiver(reason=reason)
|
||||||
|
|
||||||
|
@ -173,7 +173,7 @@ def _read(handle, timeout):
|
||||||
try:
|
try:
|
||||||
data = _hid.read(int(handle), _MAX_READ_SIZE, timeout)
|
data = _hid.read(int(handle), _MAX_READ_SIZE, timeout)
|
||||||
except Exception as reason:
|
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)
|
close(handle)
|
||||||
raise NoReceiver(reason=reason)
|
raise NoReceiver(reason=reason)
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ class NamedInt(int):
|
||||||
def __new__(cls, value, name):
|
def __new__(cls, value, name):
|
||||||
assert isinstance(name, str) or isinstance(name, unicode)
|
assert isinstance(name, str) or isinstance(name, unicode)
|
||||||
obj = int.__new__(cls, value)
|
obj = int.__new__(cls, value)
|
||||||
obj.name = name
|
obj.name = unicode(name)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def bytes(self, count=2):
|
def bytes(self, count=2):
|
||||||
|
@ -40,12 +40,11 @@ class NamedInt(int):
|
||||||
return int(self)
|
return int(self)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.name)
|
return self.name
|
||||||
def __unicode__(self):
|
__unicode__ = __str__
|
||||||
return unicode(self.name)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return 'NamedInt(%d, %s)' % (int(self), repr(self.name))
|
return 'NamedInt(%d, %r)' % (int(self), self.name)
|
||||||
|
|
||||||
|
|
||||||
class NamedInts(object):
|
class NamedInts(object):
|
||||||
|
|
|
@ -89,7 +89,11 @@ _D('Wireless Illuminated Keyboard K800')
|
||||||
_D('Zone Touch Mouse T400')
|
_D('Zone Touch Mouse T400')
|
||||||
_D('Wireless Rechargeable Touchpad T650')
|
_D('Wireless Rechargeable Touchpad T650')
|
||||||
_D('Logitech Cube', kind='mouse')
|
_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',
|
_D('Performance Mouse MX', codename='Performance MX',
|
||||||
settings=[
|
settings=[
|
||||||
_register_dpi(0x63, _NamedInts.range(0x81, 0x8F, lambda x: '_' + str((x - 0x80) * 100))),
|
_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):
|
def __init__(self, initial_handle, path):
|
||||||
assert initial_handle
|
assert initial_handle
|
||||||
if type(initial_handle) != int:
|
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
|
assert path
|
||||||
self.path = path
|
self.path = path
|
||||||
|
|
|
@ -4,4 +4,4 @@
|
||||||
|
|
||||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
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]
|
dev = self.receiver[n.devnumber]
|
||||||
|
|
||||||
if not dev:
|
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
|
return
|
||||||
|
|
||||||
if not already_known:
|
if not already_known:
|
||||||
|
|
|
@ -7,25 +7,21 @@ from __future__ import absolute_import
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
def solaar_init():
|
def init_paths():
|
||||||
|
"""Make the app work in the source tree."""
|
||||||
|
import sys
|
||||||
import os.path as _path
|
import os.path as _path
|
||||||
|
|
||||||
prefix = _path.dirname(_path.dirname(_path.realpath(_path.abspath(__file__))))
|
src_lib = _path.normpath(_path.join(_path.realpath(sys.path[0]), '..', 'src'))
|
||||||
|
init_py = _path.join(src_lib, 'hidapi', '__init__.py')
|
||||||
dist_lib = _path.join(prefix, 'share', 'solaar', 'lib')
|
if _path.exists(init_py):
|
||||||
src_lib = _path.join(prefix, 'src')
|
sys.path[0] = src_lib
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if sys.version_info >= (2, 8):
|
if sys.version_info >= (2, 8):
|
||||||
sys.exit("Python 3 is not supported by hidconsole.")
|
sys.exit("Python 3 is not supported by hidconsole.")
|
||||||
|
|
||||||
solaar_init()
|
init_paths()
|
||||||
from hidapi import hidconsole
|
from hidapi import hidconsole
|
||||||
hidconsole.main()
|
hidconsole.main()
|
||||||
|
|
Loading…
Reference in New Issue