From 9315b3fcdb71f3ddaf167e9a64a9e23aa762fdb2 Mon Sep 17 00:00:00 2001 From: "Peter F. Patel-Schneider" Date: Tue, 28 Dec 2021 06:17:46 -0500 Subject: [PATCH] receiver: optimize ReprogrammableKey in hidpp20 --- lib/logitech_receiver/hidpp20.py | 62 +++++++++----------------------- 1 file changed, 17 insertions(+), 45 deletions(-) diff --git a/lib/logitech_receiver/hidpp20.py b/lib/logitech_receiver/hidpp20.py index a689402c..da9c91cc 100644 --- a/lib/logitech_receiver/hidpp20.py +++ b/lib/logitech_receiver/hidpp20.py @@ -439,10 +439,6 @@ class ReprogrammableKeyV4(ReprogrammableKey): @property def remappable_to(self) -> List[_NamedInt]: - # this flag is only to show in UI, ignore in Solaar - # if special_keys.KEY_FLAG.reprogrammable not in self.flags: - # return [] - self._device.keys._ensure_all_keys_queried() ret = [] if self.group_mask != []: # only keys with a non-zero gmask are remappable @@ -454,7 +450,6 @@ class ReprogrammableKeyV4(ReprogrammableKey): tgt_task = _NamedInt(tgt_cid, tgt_task) if tgt_task != self.default_task: # don't put itself in twice ret.append(tgt_task) - return ret @property @@ -464,8 +459,7 @@ class ReprogrammableKeyV4(ReprogrammableKey): return special_keys.MAPPING_FLAG.flag_names(self._mapping_flags) def set_diverted(self, value: bool): - """If set, the control is diverted temporarily and reports presses as HID++ events - until a HID++ configuration reset occurs.""" + """If set, the control is diverted temporarily and reports presses as HID++ events.""" flags = {special_keys.MAPPING_FLAG.diverted: value} self._setCidReporting(flags=flags) @@ -475,23 +469,17 @@ class ReprogrammableKeyV4(ReprogrammableKey): self._setCidReporting(flags=flags) def set_rawXY_reporting(self, value: bool): - """If set, the mouse reports all its raw XY events while this control is pressed - as HID++ events. Gets cleared on a HID++ configuration reset.""" + """If set, the mouse temporarilty reports all its raw XY events while this control is pressed as HID++ events.""" flags = {special_keys.MAPPING_FLAG.raw_XY_diverted: value} self._setCidReporting(flags=flags) def remap(self, to: _NamedInt): - """Remaps this control to another action.""" + """Temporarily remaps this control to another action.""" self._setCidReporting(remap=int(to)) def _getCidReporting(self): try: - mapped_data = feature_request( - self._device, - FEATURE.REPROG_CONTROLS_V4, - 0x20, - *tuple(_pack('!H', self._cid)), - ) + mapped_data = feature_request(self._device, FEATURE.REPROG_CONTROLS_V4, 0x20, *tuple(_pack('!H', self._cid))) if mapped_data: cid, mapping_flags_1, mapped_to = _unpack('!HBH', mapped_data[:5]) if cid != self._cid and _log.isEnabledFor(_WARNING): @@ -515,9 +503,7 @@ class ReprogrammableKeyV4(ReprogrammableKey): self._mapped_to = self._cid def _setCidReporting(self, flags=None, remap=0): - """Sends a `setCidReporting` request with the given parameters to the control. Raises - an exception if the parameters are invalid. - + """Sends a `setCidReporting` request with the given parameters. Raises an exception if the parameters are invalid. Parameters: - flags {Dict[_NamedInt,bool]} -- a dictionary of which mapping flags to set/unset - remap {int} -- which control ID to remap to; or 0 to keep current mapping @@ -525,8 +511,7 @@ class ReprogrammableKeyV4(ReprogrammableKey): flags = flags if flags else {} # See flake8 B006 # if special_keys.MAPPING_FLAG.raw_XY_diverted in flags and flags[special_keys.MAPPING_FLAG.raw_XY_diverted]: - # We need diversion to report raw XY, so divert temporarily - # (since XY reporting is also temporary) + # We need diversion to report raw XY, so divert temporarily (since XY reporting is also temporary) # flags[special_keys.MAPPING_FLAG.diverted] = True # if special_keys.MAPPING_FLAG.diverted in flags and not flags[special_keys.MAPPING_FLAG.diverted]: # flags[special_keys.MAPPING_FLAG.raw_XY_diverted] = False @@ -547,35 +532,28 @@ class ReprogrammableKeyV4(ReprogrammableKey): msg=f'Tried to set mapping flag "{f}" on control "{self.key}" ' + f'which does not support "{FLAG_TO_CAPABILITY[f]}" on device {self._device}.' ) - bfield |= int(f) if v else 0 bfield |= int(f) << 1 # The 'Xvalid' bit + if self._mapping_flags: # update flags if already read + if v: + self._mapping_flags |= int(f) + else: + self._mapping_flags &= ~int(f) if remap != 0 and remap not in self.remappable_to: raise FeatureNotSupported( msg=f'Tried to remap control "{self.key}" to a control ID {remap} which it is not remappable to ' + f'on device {self._device}.' ) + if remap != 0: # update mapping if changing (even if not already read) + self._mapped_to = remap - pkt = tuple( - _pack( - '!HBH', - self._cid, - bfield & 0xff, - remap, - # TODO: to fully support version 4 of REPROG_CONTROLS_V4, append - # another byte `(bfield >> 8) & 0xff` here. But older devices - # might behave oddly given that byte, so we don't send it. - ) - ) + pkt = tuple(_pack('!HBH', self._cid, bfield & 0xff, remap)) + # TODO: to fully support version 4 of REPROG_CONTROLS_V4, append `(bfield >> 8) & 0xff` here. + # But older devices might behave oddly given that byte, so we don't send it. ret = feature_request(self._device, FEATURE.REPROG_CONTROLS_V4, 0x30, *pkt) if ret is None or _unpack('!BBBBB', ret[:5]) != pkt and _log.isEnabledFor(_WARNING): - _log.warn( - f"REPROG_CONTROLS_v4 endpoint setCidReporting on device {self._device} should echo request packet, but didn't." - ) - - # update knowledge of mapping - self._getCidReporting() + _log.warn(f"REPROG_CONTROLS_v4 setCidReporting on device {self._device} didn't echo request packet.") class KeysArray: @@ -658,12 +636,6 @@ class KeysArray: if k is not None and int(value) == int(k.key): return index - for index, k in enumerate(self.keys): - if k is None: - k = self.__getitem__(index) - if k is not None: - return index - def __iter__(self): for k in range(0, len(self.keys)): yield self.__getitem__(k)