yapf: adjust style to not indent closing brackets
Signed-off-by: Filipe Laíns <lains@archlinux.org>
This commit is contained in:
parent
bbaa144397
commit
27c90fa736
|
@ -36,8 +36,10 @@ def init_paths():
|
|||
sys.path[0].encode(sys.getfilesystemencoding())
|
||||
|
||||
except UnicodeError:
|
||||
sys.stderr.write('ERROR: Solaar cannot recognize encoding of filesystem path, '
|
||||
'this may happen because non UTF-8 characters in the pathname.\n')
|
||||
sys.stderr.write(
|
||||
'ERROR: Solaar cannot recognize encoding of filesystem path, '
|
||||
'this may happen because non UTF-8 characters in the pathname.\n'
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
prefix = _path.normpath(_path.join(_path.realpath(decoded_path), '..'))
|
||||
|
|
|
@ -80,11 +80,13 @@ def _print(marker, data, scroll=False):
|
|||
|
||||
if interactive and scroll:
|
||||
# scroll the entire screen above the current line up by 1 line
|
||||
sys.stdout.write('\033[s' # save cursor position
|
||||
'\033[S' # scroll up
|
||||
'\033[A' # cursor up
|
||||
'\033[L' # insert 1 line
|
||||
'\033[G') # move cursor to column 1
|
||||
sys.stdout.write(
|
||||
'\033[s' # save cursor position
|
||||
'\033[S' # scroll up
|
||||
'\033[A' # cursor up
|
||||
'\033[L' # insert 1 line
|
||||
'\033[G'
|
||||
) # move cursor to column 1
|
||||
sys.stdout.write(s)
|
||||
if interactive and scroll:
|
||||
# restore cursor position
|
||||
|
@ -164,8 +166,10 @@ def _open(args):
|
|||
if not handle:
|
||||
sys.exit('!! Failed to open %s, aborting.' % device)
|
||||
|
||||
print('.. Opened handle %r, vendor %r product %r serial %r.' %
|
||||
(handle, _hid.get_manufacturer(handle), _hid.get_product(handle), _hid.get_serial(handle)))
|
||||
print(
|
||||
'.. Opened handle %r, vendor %r product %r serial %r.' %
|
||||
(handle, _hid.get_manufacturer(handle), _hid.get_product(handle), _hid.get_serial(handle))
|
||||
)
|
||||
if args.hidpp:
|
||||
if _hid.get_manufacturer(handle) != b'Logitech':
|
||||
sys.exit('!! Only Logitech devices support the HID++ protocol.')
|
||||
|
@ -188,10 +192,12 @@ def _parse_arguments():
|
|||
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(
|
||||
'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()
|
||||
|
||||
|
||||
|
|
|
@ -42,17 +42,19 @@ from pyudev import Monitor as _Monitor
|
|||
|
||||
native_implementation = 'udev'
|
||||
|
||||
DeviceInfo = namedtuple('DeviceInfo', [
|
||||
'path',
|
||||
'vendor_id',
|
||||
'product_id',
|
||||
'serial',
|
||||
'release',
|
||||
'manufacturer',
|
||||
'product',
|
||||
'interface',
|
||||
'driver',
|
||||
])
|
||||
DeviceInfo = namedtuple(
|
||||
'DeviceInfo', [
|
||||
'path',
|
||||
'vendor_id',
|
||||
'product_id',
|
||||
'serial',
|
||||
'release',
|
||||
'manufacturer',
|
||||
'product',
|
||||
'interface',
|
||||
'driver',
|
||||
]
|
||||
)
|
||||
del namedtuple
|
||||
|
||||
#
|
||||
|
@ -121,29 +123,33 @@ def _match(action, device, filter):
|
|||
return
|
||||
|
||||
attrs = usb_device.attributes
|
||||
d_info = DeviceInfo(path=device.device_node,
|
||||
vendor_id=vid[-4:],
|
||||
product_id=pid[-4:],
|
||||
serial=hid_device.get('HID_UNIQ'),
|
||||
release=attrs.get('bcdDevice'),
|
||||
manufacturer=attrs.get('manufacturer'),
|
||||
product=attrs.get('product'),
|
||||
interface=usb_interface,
|
||||
driver=hid_driver_name)
|
||||
d_info = DeviceInfo(
|
||||
path=device.device_node,
|
||||
vendor_id=vid[-4:],
|
||||
product_id=pid[-4:],
|
||||
serial=hid_device.get('HID_UNIQ'),
|
||||
release=attrs.get('bcdDevice'),
|
||||
manufacturer=attrs.get('manufacturer'),
|
||||
product=attrs.get('product'),
|
||||
interface=usb_interface,
|
||||
driver=hid_driver_name
|
||||
)
|
||||
return d_info
|
||||
|
||||
elif action == 'remove':
|
||||
# print (dict(device), dict(usb_device))
|
||||
|
||||
d_info = DeviceInfo(path=device.device_node,
|
||||
vendor_id=vid[-4:],
|
||||
product_id=pid[-4:],
|
||||
serial=None,
|
||||
release=None,
|
||||
manufacturer=None,
|
||||
product=None,
|
||||
interface=None,
|
||||
driver=None)
|
||||
d_info = DeviceInfo(
|
||||
path=device.device_node,
|
||||
vendor_id=vid[-4:],
|
||||
product_id=pid[-4:],
|
||||
serial=None,
|
||||
release=None,
|
||||
manufacturer=None,
|
||||
product=None,
|
||||
interface=None,
|
||||
driver=None
|
||||
)
|
||||
return d_info
|
||||
|
||||
|
||||
|
|
|
@ -287,20 +287,22 @@ def make_notification(devnumber, data):
|
|||
|
||||
address = ord(data[1:2])
|
||||
if (
|
||||
# standard HID++ 1.0 notification, SubId may be 0x40 - 0x7F
|
||||
# standard HID++ 1.0 notification, SubId may be 0x40 - 0x7F
|
||||
(sub_id >= 0x40) or # noqa: E131
|
||||
# custom HID++1.0 battery events, where SubId is 0x07/0x0D
|
||||
# custom HID++1.0 battery events, where SubId is 0x07/0x0D
|
||||
(sub_id in (0x07, 0x0D) and len(data) == 5 and data[4:5] == b'\x00') or
|
||||
# custom HID++1.0 illumination event, where SubId is 0x17
|
||||
# custom HID++1.0 illumination event, where SubId is 0x17
|
||||
(sub_id == 0x17 and len(data) == 5) or
|
||||
# HID++ 2.0 feature notifications have the SoftwareID 0
|
||||
(address & 0x0F == 0x00)): # noqa: E129
|
||||
# HID++ 2.0 feature notifications have the SoftwareID 0
|
||||
(address & 0x0F == 0x00)
|
||||
): # noqa: E129
|
||||
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.__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
|
||||
|
@ -374,15 +376,19 @@ 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]:
|
||||
# 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])
|
||||
_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]:
|
||||
|
@ -423,8 +429,10 @@ 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)
|
||||
|
||||
|
||||
|
|
|
@ -272,7 +272,8 @@ FirmwareInfo = namedtuple('FirmwareInfo', ['kind', 'name', 'version', 'extras'])
|
|||
"""Reprogrammable keys information."""
|
||||
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
|
||||
|
|
|
@ -31,8 +31,9 @@ from .settings_templates import RegisterSettings as _RS
|
|||
#
|
||||
#
|
||||
|
||||
_DeviceDescriptor = namedtuple('_DeviceDescriptor',
|
||||
('name', 'kind', 'wpid', 'codename', 'protocol', 'registers', 'settings', 'persister'))
|
||||
_DeviceDescriptor = namedtuple(
|
||||
'_DeviceDescriptor', ('name', 'kind', 'wpid', 'codename', 'protocol', 'registers', 'settings', 'persister')
|
||||
)
|
||||
del namedtuple
|
||||
|
||||
DEVICES = {}
|
||||
|
@ -42,8 +43,10 @@ def _D(name, codename=None, kind=None, wpid=None, protocol=None, registers=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
|
||||
|
@ -70,14 +73,16 @@ def _D(name, codename=None, kind=None, wpid=None, protocol=None, registers=None,
|
|||
elif w[0:1] == '2':
|
||||
assert kind in (_DK.keyboard, _DK.numpad), '%s has protocol %0.1f, wpid %s' % (name, protocol, w)
|
||||
|
||||
device_descriptor = _DeviceDescriptor(name=name,
|
||||
kind=kind,
|
||||
wpid=wpid,
|
||||
codename=codename,
|
||||
protocol=protocol,
|
||||
registers=registers,
|
||||
settings=settings,
|
||||
persister=persister)
|
||||
device_descriptor = _DeviceDescriptor(
|
||||
name=name,
|
||||
kind=kind,
|
||||
wpid=wpid,
|
||||
codename=codename,
|
||||
protocol=protocol,
|
||||
registers=registers,
|
||||
settings=settings,
|
||||
persister=persister
|
||||
)
|
||||
|
||||
assert codename not in DEVICES, 'duplicate codename in device descriptors: %s' % (DEVICES[codename], )
|
||||
DEVICES[codename] = device_descriptor
|
||||
|
@ -293,24 +298,28 @@ _D(
|
|||
|
||||
_D('Wireless Mouse M150', protocol=2.0, wpid='4022')
|
||||
_D('Wireless Mouse M175', protocol=2.0, wpid='4008')
|
||||
_D('Wireless Mouse M185 new',
|
||||
codename='M185n',
|
||||
protocol=4.5,
|
||||
wpid='4054',
|
||||
settings=[
|
||||
_FS.lowres_smooth_scroll(),
|
||||
_FS.pointer_speed(),
|
||||
])
|
||||
_D(
|
||||
'Wireless Mouse M185 new',
|
||||
codename='M185n',
|
||||
protocol=4.5,
|
||||
wpid='4054',
|
||||
settings=[
|
||||
_FS.lowres_smooth_scroll(),
|
||||
_FS.pointer_speed(),
|
||||
]
|
||||
)
|
||||
# Apparently Logitech uses wpid 4055 for three different mice
|
||||
# That's not so strange, as M185 is used on both Unifying-ready and non-Unifying-ready mice
|
||||
_D('Wireless Mouse M185/M235/M310',
|
||||
codename='M185/M235/M310',
|
||||
protocol=4.5,
|
||||
wpid='4055',
|
||||
settings=[
|
||||
_FS.lowres_smooth_scroll(),
|
||||
_FS.pointer_speed(),
|
||||
])
|
||||
_D(
|
||||
'Wireless Mouse M185/M235/M310',
|
||||
codename='M185/M235/M310',
|
||||
protocol=4.5,
|
||||
wpid='4055',
|
||||
settings=[
|
||||
_FS.lowres_smooth_scroll(),
|
||||
_FS.pointer_speed(),
|
||||
]
|
||||
)
|
||||
_D('Wireless Mouse M185', protocol=2.0, wpid='4038')
|
||||
_D('Wireless Mouse M187', protocol=2.0, wpid='4019')
|
||||
_D('Wireless Mouse M215', protocol=1.0, wpid='1020')
|
||||
|
@ -390,15 +399,17 @@ _D(
|
|||
_RS.side_scroll(),
|
||||
],
|
||||
)
|
||||
_D('Marathon Mouse M705 (M-R0073)',
|
||||
codename='M705 (M-R0073)',
|
||||
protocol=4.5,
|
||||
wpid='406D',
|
||||
settings=[
|
||||
_FS.hires_smooth_invert(),
|
||||
_FS.hires_smooth_resolution(),
|
||||
_FS.pointer_speed(),
|
||||
])
|
||||
_D(
|
||||
'Marathon Mouse M705 (M-R0073)',
|
||||
codename='M705 (M-R0073)',
|
||||
protocol=4.5,
|
||||
wpid='406D',
|
||||
settings=[
|
||||
_FS.hires_smooth_invert(),
|
||||
_FS.hires_smooth_resolution(),
|
||||
_FS.pointer_speed(),
|
||||
]
|
||||
)
|
||||
_D('Zone Touch Mouse T400')
|
||||
_D('Touch Mouse T620', protocol=2.0)
|
||||
_D('Logitech Cube', kind=_DK.mouse, protocol=2.0)
|
||||
|
|
|
@ -38,17 +38,19 @@ del getLogger
|
|||
|
||||
DEVICE_KIND = _NamedInts(keyboard=0x01, mouse=0x02, numpad=0x03, presenter=0x04, trackball=0x08, touchpad=0x09)
|
||||
|
||||
POWER_SWITCH_LOCATION = _NamedInts(base=0x01,
|
||||
top_case=0x02,
|
||||
edge_of_top_right_corner=0x03,
|
||||
top_left_corner=0x05,
|
||||
bottom_left_corner=0x06,
|
||||
top_right_corner=0x07,
|
||||
bottom_right_corner=0x08,
|
||||
top_edge=0x09,
|
||||
right_edge=0x0A,
|
||||
left_edge=0x0B,
|
||||
bottom_edge=0x0C)
|
||||
POWER_SWITCH_LOCATION = _NamedInts(
|
||||
base=0x01,
|
||||
top_case=0x02,
|
||||
edge_of_top_right_corner=0x03,
|
||||
top_left_corner=0x05,
|
||||
bottom_left_corner=0x06,
|
||||
top_right_corner=0x07,
|
||||
bottom_right_corner=0x08,
|
||||
top_edge=0x09,
|
||||
right_edge=0x0A,
|
||||
left_edge=0x0B,
|
||||
bottom_edge=0x0C
|
||||
)
|
||||
|
||||
# Some flags are used both by devices and receivers. The Logitech documentation
|
||||
# mentions that the first and last (third) byte are used for devices while the
|
||||
|
@ -72,18 +74,20 @@ NOTIFICATION_FLAG = _NamedInts(
|
|||
wireless=0x000100, # notify when the device wireless goes on/off-line
|
||||
)
|
||||
|
||||
ERROR = _NamedInts(invalid_SubID__command=0x01,
|
||||
invalid_address=0x02,
|
||||
invalid_value=0x03,
|
||||
connection_request_failed=0x04,
|
||||
too_many_devices=0x05,
|
||||
already_exists=0x06,
|
||||
busy=0x07,
|
||||
unknown_device=0x08,
|
||||
resource_error=0x09,
|
||||
request_unavailable=0x0A,
|
||||
unsupported_parameter_value=0x0B,
|
||||
wrong_pin_code=0x0C)
|
||||
ERROR = _NamedInts(
|
||||
invalid_SubID__command=0x01,
|
||||
invalid_address=0x02,
|
||||
invalid_value=0x03,
|
||||
connection_request_failed=0x04,
|
||||
too_many_devices=0x05,
|
||||
already_exists=0x06,
|
||||
busy=0x07,
|
||||
unknown_device=0x08,
|
||||
resource_error=0x09,
|
||||
request_unavailable=0x0A,
|
||||
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)
|
||||
|
||||
|
@ -167,8 +171,10 @@ 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:
|
||||
|
@ -179,7 +185,8 @@ def parse_battery_status(register, reply):
|
|||
else BATTERY_APPOX.low if status_byte == 3 # low
|
||||
else BATTERY_APPOX.critical if status_byte == 1 # critical
|
||||
# pure 'charging' notifications may come without a status
|
||||
else BATTERY_APPOX.empty)
|
||||
else BATTERY_APPOX.empty
|
||||
)
|
||||
|
||||
charging_byte = ord(reply[1:2])
|
||||
if charging_byte == 0x00:
|
||||
|
|
|
@ -160,26 +160,23 @@ FEATURE._fallback = lambda x: 'unknown:%04X' % x
|
|||
|
||||
FEATURE_FLAG = _NamedInts(internal=0x20, hidden=0x40, obsolete=0x80)
|
||||
|
||||
DEVICE_KIND = _NamedInts(keyboard=0x00,
|
||||
remote_control=0x01,
|
||||
numpad=0x02,
|
||||
mouse=0x03,
|
||||
touchpad=0x04,
|
||||
trackball=0x05,
|
||||
presenter=0x06,
|
||||
receiver=0x07)
|
||||
DEVICE_KIND = _NamedInts(
|
||||
keyboard=0x00, remote_control=0x01, numpad=0x02, mouse=0x03, touchpad=0x04, trackball=0x05, presenter=0x06, receiver=0x07
|
||||
)
|
||||
|
||||
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_STATUS = _NamedInts(discharging=0x00,
|
||||
recharging=0x01,
|
||||
almost_full=0x02,
|
||||
full=0x03,
|
||||
slow_recharge=0x04,
|
||||
invalid_battery=0x05,
|
||||
thermal_error=0x06)
|
||||
BATTERY_STATUS = _NamedInts(
|
||||
discharging=0x00,
|
||||
recharging=0x01,
|
||||
almost_full=0x02,
|
||||
full=0x03,
|
||||
slow_recharge=0x04,
|
||||
invalid_battery=0x05,
|
||||
thermal_error=0x06
|
||||
)
|
||||
|
||||
CHARGE_STATUS = _NamedInts(charging=0x00, full=0x01, not_charging=0x02, error=0x07)
|
||||
|
||||
|
@ -187,15 +184,17 @@ CHARGE_LEVEL = _NamedInts(average=50, full=90, critical=5)
|
|||
|
||||
CHARGE_TYPE = _NamedInts(standard=0x00, fast=0x01, slow=0x02)
|
||||
|
||||
ERROR = _NamedInts(unknown=0x01,
|
||||
invalid_argument=0x02,
|
||||
out_of_range=0x03,
|
||||
hardware_error=0x04,
|
||||
logitech_internal=0x05,
|
||||
invalid_feature_index=0x06,
|
||||
invalid_function=0x07,
|
||||
busy=0x08,
|
||||
unsupported=0x09)
|
||||
ERROR = _NamedInts(
|
||||
unknown=0x01,
|
||||
invalid_argument=0x02,
|
||||
out_of_range=0x03,
|
||||
hardware_error=0x04,
|
||||
logitech_internal=0x05,
|
||||
invalid_feature_index=0x06,
|
||||
invalid_function=0x07,
|
||||
busy=0x08,
|
||||
unsupported=0x09
|
||||
)
|
||||
|
||||
#
|
||||
#
|
||||
|
@ -388,8 +387,9 @@ class KeysArray(object):
|
|||
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])
|
||||
# if key not mapped map it to itself for display
|
||||
|
@ -401,8 +401,9 @@ 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]
|
||||
|
||||
|
@ -517,8 +518,10 @@ 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
|
||||
|
||||
|
||||
|
@ -553,8 +556,10 @@ def decipher_voltage(voltage_report):
|
|||
charge_lvl = CHARGE_LEVEL.critical
|
||||
|
||||
if _log.isEnabledFor(_DEBUG):
|
||||
_log.debug('device ???, battery voltage %d mV, charging = %s, charge status %d = %s, charge level %s, charge type %s',
|
||||
voltage, status, (flags & 0x03), charge_sts, charge_lvl, charge_type)
|
||||
_log.debug(
|
||||
'device ???, battery voltage %d mV, charging = %s, charge status %d = %s, charge level %s, charge type %s',
|
||||
voltage, status, (flags & 0x03), charge_sts, charge_lvl, charge_type
|
||||
)
|
||||
|
||||
return charge_lvl, status, voltage, charge_sts, charge_type
|
||||
|
||||
|
@ -587,8 +592,9 @@ def get_vertical_scrolling_info(device):
|
|||
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',
|
||||
'reserved')[roller]
|
||||
roller_type = (
|
||||
'reserved', 'standard', 'reserved', '3G', 'micro', 'normal touch pad', 'inverted touch pad', 'reserved'
|
||||
)[roller]
|
||||
return {'roller': roller_type, 'ratchet': ratchet, 'lines': lines}
|
||||
|
||||
|
||||
|
|
|
@ -191,11 +191,13 @@ def _process_hidpp10_notification(device, status, n):
|
|||
|
||||
# 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])
|
||||
|
@ -207,8 +209,10 @@ 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:
|
||||
|
|
|
@ -266,10 +266,12 @@ class PairedDevice(object):
|
|||
return False
|
||||
|
||||
if enable:
|
||||
set_flag_bits = (_hidpp10.NOTIFICATION_FLAG.battery_status
|
||||
| _hidpp10.NOTIFICATION_FLAG.keyboard_illumination
|
||||
| _hidpp10.NOTIFICATION_FLAG.wireless
|
||||
| _hidpp10.NOTIFICATION_FLAG.software_present)
|
||||
set_flag_bits = (
|
||||
_hidpp10.NOTIFICATION_FLAG.battery_status
|
||||
| _hidpp10.NOTIFICATION_FLAG.keyboard_illumination
|
||||
| _hidpp10.NOTIFICATION_FLAG.wireless
|
||||
| _hidpp10.NOTIFICATION_FLAG.software_present
|
||||
)
|
||||
else:
|
||||
set_flag_bits = 0
|
||||
ok = _hidpp10.set_notification_flags(self, set_flag_bits)
|
||||
|
@ -361,8 +363,9 @@ 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._str = '<%s(%s,%s%s)>' % (
|
||||
self.name.replace(' ', ''), self.path, '' if isinstance(self.handle, int) else 'T', self.handle
|
||||
)
|
||||
|
||||
self._firmware = None
|
||||
self._devices = {}
|
||||
|
@ -398,9 +401,11 @@ class Receiver(object):
|
|||
return False
|
||||
|
||||
if enable:
|
||||
set_flag_bits = (_hidpp10.NOTIFICATION_FLAG.battery_status
|
||||
| _hidpp10.NOTIFICATION_FLAG.wireless
|
||||
| _hidpp10.NOTIFICATION_FLAG.software_present)
|
||||
set_flag_bits = (
|
||||
_hidpp10.NOTIFICATION_FLAG.battery_status
|
||||
| _hidpp10.NOTIFICATION_FLAG.wireless
|
||||
| _hidpp10.NOTIFICATION_FLAG.software_present
|
||||
)
|
||||
else:
|
||||
set_flag_bits = 0
|
||||
ok = _hidpp10.set_notification_flags(self, set_flag_bits)
|
||||
|
|
|
@ -167,8 +167,9 @@ class Setting(object):
|
|||
def __str__(self):
|
||||
if hasattr(self, '_value'):
|
||||
assert hasattr(self, '_device')
|
||||
return '<Setting([%s:%s] %s:%s=%s)>' % (self._rw.kind, self._validator.kind, self._device.codename, self.name,
|
||||
self._value)
|
||||
return '<Setting([%s:%s] %s:%s=%s)>' % (
|
||||
self._rw.kind, self._validator.kind, self._device.codename, self.name, self._value
|
||||
)
|
||||
return '<Setting([%s:%s] %s)>' % (self._rw.kind, self._validator.kind, self.name)
|
||||
|
||||
__unicode__ = __repr__ = __str__
|
||||
|
@ -531,8 +532,10 @@ class BooleanValidator(object):
|
|||
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,
|
||||
self.mask)
|
||||
_log.warn(
|
||||
'BooleanValidator: reply %02X mismatched %02X/%02X/%02X', reply_value, self.true_value, self.false_value,
|
||||
self.mask
|
||||
)
|
||||
return False
|
||||
|
||||
count = len(self.mask)
|
||||
|
@ -701,8 +704,8 @@ 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):
|
||||
|
|
|
@ -57,14 +57,16 @@ _F = _hidpp20.FEATURE
|
|||
#
|
||||
|
||||
|
||||
def register_toggle(name,
|
||||
register,
|
||||
true_value=_BooleanV.default_true,
|
||||
false_value=_BooleanV.default_false,
|
||||
mask=_BooleanV.default_mask,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None):
|
||||
def register_toggle(
|
||||
name,
|
||||
register,
|
||||
true_value=_BooleanV.default_true,
|
||||
false_value=_BooleanV.default_false,
|
||||
mask=_BooleanV.default_mask,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None
|
||||
):
|
||||
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)
|
||||
|
@ -77,109 +79,114 @@ def register_choices(name, register, choices, kind=_KIND.choice, label=None, des
|
|||
return _Setting(name, rw, validator, kind=kind, label=label, description=description, device_kind=device_kind)
|
||||
|
||||
|
||||
def feature_toggle(name,
|
||||
feature,
|
||||
read_function_id=_FeatureRW.default_read_fnid,
|
||||
write_function_id=_FeatureRW.default_write_fnid,
|
||||
true_value=_BooleanV.default_true,
|
||||
false_value=_BooleanV.default_false,
|
||||
mask=_BooleanV.default_mask,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None):
|
||||
def feature_toggle(
|
||||
name,
|
||||
feature,
|
||||
read_function_id=_FeatureRW.default_read_fnid,
|
||||
write_function_id=_FeatureRW.default_write_fnid,
|
||||
true_value=_BooleanV.default_true,
|
||||
false_value=_BooleanV.default_false,
|
||||
mask=_BooleanV.default_mask,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None
|
||||
):
|
||||
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)
|
||||
|
||||
|
||||
def feature_bitfield_toggle(name,
|
||||
feature,
|
||||
options,
|
||||
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(
|
||||
name,
|
||||
feature,
|
||||
options,
|
||||
read_function_id=_FeatureRW.default_read_fnid,
|
||||
write_function_id=_FeatureRW.default_write_fnid,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None
|
||||
):
|
||||
assert options
|
||||
validator = _BitFieldV(options)
|
||||
rw = _FeatureRW(feature, read_function_id, write_function_id)
|
||||
return _BitFieldSetting(name,
|
||||
rw,
|
||||
validator,
|
||||
feature=feature,
|
||||
label=label,
|
||||
description=description,
|
||||
device_kind=device_kind)
|
||||
return _BitFieldSetting(
|
||||
name, rw, validator, feature=feature, label=label, description=description, 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,
|
||||
feature,
|
||||
options,
|
||||
read_function_id=read_function_id,
|
||||
write_function_id=write_function_id,
|
||||
label=label,
|
||||
description=description,
|
||||
device_kind=device_kind)
|
||||
setting = feature_bitfield_toggle(
|
||||
name,
|
||||
feature,
|
||||
options,
|
||||
read_function_id=read_function_id,
|
||||
write_function_id=write_function_id,
|
||||
label=label,
|
||||
description=description,
|
||||
device_kind=device_kind
|
||||
)
|
||||
return setting(device)
|
||||
|
||||
instantiate._rw_kind = _FeatureRW.kind
|
||||
return instantiate
|
||||
|
||||
|
||||
def feature_choices(name,
|
||||
feature,
|
||||
choices,
|
||||
read_function_id,
|
||||
write_function_id,
|
||||
bytes_count=None,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None):
|
||||
def feature_choices(
|
||||
name,
|
||||
feature,
|
||||
choices,
|
||||
read_function_id,
|
||||
write_function_id,
|
||||
bytes_count=None,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None
|
||||
):
|
||||
assert choices
|
||||
validator = _ChoicesV(choices, bytes_count=bytes_count)
|
||||
rw = _FeatureRW(feature, read_function_id, write_function_id)
|
||||
return _Setting(name,
|
||||
rw,
|
||||
validator,
|
||||
feature=feature,
|
||||
kind=_KIND.choice,
|
||||
label=label,
|
||||
description=description,
|
||||
device_kind=device_kind)
|
||||
return _Setting(
|
||||
name, rw, validator, feature=feature, kind=_KIND.choice, label=label, description=description, device_kind=device_kind
|
||||
)
|
||||
|
||||
|
||||
def feature_choices_dynamic(name,
|
||||
feature,
|
||||
choices_callback,
|
||||
read_function_id,
|
||||
write_function_id,
|
||||
bytes_count=None,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None):
|
||||
def feature_choices_dynamic(
|
||||
name,
|
||||
feature,
|
||||
choices_callback,
|
||||
read_function_id,
|
||||
write_function_id,
|
||||
bytes_count=None,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None
|
||||
):
|
||||
# Proxy that obtains choices dynamically from a device
|
||||
def instantiate(device):
|
||||
# Obtain choices for this feature
|
||||
choices = choices_callback(device)
|
||||
setting = feature_choices(name,
|
||||
feature,
|
||||
choices,
|
||||
read_function_id,
|
||||
write_function_id,
|
||||
bytes_count=bytes_count,
|
||||
label=label,
|
||||
description=description,
|
||||
device_kind=device_kind)
|
||||
setting = feature_choices(
|
||||
name,
|
||||
feature,
|
||||
choices,
|
||||
read_function_id,
|
||||
write_function_id,
|
||||
bytes_count=bytes_count,
|
||||
label=label,
|
||||
description=description,
|
||||
device_kind=device_kind
|
||||
)
|
||||
return setting(device)
|
||||
|
||||
instantiate._rw_kind = _FeatureRW.kind
|
||||
|
@ -189,92 +196,99 @@ def feature_choices_dynamic(name,
|
|||
# maintain a mapping from keys (NamedInts) to one of a list of choices (NamedInts), default is first one
|
||||
# the setting is stored as a JSON-compatible object mapping the key int (as a string) to the choice int
|
||||
# extra_default is an extra value that comes from the device that also means the default
|
||||
def feature_map_choices(name,
|
||||
feature,
|
||||
choicesmap,
|
||||
read_function_id,
|
||||
write_function_id,
|
||||
key_bytes_count=None,
|
||||
skip_bytes_count=None,
|
||||
value_bytes_count=None,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None,
|
||||
extra_default=None):
|
||||
def feature_map_choices(
|
||||
name,
|
||||
feature,
|
||||
choicesmap,
|
||||
read_function_id,
|
||||
write_function_id,
|
||||
key_bytes_count=None,
|
||||
skip_bytes_count=None,
|
||||
value_bytes_count=None,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None,
|
||||
extra_default=None
|
||||
):
|
||||
assert choicesmap
|
||||
validator = _ChoicesMapV(choicesmap,
|
||||
key_bytes_count=key_bytes_count,
|
||||
skip_bytes_count=skip_bytes_count,
|
||||
value_bytes_count=value_bytes_count,
|
||||
extra_default=extra_default)
|
||||
validator = _ChoicesMapV(
|
||||
choicesmap,
|
||||
key_bytes_count=key_bytes_count,
|
||||
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)
|
||||
return _Settings(name,
|
||||
rw,
|
||||
validator,
|
||||
feature=feature,
|
||||
kind=_KIND.map_choice,
|
||||
label=label,
|
||||
description=description,
|
||||
device_kind=device_kind)
|
||||
return _Settings(
|
||||
name,
|
||||
rw,
|
||||
validator,
|
||||
feature=feature,
|
||||
kind=_KIND.map_choice,
|
||||
label=label,
|
||||
description=description,
|
||||
device_kind=device_kind
|
||||
)
|
||||
|
||||
|
||||
def feature_map_choices_dynamic(name,
|
||||
feature,
|
||||
choices_callback,
|
||||
read_function_id,
|
||||
write_function_id,
|
||||
key_bytes_count=None,
|
||||
skip_bytes_count=None,
|
||||
value_bytes_count=None,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None,
|
||||
extra_default=None):
|
||||
def feature_map_choices_dynamic(
|
||||
name,
|
||||
feature,
|
||||
choices_callback,
|
||||
read_function_id,
|
||||
write_function_id,
|
||||
key_bytes_count=None,
|
||||
skip_bytes_count=None,
|
||||
value_bytes_count=None,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None,
|
||||
extra_default=None
|
||||
):
|
||||
# Proxy that obtains choices dynamically from a device
|
||||
def instantiate(device):
|
||||
choices = choices_callback(device)
|
||||
if not choices: # no choices, so don't create a Setting
|
||||
return None
|
||||
setting = feature_map_choices(name,
|
||||
feature,
|
||||
choices,
|
||||
read_function_id,
|
||||
write_function_id,
|
||||
key_bytes_count=key_bytes_count,
|
||||
skip_bytes_count=skip_bytes_count,
|
||||
value_bytes_count=value_bytes_count,
|
||||
label=label,
|
||||
description=description,
|
||||
device_kind=device_kind,
|
||||
extra_default=extra_default)
|
||||
setting = feature_map_choices(
|
||||
name,
|
||||
feature,
|
||||
choices,
|
||||
read_function_id,
|
||||
write_function_id,
|
||||
key_bytes_count=key_bytes_count,
|
||||
skip_bytes_count=skip_bytes_count,
|
||||
value_bytes_count=value_bytes_count,
|
||||
label=label,
|
||||
description=description,
|
||||
device_kind=device_kind,
|
||||
extra_default=extra_default
|
||||
)
|
||||
return setting(device)
|
||||
|
||||
instantiate._rw_kind = _FeatureRWMap.kind
|
||||
return instantiate
|
||||
|
||||
|
||||
def feature_range(name,
|
||||
feature,
|
||||
min_value,
|
||||
max_value,
|
||||
read_function_id=_FeatureRW.default_read_fnid,
|
||||
write_function_id=_FeatureRW.default_write_fnid,
|
||||
rw=None,
|
||||
bytes_count=None,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None):
|
||||
def feature_range(
|
||||
name,
|
||||
feature,
|
||||
min_value,
|
||||
max_value,
|
||||
read_function_id=_FeatureRW.default_read_fnid,
|
||||
write_function_id=_FeatureRW.default_write_fnid,
|
||||
rw=None,
|
||||
bytes_count=None,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None
|
||||
):
|
||||
validator = _RangeV(min_value, max_value, bytes_count=bytes_count)
|
||||
if rw is None:
|
||||
rw = _FeatureRW(feature, read_function_id, write_function_id)
|
||||
return _Setting(name,
|
||||
rw,
|
||||
validator,
|
||||
feature=feature,
|
||||
kind=_KIND.range,
|
||||
label=label,
|
||||
description=description,
|
||||
device_kind=device_kind)
|
||||
return _Setting(
|
||||
name, rw, validator, feature=feature, kind=_KIND.range, label=label, description=description, device_kind=device_kind
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
|
@ -283,30 +297,50 @@ def feature_range(name,
|
|||
|
||||
_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.'))
|
||||
_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.'))
|
||||
_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'))
|
||||
_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.'))
|
||||
_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.'))
|
||||
|
||||
#
|
||||
|
@ -314,135 +348,143 @@ _DISABLE_KEYS = ('disable-keyboard-keys', _('Disable keys'), _('Disable specific
|
|||
#
|
||||
|
||||
|
||||
def _register_hand_detection(register=_R.keyboard_hand_detection,
|
||||
true_value=b'\x00\x00\x00',
|
||||
false_value=b'\x00\x00\x30',
|
||||
mask=b'\x00\x00\xFF'):
|
||||
return register_toggle(_HAND_DETECTION[0],
|
||||
register,
|
||||
true_value=true_value,
|
||||
false_value=false_value,
|
||||
label=_HAND_DETECTION[1],
|
||||
description=_HAND_DETECTION[2],
|
||||
device_kind=(_DK.keyboard, ))
|
||||
def _register_hand_detection(
|
||||
register=_R.keyboard_hand_detection, true_value=b'\x00\x00\x00', false_value=b'\x00\x00\x30', mask=b'\x00\x00\xFF'
|
||||
):
|
||||
return register_toggle(
|
||||
_HAND_DETECTION[0],
|
||||
register,
|
||||
true_value=true_value,
|
||||
false_value=false_value,
|
||||
label=_HAND_DETECTION[1],
|
||||
description=_HAND_DETECTION[2],
|
||||
device_kind=(_DK.keyboard, )
|
||||
)
|
||||
|
||||
|
||||
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,
|
||||
mask=mask,
|
||||
label=_FN_SWAP[1],
|
||||
description=_FN_SWAP[2],
|
||||
device_kind=(_DK.keyboard, ))
|
||||
return register_toggle(
|
||||
_FN_SWAP[0],
|
||||
register,
|
||||
true_value=true_value,
|
||||
mask=mask,
|
||||
label=_FN_SWAP[1],
|
||||
description=_FN_SWAP[2],
|
||||
device_kind=(_DK.keyboard, )
|
||||
)
|
||||
|
||||
|
||||
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,
|
||||
mask=mask,
|
||||
label=_SMOOTH_SCROLL[1],
|
||||
description=_SMOOTH_SCROLL[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball))
|
||||
return register_toggle(
|
||||
_SMOOTH_SCROLL[0],
|
||||
register,
|
||||
true_value=true_value,
|
||||
mask=mask,
|
||||
label=_SMOOTH_SCROLL[1],
|
||||
description=_SMOOTH_SCROLL[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball)
|
||||
)
|
||||
|
||||
|
||||
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,
|
||||
mask=mask,
|
||||
label=_SIDE_SCROLL[1],
|
||||
description=_SIDE_SCROLL[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball))
|
||||
return register_toggle(
|
||||
_SIDE_SCROLL[0],
|
||||
register,
|
||||
true_value=true_value,
|
||||
mask=mask,
|
||||
label=_SIDE_SCROLL[1],
|
||||
description=_SIDE_SCROLL[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball)
|
||||
)
|
||||
|
||||
|
||||
def _register_dpi(register=_R.mouse_dpi, choices=None):
|
||||
return register_choices(_DPI[0],
|
||||
register,
|
||||
choices,
|
||||
label=_DPI[1],
|
||||
description=_DPI[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball))
|
||||
return register_choices(
|
||||
_DPI[0], register, choices, label=_DPI[1], description=_DPI[2], device_kind=(_DK.mouse, _DK.trackball)
|
||||
)
|
||||
|
||||
|
||||
def _feature_fn_swap():
|
||||
return feature_toggle(_FN_SWAP[0],
|
||||
_F.FN_INVERSION,
|
||||
label=_FN_SWAP[1],
|
||||
description=_FN_SWAP[2],
|
||||
device_kind=(_DK.keyboard, ))
|
||||
return feature_toggle(
|
||||
_FN_SWAP[0], _F.FN_INVERSION, label=_FN_SWAP[1], description=_FN_SWAP[2], device_kind=(_DK.keyboard, )
|
||||
)
|
||||
|
||||
|
||||
# this might not be correct for this feature
|
||||
def _feature_new_fn_swap():
|
||||
return feature_toggle(_FN_SWAP[0],
|
||||
_F.NEW_FN_INVERSION,
|
||||
label=_FN_SWAP[1],
|
||||
description=_FN_SWAP[2],
|
||||
device_kind=(_DK.keyboard, ))
|
||||
return feature_toggle(
|
||||
_FN_SWAP[0], _F.NEW_FN_INVERSION, label=_FN_SWAP[1], description=_FN_SWAP[2], device_kind=(_DK.keyboard, )
|
||||
)
|
||||
|
||||
|
||||
# ignore the capabilities part of the feature - all devices should be able to swap Fn state
|
||||
# just use the current host (first byte = 0xFF) part of the feature to read and set the Fn state
|
||||
def _feature_k375s_fn_swap():
|
||||
return feature_toggle(_FN_SWAP[0],
|
||||
_F.K375S_FN_INVERSION,
|
||||
label=_FN_SWAP[1],
|
||||
description=_FN_SWAP[2],
|
||||
true_value=b'\xFF\x01',
|
||||
false_value=b'\xFF\x00',
|
||||
device_kind=(_DK.keyboard, ))
|
||||
return feature_toggle(
|
||||
_FN_SWAP[0],
|
||||
_F.K375S_FN_INVERSION,
|
||||
label=_FN_SWAP[1],
|
||||
description=_FN_SWAP[2],
|
||||
true_value=b'\xFF\x01',
|
||||
false_value=b'\xFF\x00',
|
||||
device_kind=(_DK.keyboard, )
|
||||
)
|
||||
|
||||
|
||||
# FIXME: This will enable all supported backlight settings,
|
||||
# we should allow the users to select which settings they want to enable.
|
||||
def _feature_backlight2():
|
||||
return feature_toggle(_BACKLIGHT[0],
|
||||
_F.BACKLIGHT2,
|
||||
label=_BACKLIGHT[1],
|
||||
description=_BACKLIGHT[2],
|
||||
device_kind=(_DK.keyboard, ))
|
||||
return feature_toggle(
|
||||
_BACKLIGHT[0], _F.BACKLIGHT2, label=_BACKLIGHT[1], description=_BACKLIGHT[2], device_kind=(_DK.keyboard, )
|
||||
)
|
||||
|
||||
|
||||
def _feature_hi_res_scroll():
|
||||
return feature_toggle(_HI_RES_SCROLL[0],
|
||||
_F.HI_RES_SCROLLING,
|
||||
label=_HI_RES_SCROLL[1],
|
||||
description=_HI_RES_SCROLL[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball))
|
||||
return feature_toggle(
|
||||
_HI_RES_SCROLL[0],
|
||||
_F.HI_RES_SCROLLING,
|
||||
label=_HI_RES_SCROLL[1],
|
||||
description=_HI_RES_SCROLL[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball)
|
||||
)
|
||||
|
||||
|
||||
def _feature_lowres_smooth_scroll():
|
||||
return feature_toggle(_LOW_RES_SCROLL[0],
|
||||
_F.LOWRES_WHEEL,
|
||||
label=_LOW_RES_SCROLL[1],
|
||||
description=_LOW_RES_SCROLL[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball))
|
||||
return feature_toggle(
|
||||
_LOW_RES_SCROLL[0],
|
||||
_F.LOWRES_WHEEL,
|
||||
label=_LOW_RES_SCROLL[1],
|
||||
description=_LOW_RES_SCROLL[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball)
|
||||
)
|
||||
|
||||
|
||||
def _feature_hires_smooth_invert():
|
||||
return feature_toggle(_HIRES_INV[0],
|
||||
_F.HIRES_WHEEL,
|
||||
read_function_id=0x10,
|
||||
write_function_id=0x20,
|
||||
true_value=0x04,
|
||||
mask=0x04,
|
||||
label=_HIRES_INV[1],
|
||||
description=_HIRES_INV[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball))
|
||||
return feature_toggle(
|
||||
_HIRES_INV[0],
|
||||
_F.HIRES_WHEEL,
|
||||
read_function_id=0x10,
|
||||
write_function_id=0x20,
|
||||
true_value=0x04,
|
||||
mask=0x04,
|
||||
label=_HIRES_INV[1],
|
||||
description=_HIRES_INV[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball)
|
||||
)
|
||||
|
||||
|
||||
def _feature_hires_smooth_resolution():
|
||||
return feature_toggle(_HIRES_RES[0],
|
||||
_F.HIRES_WHEEL,
|
||||
read_function_id=0x10,
|
||||
write_function_id=0x20,
|
||||
true_value=0x02,
|
||||
mask=0x02,
|
||||
label=_HIRES_RES[1],
|
||||
description=_HIRES_RES[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball))
|
||||
return feature_toggle(
|
||||
_HIRES_RES[0],
|
||||
_F.HIRES_WHEEL,
|
||||
read_function_id=0x10,
|
||||
write_function_id=0x20,
|
||||
true_value=0x02,
|
||||
mask=0x02,
|
||||
label=_HIRES_RES[1],
|
||||
description=_HIRES_RES[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball)
|
||||
)
|
||||
|
||||
|
||||
def _feature_smart_shift():
|
||||
|
@ -475,15 +517,17 @@ def _feature_smart_shift():
|
|||
data = _int2bytes(mode, count=1) + _int2bytes(threshold, count=1) * 2
|
||||
return super(_SmartShiftRW, self).write(device, data)
|
||||
|
||||
return feature_range(_SMART_SHIFT[0],
|
||||
_F.SMART_SHIFT,
|
||||
_MIN_SMART_SHIFT_VALUE,
|
||||
_MAX_SMART_SHIFT_VALUE,
|
||||
bytes_count=1,
|
||||
rw=_SmartShiftRW(_F.SMART_SHIFT),
|
||||
label=_SMART_SHIFT[1],
|
||||
description=_SMART_SHIFT[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball))
|
||||
return feature_range(
|
||||
_SMART_SHIFT[0],
|
||||
_F.SMART_SHIFT,
|
||||
_MIN_SMART_SHIFT_VALUE,
|
||||
_MAX_SMART_SHIFT_VALUE,
|
||||
bytes_count=1,
|
||||
rw=_SmartShiftRW(_F.SMART_SHIFT),
|
||||
label=_SMART_SHIFT[1],
|
||||
description=_SMART_SHIFT[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball)
|
||||
)
|
||||
|
||||
|
||||
def _feature_adjustable_dpi_choices(device):
|
||||
|
@ -514,30 +558,34 @@ def _feature_adjustable_dpi():
|
|||
# Assume sensorIdx 0 (there is only one sensor)
|
||||
# [2] getSensorDpi(sensorIdx) -> sensorIdx, dpiMSB, dpiLSB
|
||||
# [3] setSensorDpi(sensorIdx, dpi)
|
||||
return feature_choices_dynamic(_DPI[0],
|
||||
_F.ADJUSTABLE_DPI,
|
||||
_feature_adjustable_dpi_choices,
|
||||
read_function_id=0x20,
|
||||
write_function_id=0x30,
|
||||
bytes_count=3,
|
||||
label=_DPI[1],
|
||||
description=_DPI[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball))
|
||||
return feature_choices_dynamic(
|
||||
_DPI[0],
|
||||
_F.ADJUSTABLE_DPI,
|
||||
_feature_adjustable_dpi_choices,
|
||||
read_function_id=0x20,
|
||||
write_function_id=0x30,
|
||||
bytes_count=3,
|
||||
label=_DPI[1],
|
||||
description=_DPI[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball)
|
||||
)
|
||||
|
||||
|
||||
def _feature_pointer_speed():
|
||||
"""Pointer Speed feature"""
|
||||
# min and max values taken from usb traces of Win software
|
||||
return feature_range(_POINTER_SPEED[0],
|
||||
_F.POINTER_SPEED,
|
||||
0x002e,
|
||||
0x01ff,
|
||||
read_function_id=0x0,
|
||||
write_function_id=0x10,
|
||||
bytes_count=2,
|
||||
label=_POINTER_SPEED[1],
|
||||
description=_POINTER_SPEED[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball))
|
||||
return feature_range(
|
||||
_POINTER_SPEED[0],
|
||||
_F.POINTER_SPEED,
|
||||
0x002e,
|
||||
0x01ff,
|
||||
read_function_id=0x0,
|
||||
write_function_id=0x10,
|
||||
bytes_count=2,
|
||||
label=_POINTER_SPEED[1],
|
||||
description=_POINTER_SPEED[2],
|
||||
device_kind=(_DK.mouse, _DK.trackball)
|
||||
)
|
||||
|
||||
|
||||
# the keys for the choice map are Logitech controls (from special_keys)
|
||||
|
@ -572,18 +620,20 @@ def _feature_reprogrammable_keys_choices(device):
|
|||
|
||||
|
||||
def _feature_reprogrammable_keys():
|
||||
return feature_map_choices_dynamic(_REPROGRAMMABLE_KEYS[0],
|
||||
_F.REPROG_CONTROLS_V4,
|
||||
_feature_reprogrammable_keys_choices,
|
||||
read_function_id=0x20,
|
||||
write_function_id=0x30,
|
||||
key_bytes_count=2,
|
||||
skip_bytes_count=1,
|
||||
value_bytes_count=2,
|
||||
label=_REPROGRAMMABLE_KEYS[1],
|
||||
description=_REPROGRAMMABLE_KEYS[2],
|
||||
device_kind=(_DK.keyboard, ),
|
||||
extra_default=0)
|
||||
return feature_map_choices_dynamic(
|
||||
_REPROGRAMMABLE_KEYS[0],
|
||||
_F.REPROG_CONTROLS_V4,
|
||||
_feature_reprogrammable_keys_choices,
|
||||
read_function_id=0x20,
|
||||
write_function_id=0x30,
|
||||
key_bytes_count=2,
|
||||
skip_bytes_count=1,
|
||||
value_bytes_count=2,
|
||||
label=_REPROGRAMMABLE_KEYS[1],
|
||||
description=_REPROGRAMMABLE_KEYS[2],
|
||||
device_kind=(_DK.keyboard, ),
|
||||
extra_default=0
|
||||
)
|
||||
|
||||
|
||||
def _feature_disable_keyboard_keys_key_list(device):
|
||||
|
@ -593,14 +643,16 @@ def _feature_disable_keyboard_keys_key_list(device):
|
|||
|
||||
|
||||
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, )
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
|
|
|
@ -489,14 +489,16 @@ TASK = _NamedInts(
|
|||
)
|
||||
TASK._fallback = lambda x: 'unknown:%04X' % x
|
||||
# hidpp 4.5 info from https://lekensteyn.nl/files/logitech/x1b04_specialkeysmsebuttons.html
|
||||
KEY_FLAG = _NamedInts(virtual=0x80,
|
||||
persistently_divertable=0x40,
|
||||
divertable=0x20,
|
||||
reprogrammable=0x10,
|
||||
FN_sensitive=0x08,
|
||||
nonstandard=0x04,
|
||||
is_FN=0x02,
|
||||
mse=0x01)
|
||||
KEY_FLAG = _NamedInts(
|
||||
virtual=0x80,
|
||||
persistently_divertable=0x40,
|
||||
divertable=0x20,
|
||||
reprogrammable=0x10,
|
||||
FN_sensitive=0x08,
|
||||
nonstandard=0x04,
|
||||
is_FN=0x02,
|
||||
mse=0x01
|
||||
)
|
||||
|
||||
DISABLE = _NamedInts(
|
||||
Caps_Lock=0x01,
|
||||
|
|
|
@ -102,10 +102,12 @@ 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__
|
||||
|
||||
|
@ -209,8 +211,10 @@ class DeviceStatus(dict):
|
|||
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)
|
||||
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
|
||||
|
|
|
@ -36,43 +36,54 @@ del getLogger
|
|||
|
||||
|
||||
def _create_parser():
|
||||
parser = _argparse.ArgumentParser(prog=NAME.lower(),
|
||||
add_help=False,
|
||||
epilog='For details on individual actions, run `%s <action> --help`.' % NAME.lower())
|
||||
parser = _argparse.ArgumentParser(
|
||||
prog=NAME.lower(),
|
||||
add_help=False,
|
||||
epilog='For details on individual actions, run `%s <action> --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.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 = 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 = 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
|
||||
|
@ -130,8 +141,10 @@ 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()
|
||||
or name in dev.name.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
|
||||
|
||||
raise Exception("no device found matching '%s'" % name)
|
||||
|
|
|
@ -31,8 +31,10 @@ def _print_setting(s, verbose=True):
|
|||
if s.kind == _settings.KIND.toggle:
|
||||
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),
|
||||
'], or higher/lower/highest/max/lowest/min')
|
||||
print(
|
||||
'# possible values: one of [', ', '.join(str(v) for v in s.choices),
|
||||
'], or higher/lower/highest/max/lowest/min'
|
||||
)
|
||||
else:
|
||||
# wtf?
|
||||
pass
|
||||
|
|
|
@ -45,22 +45,32 @@ def run(receivers, args, find_receiver, _ignore):
|
|||
register = receiver.read_register(_R.notifications)
|
||||
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'))
|
||||
print(
|
||||
' Connection State %#04x: %s' %
|
||||
(_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'))
|
||||
print(
|
||||
' Device Activity %#04x: %s' %
|
||||
(_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)
|
||||
print(' Pairing Register %#04x %#04x: %s' %
|
||||
(_R.receiver_info % 0x100, sub_reg + device, '0x' + _strhex(register) if register else 'None'))
|
||||
print(
|
||||
' Pairing Register %#04x %#04x: %s' %
|
||||
(_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'))
|
||||
print(
|
||||
' Pairing Name %#04x %#02x: %s' %
|
||||
(_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'))
|
||||
print(
|
||||
' Firmware %#04x %#04x: %s' %
|
||||
(_R.firmware % 0x100, sub_reg, '0x' + _strhex(register) if register else 'None')
|
||||
)
|
||||
|
|
|
@ -48,22 +48,25 @@ 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(
|
||||
'-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(
|
||||
'-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')
|
||||
|
|
|
@ -49,12 +49,9 @@ del namedtuple
|
|||
|
||||
|
||||
def _ghost(device):
|
||||
return _GHOST_DEVICE(receiver=device.receiver,
|
||||
number=device.number,
|
||||
name=device.name,
|
||||
kind=device.kind,
|
||||
status=None,
|
||||
online=False)
|
||||
return _GHOST_DEVICE(
|
||||
receiver=device.receiver, number=device.number, name=device.name, kind=device.kind, status=None, online=False
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
|
@ -146,11 +143,15 @@ 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
|
||||
|
|
|
@ -47,12 +47,16 @@ def _error_dialog(reason, object):
|
|||
|
||||
if reason == 'permissions':
|
||||
title = _('Permissions error')
|
||||
text = (_('Found a Logitech Receiver (%s), but did not have permission to open it.') % object + '\n\n' +
|
||||
_("If you've just installed Solaar, try removing the receiver and plugging it back in."))
|
||||
text = (
|
||||
_('Found a Logitech Receiver (%s), but did not have permission to open it.') % object + '\n\n' +
|
||||
_("If you've just installed Solaar, try removing the receiver and plugging it back in.")
|
||||
)
|
||||
elif reason == 'unpair':
|
||||
title = _('Unpairing failed')
|
||||
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.'))
|
||||
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)
|
||||
|
||||
|
|
|
@ -45,15 +45,19 @@ 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(_('Testing'), (
|
||||
'Douglas Wagner',
|
||||
'Julien Gascard',
|
||||
'Peter Wu http://www.lekensteyn.nl/logitech-unifying.html',
|
||||
))
|
||||
about.add_credit_section(_('Logitech documentation'), (
|
||||
'Julien Danjou http://julien.danjou.info/blog/2012/logitech-unifying-upower',
|
||||
'Nestor Lopez Casado http://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28',
|
||||
))
|
||||
about.add_credit_section(
|
||||
_('Testing'), (
|
||||
'Douglas Wagner',
|
||||
'Julien Gascard',
|
||||
'Peter Wu http://www.lekensteyn.nl/logitech-unifying.html',
|
||||
)
|
||||
)
|
||||
about.add_credit_section(
|
||||
_('Logitech documentation'), (
|
||||
'Julien Danjou http://julien.danjou.info/blog/2012/logitech-unifying-upower',
|
||||
'Nestor Lopez Casado http://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28',
|
||||
)
|
||||
)
|
||||
except TypeError:
|
||||
# gtk3 < ~3.6.4 has incorrect gi bindings
|
||||
import logging
|
||||
|
@ -63,16 +67,18 @@ def _create():
|
|||
import logging
|
||||
logging.exception('failed to fully create the about dialog')
|
||||
|
||||
about.set_translator_credits('\n'.join((
|
||||
'gogo (croatian)',
|
||||
'Papoteur, David Geiger, Damien Lallement (français)',
|
||||
'Michele Olivo (italiano)',
|
||||
'Adrian Piotrowicz (polski)',
|
||||
'Drovetto, JrBenito (Portuguese-BR)',
|
||||
'Daniel Pavel (română)',
|
||||
'Daniel Zippert, Emelie Snecker (svensk)',
|
||||
'Dimitriy Ryazantcev (Russian)',
|
||||
)))
|
||||
about.set_translator_credits(
|
||||
'\n'.join((
|
||||
'gogo (croatian)',
|
||||
'Papoteur, David Geiger, Damien Lallement (français)',
|
||||
'Michele Olivo (italiano)',
|
||||
'Adrian Piotrowicz (polski)',
|
||||
'Drovetto, JrBenito (Portuguese-BR)',
|
||||
'Daniel Pavel (română)',
|
||||
'Daniel Zippert, Emelie Snecker (svensk)',
|
||||
'Dimitriy Ryazantcev (Russian)',
|
||||
))
|
||||
)
|
||||
|
||||
about.set_website('http://pwr-solaar.github.io/Solaar/')
|
||||
about.set_website_label(NAME)
|
||||
|
|
|
@ -91,8 +91,10 @@ def unpair(window, device):
|
|||
assert device
|
||||
assert device.kind is not None
|
||||
|
||||
qdialog = Gtk.MessageDialog(window, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.NONE,
|
||||
_('Unpair') + ' ' + device.name + ' ?')
|
||||
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)
|
||||
qdialog.add_button(_('Unpair'), Gtk.ResponseType.ACCEPT)
|
||||
|
|
|
@ -64,7 +64,8 @@ def _look_for_application_icons():
|
|||
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):
|
||||
|
|
|
@ -208,8 +208,10 @@ def create(receiver):
|
|||
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.'),
|
||||
'preferences-desktop-peripherals', page_text)
|
||||
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)
|
||||
page_intro.pack_end(spinner, True, True, 24)
|
||||
|
|
|
@ -181,8 +181,9 @@ try:
|
|||
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), '')
|
||||
|
|
|
@ -168,12 +168,14 @@ def _create_buttons_box():
|
|||
bb = Gtk.ButtonBox(Gtk.Orientation.HORIZONTAL)
|
||||
bb.set_layout(Gtk.ButtonBoxStyle.END)
|
||||
|
||||
bb._details = _new_button(None,
|
||||
'dialog-information',
|
||||
_SMALL_BUTTON_ICON_SIZE,
|
||||
tooltip=_('Show Technical Details'),
|
||||
toggle=True,
|
||||
clicked=_update_details)
|
||||
bb._details = _new_button(
|
||||
None,
|
||||
'dialog-information',
|
||||
_SMALL_BUTTON_ICON_SIZE,
|
||||
tooltip=_('Show Technical Details'),
|
||||
toggle=True,
|
||||
clicked=_update_details
|
||||
)
|
||||
bb.add(bb._details)
|
||||
bb.set_child_secondary(bb._details, True)
|
||||
bb.set_child_non_homogeneous(bb._details, True)
|
||||
|
@ -319,10 +321,9 @@ def _create_window_layout():
|
|||
bottom_buttons_box.set_spacing(20)
|
||||
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',
|
||||
icon_size=_SMALL_BUTTON_ICON_SIZE,
|
||||
clicked=_show_about_window)
|
||||
about_button = _new_button(
|
||||
_('About') + ' ' + NAME, 'help-about', icon_size=_SMALL_BUTTON_ICON_SIZE, clicked=_show_about_window
|
||||
)
|
||||
bottom_buttons_box.add(about_button)
|
||||
|
||||
# solaar_version = Gtk.Label()
|
||||
|
@ -447,8 +448,9 @@ 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,
|
||||
device)
|
||||
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)
|
||||
|
@ -533,10 +535,12 @@ def _update_details(button):
|
|||
hid_version = device.protocol
|
||||
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)
|
||||
|
@ -589,17 +593,19 @@ 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<small>%s</small>' % 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<small>%s</small>' % 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<small>%s</small>' % _('Only one device can be paired to this receiver.')
|
||||
pairings = receiver.remaining_pairings(False)
|
||||
|
@ -684,12 +690,15 @@ def _update_device_panel(device, panel, buttons, full=False):
|
|||
panel._secure._text.set_text(_('not encrypted'))
|
||||
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.'))
|
||||
_(
|
||||
'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.'
|
||||
)
|
||||
)
|
||||
else:
|
||||
panel._secure._text.set_text(_('encrypted'))
|
||||
panel._secure._icon.set_from_icon_name('security-high', _INFO_ICON_SIZE)
|
||||
|
|
Loading…
Reference in New Issue