diff --git a/lib/logitech_receiver/settings.py b/lib/logitech_receiver/settings.py index bdcb96c2..41ef9b6b 100644 --- a/lib/logitech_receiver/settings.py +++ b/lib/logitech_receiver/settings.py @@ -602,16 +602,22 @@ class FeatureRWMap(FeatureRW): class BooleanValidator: - __slots__ = ('true_value', 'false_value', 'read_offset', 'mask', 'needs_current_value') + __slots__ = ('true_value', 'false_value', 'read_skip_byte_count', 'write_prefix_bytes', 'mask', 'needs_current_value') kind = KIND.toggle default_true = 0x01 default_false = 0x00 # mask specifies all the affected bits in the value default_mask = 0xFF - default_read_offset = 0 - def __init__(self, true_value=default_true, false_value=default_false, mask=default_mask, read_offset=default_read_offset): + def __init__( + self, + true_value=default_true, + false_value=default_false, + mask=default_mask, + read_skip_byte_count=0, + write_prefix_bytes=b'' + ): if isinstance(true_value, int): assert isinstance(false_value, int) if mask is None: @@ -645,10 +651,11 @@ class BooleanValidator: self.true_value = true_value self.false_value = false_value self.mask = mask - self.read_offset = read_offset + self.read_skip_byte_count = read_skip_byte_count + self.write_prefix_bytes = write_prefix_bytes def validate_read(self, reply_bytes): - reply_bytes = reply_bytes[self.read_offset:] + reply_bytes = reply_bytes[self.read_skip_byte_count:] if isinstance(self.mask, int): reply_value = ord(reply_bytes[:1]) & self.mask if _log.isEnabledFor(_DEBUG): @@ -711,7 +718,7 @@ class BooleanValidator: if _log.isEnabledFor(_DEBUG): _log.debug('BooleanValidator: prepare_write(%s, %s) => %r', new_value, current_value, to_write) - return to_write + return self.write_prefix_bytes + to_write class BitFieldValidator: @@ -837,7 +844,7 @@ class ChoicesValidator: :param choices: a list of NamedInts :param byte_count: the size of the derived byte sequence. If None, it will be calculated from the choices.""" - def __init__(self, choices, byte_count=None, read_skip_byte_count=None, write_prefix_bytes=b''): + def __init__(self, choices, byte_count=None, read_skip_byte_count=0, write_prefix_bytes=b''): assert choices is not None assert isinstance(choices, _NamedInts) assert len(choices) > 1 @@ -850,7 +857,7 @@ class ChoicesValidator: assert self._byte_count <= byte_count self._byte_count = byte_count assert self._byte_count < 8 - self._read_skip_byte_count = read_skip_byte_count if read_skip_byte_count else 0 + self._read_skip_byte_count = read_skip_byte_count self._write_prefix_bytes = write_prefix_bytes if write_prefix_bytes else b'' assert self._byte_count + self._read_skip_byte_count <= 14 assert self._byte_count + len(self._write_prefix_bytes) <= 14 @@ -916,7 +923,7 @@ class ChoicesMapValidator(ChoicesValidator): self.choices = choices_map self.needs_current_value = False self.extra_default = extra_default - self._read_skip_byte_count = read_skip_byte_count if read_skip_byte_count else 0 + self._read_skip_byte_count = read_skip_byte_count self._write_prefix_bytes = write_prefix_bytes if write_prefix_bytes else b'' self.activate = activate self.mask = mask @@ -1091,10 +1098,8 @@ class ActionSettingRW: self.pressed = False self.release_action() else: - print(self.key.key, cids) for key in cids: if key and not key == self.key.key: # some other diverted key pressed - print(key, self.key, cids) self.key_action(key) elif n.address == 0x10: if self.pressed: diff --git a/lib/logitech_receiver/settings_templates.py b/lib/logitech_receiver/settings_templates.py index 5e64c823..81a405d5 100644 --- a/lib/logitech_receiver/settings_templates.py +++ b/lib/logitech_receiver/settings_templates.py @@ -224,13 +224,17 @@ _DISABLE_KEYS_LABEL_SUB = _('Disables the %s key.') # _FeatureRW is for feature-based settings and takes the feature name as positional argument plus the following: # read_fnid is the feature function (times 16) to read the value (default 0x00), # write_fnid is the feature function (times 16) to write the value (default 0x10), +# prefix is a prefix to add to the data being written and the read request (default b''), used for features +# that provide and set multiple settings (e.g., to read and write function key inversion for current host) # no_reply is whether to wait for a reply (default false) (USE WITH EXTREME CAUTION). # # There are three simple validators - _BooleanV, _RangeV, and _ChoicesV -# _BooleanV is for boolean values. It takes three keyword arguments that can be integers or byte strings: -# true_value is the raw value for true (default 0x01), -# false_value is the raw value for false (default 0x00), -# mask is used to keep only some bits from a sequence of bits. +# _BooleanV is for boolean values. It takes five keyword arguments +# true_value is the raw value for true (default 0x01), this can be an integer or a byte string, +# false_value is the raw value for false (default 0x00), this can be an integer or a byte string, +# mask is used to keep only some bits from a sequence of bits, this can be an integer or a byte string, +# read_skip_byte_count is the number of bytes to ignore at the beginning of the read value (default 0), +# write_prefix_bytes is a byte string to write before the value (default empty). # _RangeV is for an integer in a range. It takes three keyword arguments: # min_value is the minimum value for the setting, # max_value is the maximum value for the setting, @@ -238,8 +242,8 @@ _DISABLE_KEYS_LABEL_SUB = _('Disables the %s key.') # _ChoicesV is for symbolic choices. It takes one positional and three keyword arguments: # the positional argument is a list of named integers that are the valid choices, # byte_count is the number of bytes for the integer (default size of largest choice integer), -# read_skip_byte_count is the number of bytes to ignore at the beginning of the read value (default 0), -# write_prefix_bytes is a byte string to write before the value (default empty). +# read_skip_byte_count is as for _BooleanV, +# write_prefix_bytes is as for _BooleanV. # # The _Settings class is for settings that are maps from keys to values. # The _BitFieldSetting class is for settings that have multiple boolean values packed into a bit field. @@ -292,7 +296,7 @@ def _feature_new_fn_swap(): # 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(): - validator = _BooleanV(true_value=b'\x01', false_value=b'\x00', read_offset=1) + validator = _BooleanV(true_value=b'\x01', false_value=b'\x00', read_skip_byte_count=1) return _Setting(_FN_SWAP, _FeatureRW(_F.K375S_FN_INVERSION, prefix=b'\xFF'), validator, device_kind=(_DK.keyboard, )) @@ -480,7 +484,7 @@ def _feature_speed_change(): keys = [_NamedInt(0, _('Off')), key.key] return _ChoicesV(_NamedInts.list(keys), byte_count=2) - rw = _SpeedChangeRW('speed change', _DIVERT_KEYS[0]), + rw = _SpeedChangeRW('speed change', _DIVERT_KEYS[0]) return _Setting(_SPEED_CHANGE, rw, callback=callback, device_kind=(_DK.mouse, _DK.trackball))